diff options
author | Xin Li <delphij@google.com> | 2017-11-14 12:08:38 -0800 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2017-11-14 12:08:38 -0800 |
commit | bb9e38fef95b7bc932ebcad18508e03228f9f7d3 (patch) | |
tree | 29e859e08879c87f591507de0f370abd1ec66fe2 | |
parent | b86b2d2881d53219c59a5eb85a3d73cb45942661 (diff) | |
parent | 1a06284b24f5eb7bb9c1fea0817da8898b3b1bff (diff) | |
download | platform_hardware_interfaces-bb9e38fef95b7bc932ebcad18508e03228f9f7d3.tar.gz platform_hardware_interfaces-bb9e38fef95b7bc932ebcad18508e03228f9f7d3.tar.bz2 platform_hardware_interfaces-bb9e38fef95b7bc932ebcad18508e03228f9f7d3.zip |
Merge commit '1a06284b24f5eb7bb9c1fea0817da8898b3b1bff' from
oc-mr1-dev-plus-aosp into stage-aosp-master
Change-Id: I2a044eb8c9981d0a8198ffe2df55559afbd76341
Merged-In: I4fb9f18884f7ef21162015a0032c4431444f7025
298 files changed, 17865 insertions, 8021 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index 42399a6664..3788bc6baa 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -56,3 +56,10 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/) $(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/) $(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/) $(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore*" -print0 | xargs -0 rm -f) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/hw/android.hardware.automotive*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/android.hardware.automotive*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/android.hardware.automotive*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/android.hardware.automotive*) +$(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore\@1\.1*" -print0 | xargs -0 rm -f) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.tests*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk/android.hardware.tests*) diff --git a/audio/2.0/config/audio_policy_configuration.xsd b/audio/2.0/config/audio_policy_configuration.xsd index c94da80bfa..eb59152c91 100644 --- a/audio/2.0/config/audio_policy_configuration.xsd +++ b/audio/2.0/config/audio_policy_configuration.xsd @@ -365,10 +365,10 @@ </xs:restriction> </xs:simpleType> <xs:complexType name="profile"> - <xs:attribute name="name" type="xs:token" use="required"/> - <xs:attribute name="format" type="audioFormat" use="required"/> - <xs:attribute name="samplingRates" type="samplingRates" use="required"/> - <xs:attribute name="channelMasks" type="channelMask" use="required"/> + <xs:attribute name="name" type="xs:token" use="optional"/> + <xs:attribute name="format" type="audioFormat" use="optional"/> + <xs:attribute name="samplingRates" type="samplingRates" use="optional"/> + <xs:attribute name="channelMasks" type="channelMask" use="optional"/> </xs:complexType> <xs:simpleType name="gainMode"> <xs:restriction base="xs:string"> diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk index 621853cb0e..8dec48209c 100644 --- a/audio/2.0/default/Android.mk +++ b/audio/2.0/default/Android.mk @@ -84,8 +84,4 @@ else LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) endif -ifeq ($(TARGET_USES_BCRADIO_FUTURE_FEATURES),true) -LOCAL_CFLAGS += -DTARGET_USES_BCRADIO_FUTURE_FEATURES -endif - include $(BUILD_EXECUTABLE) diff --git a/audio/2.0/default/OWNERS b/audio/2.0/default/OWNERS new file mode 100644 index 0000000000..6fdc97ca29 --- /dev/null +++ b/audio/2.0/default/OWNERS @@ -0,0 +1,3 @@ +elaurent@google.com +krocard@google.com +mnaganov@google.com diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h index 82f05a77b4..e29af53184 100644 --- a/audio/2.0/default/Stream.h +++ b/audio/2.0/default/Stream.h @@ -49,6 +49,13 @@ using ::android::sp; struct Stream : public IStream, public ParametersUtil { explicit Stream(audio_stream_t* stream); + /** 1GiB is the maximum buffer size the HAL client is allowed to request. + * This value has been chosen to be under SIZE_MAX and still big enough + * for all audio use case. + * Keep private for 2.0, put in .hal in 2.1 + */ + static constexpr uint32_t MAX_BUFFER_SIZE = 2 << 30 /* == 1GiB */; + // Methods from ::android::hardware::audio::V2_0::IStream follow. Return<uint64_t> getFrameSize() override; Return<uint64_t> getFrameCount() override; diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp index b81cbb924f..9c933a9201 100644 --- a/audio/2.0/default/StreamIn.cpp +++ b/audio/2.0/default/StreamIn.cpp @@ -347,14 +347,10 @@ Return<void> StreamIn::prepareForReading(uint32_t frameSize, sendError(Result::INVALID_ARGUMENTS); return Void(); } - // A message queue asserts if it can not handle the requested buffer, - // thus the client has to guess the maximum size it can handle - // Choose an arbitrary margin for the overhead of a message queue - size_t metadataOverhead = 100000; - if (frameSize > - (std::numeric_limits<size_t>::max() - metadataOverhead) / framesCount) { - ALOGE("Buffer too big: %u*%u bytes can not fit in a message queue", - frameSize, framesCount); + + if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) { + ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount, + Stream::MAX_BUFFER_SIZE); sendError(Result::INVALID_ARGUMENTS); return Void(); } diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp index 290d0b103c..22dcd0c994 100644 --- a/audio/2.0/default/StreamOut.cpp +++ b/audio/2.0/default/StreamOut.cpp @@ -323,14 +323,9 @@ Return<void> StreamOut::prepareForWriting(uint32_t frameSize, sendError(Result::INVALID_ARGUMENTS); return Void(); } - // A message queue asserts if it can not handle the requested buffer, - // thus the client has to guess the maximum size it can handle - size_t metadataOverhead = - 100000; // Arbitrary margin for the overhead of a message queue - if (frameSize > - (std::numeric_limits<size_t>::max() - metadataOverhead) / framesCount) { - ALOGE("Buffer too big: %u*%u bytes can not fit in a message queue", - frameSize, framesCount); + if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) { + ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount, + Stream::MAX_BUFFER_SIZE); sendError(Result::INVALID_ARGUMENTS); return Void(); } diff --git a/audio/2.0/default/service.cpp b/audio/2.0/default/service.cpp index 7f28d7df84..a215108e95 100644 --- a/audio/2.0/default/service.cpp +++ b/audio/2.0/default/service.cpp @@ -21,8 +21,6 @@ #include <android/hardware/audio/2.0/IDevicesFactory.h> #include <android/hardware/audio/effect/2.0/IEffectsFactory.h> #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> -#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h> -#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; @@ -32,13 +30,6 @@ using android::hardware::audio::effect::V2_0::IEffectsFactory; using android::hardware::audio::V2_0::IDevicesFactory; using android::hardware::soundtrigger::V2_0::ISoundTriggerHw; using android::hardware::registerPassthroughServiceImplementation; -namespace broadcastradio = android::hardware::broadcastradio; - -#ifdef TARGET_USES_BCRADIO_FUTURE_FEATURES -static const bool useBroadcastRadioFutureFeatures = true; -#else -static const bool useBroadcastRadioFutureFeatures = false; -#endif using android::OK; @@ -49,17 +40,9 @@ int main(int /* argc */, char* /* argv */ []) { LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio service: %d", status); status = registerPassthroughServiceImplementation<IEffectsFactory>(); LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio effects service: %d", status); - // Soundtrigger and FM radio might be not present. + // Soundtrigger might be not present. status = registerPassthroughServiceImplementation<ISoundTriggerHw>(); ALOGE_IF(status != OK, "Error while registering soundtrigger service: %d", status); - if (useBroadcastRadioFutureFeatures) { - status = registerPassthroughServiceImplementation< - broadcastradio::V1_1::IBroadcastRadioFactory>(); - } else { - status = registerPassthroughServiceImplementation< - broadcastradio::V1_0::IBroadcastRadioFactory>(); - } - ALOGE_IF(status != OK, "Error while registering fm radio service: %d", status); joinRpcThreadpool(); return status; } diff --git a/audio/2.0/vts/functional/Android.bp b/audio/2.0/vts/functional/Android.bp index b289709fda..f3b2ca72cd 100644 --- a/audio/2.0/vts/functional/Android.bp +++ b/audio/2.0/vts/functional/Android.bp @@ -16,29 +16,18 @@ cc_test { name: "VtsHalAudioV2_0TargetTest", - defaults: ["hidl_defaults"], - srcs: ["AudioPrimaryHidlHalTest.cpp", - "ValidateAudioConfiguration.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libhidltransport", - "libutils", - "libcutils", - "libxml2", - "android.hardware.audio@2.0", - "android.hardware.audio.common@2.0", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "AudioPrimaryHidlHalTest.cpp", + "ValidateAudioConfiguration.cpp" ], static_libs: [ - "VtsHalHidlTargetTestBase", "android.hardware.audio.common.test.utility", + "android.hardware.audio@2.0", + "android.hardware.audio.common@2.0", + "libxml2", ], - cflags: [ - "-O0", - "-g", - "-Wall", - "-Wextra", - "-Werror", + shared_libs: [ + "libicuuc", ], } diff --git a/audio/2.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/2.0/vts/functional/ValidateAudioConfiguration.cpp index 01324c87d3..ec3259a1e3 100644 --- a/audio/2.0/vts/functional/ValidateAudioConfiguration.cpp +++ b/audio/2.0/vts/functional/ValidateAudioConfiguration.cpp @@ -14,9 +14,21 @@ * limitations under the License. */ +#include <string> +#include <unistd.h> + #include "utility/ValidateXml.h" TEST(CheckConfig, audioPolicyConfigurationValidation) { - ASSERT_VALID_XML("/vendor/etc/audio_policy_configuration.xml", - "/data/local/tmp/audio_policy_configuration.xsd"); + const char* configName = "audio_policy_configuration.xml"; + const char* possibleConfigLocations[] = {"/odm/etc", "/vendor/etc", "/system/etc"}; + const char* configSchemaPath = "/data/local/tmp/audio_policy_configuration.xsd"; + + for (std::string folder : possibleConfigLocations) { + const auto configPath = folder + '/' + configName; + if (access(configPath.c_str(), R_OK) == 0) { + ASSERT_VALID_XML(configPath.c_str(), configSchemaPath); + return; // The framework does not read past the first config file found + } + } } diff --git a/audio/common/2.0/default/Android.bp b/audio/common/2.0/default/Android.bp index 7fab220fcf..82b38c0877 100644 --- a/audio/common/2.0/default/Android.bp +++ b/audio/common/2.0/default/Android.bp @@ -17,6 +17,9 @@ cc_library_shared { name: "android.hardware.audio.common@2.0-util", defaults: ["hidl_defaults"], vendor_available: true, + vndk: { + enabled: true, + }, srcs: [ "EffectMap.cpp", "HidlUtils.cpp", diff --git a/audio/common/2.0/default/OWNERS b/audio/common/2.0/default/OWNERS new file mode 100644 index 0000000000..6fdc97ca29 --- /dev/null +++ b/audio/common/2.0/default/OWNERS @@ -0,0 +1,3 @@ +elaurent@google.com +krocard@google.com +mnaganov@google.com diff --git a/audio/common/test/utility/OWNERS b/audio/common/test/utility/OWNERS new file mode 100644 index 0000000000..6fdc97ca29 --- /dev/null +++ b/audio/common/test/utility/OWNERS @@ -0,0 +1,3 @@ +elaurent@google.com +krocard@google.com +mnaganov@google.com diff --git a/audio/effect/2.0/default/OWNERS b/audio/effect/2.0/default/OWNERS new file mode 100644 index 0000000000..6fdc97ca29 --- /dev/null +++ b/audio/effect/2.0/default/OWNERS @@ -0,0 +1,3 @@ +elaurent@google.com +krocard@google.com +mnaganov@google.com diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp index 8a370cd12d..7b421cb7e7 100644 --- a/audio/effect/2.0/vts/functional/Android.bp +++ b/audio/effect/2.0/vts/functional/Android.bp @@ -16,24 +16,20 @@ cc_test { name: "VtsHalAudioEffectV2_0TargetTest", - defaults: ["hidl_defaults"], - srcs: ["VtsHalAudioEffectV2_0TargetTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalAudioEffectV2_0TargetTest.cpp", + "ValidateAudioEffectsConfiguration.cpp" + ], + static_libs: [ + "android.hardware.audio.common.test.utility", "android.hardware.audio.common@2.0", "android.hardware.audio.effect@2.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", + "libxml2", ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", + shared_libs: [ + "libicuuc", ], } diff --git a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp new file mode 100644 index 0000000000..fdc1347497 --- /dev/null +++ b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> + +#include "utility/ValidateXml.h" + +TEST(CheckConfig, audioEffectsConfigurationValidation) { + RecordProperty("description", + "Verify that the effects configuration file is valid according to the schema"); + const char* xmlConfigFile = "/vendor/etc/audio_effects.xml"; + // Not every device uses XML configuration, so only validate + // if the XML configuration actually exists. + if (access(xmlConfigFile, F_OK) == 0) { + ASSERT_VALID_XML(xmlConfigFile, "/data/local/tmp/audio_effects_conf_V2_0.xsd"); + } +} diff --git a/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd b/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd new file mode 100644 index 0000000000..ca6a7dc65b --- /dev/null +++ b/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd @@ -0,0 +1,249 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://schemas.android.com/audio/audio_effects_conf/v2_0" + xmlns:aec="http://schemas.android.com/audio/audio_effects_conf/v2_0" + elementFormDefault="qualified"> + + <!-- Simple types --> + <xs:simpleType name="versionType"> + <xs:restriction base="xs:decimal"> + <xs:enumeration value="2.0"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="uuidType"> + <xs:restriction base="xs:string"> + <xs:pattern value="[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="streamInputType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="mic"/> + <xs:enumeration value="voice_uplink"/> + <xs:enumeration value="voice_downlink"/> + <xs:enumeration value="voice_call"/> + <xs:enumeration value="camcorder"/> + <xs:enumeration value="voice_recognition"/> + <xs:enumeration value="voice_communication"/> + <xs:enumeration value="unprocessed"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="streamOutputType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="voice_call"/> + <xs:enumeration value="system"/> + <xs:enumeration value="ring"/> + <xs:enumeration value="music"/> + <xs:enumeration value="alarm"/> + <xs:enumeration value="notification"/> + <xs:enumeration value="bluetooth_sco"/> + <xs:enumeration value="enforced_audible"/> + <xs:enumeration value="dtmf"/> + <xs:enumeration value="tts"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="relativePathType"> + <xs:restriction base="xs:string"> + <xs:pattern value="[^/].*"/> + </xs:restriction> + </xs:simpleType> + + <!-- Complex types --> + <xs:complexType name="librariesType"> + <xs:annotation> + <xs:documentation xml:lang="en"> + List of effect libraries to load. Each library element must have "name" and + "path" attributes. The latter is giving the path of the library .so file + relative to the standard effect folders: /(vendor|odm|system)/lib(64)?/soundfx/ + + Example for a library in "/vendor/lib/soundfx/lib.so": + <library name="name" path="lib.so"/> + + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element name="library" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="path" type="aec:relativePathType" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="effectImplType"> + <xs:attribute name="library" type="xs:string" use="required"/> + <xs:attribute name="uuid" type="aec:uuidType" use="required"/> + </xs:complexType> + <xs:complexType name="effectType"> + <xs:complexContent> + <xs:extension base="aec:effectImplType"> + <xs:attribute name="name" type="xs:string" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="effectProxyType"> + <xs:complexContent> + <xs:extension base="aec:effectType"> + <xs:sequence> + <xs:element name="libsw" type="aec:effectImplType"/> + <xs:element name="libhw" type="aec:effectImplType"/> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="effectsType"> + <xs:annotation> + <xs:documentation xml:lang="en"> + List of effects to load. Each effect element must contain "name", + "library", and "uuid" attrs. The value of the "library" attr must + correspond to the name of a "library" element. The name of the effect + element is indicative, only the value of the "uuid" element designates + the effect for the audio framework. The uuid is the implementation + specific UUID as specified by the effect vendor. This is not the generic + effect type UUID. + + For effect proxy implementations, SW and HW implemetations of the effect + can be specified. + + Example: + + <effect name="name" library="lib" uuid="uuuu"/> + <effectProxy name="proxied" library="proxy" uuid="xxxx"> + <libsw library="sw_bundle" uuid="yyyy"/> + <libhw library="offload_bundle" uuid="zzzz"/> + </effectProxy> + + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="effect" type="aec:effectType" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="effectProxy" type="aec:effectProxyType" minOccurs="0" maxOccurs="unbounded"/> + </xs:choice> + </xs:complexType> + <xs:complexType name="streamProcessingType"> + <xs:sequence> + <xs:element name="apply" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="effect" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="streamPreprocessType"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Audio preprocessing configuration. The processing configuration consists + of a list of elements each describing processing settings for a given + input stream. Valid input stream types are listed in "streamInputType". + + Each stream element contains a list of "apply" elements. The value of the + "effect" attr must correspond to the name of an "effect" element. + + Example: + + <stream type="voice_communication"> + <apply effect="effect1"/> + <apply effect="effect2"/> + </stream> + + </xs:documentation> + </xs:annotation> + <xs:complexContent> + <xs:extension base="aec:streamProcessingType"> + <xs:attribute name="type" type="aec:streamInputType" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="streamPostprocessType"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Audio postprocessing configuration. The processing configuration consists + of a list of elements each describing processing settings for a given + output stream. Valid output stream types are listed in "streamOutputType". + + Each stream element contains a list of "apply" elements. The value of the + "effect" attr must correspond to the name of an "effect" element. + + Example: + + <stream type="music"> + <apply effect="effect1"/> + </stream> + + </xs:documentation> + </xs:annotation> + <xs:complexContent> + <xs:extension base="aec:streamProcessingType"> + <xs:attribute name="type" type="aec:streamOutputType" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + + <!-- Root element --> + <xs:element name="audio_effects_conf"> + <xs:complexType> + <xs:sequence> + <xs:element name="libraries" type="aec:librariesType"/> + <xs:element name="effects" type="aec:effectsType"/> + <xs:element name="postprocess" minOccurs="0" maxOccurs="1"> + <xs:complexType> + <xs:sequence> + <xs:element name="stream" type="aec:streamPostprocessType" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="preprocess" minOccurs="0" maxOccurs="1"> + <xs:complexType> + <xs:sequence> + <xs:element name="stream" type="aec:streamPreprocessType" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="version" type="aec:versionType" use="required"/> + </xs:complexType> + + <!-- Keys and references --> + <xs:key name="libraryName"> + <xs:selector xpath="aec:libraries/aec:library"/> + <xs:field xpath="@name"/> + </xs:key> + <xs:keyref name="libraryNameRef1" refer="aec:libraryName"> + <xs:selector xpath="aec:effects/aec:effect"/> + <xs:field xpath="@library"/> + </xs:keyref> + <xs:keyref name="libraryNameRef2" refer="aec:libraryName"> + <xs:selector xpath="aec:effects/aec:effect/aec:libsw"/> + <xs:field xpath="@library"/> + </xs:keyref> + <xs:keyref name="libraryNameRef3" refer="aec:libraryName"> + <xs:selector xpath="aec:effects/aec:effect/aec:libhw"/> + <xs:field xpath="@library"/> + </xs:keyref> + <xs:key name="effectName"> + <xs:selector xpath="aec:effects/aec:effect"/> + <xs:field xpath="@name"/> + </xs:key> + <xs:keyref name="effectNamePreRef" refer="aec:effectName"> + <xs:selector xpath="aec:preprocess/aec:stream/aec:apply"/> + <xs:field xpath="@effect"/> + </xs:keyref> + <xs:keyref name="effectNamePostRef" refer="aec:effectName"> + <xs:selector xpath="aec:postprocess/aec:stream/aec:apply"/> + <xs:field xpath="@effect"/> + </xs:keyref> + </xs:element> +</xs:schema> diff --git a/automotive/Android.bp b/automotive/Android.bp index be588299e3..8cde817d03 100644 --- a/automotive/Android.bp +++ b/automotive/Android.bp @@ -1,7 +1,9 @@ // This is an autogenerated file, do not edit. subdirs = [ "evs/1.0", + "evs/1.0/default", "evs/1.0/vts/functional", "vehicle/2.0", - "vehicle/2.1", + "vehicle/2.0/default", + "vehicle/2.0/default/impl/vhal_v2_0/proto", ] diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp new file mode 100644 index 0000000000..2574e860b2 --- /dev/null +++ b/automotive/evs/1.0/default/Android.bp @@ -0,0 +1,31 @@ +cc_binary { + name: "android.hardware.automotive.evs@1.0-service", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + "EvsCamera.cpp", + "EvsEnumerator.cpp", + "EvsDisplay.cpp" + ], + init_rc: ["android.hardware.automotive.evs@1.0-service.rc"], + + shared_libs: [ + "android.hardware.automotive.evs@1.0", + "libui", + "libbase", + "libbinder", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + + cflags: [ + "-O0", + "-g", + ], +} diff --git a/automotive/evs/1.0/default/Android.mk b/automotive/evs/1.0/default/Android.mk deleted file mode 100644 index 0ee70711d1..0000000000 --- a/automotive/evs/1.0/default/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -LOCAL_PATH:=$(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.automotive.evs@1.0-service -LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-service.rc -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_VENDOR_MODULE := true - -LOCAL_SRC_FILES := \ - service.cpp \ - EvsCamera.cpp \ - EvsEnumerator.cpp \ - EvsDisplay.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - android.hardware.automotive.evs@1.0 \ - libui \ - libbase \ - libbinder \ - libcutils \ - libhardware \ - libhidlbase \ - libhidltransport \ - liblog \ - libutils \ - -LOCAL_CFLAGS := -O0 -g - -include $(BUILD_EXECUTABLE) diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp index e86e9bcdd8..555ff5bc42 100644 --- a/automotive/evs/1.0/vts/functional/Android.bp +++ b/automotive/evs/1.0/vts/functional/Android.bp @@ -15,10 +15,10 @@ // cc_test { - name: "VtsEvsV1_0Target", + name: "VtsHalEvsV1_0Target", srcs: [ - "VtsEvsV1_0TargetTest.cpp", + "VtsHalEvsV1_0TargetTest.cpp", "FrameHandler.cpp", "FormatConvert.cpp" ], @@ -43,4 +43,3 @@ cc_test { "-g", ], } - diff --git a/automotive/evs/1.0/vts/functional/VtsEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp index 2e80afe8fe..57050d7516 100644 --- a/automotive/evs/1.0/vts/functional/VtsEvsV1_0TargetTest.cpp +++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp @@ -17,8 +17,13 @@ #define LOG_TAG "VtsHalEvsTest" -// TODO: How should we configure these values to target appropriate hardware? -const static char kEnumeratorName[] = "EvsEnumeratorHw-Mock"; +// Note: We have't got a great way to indicate which target +// should be tested, so we'll leave the interface served by the +// default (mock) EVS driver here for easy reference. All +// actual EVS drivers should serve on the EvsEnumeratorHw name, +// however, so the code is checked in that way. +//const static char kEnumeratorName[] = "EvsEnumeratorHw-Mock"; +const static char kEnumeratorName[] = "EvsEnumeratorHw"; // These values are called out in the EVS design doc (as of Mar 8, 2017) @@ -474,4 +479,4 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { // Explicitly release the display pEnumerator->closeDisplay(pDisplay); -}
\ No newline at end of file +} diff --git a/automotive/vehicle/2.0/Android.mk b/automotive/vehicle/2.0/Android.mk index eb05f35eca..5919487471 100644 --- a/automotive/vehicle/2.0/Android.mk +++ b/automotive/vehicle/2.0/Android.mk @@ -17,6 +17,177 @@ LOCAL_JAVA_LIBRARIES := \ # +# Build types.hal (DiagnosticFloatSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/DiagnosticFloatSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.DiagnosticFloatSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (DiagnosticIntegerSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/DiagnosticIntegerSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.DiagnosticIntegerSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2CommonIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2CommonIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2CommonIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2CompressionIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2CompressionIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2CompressionIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2FuelSystemStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2FuelSystemStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2FuelSystemStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2FuelType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2FuelType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2FuelType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2IgnitionMonitorKind) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2IgnitionMonitorKind.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2IgnitionMonitorKind + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2SecondaryAirStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2SecondaryAirStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2SecondaryAirStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2SparkIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2SparkIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2SparkIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# # Build types.hal (StatusCode) # GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/StatusCode.java @@ -910,6 +1081,139 @@ $(GEN): $(LOCAL_PATH)/types.hal LOCAL_GENERATED_SOURCES += $(GEN) # +# Build types.hal (VmsAvailabilityStateIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsAvailabilityStateIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsAvailabilityStateIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsBaseMessageIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsBaseMessageIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsBaseMessageIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsMessageType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageWithLayerAndPublisherIdIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsMessageWithLayerAndPublisherIdIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageWithLayerIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageWithLayerIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsMessageWithLayerIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsOfferingMessageIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsOfferingMessageIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsOfferingMessageIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsSubscriptionsStateIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsSubscriptionsStateIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsSubscriptionsStateIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# # Build types.hal (Wheel) # GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java @@ -989,6 +1293,177 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ # +# Build types.hal (DiagnosticFloatSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/DiagnosticFloatSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.DiagnosticFloatSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (DiagnosticIntegerSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/DiagnosticIntegerSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.DiagnosticIntegerSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2CommonIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2CommonIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2CommonIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2CompressionIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2CompressionIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2CompressionIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2FuelSystemStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2FuelSystemStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2FuelSystemStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2FuelType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2FuelType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2FuelType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2IgnitionMonitorKind) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2IgnitionMonitorKind.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2IgnitionMonitorKind + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2SecondaryAirStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2SecondaryAirStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2SecondaryAirStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2SparkIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2SparkIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Obd2SparkIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# # Build types.hal (StatusCode) # GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/StatusCode.java @@ -1882,6 +2357,139 @@ $(GEN): $(LOCAL_PATH)/types.hal LOCAL_GENERATED_SOURCES += $(GEN) # +# Build types.hal (VmsAvailabilityStateIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsAvailabilityStateIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsAvailabilityStateIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsBaseMessageIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsBaseMessageIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsBaseMessageIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsMessageType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageWithLayerAndPublisherIdIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsMessageWithLayerAndPublisherIdIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageWithLayerIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageWithLayerIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsMessageWithLayerIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsOfferingMessageIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsOfferingMessageIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsOfferingMessageIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsSubscriptionsStateIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsSubscriptionsStateIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VmsSubscriptionsStateIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# # Build types.hal (Wheel) # GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp new file mode 100644 index 0000000000..1690163d2a --- /dev/null +++ b/automotive/vehicle/2.0/default/Android.bp @@ -0,0 +1,117 @@ +// 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. + +cc_defaults { + name: "vhal_v2_0_defaults", + shared_libs: [ + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + "android.hardware.automotive.vehicle@2.0", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], +} + +cc_library_headers { + name: "vhal_v2_0_common_headers", + vendor: true, + export_include_dirs: ["common/include/vhal_v2_0"], +} + +// Vehicle reference implementation lib +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-manager-lib", + vendor: true, + defaults: ["vhal_v2_0_defaults"], + srcs: [ + "common/src/Obd2SensorStore.cpp", + "common/src/SubscriptionManager.cpp", + "common/src/VehicleHalManager.cpp", + "common/src/VehicleObjectPool.cpp", + "common/src/VehiclePropertyStore.cpp", + "common/src/VehicleUtils.cpp", + ], + local_include_dirs: ["common/include/vhal_v2_0"], + export_include_dirs: ["common/include"], +} + +cc_library_shared { + name: "android.hardware.automotive.vehicle@2.0-manager-lib-shared", + vendor: true, + static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"], + export_static_lib_headers: ["android.hardware.automotive.vehicle@2.0-manager-lib"], +} + +// Vehicle default VehicleHAL implementation +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-default-impl-lib", + vendor: true, + defaults: ["vhal_v2_0_defaults"], + srcs: [ + "impl/vhal_v2_0/EmulatedVehicleHal.cpp", + "impl/vhal_v2_0/VehicleEmulator.cpp", + "impl/vhal_v2_0/PipeComm.cpp", + "impl/vhal_v2_0/SocketComm.cpp", + ], + local_include_dirs: ["common/include/vhal_v2_0"], + export_include_dirs: ["impl"], + whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"], + shared_libs: [ + "libbase", + "libprotobuf-cpp-lite", + ], + static_libs: [ + "libqemu_pipe", + "android.hardware.automotive.vehicle@2.0-libproto-native", + ], +} + +cc_test { + name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests", + vendor: true, + defaults: ["vhal_v2_0_defaults"], + whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"], + srcs: [ + "tests/RecurrentTimer_test.cpp", + "tests/SubscriptionManager_test.cpp", + "tests/VehicleHalManager_test.cpp", + "tests/VehicleObjectPool_test.cpp", + "tests/VehiclePropConfigIndex_test.cpp", + ], + header_libs: ["libbase_headers"], +} + +cc_binary { + name: "android.hardware.automotive.vehicle@2.0-service", + defaults: ["vhal_v2_0_defaults"], + init_rc: ["android.hardware.automotive.vehicle@2.0-service.rc"], + vendor: true, + relative_install_path: "hw", + srcs: ["VehicleService.cpp"], + shared_libs: [ + "libbase", + "libprotobuf-cpp-lite", + ], + static_libs: [ + "android.hardware.automotive.vehicle@2.0-manager-lib", + "android.hardware.automotive.vehicle@2.0-default-impl-lib", + "android.hardware.automotive.vehicle@2.0-libproto-native", + "libqemu_pipe", + ], +} diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk deleted file mode 100644 index 72e1364fc6..0000000000 --- a/automotive/vehicle/2.0/default/Android.mk +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright (C) 2016 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH := $(call my-dir) - -vhal_v2_0 = android.hardware.automotive.vehicle@2.0 - -############################################################################### -# Vehicle reference implementation lib -############################################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(vhal_v2_0)-manager-lib -LOCAL_SRC_FILES := \ - common/src/SubscriptionManager.cpp \ - common/src/VehicleHalManager.cpp \ - common/src/VehicleObjectPool.cpp \ - common/src/VehiclePropertyStore.cpp \ - common/src/VehicleUtils.cpp \ - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/common/include/vhal_v2_0 - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(LOCAL_PATH)/common/include - -LOCAL_SHARED_LIBRARIES := \ - libhidlbase \ - libhidltransport \ - liblog \ - libutils \ - $(vhal_v2_0) \ - -include $(BUILD_STATIC_LIBRARY) - - -include $(CLEAR_VARS) -LOCAL_MODULE := $(vhal_v2_0)-manager-lib-shared -LOCAL_SRC_FILES := \ - common/src/SubscriptionManager.cpp \ - common/src/VehicleHalManager.cpp \ - common/src/VehicleObjectPool.cpp \ - common/src/VehiclePropertyStore.cpp \ - common/src/VehicleUtils.cpp \ - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/common/include/vhal_v2_0 - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(LOCAL_PATH)/common/include - -LOCAL_SHARED_LIBRARIES := \ - libhidlbase \ - libhidltransport \ - liblog \ - libutils \ - $(vhal_v2_0) \ - -include $(BUILD_SHARED_LIBRARY) - -############################################################################### -# Vehicle HAL Protobuf library -############################################################################### -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-proto-files-under, impl/vhal_v2_0/proto) - -LOCAL_PROTOC_OPTIMIZE_TYPE := nano - -LOCAL_MODULE := $(vhal_v2_0)-libproto-native -LOCAL_MODULE_CLASS := STATIC_LIBRARIES - -LOCAL_MODULE_TAGS := optional - -LOCAL_STRIP_MODULE := keep_symbols - -generated_sources_dir := $(call local-generated-sources-dir) -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(generated_sources_dir)/proto/$(LOCAL_PATH)/impl/vhal_v2_0/proto - -include $(BUILD_STATIC_LIBRARY) - - -############################################################################### -# Vehicle default VehicleHAL implementation -############################################################################### -include $(CLEAR_VARS) - -LOCAL_MODULE:= $(vhal_v2_0)-default-impl-lib -LOCAL_SRC_FILES:= \ - impl/vhal_v2_0/EmulatedVehicleHal.cpp \ - impl/vhal_v2_0/VehicleEmulator.cpp \ - impl/vhal_v2_0/PipeComm.cpp \ - impl/vhal_v2_0/SocketComm.cpp \ - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/impl/vhal_v2_0 - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(LOCAL_PATH)/impl - -LOCAL_WHOLE_STATIC_LIBRARIES := \ - $(vhal_v2_0)-manager-lib \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libhidlbase \ - libhidltransport \ - liblog \ - libprotobuf-cpp-lite \ - libutils \ - $(vhal_v2_0) \ - -LOCAL_STATIC_LIBRARIES := \ - libqemu_pipe \ - $(vhal_v2_0)-libproto-native \ - -LOCAL_CFLAGS += -Wall -Wextra -Werror - -include $(BUILD_STATIC_LIBRARY) - - -############################################################################### -# Vehicle reference implementation unit tests -############################################################################### -include $(CLEAR_VARS) - -LOCAL_MODULE:= $(vhal_v2_0)-manager-unit-tests - -LOCAL_WHOLE_STATIC_LIBRARIES := \ - $(vhal_v2_0)-manager-lib \ - -LOCAL_SRC_FILES:= \ - tests/RecurrentTimer_test.cpp \ - tests/SubscriptionManager_test.cpp \ - tests/VehicleHalManager_test.cpp \ - tests/VehicleObjectPool_test.cpp \ - tests/VehiclePropConfigIndex_test.cpp \ - -LOCAL_HEADER_LIBRARIES := \ - libbase_headers - -LOCAL_SHARED_LIBRARIES := \ - libhidlbase \ - libhidltransport \ - liblog \ - libutils \ - $(vhal_v2_0) \ - -LOCAL_CFLAGS += -Wall -Wextra -Werror -LOCAL_MODULE_TAGS := tests - -include $(BUILD_NATIVE_TEST) - - -############################################################################### -# Vehicle HAL service -############################################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(vhal_v2_0)-service -LOCAL_INIT_RC := $(vhal_v2_0)-service.rc -LOCAL_PROPRIETARY_MODULE := true -LOCAL_MODULE_RELATIVE_PATH := hw - -LOCAL_SRC_FILES := \ - VehicleService.cpp - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libhidlbase \ - libhidltransport \ - liblog \ - libprotobuf-cpp-lite \ - libutils \ - $(vhal_v2_0) \ - -LOCAL_STATIC_LIBRARIES := \ - $(vhal_v2_0)-manager-lib \ - $(vhal_v2_0)-default-impl-lib \ - $(vhal_v2_0)-libproto-native \ - libqemu_pipe \ - -LOCAL_CFLAGS += -Wall -Wextra -Werror - -include $(BUILD_EXECUTABLE) diff --git a/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/Obd2SensorStore.h index 6c44626d12..191a565c61 100644 --- a/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/Obd2SensorStore.h @@ -14,38 +14,37 @@ * limitations under the License. */ -#ifndef android_hardware_automotive_vehicle_V2_1_Obd2SensorStore_H_ -#define android_hardware_automotive_vehicle_V2_1_Obd2SensorStore_H_ +#ifndef android_hardware_automotive_vehicle_V2_0_Obd2SensorStore_H_ +#define android_hardware_automotive_vehicle_V2_0_Obd2SensorStore_H_ #include <vector> -#include <android/hardware/automotive/vehicle/2.1/types.h> +#include <android/hardware/automotive/vehicle/2.0/types.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { -namespace V2_1 { +namespace V2_0 { // This class wraps all the logic required to create an OBD2 frame. // It allows storing sensor values, setting appropriate bitmasks as needed, // and returning appropriately laid out storage of sensor values suitable // for being returned via a VehicleHal implementation. class Obd2SensorStore { -public: + public: // Creates a sensor storage with a given number of vendor-specific sensors. - Obd2SensorStore(size_t numVendorIntegerSensors, - size_t numVendorFloatSensors); + Obd2SensorStore(size_t numVendorIntegerSensors, size_t numVendorFloatSensors); // Stores an integer-valued sensor. - V2_0::StatusCode setIntegerSensor(Obd2IntegerSensorIndex index, int32_t value); + StatusCode setIntegerSensor(DiagnosticIntegerSensorIndex index, int32_t value); // Stores an integer-valued sensor. - V2_0::StatusCode setIntegerSensor(size_t index, int32_t value); + StatusCode setIntegerSensor(size_t index, int32_t value); // Stores a float-valued sensor. - V2_0::StatusCode setFloatSensor(Obd2FloatSensorIndex index, float value); + StatusCode setFloatSensor(DiagnosticFloatSensorIndex index, float value); // Stores a float-valued sensor. - V2_0::StatusCode setFloatSensor(size_t index, float value); + StatusCode setFloatSensor(size_t index, float value); // Returns a vector that contains all integer sensors stored. const std::vector<int32_t>& getIntegerSensors() const; @@ -55,11 +54,11 @@ public: const std::vector<uint8_t>& getSensorsBitmask() const; // Given a stringValue, fill in a VehiclePropValue - void fillPropValue(const std::string& dtc, V2_0::VehiclePropValue *propValue) const; + void fillPropValue(const std::string& dtc, VehiclePropValue* propValue) const; -private: + private: class BitmaskInVector { - public: + public: BitmaskInVector(size_t numBits = 0); void resize(size_t numBits); bool get(size_t index) const; @@ -67,7 +66,7 @@ private: const std::vector<uint8_t>& getBitmask() const; - private: + private: std::vector<uint8_t> mStorage; }; @@ -76,7 +75,7 @@ private: BitmaskInVector mSensorsBitmask; }; -} // namespace V2_1 +} // namespace V2_0 } // namespace vehicle } // namespace automotive } // namespace hardware diff --git a/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp b/automotive/vehicle/2.0/default/common/src/Obd2SensorStore.cpp index f4c63a9544..65174f7a00 100644 --- a/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp +++ b/automotive/vehicle/2.0/default/common/src/Obd2SensorStore.cpp @@ -23,23 +23,21 @@ namespace android { namespace hardware { namespace automotive { namespace vehicle { -namespace V2_1 { +namespace V2_0 { -Obd2SensorStore::BitmaskInVector::BitmaskInVector(size_t numBits) -{ +Obd2SensorStore::BitmaskInVector::BitmaskInVector(size_t numBits) { resize(numBits); } void Obd2SensorStore::BitmaskInVector::resize(size_t numBits) { - mStorage = std::vector<uint8_t>((numBits+7)/8, 0); + mStorage = std::vector<uint8_t>((numBits + 7) / 8, 0); } void Obd2SensorStore::BitmaskInVector::set(size_t index, bool value) { const size_t byteIndex = index / 8; const size_t bitIndex = index % 8; const uint8_t byte = mStorage[byteIndex]; - uint8_t newValue = value ? (byte | (1 << bitIndex)) : - (byte & ~(1 << bitIndex)); + uint8_t newValue = value ? (byte | (1 << bitIndex)) : (byte & ~(1 << bitIndex)); mStorage[byteIndex] = newValue; } @@ -54,37 +52,33 @@ const std::vector<uint8_t>& Obd2SensorStore::BitmaskInVector::getBitmask() const return mStorage; } -Obd2SensorStore::Obd2SensorStore(size_t numVendorIntegerSensors, - size_t numVendorFloatSensors) { - // because the last index is valid *inclusive* - const size_t numSystemIntegerSensors = V2_0::toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)+1; - const size_t numSystemFloatSensors = V2_0::toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)+1; - mIntegerSensors = std::vector<int32_t>( - numSystemIntegerSensors+numVendorIntegerSensors, 0); - mFloatSensors = std::vector<float>( - numSystemFloatSensors+numVendorFloatSensors, 0); - mSensorsBitmask.resize(mIntegerSensors.size()+mFloatSensors.size()); +Obd2SensorStore::Obd2SensorStore(size_t numVendorIntegerSensors, size_t numVendorFloatSensors) { + // because the last index is valid *inclusive* + const size_t numSystemIntegerSensors = + toInt(DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX) + 1; + const size_t numSystemFloatSensors = toInt(DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX) + 1; + mIntegerSensors = std::vector<int32_t>(numSystemIntegerSensors + numVendorIntegerSensors, 0); + mFloatSensors = std::vector<float>(numSystemFloatSensors + numVendorFloatSensors, 0); + mSensorsBitmask.resize(mIntegerSensors.size() + mFloatSensors.size()); } -V2_0::StatusCode Obd2SensorStore::setIntegerSensor(Obd2IntegerSensorIndex index, - int32_t value) { - return setIntegerSensor(V2_0::toInt(index), value); +StatusCode Obd2SensorStore::setIntegerSensor(DiagnosticIntegerSensorIndex index, int32_t value) { + return setIntegerSensor(toInt(index), value); } -V2_0::StatusCode Obd2SensorStore::setFloatSensor(Obd2FloatSensorIndex index, - float value) { - return setFloatSensor(V2_0::toInt(index), value); +StatusCode Obd2SensorStore::setFloatSensor(DiagnosticFloatSensorIndex index, float value) { + return setFloatSensor(toInt(index), value); } -V2_0::StatusCode Obd2SensorStore::setIntegerSensor(size_t index, int32_t value) { +StatusCode Obd2SensorStore::setIntegerSensor(size_t index, int32_t value) { mIntegerSensors[index] = value; mSensorsBitmask.set(index, true); - return V2_0::StatusCode::OK; + return StatusCode::OK; } -V2_0::StatusCode Obd2SensorStore::setFloatSensor(size_t index, float value) { +StatusCode Obd2SensorStore::setFloatSensor(size_t index, float value) { mFloatSensors[index] = value; mSensorsBitmask.set(index + mIntegerSensors.size(), true); - return V2_0::StatusCode::OK; + return StatusCode::OK; } const std::vector<int32_t>& Obd2SensorStore::getIntegerSensors() const { @@ -99,8 +93,7 @@ const std::vector<uint8_t>& Obd2SensorStore::getSensorsBitmask() const { return mSensorsBitmask.getBitmask(); } -void Obd2SensorStore::fillPropValue(const std::string& dtc, - V2_0::VehiclePropValue *propValue) const { +void Obd2SensorStore::fillPropValue(const std::string& dtc, VehiclePropValue* propValue) const { propValue->timestamp = elapsedRealtimeNano(); propValue->value.int32Values = getIntegerSensors(); propValue->value.floatValues = getFloatSensors(); @@ -108,8 +101,6 @@ void Obd2SensorStore::fillPropValue(const std::string& dtc, propValue->value.stringValue = dtc; } - - } // namespace V2_0 } // namespace vehicle } // namespace automotive 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 fb63e3645e..08d3d79446 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 @@ -27,6 +27,18 @@ namespace vehicle { namespace V2_0 { namespace impl { +// +// Some handy constants to avoid conversions from enum to int. +constexpr int ABS_ACTIVE = (int)VehicleProperty::ABS_ACTIVE; +constexpr int OBD2_LIVE_FRAME = (int)VehicleProperty::OBD2_LIVE_FRAME; +constexpr int OBD2_FREEZE_FRAME = (int)VehicleProperty::OBD2_FREEZE_FRAME; +constexpr int OBD2_FREEZE_FRAME_INFO = (int)VehicleProperty::OBD2_FREEZE_FRAME_INFO; +constexpr int OBD2_FREEZE_FRAME_CLEAR = (int)VehicleProperty::OBD2_FREEZE_FRAME_CLEAR; +constexpr int TRACTION_CONTROL_ACTIVE = (int)VehicleProperty::TRACTION_CONTROL_ACTIVE; +constexpr int VEHICLE_MAP_SERVICE = (int)VehicleProperty::VEHICLE_MAP_SERVICE; +constexpr int WHEEL_TICK = (int)VehicleProperty::WHEEL_TICK; +constexpr int ALL_WHEELS = + (int)(Wheel::LEFT_FRONT | Wheel::RIGHT_FRONT | Wheel::LEFT_REAR | Wheel::RIGHT_REAR); /* * This property is used for test purpose to generate fake events. @@ -283,8 +295,68 @@ const ConfigDeclaration kVehicleProperties[]{ .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, - .initialValue = {.int32Values = {1}}} + .initialValue = {.int32Values = {1}}}, + + { + .config = + { + .prop = WHEEL_TICK, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000}, + .minSampleRate = 1.0f, + .maxSampleRate = 100.0f, + }, + }, + + { + .config = + { + .prop = ABS_ACTIVE, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, + + { + .config = + { + .prop = TRACTION_CONTROL_ACTIVE, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, + { + .config = {.prop = OBD2_LIVE_FRAME, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0, 0}}, + }, + + { + .config = {.prop = OBD2_FREEZE_FRAME, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0, 0}}, + }, + + { + .config = {.prop = OBD2_FREEZE_FRAME_INFO, + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, + }, + + { + .config = {.prop = OBD2_FREEZE_FRAME_CLEAR, + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {1}}, + }, + + {.config = {.prop = VEHICLE_MAP_SERVICE, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}}, }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp index fe34a3f610..6bc0522403 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp @@ -19,6 +19,7 @@ #include <android-base/macros.h> #include "EmulatedVehicleHal.h" +#include "Obd2SensorStore.h" namespace android { namespace hardware { @@ -28,6 +29,62 @@ namespace V2_0 { namespace impl { +static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors, + size_t numVendorFloatSensors) { + std::unique_ptr<Obd2SensorStore> sensorStore( + new Obd2SensorStore(numVendorIntegerSensors, numVendorFloatSensors)); + + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS, + toInt(Obd2FuelSystemStatus::CLOSED_LOOP)); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_MONITORS_SUPPORTED, + toInt(Obd2IgnitionMonitorKind::SPARK)); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_SPECIFIC_MONITORS, + Obd2CommonIgnitionMonitors::COMPONENTS_AVAILABLE | + Obd2CommonIgnitionMonitors::MISFIRE_AVAILABLE | + Obd2SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE | + Obd2SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS, + toInt(Obd2SecondaryAirStatus::FROM_OUTSIDE_OR_OFF)); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500); + sensorStore->setIntegerSensor( + DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51); + sensorStore->setIntegerSensor( + DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1); + sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_TYPE, + toInt(Obd2FuelType::GASOLINE)); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ENGINE_RPM, 1250.); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::VEHICLE_SPEED, 40.); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::TIMING_ADVANCE, 2.5); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::THROTTLE_POSITION, 19.75); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE, + -0.373); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1, + 190.); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094); + sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024); + + return sensorStore; +} + enum class FakeDataCommand : int32_t { Stop = 0, Start = 1, @@ -40,7 +97,7 @@ EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) this, std::placeholders::_1)), mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1, std::placeholders::_2)) { - + initStaticConfig(); for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { mPropStore->registerProperty(kVehicleProperties[i].config); } @@ -48,23 +105,39 @@ EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( const VehiclePropValue& requestedPropValue, StatusCode* outStatus) { + auto propId = requestedPropValue.prop; + auto& pool = *getValuePool(); VehiclePropValuePtr v = nullptr; - auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue); - if (internalPropValue != nullptr) { - v = getValuePool()->obtain(*internalPropValue); + switch (propId) { + case OBD2_FREEZE_FRAME: + v = pool.obtainComplex(); + *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get()); + break; + case OBD2_FREEZE_FRAME_INFO: + v = pool.obtainComplex(); + *outStatus = fillObd2DtcInfo(v.get()); + break; + default: + auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue); + if (internalPropValue != nullptr) { + v = getValuePool()->obtain(*internalPropValue); + } + + *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG; + break; } - *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG; return v; } StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { if (propValue.prop == kGenerateFakeDataControllingProperty) { - return handleGenerateFakeDataRequest(propValue); - }; - - if (mHvacPowerProps.count(propValue.prop)) { + StatusCode status = handleGenerateFakeDataRequest(propValue); + if (status != StatusCode::OK) { + return status; + } + } else if (mHvacPowerProps.count(propValue.prop)) { auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON), toInt(VehicleAreaZone::ROW_1)); @@ -72,6 +145,12 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { && hvacPowerOn->value.int32Values[0] == 0) { return StatusCode::NOT_AVAILABLE; } + } else if (propValue.prop == OBD2_FREEZE_FRAME_CLEAR) { + return clearObd2FreezeFrames(propValue); + } else if (propValue.prop == VEHICLE_MAP_SERVICE) { + // Placeholder for future implementation of VMS property in the default hal. For now, just + // returns OK; otherwise, hal clients crash with property not supported. + return StatusCode::OK; } if (!mPropStore->writeValue(propValue)) { @@ -83,12 +162,29 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { return StatusCode::OK; } +static bool isDiagnosticProperty(VehiclePropConfig propConfig) { + switch (propConfig.prop) { + case OBD2_LIVE_FRAME: + case OBD2_FREEZE_FRAME: + case OBD2_FREEZE_FRAME_CLEAR: + case OBD2_FREEZE_FRAME_INFO: + return true; + } + return false; +} + // Parse supported properties list and generate vector of property values to hold current values. void EmulatedVehicleHal::onCreate() { for (auto& it : kVehicleProperties) { VehiclePropConfig cfg = it.config; int32_t supportedAreas = cfg.supportedAreas; + if (isDiagnosticProperty(cfg)) { + // do not write an initial empty value for the diagnostic properties + // as we will initialize those separately. + continue; + } + // A global property will have supportedAreas = 0 if (isGlobalProp(cfg.prop)) { supportedAreas = 0; @@ -120,6 +216,8 @@ void EmulatedVehicleHal::onCreate() { } while (supportedAreas != 0); } + initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME)); + initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME)); } std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() { @@ -176,6 +274,13 @@ bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const { } bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) { + if (propValue.prop == kGenerateFakeDataControllingProperty) { + StatusCode status = handleGenerateFakeDataRequest(propValue); + if (status != StatusCode::OK) { + return false; + } + } + if (mPropStore->writeValue(propValue)) { doHalEvent(getValuePool()->obtain(propValue)); return true; @@ -263,6 +368,100 @@ void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) { } } +void EmulatedVehicleHal::initStaticConfig() { + for (auto&& it = std::begin(kVehicleProperties); it != std::end(kVehicleProperties); ++it) { + const auto& cfg = it->config; + VehiclePropertyStore::TokenFunction tokenFunction = nullptr; + + switch (cfg.prop) { + case OBD2_FREEZE_FRAME: { + tokenFunction = [](const VehiclePropValue& propValue) { + return propValue.timestamp; + }; + break; + } + default: + break; + } + + mPropStore->registerProperty(cfg, tokenFunction); + } +} + +void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) { + auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0); + auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]), + static_cast<size_t>(propConfig.configArray[1])); + sensorStore->fillPropValue("", liveObd2Frame.get()); + liveObd2Frame->prop = OBD2_LIVE_FRAME; + + mPropStore->writeValue(*liveObd2Frame); +} + +void EmulatedVehicleHal::initObd2FreezeFrame(const VehiclePropConfig& propConfig) { + auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]), + static_cast<size_t>(propConfig.configArray[1])); + + static std::vector<std::string> sampleDtcs = {"P0070", + "P0102" + "P0123"}; + for (auto&& dtc : sampleDtcs) { + auto freezeFrame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0); + sensorStore->fillPropValue(dtc, freezeFrame.get()); + freezeFrame->prop = OBD2_FREEZE_FRAME; + + mPropStore->writeValue(*freezeFrame); + } +} + +StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue, + VehiclePropValue* outValue) { + if (requestedPropValue.value.int64Values.size() != 1) { + ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp"); + return StatusCode::INVALID_ARG; + } + auto timestamp = requestedPropValue.value.int64Values[0]; + auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp); + if (freezeFrame == nullptr) { + ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); + return StatusCode::INVALID_ARG; + } + outValue->prop = OBD2_FREEZE_FRAME; + outValue->value.int32Values = freezeFrame->value.int32Values; + outValue->value.floatValues = freezeFrame->value.floatValues; + outValue->value.bytes = freezeFrame->value.bytes; + outValue->value.stringValue = freezeFrame->value.stringValue; + outValue->timestamp = freezeFrame->timestamp; + return StatusCode::OK; +} + +StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const VehiclePropValue& propValue) { + if (propValue.value.int64Values.size() == 0) { + mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME); + return StatusCode::OK; + } else { + for (int64_t timestamp : propValue.value.int64Values) { + auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp); + if (freezeFrame == nullptr) { + ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); + return StatusCode::INVALID_ARG; + } + mPropStore->removeValue(*freezeFrame); + } + } + return StatusCode::OK; +} + +StatusCode EmulatedVehicleHal::fillObd2DtcInfo(VehiclePropValue* outValue) { + std::vector<int64_t> timestamps; + for (const auto& freezeFrame : mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) { + timestamps.push_back(freezeFrame.timestamp); + } + outValue->value.int64Values = timestamps; + outValue->prop = OBD2_FREEZE_FRAME_INFO; + return StatusCode::OK; +} + } // impl } // namespace V2_0 diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index c25e0838c5..99d7edbc78 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -70,8 +70,15 @@ private: void onContinuousPropertyTimer(const std::vector<int32_t>& properties); bool isContinuousProperty(int32_t propId) const; - -private: + void initStaticConfig(); + void initObd2LiveFrame(const VehiclePropConfig& propConfig); + void initObd2FreezeFrame(const VehiclePropConfig& propConfig); + StatusCode fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue, + VehiclePropValue* outValue); + StatusCode fillObd2DtcInfo(VehiclePropValue* outValue); + StatusCode clearObd2FreezeFrames(const VehiclePropValue& propValue); + + /* Private members */ VehiclePropertyStore* mPropStore; std::unordered_set<int32_t> mHvacPowerProps; RecurrentTimer mRecurrentTimer; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp new file mode 100644 index 0000000000..ec352000c6 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp @@ -0,0 +1,27 @@ +// 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. + +// Vehicle HAL Protobuf library +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-libproto-native", + vendor: true, + proto: { + export_proto_headers: true, + type: "lite", + }, + strip: { + keep_symbols: true, + }, + srcs: ["VehicleHalProto.proto"] +} diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index f1fb6bf2b9..7c08b4a036 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -226,6 +226,50 @@ enum VehicleProperty: int32_t { | VehicleArea:GLOBAL), /** + * Reports wheel ticks + * + * The first four elements represent ticks for individual wheels in the + * following order: front left, front right, rear right, rear left. All + * tick counts are cumulative. Tick counts increment when the vehicle + * moves forward, and decrement when vehicles moves in reverse. The ticks + * should be reset to 0 when the vehicle is started by the user. + * + * The next element in the vector is a reset count. A reset indicates + * previous tick counts are not comparable with this and future ones. Some + * sort of discontinuity in tick counting has occurred. + * + * int64Values[0] = reset count + * int64Values[1] = front left ticks + * int64Values[2] = front right ticks + * int64Values[3] = rear right ticks + * int64Values[4] = rear left ticks + * + * configArray is used to indicate the micrometers-per-wheel-tick value as well as + * which wheels are supported. configArray is set as follows: + * + * configArray[0], bits [0:3] = supported wheels. Uses enum Wheel. + * configArray[1] = micrometers per front left wheel tick + * configArray[2] = micrometers per front right wheel tick + * configArray[3] = micrometers per rear right wheel tick + * configArray[4] = micrometers per rear left wheel tick + * + * NOTE: If a wheel is not supported, its value shall always be set to 0. + * + * VehiclePropValue.timestamp must be correctly filled in. + * + * @change_mode VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * + * @since o.mr1 + */ + WHEEL_TICK = ( + 0x0306 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + + /** * Currently selected gear * * @change_mode VehiclePropertyChangeMode:ON_CHANGE @@ -328,6 +372,34 @@ enum VehicleProperty: int32_t { | VehicleArea:GLOBAL), /** + * ABS is active. Set to true whenever ABS is activated. Reset to false when ABS is off. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * + * @since o.mr1 + */ + ABS_ACTIVE = ( + 0x040A + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /** + * Traction Control is active. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * + * @since o.mr1 + */ + TRACTION_CONTROL_ACTIVE = ( + 0x040B + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /** * Fan speed setting * * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not @@ -604,6 +676,24 @@ enum VehicleProperty: int32_t { | VehicleArea:ZONE), /** + * Represents power state for HVAC. Some HVAC properties must require + * matching power to be turned on to get out of OFF state. For non-zoned + * HVAC properties, VEHICLE_ALL_ZONE corresponds to global power state. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_string list of HVAC properties whose power is controlled by this + * property. Format is hexa-decimal number (0x...) separated + * by comma like "0x500,0x503". All zones defined in these + * affected properties must be available in the property. + */ + HVAC_POWER_ON = ( + 0x0510 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /** * Fan Positions Available * * This is a bit mask of fan positions available for the zone. Each entry in @@ -623,19 +713,18 @@ enum VehicleProperty: int32_t { | VehicleArea:ZONE), /** - * Represents power state for HVAC. Some HVAC properties must require - * matching power to be turned on to get out of OFF state. For non-zoned - * HVAC properties, VEHICLE_ALL_ZONE corresponds to global power state. + * Automatic re-circulation on/off + * + * IVehicle#set and IVehicle#get must return StatusCode::NOT_AVAILABLE when HVAC unit is off. + * See HVAC_POWER_ON property for details. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE - * @config_string list of HVAC properties whose power is controlled by this - * property. Format is hexa-decimal number (0x...) separated - * by comma like "0x500,0x503". All zones defined in these - * affected properties must be available in the property. + * + * @since o.mr1 */ - HVAC_POWER_ON = ( - 0x0510 + HVAC_AUTO_RECIRC_ON = ( + 0x0512 | VehiclePropertyGroup:SYSTEM | VehiclePropertyType:BOOLEAN | VehicleArea:ZONE), @@ -696,7 +785,8 @@ enum VehicleProperty: int32_t { * requested by Android side. The focus has both per stream characteristics * and global characteristics. * - * Focus request (get of this property) must take the following form: + * Focus request (get of this property) must take the following form with indices defined + * by VehicleAudioFocusIndex: * int32Values[0]: VehicleAudioFocusRequest type * int32Values[1]: bit flags of streams requested by this focus request. * There can be up to 32 streams. @@ -714,7 +804,7 @@ enum VehicleProperty: int32_t { * REQUEST_RELEASE). In that case, audio module must * maintain mute state until user's explicit action to * play some media. - * int32Values[3]: Currently active audio contexts. Use combination of + * int32Values[3]: Audio contexts wishing to be active. Use combination of * flags from VehicleAudioContextFlag. * This can be used as a hint to adjust audio policy or * other policy decision. @@ -729,7 +819,7 @@ enum VehicleProperty: int32_t { * request. * * Focus response (set and subscription callback for this property) must - * take the following form: + * take the following form with indices defined by VehicleAudioFocusIndex: * int32Values[0]: VehicleAudioFocusState type * int32Values[1]: bit flags of streams allowed. * int32Values[2]: External focus state: bit flags of currently active @@ -742,22 +832,26 @@ enum VehicleProperty: int32_t { * 0 means no active audio focus holder outside Android. * The state must have following values for each * VehicleAudioFocusState: - * GAIN: 0 or VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG - * when radio is active in Android side. - * GAIN_TRANSIENT: 0. Can be + * GAIN: VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG + * when radio is active in Android side. Otherwise, + * VehicleAudioExtFocusFlag#NONE_FLAG. + * GAIN_TRANSIENT: Can be * VehicleAudioExtFocusFlag#PERMANENT_FLAG or * VehicleAudioExtFocusFlag#TRANSIENT_FLAG if android * side has requested * REQUEST_GAIN_TRANSIENT_MAY_DUCK and car side is - * ducking. - * LOSS: 0 when no focus is audio is active in car side. + * ducking. Otherwise + * VehicleAudioExtFocusFlag#NONE_FLAG. + * LOSS: VehicleAudioExtFocusFlag#NONE_FLAG when no focus + * is active in car side. * VehicleAudioExtFocusFlag#PERMANENT_FLAG when car * side is playing something permanent. - * LOSS_TRANSIENT: always must be + * LOSS_TRANSIENT: must always be * VehicleAudioExtFocusFlag#PERMANENT_FLAG - * int32Values[3]: context requested by android side when responding to - * focus request. When car side is taking focus away, - * this must be zero. + * int32Values[3]: Audio context(s) allowed to be active. When responding positively to a + * focus request from Android, the request's original context must be + * repeated here. When taking focus away, or denying a request, the + * rejected or stopped context would have its corresponding bit cleared. * * A focus response must be sent per each focus request even if there is * no change in focus state. This can happen in case like focus request @@ -798,8 +892,8 @@ enum VehicleProperty: int32_t { * * VehiclePropConfig * configArray[0] : bit flags of all supported audio contexts from - * VehicleAudioContextFlag. If this is 0, audio volume is - * controlled per physical stream. + * VehicleAudioContextFlag. If this is 0, audio volume + * is controlled per physical stream. * configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag to * represent audio module's capability. * configArray[2..3] : reserved @@ -809,7 +903,7 @@ enum VehicleProperty: int32_t { * indicates mute state. * * Data type looks like: - * int32Values[0] : stream context as defined in VehicleAudioContextFlag. + * int32Values[0] : audio context as defined in VehicleAudioContextFlag. * If only physical stream is supported * (configArray[0] == 0), this must represent physical * stream number. @@ -817,8 +911,8 @@ enum VehicleProperty: int32_t { * defined in the config. * int32Values[2] : One of VehicleAudioVolumeState. * - * This property requires per stream based get. HAL implementation must - * check stream number in get call to return the right volume. + * HAL implementations must check the incoming value of audio context + * field in get call to return the right volume. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE @@ -857,18 +951,18 @@ enum VehicleProperty: int32_t { * to represent audio module's capability. * * Data type looks like: - * int32Values[0] : stream context as defined in VehicleAudioFocusFlag. + * int32Values[0] : audio context as defined in VehicleAudioContextFlag. * If only physical stream is supported * (configArray[0] == 0), this must represent physical * stream number. * int32Values[1] : maximum volume set to the stream. If there is no - * restriction, this value must be bigger than + * restriction, this value must be equal to * AUDIO_VOLUME's max value. * * If car does not support this feature, this property must not be * populated by HAL. - * This property requires per stream based get. HAL implementation must - * check stream number in get call to return the right volume. + * HAL implementations must check the incoming value of audio context + * field in get call to return the right volume. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE @@ -882,10 +976,8 @@ enum VehicleProperty: int32_t { /** * Property to share audio routing policy of android side. This property is - * set at the beginning to pass audio policy in android side down to + * set at startup to pass audio policy in android side down to * vehicle HAL and car audio module. - * This can be used as a hint to adjust audio policy or other policy - * decision. * * int32Values[0] : audio stream where the audio for the application * context must be routed by default. Note that this is @@ -893,7 +985,7 @@ enum VehicleProperty: int32_t { * still use different audio stream for whatever reason. * int32Values[1] : All audio contexts that must be sent through the * physical stream. Flag is defined in - * VehicleAudioFocusFlag. + * VehicleAudioContextFlag. * Setting of this property must be done for all available physical streams * based on audio H/W variant information acquired from AUDIO_HW_VARIANT @@ -909,11 +1001,11 @@ enum VehicleProperty: int32_t { | VehicleArea:GLOBAL), /** - * Property to return audio H/W variant type used in this car. This allows - * android side to support different audio policy based on H/W variant used. - * Note that other components like CarService may need overlay update to - * support additional variants. If this property does not - * exist, default audio policy must be used. + * Property to return audio H/W variant type used in this car. This is a + * zero based index into the set of audio routing policies defined in + * R.array.audioRoutingPolicy on CarService, which may be overlaid to + * support multiple variants. If this property does not exist, the default + * audio policy must be used. * * @change_mode VehiclePropertyChangeMode:STATIC * @access VehiclePropertyAccess:READ @@ -942,14 +1034,13 @@ enum VehicleProperty: int32_t { * for the routing. * This property can support up to 128 external routings. * To give full flexibility, there is no standard definition for each bit - * flag and assigning each big flag to specific routing type is decided by + * flag and assigning each bit flag to specific routing type is decided by * VehiclePropConfig#configString. VehiclePropConfig#configString has * format of each entry separated by ',' and each entry has format of * bitFlagPositon:typeString[:physicalStreamNumber]. - * bitFlagPosition: represents which big flag will be set to enable this - * routing. 0 means - * LSB in int32Values[0]. 31 will be MSB in int32Values[0]. 127 will MSB - * in int32Values[3]. + * bitFlagPosition: represents which bit flag will be set to enable this + * routing. 0 means LSB in int32Values[0]. 31 will be MSB in + * int32Values[0]. 127 will MSB in int32Values[3]. * typeString: string representation of external routing. Some types are * already defined in AUDIO_EXT_ROUTING_SOURCE_* and use them first * before adding something custom. Applications will find each routing @@ -1126,10 +1217,11 @@ enum VehicleProperty: int32_t { * change. Instrument cluster still needs to send * event with new mode to trigger actual mode change. * int32Values[1] : The current app context relevant for instrument - * cluster. Use the same flag with VehicleAudioFocusFlag - * but this context represents active apps, not - * active audio. Instrument cluster side may change mode - * depending on the currently active contexts. + * cluster. Use the same flag with + * VehicleAudioContextFlag but this context represents + * active apps, not active audio. Instrument cluster + * side may change mode depending on the currently + * active contexts. * When system boots up, Android side will write {0, 0, 0, 0} when it is * ready to render to instrument cluster. Before this message, rendering * from android must not be visible in the cluster. @@ -1790,85 +1882,240 @@ enum VehicleProperty: int32_t { | VehiclePropertyGroup:SYSTEM | VehiclePropertyType:BOOLEAN | VehicleArea:GLOBAL), + + + /** + * Vehicle Maps Service (VMS) message + * + * This property uses COMPLEX data to communicate vms messages. + * + * Its contents are to be interpreted as follows: + * the indices defined in VmsMessageIntegerValuesIndex are to be used to + * read from int32Values; + * bytes is a serialized VMS message as defined in the vms protocol + * which is opaque to the framework; + * + * IVehicle#get must always return StatusCode::NOT_AVAILABLE. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * + * @since o.mr1 + */ + VEHICLE_MAP_SERVICE = ( + 0x0C00 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /** + * OBD2 Live Sensor Data + * + * Reports a snapshot of the current (live) values of the OBD2 sensors available. + * + * The configArray is set as follows: + * configArray[0] = number of vendor-specific integer-valued sensors + * configArray[1] = number of vendor-specific float-valued sensors + * + * The values of this property are to be interpreted as in the following example. + * Considering a configArray = {2,3} + * int32Values must be a vector containing Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + 2 + * elements (that is, 33 elements); + * floatValues must be a vector containing Obd2FloatSensorIndex.LAST_SYSTEM_INDEX + 3 + * elements (that is, 73 elements); + * + * It is possible for each frame to contain a different subset of sensor values, both system + * provided sensors, and vendor-specific ones. In order to support that, the bytes element + * of the property value is used as a bitmask,. + * + * bytes must have a sufficient number of bytes to represent the total number of possible + * sensors (in this case, 14 bytes to represent 106 possible values); it is to be read as + * a contiguous bitmask such that each bit indicates the presence or absence of a sensor + * from the frame, starting with as many bits as the size of int32Values, immediately + * followed by as many bits as the size of floatValues. + * + * For example, should bytes[0] = 0x4C (0b01001100) it would mean that: + * int32Values[0 and 1] are not valid sensor values + * int32Values[2 and 3] are valid sensor values + * int32Values[4 and 5] are not valid sensor values + * int32Values[6] is a valid sensor value + * int32Values[7] is not a valid sensor value + * Should bytes[5] = 0x61 (0b01100001) it would mean that: + * int32Values[32] is a valid sensor value + * floatValues[0 thru 3] are not valid sensor values + * floatValues[4 and 5] are valid sensor values + * floatValues[6] is not a valid sensor value + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * + * @since o.mr1 + */ + OBD2_LIVE_FRAME = ( + 0x0D00 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /** + * OBD2 Freeze Frame Sensor Data + * + * Reports a snapshot of the value of the OBD2 sensors available at the time that a fault + * occurred and was detected. + * + * A configArray must be provided with the same meaning as defined for OBD2_LIVE_FRAME. + * + * The values of this property are to be interpreted in a similar fashion as those for + * OBD2_LIVE_FRAME, with the exception that the stringValue field may contain a non-empty + * diagnostic troubleshooting code (DTC). + * + * A IVehicle#get request of this property must provide a value for int64Values[0]. + * This will be interpreted as the timestamp of the freeze frame to retrieve. A list of + * timestamps can be obtained by a IVehicle#get of OBD2_FREEZE_FRAME_INFO. + * + * Should no freeze frame be available at the given timestamp, a response of NOT_AVAILABLE + * must be returned by the implementation. Because vehicles may have limited storage for + * freeze frames, it is possible for a frame request to respond with NOT_AVAILABLE even if + * the associated timestamp has been recently obtained via OBD2_FREEZE_FRAME_INFO. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * + * @since o.mr1 + */ + OBD2_FREEZE_FRAME = ( + 0x0D01 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /** + * OBD2 Freeze Frame Information + * + * This property describes the current freeze frames stored in vehicle + * memory and available for retrieval via OBD2_FREEZE_FRAME. + * + * The values are to be interpreted as follows: + * each element of int64Values must be the timestamp at which a a fault code + * has been detected and the corresponding freeze frame stored, and each + * such element can be used as the key to OBD2_FREEZE_FRAME to retrieve + * the corresponding freeze frame. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * + * @since o.mr1 + */ + OBD2_FREEZE_FRAME_INFO = ( + 0x0D02 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /** + * OBD2 Freeze Frame Clear + * + * This property allows deletion of any of the freeze frames stored in + * vehicle memory, as described by OBD2_FREEZE_FRAME_INFO. + * + * The configArray is set as follows: + * configArray[0] = 1 if the implementation is able to clear individual freeze frames + * by timestamp, 0 otherwise + * + * IVehicle#set of this property is to be interpreted as follows: + * if int64Values contains no elements, then all frames stored must be cleared; + * if int64Values contains one or more elements, then frames at the timestamps + * stored in int64Values must be cleared, and the others not cleared. Should the + * vehicle not support selective clearing of freeze frames, this latter mode must + * return NOT_AVAILABLE. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:WRITE + * + * @since o.mr1 + */ + OBD2_FREEZE_FRAME_CLEAR = ( + 0x0D03 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), }; /** * Bit flags for fan direction */ enum VehicleHvacFanDirection : int32_t { - FACE = 0x1, - FLOOR = 0x2, - FACE_AND_FLOOR = 0x3, - DEFROST = 0x4, - DEFROST_AND_FLOOR = 0x5, + FACE = 0x1, + FLOOR = 0x2, + FACE_AND_FLOOR = 0x3, + DEFROST = 0x4, + DEFROST_AND_FLOOR = 0x5, }; /** * Constants relevant to radio. */ enum VehicleRadioConstants : int32_t { - /** Minimum value for the radio preset */ - VEHICLE_RADIO_PRESET_MIN_VALUE = 1, + /** Minimum value for the radio preset */ + VEHICLE_RADIO_PRESET_MIN_VALUE = 1, }; enum VehicleAudioFocusRequest : int32_t { - REQUEST_GAIN = 0x1, - REQUEST_GAIN_TRANSIENT = 0x2, - REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3, - /** - * This is for the case where android side plays sound like UI feedback - * and car side does not need to duck existing playback as long as - * requested stream is available. - */ - REQUEST_GAIN_TRANSIENT_NO_DUCK = 0x4, - REQUEST_RELEASE = 0x5, - + REQUEST_GAIN = 0x1, + REQUEST_GAIN_TRANSIENT = 0x2, + REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3, + /** + * This is for the case where android side plays sound like UI feedback + * and car side does not need to duck existing playback as long as + * requested stream is available. + */ + REQUEST_GAIN_TRANSIENT_NO_DUCK = 0x4, + REQUEST_RELEASE = 0x5, }; enum VehicleAudioFocusState : int32_t { - /** - * Android side has permanent focus and can play allowed streams. - */ - STATE_GAIN = 0x1, - - /** - * Android side has transient focus and can play allowed streams. - */ - STATE_GAIN_TRANSIENT = 0x2, + /** + * Android side has permanent focus and can play allowed streams. + */ + STATE_GAIN = 0x1, - /** - * Car audio module is playing guidance kind of sound outside Android. - * Android side can still play through allowed streams with ducking. - */ - STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3, + /** + * Android side has transient focus and can play allowed streams. + */ + STATE_GAIN_TRANSIENT = 0x2, - /** - * Car audio module is playing transient sound outside Android. Android side - * must stop playing any sounds. - */ - STATE_LOSS_TRANSIENT = 0x4, + /** + * Car audio module is playing guidance kind of sound outside Android. + * Android side can still play through allowed streams with ducking. + */ + STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3, - /** - * Android side has lost focus and cannot play any sound. - */ - STATE_LOSS = 0x5, + /** + * Car audio module is playing transient sound outside Android. Android side + * must stop playing any sounds. + */ + STATE_LOSS_TRANSIENT = 0x4, - /** - * car audio module is playing safety critical sound, and Android side cannot - * request focus until the current state is finished. car audio module - * restore it to the previous state when it can allow Android to play. - */ - STATE_LOSS_TRANSIENT_EXLCUSIVE = 0x6, + /** + * Android side has lost focus and cannot play any sound. + */ + STATE_LOSS = 0x5, + /** + * car audio module is playing safety critical sound, and Android side cannot + * request focus until the current state is finished. car audio module + * restore it to the previous state when it can allow Android to play. + */ + STATE_LOSS_TRANSIENT_EXLCUSIVE = 0x6, }; /** * Flags to represent multiple streams by combining these. */ enum VehicleAudioStreamFlag : int32_t { - STREAM0_FLAG = (0x1 << 0), - STREAM1_FLAG = (0x1 << 1), - STREAM2_FLAG = (0x1 << 2), + STREAM0_FLAG = (0x1 << 0), + STREAM1_FLAG = (0x1 << 1), + STREAM2_FLAG = (0x1 << 2), }; /** @@ -1876,107 +2123,110 @@ enum VehicleAudioStreamFlag : int32_t { * Can be used for audio related property expecting one stream. */ enum VehicleAudioStream : int32_t { - STREAM0 = 0, - STREAM1 = 1, + STREAM0 = 0, + STREAM1 = 1, }; /** * Flag to represent external focus state (outside Android). */ enum VehicleAudioExtFocusFlag : int32_t { - /** - * No external focus holder. - */ - NONE_FLAG = 0x0, + /** + * No external focus holder. + */ + NONE_FLAG = 0x0, - /** - * Car side (outside Android) has component holding GAIN kind of focus state. - */ - PERMANENT_FLAG = 0x1, + /** + * Car side (outside Android) has component holding GAIN kind of focus state. + */ + PERMANENT_FLAG = 0x1, - /** - * Car side (outside Android) has component holding GAIN_TRANSIENT kind of - * focus state. - */ - TRANSIENT_FLAG = 0x2, + /** + * Car side (outside Android) has component holding GAIN_TRANSIENT kind of + * focus state. + */ + TRANSIENT_FLAG = 0x2, - /** - * Car side is expected to play something while focus is held by Android side. - * One example can be radio attached in car side. But Android's radio app - * still must have focus, and Android side must be in GAIN state, but - * media stream will not be allocated to Android side and car side can play - * radio any time while this flag is active. - */ - PLAY_ONLY_FLAG = 0x4, + /** + * Car side is expected to play something while focus is held by Android side. + * One example can be radio attached in car side. But Android's radio app + * still must have focus, and Android side must be in GAIN state, but + * media stream will not be allocated to Android side and car side can play + * radio any time while this flag is active. + */ + PLAY_ONLY_FLAG = 0x4, - /** - * Car side must mute any media including radio. This can be used with any - * focus request including GAIN* and RELEASE. - */ - MUTE_MEDIA_FLAG = 0x8, + /** + * Car side must mute any media including radio. This can be used with any + * focus request including GAIN* and RELEASE. + */ + MUTE_MEDIA_FLAG = 0x8, }; /** * Index in int32Values for VehicleProperty#AUDIO_FOCUS property. */ enum VehicleAudioFocusIndex : int32_t { - FOCUS = 0, - STREAMS = 1, - EXTERNAL_FOCUS_STATE = 2, - AUDIO_CONTEXTS = 3, + FOCUS = 0, + STREAMS = 1, + EXTERNAL_FOCUS_STATE = 2, + AUDIO_CONTEXTS = 3, }; /** * Flags to tell the current audio context. */ enum VehicleAudioContextFlag : int32_t { - /** Music playback is currently active. */ - MUSIC_FLAG = 0x1, + /** Music playback is currently active. */ + MUSIC_FLAG = 0x1, - /** Navigation is currently running. */ - NAVIGATION_FLAG = 0x2, + /** Navigation is currently running. */ + NAVIGATION_FLAG = 0x2, - /** Voice command session is currently running. */ - VOICE_COMMAND_FLAG = 0x4, + /** Voice command session is currently running. */ + VOICE_COMMAND_FLAG = 0x4, - /** Voice call is currently active. */ - CALL_FLAG = 0x8, + /** Voice call is currently active. */ + CALL_FLAG = 0x8, - /** - * Alarm is active. - * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY. - */ - ALARM_FLAG = 0x10, + /** + * Alarm is active. + * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY. + */ + ALARM_FLAG = 0x10, - /** - * Notification sound is active. - * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY. - */ - NOTIFICATION_FLAG = 0x20, + /** + * Notification sound is active. + * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY. + */ + NOTIFICATION_FLAG = 0x20, - /** - * Context unknown. Only used for VehicleProperty#AUDIO_ROUTING_POLICY to - * represent default stream for unknown contents. - */ - UNKNOWN_FLAG = 0x40, + /** + * Context unknown. Only used for VehicleProperty#AUDIO_ROUTING_POLICY to + * represent default stream for unknown contents. + */ + UNKNOWN_FLAG = 0x40, + + /** Safety alert / warning is played. */ + SAFETY_ALERT_FLAG = 0x80, - /** Safety alert / warning is played. */ - SAFETY_ALERT_FLAG = 0x80, + /** CD / DVD kind of audio is played */ + CD_ROM_FLAG = 0x100, - /** CD / DVD kind of audio is played */ - CD_ROM_FLAG = 0x100, + /** Aux audio input is played */ + AUX_AUDIO_FLAG = 0x200, - /** Aux audio input is played */ - AUX_AUDIO_FLAG = 0x200, + /** system sound like UI feedback */ + SYSTEM_SOUND_FLAG = 0x400, - /** system sound like UI feedback */ - SYSTEM_SOUND_FLAG = 0x400, + /** Radio is played */ + RADIO_FLAG = 0x800, - /** Radio is played */ - RADIO_FLAG = 0x800, + /** Ext source is played. This is for tagging generic ext sources. */ + EXT_SOURCE_FLAG = 0x1000, - /** Ext source is played. This is for tagging generic ext sources. */ - EXT_SOURCE_FLAG = 0x1000, + /** The phone ring tone is played */ + RINGTONE_FLAG = 0x2000 }; /** @@ -1984,65 +2234,65 @@ enum VehicleAudioContextFlag : int32_t { * used in configArray[1] of VehiclePropConfig. */ enum VehicleAudioVolumeCapabilityFlag : int32_t { - /** - * External audio module or vehicle hal has persistent storage - * to keep the volume level. This must be set only when per context - * volume level is supported. When this is set, audio volume level per - * each context will be retrieved from the property when system starts up. - * And external audio module is also expected to adjust volume automatically - * whenever there is an audio context change. - * When this flag is not set, android side will assume that there is no - * persistent storage and stored value in android side will be used to - * initialize the volume level. And android side will set volume level - * of each physical streams whenever there is an audio context change. - */ - PERSISTENT_STORAGE = 0x1, + /** + * External audio module or vehicle hal has persistent storage to keep the + * volume level. When this is set, the audio volume level for each context + * will be retrieved from the property when the system starts up. + * And external audio module is also expected to adjust volume automatically + * whenever there is an audio context change. + * When this flag is not set, android side will assume that there is no + * persistent storage and the value stored in the android side will be used to + * initialize the volume level, and android side will set volume level + * of each physical stream whenever there is an audio context change. + */ + PERSISTENT_STORAGE = 0x1, - /** - * When this flag is set, the H/W can support only single master volume for - * all streams. - * There is no way to set volume level differently per each stream or context. - */ - MASTER_VOLUME_ONLY = 0x2, + /** + * [DEPRECATED] + * When this flag is set, the H/W can support only single master volume for + * all streams. There is no way to set volume level differently for each stream + * or context. + */ + MASTER_VOLUME_ONLY = 0x2, }; /** * enum to represent audio volume state. */ enum VehicleAudioVolumeState : int32_t { - STATE_OK = 0, + STATE_OK = 0, - /** - * Audio volume has reached volume limit set in - * VehicleProperty#AUDIO_VOLUME_LIMIT and user's request to increase volume - * further is not allowed. - */ - LIMIT_REACHED = 1, + /** + * Audio volume has reached volume limit set in + * VehicleProperty#AUDIO_VOLUME_LIMIT and user's request to increase volume + * further is not allowed. + */ + STATE_LIMIT_REACHED = 1, }; /** * Index in int32Values for VehicleProperty#AUDIO_VOLUME property. */ enum VehicleAudioVolumeIndex : int32_t { - INDEX_STREAM = 0, - INDEX_VOLUME = 1, - INDEX_STATE = 2, + STREAM = 0, + VOLUME = 1, + STATE = 2, }; /** * Index in int32Values for VehicleProperty#AUDIO_VOLUME_LIMIT property. */ enum VehicleAudioVolumeLimitIndex : int32_t { - STREAM = 0, - MAX_VOLUME = 1, + STREAM = 0, + MAX_VOLUME = 1, }; /** * Index in int32Values for VehicleProperty#AUDIO_ROUTING_POLICY property. */ enum VehicleAudioRoutingPolicyIndex : int32_t { - STREAM = 0, - CONTEXTS = 1, + STREAM = 0, + CONTEXTS = 1, }; /** @@ -2054,172 +2304,172 @@ enum VehicleAudioHwVariantConfigFlag : int32_t { * Flag to tell that radio is internal to android and radio must * be treated like other android stream like media. * When this flag is not set or AUDIO_HW_VARIANT does not exist, - * radio is treated as external module. This brins some delta in audio focus + * radio is treated as external module. This may affect audio focus * handling as well. */ INTERNAL_RADIO_FLAG = 0x1, }; enum VehicleApPowerStateConfigFlag : int32_t /* NOTE: type is guessed */ { - /** - * AP can enter deep sleep state. If not set, AP will always shutdown from - * VehicleApPowerState#SHUTDOWN_PREPARE power state. - */ - ENABLE_DEEP_SLEEP_FLAG = 0x1, + /** + * AP can enter deep sleep state. If not set, AP will always shutdown from + * VehicleApPowerState#SHUTDOWN_PREPARE power state. + */ + ENABLE_DEEP_SLEEP_FLAG = 0x1, - /** - * The power controller can power on AP from off state after timeout - * specified in VehicleApPowerSet VEHICLE_AP_POWER_SET_SHUTDOWN_READY message. - */ - CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2, + /** + * The power controller can power on AP from off state after timeout + * specified in VehicleApPowerSet VEHICLE_AP_POWER_SET_SHUTDOWN_READY message. + */ + CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2, }; enum VehicleApPowerState : int32_t /* NOTE: type is guessed */ { - /** vehicle HAL will never publish this state to AP */ - OFF = 0, + /** vehicle HAL will never publish this state to AP */ + OFF = 0, - /** vehicle HAL will never publish this state to AP */ - DEEP_SLEEP = 1, + /** vehicle HAL will never publish this state to AP */ + DEEP_SLEEP = 1, - /** AP is on but display must be off. */ - ON_DISP_OFF = 2, + /** AP is on but display must be off. */ + ON_DISP_OFF = 2, - /** AP is on with display on. This state allows full user interaction. */ - ON_FULL = 3, + /** AP is on with display on. This state allows full user interaction. */ + ON_FULL = 3, - /** - * The power controller has requested AP to shutdown. AP can either enter - * sleep state or start full shutdown. AP can also request postponing - * shutdown by sending VehicleApPowerSetState#SHUTDOWN_POSTPONE message. The - * power controller must change power state to this state to shutdown - * system. - * - * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type - */ - SHUTDOWN_PREPARE = 4, + /** + * The power controller has requested AP to shutdown. AP can either enter + * sleep state or start full shutdown. AP can also request postponing + * shutdown by sending VehicleApPowerSetState#SHUTDOWN_POSTPONE message. The + * power controller must change power state to this state to shutdown + * system. + * + * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type + */ + SHUTDOWN_PREPARE = 4, }; enum VehicleApPowerStateShutdownParam : int32_t { - /** AP must shutdown immediately. Postponing is not allowed. */ - SHUTDOWN_IMMEDIATELY = 1, + /** AP must shutdown immediately. Postponing is not allowed. */ + SHUTDOWN_IMMEDIATELY = 1, - /** AP can enter deep sleep instead of shutting down completely. */ - CAN_SLEEP = 2, + /** AP can enter deep sleep instead of shutting down completely. */ + CAN_SLEEP = 2, - /** AP can only shutdown with postponing allowed. */ - SHUTDOWN_ONLY = 3, + /** AP can only shutdown with postponing allowed. */ + SHUTDOWN_ONLY = 3, }; enum VehicleApPowerSetState : int32_t /* NOTE: type is guessed */ { - /** - * AP has finished boot up, and can start shutdown if requested by power - * controller. - */ - BOOT_COMPLETE = 0x1, + /** + * AP has finished boot up, and can start shutdown if requested by power + * controller. + */ + BOOT_COMPLETE = 0x1, - /** - * AP is entering deep sleep state. How this state is implemented may vary - * depending on each H/W, but AP's power must be kept in this state. - */ - DEEP_SLEEP_ENTRY = 0x2, + /** + * AP is entering deep sleep state. How this state is implemented may vary + * depending on each H/W, but AP's power must be kept in this state. + */ + DEEP_SLEEP_ENTRY = 0x2, - /** - * AP is exiting from deep sleep state, and is in - * VehicleApPowerState#SHUTDOWN_PREPARE state. - * The power controller may change state to other ON states based on the - * current state. - */ - DEEP_SLEEP_EXIT = 0x3, + /** + * AP is exiting from deep sleep state, and is in + * VehicleApPowerState#SHUTDOWN_PREPARE state. + * The power controller may change state to other ON states based on the + * current state. + */ + DEEP_SLEEP_EXIT = 0x3, - /** - * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be - * 5000 ms. - * If AP needs more time, it will send another POSTPONE - * message before the previous one expires. - */ - SHUTDOWN_POSTPONE = 0x4, + /** + * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be + * 5000 ms. + * If AP needs more time, it will send another POSTPONE + * message before the previous one expires. + */ + SHUTDOWN_POSTPONE = 0x4, - /** - * AP is starting shutting down. When system completes shutdown, everything - * will stop in AP as kernel will stop all other contexts. It is - * responsibility of vehicle HAL or lower level to synchronize that state - * with external power controller. As an example, some kind of ping - * with timeout in power controller can be a solution. - * - * int32Values[1]: Time to turn on AP in secs. Power controller may turn on - * AP after specified time so that AP can run tasks like - * update. If it is set to 0, there is no wake up, and power - * controller may not necessarily support wake-up. If power - * controller turns on AP due to timer, it must start with - * VehicleApPowerState#ON_DISP_OFF state, and after - * receiving VehicleApPowerSetState#BOOT_COMPLETE, it shall - * do state transition to - * VehicleApPowerState#SHUTDOWN_PREPARE. - */ - SHUTDOWN_START = 0x5, + /** + * AP is starting shutting down. When system completes shutdown, everything + * will stop in AP as kernel will stop all other contexts. It is + * responsibility of vehicle HAL or lower level to synchronize that state + * with external power controller. As an example, some kind of ping + * with timeout in power controller can be a solution. + * + * int32Values[1]: Time to turn on AP in secs. Power controller may turn on + * AP after specified time so that AP can run tasks like + * update. If it is set to 0, there is no wake up, and power + * controller may not necessarily support wake-up. If power + * controller turns on AP due to timer, it must start with + * VehicleApPowerState#ON_DISP_OFF state, and after + * receiving VehicleApPowerSetState#BOOT_COMPLETE, it shall + * do state transition to + * VehicleApPowerState#SHUTDOWN_PREPARE. + */ + SHUTDOWN_START = 0x5, - /** - * User has requested to turn off headunit's display, which is detected in - * android side. - * The power controller may change the power state to - * VehicleApPowerState#ON_DISP_OFF. - */ - DISPLAY_OFF = 0x6, + /** + * User has requested to turn off headunit's display, which is detected in + * android side. + * The power controller may change the power state to + * VehicleApPowerState#ON_DISP_OFF. + */ + DISPLAY_OFF = 0x6, - /** - * User has requested to turn on headunit's display, most probably from power - * key input which is attached to headunit. The power controller may change - * the power state to VehicleApPowerState#ON_FULL. - */ - DISPLAY_ON = 0x7, + /** + * User has requested to turn on headunit's display, most probably from power + * key input which is attached to headunit. The power controller may change + * the power state to VehicleApPowerState#ON_FULL. + */ + DISPLAY_ON = 0x7, }; /** * Index in int32Values for VehicleProperty#AP_POWER_STATE property. */ enum VehicleApPowerStateIndex : int32_t { - STATE = 0, - ADDITIONAL = 1, + STATE = 0, + ADDITIONAL = 1, }; /** * Enum to represent bootup reason. */ enum VehicleApPowerBootupReason : int32_t { - /** - * Power on due to user's pressing of power key or rotating of ignition - * switch. - */ - USER_POWER_ON = 0, + /** + * Power on due to user's pressing of power key or rotating of ignition + * switch. + */ + USER_POWER_ON = 0, - /** - * Automatic power on triggered by door unlock or any other kind of automatic - * user detection. - */ - USER_UNLOCK = 1, + /** + * Automatic power on triggered by door unlock or any other kind of automatic + * user detection. + */ + USER_UNLOCK = 1, - /** - * Automatic power on triggered by timer. This only happens when AP has asked - * wake-up after - * certain time through time specified in - * VehicleApPowerSetState#SHUTDOWN_START. - */ - TIMER = 2, + /** + * Automatic power on triggered by timer. This only happens when AP has asked + * wake-up after + * certain time through time specified in + * VehicleApPowerSetState#SHUTDOWN_START. + */ + TIMER = 2, }; enum VehicleHwKeyInputAction : int32_t { - /** Key down */ - ACTION_DOWN = 0, + /** Key down */ + ACTION_DOWN = 0, - /** Key up */ - ACTION_UP = 1, + /** Key up */ + ACTION_UP = 1, }; enum VehicleDisplay : int32_t { - /** center console */ - MAIN = 0, + /** center console */ + MAIN = 0, - INSTRUMENT_CLUSTER = 1, + INSTRUMENT_CLUSTER = 1, }; /** @@ -2312,11 +2562,11 @@ enum VehiclePropertyChangeMode : int32_t { * the expected output. */ enum VehiclePropertyAccess : int32_t { - NONE = 0x00, + NONE = 0x00, - READ = 0x01, - WRITE = 0x02, - READ_WRITE = 0x03, + READ = 0x01, + WRITE = 0x02, + READ_WRITE = 0x03, }; /** @@ -2325,32 +2575,32 @@ enum VehiclePropertyAccess : int32_t { * The driving states determine what features of the UI will be accessible. */ enum VehicleDrivingStatus : int32_t { - UNRESTRICTED = 0x00, - NO_VIDEO = 0x01, - NO_KEYBOARD_INPUT = 0x02, - NO_VOICE_INPUT = 0x04, - NO_CONFIG = 0x08, - LIMIT_MESSAGE_LEN = 0x10, + UNRESTRICTED = 0x00, + NO_VIDEO = 0x01, + NO_KEYBOARD_INPUT = 0x02, + NO_VOICE_INPUT = 0x04, + NO_CONFIG = 0x08, + LIMIT_MESSAGE_LEN = 0x10, }; /** * Various gears which can be selected by user and chosen in system. */ enum VehicleGear: int32_t { - GEAR_NEUTRAL = 0x0001, - GEAR_REVERSE = 0x0002, - GEAR_PARK = 0x0004, - GEAR_DRIVE = 0x0008, - GEAR_LOW = 0x0010, - GEAR_1 = 0x0010, - GEAR_2 = 0x0020, - GEAR_3 = 0x0040, - GEAR_4 = 0x0080, - GEAR_5 = 0x0100, - GEAR_6 = 0x0200, - GEAR_7 = 0x0400, - GEAR_8 = 0x0800, - GEAR_9 = 0x1000, + GEAR_NEUTRAL = 0x0001, + GEAR_REVERSE = 0x0002, + GEAR_PARK = 0x0004, + GEAR_DRIVE = 0x0008, + GEAR_LOW = 0x0010, + GEAR_1 = 0x0010, + GEAR_2 = 0x0020, + GEAR_3 = 0x0040, + GEAR_4 = 0x0080, + GEAR_5 = 0x0100, + GEAR_6 = 0x0200, + GEAR_7 = 0x0400, + GEAR_8 = 0x0800, + GEAR_9 = 0x1000, }; /** @@ -2610,73 +2860,73 @@ enum VehiclePropertyOperation : int32_t { enum SubscribeFlags : int32_t { - UNDEFINED = 0x0, + UNDEFINED = 0x0, - /** - * Subscribe to event that was originated in vehicle HAL - * (most likely this event came from the vehicle itself). - */ - HAL_EVENT = 0x1, + /** + * Subscribe to event that was originated in vehicle HAL + * (most likely this event came from the vehicle itself). + */ + HAL_EVENT = 0x1, - /** - * Use this flag to subscribe on events when IVehicle#set(...) was called by - * vehicle HAL's client (e.g. Car Service). - */ - SET_CALL = 0x2, + /** + * Use this flag to subscribe on events when IVehicle#set(...) was called by + * vehicle HAL's client (e.g. Car Service). + */ + SET_CALL = 0x2, - DEFAULT = HAL_EVENT, + DEFAULT = HAL_EVENT, }; /** * Encapsulates information about subscription to vehicle property events. */ struct SubscribeOptions { - /** Property to subscribe */ - int32_t propId; + /** Property to subscribe */ + int32_t propId; - /** - * Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe - * to all areas. - */ - int32_t vehicleAreas; + /** + * Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe + * to all areas. + */ + int32_t vehicleAreas; - /** - * Sample rate in Hz. - * - * Must be provided for properties with - * VehiclePropertyChangeMode::CONTINUOUS. The value must be within - * VehiclePropConfig#minSamplingRate .. VehiclePropConfig#maxSamplingRate - * for a given property. - * This value indicates how many updates per second client wants to receive. - */ - float sampleRate; + /** + * Sample rate in Hz. + * + * Must be provided for properties with + * VehiclePropertyChangeMode::CONTINUOUS. The value must be within + * VehiclePropConfig#minSamplingRate .. VehiclePropConfig#maxSamplingRate + * for a given property. + * This value indicates how many updates per second client wants to receive. + */ + float sampleRate; - /** Flags that indicate what kind of events listen to. */ - SubscribeFlags flags; + /** Flags that indicate what kind of events listen to. */ + SubscribeFlags flags; }; /** Error codes used in vehicle HAL interface. */ enum StatusCode : int32_t { - OK = 0, + OK = 0, - /** Try again. */ - TRY_AGAIN = 1, + /** Try again. */ + TRY_AGAIN = 1, - /** Invalid argument provided. */ - INVALID_ARG = 2, + /** Invalid argument provided. */ + INVALID_ARG = 2, - /** - * This code must be returned when device that associated with the vehicle - * property is not available. For example, when client tries to set HVAC - * temperature when the whole HVAC unit is turned OFF. - */ - NOT_AVAILABLE = 3, + /** + * This code must be returned when device that associated with the vehicle + * property is not available. For example, when client tries to set HVAC + * temperature when the whole HVAC unit is turned OFF. + */ + NOT_AVAILABLE = 3, - /** Access denied */ - ACCESS_DENIED = 4, + /** Access denied */ + ACCESS_DENIED = 4, - /** Something unexpected has happened in Vehicle HAL */ - INTERNAL_ERROR = 5, + /** Something unexpected has happened in Vehicle HAL */ + INTERNAL_ERROR = 5, }; enum Wheel : int32_t { @@ -2687,3 +2937,460 @@ enum Wheel : int32_t { LEFT_REAR = 0x4, RIGHT_REAR = 0x8, }; + +/** + * The status of the vehicle's fuel system. + * These values come from the SAE J1979 standard. + */ +enum Obd2FuelSystemStatus : int32_t { + OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1, + CLOSED_LOOP = 2, + OPEN_ENGINE_LOAD_OR_DECELERATION = 4, + OPEN_SYSTEM_FAILURE = 8, + CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16, +}; + +/** Defines which ignition monitors are available to be read. */ +enum Obd2IgnitionMonitorKind : int32_t { + SPARK = 0, + COMPRESSION = 1, +}; + +/** + * Ignition monitors common to both SPARK and COMPRESSION. + * These values come from the SAE J1979 standard. + */ +enum Obd2CommonIgnitionMonitors : int32_t { + COMPONENTS_AVAILABLE = 0x1 << 0, + COMPONENTS_INCOMPLETE = 0x1 << 1, + + FUEL_SYSTEM_AVAILABLE = 0x1 << 2, + FUEL_SYSTEM_INCOMPLETE = 0x1 << 3, + + MISFIRE_AVAILABLE = 0x1 << 4, + MISFIRE_INCOMPLETE = 0x1 << 5, +}; + +/** + * Ignition monitors available for SPARK vehicles. + * These values come from the SAE J1979 standard. + */ +enum Obd2SparkIgnitionMonitors : Obd2CommonIgnitionMonitors { + EGR_AVAILABLE = 0x1 << 6, + EGR_INCOMPLETE = 0x1 << 7, + + OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8, + OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9, + + OXYGEN_SENSOR_AVAILABLE = 0x1 << 10, + OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11, + + AC_REFRIGERANT_AVAILABLE = 0x1 << 12, + AC_REFRIGERANT_INCOMPLETE = 0x1 << 13, + + SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14, + SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15, + + EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16, + EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17, + + HEATED_CATALYST_AVAILABLE = 0x1 << 18, + HEATED_CATALYST_INCOMPLETE = 0x1 << 19, + + CATALYST_AVAILABLE = 0x1 << 20, + CATALYST_INCOMPLETE = 0x1 << 21, +}; + +/** + * Ignition monitors only available for COMPRESSION vehicles. + * These values come from the SAE J1979 standard. + */ +enum Obd2CompressionIgnitionMonitors : Obd2CommonIgnitionMonitors { + EGR_OR_VVT_AVAILABLE = 0x1 << 6, + EGR_OR_VVT_INCOMPLETE = 0x1 << 7, + + PM_FILTER_AVAILABLE = 0x1 << 8, + PM_FILTER_INCOMPLETE = 0x1 << 9, + + EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10, + EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11, + + BOOST_PRESSURE_AVAILABLE = 0x1 << 12, + BOOST_PRESSURE_INCOMPLETE = 0x1 << 13, + + NOx_SCR_AVAILABLE = 0x1 << 14, + NOx_SCR_INCOMPLETE = 0x1 << 15, + + NMHC_CATALYST_AVAILABLE = 0x1 << 16, + NMHC_CATALYST_INCOMPLETE = 0x1 << 17, +}; + +/** + * The status of the vehicle's secondary air system. + * These values come from the SAE J1979 standard. + */ +enum Obd2SecondaryAirStatus : int32_t { + UPSTREAM = 1, + DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2, + FROM_OUTSIDE_OR_OFF = 4, + PUMP_ON_FOR_DIAGNOSTICS = 8, +}; + +/** + * The fuel type(s) supported by a vehicle. + * These values come from the SAE J1979 standard. + */ +enum Obd2FuelType : int32_t { + NOT_AVAILABLE = 0, + GASOLINE = 1, + METHANOL = 2, + ETHANOL = 3, + DIESEL = 4, + LPG = 5, + CNG = 6, + PROPANE = 7, + ELECTRIC = 8, + BIFUEL_RUNNING_GASOLINE = 9, + BIFUEL_RUNNING_METHANOL = 10, + BIFUEL_RUNNING_ETHANOL = 11, + BIFUEL_RUNNING_LPG = 12, + BIFUEL_RUNNING_CNG = 13, + BIFUEL_RUNNING_PROPANE = 14, + BIFUEL_RUNNING_ELECTRIC = 15, + BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16, + HYBRID_GASOLINE = 17, + HYBRID_ETHANOL = 18, + HYBRID_DIESEL = 19, + HYBRID_ELECTRIC = 20, + HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21, + HYBRID_REGENERATIVE = 22, + BIFUEL_RUNNING_DIESEL = 23, +}; + +/** + * This enum provides the canonical mapping for sensor properties that have an integer value. + * The ordering of the values is taken from the OBD2 specification. + * Some of the properties are represented as an integer mapping to another enum. In those cases + * expect a comment by the property definition describing the enum to look at for the mapping. + * Any value greater than the last reserved index is available to vendors to map their extensions. + * While these values do not directly map to SAE J1979 PIDs, an equivalence is listed next + * to each one to aid implementors. + */ +enum DiagnosticIntegerSensorIndex : int32_t { + /** refer to FuelSystemStatus for a description of this value. */ + FUEL_SYSTEM_STATUS = 0, /* PID 0x03 */ + MALFUNCTION_INDICATOR_LIGHT_ON = 1, /* PID 0x01 */ + + /** refer to IgnitionMonitorKind for a description of this value. */ + IGNITION_MONITORS_SUPPORTED = 2, /* PID 0x01 */ + + /** + * The value of this sensor is a bitmask that specifies whether ignition-specific + * tests are available and whether they are complete. The semantics of the individual + * bits in this value are given by, respectively, SparkIgnitionMonitors and + * CompressionIgnitionMonitors depending on the value of IGNITION_MONITORS_SUPPORTED. + */ + IGNITION_SPECIFIC_MONITORS = 3, /* PID 0x01 */ + INTAKE_AIR_TEMPERATURE = 4, /* PID 0x0F */ + + /** refer to SecondaryAirStatus for a description of this value. */ + COMMANDED_SECONDARY_AIR_STATUS = 5, /* PID 0x12 */ + NUM_OXYGEN_SENSORS_PRESENT = 6, /* PID 0x13 */ + RUNTIME_SINCE_ENGINE_START = 7, /* PID 0x1F */ + DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8, /* PID 0x21 */ + WARMUPS_SINCE_CODES_CLEARED = 9, /* PID 0x30 */ + DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10, /* PID 0x31 */ + ABSOLUTE_BAROMETRIC_PRESSURE = 11, /* PID 0x33 */ + CONTROL_MODULE_VOLTAGE = 12, /* PID 0x42 */ + AMBIENT_AIR_TEMPERATURE = 13, /* PID 0x46 */ + TIME_WITH_MALFUNCTION_LIGHT_ON = 14, /* PID 0x4D */ + TIME_SINCE_TROUBLE_CODES_CLEARED = 15, /* PID 0x4E */ + MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16, /* PID 0x4F */ + MAX_OXYGEN_SENSOR_VOLTAGE = 17, /* PID 0x4F */ + MAX_OXYGEN_SENSOR_CURRENT = 18, /* PID 0x4F */ + MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19, /* PID 0x4F */ + MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20, /* PID 0x50 */ + + /** refer to FuelType for a description of this value. */ + FUEL_TYPE = 21, /* PID 0x51 */ + FUEL_RAIL_ABSOLUTE_PRESSURE = 22, /* PID 0x59 */ + ENGINE_OIL_TEMPERATURE = 23, /* PID 0x5C */ + DRIVER_DEMAND_PERCENT_TORQUE = 24, /* PID 0x61 */ + ENGINE_ACTUAL_PERCENT_TORQUE = 25, /* PID 0x62 */ + ENGINE_REFERENCE_PERCENT_TORQUE = 26, /* PID 0x63 */ + ENGINE_PERCENT_TORQUE_DATA_IDLE = 27, /* PID 0x64 */ + ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28, /* PID 0x64 */ + ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29, /* PID 0x64 */ + ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30, /* PID 0x64 */ + ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31, /* PID 0x64 */ + LAST_SYSTEM_INDEX = ENGINE_PERCENT_TORQUE_DATA_POINT4, +}; + +/** + * This enum provides the canonical mapping for sensor properties that have a floating-point value. + * The ordering of the values is taken from the OBD2 specification. + * Any value greater than the last reserved index is available to vendors to map their extensions. + * While these values do not directly map to SAE J1979 PIDs, an equivalence is listed next + * to each one to aid implementors. + */ +enum DiagnosticFloatSensorIndex : int32_t { + CALCULATED_ENGINE_LOAD = 0, /* PID 0x04 */ + ENGINE_COOLANT_TEMPERATURE = 1, /* PID 0x05 */ + SHORT_TERM_FUEL_TRIM_BANK1 = 2, /* PID 0x06 */ + LONG_TERM_FUEL_TRIM_BANK1 = 3, /* PID 0x07 */ + SHORT_TERM_FUEL_TRIM_BANK2 = 4, /* PID 0x08 */ + LONG_TERM_FUEL_TRIM_BANK2 = 5, /* PID 0x09 */ + FUEL_PRESSURE = 6, /* PID 0x0A */ + INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7, /* PID 0x0B */ + ENGINE_RPM = 8, /* PID 0x0C */ + VEHICLE_SPEED = 9, /* PID 0x0D */ + TIMING_ADVANCE = 10, /* PID 0x0E */ + MAF_AIR_FLOW_RATE = 11, /* PID 0x10 */ + THROTTLE_POSITION = 12, /* PID 0x11 */ + OXYGEN_SENSOR1_VOLTAGE = 13, /* PID 0x14 */ + OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14, /* PID 0x14 */ + OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15, /* PID 0x24 */ + OXYGEN_SENSOR2_VOLTAGE = 16, /* PID 0x15 */ + OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17, /* PID 0x15 */ + OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18, /* PID 0x25 */ + OXYGEN_SENSOR3_VOLTAGE = 19, /* PID 0x16 */ + OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20, /* PID 0x16 */ + OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21, /* PID 0x26 */ + OXYGEN_SENSOR4_VOLTAGE = 22, /* PID 0x17 */ + OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23, /* PID 0x17 */ + OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24, /* PID 0x27 */ + OXYGEN_SENSOR5_VOLTAGE = 25, /* PID 0x18 */ + OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26, /* PID 0x18 */ + OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27, /* PID 0x28 */ + OXYGEN_SENSOR6_VOLTAGE = 28, /* PID 0x19 */ + OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29, /* PID 0x19 */ + OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30, /* PID 0x29 */ + OXYGEN_SENSOR7_VOLTAGE = 31, /* PID 0x1A */ + OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32, /* PID 0x1A */ + OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33, /* PID 0x2A */ + OXYGEN_SENSOR8_VOLTAGE = 34, /* PID 0x1B */ + OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35, /* PID 0x1B */ + OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36, /* PID 0x2B */ + FUEL_RAIL_PRESSURE = 37, /* PID 0x22 */ + FUEL_RAIL_GAUGE_PRESSURE = 38, /* PID 0x23 */ + COMMANDED_EXHAUST_GAS_RECIRCULATION = 39, /* PID 0x2C */ + EXHAUST_GAS_RECIRCULATION_ERROR = 40, /* PID 0x2D */ + COMMANDED_EVAPORATIVE_PURGE = 41, /* PID 0x2E */ + FUEL_TANK_LEVEL_INPUT = 42, /* PID 0x2F */ + EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43, /* PID 0x32 */ + CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44, /* PID 0x3C */ + CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45, /* PID 0x3D */ + CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46, /* PID 0x3E */ + CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47, /* PID 0x3F */ + ABSOLUTE_LOAD_VALUE = 48, /* PID 0x43 */ + FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49, /* PID 0x44 */ + RELATIVE_THROTTLE_POSITION = 50, /* PID 0x45 */ + ABSOLUTE_THROTTLE_POSITION_B = 51, /* PID 0x47 */ + ABSOLUTE_THROTTLE_POSITION_C = 52, /* PID 0x48 */ + ACCELERATOR_PEDAL_POSITION_D = 53, /* PID 0x49 */ + ACCELERATOR_PEDAL_POSITION_E = 54, /* PID 0x4A */ + ACCELERATOR_PEDAL_POSITION_F = 55, /* PID 0x4B */ + COMMANDED_THROTTLE_ACTUATOR = 56, /* PID 0x4C */ + ETHANOL_FUEL_PERCENTAGE = 57,/* PID 0x52 */ + ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58, /* PID 0x53 */ + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59, /* PID 0x55 */ + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60, /* PID 0x57 */ + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61,/* PID 0x55 */ + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62, /* PID 0x57 */ + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63, /* PID 0x56 */ + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64, /* PID 0x58 */ + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65, /* PID 0x56 */ + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66, /* PID 0x58 */ + RELATIVE_ACCELERATOR_PEDAL_POSITION = 67, /* PID 0x5A */ + HYBRID_BATTERY_PACK_REMAINING_LIFE = 68, /* PID 0x5B */ + FUEL_INJECTION_TIMING = 69, /* PID 0x5D */ + ENGINE_FUEL_RATE = 70, /* PID 0x5E */ + LAST_SYSTEM_INDEX = ENGINE_FUEL_RATE, +}; + +/** + * This enum lists the types of supported VMS messages. It is used as the first + * integer in the vehicle property integers array and determines how the rest of + * the message is decoded. + */ +enum VmsMessageType : int32_t { + /** + * A request from the subscribers to the VMS service to subscribe to a layer. + * + * This message type uses enum VmsMessageWithLayerIntegerValuesIndex. + */ + SUBSCRIBE = 1, + + /** + * A request from the subscribers to the VMS service to subscribe to a layer from a specific publisher. + * + * This message type uses enum VmsMessageWithLayerAndPublisherIdIntegerValuesIndex. + */ + SUBSCRIBE_TO_PUBLISHER = 2, + + /** + * A request from the subscribers to the VMS service to unsubscribes from a layer. + * + * This message type uses enum VmsMessageWithLayerIntegerValuesIndex. + */ + UNSUBSCRIBE = 3, + + /** + * A request from the subscribers to the VMS service to unsubscribes from a layer from a specific publisher. + * + * This message type uses enum VmsMessageWithLayerAndPublisherIdIntegerValuesIndex. + */ + UNSUBSCRIBE_TO_PUBLISHER = 4, + + /** + * Information from the publishers to the VMS service about the layers which the client can publish. + * + * This message type uses enum VmsOfferingMessageIntegerValuesIndex. + */ + OFFERING = 5, + + /** + * A request from the subscribers to the VMS service to get the available layers. + * + * This message type uses enum VmsBaseMessageIntegerValuesIndex. + */ + AVAILABILITY_REQUEST = 6, + + /** + * A request from the publishers to the VMS service to get the layers with subscribers. + * + * This message type uses enum VmsBaseMessageIntegerValuesIndex. + */ + SUBSCRIPTIONS_REQUEST = 7, + + /** + * A response from the VMS service to the subscribers to a VmsMessageType.AVAILABILITY_REQUEST + * + * This message type uses enum VmsAvailabilityStateIntegerValuesIndex. + */ + AVAILABILITY_RESPONSE = 8, + + /** + * A notification from the VMS service to the subscribers on a change in the available layers. + * + * This message type uses enum VmsAvailabilityStateIntegerValuesIndex. + */ + AVAILABILITY_CHANGE = 9, + + /** + * A response from the VMS service to the publishers to a VmsMessageType.SUBSCRIPTIONS_REQUEST + * + * This message type uses enum VmsSubscriptionsStateIntegerValuesIndex. + */ + SUBSCRIPTIONS_RESPONSE = 10, + + /** + * A notification from the VMS service to the publishers on a change in the layers with subscribers. + * + * This message type uses enum VmsSubscriptionsStateIntegerValuesIndex. + */ + SUBSCRIPTIONS_CHANGE = 11, + + /** + * A message from the VMS service to the subscribers or from the publishers to the VMS service + * with a serialized VMS data packet as defined in the VMS protocol. + * + * This message type uses enum VmsBaseMessageIntegerValuesIndex. + */ + DATA = 12, +}; + +/** + * Every VMS message starts with the type of the message from the VmsMessageType enum. + * Messages with no parameters such as VmsMessageType.AVAILABILITY_REQUEST, + * VmsMessageType.SUBSCRIPTIONS_REQUEST and VmsMessageType.DATA are also based on this enum. + */ +enum VmsBaseMessageIntegerValuesIndex : int32_t { + /* The message type as enumerated by VmsMessageType enum. */ + MESSAGE_TYPE = 0, +}; + +/* + * A VMS message with a layer is sent as part of a VmsMessageType.SUBSCRIBE or + * VmsMessageType.UNSUBSCRIBE messages. + * + * The layer type is defined in the VMS protocol, and the subtype and version are + * controlled by the implementer of the publisher. + */ +enum VmsMessageWithLayerIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { + LAYER_TYPE = 1, + LAYER_SUBTYPE = 2, + LAYER_VERSION = 3, +}; + +/* + * A VMS message with a layer and publisher ID is sent as part of a + * VmsMessageType.SUBSCRIBE_TO_PUBLISHER and VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER messages. + */ +enum VmsMessageWithLayerAndPublisherIdIntegerValuesIndex : VmsMessageWithLayerIntegerValuesIndex { + PUBLISHER_ID = 4, +}; + +/* + * An offering can be sent by publishers as part of VmsMessageType.OFFERING in order to + * advertise which layers they can publish and under which constraints: e.g., I can publish Layer X + * if someone else will publish Layer Y. + * The offering contains the publisher ID which was assigned to the publisher by the VMS service. + * A single offering is represented as: + * - Layer type + * - Layer subtype + * - Layer version + * - Number of dependencies (N) + * - N x (Layer type, Layer subtype, Layer version) + */ +enum VmsOfferingMessageIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { + PUBLISHER_ID = 1, + NUMBER_OF_OFFERS = 2, + OFFERING_START = 3, +}; + +/** + * A subscriptions state is sent to the publishers in response to a change in the subscriptions + * as part of a VmsMessageType.SUBSCRIPTIONS_CHANGE, or in response to a + * VmsMessageType.SUBSCRIPTIONS_REQUEST message as part of VmsMessageType.SUBSCRIPTIONS_RESPONSE. + * The VMS service issues monotonically increasing sequence numbers, and in case a subscriber receives + * a smaller sequnce number it should ignore the message. + * The subscriptions are sent as a list of layers followed by a list of associated layers: + * {Sequence number, N, M, N x layer, M x associated layer} + * A subscribed layer is represented as three integers: + * - Layer type + * - Layer subtype + * - Layer version + * A subscribed associated layer is a layer with a list of publisher IDs. It is represented as: + * - Layer type + * - Layer subtype + * - Layer version + * - Number of publisher IDs (N) + * - N x publisher ID + */ +enum VmsSubscriptionsStateIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { + SEQUENCE_NUMBER = 1, + NUMBER_OF_LAYERS = 2, + NUMBER_OF_ASSOCIATED_LAYERS = 3, + SUBSCRIPTIONS_START = 4, +}; + +/** + * An availability state is sent to the subscribers in response to a change in the available + * layers as part of a VmsMessageType.AVAILABILITY_CHANGE message, or in response to a + * VmsMessageType.AVAILABILITY_REQUEST message as part of a VmsMessageType.AVAILABILITY_RESPONSE. + * The VMS service issues monotonically increasing sequence numbers, and in case a subscriber receives + * a smaller sequnce number, it should ignore the message. + * An available associated layer is a layer with a list of publisher IDs: + * - Layer type + * - Layer subtype + * - Layer version + * - Number of publisher IDs (N) + * - N x publisher ID +*/ +enum VmsAvailabilityStateIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { + SEQUENCE_NUMBER = 1, + NUMBER_OF_ASSOCIATED_LAYERS = 2, + LAYERS_START = 3, +}; + diff --git a/automotive/vehicle/2.1/Android.bp b/automotive/vehicle/2.1/Android.bp deleted file mode 100644 index 447c08e336..0000000000 --- a/automotive/vehicle/2.1/Android.bp +++ /dev/null @@ -1,68 +0,0 @@ -// This file is autogenerated by hidl-gen. Do not edit manually. - -filegroup { - name: "android.hardware.automotive.vehicle@2.1_hal", - srcs: [ - "types.hal", - "IVehicle.hal", - ], -} - -genrule { - name: "android.hardware.automotive.vehicle@2.1_genc++", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.1", - srcs: [ - ":android.hardware.automotive.vehicle@2.1_hal", - ], - out: [ - "android/hardware/automotive/vehicle/2.1/types.cpp", - "android/hardware/automotive/vehicle/2.1/VehicleAll.cpp", - ], -} - -genrule { - name: "android.hardware.automotive.vehicle@2.1_genc++_headers", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.1", - srcs: [ - ":android.hardware.automotive.vehicle@2.1_hal", - ], - out: [ - "android/hardware/automotive/vehicle/2.1/types.h", - "android/hardware/automotive/vehicle/2.1/hwtypes.h", - "android/hardware/automotive/vehicle/2.1/IVehicle.h", - "android/hardware/automotive/vehicle/2.1/IHwVehicle.h", - "android/hardware/automotive/vehicle/2.1/BnHwVehicle.h", - "android/hardware/automotive/vehicle/2.1/BpHwVehicle.h", - "android/hardware/automotive/vehicle/2.1/BsVehicle.h", - ], -} - -cc_library { - name: "android.hardware.automotive.vehicle@2.1", - defaults: ["hidl-module-defaults"], - generated_sources: ["android.hardware.automotive.vehicle@2.1_genc++"], - generated_headers: ["android.hardware.automotive.vehicle@2.1_genc++_headers"], - export_generated_headers: ["android.hardware.automotive.vehicle@2.1_genc++_headers"], - vendor_available: true, - vndk: { - enabled: true, - }, - shared_libs: [ - "libhidlbase", - "libhidltransport", - "libhwbinder", - "liblog", - "libutils", - "libcutils", - "android.hardware.automotive.vehicle@2.0", - ], - export_shared_lib_headers: [ - "libhidlbase", - "libhidltransport", - "libhwbinder", - "libutils", - "android.hardware.automotive.vehicle@2.0", - ], -} diff --git a/automotive/vehicle/2.1/Android.mk b/automotive/vehicle/2.1/Android.mk deleted file mode 100644 index 8e1c0dd321..0000000000 --- a/automotive/vehicle/2.1/Android.mk +++ /dev/null @@ -1,648 +0,0 @@ -# This file is autogenerated by hidl-gen. Do not edit manually. - -LOCAL_PATH := $(call my-dir) - -################################################################################ - -include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.automotive.vehicle-V2.1-java -LOCAL_MODULE_CLASS := JAVA_LIBRARIES - -intermediates := $(call local-generated-sources-dir, COMMON) - -HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) - -LOCAL_JAVA_LIBRARIES := \ - android.hardware.automotive.vehicle-V2.0-java \ - android.hidl.base-V1.0-java \ - - -# -# Build types.hal (CommonIgnitionMonitors) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CommonIgnitionMonitors.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.CommonIgnitionMonitors - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (CompressionIgnitionMonitors) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CompressionIgnitionMonitors.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.CompressionIgnitionMonitors - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (FuelSystemStatus) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelSystemStatus.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.FuelSystemStatus - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (FuelType) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelType.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.FuelType - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (IgnitionMonitorKind) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IgnitionMonitorKind.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.IgnitionMonitorKind - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (Obd2FloatSensorIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2FloatSensorIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.Obd2FloatSensorIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (Obd2IntegerSensorIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2IntegerSensorIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.Obd2IntegerSensorIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (SecondaryAirStatus) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SecondaryAirStatus.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.SecondaryAirStatus - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (SparkIgnitionMonitors) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SparkIgnitionMonitors.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.SparkIgnitionMonitors - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VehicleProperty) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VehicleProperty.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VehicleProperty - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsBaseMessageIntegerValuesIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsBaseMessageIntegerValuesIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsBaseMessageIntegerValuesIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsMessageType) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsMessageType - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsOfferingMessageIntegerValuesIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsOfferingMessageIntegerValuesIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsOfferingMessageIntegerValuesIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsSimpleMessageIntegerValuesIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsSimpleMessageIntegerValuesIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsSimpleMessageIntegerValuesIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsSubscriptionResponseFormat) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsSubscriptionResponseFormat.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsSubscriptionResponseFormat - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build IVehicle.hal -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::IVehicle - -$(GEN): $(LOCAL_PATH)/IVehicle.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) -include $(BUILD_JAVA_LIBRARY) - - -################################################################################ - -include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.automotive.vehicle-V2.1-java-static -LOCAL_MODULE_CLASS := JAVA_LIBRARIES - -intermediates := $(call local-generated-sources-dir, COMMON) - -HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) - -LOCAL_STATIC_JAVA_LIBRARIES := \ - android.hardware.automotive.vehicle-V2.0-java-static \ - android.hidl.base-V1.0-java-static \ - - -# -# Build types.hal (CommonIgnitionMonitors) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CommonIgnitionMonitors.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.CommonIgnitionMonitors - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (CompressionIgnitionMonitors) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CompressionIgnitionMonitors.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.CompressionIgnitionMonitors - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (FuelSystemStatus) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelSystemStatus.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.FuelSystemStatus - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (FuelType) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelType.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.FuelType - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (IgnitionMonitorKind) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IgnitionMonitorKind.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.IgnitionMonitorKind - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (Obd2FloatSensorIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2FloatSensorIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.Obd2FloatSensorIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (Obd2IntegerSensorIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2IntegerSensorIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.Obd2IntegerSensorIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (SecondaryAirStatus) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SecondaryAirStatus.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.SecondaryAirStatus - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (SparkIgnitionMonitors) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SparkIgnitionMonitors.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.SparkIgnitionMonitors - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VehicleProperty) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VehicleProperty.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VehicleProperty - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsBaseMessageIntegerValuesIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsBaseMessageIntegerValuesIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsBaseMessageIntegerValuesIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsMessageType) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsMessageType - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsOfferingMessageIntegerValuesIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsOfferingMessageIntegerValuesIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsOfferingMessageIntegerValuesIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsSimpleMessageIntegerValuesIndex) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsSimpleMessageIntegerValuesIndex.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsSimpleMessageIntegerValuesIndex - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build types.hal (VmsSubscriptionResponseFormat) -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsSubscriptionResponseFormat.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::types.VmsSubscriptionResponseFormat - -$(GEN): $(LOCAL_PATH)/types.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# -# Build IVehicle.hal -# -GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java -$(GEN): $(HIDL) -$(GEN): PRIVATE_HIDL := $(HIDL) -$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal -$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) -$(GEN): PRIVATE_CUSTOM_TOOL = \ - $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ - -Ljava \ - -randroid.hardware:hardware/interfaces \ - -randroid.hidl:system/libhidl/transport \ - android.hardware.automotive.vehicle@2.1::IVehicle - -$(GEN): $(LOCAL_PATH)/IVehicle.hal - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) -include $(BUILD_STATIC_JAVA_LIBRARY) - - - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/automotive/vehicle/2.1/IVehicle.hal b/automotive/vehicle/2.1/IVehicle.hal deleted file mode 100644 index a22d1e685c..0000000000 --- a/automotive/vehicle/2.1/IVehicle.hal +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.1 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.automotive.vehicle@2.1; - -import android.hardware.automotive.vehicle@2.0; - -/** - * New revision of IVehicle interface that supports properties defined in - * VehicleProperty enum version 2.1. - * - * NOTE: this HAL interface is under development and shouldn't be used in - * production. - * - * TODO(pavelm): update comment when this interface is ready for prod. - */ -interface IVehicle extends @2.0::IVehicle { -}; diff --git a/automotive/vehicle/2.1/default/Android.mk b/automotive/vehicle/2.1/default/Android.mk deleted file mode 100644 index f19263c7d1..0000000000 --- a/automotive/vehicle/2.1/default/Android.mk +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (C) 2016 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH := $(call my-dir) - -vhal_v2_0 = android.hardware.automotive.vehicle@2.0 -vhal_v2_1 = android.hardware.automotive.vehicle@2.1 - -############################################################################### -# Vehicle reference implementation lib -############################################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(vhal_v2_1)-manager-lib -LOCAL_SRC_FILES := \ - common/src/Obd2SensorStore.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/common/include/vhal_v2_1 \ - $(LOCAL_PATH)/../../2.0/default/common/include/vhal_v2_0 \ - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(LOCAL_PATH)/common/include - -LOCAL_SHARED_LIBRARIES := \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - liblog \ - libutils \ - $(vhal_v2_1) \ - -include $(BUILD_STATIC_LIBRARY) - -############################################################################### -# Vehicle default VehicleHAL implementation -############################################################################### -include $(CLEAR_VARS) - -LOCAL_MODULE:= $(vhal_v2_1)-default-impl-lib -LOCAL_SRC_FILES:= \ - impl/vhal_v2_1/EmulatedVehicleHal.cpp \ - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/impl/vhal_v2_1 \ - $(LOCAL_PATH)/common/include - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(LOCAL_PATH)/impl \ - $(LOCAL_PATH)/common/include - - -# LOCAL_WHOLE_STATIC_LIBRARIES := \ - -LOCAL_STATIC_LIBRARIES := \ - $(vhal_v2_0)-default-impl-lib \ - $(vhal_v2_0)-manager-lib \ - libqemu_pipe \ - $(vhal_v2_1)-manager-lib \ - $(vhal_v2_0)-libproto-native - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - liblog \ - libutils \ - libprotobuf-cpp-lite \ - $(vhal_v2_0) \ - $(vhal_v2_1) \ - -LOCAL_CFLAGS += -Wall -Wextra -Werror - -include $(BUILD_STATIC_LIBRARY) - -############################################################################### -# Vehicle HAL service -############################################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(vhal_v2_1)-service -LOCAL_INIT_RC := $(vhal_v2_1)-service.rc -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true -LOCAL_SRC_FILES := \ - service.cpp - -LOCAL_WHOLE_STATIC_LIBRARIES := \ - $(vhal_v2_0)-libproto-native \ - -LOCAL_STATIC_LIBRARIES := \ - $(vhal_v2_0)-manager-lib \ - $(vhal_v2_0)-default-impl-lib \ - $(vhal_v2_1)-default-impl-lib \ - libqemu_pipe \ - $(vhal_v2_1)-manager-lib \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - liblog \ - libutils \ - libprotobuf-cpp-lite \ - $(vhal_v2_0) \ - $(vhal_v2_1) \ - -LOCAL_CFLAGS += -Wall -Wextra -Werror - -include $(BUILD_EXECUTABLE) diff --git a/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc b/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc deleted file mode 100644 index 8929d25668..0000000000 --- a/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc +++ /dev/null @@ -1,4 +0,0 @@ -service vehicle-hal-2.1 /vendor/bin/hw/android.hardware.automotive.vehicle@2.1-service - class hal - user vehicle_network - group system inet diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h deleted file mode 100644 index 0f10086d70..0000000000 --- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_ -#define android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_ - -#include <android/hardware/automotive/vehicle/2.1/types.h> -#include <vhal_v2_0/VehicleUtils.h> - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_1 { - -namespace impl { - -// Some handy constants to avoid conversions from enum to int. -constexpr int OBD2_LIVE_FRAME = (int) V2_1::VehicleProperty::OBD2_LIVE_FRAME; -constexpr int OBD2_FREEZE_FRAME = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME; -constexpr int OBD2_FREEZE_FRAME_INFO = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO; -constexpr int OBD2_FREEZE_FRAME_CLEAR = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR; -constexpr int VEHICLE_MAP_SERVICE = (int) V2_1::VehicleProperty::VEHICLE_MAP_SERVICE; -constexpr int WHEEL_TICK = (int) V2_1::VehicleProperty::WHEEL_TICK; - - -const V2_0::VehiclePropConfig kVehicleProperties[] = { - { - .prop = WHEEL_TICK, - .access = V2_0::VehiclePropertyAccess::READ, - .changeMode = V2_0::VehiclePropertyChangeMode::CONTINUOUS, - .minSampleRate = 1.0f, - .maxSampleRate = 100.0f, - }, - - { - .prop = OBD2_LIVE_FRAME, - .access = V2_0::VehiclePropertyAccess::READ, - .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {0,0} - }, - - { - .prop = OBD2_FREEZE_FRAME, - .access = V2_0::VehiclePropertyAccess::READ, - .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE, - .configArray = {0,0} - }, - - { - .prop = OBD2_FREEZE_FRAME_INFO, - .access = V2_0::VehiclePropertyAccess::READ, - .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE - }, - - { - .prop = OBD2_FREEZE_FRAME_CLEAR, - .access = V2_0::VehiclePropertyAccess::WRITE, - .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE - }, - - { - .prop = VEHICLE_MAP_SERVICE, - .access = V2_0::VehiclePropertyAccess::READ_WRITE, - .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE - } -}; - -} // impl - -} // namespace V2_1 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android - -#endif // android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_ diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp deleted file mode 100644 index 46e062b86b..0000000000 --- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "DefaultVehicleHal_v2_1" -#include <android/log.h> - -#include <log/log.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <algorithm> - -#include "EmulatedVehicleHal.h" - -#define DEBUG_SOCKET (33452) - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_1 { - -namespace impl { - -static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame( - size_t numVendorIntegerSensors, - size_t numVendorFloatSensors) { - std::unique_ptr<Obd2SensorStore> sensorStore(new Obd2SensorStore( - numVendorIntegerSensors, numVendorFloatSensors)); - - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS, - V2_0::toInt(FuelSystemStatus::CLOSED_LOOP)); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::IGNITION_MONITORS_SUPPORTED, - V2_0::toInt(IgnitionMonitorKind::SPARK)); - sensorStore->setIntegerSensor(Obd2IntegerSensorIndex::IGNITION_SPECIFIC_MONITORS, - CommonIgnitionMonitors::COMPONENTS_AVAILABLE | - CommonIgnitionMonitors::MISFIRE_AVAILABLE | - SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE | - SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS, - V2_0::toInt(SecondaryAirStatus::FROM_OUTSIDE_OR_OFF)); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1); - sensorStore->setIntegerSensor( - Obd2IntegerSensorIndex::FUEL_TYPE, V2_0::toInt(FuelType::GASOLINE)); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::ENGINE_RPM, 1250.); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::VEHICLE_SPEED, 40.); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::TIMING_ADVANCE, 2.5); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::THROTTLE_POSITION, 19.75); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE, -0.373); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1, 190.); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094); - sensorStore->setFloatSensor( - Obd2FloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024); - - return sensorStore; -} - -void EmulatedVehicleHal::initObd2LiveFrame(const V2_0::VehiclePropConfig& propConfig) { - auto liveObd2Frame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0); - auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]), - static_cast<size_t>(propConfig.configArray[1])); - sensorStore->fillPropValue("", liveObd2Frame.get()); - liveObd2Frame->prop = OBD2_LIVE_FRAME; - - mPropStore->writeValue(*liveObd2Frame); -} - -void EmulatedVehicleHal::initObd2FreezeFrame(const V2_0::VehiclePropConfig& propConfig) { - auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]), - static_cast<size_t>(propConfig.configArray[1])); - - static std::vector<std::string> sampleDtcs = { "P0070", "P0102" "P0123" }; - for (auto&& dtc : sampleDtcs) { - auto freezeFrame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0); - sensorStore->fillPropValue(dtc, freezeFrame.get()); - freezeFrame->prop = OBD2_FREEZE_FRAME; - - mPropStore->writeValue(*freezeFrame); - } -} - -V2_0::StatusCode EmulatedVehicleHal::fillObd2FreezeFrame( - const V2_0::VehiclePropValue& requestedPropValue, - V2_0::VehiclePropValue* outValue) { - if (requestedPropValue.value.int64Values.size() != 1) { - ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp"); - return V2_0::StatusCode::INVALID_ARG; - } - auto timestamp = requestedPropValue.value.int64Values[0]; - auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp); - if(freezeFrame == nullptr) { - ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); - return V2_0::StatusCode::INVALID_ARG; - } - outValue->prop = OBD2_FREEZE_FRAME; - outValue->value.int32Values = freezeFrame->value.int32Values; - outValue->value.floatValues = freezeFrame->value.floatValues; - outValue->value.bytes = freezeFrame->value.bytes; - outValue->value.stringValue = freezeFrame->value.stringValue; - outValue->timestamp = freezeFrame->timestamp; - return V2_0::StatusCode::OK; -} - -V2_0::StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue) { - if (propValue.value.int64Values.size() == 0) { - mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME); - return V2_0::StatusCode::OK; - } else { - for(int64_t timestamp: propValue.value.int64Values) { - auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp); - if(freezeFrame == nullptr) { - ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); - return V2_0::StatusCode::INVALID_ARG; - } - mPropStore->removeValue(*freezeFrame); - } - } - return V2_0::StatusCode::OK; -} - -V2_0::StatusCode EmulatedVehicleHal::fillObd2DtcInfo(V2_0::VehiclePropValue* outValue) { - std::vector<int64_t> timestamps; - for(const auto& freezeFrame: mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) { - timestamps.push_back(freezeFrame.timestamp); - } - outValue->value.int64Values = timestamps; - return V2_0::StatusCode::OK; -} - -void EmulatedVehicleHal::onCreate() { - V2_0::impl::EmulatedVehicleHal::onCreate(); - - initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME)); - initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME)); -} - -void EmulatedVehicleHal::initStaticConfig() { - for (auto&& cfg = std::begin(kVehicleProperties); cfg != std::end(kVehicleProperties); ++cfg) { - V2_0::VehiclePropertyStore::TokenFunction tokenFunction = nullptr; - - switch (cfg->prop) { - case OBD2_FREEZE_FRAME: { - tokenFunction = [] (const V2_0::VehiclePropValue& propValue) { - return propValue.timestamp; - }; - break; - } - default: - break; - } - - mPropStore->registerProperty(*cfg, tokenFunction); - } -} - -EmulatedVehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( - const V2_0::VehiclePropValue& requestedPropValue, - V2_0::StatusCode* outStatus) { - - auto propId = requestedPropValue.prop; - VehiclePropValuePtr v = nullptr; - auto& pool = *getValuePool(); - - switch (propId) { - case OBD2_FREEZE_FRAME: - v = pool.obtainComplex(); - *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get()); - return v; - case OBD2_FREEZE_FRAME_INFO: - v = pool.obtainComplex(); - *outStatus = fillObd2DtcInfo(v.get()); - return v; - default: - return V2_0::impl::EmulatedVehicleHal::get(requestedPropValue, outStatus); - } -} - -V2_0::StatusCode EmulatedVehicleHal::set(const V2_0::VehiclePropValue& propValue) { - auto propId = propValue.prop; - switch (propId) { - case OBD2_FREEZE_FRAME_CLEAR: - return clearObd2FreezeFrames(propValue); - case VEHICLE_MAP_SERVICE: - // Placeholder for future implementation of VMS property in the default hal. For now, just - // returns OK; otherwise, hal clients crash with property not supported. - return V2_0::StatusCode::OK; - default: - return V2_0::impl::EmulatedVehicleHal::set(propValue); - } -} - -} // impl - -} // namespace V2_1 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.h deleted file mode 100644 index 7cc3b79679..0000000000 --- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef android_hardware_automotive_vehicle_V2_1_impl_EmulatedVehicleHal_H_ -#define android_hardware_automotive_vehicle_V2_1_impl_EmulatedVehicleHal_H_ - -#include <memory> - -#include <utils/SystemClock.h> - -#include <vhal_v2_0/EmulatedVehicleHal.h> -#include <vhal_v2_0/VehicleHal.h> -#include <vhal_v2_0/VehiclePropertyStore.h> -#include <vhal_v2_1/Obd2SensorStore.h> - -#include "DefaultConfig.h" - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_1 { - -namespace impl { - -using namespace std::placeholders; - -class EmulatedVehicleHal : public V2_0::impl::EmulatedVehicleHal { -public: - EmulatedVehicleHal(V2_0::VehiclePropertyStore* propStore) - : V2_0::impl::EmulatedVehicleHal(propStore), mPropStore(propStore) { - initStaticConfig(); - } - - VehiclePropValuePtr get(const V2_0::VehiclePropValue& requestedPropValue, - V2_0::StatusCode* outStatus) override; - - V2_0::StatusCode set(const V2_0::VehiclePropValue& propValue) override; - - void onCreate() override; - -private: - void initStaticConfig(); - void initObd2LiveFrame(const V2_0::VehiclePropConfig& propConfig); - void initObd2FreezeFrame(const V2_0::VehiclePropConfig& propConfig); - V2_0::StatusCode fillObd2FreezeFrame(const V2_0::VehiclePropValue& requestedPropValue, - V2_0::VehiclePropValue* outValue); - V2_0::StatusCode fillObd2DtcInfo(V2_0::VehiclePropValue *outValue); - V2_0::StatusCode clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue); - -private: - V2_0::VehiclePropertyStore* mPropStore; -}; - -} // impl - -} // namespace V2_1 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android - - -#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_ diff --git a/automotive/vehicle/2.1/default/service.cpp b/automotive/vehicle/2.1/default/service.cpp deleted file mode 100644 index bae64fde9f..0000000000 --- a/automotive/vehicle/2.1/default/service.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "automotive.vehicle@2.1-service" -#include <android/log.h> -#include <hidl/HidlTransportSupport.h> - -#include <iostream> - -#include <android/hardware/automotive/vehicle/2.1/IVehicle.h> - -#include <vhal_v2_0/VehicleHalManager.h> -#include <vhal_v2_0/VehiclePropertyStore.h> -#include <vhal_v2_0/EmulatedVehicleHal.h> - -#include <vhal_v2_1/EmulatedVehicleHal.h> - -using namespace android; -using namespace android::hardware; - -namespace V2_1 = ::android::hardware::automotive::vehicle::V2_1; -namespace V2_0 = ::android::hardware::automotive::vehicle::V2_0; - -using StatusCode = V2_0::StatusCode; -using VehiclePropValue = V2_0::VehiclePropValue; - -/* Just wrapper that passes all calls to the provided V2_0::IVehicle object */ -struct Vehicle_V2_1 : public V2_1::IVehicle { - - Vehicle_V2_1(V2_0::IVehicle* vehicle20) : mVehicle20(vehicle20) {} - - // Methods derived from IVehicle - Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) override { - return mVehicle20->getAllPropConfigs(_hidl_cb); - } - - Return<void> getPropConfigs(const hidl_vec<int32_t>& properties, - getPropConfigs_cb _hidl_cb) override { - return mVehicle20->getPropConfigs(properties, _hidl_cb); - } - - Return<void> get(const V2_0::VehiclePropValue& requestedPropValue, - get_cb _hidl_cb) override { - return mVehicle20->get(requestedPropValue, _hidl_cb); - } - - Return<StatusCode> set(const VehiclePropValue& value) override { - return mVehicle20->set(value); - } - - Return<StatusCode> subscribe(const sp<V2_0::IVehicleCallback>& callback, - const hidl_vec<V2_0::SubscribeOptions>& - options) override { - return mVehicle20->subscribe(callback, options); - } - - Return<StatusCode> unsubscribe(const sp<V2_0::IVehicleCallback>& callback, - int32_t propId) override { - return mVehicle20->unsubscribe(callback, propId); - } - - Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override { - return mVehicle20->debugDump(_hidl_cb); - } - -private: - V2_0::IVehicle* mVehicle20; -}; - -int main(int /* argc */, char* /* argv */ []) { - auto store = std::make_unique<V2_0::VehiclePropertyStore>(); - auto hal = std::make_unique<V2_1::impl::EmulatedVehicleHal>(store.get()); - auto emulator = std::make_unique<V2_0::impl::VehicleEmulator>(hal.get()); - auto vehicleManager = std::make_unique<V2_0::VehicleHalManager>(hal.get()); - - Vehicle_V2_1 vehicle21(vehicleManager.get()); - - configureRpcThreadpool(1, true /* callerWillJoin */); - - ALOGI("Registering as service..."); - status_t status = vehicle21.registerAsService(); - - if (status != OK) { - ALOGE("Unable to register vehicle service (%d).", status); - return 1; - } - - ALOGI("Ready"); - joinRpcThreadpool(); - return 1; -} diff --git a/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp b/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp deleted file mode 100644 index a01c0f498c..0000000000 --- a/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - #include <gtest/gtest.h> - -#include "vhal_v2_0/Obd2SensorStore.h" -#include "vhal_v2_0/VehicleUtils.h" - -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { - -namespace { - -static constexpr size_t getNumVendorIntegerSensors() { - return 5; -} -static constexpr size_t getNumVendorFloatSensors() { - return 3; -} - -// this struct holds information necessary for a test to be able to validate -// that the sensor bitmask contains the right data: -// - the index of the byte at which the bit for a given sensor lives -// - the expected value of that byte given that a certain sensor is present -class BitmaskIndexingInfo { -public: - size_t mByteIndex; - uint8_t mExpectedByteValue; - - // Returns the information required to validate the bitmask for an - // integer-valued sensor. - static BitmaskIndexingInfo getForIntegerSensor(size_t index) { - const size_t indexInBitstream = index; - return getForBitstreamIndex(indexInBitstream); - } - - // Returns the information required to validate the bitmask for a - // float-valued sensor. - static BitmaskIndexingInfo getForFloatSensor(size_t index) { - const size_t indexInBitstream = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) + - 1 + getNumVendorIntegerSensors() + index; - return getForBitstreamIndex(indexInBitstream); - } - -private: - static BitmaskIndexingInfo getForBitstreamIndex(size_t indexInBitstream) { - BitmaskIndexingInfo indexingInfo; - indexingInfo.mByteIndex = indexInBitstream / 8; - indexingInfo.mExpectedByteValue = 1 << (indexInBitstream % 8); - return indexingInfo; - } -}; - -static Obd2SensorStore getSensorStore() { - return Obd2SensorStore(getNumVendorIntegerSensors(), - getNumVendorFloatSensors()); -} - -// Test that one can set and retrieve a value for the first integer sensor. -TEST(Obd2SensorStoreTest, setFirstIntegerSensor) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setIntegerSensor( - Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS, - toInt(FuelSystemStatus::CLOSED_LOOP)); - const auto& integerSensors(sensorStore.getIntegerSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ( - toInt(FuelSystemStatus::CLOSED_LOOP), - integerSensors[toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS)]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( - toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS))); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -// Test that one can set and retrieve a value for the first float sensor. -TEST(Obd2SensorStoreTest, setFirstFloatSensor) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setFloatSensor( - Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD, - 1.25f); - const auto& floatSensors(sensorStore.getFloatSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ( - 1.25f, - floatSensors[toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD)]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( - toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD))); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -// Test that one can set and retrieve a value for an integer sensor. -TEST(Obd2SensorStoreTest, setAnyIntegerSensor) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setIntegerSensor( - Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, - 4000); - const auto& integerSensors(sensorStore.getIntegerSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(4000, - integerSensors[toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE)]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( - toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE))); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -// Test that one can set and retrieve a value for a float sensor. -TEST(Obd2SensorStoreTest, setAnyFloatSensor) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setFloatSensor( - Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE, - 2.5f); - const auto& floatSensors(sensorStore.getFloatSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(2.5f, - floatSensors[toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE)]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( - toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE))); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -// Test that one can set and retrieve a value for the last system integer sensor. -TEST(Obd2SensorStoreTest, setLastSystemIntegerSensor) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setIntegerSensor( - Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX, - 30); - const auto& integerSensors(sensorStore.getIntegerSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(30, - integerSensors[toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( - toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX))); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -// Test that one can set and retrieve a value for the last system float sensor. -TEST(Obd2SensorStoreTest, setLastSystemFloatSensor) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setFloatSensor( - Obd2FloatSensorIndex::LAST_SYSTEM_INDEX, - 2.5f); - const auto& floatSensors(sensorStore.getFloatSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(2.5f, - floatSensors[toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( - toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX))); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -// Test that one can set and retrieve a value for two integer sensors at once. -TEST(Obd2SensorStoreTest, setTwoIntegerSensors) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setIntegerSensor( - Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE, - 6); - sensorStore.setIntegerSensor( - Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED, - 1245); - const auto& integerSensors(sensorStore.getIntegerSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(6, - integerSensors[toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE)]); - ASSERT_EQ(1245, - integerSensors[toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED)]); - const BitmaskIndexingInfo voltageIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor( - toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE))); - const BitmaskIndexingInfo timeIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor( - toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED))); - if (voltageIndexingInfo.mByteIndex == timeIndexingInfo.mByteIndex) { - ASSERT_EQ( - voltageIndexingInfo.mExpectedByteValue | - timeIndexingInfo.mExpectedByteValue, - sensorBitmask[timeIndexingInfo.mByteIndex]); - } - else { - ASSERT_EQ( - timeIndexingInfo.mExpectedByteValue, - sensorBitmask[timeIndexingInfo.mByteIndex]); - ASSERT_EQ( - voltageIndexingInfo.mExpectedByteValue, - sensorBitmask[voltageIndexingInfo.mByteIndex]); - } -} - -// Test that one can set and retrieve a value for two float sensors at once. -TEST(Obd2SensorStoreTest, setTwoFloatSensors) { - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setFloatSensor( - Obd2FloatSensorIndex::VEHICLE_SPEED, - 1.25f); - sensorStore.setFloatSensor( - Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE, - 2.5f); - const auto& floatSensors(sensorStore.getFloatSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(1.25f, - floatSensors[toInt(Obd2FloatSensorIndex::VEHICLE_SPEED)]); - ASSERT_EQ(2.5f, - floatSensors[toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE)]); - const BitmaskIndexingInfo speedIndexingInfo(BitmaskIndexingInfo::getForFloatSensor( - toInt(Obd2FloatSensorIndex::VEHICLE_SPEED))); - const BitmaskIndexingInfo airflowIndexingInfo(BitmaskIndexingInfo::getForFloatSensor( - toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE))); - if (speedIndexingInfo.mByteIndex == airflowIndexingInfo.mByteIndex) { - ASSERT_EQ( - speedIndexingInfo.mExpectedByteValue | - airflowIndexingInfo.mExpectedByteValue, - sensorBitmask[airflowIndexingInfo.mByteIndex]); - } - else { - ASSERT_EQ( - speedIndexingInfo.mExpectedByteValue, - sensorBitmask[speedIndexingInfo.mByteIndex]); - ASSERT_EQ( - airflowIndexingInfo.mExpectedByteValue, - sensorBitmask[airflowIndexingInfo.mByteIndex]); - } -} - -// Test that one can set and retrieve a value for a vendor integer sensor. -TEST(Obd2SensorStoreTest, setVendorIntegerSensor) { - const size_t sensorIndex = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) + 2; - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setIntegerSensor(sensorIndex, 22); - const auto& integerSensors(sensorStore.getIntegerSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(22, integerSensors[sensorIndex]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( - sensorIndex)); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -// Test that one can set and retrieve a value for a vendor float sensor. -TEST(Obd2SensorStoreTest, setVendorFloatSensor) { - const size_t sensorIndex = toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX) + 2; - Obd2SensorStore sensorStore(getSensorStore()); - sensorStore.setFloatSensor(sensorIndex, 1.25f); - const auto& floatSensors(sensorStore.getFloatSensors()); - const auto& sensorBitmask(sensorStore.getSensorsBitmask()); - ASSERT_EQ(1.25f, floatSensors[sensorIndex]); - const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( - sensorIndex)); - ASSERT_EQ( - indexingInfo.mExpectedByteValue, - sensorBitmask[indexingInfo.mByteIndex]); -} - -} // namespace anonymous - -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android diff --git a/automotive/vehicle/2.1/types.hal b/automotive/vehicle/2.1/types.hal deleted file mode 100644 index 7be611c55b..0000000000 --- a/automotive/vehicle/2.1/types.hal +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.1 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.automotive.vehicle@2.1; - -import android.hardware.automotive.vehicle@2.0; - -/** - * Extension of VehicleProperty enum declared in Vehicle HAL 2.0 - */ -enum VehicleProperty: @2.0::VehicleProperty { - /** - * Reports wheel rotational distance in meters since last wheel tick - * event - * - * The value is a vector each element represents distance for individual - * wheel in the following order: left front, right front, left rear, - * right rear. VehiclePropValue.timestamp must be correctly filled in. - * - * Vendors must specify wheels that support this sensor in - * VehiclePropConfig.configFlags. The format of this field is a bitset of - * values from Wheel enum. - * - * @change_mode VehiclePropertyChangeMode:ON_CHANGE |VehiclePropertyChangeMode:CONTINUOUS - * @access VehiclePropertyAccess:READ - * @unit VehicleUnit:METER - */ - WHEEL_TICK = ( - 0x0306 - | VehiclePropertyGroup:SYSTEM - | VehiclePropertyType:FLOAT_VEC - | VehicleArea:GLOBAL), - - /** - * OBD2 Live Sensor Data - * - * This property uses COMPLEX data to send a snapshot of the current (live) - * values of the OBD2 sensors provided by the vehicle. - * - * VehiclePropConfig - * configArray[0] : number of vendor-specific integer-valued sensors - * that can be returned in a frame. - * configArray[1] : number of vendor-specific float-valued sensors - * that can be returned in a frame. - * - * The values are to be interpreted as follows: - * the indices defined in Obd2IntegerSensorIndex are to be used to - * read from int32Values; - * the indices defined in Obd2FloatSensorIndex are to be used to - * read from floatValues. - * the elements of bytes are to be interpreted as a bitmask, such that - * the bits 0 thru the integer value of - * Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[0] - * are 1 if the corresponding index is a valid sensor index whose value can - * be read in the returned int32Values vector, 0 otherwise. - * the bits Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX+1 thru - * Obd2FloatingSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[1] - * are 1 if the corresponding index is a valid sensor index whose value - * can be read in the returned floatValues vector, 0 otherwise. - * - * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and - * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD, but that mapping - * is only valid if the corresponding bits in the bytes vector are set to 1. - * - * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ - */ - OBD2_LIVE_FRAME = ( - 0x0D00 - | VehiclePropertyGroup:SYSTEM - | VehiclePropertyType:COMPLEX - | VehicleArea:GLOBAL), - - /** - * OBD2 Freeze Frame Sensor Data - * - * This property uses COMPLEX data to send a snapshot of the values of the - * OBD2 sensors provided by the vehicle at the time that a diagnostic - * troubleshooting code (DTC) was recorded by the vehicle. - * - * VehiclePropConfig - * configArray[0] : number of vendor-specific integer-valued sensors - * that can be returned in a frame. - * configArray[1] : number of vendor-specific float-valued sensors - * that can be returned in a frame. - * - * A get of this property must take the following form: - * int64Values[0]: timestamp of the freeze frame to retrieve. - * Valid timestamps are given by OBD2_DTC_INFO. - * - * The values are to be interpreted as follows: - * the indices defined in Obd2IntegerSensorIndex are to be used to - * read from int32Values; - * the indices defined in Obd2FloatSensorIndex are to be used to - * read from floatValues; - * the elements of bytes are to be interpreted as a bitmask, such that - * the bits 0 thru the integer value of - * Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[0] - * are 1 if the corresponding index is a valid sensor index whose value can - * be read in the returned int32Values vector, 0 otherwise. - * the bits Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX+1 thru - * Obd2FloatingSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[1] - * are 1 if the corresponding index is a valid sensor index whose value - * can be read in the returned floatValues vector, 0 otherwise. - * stringValue is the DTC that caused this freeze frame to be recorded. - * - * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and - * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD, but that mapping - * is only valid if the corresponding bits in the bytes vector are set to 1, - * and a possible valid stringValue is "P0176" to indicate a malfunction - * of the fuel composition sensor circuit. - * - * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ - */ - OBD2_FREEZE_FRAME = ( - 0x0D01 - | VehiclePropertyGroup:SYSTEM - | VehiclePropertyType:COMPLEX - | VehicleArea:GLOBAL), - - /** - * OBD2 Freeze Frame Information - * - * This property describes the current freeze frames stored in vehicle - * memory and available for retrieval via OBD2_FREEZE_FRAME. - * - * The values are to be interpreted as follows: - * each element of int64Values is the timestamp at which a a fault code - * has been detected and the corresponding freeze frame stored, and each - * such element can be used as the key to OBD2_FREEZE_FRAME to retrieve - * the corresponding freeze frame. - * - * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ - */ - OBD2_FREEZE_FRAME_INFO = ( - 0x0D02 - | VehiclePropertyGroup:SYSTEM - | VehiclePropertyType:COMPLEX - | VehicleArea:GLOBAL), - - /** - * OBD2 Freeze Frame Clear - * - * This property allows deletion of any of the freeze frames stored in - * vehicle memory, as described by OBD2_DTC_INFO. - * - * A set of this property is to be interpreted as follows: - * if int64Values contains no elements, then all DTCs stored will be cleared; - * if int64Values contains one or more elements, then DTCs at the timestamps - * stored in int64Values will be cleared, and the others not cleared, except - * the memory will be compacted so that all remaining DTCs are stored - * contiguously. - * - * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:WRITE - */ - OBD2_FREEZE_FRAME_CLEAR = ( - 0x0D03 - | VehiclePropertyGroup:SYSTEM - | VehiclePropertyType:COMPLEX - | VehicleArea:GLOBAL), - - /** - * Vehicle Maps Service (VMS) message - * - * This property uses COMPLEX data to communicate vms messages. - * - * Its contents are to be interpreted as follows: - * the indices defined in VmsMessageIntegerValuesIndex are to be used to - * read from int32Values; - * bytes is a serialized VMS message as defined in the vms protocol - * which is opaque to the framework; - * - * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE - */ - VEHICLE_MAP_SERVICE = ( - 0x0C00 - | VehiclePropertyGroup:SYSTEM - | VehiclePropertyType:COMPLEX - | VehicleArea:GLOBAL), -}; - -/** The status of a fuel system as described by the OBD2 specification. */ -enum FuelSystemStatus : int32_t { - OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1, - - CLOSED_LOOP = 2, - - OPEN_ENGINE_LOAD_OR_DECELERATION = 4, - - OPEN_SYSTEM_FAILURE = 8, - - CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16, -}; - -/** Defines which ignition monitors are available to be read. */ -enum IgnitionMonitorKind : int32_t { - SPARK = 0, - - COMPRESSION = 1, -}; - -/** These ignition monitors are common to both SPARK and COMPRESSION. */ -enum CommonIgnitionMonitors : int32_t { - COMPONENTS_AVAILABLE = 0x1 << 0, - COMPONENTS_INCOMPLETE = 0x1 << 1, - - FUEL_SYSTEM_AVAILABLE = 0x1 << 2, - FUEL_SYSTEM_INCOMPLETE = 0x1 << 3, - - MISFIRE_AVAILABLE = 0x1 << 4, - MISFIRE_INCOMPLETE = 0x1 << 5, -}; - -/** Ignition monitors available for SPARK vehicles. */ -enum SparkIgnitionMonitors : CommonIgnitionMonitors { - EGR_AVAILABLE = 0x1 << 6, - EGR_INCOMPLETE = 0x1 << 7, - - OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8, - OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9, - - OXYGEN_SENSOR_AVAILABLE = 0x1 << 10, - OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11, - - AC_REFRIGERANT_AVAILABLE = 0x1 << 12, - AC_REFRIGERANT_INCOMPLETE = 0x1 << 13, - - SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14, - SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15, - - EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16, - EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17, - - HEATED_CATALYST_AVAILABLE = 0x1 << 18, - HEATED_CATALYST_INCOMPLETE = 0x1 << 19, - - CATALYST_AVAILABLE = 0x1 << 20, - CATALYST_INCOMPLETE = 0x1 << 21, -}; - -/** Ignition monitors only available for COMPRESSION vehicles. */ -enum CompressionIgnitionMonitors : CommonIgnitionMonitors { - EGR_OR_VVT_AVAILABLE = 0x1 << 6, - EGR_OR_VVT_INCOMPLETE = 0x1 << 7, - - PM_FILTER_AVAILABLE = 0x1 << 8, - PM_FILTER_INCOMPLETE = 0x1 << 9, - - EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10, - EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11, - - BOOST_PRESSURE_AVAILABLE = 0x1 << 12, - BOOST_PRESSURE_INCOMPLETE = 0x1 << 13, - - NOx_SCR__AVAILABLE = 0x1 << 14, - NOx_SCR_INCOMPLETE = 0x1 << 15, - - NMHC_CATALYST_AVAILABLE = 0x1 << 16, - NMHC_CATALYST_INCOMPLETE = 0x1 << 17, -}; - -enum SecondaryAirStatus : int32_t { - UPSTREAM = 1, - - DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2, - - FROM_OUTSIDE_OR_OFF = 4, - - PUMP_ON_FOR_DIAGNOSTICS = 8, -}; - -enum FuelType : int32_t { - NOT_AVAILABLE = 0, - - GASOLINE = 1, - - METHANOL = 2, - - ETHANOL = 3, - - DIESEL = 4, - - LPG = 5, - - CNG = 6, - - PROPANE = 7, - - ELECTRIC = 8, - - BIFUEL_RUNNING_GASOLINE = 9, - - BIFUEL_RUNNING_METHANOL = 10, - - BIFUEL_RUNNING_ETHANOL = 11, - - BIFUEL_RUNNING_LPG = 12, - - BIFUEL_RUNNING_CNG = 13, - - BIFUEL_RUNNING_PROPANE = 14, - - BIFUEL_RUNNING_ELECTRIC = 15, - - BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16, - - HYBRID_GASOLINE = 17, - - HYBRID_ETHANOL = 18, - - HYBRID_DIESEL = 19, - - HYBRID_ELECTRIC = 20, - - HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21, - - HYBRID_REGENERATIVE = 22, - - BIFUEL_RUNNING_DIESEL = 23, -}; - -/** - * This enum provides the canonical mapping for sensor properties that have an integer value. - * The ordering of the values is taken from the OBD2 specification. - * Some of the properties are represented as an integer mapping to another enum. In those cases - * expect a comment by the property definition describing the enum to look at for the mapping. - * Any value greater than the last reserved index is available to vendors to map their extensions. - */ -enum Obd2IntegerSensorIndex : int32_t { - /** refer to FuelSystemStatus for a description of this value. */ - FUEL_SYSTEM_STATUS = 0, - - MALFUNCTION_INDICATOR_LIGHT_ON = 1, - - /** refer to IgnitionMonitorKind for a description of this value. */ - IGNITION_MONITORS_SUPPORTED = 2, - - /** - * The value of this sensor is a bitmask that specifies whether ignition-specific - * tests are available and whether they are complete. The semantics of the individual - * bits in this value are given by, respectively, SparkIgnitionMonitors and - * CompressionIgnitionMonitors depending on the value of IGNITION_MONITORS_SUPPORTED. - */ - IGNITION_SPECIFIC_MONITORS = 3, - - INTAKE_AIR_TEMPERATURE = 4, - - /** refer to SecondaryAirStatus for a description of this value. */ - COMMANDED_SECONDARY_AIR_STATUS = 5, - - NUM_OXYGEN_SENSORS_PRESENT = 6, - - RUNTIME_SINCE_ENGINE_START = 7, - - DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8, - - WARMUPS_SINCE_CODES_CLEARED = 9, - - DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10, - - ABSOLUTE_BAROMETRIC_PRESSURE = 11, - - CONTROL_MODULE_VOLTAGE = 12, - - AMBIENT_AIR_TEMPERATURE = 13, - - TIME_WITH_MALFUNCTION_LIGHT_ON = 14, - - TIME_SINCE_TROUBLE_CODES_CLEARED = 15, - - MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16, - - MAX_OXYGEN_SENSOR_VOLTAGE = 17, - - MAX_OXYGEN_SENSOR_CURRENT = 18, - - MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19, - - MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20, - - /** refer to FuelType for a description of this value. */ - FUEL_TYPE = 21, - - FUEL_RAIL_ABSOLUTE_PRESSURE = 22, - - ENGINE_OIL_TEMPERATURE = 23, - - DRIVER_DEMAND_PERCENT_TORQUE = 24, - - ENGINE_ACTUAL_PERCENT_TORQUE = 25, - - ENGINE_REFERENCE_PERCENT_TORQUE = 26, - - ENGINE_PERCENT_TORQUE_DATA_IDLE = 27, - - ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28, - - ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29, - - ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30, - - ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31, - - LAST_SYSTEM_INDEX = ENGINE_PERCENT_TORQUE_DATA_POINT4, -}; - -/** - * This enum provides the canonical mapping for sensor properties that have a floating-point value. - * The ordering of the values is taken from the OBD2 specification. - * Any value greater than the last reserved index is available to vendors to map their extensions. - */ -enum Obd2FloatSensorIndex : int32_t { - CALCULATED_ENGINE_LOAD = 0, - - ENGINE_COOLANT_TEMPERATURE = 1, - - SHORT_TERM_FUEL_TRIM_BANK1 = 2, - - LONG_TERM_FUEL_TRIM_BANK1 = 3, - - SHORT_TERM_FUEL_TRIM_BANK2 = 4, - - LONG_TERM_FUEL_TRIM_BANK2 = 5, - - FUEL_PRESSURE = 6, - - INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7, - - ENGINE_RPM = 8, - - VEHICLE_SPEED = 9, - - TIMING_ADVANCE = 10, - - MAF_AIR_FLOW_RATE = 11, - - THROTTLE_POSITION = 12, - - OXYGEN_SENSOR1_VOLTAGE = 13, - - OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14, - - OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15, - - OXYGEN_SENSOR2_VOLTAGE = 16, - - OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17, - - OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18, - - OXYGEN_SENSOR3_VOLTAGE = 19, - - OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20, - - OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21, - - OXYGEN_SENSOR4_VOLTAGE = 22, - - OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23, - - OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24, - - OXYGEN_SENSOR5_VOLTAGE = 25, - - OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26, - - OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27, - - OXYGEN_SENSOR6_VOLTAGE = 28, - - OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29, - - OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30, - - OXYGEN_SENSOR7_VOLTAGE = 31, - - OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32, - - OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33, - - OXYGEN_SENSOR8_VOLTAGE = 34, - - OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35, - - OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36, - - FUEL_RAIL_PRESSURE = 37, - - FUEL_RAIL_GAUGE_PRESSURE = 38, - - COMMANDED_EXHAUST_GAS_RECIRCULATION = 39, - - EXHAUST_GAS_RECIRCULATION_ERROR = 40, - - COMMANDED_EVAPORATIVE_PURGE = 41, - - FUEL_TANK_LEVEL_INPUT = 42, - - EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43, - - CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44, - - CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45, - - CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46, - - CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47, - - ABSOLUTE_LOAD_VALUE = 48, - - FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49, - - RELATIVE_THROTTLE_POSITION = 50, - - ABSOLUTE_THROTTLE_POSITION_B = 51, - - ABSOLUTE_THROTTLE_POSITION_C = 52, - - ACCELERATOR_PEDAL_POSITION_D = 53, - - ACCELERATOR_PEDAL_POSITION_E = 54, - - ACCELERATOR_PEDAL_POSITION_F = 55, - - COMMANDED_THROTTLE_ACTUATOR = 56, - - ETHANOL_FUEL_PERCENTAGE = 57, - - ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58, - - SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59, - - SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60, - - SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61, - - SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62, - - LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63, - - LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64, - - LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65, - - LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66, - - RELATIVE_ACCELERATOR_PEDAL_POSITION = 67, - - HYBRID_BATTERY_PACK_REMAINING_LIFE = 68, - - FUEL_INJECTION_TIMING = 69, - - ENGINE_FUEL_RATE = 70, - - LAST_SYSTEM_INDEX = ENGINE_FUEL_RATE, -}; - -/** - * This enum lists the types of supported VMS messages. - */ -enum VmsMessageType : int32_t { - /** A client subscribes to a layer. */ - SUBSCRIBE = 1, - - /** A client unsubscribes from a layer. */ - UNSUBSCRIBE = 2, - - /** A client publishes a data packet. */ - DATA = 3, - - /* A client declaring layers offering. */ - OFFERING = 4, - - /* Requesting the list of available layers. */ - AVAILABILITY_REQUEST = 5, - - /* Returning the list of available layers. */ - AVAILABILITY_RESPONSE = 6, - - /** Requesting layers that have subscribers. */ - SUBSCRIPTION_REQUEST = 7, - - /** Returning layers that have subscribers. */ - SUBSCRIPTION_RESPONSE = 8, -}; - -/** - * This enum provides the canonical mapping for VMS properties that have an - * integer value. - */ -enum VmsBaseMessageIntegerValuesIndex : int32_t { - /* The message type as enumerated by VmsMessageType enum. */ - VMS_MESSAGE_TYPE = 0, -}; - -/* - * This enum provides the canonical mapping for VMS SUBMIT, UNSUBMIT and DATA - * messages integer value properties. - */ -enum VmsSimpleMessageIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { - /* The layer ID as defined in the vms protocol. */ - VMS_LAYER_ID = 1, - - /* The version of the VMS layer. */ - VMS_LAYER_VERSION = 2, -}; - -/* - * This enum provides the canonical mapping for VMS offering messages integer - * value properties - */ -enum VmsOfferingMessageIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { - /* The number of VMS layer dependencies. */ - VMS_NUMBER_OF_LAYERS_DEPENDENCIES = 1, - - /* The first index that contain dependencies */ - FIRST_DEPENDENCIES_INDEX = 2, -}; - -/** - * A VMS subscription request only contains its message type. The format of a VMS subscription - * response is described below. - */ -enum VmsSubscriptionResponseFormat : VmsBaseMessageIntegerValuesIndex { - /** - * Recipients should ignore any packet with a sequence number that is less than the highest - * sequence number they have seen thus far. - */ - SEQUENCE_NUMBER = 1, - - /** The number of VMS layers. Each layer has two integers: type and version. */ - NUMBER_OF_LAYERS = 2, - - /** The first index that contains a layer. */ - FIRST_LAYER = 3, -}; diff --git a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp index c6774ca222..f68795955a 100644 --- a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp +++ b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp @@ -145,6 +145,7 @@ FingerprintAcquiredInfo BiometricsFingerprint::VendorAcquiredFilter( Return<uint64_t> BiometricsFingerprint::setNotify( const sp<IBiometricsFingerprintClientCallback>& clientCallback) { + std::lock_guard<std::mutex> lock(mClientCallbackMutex); mClientCallback = clientCallback; // This is here because HAL 2.1 doesn't have a way to propagate a // unique token for its driver. Subsequent versions should send a unique @@ -259,6 +260,7 @@ fingerprint_device_t* BiometricsFingerprint::openHal() { void BiometricsFingerprint::notify(const fingerprint_msg_t *msg) { BiometricsFingerprint* thisPtr = static_cast<BiometricsFingerprint*>( BiometricsFingerprint::getInstance()); + std::lock_guard<std::mutex> lock(thisPtr->mClientCallbackMutex); if (thisPtr == nullptr || thisPtr->mClientCallback == nullptr) { ALOGE("Receiving callbacks before the client callback is registered."); return; diff --git a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h index 5923c849c8..6d64e3d38d 100644 --- a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h +++ b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h @@ -69,6 +69,7 @@ private: static FingerprintAcquiredInfo VendorAcquiredFilter(int32_t error, int32_t* vendorCode); static BiometricsFingerprint* sInstance; + std::mutex mClientCallbackMutex; sp<IBiometricsFingerprintClientCallback> mClientCallback; fingerprint_device_t *mDevice; }; diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc index d8714f5b5b..7c74643871 100644 --- a/bluetooth/1.0/default/async_fd_watcher.cc +++ b/bluetooth/1.0/default/async_fd_watcher.cc @@ -24,7 +24,7 @@ #include <map> #include <mutex> #include <thread> -#include <utils/Log.h> +#include <log/log.h> #include <vector> #include "fcntl.h" #include "sys/select.h" diff --git a/bluetooth/1.0/default/bluetooth_address.cc b/bluetooth/1.0/default/bluetooth_address.cc index 34df752b3c..93a5469958 100644 --- a/bluetooth/1.0/default/bluetooth_address.cc +++ b/bluetooth/1.0/default/bluetooth_address.cc @@ -19,6 +19,7 @@ #include <cutils/properties.h> #include <errno.h> #include <fcntl.h> +#include <unistd.h> #include <utils/Log.h> namespace android { diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc index 5a89557e39..163cc333c4 100644 --- a/bluetooth/1.0/default/h4_protocol.cc +++ b/bluetooth/1.0/default/h4_protocol.cc @@ -22,6 +22,7 @@ #include <fcntl.h> #include <log/log.h> #include <sys/uio.h> +#include <unistd.h> namespace android { namespace hardware { diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc index 2da1254531..fde08ac1cb 100644 --- a/bluetooth/1.0/default/hci_packetizer.cc +++ b/bluetooth/1.0/default/hci_packetizer.cc @@ -21,6 +21,7 @@ #include <dlfcn.h> #include <errno.h> #include <fcntl.h> +#include <unistd.h> #include <utils/Log.h> namespace { diff --git a/bluetooth/1.0/default/hci_protocol.cc b/bluetooth/1.0/default/hci_protocol.cc index 5d6f1d1396..bf94dfe884 100644 --- a/bluetooth/1.0/default/hci_protocol.cc +++ b/bluetooth/1.0/default/hci_protocol.cc @@ -20,6 +20,7 @@ #include <assert.h> #include <errno.h> #include <fcntl.h> +#include <unistd.h> #include <log/log.h> namespace android { diff --git a/broadcastradio/1.0/default/OWNERS b/broadcastradio/1.0/default/OWNERS new file mode 100644 index 0000000000..b159083944 --- /dev/null +++ b/broadcastradio/1.0/default/OWNERS @@ -0,0 +1,4 @@ +elaurent@google.com +krocard@google.com +mnaganov@google.com +twasilczyk@google.com diff --git a/broadcastradio/1.0/types.hal b/broadcastradio/1.0/types.hal index 045231d495..8c3ec119d3 100644 --- a/broadcastradio/1.0/types.hal +++ b/broadcastradio/1.0/types.hal @@ -146,8 +146,11 @@ enum MetadataType : int32_t { /** String */ TEXT = 1, /** - * Raw binary data (icon or art) - This data must be transparent to the android framework */ + * Raw binary data (icon or art). + * + * The data should be a valid PNG, JPEG, GIF or BMP file. + * Invalid format must be handled gracefully as if the field was missing. + */ RAW = 2, /** clock data, see MetaDataClock */ CLOCK = 3, @@ -155,7 +158,7 @@ enum MetadataType : int32_t { enum MetadataKey : int32_t { INVALID = -1, - /** RDS PI - string */ + /** RDS PI - int32_t */ RDS_PI = 0, /** RDS PS - string */ RDS_PS = 1, @@ -173,9 +176,9 @@ enum MetadataKey : int32_t { ALBUM = 7, /** Musical genre - string */ GENRE = 8, - /** Station icon - raw */ + /** Station icon - raw (int32_t for HAL 1.1) */ ICON = 9, - /** Album art - raw */ + /** Album art - raw (int32_t for HAL 1.1) */ ART = 10, /** Clock - MetaDataClock */ CLOCK = 11, @@ -208,10 +211,24 @@ struct MetaData { struct ProgramInfo { uint32_t channel; /** current channel. (e.g kHz for band type AM_FM) */ uint32_t subChannel; /** current sub channel. (FM_HD) */ - bool tuned; /** tuned to a program or not */ + + /** + * Tuned to a program (not a noise). It's the same condition that would + * stop scan operation. + */ + bool tuned; + bool stereo; /** program is stereo or not */ bool digital; /** digital program or not (e.g HD Radio program) */ - uint32_t signalStrength; /** signal strength from 0 to 100 */ - vec<MetaData> metadata; /** non empty if meta data are present (e.g PTY, song title ...) */ + + /** + * Signal quality measured in 0% to 100% range. + * + * Despite the name, this is not a signal strength. + * The purpose of this field is primarily informative. + */ + uint32_t signalStrength; + + vec<MetaData> metadata; /** Metadata: PTY, song title etc. */ }; diff --git a/broadcastradio/1.1/IBroadcastRadio.hal b/broadcastradio/1.1/IBroadcastRadio.hal index dd37d4942c..dadba2accb 100644 --- a/broadcastradio/1.1/IBroadcastRadio.hal +++ b/broadcastradio/1.1/IBroadcastRadio.hal @@ -27,4 +27,38 @@ interface IBroadcastRadio extends @1.0::IBroadcastRadio { */ getProperties_1_1() generates (Properties properties); + /** + * Fetch image from radio module. + * + * This call is meant to make V1_0::MetaData lightweight - instead of + * passing an image data blob in the MetadataType.RAW field, the HAL + * implementation only passes the identifier, so the client may cache images + * or even not fetch them. + * + * The identifier may be any arbitrary number - sequential, sha256 prefix, + * or any other unique value selected by the vendor. + * + * The data should be a valid PNG, JPEG, GIF or BMP file. + * Image data with an invalid format must be handled gracefully in the same + * way as a missing image. + * + * The image identifier may become invalid after some time from passing it + * with metadata struct (due to resource cleanup at the HAL implementation). + * However, it must remain valid for a currently tuned program at least + * until currentProgramInfoChanged or programListChanged is called and + * metadata changes for the current program. + * + * There is still a race condition possible (if the HAL deletes the old + * image immediately after notifying about the new one) between + * currentProgramInfoChanged callback propagating through the framework and + * the HAL implementation removing previous image. In such case, client + * application may expect the new currentProgramInfoChanged callback with + * updated image identifier. + * + * @param id Identifier of an image; + * value of 0 is reserved and should be treated as invalid image. + * @return image A binary blob with image data + * or a zero-length vector if identifier doesn't exist. + */ + getImage(int32_t id) generates (vec<uint8_t> image); }; diff --git a/broadcastradio/1.1/IBroadcastRadioFactory.hal b/broadcastradio/1.1/IBroadcastRadioFactory.hal index fce1cc0c72..edf78ff09a 100644 --- a/broadcastradio/1.1/IBroadcastRadioFactory.hal +++ b/broadcastradio/1.1/IBroadcastRadioFactory.hal @@ -19,8 +19,10 @@ package android.hardware.broadcastradio@1.1; import @1.0::IBroadcastRadioFactory; /** - * To use 1.1 features you must cast specific interfaces after being returned from 1.0 HAL, - * for example V1_1::ITuner::castFrom() after retrieving it from IBroadcastRadio::openTuner(). + * To use 1.1 features you must cast specific interfaces returned from the + * 1.0 HAL. For example V1_0::IBroadcastRadio::openTuner() returns V1_0::ITuner, + * which can be cast with V1_1::ITuner::castFrom() call. + * * The 1.1 server must always return the 1.1 version of specific interface. */ interface IBroadcastRadioFactory extends @1.0::IBroadcastRadioFactory { diff --git a/broadcastradio/1.1/ITuner.hal b/broadcastradio/1.1/ITuner.hal index 751162966f..b20c5f4fba 100644 --- a/broadcastradio/1.1/ITuner.hal +++ b/broadcastradio/1.1/ITuner.hal @@ -21,6 +21,45 @@ import @1.0::ITuner; interface ITuner extends @1.0::ITuner { /** + * Tune to a specified program. + * + * For AM/FM, it must be called when a valid configuration has been applied. + * Automatically cancels pending scan, step or tune. + * + * If method returns OK, ITunerCallback.tuneComplete_1_1() MUST be called: + * - once successfully tuned; + * - after a time out; + * - after a full band scan, if no station found. + * + * The tuned field of ProgramInfo should indicate if tuned to a valid + * station or not. + * + * @param program Program to tune to. + * @return result OK if successfully started tunning. + * INVALID_ARGUMENTS if invalid arguments are passed. + * NOT_INITIALIZED if another error occurs. + */ + tuneByProgramSelector(ProgramSelector program) generates (Result result); + + /** + * Cancels announcement. + * + * If it was traffic announcement, trafficAnnouncement(false) callback + * should be called (just like it was ended in a normal way). Similarly for + * emergency announcement. If there was no announcement, then no action + * should be taken. + * + * There is a race condition between calling cancelAnnouncement and the + * actual announcement being finished, so trafficAnnouncement / + * emergencyAnnouncement callback should be tracked with proper locking. + * + * @return result OK if successfully cancelled announcement or there was + * no announcement. + * NOT_INITIALIZED if another error occurs. + */ + cancelAnnouncement() generates (Result result); + + /** * Retrieve current station information. * @return result OK if scan successfully started * NOT_INITIALIZED if another error occurs @@ -45,6 +84,13 @@ interface ITuner extends @1.0::ITuner { * subsequent calls to startBackgroundScan, issuing a single * backgroundScanComplete callback. * + * If a device supports continuous background scanning, it may succeed + * (return OK and call backgroundScanComplete) without any additional + * operation performed. + * + * Foreground scanning may be implemented in the front end app with + * @1.0::ITuner scan operation. + * * @return result OK if the scan was properly scheduled (this does not mean * it successfully finished). * UNAVAILABLE if the background scan is unavailable, @@ -60,10 +106,8 @@ interface ITuner extends @1.0::ITuner { * This call does not trigger actual scan, but operates on the list cached * internally at the driver level. * - * @param filter vendor-specific filter for the stations to be retrieved. - * An empty string MUST result in full list. - * Client application MUST verify vendor/product name - * before setting this parameter to anything else. + * @param vendorFilter vendor-specific filter for the stations to be retrieved. + * An empty vector MUST result in full list for a given tuner. * @return result OK if the list was successfully retrieved. * INVALID_ARGUMENTS if invalid arguments are passed * NOT_READY if the scan is in progress. @@ -72,23 +116,10 @@ interface ITuner extends @1.0::ITuner { * NOT_INITIALIZED if any other error occurs. * @return programList List of stations available for user. */ - getProgramList(string filter) + getProgramList(vec<VendorKeyValue> vendorFilter) generates (ProgramListResult result, vec<ProgramInfo> programList); /** - * Checks, if the analog playback is forced, see setAnalogForced. - * - * The isForced value is only valid if result was OK. - * - * @return result OK if the call succeeded and isForced is valid. - * INVALID_STATE if the switch is not supported at current - * configuration. - * NOT_INITIALIZED if any other error occurs. - * @return isForced true if analog is forced, false otherwise. - */ - isAnalogForced() generates (Result result, bool isForced); - - /** * Forces the analog playback for the supporting radio technology. * * User may disable digital playback for FM HD Radio or hybrid FM/DAB with @@ -104,4 +135,17 @@ interface ITuner extends @1.0::ITuner { * NOT_INITIALIZED if any other error occurs. */ setAnalogForced(bool isForced) generates (Result result); + + /** + * Checks, if the analog playback is forced, see setAnalogForced. + * + * The isForced value is only valid if result was OK. + * + * @return result OK if the call succeeded and isForced is valid. + * INVALID_STATE if the switch is not supported at current + * configuration. + * NOT_INITIALIZED if any other error occurs. + * @return isForced true if analog is forced, false otherwise. + */ + isAnalogForced() generates (Result result, bool isForced); }; diff --git a/broadcastradio/1.1/ITunerCallback.hal b/broadcastradio/1.1/ITunerCallback.hal index 158e2170b1..8bf5b7f120 100644 --- a/broadcastradio/1.1/ITunerCallback.hal +++ b/broadcastradio/1.1/ITunerCallback.hal @@ -28,16 +28,19 @@ interface ITunerCallback extends @1.0::ITunerCallback { /** * Method called by the HAL when a tuning operation completes * following a step(), scan() or tune() command. + * + * This callback supersedes V1_0::tuneComplete. + * The 1.0 callback must not be called when HAL implementation detects + * 1.1 client (by casting V1_0::ITunerCallback to V1_1::ITunerCallback). + * + * In case of success, currentProgramInfoChanged must be called too. + * It means the success case may (or may not) be handled by the client in + * currentProgramInfoChanged, instead of here. + * * @param result OK if tune succeeded or TIMEOUT in case of time out. - * @param info A ProgramInfo structure describing the tuned station. + * @param selector A ProgramSelector structure describing the tuned station. */ - oneway tuneComplete_1_1(Result result, ProgramInfo info); - - /** - * Method called by the HAL when a frequency switch occurs. - * @param info A ProgramInfo structure describing the new tuned station. - */ - oneway afSwitch_1_1(ProgramInfo info); + oneway tuneComplete_1_1(Result result, ProgramSelector selector); /** * Called by the HAL when background scan feature becomes available or not. @@ -63,10 +66,31 @@ interface ITunerCallback extends @1.0::ITunerCallback { * call it immediately, ie. it may wait for a short time to accumulate * multiple list change notifications into a single event. * + * This callback is only for notifying about insertions and deletions, + * not about metadata changes. + * * It may be triggered either by an explicitly issued background scan, * or a scan issued by the device internally. * * Client may retrieve the actual list with ITuner::getProgramList. */ oneway programListChanged(); + + /** + * Method called by the HAL when current program information (including + * metadata) is updated. + * + * Client may retrieve the actual program info with + * ITuner::getProgramInformation_1_1. + * + * This may be called together with tuneComplete_1_1 or afSwitch_1_1. + * + * This callback supersedes V1_0::newMetadata and V1_0::afSwitch; + * partly V1_0::tuneComplete. + * 1.0 callbacks must not be called when HAL implementation detects + * 1.1 client (by casting V1_0::ITunerCallback to V1_1::ITunerCallback). + * + * @param info current program information + */ + oneway currentProgramInfoChanged(ProgramInfo info); }; diff --git a/broadcastradio/1.1/WARNING b/broadcastradio/1.1/WARNING deleted file mode 100644 index e867cfa362..0000000000 --- a/broadcastradio/1.1/WARNING +++ /dev/null @@ -1 +0,0 @@ -This is experimental interface, do not use it yet. diff --git a/broadcastradio/1.1/default/Android.bp b/broadcastradio/1.1/default/Android.bp index 759eb09118..6d26b11bd8 100644 --- a/broadcastradio/1.1/default/Android.bp +++ b/broadcastradio/1.1/default/Android.bp @@ -14,8 +14,9 @@ // limitations under the License. // -cc_library_shared { - name: "android.hardware.broadcastradio@1.1-impl", +cc_binary { + name: "android.hardware.broadcastradio@1.1-service", + init_rc: ["android.hardware.broadcastradio@1.1-service.rc"], vendor: true, relative_install_path: "hw", cflags: [ @@ -27,16 +28,20 @@ cc_library_shared { "BroadcastRadio.cpp", "BroadcastRadioFactory.cpp", "Tuner.cpp", - "Utils.cpp", + "VirtualProgram.cpp", + "VirtualRadio.cpp", + "service.cpp" + ], + static_libs: [ + "android.hardware.broadcastradio@1.1-utils-lib", ], shared_libs: [ + "android.hardware.broadcastradio@1.0", + "android.hardware.broadcastradio@1.1", + "libbase", "libhidlbase", "libhidltransport", - "libutils", "liblog", - "libhardware", - "android.hardware.broadcastradio@1.0", - "android.hardware.broadcastradio@1.1", - "libradio_metadata", + "libutils", ], } diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp index 68c9b93870..1bcfd824f7 100644 --- a/broadcastradio/1.1/default/BroadcastRadio.cpp +++ b/broadcastradio/1.1/default/BroadcastRadio.cpp @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "BroadcastRadio" -//#define LOG_NDEBUG 0 +#define LOG_TAG "BroadcastRadioDefault.module" +#define LOG_NDEBUG 0 + +#include "BroadcastRadio.h" #include <log/log.h> -#include "BroadcastRadio.h" -#include "Tuner.h" -#include "Utils.h" +#include "resources.h" namespace android { namespace hardware { @@ -28,117 +28,163 @@ namespace broadcastradio { namespace V1_1 { namespace implementation { -using ::android::sp; +using V1_0::Band; +using V1_0::BandConfig; +using V1_0::Class; +using V1_0::Deemphasis; +using V1_0::Rds; + +using std::lock_guard; +using std::map; +using std::mutex; +using std::vector; + +// clang-format off +static const map<Class, ModuleConfig> gModuleConfigs{ + {Class::AM_FM, ModuleConfig({ + "Digital radio mock", + { // amFmBands + AmFmBandConfig({ + Band::AM, + 153, // lowerLimit + 26100, // upperLimit + {5, 9, 10}, // spacings + }), + AmFmBandConfig({ + Band::FM, + 65800, // lowerLimit + 108000, // upperLimit + {10, 100, 200}, // spacings + }), + AmFmBandConfig({ + Band::AM_HD, + 153, // lowerLimit + 26100, // upperLimit + {5, 9, 10}, // spacings + }), + AmFmBandConfig({ + Band::FM_HD, + 87700, // lowerLimit + 107900, // upperLimit + {200}, // spacings + }), + }, + })}, + + {Class::SAT, ModuleConfig({ + "Satellite radio mock", + {}, // amFmBands + })}, +}; +// clang-format on BroadcastRadio::BroadcastRadio(Class classId) - : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL) -{ + : mClassId(classId), mConfig(gModuleConfigs.at(classId)) {} + +bool BroadcastRadio::isSupported(Class classId) { + return gModuleConfigs.find(classId) != gModuleConfigs.end(); } -BroadcastRadio::~BroadcastRadio() -{ - if (mHwDevice != NULL) { - radio_hw_device_close(mHwDevice); - } +Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) { + ALOGV("%s", __func__); + return getProperties_1_1( + [&](const Properties& properties) { _hidl_cb(Result::OK, properties.base); }); } -void BroadcastRadio::onFirstRef() -{ - const hw_module_t *mod; - int rc; - ALOGI("%s mClassId %d", __FUNCTION__, mClassId); - - mHwDevice = NULL; - const char *classString = Utils::getClassString(mClassId); - if (classString == NULL) { - ALOGE("invalid class ID %d", mClassId); - mStatus = Result::INVALID_ARGUMENTS; - return; +Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) { + ALOGV("%s", __func__); + Properties prop11 = {}; + auto& prop10 = prop11.base; + + prop10.classId = mClassId; + prop10.implementor = "Google"; + prop10.product = mConfig.productName; + prop10.numTuners = 1; + prop10.numAudioSources = 1; + prop10.supportsCapture = false; + prop11.supportsBackgroundScanning = false; + prop11.supportedProgramTypes = hidl_vec<uint32_t>({ + static_cast<uint32_t>(ProgramType::AM), static_cast<uint32_t>(ProgramType::FM), + static_cast<uint32_t>(ProgramType::AM_HD), static_cast<uint32_t>(ProgramType::FM_HD), + }); + prop11.supportedIdentifierTypes = hidl_vec<uint32_t>({ + static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY), + static_cast<uint32_t>(IdentifierType::RDS_PI), + static_cast<uint32_t>(IdentifierType::HD_STATION_ID_EXT), + static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), + }); + prop11.vendorInfo = hidl_vec<VendorKeyValue>({ + {"com.google.dummy", "dummy"}, + }); + + prop10.bands.resize(mConfig.amFmBands.size()); + for (size_t i = 0; i < mConfig.amFmBands.size(); i++) { + auto& src = mConfig.amFmBands[i]; + auto& dst = prop10.bands[i]; + + dst.type = src.type; + dst.antennaConnected = true; + dst.lowerLimit = src.lowerLimit; + dst.upperLimit = src.upperLimit; + dst.spacings = src.spacings; + + if (utils::isAm(src.type)) { + dst.ext.am.stereo = true; + } else if (utils::isFm(src.type)) { + dst.ext.fm.deemphasis = static_cast<Deemphasis>(Deemphasis::D50 | Deemphasis::D75); + dst.ext.fm.stereo = true; + dst.ext.fm.rds = static_cast<Rds>(Rds::WORLD | Rds::US); + dst.ext.fm.ta = true; + dst.ext.fm.af = true; + dst.ext.fm.ea = true; + } } - ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s", - __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString); - - rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod); - if (rc != 0) { - ALOGE("couldn't load radio module %s.%s (%s)", - RADIO_HARDWARE_MODULE_ID, classString, strerror(-rc)); - return; - } - rc = radio_hw_device_open(mod, &mHwDevice); - if (rc != 0) { - ALOGE("couldn't open radio hw device in %s.%s (%s)", - RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc)); - mHwDevice = NULL; - return; - } - if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) { - ALOGE("wrong radio hw device version %04x", mHwDevice->common.version); - radio_hw_device_close(mHwDevice); - mHwDevice = NULL; - } else { - mStatus = Result::OK; - } + _hidl_cb(prop11); + return Void(); } -int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner) -{ - ALOGV("%s", __FUNCTION__); - if (mHwDevice == NULL) { - return -ENODEV; +Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused, + const sp<V1_0::ITunerCallback>& callback, + openTuner_cb _hidl_cb) { + ALOGV("%s(%s)", __func__, toString(config.type).c_str()); + lock_guard<mutex> lk(mMut); + + auto oldTuner = mTuner.promote(); + if (oldTuner != nullptr) { + ALOGI("Force-closing previously opened tuner"); + oldTuner->forceClose(); + mTuner = nullptr; } - if (halTuner == 0) { - return -EINVAL; - } - return mHwDevice->close_tuner(mHwDevice, halTuner); -} - -// Methods from ::android::hardware::broadcastradio::V1_1::IBroadcastRadio follow. -Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) -{ - int rc; - radio_hal_properties_t halProperties; - Properties properties; - - if (mHwDevice == NULL) { - rc = -ENODEV; - goto exit; - } - rc = mHwDevice->get_properties(mHwDevice, &halProperties); - if (rc == 0) { - Utils::convertPropertiesFromHal(&properties, &halProperties); + sp<Tuner> newTuner = new Tuner(mClassId, callback); + mTuner = newTuner; + if (mClassId == Class::AM_FM) { + auto ret = newTuner->setConfiguration(config); + if (ret != Result::OK) { + _hidl_cb(Result::INVALID_ARGUMENTS, {}); + return Void(); + } } -exit: - _hidl_cb(Utils::convertHalResult(rc), properties); + _hidl_cb(Result::OK, newTuner); return Void(); } -Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb __unused) -{ - return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); -} +Return<void> BroadcastRadio::getImage(int32_t id, getImage_cb _hidl_cb) { + ALOGV("%s(%x)", __func__, id); -Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio, - const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb) -{ - sp<Tuner> tunerImpl = new Tuner(callback, this); - - radio_hal_band_config_t halConfig; - const struct radio_tuner *halTuner; - Utils::convertBandConfigToHal(&halConfig, &config); - int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio, Tuner::callback, - tunerImpl.get(), &halTuner); - if (rc == 0) { - tunerImpl->setHalTuner(halTuner); + if (id == resources::demoPngId) { + _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng))); + return {}; } - _hidl_cb(Utils::convertHalResult(rc), tunerImpl); + ALOGI("Image %x doesn't exists", id); + _hidl_cb({}); return Void(); } -} // namespace implementation +} // namespace implementation } // namespace V1_1 } // namespace broadcastradio } // namespace hardware diff --git a/broadcastradio/1.1/default/BroadcastRadio.h b/broadcastradio/1.1/default/BroadcastRadio.h index 7de31a07cb..a96a2ab933 100644 --- a/broadcastradio/1.1/default/BroadcastRadio.h +++ b/broadcastradio/1.1/default/BroadcastRadio.h @@ -16,9 +16,10 @@ #ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H #define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H +#include "Tuner.h" + #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h> #include <android/hardware/broadcastradio/1.1/types.h> -#include <hardware/radio.h> namespace android { namespace hardware { @@ -26,42 +27,49 @@ namespace broadcastradio { namespace V1_1 { namespace implementation { -using V1_0::Class; -using V1_0::BandConfig; -using V1_0::Properties; +struct AmFmBandConfig { + V1_0::Band type; + uint32_t lowerLimit; // kHz + uint32_t upperLimit; // kHz + std::vector<uint32_t> spacings; // kHz +}; + +struct ModuleConfig { + std::string productName; + std::vector<AmFmBandConfig> amFmBands; +}; struct BroadcastRadio : public V1_1::IBroadcastRadio { + /** + * Constructs new broadcast radio module. + * + * Before calling a constructor with a given classId, it must be checked with isSupported + * method first. Otherwise it results in undefined behaviour. + * + * @param classId type of a radio. + */ + BroadcastRadio(V1_0::Class classId); - BroadcastRadio(Class classId); + /** + * Checks, if a given radio type is supported. + * + * @param classId type of a radio. + */ + static bool isSupported(V1_0::Class classId); - // Methods from ::android::hardware::broadcastradio::V1_1::IBroadcastRadio follow. + // V1_1::IBroadcastRadio methods Return<void> getProperties(getProperties_cb _hidl_cb) override; Return<void> getProperties_1_1(getProperties_1_1_cb _hidl_cb) override; - Return<void> openTuner(const BandConfig& config, bool audio, - const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb) override; - - // RefBase - virtual void onFirstRef() override; - - Result initCheck() { return mStatus; } - int closeHalTuner(const struct radio_tuner *halTuner); - -private: - virtual ~BroadcastRadio(); - - static const char * sClassModuleNames[]; - - Result convertHalResult(int rc); - void convertBandConfigFromHal(BandConfig *config, - const radio_hal_band_config_t *halConfig); - void convertPropertiesFromHal(Properties *properties, - const radio_hal_properties_t *halProperties); - void convertBandConfigToHal(radio_hal_band_config_t *halConfig, - const BandConfig *config); + Return<void> openTuner(const V1_0::BandConfig& config, bool audio, + const sp<V1_0::ITunerCallback>& callback, + openTuner_cb _hidl_cb) override; + Return<void> getImage(int32_t id, getImage_cb _hidl_cb); - Result mStatus; - Class mClassId; - struct radio_hw_device *mHwDevice; + private: + std::mutex mMut; + V1_0::Class mClassId; + ModuleConfig mConfig; + wp<Tuner> mTuner; }; } // namespace implementation diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp index c8b6c39f54..f57bc79feb 100644 --- a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp +++ b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp @@ -13,29 +13,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#define LOG_TAG "BroadcastRadioDefault.factory" +#define LOG_NDEBUG 0 + #include "BroadcastRadioFactory.h" + #include "BroadcastRadio.h" +#include <log/log.h> + namespace android { namespace hardware { namespace broadcastradio { namespace V1_1 { namespace implementation { -// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow. -Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) { - sp<BroadcastRadio> impl = new BroadcastRadio(classId); - Result retval = Result::NOT_INITIALIZED; - if (impl != 0) { - retval = impl->initCheck(); +using V1_0::Class; + +using std::vector; + +static const vector<Class> gAllClasses = { + Class::AM_FM, Class::SAT, Class::DT, +}; + +IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name __unused) { + return new BroadcastRadioFactory(); +} + +BroadcastRadioFactory::BroadcastRadioFactory() { + for (auto&& classId : gAllClasses) { + if (!BroadcastRadio::isSupported(classId)) continue; + mRadioModules[classId] = new BroadcastRadio(classId); } - _hidl_cb(retval, impl); - return Void(); } +Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) { + ALOGV("%s(%s)", __func__, toString(classId).c_str()); -IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) { - return new BroadcastRadioFactory(); + auto moduleIt = mRadioModules.find(classId); + if (moduleIt == mRadioModules.end()) { + _hidl_cb(Result::INVALID_ARGUMENTS, nullptr); + } else { + _hidl_cb(Result::OK, moduleIt->second); + } + + return Void(); } } // namespace implementation diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.h b/broadcastradio/1.1/default/BroadcastRadioFactory.h index 8eb851485a..8b67ac3637 100644 --- a/broadcastradio/1.1/default/BroadcastRadioFactory.h +++ b/broadcastradio/1.1/default/BroadcastRadioFactory.h @@ -16,6 +16,7 @@ #ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H #define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H +#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h> #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> #include <android/hardware/broadcastradio/1.1/types.h> @@ -25,14 +26,17 @@ namespace broadcastradio { namespace V1_1 { namespace implementation { -using V1_0::Class; +extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name); struct BroadcastRadioFactory : public IBroadcastRadioFactory { - // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow. - Return<void> connectModule(Class classId, connectModule_cb _hidl_cb) override; -}; + BroadcastRadioFactory(); -extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name); + // V1_0::IBroadcastRadioFactory methods + Return<void> connectModule(V1_0::Class classId, connectModule_cb _hidl_cb) override; + + private: + std::map<V1_0::Class, sp<IBroadcastRadio>> mRadioModules; +}; } // namespace implementation } // namespace V1_1 diff --git a/broadcastradio/1.1/default/OWNERS b/broadcastradio/1.1/default/OWNERS new file mode 100644 index 0000000000..0c27b71865 --- /dev/null +++ b/broadcastradio/1.1/default/OWNERS @@ -0,0 +1,4 @@ +# Automotive team +egranata@google.com +keunyoung@google.com +twasilczyk@google.com diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp index ae5848cec7..9a34cb128c 100644 --- a/broadcastradio/1.1/default/Tuner.cpp +++ b/broadcastradio/1.1/default/Tuner.cpp @@ -14,15 +14,14 @@ * limitations under the License. */ -#define LOG_TAG "Tuner" -//#define LOG_NDEBUG 0 - -#include <log/log.h> +#define LOG_TAG "BroadcastRadioDefault.tuner" +#define LOG_NDEBUG 0 #include "BroadcastRadio.h" #include "Tuner.h" -#include "Utils.h" -#include <system/RadioMetadataWrapper.h> + +#include <broadcastradio-utils/Utils.h> +#include <log/log.h> namespace android { namespace hardware { @@ -30,199 +29,351 @@ namespace broadcastradio { namespace V1_1 { namespace implementation { -void Tuner::onCallback(radio_hal_event_t *halEvent) -{ - BandConfig config; - ProgramInfo info; - hidl_vec<MetaData> metadata; - - if (mCallback != 0) { - switch(halEvent->type) { - case RADIO_EVENT_CONFIG: - Utils::convertBandConfigFromHal(&config, &halEvent->config); - mCallback->configChange(Utils::convertHalResult(halEvent->status), config); - break; - case RADIO_EVENT_ANTENNA: - mCallback->antennaStateChange(halEvent->on); - break; - case RADIO_EVENT_TUNED: - Utils::convertProgramInfoFromHal(&info, &halEvent->info); - if (mCallback1_1 != nullptr) { - mCallback1_1->tuneComplete_1_1(Utils::convertHalResult(halEvent->status), info); - } - mCallback->tuneComplete(Utils::convertHalResult(halEvent->status), info.base); - break; - case RADIO_EVENT_METADATA: { - uint32_t channel; - uint32_t sub_channel; - if (radio_metadata_get_channel(halEvent->metadata, &channel, &sub_channel) == 0) { - Utils::convertMetaDataFromHal(metadata, halEvent->metadata); - mCallback->newMetadata(channel, sub_channel, metadata); - } - } break; - case RADIO_EVENT_TA: - mCallback->trafficAnnouncement(halEvent->on); - break; - case RADIO_EVENT_AF_SWITCH: - Utils::convertProgramInfoFromHal(&info, &halEvent->info); - if (mCallback1_1 != nullptr) { - mCallback1_1->afSwitch_1_1(info); - } - mCallback->afSwitch(info.base); - break; - case RADIO_EVENT_EA: - mCallback->emergencyAnnouncement(halEvent->on); - break; - case RADIO_EVENT_HW_FAILURE: - default: - mCallback->hardwareFailure(); - break; +using namespace std::chrono_literals; + +using V1_0::Band; +using V1_0::BandConfig; +using V1_0::Class; +using V1_0::Direction; +using utils::HalRevision; + +using std::chrono::milliseconds; +using std::lock_guard; +using std::move; +using std::mutex; +using std::sort; +using std::vector; + +const struct { + milliseconds config = 50ms; + milliseconds scan = 200ms; + milliseconds step = 100ms; + milliseconds tune = 150ms; +} gDefaultDelay; + +Tuner::Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback) + : mClassId(classId), + mCallback(callback), + mCallback1_1(ITunerCallback::castFrom(callback).withDefault(nullptr)), + mVirtualRadio(getRadio(classId)), + mIsAnalogForced(false) {} + +void Tuner::forceClose() { + lock_guard<mutex> lk(mMut); + mIsClosed = true; + mThread.cancelAll(); +} + +Return<Result> Tuner::setConfiguration(const BandConfig& config) { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return Result::NOT_INITIALIZED; + if (mClassId != Class::AM_FM) { + ALOGE("Can't set AM/FM configuration on SAT/DT radio tuner"); + return Result::INVALID_STATE; + } + + if (config.lowerLimit >= config.upperLimit) return Result::INVALID_ARGUMENTS; + + auto task = [this, config]() { + ALOGI("Setting AM/FM config"); + lock_guard<mutex> lk(mMut); + + mAmfmConfig = move(config); + mAmfmConfig.antennaConnected = true; + mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit); + + if (utils::isFm(mAmfmConfig.type)) { + mVirtualRadio = std::ref(getFmRadio()); + } else { + mVirtualRadio = std::ref(getAmRadio()); } + + mIsAmfmConfigSet = true; + mCallback->configChange(Result::OK, mAmfmConfig); + }; + mThread.schedule(task, gDefaultDelay.config); + + return Result::OK; +} + +Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + + if (!mIsClosed && mIsAmfmConfigSet) { + _hidl_cb(Result::OK, mAmfmConfig); + } else { + _hidl_cb(Result::NOT_INITIALIZED, {}); } + return {}; } -//static -void Tuner::callback(radio_hal_event_t *halEvent, void *cookie) -{ - wp<Tuner> weak(reinterpret_cast<Tuner*>(cookie)); - sp<Tuner> tuner = weak.promote(); - if (tuner == 0) return; - tuner->onCallback(halEvent); +// makes ProgramInfo that points to no program +static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) { + ProgramInfo info11 = {}; + auto& info10 = info11.base; + + utils::getLegacyChannel(selector, &info10.channel, &info10.subChannel); + info11.selector = selector; + info11.flags |= ProgramInfoFlags::MUTED; + + return info11; } -Tuner::Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& parentDevice) - : mHalTuner(NULL), mCallback(callback), mCallback1_1(ITunerCallback::castFrom(callback)), - mParentDevice(parentDevice) -{ - ALOGV("%s", __FUNCTION__); +HalRevision Tuner::getHalRev() const { + if (mCallback1_1 != nullptr) { + return HalRevision::V1_1; + } else { + return HalRevision::V1_0; + } } +void Tuner::tuneInternalLocked(const ProgramSelector& sel) { + VirtualProgram virtualProgram; + if (mVirtualRadio.get().getProgram(sel, virtualProgram)) { + mCurrentProgram = virtualProgram.selector; + mCurrentProgramInfo = virtualProgram.getProgramInfo(getHalRev()); + } else { + mCurrentProgram = sel; + mCurrentProgramInfo = makeDummyProgramInfo(sel); + } + mIsTuneCompleted = true; -Tuner::~Tuner() -{ - ALOGV("%s", __FUNCTION__); - const sp<BroadcastRadio> parentDevice = mParentDevice.promote(); - if (parentDevice != 0) { - parentDevice->closeHalTuner(mHalTuner); + if (mCallback1_1 == nullptr) { + mCallback->tuneComplete(Result::OK, mCurrentProgramInfo.base); + } else { + mCallback1_1->tuneComplete_1_1(Result::OK, mCurrentProgramInfo.selector); + mCallback1_1->currentProgramInfoChanged(mCurrentProgramInfo); } } -// Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow. -Return<Result> Tuner::setConfiguration(const BandConfig& config) { - ALOGV("%s", __FUNCTION__); - if (mHalTuner == NULL) { - return Utils::convertHalResult(-ENODEV); +Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return Result::NOT_INITIALIZED; + + auto list = mVirtualRadio.get().getProgramList(); + + if (list.empty()) { + mIsTuneCompleted = false; + auto task = [this, direction]() { + ALOGI("Performing failed scan %s", toString(direction).c_str()); + + if (mCallback1_1 == nullptr) { + mCallback->tuneComplete(Result::TIMEOUT, {}); + } else { + mCallback1_1->tuneComplete_1_1(Result::TIMEOUT, {}); + } + }; + mThread.schedule(task, gDefaultDelay.scan); + + return Result::OK; + } + + // Not optimal (O(sort) instead of O(n)), but not a big deal here; + // also, it's likely that list is already sorted (so O(n) anyway). + sort(list.begin(), list.end()); + auto current = mCurrentProgram; + auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current})); + if (direction == Direction::UP) { + if (found < list.end() - 1) { + if (utils::tunesTo(current, found->selector)) found++; + } else { + found = list.begin(); + } + } else { + if (found > list.begin() && found != list.end()) { + found--; + } else { + found = list.end() - 1; + } } - radio_hal_band_config_t halConfig; - Utils::convertBandConfigToHal(&halConfig, &config); - int rc = mHalTuner->set_configuration(mHalTuner, &halConfig); - return Utils::convertHalResult(rc); + auto tuneTo = found->selector; + + mIsTuneCompleted = false; + auto task = [this, tuneTo, direction]() { + ALOGI("Performing scan %s", toString(direction).c_str()); + + lock_guard<mutex> lk(mMut); + tuneInternalLocked(tuneTo); + }; + mThread.schedule(task, gDefaultDelay.scan); + + return Result::OK; } -Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) { - int rc; - radio_hal_band_config_t halConfig; - BandConfig config; +Return<Result> Tuner::step(Direction direction, bool skipSubChannel) { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return Result::NOT_INITIALIZED; - ALOGV("%s", __FUNCTION__); - if (mHalTuner == NULL) { - rc = -ENODEV; - goto exit; + ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel"); + + if (!utils::isAmFm(utils::getType(mCurrentProgram))) { + ALOGE("Can't step in anything else than AM/FM"); + return Result::NOT_INITIALIZED; } - rc = mHalTuner->get_configuration(mHalTuner, &halConfig); - if (rc == 0) { - Utils::convertBandConfigFromHal(&config, &halConfig); + + if (!mIsAmfmConfigSet) { + ALOGW("AM/FM config not set"); + return Result::INVALID_STATE; } + mIsTuneCompleted = false; + + auto task = [this, direction]() { + ALOGI("Performing step %s", toString(direction).c_str()); + + lock_guard<mutex> lk(mMut); -exit: - _hidl_cb(Utils::convertHalResult(rc), config); - return Void(); + auto current = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY, 0); + + if (direction == Direction::UP) { + current += mAmfmConfig.spacings[0]; + } else { + current -= mAmfmConfig.spacings[0]; + } + + if (current > mAmfmConfig.upperLimit) current = mAmfmConfig.lowerLimit; + if (current < mAmfmConfig.lowerLimit) current = mAmfmConfig.upperLimit; + + tuneInternalLocked(utils::make_selector(mAmfmConfig.type, current)); + }; + mThread.schedule(task, gDefaultDelay.step); + + return Result::OK; } -Return<Result> Tuner::scan(Direction direction, bool skipSubChannel) { - if (mHalTuner == NULL) { - return Utils::convertHalResult(-ENODEV); +Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) { + ALOGV("%s(%d, %d)", __func__, channel, subChannel); + Band band; + { + lock_guard<mutex> lk(mMut); + band = mAmfmConfig.type; } - int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel); - return Utils::convertHalResult(rc); + return tuneByProgramSelector(utils::make_selector(band, channel, subChannel)); } -Return<Result> Tuner::step(Direction direction, bool skipSubChannel) { - if (mHalTuner == NULL) { - return Utils::convertHalResult(-ENODEV); +Return<Result> Tuner::tuneByProgramSelector(const ProgramSelector& sel) { + ALOGV("%s(%s)", __func__, toString(sel).c_str()); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return Result::NOT_INITIALIZED; + + // checking if ProgramSelector is valid + auto programType = utils::getType(sel); + if (utils::isAmFm(programType)) { + if (!mIsAmfmConfigSet) { + ALOGW("AM/FM config not set"); + return Result::INVALID_STATE; + } + + auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY); + if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) { + return Result::INVALID_ARGUMENTS; + } + } else if (programType == ProgramType::DAB) { + if (!utils::hasId(sel, IdentifierType::DAB_SIDECC)) return Result::INVALID_ARGUMENTS; + } else if (programType == ProgramType::DRMO) { + if (!utils::hasId(sel, IdentifierType::DRMO_SERVICE_ID)) return Result::INVALID_ARGUMENTS; + } else if (programType == ProgramType::SXM) { + if (!utils::hasId(sel, IdentifierType::SXM_SERVICE_ID)) return Result::INVALID_ARGUMENTS; + } else { + return Result::INVALID_ARGUMENTS; } - int rc = mHalTuner->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel); - return Utils::convertHalResult(rc); + + mIsTuneCompleted = false; + auto task = [this, sel]() { + lock_guard<mutex> lk(mMut); + tuneInternalLocked(sel); + }; + mThread.schedule(task, gDefaultDelay.tune); + + return Result::OK; } -Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) { - if (mHalTuner == NULL) { - return Utils::convertHalResult(-ENODEV); - } - int rc = mHalTuner->tune(mHalTuner, channel, subChannel); - return Utils::convertHalResult(rc); +Return<Result> Tuner::cancel() { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return Result::NOT_INITIALIZED; + + mThread.cancelAll(); + return Result::OK; } -Return<Result> Tuner::cancel() { - if (mHalTuner == NULL) { - return Utils::convertHalResult(-ENODEV); - } - int rc = mHalTuner->cancel(mHalTuner); - return Utils::convertHalResult(rc); +Return<Result> Tuner::cancelAnnouncement() { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return Result::NOT_INITIALIZED; + + return Result::OK; } -Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) { - ALOGV("%s", __FUNCTION__); +Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) { + ALOGV("%s", __func__); return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) { _hidl_cb(result, info.base); }); } -Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) { - int rc; - radio_program_info_t halInfo; - RadioMetadataWrapper metadataWrapper(&halInfo.metadata); - ProgramInfo info; - - ALOGV("%s", __FUNCTION__); - if (mHalTuner == NULL) { - rc = -ENODEV; - goto exit; - } +Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); - rc = mHalTuner->get_program_information(mHalTuner, &halInfo); - if (rc == 0) { - Utils::convertProgramInfoFromHal(&info, &halInfo); + if (mIsClosed) { + _hidl_cb(Result::NOT_INITIALIZED, {}); + } else if (mIsTuneCompleted) { + _hidl_cb(Result::OK, mCurrentProgramInfo); + } else { + _hidl_cb(Result::NOT_INITIALIZED, makeDummyProgramInfo(mCurrentProgram)); } - -exit: - _hidl_cb(Utils::convertHalResult(rc), info); - return Void(); + return {}; } Return<ProgramListResult> Tuner::startBackgroundScan() { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return ProgramListResult::NOT_INITIALIZED; + return ProgramListResult::UNAVAILABLE; } -Return<void> Tuner::getProgramList(const hidl_string& filter __unused, getProgramList_cb _hidl_cb) { - hidl_vec<ProgramInfo> pList; - // TODO(b/34054813): do the actual implementation. - _hidl_cb(ProgramListResult::NOT_STARTED, pList); - return Void(); +Return<void> Tuner::getProgramList(const hidl_vec<VendorKeyValue>& vendorFilter, + getProgramList_cb _hidl_cb) { + ALOGV("%s(%s)", __func__, toString(vendorFilter).substr(0, 100).c_str()); + lock_guard<mutex> lk(mMut); + if (mIsClosed) { + _hidl_cb(ProgramListResult::NOT_INITIALIZED, {}); + return {}; + } + + auto list = mVirtualRadio.get().getProgramList(); + ALOGD("returning a list of %zu programs", list.size()); + _hidl_cb(ProgramListResult::OK, getProgramInfoVector(list, getHalRev())); + return {}; } -Return<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) { - // TODO(b/34348946): do the actual implementation. - _hidl_cb(Result::INVALID_STATE, false); - return Void(); +Return<Result> Tuner::setAnalogForced(bool isForced) { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + if (mIsClosed) return Result::NOT_INITIALIZED; + + mIsAnalogForced = isForced; + return Result::OK; } -Return<Result> Tuner::setAnalogForced(bool isForced __unused) { - // TODO(b/34348946): do the actual implementation. - return Result::INVALID_STATE; +Return<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) { + ALOGV("%s", __func__); + lock_guard<mutex> lk(mMut); + + if (mIsClosed) { + _hidl_cb(Result::NOT_INITIALIZED, false); + } else { + _hidl_cb(Result::OK, mIsAnalogForced); + } + return {}; } -} // namespace implementation +} // namespace implementation } // namespace V1_1 } // namespace broadcastradio } // namespace hardware diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h index 57eafd3d7c..07d31898a7 100644 --- a/broadcastradio/1.1/default/Tuner.h +++ b/broadcastradio/1.1/default/Tuner.h @@ -16,8 +16,11 @@ #ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H #define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H +#include "VirtualRadio.h" + #include <android/hardware/broadcastradio/1.1/ITuner.h> #include <android/hardware/broadcastradio/1.1/ITunerCallback.h> +#include <broadcastradio-utils/WorkerThread.h> namespace android { namespace hardware { @@ -25,43 +28,48 @@ namespace broadcastradio { namespace V1_1 { namespace implementation { -using V1_0::Direction; - -struct BroadcastRadio; - struct Tuner : public ITuner { + Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback); - Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& mParentDevice); - - // Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow. - Return<Result> setConfiguration(const BandConfig& config) override; - Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override; - Return<Result> scan(Direction direction, bool skipSubChannel) override; - Return<Result> step(Direction direction, bool skipSubChannel) override; - Return<Result> tune(uint32_t channel, uint32_t subChannel) override; - Return<Result> cancel() override; - Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override; - Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override; - Return<ProgramListResult> startBackgroundScan() override; - Return<void> getProgramList(const hidl_string& filter, getProgramList_cb _hidl_cb) override; - Return<void> isAnalogForced(isAnalogForced_cb _hidl_cb) override; - Return<Result> setAnalogForced(bool isForced) override; + void forceClose(); - static void callback(radio_hal_event_t *halEvent, void *cookie); - void onCallback(radio_hal_event_t *halEvent); + // V1_1::ITuner methods + virtual Return<Result> setConfiguration(const V1_0::BandConfig& config) override; + virtual Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override; + virtual Return<Result> scan(V1_0::Direction direction, bool skipSubChannel) override; + virtual Return<Result> step(V1_0::Direction direction, bool skipSubChannel) override; + virtual Return<Result> tune(uint32_t channel, uint32_t subChannel) override; + virtual Return<Result> tuneByProgramSelector(const ProgramSelector& program) override; + virtual Return<Result> cancel() override; + virtual Return<Result> cancelAnnouncement() override; + virtual Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override; + virtual Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override; + virtual Return<ProgramListResult> startBackgroundScan() override; + virtual Return<void> getProgramList(const hidl_vec<VendorKeyValue>& filter, + getProgramList_cb _hidl_cb) override; + virtual Return<Result> setAnalogForced(bool isForced) override; + virtual Return<void> isAnalogForced(isAnalogForced_cb _hidl_cb) override; - void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; } - const struct radio_tuner *getHalTuner() { return mHalTuner; } + private: + std::mutex mMut; + WorkerThread mThread; + bool mIsClosed = false; -private: - ~Tuner(); - - const struct radio_tuner *mHalTuner; + V1_0::Class mClassId; const sp<V1_0::ITunerCallback> mCallback; const sp<V1_1::ITunerCallback> mCallback1_1; - const wp<BroadcastRadio> mParentDevice; -}; + std::reference_wrapper<VirtualRadio> mVirtualRadio; + bool mIsAmfmConfigSet = false; + V1_0::BandConfig mAmfmConfig; + bool mIsTuneCompleted = false; + ProgramSelector mCurrentProgram = {}; + ProgramInfo mCurrentProgramInfo = {}; + std::atomic<bool> mIsAnalogForced; + + utils::HalRevision getHalRev() const; + void tuneInternalLocked(const ProgramSelector& sel); +}; } // namespace implementation } // namespace V1_1 diff --git a/broadcastradio/1.1/default/Utils.cpp b/broadcastradio/1.1/default/Utils.cpp deleted file mode 100644 index e21344ede2..0000000000 --- a/broadcastradio/1.1/default/Utils.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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. - */ -#define LOG_TAG "BroadcastRadioHalUtils" -//#define LOG_NDEBUG 0 - -#include <log/log.h> -#include <system/radio_metadata.h> - -#include "Utils.h" - -namespace android { -namespace hardware { -namespace broadcastradio { -namespace V1_1 { -namespace implementation { - -using V1_0::Band; -using V1_0::Deemphasis; -using V1_0::Direction; -using V1_0::MetadataKey; -using V1_0::MetadataType; -using V1_0::Rds; - -const char *Utils::sClassModuleNames[] = { - RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */ - RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */ - RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */ -}; - -// make sure HIDL enum values are aligned with legacy values -static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM), - "AM/FM class mismatch with legacy"); -static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT), - "SAT class mismatch with legacy"); -static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT), - "DT class mismatch with legacy"); - -static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM), - "AM band mismatch with legacy"); -static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM), - "FM band mismatch with legacy"); -static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD), - "AM HD band mismatch with legacy"); -static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD), - "FM HD band mismatch with legacy"); - -static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE), - "RDS NONE mismatch with legacy"); -static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD), - "RDS WORLD mismatch with legacy"); -static_assert(RADIO_RDS_US == static_cast<int>(Rds::US), - "RDS US mismatch with legacy"); - -static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50), - "De-emphasis 50 mismatch with legacy"); -static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75), - "De-emphasis 75 mismatch with legacy"); - -static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP), - "Direction Up mismatch with legacy"); -static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN), - "Direction Up mismatch with legacy"); - -static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID), - "Metadata type INVALID mismatch with legacy"); -static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT), - "Metadata type INT mismatch with legacy"); -static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT), - "Metadata type TEXT mismatch with legacy"); -static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW), - "Metadata type RAW mismatch with legacy"); -static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK), - "Metadata type CLOCK mismatch with legacy"); - -static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID), - "Metadata key INVALID mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI), - "Metadata key RDS_PI mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS), - "Metadata key RDS_PS mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY), - "Metadata key RDS_PTY mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY), - "Metadata key RBDS_PTY mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT), - "Metadata key RDS_RT mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE), - "Metadata key TITLE mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST), - "Metadata key ARTIST mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM), - "Metadata key ALBUM mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE), - "Metadata key GENRE mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON), - "Metadata key ICON mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART), - "Metadata key ART mismatch with legacy"); -static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK), - "Metadata key CLOCK mismatch with legacy"); - - -//static -const char * Utils::getClassString(Class ClassId) -{ - int id = static_cast<int>(ClassId); - - if ((id < 0) || - (id >= NELEM(sClassModuleNames))) { - ALOGE("invalid class ID %d", id); - return NULL; - } - return sClassModuleNames[id]; -} - -//static -Result Utils::convertHalResult(int rc) -{ - switch (rc) { - case 0: - return Result::OK; - case -EINVAL: - return Result::INVALID_ARGUMENTS; - case -ENOSYS: - return Result::INVALID_STATE; - case -ETIMEDOUT: - return Result::TIMEOUT; - case -ENODEV: - default: - return Result::NOT_INITIALIZED; - } -} - -//static -void Utils::convertBandConfigFromHal( - BandConfig *config, - const radio_hal_band_config_t *halConfig) -{ - - config->type = static_cast<Band>(halConfig->type); - config->antennaConnected = halConfig->antenna_connected; - config->lowerLimit = halConfig->lower_limit; - config->upperLimit = halConfig->upper_limit; - config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]), - halConfig->num_spacings * sizeof(uint32_t)); - // FIXME: transfer buffer ownership. should have a method for that in hidl_vec - config->spacings.resize(halConfig->num_spacings); - - if (config->type == Band::FM) { - config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis); - config->ext.fm.stereo = halConfig->fm.stereo; - config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds); - config->ext.fm.ta = halConfig->fm.ta; - config->ext.fm.af = halConfig->fm.af; - config->ext.fm.ea = halConfig->fm.ea; - } else { - config->ext.am.stereo = halConfig->am.stereo; - } -} - -//static -void Utils::convertPropertiesFromHal(Properties *properties, - const radio_hal_properties_t *halProperties) -{ - properties->classId = static_cast<Class>(halProperties->class_id); - properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor)); - properties->product.setToExternal(halProperties->product, strlen(halProperties->product)); - properties->version.setToExternal(halProperties->version, strlen(halProperties->version)); - properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial)); - properties->numTuners = halProperties->num_tuners; - properties->numAudioSources = halProperties->num_audio_sources; - properties->supportsCapture = halProperties->supports_capture; - - BandConfig *bands = - new BandConfig[halProperties->num_bands]; - for (size_t i = 0; i < halProperties->num_bands; i++) { - convertBandConfigFromHal(&bands[i], &halProperties->bands[i]); - } - properties->bands.setToExternal(bands, halProperties->num_bands); - // FIXME: transfer buffer ownership. should have a method for that in hidl_vec - properties->bands.resize(halProperties->num_bands); - delete[] bands; -} - -//static -void Utils::convertBandConfigToHal(radio_hal_band_config_t *halConfig, const BandConfig *config) -{ - halConfig->type = static_cast<radio_band_t>(config->type); - halConfig->antenna_connected = config->antennaConnected; - halConfig->lower_limit = config->lowerLimit; - halConfig->upper_limit = config->upperLimit; - halConfig->num_spacings = config->spacings.size(); - if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) { - halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX; - } - memcpy(halConfig->spacings, config->spacings.data(), - sizeof(uint32_t) * halConfig->num_spacings); - - if (config->type == Band::FM) { - halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis); - halConfig->fm.stereo = config->ext.fm.stereo; - halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds); - halConfig->fm.ta = config->ext.fm.ta; - halConfig->fm.af = config->ext.fm.af; - halConfig->fm.ea = config->ext.fm.ea; - } else { - halConfig->am.stereo = config->ext.am.stereo; - } -} - - -//static -void Utils::convertProgramInfoFromHal(ProgramInfo *info, radio_program_info_t *halInfo) -{ - auto &info_1_1 = *info; - auto &info_1_0 = info->base; - - info_1_0.channel = halInfo->channel; - info_1_0.subChannel = halInfo->sub_channel; - info_1_0.tuned = halInfo->tuned; - info_1_0.stereo = halInfo->stereo; - info_1_0.digital = halInfo->digital; - info_1_0.signalStrength = halInfo->signal_strength; - convertMetaDataFromHal(info_1_0.metadata, halInfo->metadata); - // TODO(b/34348946): add support for HAL 1.1 fields - info_1_1.flags = 0; -} - -//static -int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, radio_metadata_t *halMetadata) -{ - if (halMetadata == NULL) { - ALOGE("Invalid argument: halMetadata is NULL"); - return 0; - } - - int count = radio_metadata_get_count(halMetadata); - if (count <= 0) { - return count; - } - MetaData *newMetadata = new MetaData[count]; - int outCount = 0; - for (int i = 0; i < count; i++) { - radio_metadata_key_t key; - radio_metadata_type_t type; - void *value; - size_t size; - if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 || - size == 0) { - continue; - } - switch (type) { - case RADIO_METADATA_TYPE_INT: { - newMetadata[outCount].intValue = *(static_cast<int32_t *>(value)); - } break; - case RADIO_METADATA_TYPE_TEXT: { - newMetadata[outCount].stringValue = static_cast<char *>(value); - } break; - case RADIO_METADATA_TYPE_RAW: { - newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size); - // FIXME: transfer buffer ownership. should have a method for that in hidl_vec - newMetadata[outCount].rawValue.resize(size); - } break; - case RADIO_METADATA_TYPE_CLOCK: { - radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value); - newMetadata[outCount].clockValue.utcSecondsSinceEpoch = - clock->utc_seconds_since_epoch; - newMetadata[outCount].clockValue.timezoneOffsetInMinutes = - clock->timezone_offset_in_minutes; - } break; - } - newMetadata[outCount].type = static_cast<MetadataType>(type); - newMetadata[outCount].key = static_cast<MetadataKey>(key); - outCount++; - } - metadata.setToExternal(newMetadata, outCount); - // FIXME: transfer buffer ownership. should have a method for that in hidl_vec - metadata.resize(outCount); - return outCount; -} - -} // namespace implementation -} // namespace V1_1 -} // namespace broadcastradio -} // namespace hardware -} // namespace android diff --git a/broadcastradio/1.1/default/Utils.h b/broadcastradio/1.1/default/Utils.h deleted file mode 100644 index 22902ba513..0000000000 --- a/broadcastradio/1.1/default/Utils.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ -#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H -#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H - -#include <android/hardware/broadcastradio/1.1/types.h> -#include <hardware/radio.h> - -namespace android { -namespace hardware { -namespace broadcastradio { -namespace V1_1 { -namespace implementation { - -using V1_0::Class; -using V1_0::BandConfig; -using V1_0::MetaData; -using V1_0::Properties; - -class Utils { -public: - static const char * getClassString(Class ClassId); - static Result convertHalResult(int rc); - static void convertBandConfigFromHal(BandConfig *config, - const radio_hal_band_config_t *halConfig); - static void convertPropertiesFromHal(Properties *properties, - const radio_hal_properties_t *halProperties); - static void convertBandConfigToHal(radio_hal_band_config_t *halConfig, - const BandConfig *config); - static void convertProgramInfoFromHal(ProgramInfo *info, - radio_program_info_t *halInfo); - static int convertMetaDataFromHal(hidl_vec<MetaData>& metadata, - radio_metadata_t *halMetadata); -private: - static const char * sClassModuleNames[]; - -}; - -} // namespace implementation -} // namespace V1_1 -} // namespace broadcastradio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H diff --git a/broadcastradio/1.1/default/VirtualProgram.cpp b/broadcastradio/1.1/default/VirtualProgram.cpp new file mode 100644 index 0000000000..7977391cdd --- /dev/null +++ b/broadcastradio/1.1/default/VirtualProgram.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "VirtualProgram.h" + +#include <broadcastradio-utils/Utils.h> + +#include "resources.h" + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using std::vector; + +using V1_0::MetaData; +using V1_0::MetadataKey; +using V1_0::MetadataType; +using utils::HalRevision; + +static MetaData createDemoBitmap(MetadataKey key, HalRevision halRev) { + MetaData bmp = {MetadataType::INT, key, resources::demoPngId, {}, {}, {}}; + if (halRev < HalRevision::V1_1) { + bmp.type = MetadataType::RAW; + bmp.intValue = 0; + bmp.rawValue = hidl_vec<uint8_t>(resources::demoPng, std::end(resources::demoPng)); + } + return bmp; +} + +ProgramInfo VirtualProgram::getProgramInfo(HalRevision halRev) const { + ProgramInfo info11 = {}; + auto& info10 = info11.base; + + utils::getLegacyChannel(selector, &info10.channel, &info10.subChannel); + info11.selector = selector; + info10.tuned = true; + info10.stereo = true; + info10.digital = utils::isDigital(selector); + info10.signalStrength = info10.digital ? 100 : 80; + + info10.metadata = hidl_vec<MetaData>({ + {MetadataType::TEXT, MetadataKey::RDS_PS, {}, {}, programName, {}}, + {MetadataType::TEXT, MetadataKey::TITLE, {}, {}, songTitle, {}}, + {MetadataType::TEXT, MetadataKey::ARTIST, {}, {}, songArtist, {}}, + createDemoBitmap(MetadataKey::ICON, halRev), + createDemoBitmap(MetadataKey::ART, halRev), + }); + + info11.vendorInfo = hidl_vec<VendorKeyValue>({ + {"com.google.dummy", "dummy"}, + {"com.google.dummy.VirtualProgram", std::to_string(reinterpret_cast<uintptr_t>(this))}, + }); + + return info11; +} + +// Defining order on virtual programs, how they appear on band. +// It's mostly for default implementation purposes, may not be complete or correct. +bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) { + auto& l = lhs.selector; + auto& r = rhs.selector; + + // Two programs with the same primaryId is considered the same. + if (l.programType != r.programType) return l.programType < r.programType; + if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type; + if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value; + + // A little exception for HD Radio subchannel - we check secondary ID too. + if (utils::hasId(l, IdentifierType::HD_SUBCHANNEL) && + utils::hasId(r, IdentifierType::HD_SUBCHANNEL)) { + return utils::getId(l, IdentifierType::HD_SUBCHANNEL) < + utils::getId(r, IdentifierType::HD_SUBCHANNEL); + } + + return false; +} + +vector<ProgramInfo> getProgramInfoVector(const vector<VirtualProgram>& vec, HalRevision halRev) { + vector<ProgramInfo> out; + out.reserve(vec.size()); + for (auto&& program : vec) { + out.push_back(program.getProgramInfo(halRev)); + } + return out; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android diff --git a/broadcastradio/1.1/default/VirtualProgram.h b/broadcastradio/1.1/default/VirtualProgram.h new file mode 100644 index 0000000000..a14830d77a --- /dev/null +++ b/broadcastradio/1.1/default/VirtualProgram.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H + +#include <android/hardware/broadcastradio/1.1/types.h> +#include <broadcastradio-utils/Utils.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +/** + * A radio program mock. + * + * This represents broadcast waves flying over the air, + * not an entry for a captured station in the radio tuner memory. + */ +struct VirtualProgram { + ProgramSelector selector; + + std::string programName = ""; + std::string songArtist = ""; + std::string songTitle = ""; + + ProgramInfo getProgramInfo(utils::HalRevision halRev) const; + + friend bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs); +}; + +std::vector<ProgramInfo> getProgramInfoVector(const std::vector<VirtualProgram>& vec, + utils::HalRevision halRev); + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H diff --git a/broadcastradio/1.1/default/VirtualRadio.cpp b/broadcastradio/1.1/default/VirtualRadio.cpp new file mode 100644 index 0000000000..36d47a92e7 --- /dev/null +++ b/broadcastradio/1.1/default/VirtualRadio.cpp @@ -0,0 +1,105 @@ +/* + * 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. + */ +#define LOG_TAG "BroadcastRadioDefault.VirtualRadio" +//#define LOG_NDEBUG 0 + +#include "VirtualRadio.h" + +#include <broadcastradio-utils/Utils.h> +#include <log/log.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using V1_0::Band; +using V1_0::Class; + +using std::lock_guard; +using std::move; +using std::mutex; +using std::vector; + +using utils::make_selector; + +static const vector<VirtualProgram> gInitialFmPrograms{ + {make_selector(Band::FM, 94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"}, + {make_selector(Band::FM, 96500), "KOIT", "Celine Dion", "All By Myself"}, + {make_selector(Band::FM, 97300), "Alice@97.3", "Drops of Jupiter", "Train"}, + {make_selector(Band::FM, 99700), "99.7 Now!", "The Chainsmokers", "Closer"}, + {make_selector(Band::FM, 101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"}, + {make_selector(Band::FM, 103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"}, + {make_selector(Band::FM, 106100), "106 KMEL", "Drake", "Marvins Room"}, +}; + +static VirtualRadio gEmptyRadio({}); +static VirtualRadio gFmRadio(gInitialFmPrograms); + +VirtualRadio::VirtualRadio(const vector<VirtualProgram> initialList) : mPrograms(initialList) {} + +vector<VirtualProgram> VirtualRadio::getProgramList() { + lock_guard<mutex> lk(mMut); + return mPrograms; +} + +bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram& programOut) { + lock_guard<mutex> lk(mMut); + for (auto&& program : mPrograms) { + if (utils::tunesTo(selector, program.selector)) { + programOut = program; + return true; + } + } + return false; +} + +VirtualRadio& getRadio(V1_0::Class classId) { + switch (classId) { + case Class::AM_FM: + return getFmRadio(); + case Class::SAT: + return getSatRadio(); + case Class::DT: + return getDigitalRadio(); + default: + ALOGE("Invalid class ID"); + return gEmptyRadio; + } +} + +VirtualRadio& getAmRadio() { + return gEmptyRadio; +} + +VirtualRadio& getFmRadio() { + return gFmRadio; +} + +VirtualRadio& getSatRadio() { + return gEmptyRadio; +} + +VirtualRadio& getDigitalRadio() { + return gEmptyRadio; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android diff --git a/broadcastradio/1.1/default/VirtualRadio.h b/broadcastradio/1.1/default/VirtualRadio.h new file mode 100644 index 0000000000..3c7ae5c193 --- /dev/null +++ b/broadcastradio/1.1/default/VirtualRadio.h @@ -0,0 +1,80 @@ +/* + * 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H + +#include "VirtualProgram.h" + +#include <mutex> +#include <vector> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +/** + * A radio frequency space mock. + * + * This represents all broadcast waves in the air for a given radio technology, + * not a captured station list in the radio tuner memory. + * + * It's meant to abstract out radio content from default tuner implementation. + */ +class VirtualRadio { + public: + VirtualRadio(const std::vector<VirtualProgram> initialList); + + std::vector<VirtualProgram> getProgramList(); + bool getProgram(const ProgramSelector& selector, VirtualProgram& program); + + private: + std::mutex mMut; + std::vector<VirtualProgram> mPrograms; +}; + +/** + * Get virtual radio space for a given radio class. + * + * As a space, each virtual radio always exists. For example, DAB frequencies + * exists in US, but contains no programs. + * + * The lifetime of the virtual radio space is virtually infinite, but for the + * needs of default implementation, it's bound with the lifetime of default + * implementation process. + * + * Internally, it's a static object, so trying to access the reference during + * default implementation library unloading may result in segmentation fault. + * It's unlikely for testing purposes. + * + * @param classId A class of radio technology. + * @return A reference to virtual radio space for a given technology. + */ +VirtualRadio& getRadio(V1_0::Class classId); + +VirtualRadio& getAmRadio(); +VirtualRadio& getFmRadio(); +VirtualRadio& getSatRadio(); +VirtualRadio& getDigitalRadio(); + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H diff --git a/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc b/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc new file mode 100644 index 0000000000..7c57135fc2 --- /dev/null +++ b/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc @@ -0,0 +1,4 @@ +service broadcastradio-hal /vendor/bin/hw/android.hardware.broadcastradio@1.1-service + class hal + user audioserver + group audio diff --git a/broadcastradio/1.1/default/resources.h b/broadcastradio/1.1/default/resources.h new file mode 100644 index 0000000000..b7e709f955 --- /dev/null +++ b/broadcastradio/1.1/default/resources.h @@ -0,0 +1,46 @@ +/* + * 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_RESOURCES_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_RESOURCES_H + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { +namespace resources { + +constexpr int32_t demoPngId = 123456; +constexpr uint8_t demoPng[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, + 0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x08, 0x02, 0x00, 0x00, 0x00, 0x25, + 0x0b, 0xe6, 0x89, 0x00, 0x00, 0x00, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9, + 0xc1, 0x09, 0x00, 0x30, 0x08, 0x04, 0xc1, 0x33, 0xfd, 0xf7, 0x6c, 0x6a, 0xc8, 0x23, 0x04, + 0xc9, 0x6c, 0x01, 0xc2, 0x20, 0xbe, 0x4c, 0x86, 0x57, 0x49, 0xba, 0xfb, 0xd6, 0xf4, 0xba, + 0x3e, 0x7f, 0x4d, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x00, 0xbd, 0xce, 0x7f, + 0xc0, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xb8, 0x0d, 0x32, 0xd4, 0x0c, 0x77, 0xbd, + 0xfb, 0xc1, 0xce, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82}; + +} // namespace resources +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_RESOURCES_H diff --git a/broadcastradio/1.1/default/service.cpp b/broadcastradio/1.1/default/service.cpp new file mode 100644 index 0000000000..f8af0b78cb --- /dev/null +++ b/broadcastradio/1.1/default/service.cpp @@ -0,0 +1,36 @@ +/* + * 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. + */ +#define LOG_TAG "BroadcastRadioDefault.service" + +#include <android-base/logging.h> +#include <hidl/HidlTransportSupport.h> + +#include "BroadcastRadioFactory.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::broadcastradio::V1_1::implementation::BroadcastRadioFactory; + +int main(int /* argc */, char** /* argv */) { + configureRpcThreadpool(4, true); + + BroadcastRadioFactory broadcastRadioFactory; + auto status = broadcastRadioFactory.registerAsService(); + CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation"; + + joinRpcThreadpool(); + return 1; // joinRpcThreadpool shouldn't exit +} diff --git a/broadcastradio/1.1/tests/Android.bp b/broadcastradio/1.1/tests/Android.bp new file mode 100644 index 0000000000..fa1fd94409 --- /dev/null +++ b/broadcastradio/1.1/tests/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +cc_test { + name: "android.hardware.broadcastradio@1.1-utils-tests", + vendor: true, + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "WorkerThread_test.cpp", + ], + static_libs: ["android.hardware.broadcastradio@1.1-utils-lib"], +} diff --git a/broadcastradio/1.1/tests/OWNERS b/broadcastradio/1.1/tests/OWNERS new file mode 100644 index 0000000000..aa5ce82e16 --- /dev/null +++ b/broadcastradio/1.1/tests/OWNERS @@ -0,0 +1,8 @@ +# Automotive team +egranata@google.com +keunyoung@google.com +twasilczyk@google.com + +# VTS team +ryanjcampbell@google.com +yim@google.com diff --git a/broadcastradio/1.1/tests/WorkerThread_test.cpp b/broadcastradio/1.1/tests/WorkerThread_test.cpp new file mode 100644 index 0000000000..ed36de3e85 --- /dev/null +++ b/broadcastradio/1.1/tests/WorkerThread_test.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <broadcastradio-utils/WorkerThread.h> +#include <gtest/gtest.h> + +namespace { + +using namespace std::chrono_literals; + +using android::WorkerThread; + +using std::atomic; +using std::chrono::time_point; +using std::chrono::steady_clock; +using std::is_sorted; +using std::lock_guard; +using std::mutex; +using std::this_thread::sleep_for; +using std::vector; + +#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \ + ASSERT_LE((val1) - (tolerance), (val2)); \ + ASSERT_GE((val1) + (tolerance), (val2)); + +TEST(WorkerThreadTest, oneTask) { + atomic<bool> executed(false); + atomic<time_point<steady_clock>> stop; + WorkerThread thread; + + auto start = steady_clock::now(); + thread.schedule( + [&]() { + stop = steady_clock::now(); + executed = true; + }, + 100ms); + + sleep_for(150ms); + + ASSERT_TRUE(executed); + auto delta = stop.load() - start; + ASSERT_EQ_WITH_TOLERANCE(delta, 100ms, 50ms); +} + +TEST(WorkerThreadTest, cancelSecond) { + atomic<bool> executed1(false); + atomic<bool> executed2(false); + WorkerThread thread; + + thread.schedule([&]() { executed2 = true; }, 100ms); + thread.schedule([&]() { executed1 = true; }, 25ms); + + sleep_for(50ms); + thread.cancelAll(); + sleep_for(100ms); + + ASSERT_TRUE(executed1); + ASSERT_FALSE(executed2); +} + +TEST(WorkerThreadTest, executeInOrder) { + mutex mut; + vector<int> order; + WorkerThread thread; + + thread.schedule( + [&]() { + lock_guard<mutex> lk(mut); + order.push_back(0); + }, + 50ms); + + thread.schedule( + [&]() { + lock_guard<mutex> lk(mut); + order.push_back(4); + }, + 400ms); + + thread.schedule( + [&]() { + lock_guard<mutex> lk(mut); + order.push_back(1); + }, + 100ms); + + thread.schedule( + [&]() { + lock_guard<mutex> lk(mut); + order.push_back(3); + }, + 300ms); + + thread.schedule( + [&]() { + lock_guard<mutex> lk(mut); + order.push_back(2); + }, + 200ms); + + sleep_for(500ms); + + ASSERT_EQ(5u, order.size()); + ASSERT_TRUE(is_sorted(order.begin(), order.end())); +} + +TEST(WorkerThreadTest, dontExecuteAfterDestruction) { + atomic<bool> executed1(false); + atomic<bool> executed2(false); + { + WorkerThread thread; + + thread.schedule([&]() { executed2 = true; }, 100ms); + thread.schedule([&]() { executed1 = true; }, 25ms); + + sleep_for(50ms); + } + sleep_for(100ms); + + ASSERT_TRUE(executed1); + ASSERT_FALSE(executed2); +} + +} // anonymous namespace diff --git a/broadcastradio/1.1/types.hal b/broadcastradio/1.1/types.hal index 5577ea02da..8b8fc6fdde 100644 --- a/broadcastradio/1.1/types.hal +++ b/broadcastradio/1.1/types.hal @@ -43,6 +43,35 @@ enum ProgramInfoFlags : uint32_t { * increasing volume too much. */ MUTED = 1 << 1, + + /** + * Station broadcasts traffic information regularly, + * but not necessarily right now. + */ + TRAFFIC_PROGRAM = 1 << 2, + + /** + * Station is broadcasting traffic information at the very moment. + */ + TRAFFIC_ANNOUNCEMENT = 1 << 3, +}; + +/** + * A key-value pair for vendor-specific information to be passed as-is through + * Android framework to the front-end application. + */ +struct VendorKeyValue { + /** + * Key must be prefixed with unique vendor Java-style namespace, + * eg. 'com.somecompany.parameter1'. + */ + string key; + + /** + * Value must be passed through the framework without any changes. + * Format of this string can vary across vendors. + */ + string value; }; struct Properties { @@ -55,16 +84,204 @@ struct Properties { bool supportsBackgroundScanning; /** - * Opaque vendor-specific string, to be passed to front-end without changes. - * Format of this string can vary across vendors. + * A list of supported ProgramType values. + * + * If a program type is supported by radio module, it means it can tune + * to ProgramSelector of a given type. + * + * Support for VENDOR program type does not guarantee compatibility, as + * other module properties (implementor, product, version) must be checked. + */ + vec<uint32_t> supportedProgramTypes; + + /** + * A list of supported IdentifierType values. + * + * If an identifier is supported by radio module, it means it can use it for + * tuning to ProgramSelector with either primary or secondary Identifier of + * a given type. + * + * Support for VENDOR identifier type does not guarantee compatibility, as + * other module properties (implementor, product, version) must be checked. + */ + vec<uint32_t> supportedIdentifierTypes; + + /** + * Vendor-specific information. + * + * It may be used for extra features, not supported by the platform, + * for example: com.me.preset-slots=6; com.me.ultra-hd-capable=false. + */ + vec<VendorKeyValue> vendorInfo; +}; + +/** + * Type of modulation. + * + * Used as a value for DRMO_MODULATION IdentifierType. + */ +enum Modulation : uint32_t { + AM = 1, + FM, +}; + +/** + * Type of a radio technology. + * + * VENDOR program types must be opaque to the framework. + * + * There are multiple VENDOR program types just to make vendor implementation + * easier with multiple properitary radio technologies. They are treated the + * same by the framework. + * + * All other values are reserved for future use. + * Values not matching any enumerated constant must be ignored. + */ +enum ProgramType : uint32_t { + AM = 1, // analogue AM radio (with or without RDS) + FM, // analogue FM radio (with or without RDS) + AM_HD, // AM HD Radio + FM_HD, // FM HD Radio + DAB, // Digital audio broadcasting + DRMO, // Digital Radio Mondiale + SXM, // SiriusXM Satellite Radio + + // Vendor-specific, not synced across devices. + VENDOR_START = 1000, + VENDOR_END = 1999, +}; + +/** + * Type of program identifier component. + * + * It MUST match the radio technology for primary ID but does not have to match + * it for secondary IDs. For example, a satellite program may set AM/FM fallback + * frequency, if a station broadcasts both via satellite and AM/FM. + * + * VENDOR identifier types must be opaque to the framework. + * + * The value format for each (but VENDOR_PRIMARY) identifier is strictly defined + * to maintain interoperability between devices made by different vendors. + * + * All other values are reserved for future use. + * Values not matching any enumerated constant must be ignored. + */ +enum IdentifierType : uint32_t { + AMFM_FREQUENCY = 1, // kHz + RDS_PI, // 16bit + + /** + * 64bit compound primary identifier for HD Radio. + * + * Consists of (from the LSB): + * - 32bit: Station ID number; + * - 4bit: HD_SUBCHANNEL; + * - 18bit: AMFM_FREQUENCY. + * The remaining bits should be set to zeros when writing on the chip side + * and ignored when read. + */ + HD_STATION_ID_EXT, + + /** + * HD Radio subchannel - a value of range 0-7. + * + * The subchannel index is 0-based (where 0 is MPS and 1..7 are SPS), + * as opposed to HD Radio standard (where it's 1-based). + */ + HD_SUBCHANNEL, + + /** + * 24bit compound primary identifier for DAB. + * + * Consists of (from the LSB): + * - 16bit: SId; + * - 8bit: ECC code. + * The remaining bits should be set to zeros when writing on the chip side + * and ignored when read. + */ + DAB_SIDECC, + + DAB_ENSEMBLE, // 16bit + DAB_SCID, // 12bit + DAB_FREQUENCY, // kHz + DRMO_SERVICE_ID, // 24bit + DRMO_FREQUENCY, // kHz + DRMO_MODULATION, // Modulation enum + SXM_SERVICE_ID, // 32bit + SXM_CHANNEL, // 0-999 range + + /** + * Primary identifier for vendor-specific radio technology. + * The value format is determined by a vendor. + * + * It must not be used in any other programType than corresponding VENDOR + * type between VENDOR_START and VENDOR_END (eg. identifier type 1015 must + * not be used in any program type other than 1015). + */ + VENDOR_PRIMARY_START = ProgramType:VENDOR_START, + VENDOR_PRIMARY_END = ProgramType:VENDOR_END, +}; + +/** + * A single program identifier component, eg. frequency or channel ID. + * + * The uint32_t type field maps to IdentifierType enum. It's not straight, + * because the enum may be extended in future versions of the HAL. Values out of + * the enum range must not be used when writing and ignored when reading. + * + * The uint64_t value field holds the value in format described in comments for + * IdentifierType enum. + */ +struct ProgramIdentifier { + uint32_t type; // IdentifierType + uint64_t value; +}; + +/** + * A set of identifiers necessary to tune to a given station. + * + * This can hold various identifiers, like + * - AM/FM frequency + * - HD Radio subchannel + * - DAB channel info + * + * The uint32_t programType field maps to ProgramType enum. It's not straight, + * because the enum may be extended in future versions of the HAL. Values out of + * the enum range must not be used when writing and ignored when reading. + * + * The primary ID uniquely identifies a station and can be used for equality + * check. The secondary IDs are supplementary and can speed up tuning process, + * but the primary ID is sufficient (ie. after a full band scan). + * + * Two selectors with different secondary IDs, but the same primary ID are + * considered equal. In particular, secondary IDs vector may get updated for + * an entry on the program list (ie. when a better frequency for a given + * station is found). + * + * The primaryId of a given programType MUST be of a specific type: + * - AM, FM: RDS_PI if the station broadcasts RDS, AMFM_FREQUENCY otherwise; + * - AM_HD, FM_HD: HD_STATION_ID_EXT; + * - DAB: DAB_SIDECC; + * - DRMO: DRMO_SERVICE_ID; + * - SXM: SXM_SERVICE_ID; + * - VENDOR: VENDOR_PRIMARY. + */ +struct ProgramSelector { + uint32_t programType; // ProgramType + ProgramIdentifier primaryId; // uniquely identifies a station + vec<ProgramIdentifier> secondaryIds; + + /** + * Opaque vendor-specific identifiers, to be passed to front-end + * without changes. * - * It may be used for extra features, that's not supported by a platform, - * for example: "preset-slots=6;ultra-hd-capable=false". + * The order is meaningful, ie. the first element may be defined as + * frequency, second as the subchannel etc. * - * Front-end application MUST verify vendor/product name from the - * @1.0::Properties struct before doing any interpretation of this value. + * The vector is not serialized (either locally or to the cloud), + * unless it's a VENDOR program type. */ - string vendorExension; + vec<uint64_t> vendorIds; }; /** @@ -73,17 +290,16 @@ struct Properties { */ struct ProgramInfo { @1.0::ProgramInfo base; + + ProgramSelector selector; + bitfield<ProgramInfoFlags> flags; /** - * Opaque vendor-specific string, to be passed to front-end without changes. - * Format of this string can vary across vendors. - * - * It may be used for extra features, that's not supported by a platform, - * for example: "paid-service=true;bitrate=320kbps". + * Vendor-specific information. * - * Front-end application MUST verify vendor/product name from the - * @1.0::Properties struct before doing any interpretation of this value. + * It may be used for extra features, not supported by the platform, + * for example: paid-service=true; bitrate=320kbps. */ - string vendorExension; + vec<VendorKeyValue> vendorInfo; }; diff --git a/power/1.1/default/Android.bp b/broadcastradio/1.1/utils/Android.bp index 0b3598bbf5..e80d133dca 100644 --- a/power/1.1/default/Android.bp +++ b/broadcastradio/1.1/utils/Android.bp @@ -1,4 +1,5 @@ -// Copyright (C) 2016 The Android Open Source Project +// +// 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. @@ -11,23 +12,23 @@ // WITHOUT 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 { - proprietary: true, - defaults: ["hidl_defaults"], +cc_library_static { + name: "android.hardware.broadcastradio@1.1-utils-lib", + vendor_available: true, relative_install_path: "hw", - name: "android.hardware.power@1.1-service", - init_rc: ["android.hardware.power@1.1-service.rc"], - srcs: ["service.cpp" , "Power.cpp"], - + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "Utils.cpp", + "WorkerThread.cpp", + ], + export_include_dirs: ["include"], shared_libs: [ - "liblog", - "libdl", - "libutils", - "libhardware", - "libhidlbase", - "libhidltransport", - "android.hardware.power@1.0", - "android.hardware.power@1.1", + "android.hardware.broadcastradio@1.1", ], } diff --git a/broadcastradio/1.1/utils/OWNERS b/broadcastradio/1.1/utils/OWNERS new file mode 100644 index 0000000000..0c27b71865 --- /dev/null +++ b/broadcastradio/1.1/utils/OWNERS @@ -0,0 +1,4 @@ +# Automotive team +egranata@google.com +keunyoung@google.com +twasilczyk@google.com diff --git a/broadcastradio/1.1/utils/Utils.cpp b/broadcastradio/1.1/utils/Utils.cpp new file mode 100644 index 0000000000..4dd6b139c4 --- /dev/null +++ b/broadcastradio/1.1/utils/Utils.cpp @@ -0,0 +1,234 @@ +/* + * 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. + */ +#define LOG_TAG "BroadcastRadioDefault.utils" +//#define LOG_NDEBUG 0 + +#include <broadcastradio-utils/Utils.h> + +#include <log/log.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace utils { + +using V1_0::Band; + +static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) { + auto a = static_cast<ProgramType>(ia); + auto b = static_cast<ProgramType>(ib); + + if (a == b) return true; + if (a == ProgramType::AM && b == ProgramType::AM_HD) return true; + if (a == ProgramType::AM_HD && b == ProgramType::AM) return true; + if (a == ProgramType::FM && b == ProgramType::FM_HD) return true; + if (a == ProgramType::FM_HD && b == ProgramType::FM) return true; + return false; +} + +static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, + const IdentifierType type) { + return hasId(a, type) && hasId(b, type); +} + +static bool anyHaveId(const ProgramSelector& a, const ProgramSelector& b, + const IdentifierType type) { + return hasId(a, type) || hasId(b, type); +} + +static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b, + const IdentifierType type) { + if (!bothHaveId(a, b, type)) return false; + /* We should check all Ids of a given type (ie. other AF), + * but it doesn't matter for default implementation. + */ + auto aId = getId(a, type); + auto bId = getId(b, type); + return aId == bId; +} + +bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) { + if (!isCompatibleProgramType(a.programType, b.programType)) return false; + + auto type = getType(a); + + switch (type) { + case ProgramType::AM: + case ProgramType::AM_HD: + case ProgramType::FM: + case ProgramType::FM_HD: + if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true; + + // if HD Radio subchannel is specified, it must match + if (anyHaveId(a, b, IdentifierType::HD_SUBCHANNEL)) { + // missing subchannel (analog) is an equivalent of first subchannel (MPS) + auto aCh = getId(a, IdentifierType::HD_SUBCHANNEL, 0); + auto bCh = getId(b, IdentifierType::HD_SUBCHANNEL, 0); + if (aCh != bCh) return false; + } + + if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true; + + return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY); + case ProgramType::DAB: + return haveEqualIds(a, b, IdentifierType::DAB_SIDECC); + case ProgramType::DRMO: + return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID); + case ProgramType::SXM: + if (anyHaveId(a, b, IdentifierType::SXM_SERVICE_ID)) { + return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID); + } + return haveEqualIds(a, b, IdentifierType::SXM_CHANNEL); + default: // includes all vendor types + ALOGW("Unsupported program type: %s", toString(type).c_str()); + return false; + } +} + +ProgramType getType(const ProgramSelector& sel) { + return static_cast<ProgramType>(sel.programType); +} + +bool isAmFm(const ProgramType type) { + switch (type) { + case ProgramType::AM: + case ProgramType::FM: + case ProgramType::AM_HD: + case ProgramType::FM_HD: + return true; + default: + return false; + } +} + +bool isAm(const Band band) { + return band == Band::AM || band == Band::AM_HD; +} + +bool isFm(const Band band) { + return band == Band::FM || band == Band::FM_HD; +} + +bool hasId(const ProgramSelector& sel, const IdentifierType type) { + auto itype = static_cast<uint32_t>(type); + if (sel.primaryId.type == itype) return true; + // not optimal, but we don't care in default impl + for (auto&& id : sel.secondaryIds) { + if (id.type == itype) return true; + } + return false; +} + +uint64_t getId(const ProgramSelector& sel, const IdentifierType type) { + auto itype = static_cast<uint32_t>(type); + if (sel.primaryId.type == itype) return sel.primaryId.value; + // not optimal, but we don't care in default impl + for (auto&& id : sel.secondaryIds) { + if (id.type == itype) return id.value; + } + ALOGW("Identifier %s not found", toString(type).c_str()); + return 0; +} + +uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) { + if (!hasId(sel, type)) return defval; + return getId(sel, type); +} + +ProgramSelector make_selector(Band band, uint32_t channel, uint32_t subChannel) { + ProgramSelector sel = {}; + + ALOGW_IF((subChannel > 0) && (band == Band::AM || band == Band::FM), + "got subChannel for non-HD AM/FM"); + + // we can't use ProgramType::AM_HD or FM_HD, because we don't know HD station ID + ProgramType type; + if (isAm(band)) { + type = ProgramType::AM; + } else if (isFm(band)) { + type = ProgramType::FM; + } else { + LOG_ALWAYS_FATAL("Unsupported band: %s", toString(band).c_str()); + } + + sel.programType = static_cast<uint32_t>(type); + sel.primaryId.type = static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY); + sel.primaryId.value = channel; + if (subChannel > 0) { + /* stating sub channel for AM/FM channel does not give any guarantees, + * but we can't do much more without HD station ID + * + * The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based. + */ + sel.secondaryIds = hidl_vec<ProgramIdentifier>{ + {static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), subChannel - 1}, + }; + } + + return sel; +} + +bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut) { + if (channelOut) *channelOut = 0; + if (subChannelOut) *subChannelOut = 0; + if (isAmFm(getType(sel))) { + if (channelOut) *channelOut = getId(sel, IdentifierType::AMFM_FREQUENCY); + if (subChannelOut && hasId(sel, IdentifierType::HD_SUBCHANNEL)) { + // The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based. + *subChannelOut = getId(sel, IdentifierType::HD_SUBCHANNEL) + 1; + } + return true; + } + return false; +} + +bool isDigital(const ProgramSelector& sel) { + switch (getType(sel)) { + case ProgramType::AM: + case ProgramType::FM: + return false; + default: + // VENDOR might not be digital, but it doesn't matter for default impl. + return true; + } +} + +} // namespace utils +} // namespace V1_1 + +namespace V1_0 { + +bool operator==(const BandConfig& l, const BandConfig& r) { + if (l.type != r.type) return false; + if (l.antennaConnected != r.antennaConnected) return false; + if (l.lowerLimit != r.lowerLimit) return false; + if (l.upperLimit != r.upperLimit) return false; + if (l.spacings != r.spacings) return false; + if (V1_1::utils::isAm(l.type)) { + return l.ext.am == r.ext.am; + } else if (V1_1::utils::isFm(l.type)) { + return l.ext.fm == r.ext.fm; + } else { + ALOGW("Unsupported band config type: %s", toString(l.type).c_str()); + return false; + } +} + +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android diff --git a/broadcastradio/1.1/utils/WorkerThread.cpp b/broadcastradio/1.1/utils/WorkerThread.cpp new file mode 100644 index 0000000000..bfcbb390e8 --- /dev/null +++ b/broadcastradio/1.1/utils/WorkerThread.cpp @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#define LOG_TAG "WorkerThread" +//#define LOG_NDEBUG 0 + +#include <broadcastradio-utils/WorkerThread.h> + +#include <log/log.h> + +namespace android { + +using std::chrono::milliseconds; +using std::chrono::steady_clock; +using std::function; +using std::lock_guard; +using std::mutex; +using std::priority_queue; +using std::this_thread::sleep_for; +using std::unique_lock; + +bool operator<(const WorkerThread::Task& lhs, const WorkerThread::Task& rhs) { + return lhs.when > rhs.when; +} + +WorkerThread::WorkerThread() : mIsTerminating(false), mThread(&WorkerThread::threadLoop, this) {} + +WorkerThread::~WorkerThread() { + ALOGV("%s", __func__); + { + lock_guard<mutex> lk(mMut); + mIsTerminating = true; + mCond.notify_one(); + } + mThread.join(); +} + +void WorkerThread::schedule(function<void()> task, milliseconds delay) { + ALOGV("%s", __func__); + + auto when = steady_clock::now() + delay; + + lock_guard<mutex> lk(mMut); + mTasks.push(Task({when, task})); + mCond.notify_one(); +} + +void WorkerThread::cancelAll() { + ALOGV("%s", __func__); + + lock_guard<mutex> lk(mMut); + priority_queue<Task>().swap(mTasks); // empty queue +} + +void WorkerThread::threadLoop() { + ALOGV("%s", __func__); + while (!mIsTerminating) { + unique_lock<mutex> lk(mMut); + if (mTasks.empty()) { + mCond.wait(lk); + continue; + } + + auto task = mTasks.top(); + if (task.when > steady_clock::now()) { + mCond.wait_until(lk, task.when); + continue; + } + + mTasks.pop(); + lk.unlock(); // what() might need to schedule another task + task.what(); + } +} + +} // namespace android diff --git a/broadcastradio/1.1/utils/include/broadcastradio-utils/Utils.h b/broadcastradio/1.1/utils/include/broadcastradio-utils/Utils.h new file mode 100644 index 0000000000..24c60ee460 --- /dev/null +++ b/broadcastradio/1.1/utils/include/broadcastradio-utils/Utils.h @@ -0,0 +1,89 @@ +/* + * 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H + +#include <android/hardware/broadcastradio/1.1/types.h> +#include <chrono> +#include <queue> +#include <thread> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace utils { + +// TODO(b/64115813): move it out from frameworks/base/services/core/jni/BroadcastRadio/types.h +enum class HalRevision : uint32_t { + V1_0 = 1, + V1_1, +}; + +/** + * Checks, if {@code pointer} tunes to {@channel}. + * + * For example, having a channel {AMFM_FREQUENCY = 103.3}: + * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 0} can tune to this channel; + * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 1} can't. + * + * @param pointer selector we're trying to match against channel. + * @param channel existing channel. + */ +bool tunesTo(const ProgramSelector& pointer, const ProgramSelector& channel); + +ProgramType getType(const ProgramSelector& sel); +bool isAmFm(const ProgramType type); + +bool isAm(const V1_0::Band band); +bool isFm(const V1_0::Band band); + +bool hasId(const ProgramSelector& sel, const IdentifierType type); + +/** + * Returns ID (either primary or secondary) for a given program selector. + * + * If the selector does not contain given type, returns 0 and emits a warning. + */ +uint64_t getId(const ProgramSelector& sel, const IdentifierType type); + +/** + * Returns ID (either primary or secondary) for a given program selector. + * + * If the selector does not contain given type, returns default value. + */ +uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval); + +ProgramSelector make_selector(V1_0::Band band, uint32_t channel, uint32_t subChannel = 0); + +bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut); + +bool isDigital(const ProgramSelector& sel); + +} // namespace utils +} // namespace V1_1 + +namespace V1_0 { + +bool operator==(const BandConfig& l, const BandConfig& r); + +} // namespace V1_0 + +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H diff --git a/broadcastradio/1.1/utils/include/broadcastradio-utils/WorkerThread.h b/broadcastradio/1.1/utils/include/broadcastradio-utils/WorkerThread.h new file mode 100644 index 0000000000..635876fbcb --- /dev/null +++ b/broadcastradio/1.1/utils/include/broadcastradio-utils/WorkerThread.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H + +#include <chrono> +#include <queue> +#include <thread> + +namespace android { + +class WorkerThread { + public: + WorkerThread(); + virtual ~WorkerThread(); + + void schedule(std::function<void()> task, std::chrono::milliseconds delay); + void cancelAll(); + + private: + struct Task { + std::chrono::time_point<std::chrono::steady_clock> when; + std::function<void()> what; + }; + friend bool operator<(const Task& lhs, const Task& rhs); + + std::atomic<bool> mIsTerminating; + std::mutex mMut; + std::condition_variable mCond; + std::thread mThread; + std::priority_queue<Task> mTasks; + + void threadLoop(); +}; + +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H diff --git a/broadcastradio/1.1/vts/OWNERS b/broadcastradio/1.1/vts/OWNERS new file mode 100644 index 0000000000..aa5ce82e16 --- /dev/null +++ b/broadcastradio/1.1/vts/OWNERS @@ -0,0 +1,8 @@ +# Automotive team +egranata@google.com +keunyoung@google.com +twasilczyk@google.com + +# VTS team +ryanjcampbell@google.com +yim@google.com diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp index a4c0849cf2..4b93cbcf1f 100644 --- a/broadcastradio/1.1/vts/functional/Android.bp +++ b/broadcastradio/1.1/vts/functional/Android.bp @@ -16,22 +16,13 @@ cc_test { name: "VtsHalBroadcastradioV1_1TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalBroadcastradioV1_1TargetTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", + static_libs: [ "android.hardware.broadcastradio@1.0", "android.hardware.broadcastradio@1.1", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", + "android.hardware.broadcastradio@1.1-utils-lib", + "android.hardware.broadcastradio@1.1-vts-utils-lib", + "libgmock", ], } diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp index aa5ab548f6..a46378ee6a 100644 --- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp +++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp @@ -14,463 +14,527 @@ * limitations under the License. */ -#define LOG_TAG "BroadcastRadioHidlHalTest" +#define LOG_TAG "broadcastradio.vts" + #include <VtsHalHidlTargetTestBase.h> +#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h> +#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> +#include <android/hardware/broadcastradio/1.1/ITuner.h> +#include <android/hardware/broadcastradio/1.1/ITunerCallback.h> +#include <android/hardware/broadcastradio/1.1/types.h> #include <android-base/logging.h> +#include <broadcastradio-utils/Utils.h> +#include <broadcastradio-vts-utils/call-barrier.h> +#include <broadcastradio-vts-utils/mock-timeout.h> #include <cutils/native_handle.h> #include <cutils/properties.h> +#include <gmock/gmock.h> #include <hidl/HidlTransportSupport.h> #include <utils/threads.h> -#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> -#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> -#include <android/hardware/broadcastradio/1.1/ITuner.h> -#include <android/hardware/broadcastradio/1.1/ITunerCallback.h> -#include <android/hardware/broadcastradio/1.1/types.h> - - -namespace V1_0 = ::android::hardware::broadcastradio::V1_0; - -using ::android::sp; -using ::android::Mutex; -using ::android::Condition; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::hardware::broadcastradio::V1_0::BandConfig; -using ::android::hardware::broadcastradio::V1_0::Class; -using ::android::hardware::broadcastradio::V1_0::Direction; -using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; -using ::android::hardware::broadcastradio::V1_0::MetaData; -using ::android::hardware::broadcastradio::V1_0::Properties; -using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory; -using ::android::hardware::broadcastradio::V1_1::ITuner; -using ::android::hardware::broadcastradio::V1_1::ITunerCallback; -using ::android::hardware::broadcastradio::V1_1::ProgramInfo; -using ::android::hardware::broadcastradio::V1_1::Result; -using ::android::hardware::broadcastradio::V1_1::ProgramListResult; - - -// The main test class for Broadcast Radio HIDL HAL. - -class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase { - protected: - virtual void SetUp() override { - auto factory = ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>(); - if (factory != 0) { - factory->connectModule(Class::AM_FM, - [&](Result retval, const ::android::sp<IBroadcastRadio>& result) { - if (retval == Result::OK) { - mRadio = IBroadcastRadio::castFrom(result); - } - }); - } - mTunerCallback = new MyCallback(this); - ASSERT_NE(nullptr, mRadio.get()); - ASSERT_NE(nullptr, mTunerCallback.get()); - } - - virtual void TearDown() override { - mTuner.clear(); - mRadio.clear(); - } +#include <chrono> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace vts { + +using namespace std::chrono_literals; + +using testing::_; +using testing::AnyNumber; +using testing::ByMove; +using testing::DoAll; +using testing::Invoke; +using testing::SaveArg; + +using broadcastradio::vts::CallBarrier; +using V1_0::BandConfig; +using V1_0::Class; +using V1_0::MetaData; +using V1_0::MetadataKey; +using V1_0::MetadataType; + +using std::chrono::steady_clock; +using std::this_thread::sleep_for; + +static constexpr auto kConfigTimeout = 10s; +static constexpr auto kConnectModuleTimeout = 1s; +static constexpr auto kTuneTimeout = 30s; +static constexpr auto kEventPropagationTimeout = 1s; +static constexpr auto kFullScanTimeout = 1min; + +static constexpr ProgramType kStandardProgramTypes[] = { + ProgramType::AM, ProgramType::FM, ProgramType::AM_HD, ProgramType::FM_HD, + ProgramType::DAB, ProgramType::DRMO, ProgramType::SXM}; + +static void printSkipped(std::string msg) { + std::cout << "[ SKIPPED ] " << msg << std::endl; +} - class MyCallback : public ITunerCallback { - public: +struct TunerCallbackMock : public ITunerCallback { + TunerCallbackMock() { EXPECT_CALL(*this, hardwareFailure()).Times(0); } + + MOCK_METHOD0(hardwareFailure, Return<void>()); + MOCK_TIMEOUT_METHOD2(configChange, Return<void>(Result, const BandConfig&)); + MOCK_METHOD2(tuneComplete, Return<void>(Result, const V1_0::ProgramInfo&)); + MOCK_TIMEOUT_METHOD2(tuneComplete_1_1, Return<void>(Result, const ProgramSelector&)); + MOCK_METHOD1(afSwitch, Return<void>(const V1_0::ProgramInfo&)); + MOCK_METHOD1(antennaStateChange, Return<void>(bool connected)); + MOCK_METHOD1(trafficAnnouncement, Return<void>(bool active)); + MOCK_METHOD1(emergencyAnnouncement, Return<void>(bool active)); + MOCK_METHOD3(newMetadata, Return<void>(uint32_t ch, uint32_t subCh, const hidl_vec<MetaData>&)); + MOCK_METHOD1(backgroundScanAvailable, Return<void>(bool)); + MOCK_TIMEOUT_METHOD1(backgroundScanComplete, Return<void>(ProgramListResult)); + MOCK_METHOD0(programListChanged, Return<void>()); + MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return<void>(const ProgramInfo&)); +}; - // ITunerCallback methods (see doc in ITunerCallback.hal) - virtual Return<void> hardwareFailure() { - ALOGI("%s", __FUNCTION__); - mParentTest->onHwFailureCallback(); - return Void(); - } +class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase, + public ::testing::WithParamInterface<Class> { + protected: + virtual void SetUp() override; + virtual void TearDown() override; - virtual Return<void> configChange(Result result, const BandConfig& config __unused) { - ALOGI("%s result %d", __FUNCTION__, result); - mParentTest->onResultCallback(result); - return Void(); - } + bool openTuner(); + bool nextBand(); + bool getProgramList(std::function<void(const hidl_vec<ProgramInfo>& list)> cb); - virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) { - return Void(); - } + Class radioClass; + bool skipped = false; - virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) { - ALOGI("%s result %d", __FUNCTION__, result); - mParentTest->onResultCallback(result); - return Void(); - } + sp<IBroadcastRadio> mRadioModule; + sp<ITuner> mTuner; + sp<TunerCallbackMock> mCallback = new TunerCallbackMock(); - virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) { - return Void(); - } + private: + const BandConfig& getBand(unsigned idx); - virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) { - return Void(); - } + unsigned currentBandIndex = 0; + hidl_vec<BandConfig> mBands; +}; - virtual Return<void> antennaStateChange(bool connected) { - ALOGI("%s connected %d", __FUNCTION__, connected); - return Void(); +/** + * Clears strong pointer and waits until the object gets destroyed. + * + * @param ptr The pointer to get cleared. + * @param timeout Time to wait for other references. + */ +template <typename T> +static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) { + wp<T> wptr = ptr; + ptr.clear(); + auto limit = steady_clock::now() + timeout; + while (wptr.promote() != nullptr) { + constexpr auto step = 10ms; + if (steady_clock::now() + step > limit) { + FAIL() << "Pointer was not released within timeout"; + break; } + sleep_for(step); + } +} - virtual Return<void> trafficAnnouncement(bool active) { - ALOGI("%s active %d", __FUNCTION__, active); - return Void(); - } +void BroadcastRadioHalTest::SetUp() { + radioClass = GetParam(); + + // lookup HIDL service + auto factory = getService<IBroadcastRadioFactory>(); + ASSERT_NE(nullptr, factory.get()); + + // connect radio module + Result connectResult; + CallBarrier onConnect; + factory->connectModule(radioClass, [&](Result ret, const sp<V1_0::IBroadcastRadio>& radio) { + connectResult = ret; + if (ret == Result::OK) mRadioModule = IBroadcastRadio::castFrom(radio); + onConnect.call(); + }); + ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout)); + + if (connectResult == Result::INVALID_ARGUMENTS) { + printSkipped("This device class is not supported."); + skipped = true; + return; + } + ASSERT_EQ(connectResult, Result::OK); + ASSERT_NE(nullptr, mRadioModule.get()); + + // get module properties + Properties prop11; + auto& prop10 = prop11.base; + auto propResult = + mRadioModule->getProperties_1_1([&](const Properties& properties) { prop11 = properties; }); + + ASSERT_TRUE(propResult.isOk()); + EXPECT_EQ(radioClass, prop10.classId); + EXPECT_GT(prop10.numTuners, 0u); + EXPECT_GT(prop11.supportedProgramTypes.size(), 0u); + EXPECT_GT(prop11.supportedIdentifierTypes.size(), 0u); + if (radioClass == Class::AM_FM) { + EXPECT_GT(prop10.bands.size(), 0u); + } + mBands = prop10.bands; +} - virtual Return<void> emergencyAnnouncement(bool active) { - ALOGI("%s active %d", __FUNCTION__, active); - return Void(); - } +void BroadcastRadioHalTest::TearDown() { + mTuner.clear(); + mRadioModule.clear(); + clearAndWait(mCallback, 1s); +} - virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused, - const ::android::hardware::hidl_vec<MetaData>& metadata __unused) { - ALOGI("%s", __FUNCTION__); - return Void(); - } +bool BroadcastRadioHalTest::openTuner() { + EXPECT_EQ(nullptr, mTuner.get()); - virtual Return<void> backgroundScanAvailable(bool isAvailable __unused) { - return Void(); - } + if (radioClass == Class::AM_FM) { + EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _); + } - virtual Return<void> backgroundScanComplete(ProgramListResult result __unused) { - return Void(); - } + Result halResult = Result::NOT_INITIALIZED; + auto openCb = [&](Result result, const sp<V1_0::ITuner>& tuner) { + halResult = result; + if (result != Result::OK) return; + mTuner = ITuner::castFrom(tuner); + }; + currentBandIndex = 0; + auto hidlResult = mRadioModule->openTuner(getBand(0), true, mCallback, openCb); - virtual Return<void> programListChanged() { - return Void(); - } + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, halResult); + EXPECT_NE(nullptr, mTuner.get()); + if (radioClass == Class::AM_FM && mTuner != nullptr) { + EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout); - MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {} + BandConfig halConfig; + Result halResult = Result::NOT_INITIALIZED; + mTuner->getConfiguration([&](Result result, const BandConfig& config) { + halResult = result; + halConfig = config; + }); + EXPECT_EQ(Result::OK, halResult); + EXPECT_TRUE(halConfig.antennaConnected); + } - private: - // BroadcastRadioHidlTest instance to which callbacks will be notified. - BroadcastRadioHidlTest *mParentTest; - }; + EXPECT_NE(nullptr, mTuner.get()); + return nullptr != mTuner.get(); +} +const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) { + static const BandConfig dummyBandConfig = {}; - /** - * Method called by MyCallback when a callback with no status or boolean value is received - */ - void onCallback() { - Mutex::Autolock _l(mLock); - onCallback_l(); + if (radioClass != Class::AM_FM) { + ALOGD("Not AM/FM radio, returning dummy band config"); + return dummyBandConfig; } - /** - * Method called by MyCallback when hardwareFailure() callback is received - */ - void onHwFailureCallback() { - Mutex::Autolock _l(mLock); - mHwFailure = true; - onCallback_l(); + EXPECT_GT(mBands.size(), idx); + if (mBands.size() <= idx) { + ALOGD("Band index out of bound, returning dummy band config"); + return dummyBandConfig; } - /** - * Method called by MyCallback when a callback with status is received - */ - void onResultCallback(Result result) { - Mutex::Autolock _l(mLock); - mResultCallbackData = result; - onCallback_l(); - } + auto& band = mBands[idx]; + ALOGD("Returning %s band", toString(band.type).c_str()); + return band; +} - /** - * Method called by MyCallback when a boolean indication is received - */ - void onBoolCallback(bool result) { - Mutex::Autolock _l(mLock); - mBoolCallbackData = result; - onCallback_l(); - } +bool BroadcastRadioHalTest::nextBand() { + if (currentBandIndex + 1 >= mBands.size()) return false; + currentBandIndex++; + BandConfig bandCb; + EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _) + .WillOnce(DoAll(SaveArg<1>(&bandCb), testing::Return(ByMove(Void())))); + auto hidlResult = mTuner->setConfiguration(getBand(currentBandIndex)); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout); + EXPECT_EQ(getBand(currentBandIndex), bandCb); - BroadcastRadioHidlTest() : - mCallbackCalled(false), mBoolCallbackData(false), - mResultCallbackData(Result::OK), mHwFailure(false) {} + return true; +} - void onCallback_l() { - if (!mCallbackCalled) { - mCallbackCalled = true; - mCallbackCond.broadcast(); - } - } +bool BroadcastRadioHalTest::getProgramList( + std::function<void(const hidl_vec<ProgramInfo>& list)> cb) { + ProgramListResult getListResult = ProgramListResult::NOT_INITIALIZED; + bool isListEmpty = true; + auto getListCb = [&](ProgramListResult result, const hidl_vec<ProgramInfo>& list) { + ALOGD("getListCb(%s, ProgramInfo[%zu])", toString(result).c_str(), list.size()); + getListResult = result; + if (result != ProgramListResult::OK) return; + isListEmpty = (list.size() == 0); + if (!isListEmpty) cb(list); + }; + // first try... + EXPECT_TIMEOUT_CALL(*mCallback, backgroundScanComplete, ProgramListResult::OK) + .Times(AnyNumber()); + auto hidlResult = mTuner->getProgramList({}, getListCb); + EXPECT_TRUE(hidlResult.isOk()); + if (!hidlResult.isOk()) return false; - bool waitForCallback(nsecs_t reltime = 0) { - Mutex::Autolock _l(mLock); - nsecs_t endTime = systemTime() + reltime; - while (!mCallbackCalled) { - if (reltime == 0) { - mCallbackCond.wait(mLock); - } else { - nsecs_t now = systemTime(); - if (now > endTime) { - return false; - } - mCallbackCond.waitRelative(mLock, endTime - now); - } - } - return true; + if (getListResult == ProgramListResult::NOT_STARTED) { + auto result = mTuner->startBackgroundScan(); + EXPECT_EQ(ProgramListResult::OK, result); + getListResult = ProgramListResult::NOT_READY; // continue as in NOT_READY case + } + if (getListResult == ProgramListResult::NOT_READY) { + EXPECT_TIMEOUT_CALL_WAIT(*mCallback, backgroundScanComplete, kFullScanTimeout); + + // second (last) try... + hidlResult = mTuner->getProgramList({}, getListCb); + EXPECT_TRUE(hidlResult.isOk()); + if (!hidlResult.isOk()) return false; + EXPECT_EQ(ProgramListResult::OK, getListResult); } - bool getProperties(); - bool openTuner(); - bool checkAntenna(); + return !isListEmpty; +} - static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10); - static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30); +/** + * Test IBroadcastRadio::openTuner() method called twice. + * + * Verifies that: + * - the openTuner method succeeds when called for the second time without + * deleting previous ITuner instance. + * + * This is a more strict requirement than in 1.0, where a second openTuner + * might fail. + */ +TEST_P(BroadcastRadioHalTest, OpenTunerTwice) { + if (skipped) return; - sp<IBroadcastRadio> mRadio; - Properties mHalProperties; - sp<ITuner> mTuner; - sp<MyCallback> mTunerCallback; - Mutex mLock; - Condition mCallbackCond; - bool mCallbackCalled; - bool mBoolCallbackData; - Result mResultCallbackData; - bool mHwFailure; -}; + ASSERT_TRUE(openTuner()); -// A class for test environment setup (kept since this file is a template). -class BroadcastRadioHidlEnvironment : public ::testing::Environment { - public: - virtual void SetUp() {} - virtual void TearDown() {} -}; + auto secondTuner = mTuner; + mTuner.clear(); -bool BroadcastRadioHidlTest::getProperties() -{ - if (mHalProperties.bands.size() == 0) { - Result halResult = Result::NOT_INITIALIZED; - Return<void> hidlReturn = - mRadio->getProperties([&](Result result, const Properties& properties) { - halResult = result; - if (result == Result::OK) { - mHalProperties = properties; - } - }); - - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_EQ(Result::OK, halResult); - EXPECT_EQ(Class::AM_FM, mHalProperties.classId); - EXPECT_GT(mHalProperties.numTuners, 0u); - EXPECT_GT(mHalProperties.bands.size(), 0u); - } - return mHalProperties.bands.size() > 0; + ASSERT_TRUE(openTuner()); } -bool BroadcastRadioHidlTest::openTuner() -{ - if (!getProperties()) { - return false; - } - if (mTuner.get() == nullptr) { - Result halResult = Result::NOT_INITIALIZED; - auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, - [&](Result result, const sp<V1_0::ITuner>& tuner) { - halResult = result; - if (result == Result::OK) { - mTuner = ITuner::castFrom(tuner); - } - }); - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_EQ(Result::OK, halResult); - EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); - } - EXPECT_NE(nullptr, mTuner.get()); - return nullptr != mTuner.get(); -} +/** + * Test tuning to program list entry. + * + * Verifies that: + * - getProgramList either succeeds or returns NOT_STARTED/NOT_READY status; + * - if the program list is NOT_STARTED, startBackgroundScan makes it completed + * within a full scan timeout and the next getProgramList call succeeds; + * - if the program list is not empty, tuneByProgramSelector call succeeds; + * - getProgramInformation_1_1 returns the same selector as returned in tuneComplete_1_1 call. + */ +TEST_P(BroadcastRadioHalTest, TuneFromProgramList) { + if (skipped) return; + ASSERT_TRUE(openTuner()); -bool BroadcastRadioHidlTest::checkAntenna() -{ - BandConfig halConfig; - Result halResult = Result::NOT_INITIALIZED; - Return<void> hidlReturn = - mTuner->getConfiguration([&](Result result, const BandConfig& config) { - halResult = result; - if (result == Result::OK) { - halConfig = config; - } - }); + ProgramInfo firstProgram; + bool foundAny = false; + do { + auto getCb = [&](const hidl_vec<ProgramInfo>& list) { + // don't copy the whole list out, it might be heavy + firstProgram = list[0]; + }; + if (getProgramList(getCb)) foundAny = true; + } while (nextBand()); + if (HasFailure()) return; + if (!foundAny) { + printSkipped("Program list is empty."); + return; + } - return ((halResult == Result::OK) && (halConfig.antennaConnected == true)); + ProgramInfo infoCb; + ProgramSelector selCb; + EXPECT_CALL(*mCallback, tuneComplete(_, _)).Times(0); + EXPECT_TIMEOUT_CALL(*mCallback, tuneComplete_1_1, Result::OK, _) + .WillOnce(DoAll(SaveArg<1>(&selCb), testing::Return(ByMove(Void())))); + EXPECT_TIMEOUT_CALL(*mCallback, currentProgramInfoChanged, _) + .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void())))); + auto tuneResult = mTuner->tuneByProgramSelector(firstProgram.selector); + ASSERT_EQ(Result::OK, tuneResult); + EXPECT_TIMEOUT_CALL_WAIT(*mCallback, tuneComplete_1_1, kTuneTimeout); + EXPECT_TIMEOUT_CALL_WAIT(*mCallback, currentProgramInfoChanged, kEventPropagationTimeout); + EXPECT_EQ(firstProgram.selector.primaryId, selCb.primaryId); + EXPECT_EQ(infoCb.selector, selCb); + + bool called = false; + auto getResult = mTuner->getProgramInformation_1_1([&](Result result, ProgramInfo info) { + called = true; + EXPECT_EQ(Result::OK, result); + EXPECT_EQ(selCb, info.selector); + }); + ASSERT_TRUE(getResult.isOk()); + ASSERT_TRUE(called); } - /** - * Test IBroadcastRadio::getProperties() method + * Test that primary vendor identifier isn't used for standard program types. * * Verifies that: - * - the HAL implements the method - * - the method returns 0 (no error) - * - the implementation class is AM_FM - * - the implementation supports at least one tuner - * - the implementation supports at one band + * - tuneByProgramSelector fails when VENDORn_PRIMARY is set as a primary + * identifier for program types other than VENDORn. */ -TEST_F(BroadcastRadioHidlTest, GetProperties) { - EXPECT_TRUE(getProperties()); +TEST_P(BroadcastRadioHalTest, TuneFailsForPrimaryVendor) { + if (skipped) return; + ASSERT_TRUE(openTuner()); + + for (auto ptype : kStandardProgramTypes) { + ALOGD("Checking %s...", toString(ptype).c_str()); + ProgramSelector sel = {}; + sel.programType = static_cast<uint32_t>(ptype); + sel.primaryId.type = static_cast<uint32_t>(IdentifierType::VENDOR_PRIMARY_START); + + auto tuneResult = mTuner->tuneByProgramSelector(sel); + ASSERT_NE(Result::OK, tuneResult); + } } /** - * Test IBroadcastRadio::openTuner() method + * Test that tune with unknown program type fails. * * Verifies that: - * - the HAL implements the method - * - the method returns 0 (no error) and a valid ITuner interface + * - tuneByProgramSelector fails with INVALID_ARGUMENT when unknown program type is passed. */ -TEST_F(BroadcastRadioHidlTest, OpenTuner) { - EXPECT_TRUE(openTuner()); +TEST_P(BroadcastRadioHalTest, TuneFailsForUnknownProgram) { + if (skipped) return; + ASSERT_TRUE(openTuner()); + + // Program type is 1-based, so 0 will be always invalid. + ProgramSelector sel = {}; + auto tuneResult = mTuner->tuneByProgramSelector(sel); + ASSERT_EQ(Result::INVALID_ARGUMENTS, tuneResult); } /** - * Test ITuner::setConfiguration() and getConfiguration methods + * Test cancelling announcement. * * Verifies that: - * - the HAL implements both methods - * - the methods return 0 (no error) - * - the configuration callback is received within kConfigCallbacktimeoutNs ns - * - the configuration read back from HAl has the same class Id + * - cancelAnnouncement succeeds either when there is an announcement or there is none. */ -TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) { +TEST_P(BroadcastRadioHalTest, CancelAnnouncement) { + if (skipped) return; ASSERT_TRUE(openTuner()); - // test setConfiguration - mCallbackCalled = false; - Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]); - EXPECT_TRUE(hidlResult.isOk()); + + auto hidlResult = mTuner->cancelAnnouncement(); EXPECT_EQ(Result::OK, hidlResult); - EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); - EXPECT_EQ(Result::OK, mResultCallbackData); - - // test getConfiguration - BandConfig halConfig; - Result halResult; - Return<void> hidlReturn = - mTuner->getConfiguration([&](Result result, const BandConfig& config) { - halResult = result; - if (result == Result::OK) { - halConfig = config; - } - }); - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_EQ(Result::OK, halResult); - EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type); } /** - * Test ITuner::scan + * Test getImage call with invalid image ID. * * Verifies that: - * - the HAL implements the method - * - the method returns 0 (no error) - * - the tuned callback is received within kTuneCallbacktimeoutNs ns + * - getImage call handles argument 0 gracefully. */ -TEST_F(BroadcastRadioHidlTest, Scan) { - ASSERT_TRUE(openTuner()); - ASSERT_TRUE(checkAntenna()); - // test scan UP - mCallbackCalled = false; - Return<Result> hidlResult = mTuner->scan(Direction::UP, true); - EXPECT_TRUE(hidlResult.isOk()); - EXPECT_EQ(Result::OK, hidlResult); - EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); +TEST_P(BroadcastRadioHalTest, GetNoImage) { + if (skipped) return; - // test scan DOWN - mCallbackCalled = false; - hidlResult = mTuner->scan(Direction::DOWN, true); - EXPECT_TRUE(hidlResult.isOk()); - EXPECT_EQ(Result::OK, hidlResult); - EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); + size_t len = 0; + auto hidlResult = + mRadioModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); }); + + ASSERT_TRUE(hidlResult.isOk()); + ASSERT_EQ(0u, len); } /** - * Test ITuner::step + * Test proper image format in metadata. * * Verifies that: - * - the HAL implements the method - * - the method returns 0 (no error) - * - the tuned callback is received within kTuneCallbacktimeoutNs ns + * - all images in metadata are provided out-of-band (by id, not as a binary blob); + * - images are available for getImage call. */ -TEST_F(BroadcastRadioHidlTest, Step) { +TEST_P(BroadcastRadioHalTest, OobImagesOnly) { + if (skipped) return; ASSERT_TRUE(openTuner()); - ASSERT_TRUE(checkAntenna()); - // test step UP - mCallbackCalled = false; - Return<Result> hidlResult = mTuner->step(Direction::UP, true); - EXPECT_TRUE(hidlResult.isOk()); - EXPECT_EQ(Result::OK, hidlResult); - EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); - // test step DOWN - mCallbackCalled = false; - hidlResult = mTuner->step(Direction::DOWN, true); - EXPECT_TRUE(hidlResult.isOk()); - EXPECT_EQ(Result::OK, hidlResult); - EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); + std::vector<int> imageIds; + + do { + auto getCb = [&](const hidl_vec<ProgramInfo>& list) { + for (auto&& program : list) { + for (auto&& entry : program.base.metadata) { + EXPECT_NE(MetadataType::RAW, entry.type); + if (entry.key != MetadataKey::ICON && entry.key != MetadataKey::ART) continue; + EXPECT_NE(0, entry.intValue); + EXPECT_EQ(0u, entry.rawValue.size()); + if (entry.intValue != 0) imageIds.push_back(entry.intValue); + } + } + }; + getProgramList(getCb); + } while (nextBand()); + + if (imageIds.size() == 0) { + printSkipped("No images found"); + return; + } + + for (auto id : imageIds) { + ALOGD("Checking image %d", id); + + size_t len = 0; + auto hidlResult = + mRadioModule->getImage(id, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); }); + + ASSERT_TRUE(hidlResult.isOk()); + ASSERT_GT(len, 0u); + } } /** - * Test ITuner::tune, getProgramInformation and cancel methods + * Test AnalogForced switch. * * Verifies that: - * - the HAL implements the methods - * - the methods return 0 (no error) - * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune() + * - setAnalogForced results either with INVALID_STATE, or isAnalogForced replying the same. */ -TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) { +TEST_P(BroadcastRadioHalTest, AnalogForcedSwitch) { + if (skipped) return; ASSERT_TRUE(openTuner()); - ASSERT_TRUE(checkAntenna()); - - // test tune - ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u); - ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit); - - // test scan UP - uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit; - uint32_t upperLimit = mHalProperties.bands[0].upperLimit; - uint32_t spacing = mHalProperties.bands[0].spacings[0]; - - uint32_t channel = - lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing; - mCallbackCalled = false; - mResultCallbackData = Result::NOT_INITIALIZED; - Return<Result> hidlResult = mTuner->tune(channel, 0); - EXPECT_TRUE(hidlResult.isOk()); - EXPECT_EQ(Result::OK, hidlResult); - EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); - // test getProgramInformation - ProgramInfo halInfo; - Result halResult = Result::NOT_INITIALIZED; - Return<void> hidlReturn = mTuner->getProgramInformation_1_1( - [&](Result result, const ProgramInfo& info) { - halResult = result; - if (result == Result::OK) { - halInfo = info; - } - }); - EXPECT_TRUE(hidlReturn.isOk()); - EXPECT_EQ(Result::OK, halResult); - auto &halInfo_1_1 = halInfo.base; - if (mResultCallbackData == Result::OK) { - EXPECT_TRUE(halInfo_1_1.tuned); - EXPECT_LE(halInfo_1_1.channel, upperLimit); - EXPECT_GE(halInfo_1_1.channel, lowerLimit); - } else { - EXPECT_EQ(false, halInfo_1_1.tuned); - } + bool forced; + Result halIsResult; + auto isCb = [&](Result result, bool isForced) { + halIsResult = result; + forced = isForced; + }; - // test cancel - mTuner->tune(lowerLimit, 0); - hidlResult = mTuner->cancel(); - EXPECT_TRUE(hidlResult.isOk()); - EXPECT_EQ(Result::OK, hidlResult); + // set analog mode + auto setResult = mTuner->setAnalogForced(true); + ASSERT_TRUE(setResult.isOk()); + if (Result::INVALID_STATE == setResult) { + // if setter fails, getter should fail too - it means the switch is not supported at all + auto isResult = mTuner->isAnalogForced(isCb); + ASSERT_TRUE(isResult.isOk()); + EXPECT_EQ(Result::INVALID_STATE, halIsResult); + return; + } + ASSERT_EQ(Result::OK, setResult); + + // check, if it's analog + auto isResult = mTuner->isAnalogForced(isCb); + ASSERT_TRUE(isResult.isOk()); + EXPECT_EQ(Result::OK, halIsResult); + ASSERT_TRUE(forced); + + // set digital mode + setResult = mTuner->setAnalogForced(false); + ASSERT_EQ(Result::OK, setResult); + + // check, if it's digital + isResult = mTuner->isAnalogForced(isCb); + ASSERT_TRUE(isResult.isOk()); + EXPECT_EQ(Result::OK, halIsResult); + ASSERT_FALSE(forced); } +INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest, + ::testing::Values(Class::AM_FM, Class::SAT, Class::DT)); + +} // namespace vts +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment); ::testing::InitGoogleTest(&argc, argv); int status = RUN_ALL_TESTS(); ALOGI("Test result = %d", status); diff --git a/broadcastradio/1.1/vts/utils/Android.bp b/broadcastradio/1.1/vts/utils/Android.bp new file mode 100644 index 0000000000..0c7e2a4433 --- /dev/null +++ b/broadcastradio/1.1/vts/utils/Android.bp @@ -0,0 +1,28 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.broadcastradio@1.1-vts-utils-lib", + srcs: [ + "call-barrier.cpp", + ], + export_include_dirs: ["include"], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], +} diff --git a/broadcastradio/1.1/vts/utils/call-barrier.cpp b/broadcastradio/1.1/vts/utils/call-barrier.cpp new file mode 100644 index 0000000000..d8c47162ed --- /dev/null +++ b/broadcastradio/1.1/vts/utils/call-barrier.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <broadcastradio-vts-utils/call-barrier.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace vts { + +using std::lock_guard; +using std::mutex; +using std::unique_lock; + +void CallBarrier::call() { + lock_guard<mutex> lk(mMut); + mWasCalled = true; + mCond.notify_all(); +} + +bool CallBarrier::waitForCall(std::chrono::milliseconds timeout) { + unique_lock<mutex> lk(mMut); + + if (mWasCalled) return true; + + auto status = mCond.wait_for(lk, timeout); + return status == std::cv_status::no_timeout; +} + +} // namespace vts +} // namespace broadcastradio +} // namespace hardware +} // namespace android diff --git a/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/call-barrier.h b/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/call-barrier.h new file mode 100644 index 0000000000..462396a55b --- /dev/null +++ b/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/call-barrier.h @@ -0,0 +1,59 @@ +/* + * 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_CALL_BARRIER +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_CALL_BARRIER + +#include <chrono> +#include <thread> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace vts { + +/** + * A barrier for thread synchronization, where one should wait for another to + * reach a specific point in execution. + */ +class CallBarrier { + public: + /** + * Notify the other thread it may continue execution. + * + * This may be called before the other thread starts waiting on the barrier. + */ + void call(); + + /** + * Wait for the other thread to reach call() execution point. + * + * @param timeout a maximum time to wait. + * @returns {@code false} if timed out, {@code true} otherwise. + */ + bool waitForCall(std::chrono::milliseconds timeout); + + private: + bool mWasCalled = false; + std::mutex mMut; + std::condition_variable mCond; +}; + +} // namespace vts +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_CALL_BARRIER diff --git a/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h b/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h new file mode 100644 index 0000000000..b0ce08806d --- /dev/null +++ b/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h @@ -0,0 +1,111 @@ +/* + * 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT + +#include <gmock/gmock.h> +#include <thread> + +/** + * Common helper objects for gmock timeout extension. + * + * INTERNAL IMPLEMENTATION - don't use in user code. + */ +#define EGMOCK_TIMEOUT_METHOD_DEF_(Method, ...) \ + std::atomic<bool> egmock_called_##Method; \ + std::mutex egmock_mut_##Method; \ + std::condition_variable egmock_cond_##Method; + +/** + * Common method body for gmock timeout extension. + * + * INTERNAL IMPLEMENTATION - don't use in user code. + */ +#define EGMOCK_TIMEOUT_METHOD_BODY_(Method, ...) \ + auto ret = egmock_##Method(__VA_ARGS__); \ + { \ + std::lock_guard<std::mutex> lk(egmock_mut_##Method); \ + egmock_called_##Method = true; \ + egmock_cond_##Method.notify_all(); \ + } \ + return ret; + +/** + * Gmock MOCK_METHOD0 timeout-capable extension. + */ +#define MOCK_TIMEOUT_METHOD0(Method, ...) \ + MOCK_METHOD0(egmock_##Method, __VA_ARGS__); \ + EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ + virtual GMOCK_RESULT_(, __VA_ARGS__) Method() { EGMOCK_TIMEOUT_METHOD_BODY_(Method); } + +/** + * Gmock MOCK_METHOD1 timeout-capable extension. + */ +#define MOCK_TIMEOUT_METHOD1(Method, ...) \ + MOCK_METHOD1(egmock_##Method, __VA_ARGS__); \ + EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ + virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \ + EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1); \ + } + +/** + * Gmock MOCK_METHOD2 timeout-capable extension. + */ +#define MOCK_TIMEOUT_METHOD2(Method, ...) \ + MOCK_METHOD2(egmock_##Method, __VA_ARGS__); \ + EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ + virtual GMOCK_RESULT_(, __VA_ARGS__) \ + Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \ + EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2); \ + } + +/** + * Gmock EXPECT_CALL timeout-capable extension. + * + * It has slightly different syntax from the original macro, to make method name accessible. + * So, instead of typing + * EXPECT_CALL(account, charge(100, Currency::USD)); + * you need to inline arguments + * EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD); + */ +#define EXPECT_TIMEOUT_CALL(obj, Method, ...) \ + (obj).egmock_called_##Method = false; \ + EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__)) + +/** + * Waits for an earlier EXPECT_TIMEOUT_CALL to execute. + * + * It does not fully support special constraints of the EXPECT_CALL clause, just proceeds when the + * first call to a given method comes. For example, in the following code: + * EXPECT_TIMEOUT_CALL(account, charge, 100, _); + * account.charge(50, Currency::USD); + * EXPECT_TIMEOUT_CALL_WAIT(account, charge, 500ms); + * the wait clause will just continue, as the charge method was called. + * + * @param obj object for a call + * @param Method the method to wait for + * @param timeout the maximum time for waiting + */ +#define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout) \ + { \ + std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method); \ + if (!(obj).egmock_called_##Method) { \ + auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \ + EXPECT_EQ(std::cv_status::no_timeout, status); \ + } \ + } + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT diff --git a/broadcastradio/Android.bp b/broadcastradio/Android.bp index 7a315faab3..8c65bf6013 100644 --- a/broadcastradio/Android.bp +++ b/broadcastradio/Android.bp @@ -5,5 +5,8 @@ subdirs = [ "1.0/vts/functional", "1.1", "1.1/default", + "1.1/tests", + "1.1/utils", "1.1/vts/functional", + "1.1/vts/utils", ] diff --git a/camera/Android.bp b/camera/Android.bp index 3869766db5..0240751c5a 100644 --- a/camera/Android.bp +++ b/camera/Android.bp @@ -6,6 +6,8 @@ subdirs = [ "device/1.0/default", "device/3.2", "device/3.2/default", + "device/3.3", + "device/3.3/default", "metadata/3.2", "provider/2.4", "provider/2.4/default", diff --git a/camera/common/1.0/default/CameraParameters.cpp b/camera/common/1.0/default/CameraParameters.cpp index d224483c75..e707b0855a 100644 --- a/camera/common/1.0/default/CameraParameters.cpp +++ b/camera/common/1.0/default/CameraParameters.cpp @@ -20,6 +20,7 @@ #include <string.h> #include <stdlib.h> +#include <unistd.h> #include "CameraParameters.h" #include <system/graphics.h> diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp index 1a349d6a3e..e0b31f0a48 100644 --- a/camera/device/1.0/default/Android.bp +++ b/camera/device/1.0/default/Android.bp @@ -26,6 +26,9 @@ cc_library_shared { static_libs: [ "android.hardware.camera.common@1.0-helper" ], + header_libs: [ + "media_plugin_headers", + ], include_dirs: [ "frameworks/native/include/media/openmax" ], diff --git a/camera/device/1.0/default/OWNERS b/camera/device/1.0/default/OWNERS new file mode 100644 index 0000000000..18acfee145 --- /dev/null +++ b/camera/device/1.0/default/OWNERS @@ -0,0 +1,6 @@ +cychen@google.com +epeev@google.com +etalvala@google.com +shuzhenwang@google.com +yinchiayeh@google.com +zhijunhe@google.com diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp index 637a1e6616..295ee32865 100644 --- a/camera/device/3.2/default/CameraDevice.cpp +++ b/camera/device/3.2/default/CameraDevice.cpp @@ -177,7 +177,7 @@ Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_ if (callback == nullptr) { ALOGE("%s: cannot open camera %s. callback is null!", __FUNCTION__, mCameraId.c_str()); - _hidl_cb(Status::ILLEGAL_ARGUMENT, session); + _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } @@ -186,7 +186,7 @@ Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_ // this must be a disconnected camera ALOGE("%s: cannot open camera %s. camera is disconnected!", __FUNCTION__, mCameraId.c_str()); - _hidl_cb(Status::CAMERA_DISCONNECTED, session); + _hidl_cb(Status::CAMERA_DISCONNECTED, nullptr); return Void(); } else { mLock.lock(); @@ -239,7 +239,7 @@ Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_ return Void(); } - session = new CameraDeviceSession( + session = createSession( device, info.static_camera_characteristics, callback); if (session == nullptr) { ALOGE("%s: camera device session allocation failed", __FUNCTION__); @@ -255,9 +255,19 @@ Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_ return Void(); } mSession = session; + + IF_ALOGV() { + session->getInterface()->interfaceChain([]( + ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { + ALOGV("Session interface chain:"); + for (auto iface : interfaceChain) { + ALOGV(" %s", iface.c_str()); + } + }); + } mLock.unlock(); } - _hidl_cb(status, session); + _hidl_cb(status, session->getInterface()); return Void(); } @@ -286,6 +296,13 @@ Return<void> CameraDevice::dumpState(const ::android::hardware::hidl_handle& han session->dumpState(handle); return Void(); } + +sp<CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device, + const camera_metadata_t* deviceInfo, + const sp<ICameraDeviceCallback>& callback) { + return new CameraDeviceSession(device, deviceInfo, callback); +} + // End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice. } // namespace implementation diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp index fcd134f45e..d6a04bc56b 100644 --- a/camera/device/3.2/default/CameraDeviceSession.cpp +++ b/camera/device/3.2/default/CameraDeviceSession.cpp @@ -49,7 +49,6 @@ CameraDeviceSession::CameraDeviceSession( mDerivePostRawSensKey(false), mNumPartialResults(1), mResultBatcher(callback) { - mDeviceInfo = deviceInfo; camera_metadata_entry partialResultsCount = mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT); @@ -328,7 +327,8 @@ void CameraDeviceSession::ResultBatcher::setBatchedStreams( mStreamsToBatch = streamsToBatch; } -void CameraDeviceSession::ResultBatcher::setResultMetadataQueue(std::shared_ptr<ResultMetadataQueue> q) { +void CameraDeviceSession::ResultBatcher::setResultMetadataQueue( + std::shared_ptr<ResultMetadataQueue> q) { Mutex::Autolock _l(mLock); mResultMetadataQueue = q; } @@ -387,7 +387,8 @@ void CameraDeviceSession::ResultBatcher::checkAndRemoveFirstBatch() { } } -void CameraDeviceSession::ResultBatcher::sendBatchShutterCbsLocked(std::shared_ptr<InflightBatch> batch) { +void CameraDeviceSession::ResultBatcher::sendBatchShutterCbsLocked( + std::shared_ptr<InflightBatch> batch) { if (batch->mShutterDelivered) { ALOGW("%s: batch shutter callback already sent!", __FUNCTION__); return; @@ -441,7 +442,8 @@ void CameraDeviceSession::ResultBatcher::pushStreamBuffer( } } -void CameraDeviceSession::ResultBatcher::sendBatchBuffersLocked(std::shared_ptr<InflightBatch> batch) { +void CameraDeviceSession::ResultBatcher::sendBatchBuffersLocked( + std::shared_ptr<InflightBatch> batch) { sendBatchBuffersLocked(batch, mStreamsToBatch); } @@ -736,7 +738,7 @@ void CameraDeviceSession::ResultBatcher::processCaptureResult(CaptureResult& res // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow. Return<void> CameraDeviceSession::constructDefaultRequestSettings( - RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) { + RequestTemplate type, ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) { Status status = initStatus(); CameraMetadata outMetadata; const camera_metadata_t *rawRequest; @@ -802,7 +804,8 @@ android_dataspace CameraDeviceSession::mapToLegacyDataspace( } Return<void> CameraDeviceSession::configureStreams( - const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) { + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_cb _hidl_cb) { Status status = initStatus(); HalStreamConfiguration outStreams; @@ -960,13 +963,13 @@ void CameraDeviceSession::updateBufferCaches(const hidl_vec<BufferCache>& caches } Return<void> CameraDeviceSession::getCaptureRequestMetadataQueue( - getCaptureRequestMetadataQueue_cb _hidl_cb) { + ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) { _hidl_cb(*mRequestMetadataQueue->getDesc()); return Void(); } Return<void> CameraDeviceSession::getCaptureResultMetadataQueue( - getCaptureResultMetadataQueue_cb _hidl_cb) { + ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) { _hidl_cb(*mResultMetadataQueue->getDesc()); return Void(); } @@ -974,7 +977,7 @@ Return<void> CameraDeviceSession::getCaptureResultMetadataQueue( Return<void> CameraDeviceSession::processCaptureRequest( const hidl_vec<CaptureRequest>& requests, const hidl_vec<BufferCache>& cachesToRemove, - processCaptureRequest_cb _hidl_cb) { + ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) { updateBufferCaches(cachesToRemove); uint32_t numRequestProcessed = 0; diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h index 2fe189fde1..69e2e2c802 100644 --- a/camera/device/3.2/default/CameraDeviceSession.h +++ b/camera/device/3.2/default/CameraDeviceSession.h @@ -55,6 +55,8 @@ using ::android::hardware::hidl_string; using ::android::sp; using ::android::Mutex; +struct Camera3Stream; + /** * Function pointer types with C calling convention to * use for HAL callback functions. @@ -69,12 +71,12 @@ extern "C" { const camera3_notify_msg_t *); } -struct CameraDeviceSession : public ICameraDeviceSession, private camera3_callback_ops { +struct CameraDeviceSession : public virtual RefBase, protected camera3_callback_ops { CameraDeviceSession(camera3_device_t*, const camera_metadata_t* deviceInfo, const sp<ICameraDeviceCallback>&); - ~CameraDeviceSession(); + virtual ~CameraDeviceSession(); // Call by CameraDevice to dump active device states void dumpState(const native_handle_t* fd); // Caller must use this method to check if CameraDeviceSession ctor failed @@ -83,23 +85,35 @@ struct CameraDeviceSession : public ICameraDeviceSession, private camera3_callba void disconnect(); bool isClosed(); - // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow. + // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when + // dealing with minor version revs and simultaneous implementation and interface inheritance + virtual sp<ICameraDeviceSession> getInterface() { + return new TrampolineSessionInterface_3_2(this); + } + +protected: + + // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow + Return<void> constructDefaultRequestSettings( - RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) override; + RequestTemplate type, + ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb); Return<void> configureStreams( - const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) override; + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_cb _hidl_cb); Return<void> getCaptureRequestMetadataQueue( - getCaptureRequestMetadataQueue_cb _hidl_cb) override; + ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb); Return<void> getCaptureResultMetadataQueue( - getCaptureResultMetadataQueue_cb _hidl_cb) override; + ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb); Return<void> processCaptureRequest( const hidl_vec<CaptureRequest>& requests, const hidl_vec<BufferCache>& cachesToRemove, - processCaptureRequest_cb _hidl_cb) override; - Return<Status> flush() override; - Return<void> close() override; + ICameraDeviceSession::processCaptureRequest_cb _hidl_cb); + Return<Status> flush(); + Return<void> close(); + +protected: -private: // protecting mClosed/mDisconnected/mInitFail mutable Mutex mStateLock; // device is closed either @@ -302,6 +316,52 @@ private: */ static callbacks_process_capture_result_t sProcessCaptureResult; static callbacks_notify_t sNotify; + +private: + + struct TrampolineSessionInterface_3_2 : public ICameraDeviceSession { + TrampolineSessionInterface_3_2(sp<CameraDeviceSession> parent) : + mParent(parent) {} + + virtual Return<void> constructDefaultRequestSettings( + V3_2::RequestTemplate type, + V3_2::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override { + return mParent->constructDefaultRequestSettings(type, _hidl_cb); + } + + virtual Return<void> configureStreams( + const V3_2::StreamConfiguration& requestedConfiguration, + V3_2::ICameraDeviceSession::configureStreams_cb _hidl_cb) override { + return mParent->configureStreams(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests, + const hidl_vec<V3_2::BufferCache>& cachesToRemove, + V3_2::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override { + return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb); + } + + virtual Return<void> getCaptureRequestMetadataQueue( + V3_2::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureRequestMetadataQueue(_hidl_cb); + } + + virtual Return<void> getCaptureResultMetadataQueue( + V3_2::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return<Status> flush() override { + return mParent->flush(); + } + + virtual Return<void> close() override { + return mParent->close(); + } + + private: + sp<CameraDeviceSession> mParent; + }; }; } // namespace implementation diff --git a/camera/device/3.2/default/CameraDevice_3_2.h b/camera/device/3.2/default/CameraDevice_3_2.h index 4e8606757c..9534707bd0 100644 --- a/camera/device/3.2/default/CameraDevice_3_2.h +++ b/camera/device/3.2/default/CameraDevice_3_2.h @@ -80,7 +80,13 @@ struct CameraDevice : public ICameraDevice { Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override; /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */ -private: +protected: + + // Overridden by child implementations for returning different versions of CameraDeviceSession + virtual sp<CameraDeviceSession> createSession(camera3_device_t*, + const camera_metadata_t* deviceInfo, + const sp<ICameraDeviceCallback>&); + const sp<CameraModule> mModule; const std::string mCameraId; // const after ctor diff --git a/camera/device/3.2/default/OWNERS b/camera/device/3.2/default/OWNERS new file mode 100644 index 0000000000..18acfee145 --- /dev/null +++ b/camera/device/3.2/default/OWNERS @@ -0,0 +1,6 @@ +cychen@google.com +epeev@google.com +etalvala@google.com +shuzhenwang@google.com +yinchiayeh@google.com +zhijunhe@google.com diff --git a/camera/device/3.3/Android.bp b/camera/device/3.3/Android.bp new file mode 100644 index 0000000000..2a1999165c --- /dev/null +++ b/camera/device/3.3/Android.bp @@ -0,0 +1,72 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.camera.device@3.3_hal", + srcs: [ + "types.hal", + "ICameraDeviceSession.hal", + ], +} + +genrule { + name: "android.hardware.camera.device@3.3_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@3.3", + srcs: [ + ":android.hardware.camera.device@3.3_hal", + ], + out: [ + "android/hardware/camera/device/3.3/types.cpp", + "android/hardware/camera/device/3.3/CameraDeviceSessionAll.cpp", + ], +} + +genrule { + name: "android.hardware.camera.device@3.3_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@3.3", + srcs: [ + ":android.hardware.camera.device@3.3_hal", + ], + out: [ + "android/hardware/camera/device/3.3/types.h", + "android/hardware/camera/device/3.3/hwtypes.h", + "android/hardware/camera/device/3.3/ICameraDeviceSession.h", + "android/hardware/camera/device/3.3/IHwCameraDeviceSession.h", + "android/hardware/camera/device/3.3/BnHwCameraDeviceSession.h", + "android/hardware/camera/device/3.3/BpHwCameraDeviceSession.h", + "android/hardware/camera/device/3.3/BsCameraDeviceSession.h", + ], +} + +cc_library { + name: "android.hardware.camera.device@3.3", + defaults: ["hidl-module-defaults"], + generated_sources: ["android.hardware.camera.device@3.3_genc++"], + generated_headers: ["android.hardware.camera.device@3.3_genc++_headers"], + export_generated_headers: ["android.hardware.camera.device@3.3_genc++_headers"], + vendor_available: true, + vndk: { + enabled: true, + }, + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.graphics.common@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.graphics.common@1.0", + ], +} diff --git a/camera/device/3.3/ICameraDeviceSession.hal b/camera/device/3.3/ICameraDeviceSession.hal new file mode 100644 index 0000000000..764392f1cf --- /dev/null +++ b/camera/device/3.3/ICameraDeviceSession.hal @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera.device@3.3; + +import android.hardware.camera.common@1.0::Status; +import android.hardware.camera.device@3.2::ICameraDeviceSession; +import android.hardware.camera.device@3.2::StreamConfiguration; + +/** + * Camera device active session interface. + * + * Obtained via ICameraDevice::open(), this interface contains the methods to + * configure and request captures from an active camera device. + * + */ +interface ICameraDeviceSession extends @3.2::ICameraDeviceSession { + + /** + * configureStreams_3_3: + * + * Identical to @3.2::ICameraDeviceSession.configureStreams, except that: + * + * - The output HalStreamConfiguration now contains an overrideDataspace + * field, to be used by the HAL to select a different dataspace for some + * use cases when dealing with the IMPLEMENTATION_DEFINED pixel format. + * + * Clients may invoke either this method or + * @3.2::ICameraDeviceSession.configureStreams() for stream configuration. + * This method is recommended for clients to use since it provides more + * flexibility. + */ + configureStreams_3_3(StreamConfiguration requestedConfiguration) + generates (Status status, + @3.3::HalStreamConfiguration halConfiguration); + +}; diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp new file mode 100644 index 0000000000..b1e9b46d8f --- /dev/null +++ b/camera/device/3.3/default/Android.bp @@ -0,0 +1,30 @@ +cc_library_shared { + name: "camera.device@3.3-impl", + defaults: ["hidl_defaults"], + proprietary: true, + srcs: ["CameraDevice.cpp", + "CameraDeviceSession.cpp", + "convert.cpp"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libutils", + "libcutils", + "camera.device@3.2-impl", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.provider@2.4", + "android.hardware.graphics.mapper@2.0", + "liblog", + "libhardware", + "libcamera_metadata", + "libfmq" + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper" + ], + export_include_dirs: ["."], + export_shared_lib_headers: [ + "libfmq", + ] +} diff --git a/camera/device/3.3/default/CameraDevice.cpp b/camera/device/3.3/default/CameraDevice.cpp new file mode 100644 index 0000000000..ce5e1de239 --- /dev/null +++ b/camera/device/3.3/default/CameraDevice.cpp @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#define LOG_TAG "CamDev@3.3-impl" +#include <log/log.h> + +#include <utils/Vector.h> +#include <utils/Trace.h> +#include "CameraDevice_3_3.h" +#include <include/convert.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_3 { +namespace implementation { + +using ::android::hardware::camera::common::V1_0::Status; +using namespace ::android::hardware::camera::device; + +CameraDevice::CameraDevice( + sp<CameraModule> module, const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) : + V3_2::implementation::CameraDevice(module, cameraId, cameraDeviceNames) { +} + +CameraDevice::~CameraDevice() { +} + +sp<V3_2::implementation::CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>& callback) { + sp<CameraDeviceSession> session = new CameraDeviceSession(device, deviceInfo, callback); + IF_ALOGV() { + session->getInterface()->interfaceChain([]( + ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { + ALOGV("Session interface chain:"); + for (auto iface : interfaceChain) { + ALOGV(" %s", iface.c_str()); + } + }); + } + return session; +} + +// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice. + +} // namespace implementation +} // namespace V3_3 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.3/default/CameraDeviceSession.cpp b/camera/device/3.3/default/CameraDeviceSession.cpp new file mode 100644 index 0000000000..f877895ebb --- /dev/null +++ b/camera/device/3.3/default/CameraDeviceSession.cpp @@ -0,0 +1,178 @@ +/* + * 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. + */ + +#define LOG_TAG "CamDevSession@3.3-impl" +#include <android/log.h> + +#include <set> +#include <utils/Trace.h> +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> +#include "CameraDeviceSession.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_3 { +namespace implementation { + +CameraDeviceSession::CameraDeviceSession( + camera3_device_t* device, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>& callback) : + V3_2::implementation::CameraDeviceSession(device, deviceInfo, callback) { +} + +CameraDeviceSession::~CameraDeviceSession() { +} + +Return<void> CameraDeviceSession::configureStreams_3_3( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb) { + Status status = initStatus(); + HalStreamConfiguration outStreams; + + // hold the inflight lock for entire configureStreams scope since there must not be any + // inflight request/results during stream configuration. + Mutex::Autolock _l(mInflightLock); + if (!mInflightBuffers.empty()) { + ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!", + __FUNCTION__, mInflightBuffers.size()); + _hidl_cb(Status::INTERNAL_ERROR, outStreams); + return Void(); + } + + if (!mInflightAETriggerOverrides.empty()) { + ALOGE("%s: trying to configureStreams while there are still %zu inflight" + " trigger overrides!", __FUNCTION__, + mInflightAETriggerOverrides.size()); + _hidl_cb(Status::INTERNAL_ERROR, outStreams); + return Void(); + } + + if (!mInflightRawBoostPresent.empty()) { + ALOGE("%s: trying to configureStreams while there are still %zu inflight" + " boost overrides!", __FUNCTION__, + mInflightRawBoostPresent.size()); + _hidl_cb(Status::INTERNAL_ERROR, outStreams); + return Void(); + } + + if (status != Status::OK) { + _hidl_cb(status, outStreams); + return Void(); + } + + camera3_stream_configuration_t stream_list; + hidl_vec<camera3_stream_t*> streams; + + stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode; + stream_list.num_streams = requestedConfiguration.streams.size(); + streams.resize(stream_list.num_streams); + stream_list.streams = streams.data(); + + for (uint32_t i = 0; i < stream_list.num_streams; i++) { + int id = requestedConfiguration.streams[i].id; + + if (mStreamMap.count(id) == 0) { + Camera3Stream stream; + V3_2::implementation::convertFromHidl(requestedConfiguration.streams[i], &stream); + mStreamMap[id] = stream; + mStreamMap[id].data_space = mapToLegacyDataspace( + mStreamMap[id].data_space); + mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{}); + } else { + // width/height/format must not change, but usage/rotation might need to change + if (mStreamMap[id].stream_type != + (int) requestedConfiguration.streams[i].streamType || + mStreamMap[id].width != requestedConfiguration.streams[i].width || + mStreamMap[id].height != requestedConfiguration.streams[i].height || + mStreamMap[id].format != (int) requestedConfiguration.streams[i].format || + mStreamMap[id].data_space != + mapToLegacyDataspace( static_cast<android_dataspace_t> ( + requestedConfiguration.streams[i].dataSpace))) { + ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); + _hidl_cb(Status::INTERNAL_ERROR, outStreams); + return Void(); + } + mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation; + mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage; + } + streams[i] = &mStreamMap[id]; + } + + ATRACE_BEGIN("camera3->configure_streams"); + status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list); + ATRACE_END(); + + // In case Hal returns error most likely it was not able to release + // the corresponding resources of the deleted streams. + if (ret == OK) { + // delete unused streams, note we do this after adding new streams to ensure new stream + // will not have the same address as deleted stream, and HAL has a chance to reference + // the to be deleted stream in configure_streams call + for(auto it = mStreamMap.begin(); it != mStreamMap.end();) { + int id = it->first; + bool found = false; + for (const auto& stream : requestedConfiguration.streams) { + if (id == stream.id) { + found = true; + break; + } + } + if (!found) { + // Unmap all buffers of deleted stream + // in case the configuration call succeeds and HAL + // is able to release the corresponding resources too. + cleanupBuffersLocked(id); + it = mStreamMap.erase(it); + } else { + ++it; + } + } + + // Track video streams + mVideoStreamIds.clear(); + for (const auto& stream : requestedConfiguration.streams) { + if (stream.streamType == V3_2::StreamType::OUTPUT && + stream.usage & + graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) { + mVideoStreamIds.push_back(stream.id); + } + } + mResultBatcher.setBatchedStreams(mVideoStreamIds); + } + + if (ret == -EINVAL) { + status = Status::ILLEGAL_ARGUMENT; + } else if (ret != OK) { + status = Status::INTERNAL_ERROR; + } else { + convertToHidl(stream_list, &outStreams); + mFirstRequest = true; + } + + _hidl_cb(status, outStreams); + return Void(); +} + +} // namespace implementation +} // namespace V3_3 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.3/default/CameraDeviceSession.h b/camera/device/3.3/default/CameraDeviceSession.h new file mode 100644 index 0000000000..dd52b35b8e --- /dev/null +++ b/camera/device/3.3/default/CameraDeviceSession.h @@ -0,0 +1,138 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_3_CAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_3_CAMERADEVICE3SESSION_H + +#include <android/hardware/camera/device/3.2/ICameraDevice.h> +#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h> +#include <../../3.2/default/CameraDeviceSession.h> +#include <fmq/MessageQueue.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <include/convert.h> +#include <deque> +#include <map> +#include <unordered_map> +#include "CameraMetadata.h" +#include "HandleImporter.h" +#include "hardware/camera3.h" +#include "hardware/camera_common.h" +#include "utils/Mutex.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_3 { +namespace implementation { + +using namespace ::android::hardware::camera::device; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::StreamConfiguration; +using ::android::hardware::camera::device::V3_3::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_3::ICameraDeviceSession; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; + +struct CameraDeviceSession : public V3_2::implementation::CameraDeviceSession { + + CameraDeviceSession(camera3_device_t*, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>&); + virtual ~CameraDeviceSession(); + + virtual sp<V3_2::ICameraDeviceSession> getInterface() override { + return new TrampolineSessionInterface_3_3(this); + } + +protected: + // Methods from v3.2 and earlier will trampoline to inherited implementation + + // New methods for v3.3 + + Return<void> configureStreams_3_3( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb); +private: + + struct TrampolineSessionInterface_3_3 : public ICameraDeviceSession { + TrampolineSessionInterface_3_3(sp<CameraDeviceSession> parent) : + mParent(parent) {} + + virtual Return<void> constructDefaultRequestSettings( + V3_2::RequestTemplate type, + V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override { + return mParent->constructDefaultRequestSettings(type, _hidl_cb); + } + + virtual Return<void> configureStreams( + const V3_2::StreamConfiguration& requestedConfiguration, + V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override { + return mParent->configureStreams(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests, + const hidl_vec<V3_2::BufferCache>& cachesToRemove, + V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override { + return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb); + } + + virtual Return<void> getCaptureRequestMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureRequestMetadataQueue(_hidl_cb); + } + + virtual Return<void> getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return<Status> flush() override { + return mParent->flush(); + } + + virtual Return<void> close() override { + return mParent->close(); + } + + virtual Return<void> configureStreams_3_3( + const StreamConfiguration& requestedConfiguration, configureStreams_3_3_cb _hidl_cb) override { + return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb); + } + + private: + sp<CameraDeviceSession> mParent; + }; +}; + +} // namespace implementation +} // namespace V3_3 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_3_CAMERADEVICE3SESSION_H diff --git a/camera/device/3.3/default/CameraDevice_3_3.h b/camera/device/3.3/default/CameraDevice_3_3.h new file mode 100644 index 0000000000..18b3fe8e81 --- /dev/null +++ b/camera/device/3.3/default/CameraDevice_3_3.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_3_CAMERADEVICE_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_3_CAMERADEVICE_H + +#include "utils/Mutex.h" +#include "CameraModule.h" +#include "CameraMetadata.h" +#include "CameraDeviceSession.h" +#include <../../3.2/default/CameraDevice_3_2.h> + +#include <android/hardware/camera/device/3.2/ICameraDevice.h> +#include <hidl/Status.h> +#include <hidl/MQDescriptor.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_3 { +namespace implementation { + +using namespace ::android::hardware::camera::device; +using ::android::hardware::camera::common::V1_0::helper::CameraModule; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * The camera device HAL implementation is opened lazily (via the open call) + */ +struct CameraDevice : public V3_2::implementation::CameraDevice { + + // Called by provider HAL. + // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could + // be multiple CameraDevice trying to access the same physical camera. Also, provider will have + // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying + // camera is detached. + // Delegates nearly all work to CameraDevice_3_2 + CameraDevice(sp<CameraModule> module, + const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames); + ~CameraDevice(); + +protected: + virtual sp<V3_2::implementation::CameraDeviceSession> createSession(camera3_device_t*, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>&) override; + +}; + +} // namespace implementation +} // namespace V3_3 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_3_CAMERADEVICE_H diff --git a/camera/device/3.3/default/OWNERS b/camera/device/3.3/default/OWNERS new file mode 100644 index 0000000000..18acfee145 --- /dev/null +++ b/camera/device/3.3/default/OWNERS @@ -0,0 +1,6 @@ +cychen@google.com +epeev@google.com +etalvala@google.com +shuzhenwang@google.com +yinchiayeh@google.com +zhijunhe@google.com diff --git a/camera/device/3.3/default/convert.cpp b/camera/device/3.3/default/convert.cpp new file mode 100644 index 0000000000..dae190b03c --- /dev/null +++ b/camera/device/3.3/default/convert.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.camera.device@3.3-convert-impl" +#include <log/log.h> + +#include "include/convert.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_3 { +namespace implementation { + +using ::android::hardware::graphics::common::V1_0::Dataspace; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::camera::device::V3_2::BufferUsageFlags; + +void convertToHidl(const Camera3Stream* src, HalStream* dst) { + dst->overrideDataSpace = src->data_space; + dst->v3_2.id = src->mId; + dst->v3_2.overrideFormat = (PixelFormat) src->format; + dst->v3_2.maxBuffers = src->max_buffers; + if (src->stream_type == CAMERA3_STREAM_OUTPUT) { + dst->v3_2.consumerUsage = (BufferUsageFlags)0; + dst->v3_2.producerUsage = (BufferUsageFlags)src->usage; + } else if (src->stream_type == CAMERA3_STREAM_INPUT) { + dst->v3_2.producerUsage = (BufferUsageFlags)0; + dst->v3_2.consumerUsage = (BufferUsageFlags)src->usage; + } else { + //Should not reach here per current HIDL spec, but we might end up adding + // bi-directional stream to HIDL. + ALOGW("%s: Stream type %d is not currently supported!", + __FUNCTION__, src->stream_type); + } +} + +void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst) { + dst->streams.resize(src.num_streams); + for (uint32_t i = 0; i < src.num_streams; i++) { + convertToHidl(static_cast<Camera3Stream*>(src.streams[i]), &dst->streams[i]); + } + return; +} + +} // namespace implementation +} // namespace V3_3 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.3/default/include/convert.h b/camera/device/3.3/default/include/convert.h new file mode 100644 index 0000000000..23bb79796c --- /dev/null +++ b/camera/device/3.3/default/include/convert.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_V3_3_DEFAULT_INCLUDE_CONVERT_H_ + +#define HARDWARE_INTERFACES_CAMERA_DEVICE_V3_3_DEFAULT_INCLUDE_CONVERT_H_ + +#include <set> + + +#include <android/hardware/graphics/common/1.0/types.h> +#include <android/hardware/camera/device/3.3/types.h> +#include "hardware/camera3.h" +#include "../../3.2/default/include/convert.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_3 { +namespace implementation { + +using ::android::hardware::camera::device::V3_2::implementation::Camera3Stream; + +void convertToHidl(const Camera3Stream* src, HalStream* dst); + +void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst); + +} // namespace implementation +} // namespace V3_3 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_V3_3_DEFAULT_INCLUDE_CONVERT_H_ diff --git a/camera/device/3.3/types.hal b/camera/device/3.3/types.hal new file mode 100644 index 0000000000..b4ad702292 --- /dev/null +++ b/camera/device/3.3/types.hal @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera.device@3.3; + +import android.hardware.camera.device@3.2::DataspaceFlags; +import android.hardware.camera.device@3.2::HalStream; + +/** + * HalStream: + * + * The camera HAL's response to each requested stream configuration. + * + * This version extends the @3.2 HalStream with the overrideDataspace + * field + */ +struct HalStream { + /** + * The definition of HalStream from the prior version. + */ + @3.2::HalStream v3_2; + + /** + * An override dataSpace for the buffers in this stream. + * + * The HAL must respect the requested dataSpace in Stream unless it is + * IMPLEMENTATION_DEFINED, in which case the override dataSpace here must be + * used by the client instead, for this stream. This allows cross-platform + * HALs to use a specific dataSpace since IMPLEMENTATION_DEFINED formats often + * require device-specific information for correct selection. In all other cases, the + * overrideFormat must match the requested format. + */ + DataspaceFlags overrideDataSpace; +}; + +/** + * HalStreamConfiguration: + * + * Identical to @3.2::HalStreamConfiguration, except that it contains @3.3::HalStream entries. + * + */ +struct HalStreamConfiguration { + vec<HalStream> streams; +}; diff --git a/camera/device/README.md b/camera/device/README.md index 6e5703a578..9f607816d8 100644 --- a/camera/device/README.md +++ b/camera/device/README.md @@ -33,6 +33,8 @@ support for ICameraDevice@1.0 will be removed with the Android R release. This HAL interface version only allows support at the LEGACY level for the android.hardware.camera2 API. +Added in Android 8.0. + Subsidiary HALs: #### ICameraDevice1PreviewCallback.hal@1.0: @@ -62,6 +64,8 @@ The open() method actually opens the camera device for use, returning a Session interface for operating the active camera. It takes a Callback interface as an argument. +Added in Android 8.0. + Subsidiary HALs: #### ICameraDevice3Session.hal@3.2: @@ -74,3 +78,12 @@ capture requests to it. Callback interface for sending completed captures and other asynchronous events from tehe HAL to the client. + +### ICameraDevice.hal@3.3: + +A minor revision to the ICameraDevice.hal@3.2. + + - Adds support for overriding the output dataspace of a stream, which was + supported in the legacy camera HAL. + +Added in Android 8.1. diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp index f2a2d2e71e..c0b35912f7 100644 --- a/camera/provider/2.4/default/Android.bp +++ b/camera/provider/2.4/default/Android.bp @@ -11,8 +11,10 @@ cc_library_shared { "libcutils", "android.hardware.camera.device@1.0", "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", "camera.device@1.0-impl", "camera.device@3.2-impl", + "camera.device@3.3-impl", "android.hardware.camera.provider@2.4", "android.hardware.camera.common@1.0", "android.hardware.graphics.mapper@2.0", @@ -43,6 +45,7 @@ cc_binary { "libutils", "android.hardware.camera.device@1.0", "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", "android.hardware.camera.provider@2.4", "android.hardware.camera.common@1.0", ], diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp index 19f7bdd7b2..d50168a20b 100644 --- a/camera/provider/2.4/default/CameraProvider.cpp +++ b/camera/provider/2.4/default/CameraProvider.cpp @@ -15,11 +15,13 @@ */ #define LOG_TAG "CamProvider@2.4-impl" +//#define LOG_NDEBUG 0 #include <android/log.h> #include "CameraProvider.h" #include "CameraDevice_1_0.h" -#include "CameraDevice_3_2.h" +#include "CameraDevice_3_3.h" +#include <cutils/properties.h> #include <string.h> #include <utils/Trace.h> @@ -36,6 +38,7 @@ const char *kLegacyProviderName = "legacy/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 *kHAL1_0 = "1.0"; const int kMaxCameraDeviceNameLen = 128; const int kMaxCameraIdLen = 16; @@ -140,8 +143,9 @@ int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) { if (!match) { return -1; } - if (deviceVersion == kHAL3_2) { - // maybe switched to 3.4 or define the hidl version enum later + 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; @@ -158,10 +162,12 @@ std::string CameraProvider::getHidlDeviceName( deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 ) { return hidl_string(""); } - const char* versionStr = (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) ? kHAL1_0 : kHAL3_2; + bool isV1 = deviceVersion == CAMERA_DEVICE_API_VERSION_1_0; + int versionMajor = isV1 ? 1 : 3; + int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion; char deviceName[kMaxCameraDeviceNameLen]; - snprintf(deviceName, sizeof(deviceName), "device@%s/legacy/%s", - versionStr, cameraId.c_str()); + snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s", + versionMajor, versionMinor, cameraId.c_str()); return deviceName; } @@ -205,6 +211,19 @@ bool CameraProvider::initialize() { return true; } + mPreferredHal3MinorVersion = property_get_int32("ro.camera.wrapper.hal3TrebleMinorVersion", 3); + ALOGV("Preferred HAL 3 minor version is %d", mPreferredHal3MinorVersion); + switch(mPreferredHal3MinorVersion) { + case 2: + case 3: + // OK + break; + default: + ALOGW("Unknown minor camera device HAL version %d in property " + "'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3", mPreferredHal3MinorVersion); + mPreferredHal3MinorVersion = 3; + } + mNumberOfLegacyCameras = mModule->getNumberOfCameras(); for (int i = 0; i < mNumberOfLegacyCameras; i++) { struct camera_info info; @@ -461,23 +480,45 @@ Return<void> CameraProvider::getCameraDeviceInterface_V3_x( return Void(); } - sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> device = - new android::hardware::camera::device::V3_2::implementation::CameraDevice( + // Since some Treble HAL revisions can map to the same legacy HAL version(s), we default + // to the newest possible Treble HAL revision, but allow for override if needed via + // system property. + sp<android::hardware::camera::device::V3_2::ICameraDevice> device; + switch (mPreferredHal3MinorVersion) { + case 2: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.2 + ALOGV("Constructing v3.2 camera device"); + sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl = + new android::hardware::camera::device::V3_2::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); - - if (device == nullptr) { - ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str()); - _hidl_cb(Status::INTERNAL_ERROR, nullptr); - return Void(); - } - - if (device->isInitFailed()) { - ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); - device = nullptr; - _hidl_cb(Status::INTERNAL_ERROR, nullptr); - return Void(); + if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { + ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); + device = nullptr; + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + device = deviceImpl; + break; + } + case 3: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.3 + ALOGV("Constructing v3.3 camera device"); + sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl = + new android::hardware::camera::device::V3_3::implementation::CameraDevice( + mModule, cameraId, mCameraDeviceNames); + if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { + ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); + device = nullptr; + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + device = deviceImpl; + break; + } + default: + ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion); + device = nullptr; + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); } - _hidl_cb (Status::OK, device); return Void(); } diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h index 75971fa3a0..4980711bcf 100644 --- a/camera/provider/2.4/default/CameraProvider.h +++ b/camera/provider/2.4/default/CameraProvider.h @@ -82,6 +82,8 @@ private: // (cameraId string, hidl device name) pairs SortedVector<std::pair<std::string, std::string>> mCameraDeviceNames; + int mPreferredHal3MinorVersion; + // Must be queried before using any APIs. // APIs will only work when this returns true bool mInitFailed; @@ -91,13 +93,13 @@ private: bool setUpVendorTags(); int checkCameraVersion(int id, camera_info info); + // create HIDL device name from camera ID and legacy device version + std::string getHidlDeviceName(std::string cameraId, int deviceVersion); + // 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); - // create HIDL device name from camera ID and device version - static std::string getHidlDeviceName(std::string cameraId, int deviceVersion); - // convert conventional HAL status to HIDL Status static Status getHidlStatus(int); diff --git a/camera/provider/2.4/default/OWNERS b/camera/provider/2.4/default/OWNERS new file mode 100644 index 0000000000..18acfee145 --- /dev/null +++ b/camera/provider/2.4/default/OWNERS @@ -0,0 +1,6 @@ +cychen@google.com +epeev@google.com +etalvala@google.com +shuzhenwang@google.com +yinchiayeh@google.com +zhijunhe@google.com diff --git a/camera/provider/2.4/vts/OWNERS b/camera/provider/2.4/vts/OWNERS new file mode 100644 index 0000000000..003fe71fa8 --- /dev/null +++ b/camera/provider/2.4/vts/OWNERS @@ -0,0 +1,11 @@ +# Camera team +cychen@google.com +epeev@google.com +etalvala@google.com +shuzhenwang@google.com +yinchiayeh@google.com +zhijunhe@google.com + +# VTS team +yim@google.com +zhuoyao@google.com diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index 439fe3dd67..81d3de1566 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -16,30 +16,28 @@ cc_test { name: "VtsHalCameraProviderV2_4TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalCameraProviderV2_4TargetTest.cpp"], + + // TODO(b/64437680): Assume these are always available on the device. shared_libs: [ - "liblog", - "libhidlbase", - "libhidltransport", - "libcutils", - "libutils", - "android.hardware.camera.provider@2.4", - "android.hardware.camera.device@3.2", - "android.hardware.camera.device@1.0", - "libcamera_metadata", "libbinder", + "libcamera_metadata", + "libfmq", "libgui", "libui", - "libfmq", ], + + // Statically link to libs not guaranteed to be present on the device. static_libs: [ - "VtsHalHidlTargetTestBase", - "libgrallocusage", + "android.hardware.camera.common@1.0", "android.hardware.camera.common@1.0-helper", - ], - cflags: [ - "-O0", - "-g", + "android.hardware.camera.device@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.provider@2.4", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.mapper@2.0", + "libgrallocusage", ], } diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 6f04efc598..e4cf9af273 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -26,6 +26,7 @@ #include <android/hardware/camera/device/1.0/ICameraDevice.h> #include <android/hardware/camera/device/3.2/ICameraDevice.h> +#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h> #include <android/hardware/camera/provider/2.4/ICameraProvider.h> #include <android/hidl/manager/1.0/IServiceManager.h> #include <binder/MemoryHeapBase.h> @@ -43,6 +44,7 @@ #include <ui/GraphicBuffer.h> #include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> using ::android::hardware::Return; using ::android::hardware::Void; @@ -100,8 +102,8 @@ using ::android::hardware::kSynchronizedReadWrite; using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>; using ::android::hidl::manager::V1_0::IServiceManager; -const char kCameraPassthroughServiceName[] = "legacy/0"; -const char *kProviderFQName = "android.hardware.camera.provider@2.4::ICameraProvider"; +using namespace ::android::hardware::camera; + const uint32_t kMaxPreviewWidth = 1920; const uint32_t kMaxPreviewHeight = 1080; const uint32_t kMaxVideoWidth = 4096; @@ -126,8 +128,10 @@ struct AvailableZSLInputOutput { namespace { // "device@<version>/legacy/<id>" const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)"; + const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303; const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302; const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100; + const char *kHAL3_3 = "3.3"; const char *kHAL3_2 = "3.2"; const char *kHAL1_0 = "1.0"; @@ -160,8 +164,9 @@ namespace { return -1; } - if (version.compare(kHAL3_2) == 0) { - // maybe switched to 3.4 or define the hidl version enumlater + if (version.compare(kHAL3_3) == 0) { + return CAMERA_DEVICE_API_VERSION_3_3; + } else if (version.compare(kHAL3_2) == 0) { return CAMERA_DEVICE_API_VERSION_3_2; } else if (version.compare(kHAL1_0) == 0) { return CAMERA_DEVICE_API_VERSION_1_0; @@ -231,66 +236,26 @@ namespace { } // Test environment for camera -class CameraHidlEnvironment : public ::testing::Environment { -public: +class CameraHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: // get the test environment singleton static CameraHidlEnvironment* Instance() { static CameraHidlEnvironment* instance = new CameraHidlEnvironment; return instance; } - virtual void SetUp() override; - virtual void TearDown() override; + virtual void HidlSetUp() override { ALOGI("SetUp CameraHidlEnvironment"); } - std::unordered_map<std::string, sp<ICameraProvider> > mProviders; + virtual void HidlTearDown() override { ALOGI("TearDown CameraHidlEnvironment"); } -private: + virtual void registerTestServices() override { registerTestService<ICameraProvider>(); } + + private: CameraHidlEnvironment() {} GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment); }; -void CameraHidlEnvironment::SetUp() { - sp<IServiceManager> manager = IServiceManager::getService(); - ASSERT_NE(manager, nullptr); - - manager->listByInterface(kProviderFQName, - [this](const hidl_vec<hidl_string> ®istered) { - std::string name; - uint32_t id; - sp<ICameraProvider> provider = nullptr; - for (size_t i = 0; i < registered.size(); i++) { - ASSERT_TRUE(parseProviderName(registered[i], - &name /*out*/, &id /*out*/)); - provider = ICameraProvider::tryGetService(registered[i]); - ALOGI_IF(provider, "provider is not nullptr, %p", provider.get()); - if (nullptr != provider.get()) { - mProviders.emplace(name, provider); - } - } - }); - - std::string legacyName; - uint32_t legacyId; - ASSERT_TRUE(parseProviderName(kCameraPassthroughServiceName, - &legacyName /*out*/, &legacyId /*out*/)); - auto legacyIt = mProviders.find(legacyName); - //Add any legacy passthrough implementations - if (legacyIt == mProviders.end()) { - sp<ICameraProvider> provider = ICameraProvider::tryGetService( - kCameraPassthroughServiceName); - if (nullptr != provider.get()) { - mProviders.emplace(legacyName, provider); - } - } - - ASSERT_FALSE(mProviders.empty()); -} - -void CameraHidlEnvironment::TearDown() { - ALOGI("TearDown CameraHidlEnvironment"); -} - struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener { BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {} @@ -533,23 +498,32 @@ Return<Status> PreviewWindowCb::setTimestamp(int64_t timestamp) { // The main test class for camera HIDL HAL. class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: - virtual void SetUp() override {} - virtual void TearDown() override {} - - hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider); - - struct EmptyDeviceCb : public ICameraDeviceCallback { - virtual Return<void> processCaptureResult(const hidl_vec<CaptureResult>& /*results*/) override { - ALOGI("processCaptureResult callback"); - ADD_FAILURE(); // Empty callback should not reach here - return Void(); - } - - virtual Return<void> notify(const hidl_vec<NotifyMsg>& /*msgs*/) override { - ALOGI("notify callback"); - ADD_FAILURE(); // Empty callback should not reach here - return Void(); - } + virtual void SetUp() override { + string service_name = CameraHidlEnvironment::Instance()->getServiceName<ICameraProvider>(); + ALOGI("get service with name: %s", service_name.c_str()); + mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(service_name); + ASSERT_NE(mProvider, nullptr); + + uint32_t id; + ASSERT_TRUE(parseProviderName(service_name, &mProviderType, &id)); + } + virtual void TearDown() override {} + + hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider); + + struct EmptyDeviceCb : public ICameraDeviceCallback { + virtual Return<void> processCaptureResult( + const hidl_vec<CaptureResult>& /*results*/) override { + ALOGI("processCaptureResult callback"); + ADD_FAILURE(); // Empty callback should not reach here + return Void(); + } + + virtual Return<void> notify(const hidl_vec<NotifyMsg>& /*msgs*/) override { + ALOGI("notify callback"); + ADD_FAILURE(); // Empty callback should not reach here + return Void(); + } }; struct DeviceCb : public ICameraDeviceCallback { @@ -637,6 +611,7 @@ public: void openEmptyDeviceSession(const std::string &name, sp<ICameraProvider> provider, sp<ICameraDeviceSession> *session /*out*/, + sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/, camera_metadata_t **staticMeta /*out*/); void configurePreviewStream(const std::string &name, sp<ICameraProvider> provider, @@ -743,6 +718,11 @@ protected: // Holds camera registered buffers std::unordered_map<uint32_t, sp<::android::MemoryHeapBase> > mMemoryPool; + + // Camera provider service + sp<ICameraProvider> mProvider; + // Camera provider type. + std::string mProviderType; }; Return<void> CameraHidlTest::Camera1DeviceCb::notifyCallback( @@ -1044,59 +1024,45 @@ hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> p // Test if ICameraProvider::isTorchModeSupported returns Status::OK TEST_F(CameraHidlTest, isTorchModeSupported) { Return<void> ret; - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - ret = provider.second->isSetTorchModeSupported( - [&](auto status, bool support) { - ALOGI("isSetTorchModeSupported returns status:%d supported:%d", - (int)status, support); - ASSERT_EQ(Status::OK, status); - }); - ASSERT_TRUE(ret.isOk()); - } + ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) { + ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support); + ASSERT_EQ(Status::OK, status); + }); + ASSERT_TRUE(ret.isOk()); } // TODO: consider removing this test if getCameraDeviceNames() has the same coverage TEST_F(CameraHidlTest, getCameraIdList) { Return<void> ret; - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - ret = provider.second->getCameraIdList( - [&](auto status, const auto& idList) { - ALOGI("getCameraIdList returns status:%d", (int)status); - for (size_t i = 0; i < idList.size(); i++) { - ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str()); - } - ASSERT_EQ(Status::OK, status); - // This is true for internal camera provider. - // Not necessary hold for external cameras providers - ASSERT_GT(idList.size(), 0u); - }); - ASSERT_TRUE(ret.isOk()); - } + ret = mProvider->getCameraIdList([&](auto status, const auto& idList) { + ALOGI("getCameraIdList returns status:%d", (int)status); + for (size_t i = 0; i < idList.size(); i++) { + ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str()); + } + ASSERT_EQ(Status::OK, status); + // This is true for internal camera provider. + // Not necessary hold for external cameras providers + ASSERT_GT(idList.size(), 0u); + }); + ASSERT_TRUE(ret.isOk()); } // Test if ICameraProvider::getVendorTags returns Status::OK TEST_F(CameraHidlTest, getVendorTags) { Return<void> ret; - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - ret = provider.second->getVendorTags( - [&](auto status, const auto& vendorTagSecs) { - ALOGI("getVendorTags returns status:%d numSections %zu", - (int)status, vendorTagSecs.size()); - for (size_t i = 0; i < vendorTagSecs.size(); i++) { - ALOGI("Vendor tag section %zu name %s", - i, vendorTagSecs[i].sectionName.c_str()); - for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) { - const auto& tag = vendorTagSecs[i].tags[j]; - ALOGI("Vendor tag id %u name %s type %d", - tag.tagId, - tag.tagName.c_str(), - (int) tag.tagType); - } - } - ASSERT_EQ(Status::OK, status); - }); - ASSERT_TRUE(ret.isOk()); - } + ret = mProvider->getVendorTags([&](auto status, const auto& vendorTagSecs) { + ALOGI("getVendorTags returns status:%d numSections %zu", (int)status, vendorTagSecs.size()); + for (size_t i = 0; i < vendorTagSecs.size(); i++) { + ALOGI("Vendor tag section %zu name %s", i, vendorTagSecs[i].sectionName.c_str()); + for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) { + const auto& tag = vendorTagSecs[i].tags[j]; + ALOGI("Vendor tag id %u name %s type %d", tag.tagId, tag.tagName.c_str(), + (int)tag.tagType); + } + } + ASSERT_EQ(Status::OK, status); + }); + ASSERT_TRUE(ret.isOk()); } // Test if ICameraProvider::setCallback returns Status::OK @@ -1119,49 +1085,49 @@ TEST_F(CameraHidlTest, setCallback) { } }; sp<ProviderCb> cb = new ProviderCb; - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - auto status = provider.second->setCallback(cb); - ASSERT_TRUE(status.isOk()); - ASSERT_EQ(Status::OK, status); - // Reset callback since cb will go out of scope - status = provider.second->setCallback(nullptr); - ASSERT_TRUE(status.isOk()); - ASSERT_EQ(Status::OK, status); - } + auto status = mProvider->setCallback(cb); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(Status::OK, status); + status = mProvider->setCallback(nullptr); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(Status::OK, status); } // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device TEST_F(CameraHidlTest, getCameraDeviceInterface) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { Return<void> ret; - ret = provider.second->getCameraDeviceInterface_V3_x( - name, - [&](auto status, const auto& device3_2) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device3_x) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); - ASSERT_NE(device3_2, nullptr); + ASSERT_NE(device3_x, nullptr); }); ASSERT_TRUE(ret.isOk()); - } else if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { + } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { Return<void> ret; - ret = provider.second->getCameraDeviceInterface_V1_x( - name, - [&](auto status, const auto& device1) { - ALOGI("getCameraDeviceInterface_V1_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V1_x( + name, [&](auto status, const auto& device1) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device1, nullptr); }); ASSERT_TRUE(ret.isOk()); } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -1169,66 +1135,67 @@ TEST_F(CameraHidlTest, getCameraDeviceInterface) { // Verify that the device resource cost can be retrieved and the values are // sane. TEST_F(CameraHidlTest, getResourceCost) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; ALOGI("getResourceCost: Testing camera device %s", name.c_str()); Return<void> ret; - ret = provider.second->getCameraDeviceInterface_V3_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); - ret = device3_2->getResourceCost( - [&](auto status, const auto& resourceCost) { - ALOGI("getResourceCost returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ALOGI(" Resource cost is %d", resourceCost.resourceCost); - ASSERT_LE(resourceCost.resourceCost, 100u); - for (const auto& name : resourceCost.conflictingDevices) { - ALOGI(" Conflicting device: %s", name.c_str()); - } - }); + ret = device3_x->getResourceCost([&](auto status, const auto& resourceCost) { + ALOGI("getResourceCost returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ALOGI(" Resource cost is %d", resourceCost.resourceCost); + ASSERT_LE(resourceCost.resourceCost, 100u); + for (const auto& name : resourceCost.conflictingDevices) { + ALOGI(" Conflicting device: %s", name.c_str()); + } + }); ASSERT_TRUE(ret.isOk()); - } else { + } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; ALOGI("getResourceCost: Testing camera device %s", name.c_str()); Return<void> ret; - ret = provider.second->getCameraDeviceInterface_V1_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V1_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V1_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); device1 = device; }); ASSERT_TRUE(ret.isOk()); - ret = device1->getResourceCost( - [&](auto status, const auto& resourceCost) { - ALOGI("getResourceCost returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ALOGI(" Resource cost is %d", - resourceCost.resourceCost); - ASSERT_LE(resourceCost.resourceCost, 100u); - for (const auto& name : resourceCost.conflictingDevices) { - ALOGI(" Conflicting device: %s", name.c_str()); - } - }); + ret = device1->getResourceCost([&](auto status, const auto& resourceCost) { + ALOGI("getResourceCost returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ALOGI(" Resource cost is %d", resourceCost.resourceCost); + ASSERT_LE(resourceCost.resourceCost, 100u); + for (const auto& name : resourceCost.conflictingDevices) { + ALOGI(" Conflicting device: %s", name.c_str()); + } + }); ASSERT_TRUE(ret.isOk()); } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -1236,143 +1203,117 @@ TEST_F(CameraHidlTest, getResourceCost) { // Verify that the static camera info can be retrieved // successfully. TEST_F(CameraHidlTest, getCameraInfo) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - ALOGI("getCameraCharacteristics: Testing camera device %s", - name.c_str()); - Return<void> ret; - ret = provider.second->getCameraDeviceInterface_V1_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V1_x returns status:%d", - (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(device, nullptr); - device1 = device; - }); - ASSERT_TRUE(ret.isOk()); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = mProvider->getCameraDeviceInterface_V1_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device1 = device; + }); + ASSERT_TRUE(ret.isOk()); - ret = device1->getCameraInfo( - [&](auto status, const auto& info) { - ALOGI("getCameraInfo returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - switch(info.orientation) { - case 0: - case 90: - case 180: - case 270: - //Expected cases - ALOGI("camera orientation: %d", info.orientation); - break; - default: - FAIL() << "Unexpected camera orientation:" << info.orientation; - } - switch(info.facing) { - case CameraFacing::BACK: - case CameraFacing::FRONT: - case CameraFacing::EXTERNAL: - //Expected cases - ALOGI("camera facing: %d", info.facing); - break; - default: - FAIL() << "Unexpected camera facing:" << static_cast<uint32_t> ( - info.facing); - } - }); - ASSERT_TRUE(ret.isOk()); - } + ret = device1->getCameraInfo([&](auto status, const auto& info) { + ALOGI("getCameraInfo returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + switch (info.orientation) { + case 0: + case 90: + case 180: + case 270: + // Expected cases + ALOGI("camera orientation: %d", info.orientation); + break; + default: + FAIL() << "Unexpected camera orientation:" << info.orientation; + } + switch (info.facing) { + case CameraFacing::BACK: + case CameraFacing::FRONT: + case CameraFacing::EXTERNAL: + // Expected cases + ALOGI("camera facing: %d", info.facing); + break; + default: + FAIL() << "Unexpected camera facing:" << static_cast<uint32_t>(info.facing); + } + }); + ASSERT_TRUE(ret.isOk()); } } } // Check whether preview window can be configured TEST_F(CameraHidlTest, setPreviewWindow) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, - &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); - Return<void> ret; - ret = device1->close(); - ASSERT_TRUE(ret.isOk()); - } + Return<void> ret; + ret = device1->close(); + ASSERT_TRUE(ret.isOk()); } } } // Verify that setting preview window fails in case device is not open TEST_F(CameraHidlTest, setPreviewWindowInvalid) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - ALOGI("getCameraCharacteristics: Testing camera device %s", - name.c_str()); - Return<void> ret; - ret = provider.second->getCameraDeviceInterface_V1_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V1_x returns status:%d", - (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(device, nullptr); - device1 = device; - }); - ASSERT_TRUE(ret.isOk()); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = mProvider->getCameraDeviceInterface_V1_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device1 = device; + }); + ASSERT_TRUE(ret.isOk()); - Return<Status> returnStatus = device1->setPreviewWindow(nullptr); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus); - } + Return<Status> returnStatus = device1->setPreviewWindow(nullptr); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus); } } } // Start and stop preview checking whether it gets enabled in between. TEST_F(CameraHidlTest, startStopPreview) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, - &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); - startPreview(device1); + startPreview(device1); - Return<bool> returnBoolStatus = device1->previewEnabled(); - ASSERT_TRUE(returnBoolStatus.isOk()); - ASSERT_TRUE(returnBoolStatus); + Return<bool> returnBoolStatus = device1->previewEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_TRUE(returnBoolStatus); - stopPreviewAndClose(device1); - } + stopPreviewAndClose(device1); } } } @@ -1380,646 +1321,552 @@ TEST_F(CameraHidlTest, startStopPreview) { // Start preview without active preview window. Preview should start as soon // as a valid active window gets configured. TEST_F(CameraHidlTest, startStopPreviewDelayed) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); - Return<Status> returnStatus = device1->setPreviewWindow(nullptr); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + Return<Status> returnStatus = device1->setPreviewWindow(nullptr); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - startPreview(device1); + startPreview(device1); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); - //Preview should get enabled now - Return<bool> returnBoolStatus = device1->previewEnabled(); - ASSERT_TRUE(returnBoolStatus.isOk()); - ASSERT_TRUE(returnBoolStatus); + // Preview should get enabled now + Return<bool> returnBoolStatus = device1->previewEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_TRUE(returnBoolStatus); - stopPreviewAndClose(device1); - } + stopPreviewAndClose(device1); } } } // Verify that image capture behaves as expected along with preview callbacks. TEST_F(CameraHidlTest, takePicture) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - - { - std::unique_lock<std::mutex> l(mLock); - mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; - } - - enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, - device1); - startPreview(device1); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + + { + std::unique_lock<std::mutex> l(mLock); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + } - { - std::unique_lock<std::mutex> l(mLock); - waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); - } + enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); + startPreview(device1); - disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, - device1); - enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, - device1); + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); + } - { - std::unique_lock<std::mutex> l(mLock); - mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; - } + disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); + enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, device1); - Return<Status> returnStatus = device1->takePicture(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + { + std::unique_lock<std::mutex> l(mLock); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + } - { - std::unique_lock<std::mutex> l(mLock); - waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l); - } + Return<Status> returnStatus = device1->takePicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, - device1); - stopPreviewAndClose(device1); + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l); } + + disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, device1); + stopPreviewAndClose(device1); } } } // Image capture should fail in case preview didn't get enabled first. TEST_F(CameraHidlTest, takePictureFail) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); - Return<Status> returnStatus = device1->takePicture(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_NE(Status::OK, returnStatus); + Return<Status> returnStatus = device1->takePicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_NE(Status::OK, returnStatus); - Return<void> ret = device1->close(); - ASSERT_TRUE(ret.isOk()); - } + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); } } } // Verify that image capture can be cancelled. TEST_F(CameraHidlTest, cancelPicture) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - startPreview(device1); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + startPreview(device1); - Return<Status> returnStatus = device1->takePicture(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + Return<Status> returnStatus = device1->takePicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - returnStatus = device1->cancelPicture(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + returnStatus = device1->cancelPicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - stopPreviewAndClose(device1); - } + stopPreviewAndClose(device1); } } } // Image capture cancel is a no-op when image capture is not running. TEST_F(CameraHidlTest, cancelPictureNOP) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - startPreview(device1); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + startPreview(device1); - Return<Status> returnStatus = device1->cancelPicture(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + Return<Status> returnStatus = device1->cancelPicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - stopPreviewAndClose(device1); - } + stopPreviewAndClose(device1); } } } // Test basic video recording. TEST_F(CameraHidlTest, startStopRecording) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - - { - std::unique_lock<std::mutex> l(mLock); - mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; - } + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + + { + std::unique_lock<std::mutex> l(mLock); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + } - enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, - device1); - startPreview(device1); + enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); + startPreview(device1); - { - std::unique_lock<std::mutex> l(mLock); - waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); - mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; - mVideoBufferIndex = UINT32_MAX; - } + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + mVideoBufferIndex = UINT32_MAX; + } - disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, - device1); + disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); - bool videoMetaEnabled = false; - Return<Status> returnStatus = device1->storeMetaDataInBuffers( - true); - ASSERT_TRUE(returnStatus.isOk()); - // It is allowed for devices to not support this feature - ASSERT_TRUE((Status::OK == returnStatus) || + bool videoMetaEnabled = false; + Return<Status> returnStatus = device1->storeMetaDataInBuffers(true); + ASSERT_TRUE(returnStatus.isOk()); + // It is allowed for devices to not support this feature + ASSERT_TRUE((Status::OK == returnStatus) || (Status::OPERATION_NOT_SUPPORTED == returnStatus)); - if (Status::OK == returnStatus) { - videoMetaEnabled = true; - } + if (Status::OK == returnStatus) { + videoMetaEnabled = true; + } - enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, - device1); - Return<bool> returnBoolStatus = device1->recordingEnabled(); - ASSERT_TRUE(returnBoolStatus.isOk()); - ASSERT_FALSE(returnBoolStatus); + enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1); + Return<bool> returnBoolStatus = device1->recordingEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_FALSE(returnBoolStatus); - returnStatus = device1->startRecording(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + returnStatus = device1->startRecording(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - { - std::unique_lock<std::mutex> l(mLock); - waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l); - ASSERT_NE(UINT32_MAX, mVideoBufferIndex); - disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, - device1); - } - - returnBoolStatus = device1->recordingEnabled(); - ASSERT_TRUE(returnBoolStatus.isOk()); - ASSERT_TRUE(returnBoolStatus); + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l); + ASSERT_NE(UINT32_MAX, mVideoBufferIndex); + disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1); + } - Return<void> ret; - if (videoMetaEnabled) { - ret = device1->releaseRecordingFrameHandle(mVideoData, - mVideoBufferIndex, mVideoNativeHandle); - ASSERT_TRUE(ret.isOk()); - } else { - ret = device1->releaseRecordingFrame(mVideoData, - mVideoBufferIndex); - ASSERT_TRUE(ret.isOk()); - } + returnBoolStatus = device1->recordingEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_TRUE(returnBoolStatus); - ret = device1->stopRecording(); + Return<void> ret; + if (videoMetaEnabled) { + ret = device1->releaseRecordingFrameHandle(mVideoData, mVideoBufferIndex, + mVideoNativeHandle); + ASSERT_TRUE(ret.isOk()); + } else { + ret = device1->releaseRecordingFrame(mVideoData, mVideoBufferIndex); ASSERT_TRUE(ret.isOk()); - - stopPreviewAndClose(device1); } + + ret = device1->stopRecording(); + ASSERT_TRUE(ret.isOk()); + + stopPreviewAndClose(device1); } } } // It shouldn't be possible to start recording without enabling preview first. TEST_F(CameraHidlTest, startRecordingFail) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); - Return<bool> returnBoolStatus = device1->recordingEnabled(); - ASSERT_TRUE(returnBoolStatus.isOk()); - ASSERT_FALSE(returnBoolStatus); + Return<bool> returnBoolStatus = device1->recordingEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_FALSE(returnBoolStatus); - Return<Status> returnStatus = device1->startRecording(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_NE(Status::OK, returnStatus); + Return<Status> returnStatus = device1->startRecording(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_NE(Status::OK, returnStatus); - Return<void> ret = device1->close(); - ASSERT_TRUE(ret.isOk()); - } + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); } } } // Check autofocus support if available. TEST_F(CameraHidlTest, autoFocus) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<const char *> focusModes = {CameraParameters::FOCUS_MODE_AUTO, - CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE, - CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO}; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<const char*> focusModes = {CameraParameters::FOCUS_MODE_AUTO, + CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE, + CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO}; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + if (Status::OK != + isAutoFocusModeAvailable(cameraParams, CameraParameters::FOCUS_MODE_AUTO)) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } - CameraParameters cameraParams; - getParameters(device1, &cameraParams /*out*/); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + startPreview(device1); + enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); - if (Status::OK != isAutoFocusModeAvailable(cameraParams, - CameraParameters::FOCUS_MODE_AUTO)) { - Return<void> ret = device1->close(); - ASSERT_TRUE(ret.isOk()); + for (auto& iter : focusModes) { + if (Status::OK != isAutoFocusModeAvailable(cameraParams, iter)) { continue; } - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - startPreview(device1); - enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); - - for (auto &iter : focusModes) { - if (Status::OK != isAutoFocusModeAvailable(cameraParams, - iter)) { - continue; - } + cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter); + setParameters(device1, cameraParams); + { + std::unique_lock<std::mutex> l(mLock); + mNotifyMessage = NotifyCallbackMsg::ERROR; + } - cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter); - setParameters(device1, cameraParams); - { - std::unique_lock<std::mutex> l(mLock); - mNotifyMessage = NotifyCallbackMsg::ERROR; - } + Return<Status> returnStatus = device1->autoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - Return<Status> returnStatus = device1->autoFocus(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); - - { - std::unique_lock<std::mutex> l(mLock); - while (NotifyCallbackMsg::FOCUS != mNotifyMessage) { - auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kAutoFocusTimeoutSec); - ASSERT_NE(std::cv_status::timeout, - mResultCondition.wait_until(l, timeout)); - } + { + std::unique_lock<std::mutex> l(mLock); + while (NotifyCallbackMsg::FOCUS != mNotifyMessage) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kAutoFocusTimeoutSec); + ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout)); } } - - disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); - stopPreviewAndClose(device1); } + + disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); + stopPreviewAndClose(device1); } } } // In case autofocus is supported verify that it can be cancelled. TEST_F(CameraHidlTest, cancelAutoFocus) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); - CameraParameters cameraParams; - getParameters(device1, &cameraParams /*out*/); + CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); - if (Status::OK != isAutoFocusModeAvailable(cameraParams, - CameraParameters::FOCUS_MODE_AUTO)) { - Return<void> ret = device1->close(); - ASSERT_TRUE(ret.isOk()); - continue; - } + if (Status::OK != + isAutoFocusModeAvailable(cameraParams, CameraParameters::FOCUS_MODE_AUTO)) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } - // It should be fine to call before preview starts. - ASSERT_EQ(Status::OK, device1->cancelAutoFocus()); + // It should be fine to call before preview starts. + ASSERT_EQ(Status::OK, device1->cancelAutoFocus()); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - startPreview(device1); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + startPreview(device1); - // It should be fine to call after preview starts too. - Return<Status> returnStatus = device1->cancelAutoFocus(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + // It should be fine to call after preview starts too. + Return<Status> returnStatus = device1->cancelAutoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - returnStatus = device1->autoFocus(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + returnStatus = device1->autoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - returnStatus = device1->cancelAutoFocus(); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + returnStatus = device1->cancelAutoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - stopPreviewAndClose(device1); - } + stopPreviewAndClose(device1); } } } // Check whether face detection is available and try to enable&disable. TEST_F(CameraHidlTest, sendCommandFaceDetection) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); - CameraParameters cameraParams; - getParameters(device1, &cameraParams /*out*/); + CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); - int32_t hwFaces = cameraParams.getInt( - CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW); - int32_t swFaces = cameraParams.getInt( - CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW); - if ((0 >= hwFaces) && (0 >= swFaces)) { - Return<void> ret = device1->close(); - ASSERT_TRUE(ret.isOk()); - continue; - } + int32_t hwFaces = cameraParams.getInt(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW); + int32_t swFaces = cameraParams.getInt(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW); + if ((0 >= hwFaces) && (0 >= swFaces)) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - startPreview(device1); - - if (0 < hwFaces) { - Return<Status> returnStatus = device1->sendCommand( - CommandType::START_FACE_DETECTION, - CAMERA_FACE_DETECTION_HW, 0); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); - // TODO(epeev) : Enable and check for face notifications - returnStatus = device1->sendCommand( - CommandType::STOP_FACE_DETECTION, - CAMERA_FACE_DETECTION_HW, 0); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); - } + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + startPreview(device1); - if (0 < swFaces) { - Return<Status> returnStatus = device1->sendCommand( - CommandType::START_FACE_DETECTION, - CAMERA_FACE_DETECTION_SW, 0); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); - // TODO(epeev) : Enable and check for face notifications - returnStatus = device1->sendCommand( - CommandType::STOP_FACE_DETECTION, - CAMERA_FACE_DETECTION_SW, 0); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); - } + if (0 < hwFaces) { + Return<Status> returnStatus = device1->sendCommand( + CommandType::START_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + // TODO(epeev) : Enable and check for face notifications + returnStatus = device1->sendCommand(CommandType::STOP_FACE_DETECTION, + CAMERA_FACE_DETECTION_HW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + } - stopPreviewAndClose(device1); + if (0 < swFaces) { + Return<Status> returnStatus = device1->sendCommand( + CommandType::START_FACE_DETECTION, CAMERA_FACE_DETECTION_SW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + // TODO(epeev) : Enable and check for face notifications + returnStatus = device1->sendCommand(CommandType::STOP_FACE_DETECTION, + CAMERA_FACE_DETECTION_SW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); } + + stopPreviewAndClose(device1); } } } // Check whether smooth zoom is available and try to enable&disable. TEST_F(CameraHidlTest, sendCommandSmoothZoom) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); - - CameraParameters cameraParams; - getParameters(device1, &cameraParams /*out*/); - - const char *smoothZoomStr = cameraParams.get( - CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED); - bool smoothZoomSupported = ((nullptr != smoothZoomStr) && - (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ? - true : false; - if (!smoothZoomSupported) { - Return<void> ret = device1->close(); - ASSERT_TRUE(ret.isOk()); - continue; - } + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + const char* smoothZoomStr = + cameraParams.get(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED); + bool smoothZoomSupported = + ((nullptr != smoothZoomStr) && (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) + ? true + : false; + if (!smoothZoomSupported) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } - int32_t maxZoom = cameraParams.getInt( - CameraParameters::KEY_MAX_ZOOM); - ASSERT_TRUE(0 < maxZoom); + int32_t maxZoom = cameraParams.getInt(CameraParameters::KEY_MAX_ZOOM); + ASSERT_TRUE(0 < maxZoom); - sp<BufferItemConsumer> bufferItemConsumer; - sp<BufferItemHander> bufferHandler; - setupPreviewWindow(device1, &bufferItemConsumer /*out*/, - &bufferHandler /*out*/); - startPreview(device1); - setParameters(device1, cameraParams); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + startPreview(device1); + setParameters(device1, cameraParams); - Return<Status> returnStatus = device1->sendCommand( - CommandType::START_SMOOTH_ZOOM, maxZoom, 0); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); - // TODO(epeev) : Enable and check for face notifications - returnStatus = device1->sendCommand( - CommandType::STOP_SMOOTH_ZOOM, 0, 0); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + Return<Status> returnStatus = + device1->sendCommand(CommandType::START_SMOOTH_ZOOM, maxZoom, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + // TODO(epeev) : Enable and check for face notifications + returnStatus = device1->sendCommand(CommandType::STOP_SMOOTH_ZOOM, 0, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - stopPreviewAndClose(device1); - } + stopPreviewAndClose(device1); } } } // Basic sanity tests related to camera parameters. TEST_F(CameraHidlTest, getSetParameters) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { - sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); - ASSERT_NE(nullptr, device1.get()); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name, mProviderType) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, mProvider, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + int32_t width, height; + cameraParams.getPictureSize(&width, &height); + ASSERT_TRUE((0 < width) && (0 < height)); + cameraParams.getPreviewSize(&width, &height); + ASSERT_TRUE((0 < width) && (0 < height)); + int32_t minFps, maxFps; + cameraParams.getPreviewFpsRange(&minFps, &maxFps); + ASSERT_TRUE((0 < minFps) && (0 < maxFps)); + ASSERT_NE(nullptr, cameraParams.getPreviewFormat()); + ASSERT_NE(nullptr, cameraParams.getPictureFormat()); + ASSERT_TRUE( + strcmp(CameraParameters::PIXEL_FORMAT_JPEG, cameraParams.getPictureFormat()) == 0); + + const char* flashMode = cameraParams.get(CameraParameters::KEY_FLASH_MODE); + ASSERT_TRUE((nullptr == flashMode) || + (strcmp(CameraParameters::FLASH_MODE_OFF, flashMode) == 0)); + + const char* wbMode = cameraParams.get(CameraParameters::KEY_WHITE_BALANCE); + ASSERT_TRUE((nullptr == wbMode) || + (strcmp(CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0)); + + const char* effect = cameraParams.get(CameraParameters::KEY_EFFECT); + ASSERT_TRUE((nullptr == effect) || + (strcmp(CameraParameters::EFFECT_NONE, effect) == 0)); + + ::android::Vector<Size> previewSizes; + cameraParams.getSupportedPreviewSizes(previewSizes); + ASSERT_FALSE(previewSizes.empty()); + ::android::Vector<Size> pictureSizes; + cameraParams.getSupportedPictureSizes(pictureSizes); + ASSERT_FALSE(pictureSizes.empty()); + const char* previewFormats = + cameraParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); + ASSERT_NE(nullptr, previewFormats); + ::android::String8 previewFormatsString(previewFormats); + ASSERT_TRUE(previewFormatsString.contains(CameraParameters::PIXEL_FORMAT_YUV420SP)); + ASSERT_NE(nullptr, cameraParams.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); + ASSERT_NE(nullptr, + cameraParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); + const char* focusModes = cameraParams.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES); + ASSERT_NE(nullptr, focusModes); + ::android::String8 focusModesString(focusModes); + const char* focusMode = cameraParams.get(CameraParameters::KEY_FOCUS_MODE); + ASSERT_NE(nullptr, focusMode); + // Auto focus mode should be default + if (focusModesString.contains(CameraParameters::FOCUS_MODE_AUTO)) { + ASSERT_TRUE(strcmp(CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0); + } + ASSERT_TRUE(0 < cameraParams.getInt(CameraParameters::KEY_FOCAL_LENGTH)); + int32_t horizontalViewAngle = + cameraParams.getInt(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE); + ASSERT_TRUE((0 < horizontalViewAngle) && (360 >= horizontalViewAngle)); + int32_t verticalViewAngle = + cameraParams.getInt(CameraParameters::KEY_VERTICAL_VIEW_ANGLE); + ASSERT_TRUE((0 < verticalViewAngle) && (360 >= verticalViewAngle)); + int32_t jpegQuality = cameraParams.getInt(CameraParameters::KEY_JPEG_QUALITY); + ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality)); + int32_t jpegThumbQuality = + cameraParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + ASSERT_TRUE((1 <= jpegThumbQuality) && (100 >= jpegThumbQuality)); - CameraParameters cameraParams; - getParameters(device1, &cameraParams /*out*/); - - int32_t width, height; - cameraParams.getPictureSize(&width, &height); - ASSERT_TRUE((0 < width) && (0 < height)); - cameraParams.getPreviewSize(&width, &height); - ASSERT_TRUE((0 < width) && (0 < height)); - int32_t minFps, maxFps; - cameraParams.getPreviewFpsRange(&minFps, &maxFps); - ASSERT_TRUE((0 < minFps) && (0 < maxFps)); - ASSERT_NE(nullptr, cameraParams.getPreviewFormat()); - ASSERT_NE(nullptr, cameraParams.getPictureFormat()); - ASSERT_TRUE(strcmp(CameraParameters::PIXEL_FORMAT_JPEG, - cameraParams.getPictureFormat()) == 0); - - const char *flashMode = cameraParams.get( - CameraParameters::KEY_FLASH_MODE); - ASSERT_TRUE((nullptr == flashMode) || (strcmp( - CameraParameters::FLASH_MODE_OFF, flashMode) == 0)); - - const char *wbMode = cameraParams.get( - CameraParameters::KEY_WHITE_BALANCE); - ASSERT_TRUE((nullptr == wbMode) || (strcmp( - CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0)); - - const char *effect = cameraParams.get( - CameraParameters::KEY_EFFECT); - ASSERT_TRUE((nullptr == effect) || (strcmp( - CameraParameters::EFFECT_NONE, effect) == 0)); - - ::android::Vector<Size> previewSizes; - cameraParams.getSupportedPreviewSizes(previewSizes); - ASSERT_FALSE(previewSizes.empty()); - ::android::Vector<Size> pictureSizes; - cameraParams.getSupportedPictureSizes(pictureSizes); - ASSERT_FALSE(pictureSizes.empty()); - const char *previewFormats = cameraParams.get( - CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); - ASSERT_NE(nullptr, previewFormats); - ::android::String8 previewFormatsString(previewFormats); - ASSERT_TRUE(previewFormatsString.contains( - CameraParameters::PIXEL_FORMAT_YUV420SP)); - ASSERT_NE(nullptr, cameraParams.get( - CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); - ASSERT_NE(nullptr, cameraParams.get( - CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); - const char *focusModes = cameraParams.get( - CameraParameters::KEY_SUPPORTED_FOCUS_MODES); - ASSERT_NE(nullptr, focusModes); - ::android::String8 focusModesString(focusModes); - const char *focusMode = cameraParams.get( - CameraParameters::KEY_FOCUS_MODE); - ASSERT_NE(nullptr, focusMode); - // Auto focus mode should be default - if (focusModesString.contains( - CameraParameters::FOCUS_MODE_AUTO)) { - ASSERT_TRUE(strcmp( - CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0); - } - ASSERT_TRUE(0 < cameraParams.getInt( - CameraParameters::KEY_FOCAL_LENGTH)); - int32_t horizontalViewAngle = cameraParams.getInt( - CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE); - ASSERT_TRUE((0 < horizontalViewAngle) && - (360 >= horizontalViewAngle)); - int32_t verticalViewAngle = cameraParams.getInt( - CameraParameters::KEY_VERTICAL_VIEW_ANGLE); - ASSERT_TRUE((0 < verticalViewAngle) && - (360 >= verticalViewAngle)); - int32_t jpegQuality = cameraParams.getInt( - CameraParameters::KEY_JPEG_QUALITY); - ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality)); - int32_t jpegThumbQuality = cameraParams.getInt( - CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); - ASSERT_TRUE((1 <= jpegThumbQuality) && - (100 >= jpegThumbQuality)); - - cameraParams.setPictureSize(pictureSizes[0].width, - pictureSizes[0].height); - cameraParams.setPreviewSize(previewSizes[0].width, - previewSizes[0].height); + cameraParams.setPictureSize(pictureSizes[0].width, pictureSizes[0].height); + cameraParams.setPreviewSize(previewSizes[0].width, previewSizes[0].height); - setParameters(device1, cameraParams); - getParameters(device1, &cameraParams /*out*/); + setParameters(device1, cameraParams); + getParameters(device1, &cameraParams /*out*/); - cameraParams.getPictureSize(&width, &height); - ASSERT_TRUE((pictureSizes[0].width == width) && - (pictureSizes[0].height == height)); - cameraParams.getPreviewSize(&width, &height); - ASSERT_TRUE((previewSizes[0].width == width) && - (previewSizes[0].height == height)); + cameraParams.getPictureSize(&width, &height); + ASSERT_TRUE((pictureSizes[0].width == width) && (pictureSizes[0].height == height)); + cameraParams.getPreviewSize(&width, &height); + ASSERT_TRUE((previewSizes[0].width == width) && (previewSizes[0].height == height)); - Return<void> ret = device1->close(); - ASSERT_TRUE(ret.isOk()); - } + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); } } } @@ -2027,50 +1874,50 @@ TEST_F(CameraHidlTest, getSetParameters) { // Verify that the static camera characteristics can be retrieved // successfully. TEST_F(CameraHidlTest, getCameraCharacteristics) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; - ALOGI("getCameraCharacteristics: Testing camera device %s", - name.c_str()); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; + ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); Return<void> ret; - ret = provider.second->getCameraDeviceInterface_V3_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); - ret = device3_2->getCameraCharacteristics( - [&](auto status, const auto& chars) { - ALOGI("getCameraCharacteristics returns status:%d", - (int)status); - ASSERT_EQ(Status::OK, status); - const camera_metadata_t* metadata = - (camera_metadata_t*) chars.data(); - size_t expectedSize = chars.size(); - int result = validate_camera_metadata_structure( - metadata, &expectedSize); - ASSERT_TRUE((result == 0) || - (result == CAMERA_METADATA_VALIDATION_SHIFTED)); - size_t entryCount = get_camera_metadata_entry_count( - metadata); - // TODO: we can do better than 0 here. Need to check how many required - // characteristics keys we've defined. - ASSERT_GT(entryCount, 0u); - ALOGI("getCameraCharacteristics metadata entry count is %zu", - entryCount); - }); + ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) { + ALOGI("getCameraCharacteristics returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); + size_t expectedSize = chars.size(); + int result = validate_camera_metadata_structure(metadata, &expectedSize); + ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED)); + size_t entryCount = get_camera_metadata_entry_count(metadata); + // TODO: we can do better than 0 here. Need to check how many required + // characteristics keys we've defined. + ASSERT_GT(entryCount, 0u); + ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount); + }); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -2078,44 +1925,39 @@ TEST_F(CameraHidlTest, getCameraCharacteristics) { //In case it is supported verify that torch can be enabled. //Check for corresponding toch callbacks as well. TEST_F(CameraHidlTest, setTorchMode) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - bool torchControlSupported = false; - Return<void> ret; - - ret = provider.second->isSetTorchModeSupported( - [&](auto status, bool support) { - ALOGI("isSetTorchModeSupported returns status:%d supported:%d", - (int)status, support); - ASSERT_EQ(Status::OK, status); - torchControlSupported = support; - }); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + bool torchControlSupported = false; + Return<void> ret; + ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) { + ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support); + ASSERT_EQ(Status::OK, status); + torchControlSupported = support; + }); - sp<TorchProviderCb> cb = new TorchProviderCb(this); - Return<Status> returnStatus = provider.second->setCallback(cb); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); + sp<TorchProviderCb> cb = new TorchProviderCb(this); + Return<Status> returnStatus = mProvider->setCallback(cb); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; ALOGI("setTorchMode: Testing camera device %s", name.c_str()); - ret = provider.second->getCameraDeviceInterface_V3_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); mTorchStatus = TorchModeStatus::NOT_AVAILABLE; - returnStatus = device3_2->setTorchMode(TorchMode::ON); + returnStatus = device3_x->setTorchMode(TorchMode::ON); ASSERT_TRUE(returnStatus.isOk()); if (!torchControlSupported) { ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus); @@ -2127,16 +1969,14 @@ TEST_F(CameraHidlTest, setTorchMode) { std::unique_lock<std::mutex> l(mTorchLock); while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kTorchTimeoutSec); - ASSERT_NE(std::cv_status::timeout, - mTorchCond.wait_until(l, timeout)); + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, timeout)); } - ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, - mTorchStatus); + ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus); mTorchStatus = TorchModeStatus::NOT_AVAILABLE; } - returnStatus = device3_2->setTorchMode(TorchMode::OFF); + returnStatus = device3_x->setTorchMode(TorchMode::OFF); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); @@ -2144,24 +1984,21 @@ TEST_F(CameraHidlTest, setTorchMode) { std::unique_lock<std::mutex> l(mTorchLock); while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kTorchTimeoutSec); - ASSERT_NE(std::cv_status::timeout, - mTorchCond.wait_until(l, timeout)); + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, timeout)); } - ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, - mTorchStatus); + ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus); } } } - } else if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { + } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; ALOGI("dumpState: Testing camera device %s", name.c_str()); - ret = provider.second->getCameraDeviceInterface_V1_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V1_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V1_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); device1 = device; @@ -2181,12 +2018,11 @@ TEST_F(CameraHidlTest, setTorchMode) { std::unique_lock<std::mutex> l(mTorchLock); while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kTorchTimeoutSec); - ASSERT_NE(std::cv_status::timeout, - mTorchCond.wait_until(l, timeout)); + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, + timeout)); } - ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, - mTorchStatus); + ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus); mTorchStatus = TorchModeStatus::NOT_AVAILABLE; } @@ -2198,46 +2034,49 @@ TEST_F(CameraHidlTest, setTorchMode) { std::unique_lock<std::mutex> l(mTorchLock); while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kTorchTimeoutSec); - ASSERT_NE(std::cv_status::timeout, - mTorchCond.wait_until(l, timeout)); + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, + timeout)); } - ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, - mTorchStatus); + ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus); } } } ret = device1->close(); ASSERT_TRUE(ret.isOk()); } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } - - returnStatus = provider.second->setCallback(nullptr); - ASSERT_TRUE(returnStatus.isOk()); - ASSERT_EQ(Status::OK, returnStatus); } + + returnStatus = mProvider->setCallback(nullptr); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); } // Check dump functionality. TEST_F(CameraHidlTest, dumpState) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - Return<void> ret; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - ::android::sp<ICameraDevice> device3_2; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + Return<void> ret; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + ::android::sp<ICameraDevice> device3_x; ALOGI("dumpState: Testing camera device %s", name.c_str()); - ret = provider.second->getCameraDeviceInterface_V3_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); @@ -2245,19 +2084,18 @@ TEST_F(CameraHidlTest, dumpState) { raw_handle->data[0] = open(kDumpOutput, O_RDWR); ASSERT_GE(raw_handle->data[0], 0); hidl_handle handle = raw_handle; - ret= device3_2->dumpState(handle); + ret = device3_x->dumpState(handle); ASSERT_TRUE(ret.isOk()); close(raw_handle->data[0]); native_handle_delete(raw_handle); - } else if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { + } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; ALOGI("dumpState: Testing camera device %s", name.c_str()); - ret = provider.second->getCameraDeviceInterface_V1_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V1_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V1_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); device1 = device; @@ -2274,50 +2112,61 @@ TEST_F(CameraHidlTest, dumpState) { close(raw_handle->data[0]); native_handle_delete(raw_handle); } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } // Open, dumpStates, then close TEST_F(CameraHidlTest, openClose) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - Return<void> ret; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + Return<void> ret; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; ALOGI("openClose: Testing camera device %s", name.c_str()); - ret = provider.second->getCameraDeviceInterface_V3_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", - (int)status); + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); sp<EmptyDeviceCb> cb = new EmptyDeviceCb; sp<ICameraDeviceSession> session; - ret = device3_2->open( - cb, - [&](auto status, const auto& newSession) { - ALOGI("device::open returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(newSession, nullptr); - session = newSession; - }); + ret = device3_x->open(cb, [&](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + session = newSession; + }); ASSERT_TRUE(ret.isOk()); - + // Ensure that a device labeling itself as 3.3 can have its session interface cast + // to the 3.3 interface, and that lower versions can't be cast to it. + auto castResult = device::V3_3::ICameraDeviceSession::castFrom(session); + ASSERT_TRUE(castResult.isOk()); + sp<device::V3_3::ICameraDeviceSession> sessionV3_3 = castResult; + if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) { + ASSERT_TRUE(sessionV3_3.get() != nullptr); + } else { + ASSERT_TRUE(sessionV3_3.get() == nullptr); + } native_handle_t* raw_handle = native_handle_create(1, 0); raw_handle->data[0] = open(kDumpOutput, O_RDWR); ASSERT_GE(raw_handle->data[0], 0); hidl_handle handle = raw_handle; - ret = device3_2->dumpState(handle); + ret = device3_x->dumpState(handle); ASSERT_TRUE(ret.isOk()); close(raw_handle->data[0]); native_handle_delete(raw_handle); @@ -2326,10 +2175,11 @@ TEST_F(CameraHidlTest, openClose) { ASSERT_TRUE(ret.isOk()); // TODO: test all session API calls return INTERNAL_ERROR after close // TODO: keep a wp copy here and verify session cannot be promoted out of this scope - } else if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_1_0) { + } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; - openCameraDevice(name, provider.second, &device1 /*out*/); + openCameraDevice(name, mProvider, &device1 /*out*/); ASSERT_NE(nullptr, device1.get()); native_handle_t* raw_handle = native_handle_create(1, 0); @@ -2345,6 +2195,12 @@ TEST_F(CameraHidlTest, openClose) { ret = device1->close(); ASSERT_TRUE(ret.isOk()); } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -2352,124 +2208,140 @@ TEST_F(CameraHidlTest, openClose) { // Check whether all common default request settings can be sucessfully // constructed. TEST_F(CameraHidlTest, constructDefaultRequestSettings) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; Return<void> ret; - ALOGI("constructDefaultRequestSettings: Testing camera device %s", - name.c_str()); - ret = provider.second->getCameraDeviceInterface_V3_x( - name, - [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", - (int)status); + ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str()); + ret = mProvider->getCameraDeviceInterface_V3_x( + name, [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); sp<EmptyDeviceCb> cb = new EmptyDeviceCb; sp<ICameraDeviceSession> session; - ret = device3_2->open( - cb, - [&](auto status, const auto& newSession) { - ALOGI("device::open returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(newSession, nullptr); - session = newSession; - }); + ret = device3_x->open(cb, [&](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + session = newSession; + }); ASSERT_TRUE(ret.isOk()); - for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW; - t <= (uint32_t) RequestTemplate::MANUAL; t++) { - RequestTemplate reqTemplate = (RequestTemplate) t; - ret = session->constructDefaultRequestSettings( - reqTemplate, - [&](auto status, const auto& req) { - ALOGI("constructDefaultRequestSettings returns status:%d", - (int)status); - if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG || - reqTemplate == RequestTemplate::MANUAL) { - // optional templates - ASSERT_TRUE((status == Status::OK) || - (status == Status::ILLEGAL_ARGUMENT)); - } else { - ASSERT_EQ(Status::OK, status); - } - - if (status == Status::OK) { - const camera_metadata_t* metadata = - (camera_metadata_t*) req.data(); - size_t expectedSize = req.size(); - int result = validate_camera_metadata_structure( - metadata, &expectedSize); - ASSERT_TRUE((result == 0) || - (result == CAMERA_METADATA_VALIDATION_SHIFTED)); - size_t entryCount = - get_camera_metadata_entry_count(metadata); - // TODO: we can do better than 0 here. Need to check how many required - // request keys we've defined for each template - ASSERT_GT(entryCount, 0u); - ALOGI("template %u metadata entry count is %zu", - t, entryCount); - } else { - ASSERT_EQ(0u, req.size()); - } - }); + for (uint32_t t = (uint32_t)RequestTemplate::PREVIEW; + t <= (uint32_t)RequestTemplate::MANUAL; t++) { + RequestTemplate reqTemplate = (RequestTemplate)t; + ret = + session->constructDefaultRequestSettings( + reqTemplate, [&](auto status, const auto& req) { + ALOGI("constructDefaultRequestSettings returns status:%d", + (int)status); + if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG || + reqTemplate == RequestTemplate::MANUAL) { + // optional templates + ASSERT_TRUE((status == Status::OK) || + (status == Status::ILLEGAL_ARGUMENT)); + } else { + ASSERT_EQ(Status::OK, status); + } + + if (status == Status::OK) { + const camera_metadata_t* metadata = + (camera_metadata_t*) req.data(); + size_t expectedSize = req.size(); + int result = validate_camera_metadata_structure( + metadata, &expectedSize); + ASSERT_TRUE((result == 0) || + (result == CAMERA_METADATA_VALIDATION_SHIFTED)); + size_t entryCount = + get_camera_metadata_entry_count(metadata); + // TODO: we can do better than 0 here. Need to check how many required + // request keys we've defined for each template + ASSERT_GT(entryCount, 0u); + ALOGI("template %u metadata entry count is %zu", + t, entryCount); + } else { + ASSERT_EQ(0u, req.size()); + } + }); ASSERT_TRUE(ret.isOk()); } ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } + // Verify that all supported stream formats and sizes can be configured // successfully. TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputStreams; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - camera_metadata_t *staticMeta; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputStreams; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + camera_metadata_t* staticMeta; Return<void> ret; sp<ICameraDeviceSession> session; - openEmptyDeviceSession(name, provider.second, &session /*out*/, - &staticMeta /*out*/); + sp<device::V3_3::ICameraDeviceSession> session3_3; + openEmptyDeviceSession(name, mProvider, + &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/); outputStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - outputStreams)); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams)); ASSERT_NE(0u, outputStreams.size()); int32_t streamId = 0; - for (auto &it : outputStreams) { - Stream stream = {streamId, StreamType::OUTPUT, - static_cast<uint32_t> (it.width), - static_cast<uint32_t> (it.height), - static_cast<PixelFormat> (it.format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, - StreamRotation::ROTATION_0}; + for (auto& it : outputStreams) { + Stream stream = {streamId, + StreamType::OUTPUT, + static_cast<uint32_t>(it.width), + static_cast<uint32_t>(it.height), + static_cast<PixelFormat>(it.format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + 0, + StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec<Stream> streams = {stream}; - StreamConfiguration config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, [streamId] (Status s, - HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(1u, halConfig.streams.size()); - ASSERT_EQ(halConfig.streams[0].id, streamId); - }); + StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [streamId](Status s, HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].id, streamId); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId); + }); + } ASSERT_TRUE(ret.isOk()); streamId++; } @@ -2478,92 +2350,135 @@ TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } // Check for correct handling of invalid/incorrect configuration parameters. TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputStreams; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - camera_metadata_t *staticMeta; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputStreams; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + camera_metadata_t* staticMeta; Return<void> ret; sp<ICameraDeviceSession> session; - openEmptyDeviceSession(name, provider.second, &session /*out*/, - &staticMeta /*out*/); + sp<device::V3_3::ICameraDeviceSession> session3_3; + openEmptyDeviceSession(name, mProvider, + &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/); outputStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - outputStreams)); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams)); ASSERT_NE(0u, outputStreams.size()); int32_t streamId = 0; - Stream stream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (0), - static_cast<uint32_t> (0), - static_cast<PixelFormat> (outputStreams[0].format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, - StreamRotation::ROTATION_0}; + Stream stream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(0), + static_cast<uint32_t>(0), + static_cast<PixelFormat>(outputStreams[0].format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + 0, + StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec<Stream> streams = {stream}; - StreamConfiguration config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, [] (Status s, - HalStreamConfiguration) { - ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || - (Status::INTERNAL_ERROR == s)); - }); + StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE}; + if(session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); + } ASSERT_TRUE(ret.isOk()); - stream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (UINT32_MAX), - static_cast<uint32_t> (UINT32_MAX), - static_cast<PixelFormat> (outputStreams[0].format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, - StreamRotation::ROTATION_0}; + stream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(UINT32_MAX), + static_cast<uint32_t>(UINT32_MAX), + static_cast<PixelFormat>(outputStreams[0].format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + 0, + StreamRotation::ROTATION_0}; streams[0] = stream; - config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, [] (Status s, - HalStreamConfiguration) { - ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); - }); + config = {streams, StreamConfigurationMode::NORMAL_MODE}; + if(session3_3 == nullptr) { + ret = session->configureStreams(config, [](Status s, + HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else { + ret = session3_3->configureStreams_3_3(config, [](Status s, + device::V3_3::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } ASSERT_TRUE(ret.isOk()); - for (auto &it : outputStreams) { - stream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (it.width), - static_cast<uint32_t> (it.height), - static_cast<PixelFormat> (UINT32_MAX), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, - StreamRotation::ROTATION_0}; + for (auto& it : outputStreams) { + stream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(it.width), + static_cast<uint32_t>(it.height), + static_cast<PixelFormat>(UINT32_MAX), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + 0, + StreamRotation::ROTATION_0}; streams[0] = stream; - config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, [] (Status s, - HalStreamConfiguration) { - ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); - }); + config = {streams, StreamConfigurationMode::NORMAL_MODE}; + if(session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } ASSERT_TRUE(ret.isOk()); - stream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (it.width), - static_cast<uint32_t> (it.height), - static_cast<PixelFormat> (it.format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, - static_cast<StreamRotation> (UINT32_MAX)}; + stream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(it.width), + static_cast<uint32_t>(it.height), + static_cast<PixelFormat>(it.format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + 0, + static_cast<StreamRotation>(UINT32_MAX)}; streams[0] = stream; - config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, [] (Status s, - HalStreamConfiguration) { - ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); - }); + config = {streams, StreamConfigurationMode::NORMAL_MODE}; + if(session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } ASSERT_TRUE(ret.isOk()); } @@ -2571,6 +2486,16 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -2578,20 +2503,21 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { // Check whether all supported ZSL output stream combinations can be // configured successfully. TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> inputStreams; - std::vector<AvailableZSLInputOutput> inputOutputMap; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - camera_metadata_t *staticMeta; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> inputStreams; + std::vector<AvailableZSLInputOutput> inputOutputMap; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + camera_metadata_t* staticMeta; Return<void> ret; sp<ICameraDeviceSession> session; - openEmptyDeviceSession(name, provider.second, &session /*out*/, - &staticMeta /*out*/); + sp<device::V3_3::ICameraDeviceSession> session3_3; + openEmptyDeviceSession(name, mProvider, + &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/); Status rc = isZSLModeAvailable(staticMeta); if (Status::METHOD_NOT_SUPPORTED == rc) { @@ -2602,55 +2528,69 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { ASSERT_EQ(Status::OK, rc); inputStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - inputStreams)); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, inputStreams)); ASSERT_NE(0u, inputStreams.size()); inputOutputMap.clear(); - ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, - inputOutputMap)); + ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap)); ASSERT_NE(0u, inputOutputMap.size()); int32_t streamId = 0; - for (auto &inputIter : inputOutputMap) { + for (auto& inputIter : inputOutputMap) { AvailableStream input; - ASSERT_EQ(Status::OK, - findLargestSize(inputStreams, inputIter.inputFormat, input)); + ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat, + input)); ASSERT_NE(0u, inputStreams.size()); AvailableStream outputThreshold = {INT32_MAX, INT32_MAX, - inputIter.outputFormat}; + inputIter.outputFormat}; std::vector<AvailableStream> outputStreams; - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - outputStreams, &outputThreshold)); - for (auto &outputIter : outputStreams) { - Stream zslStream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (input.width), - static_cast<uint32_t> (input.height), - static_cast<PixelFormat> (input.format), - GRALLOC_USAGE_HW_CAMERA_ZSL, 0, - StreamRotation::ROTATION_0}; - Stream inputStream = {streamId++, StreamType::INPUT, - static_cast<uint32_t> (input.width), - static_cast<uint32_t> (input.height), - static_cast<PixelFormat> (input.format), 0, 0, - StreamRotation::ROTATION_0}; - Stream outputStream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (outputIter.width), - static_cast<uint32_t> (outputIter.height), - static_cast<PixelFormat> (outputIter.format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, - StreamRotation::ROTATION_0}; - - ::android::hardware::hidl_vec<Stream> streams = { - inputStream, zslStream, outputStream}; + ASSERT_EQ(Status::OK, + getAvailableOutputStreams(staticMeta, outputStreams, + &outputThreshold)); + for (auto& outputIter : outputStreams) { + Stream zslStream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(input.width), + static_cast<uint32_t>(input.height), + static_cast<PixelFormat>(input.format), + GRALLOC_USAGE_HW_CAMERA_ZSL, + 0, + StreamRotation::ROTATION_0}; + Stream inputStream = {streamId++, + StreamType::INPUT, + static_cast<uint32_t>(input.width), + static_cast<uint32_t>(input.height), + static_cast<PixelFormat>(input.format), + 0, + 0, + StreamRotation::ROTATION_0}; + Stream outputStream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(outputIter.width), + static_cast<uint32_t>(outputIter.height), + static_cast<PixelFormat>(outputIter.format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + 0, + StreamRotation::ROTATION_0}; + + ::android::hardware::hidl_vec<Stream> streams = {inputStream, zslStream, + outputStream}; StreamConfiguration config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, - [](Status s, HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(3u, halConfig.streams.size()); - }); + StreamConfigurationMode::NORMAL_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(3u, halConfig.streams.size()); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(3u, halConfig.streams.size()); + }); + } ASSERT_TRUE(ret.isOk()); } } @@ -2659,6 +2599,16 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -2666,59 +2616,73 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { // Verify that all supported preview + still capture stream combinations // can be configured successfully. TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputBlobStreams; - std::vector<AvailableStream> outputPreviewStreams; - AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, - static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; - AvailableStream blobThreshold = {INT32_MAX, INT32_MAX, - static_cast<int32_t>(PixelFormat::BLOB)}; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - camera_metadata_t *staticMeta; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputBlobStreams; + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + AvailableStream blobThreshold = {INT32_MAX, INT32_MAX, + static_cast<int32_t>(PixelFormat::BLOB)}; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + camera_metadata_t* staticMeta; Return<void> ret; sp<ICameraDeviceSession> session; - openEmptyDeviceSession(name, provider.second, &session /*out*/, - &staticMeta /*out*/); + sp<device::V3_3::ICameraDeviceSession> session3_3; + openEmptyDeviceSession(name, mProvider, + &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/); outputBlobStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - outputBlobStreams, &blobThreshold)); + ASSERT_EQ(Status::OK, + getAvailableOutputStreams(staticMeta, outputBlobStreams, + &blobThreshold)); ASSERT_NE(0u, outputBlobStreams.size()); outputPreviewStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - outputPreviewStreams, &previewThreshold)); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams, + &previewThreshold)); ASSERT_NE(0u, outputPreviewStreams.size()); int32_t streamId = 0; - for (auto &blobIter : outputBlobStreams) { - for (auto &previewIter : outputPreviewStreams) { - Stream previewStream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (previewIter.width), - static_cast<uint32_t> (previewIter.height), - static_cast<PixelFormat> (previewIter.format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, - StreamRotation::ROTATION_0}; - Stream blobStream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (blobIter.width), - static_cast<uint32_t> (blobIter.height), - static_cast<PixelFormat> (blobIter.format), - GRALLOC1_CONSUMER_USAGE_CPU_READ, 0, - StreamRotation::ROTATION_0}; - ::android::hardware::hidl_vec<Stream> streams = { - previewStream, blobStream}; + for (auto& blobIter : outputBlobStreams) { + for (auto& previewIter : outputPreviewStreams) { + Stream previewStream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(previewIter.width), + static_cast<uint32_t>(previewIter.height), + static_cast<PixelFormat>(previewIter.format), + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, + 0, + StreamRotation::ROTATION_0}; + Stream blobStream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(blobIter.width), + static_cast<uint32_t>(blobIter.height), + static_cast<PixelFormat>(blobIter.format), + GRALLOC1_CONSUMER_USAGE_CPU_READ, + 0, + StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = {previewStream, + blobStream}; StreamConfiguration config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, - [](Status s, HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(2u, halConfig.streams.size()); - }); + StreamConfigurationMode::NORMAL_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + } ASSERT_TRUE(ret.isOk()); } } @@ -2727,6 +2691,16 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -2735,18 +2709,19 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { // configured. Additionally check for common invalid inputs when // using this mode. TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - camera_metadata_t *staticMeta; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + camera_metadata_t* staticMeta; Return<void> ret; sp<ICameraDeviceSession> session; - openEmptyDeviceSession(name, provider.second, &session /*out*/, - &staticMeta /*out*/); + sp<device::V3_3::ICameraDeviceSession> session3_3; + openEmptyDeviceSession(name, mProvider, + &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/); Status rc = isConstrainedModeAvailable(staticMeta); if (Status::METHOD_NOT_SUPPORTED == rc) { @@ -2761,73 +2736,119 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { ASSERT_EQ(Status::OK, rc); int32_t streamId = 0; - Stream stream = {streamId, StreamType::OUTPUT, - static_cast<uint32_t> (hfrStream.width), - static_cast<uint32_t> (hfrStream.height), - static_cast<PixelFormat> (hfrStream.format), - GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, 0, - StreamRotation::ROTATION_0}; + Stream stream = {streamId, + StreamType::OUTPUT, + static_cast<uint32_t>(hfrStream.width), + static_cast<uint32_t>(hfrStream.height), + static_cast<PixelFormat>(hfrStream.format), + GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, + 0, + StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec<Stream> streams = {stream}; StreamConfiguration config = {streams, - StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; - ret = session->configureStreams(config, [streamId] (Status s, - HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(1u, halConfig.streams.size()); - ASSERT_EQ(halConfig.streams[0].id, streamId); - }); + StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [streamId](Status s, HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].id, streamId); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId); + }); + } ASSERT_TRUE(ret.isOk()); - stream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (0), - static_cast<uint32_t> (0), - static_cast<PixelFormat> (hfrStream.format), - GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, 0, - StreamRotation::ROTATION_0}; + stream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(0), + static_cast<uint32_t>(0), + static_cast<PixelFormat>(hfrStream.format), + GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, + 0, + StreamRotation::ROTATION_0}; streams[0] = stream; - config = {streams, - StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; - ret = session->configureStreams(config, [] (Status s, - HalStreamConfiguration) { - ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || - (Status::INTERNAL_ERROR == s)); - }); + config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); + } ASSERT_TRUE(ret.isOk()); - stream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (UINT32_MAX), - static_cast<uint32_t> (UINT32_MAX), - static_cast<PixelFormat> (hfrStream.format), - GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, 0, - StreamRotation::ROTATION_0}; + stream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(UINT32_MAX), + static_cast<uint32_t>(UINT32_MAX), + static_cast<PixelFormat>(hfrStream.format), + GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, + 0, + StreamRotation::ROTATION_0}; streams[0] = stream; - config = {streams, - StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; - ret = session->configureStreams(config, [] (Status s, - HalStreamConfiguration) { - ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); - }); + config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } ASSERT_TRUE(ret.isOk()); - stream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (hfrStream.width), - static_cast<uint32_t> (hfrStream.height), - static_cast<PixelFormat> (UINT32_MAX), - GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, 0, - StreamRotation::ROTATION_0}; + stream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(hfrStream.width), + static_cast<uint32_t>(hfrStream.height), + static_cast<PixelFormat>(UINT32_MAX), + GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, + 0, + StreamRotation::ROTATION_0}; streams[0] = stream; - config = {streams, - StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; - ret = session->configureStreams(config, [] (Status s, - HalStreamConfiguration) { - ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); - }); + config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } ASSERT_TRUE(ret.isOk()); free_camera_metadata(staticMeta); ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -2835,59 +2856,73 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { // Verify that all supported video + snapshot stream combinations can // be configured successfully. TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputBlobStreams; - std::vector<AvailableStream> outputVideoStreams; - AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight, - static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; - AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight, - static_cast<int32_t>(PixelFormat::BLOB)}; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { - camera_metadata_t *staticMeta; + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputBlobStreams; + std::vector<AvailableStream> outputVideoStreams; + AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight, + static_cast<int32_t>(PixelFormat::BLOB)}; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { + camera_metadata_t* staticMeta; Return<void> ret; sp<ICameraDeviceSession> session; - openEmptyDeviceSession(name, provider.second, &session /*out*/, - &staticMeta /*out*/); + sp<device::V3_3::ICameraDeviceSession> session3_3; + openEmptyDeviceSession(name, mProvider, + &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/); outputBlobStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - outputBlobStreams, &blobThreshold)); + ASSERT_EQ(Status::OK, + getAvailableOutputStreams(staticMeta, outputBlobStreams, + &blobThreshold)); ASSERT_NE(0u, outputBlobStreams.size()); outputVideoStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, - outputVideoStreams, &videoThreshold)); + ASSERT_EQ(Status::OK, + getAvailableOutputStreams(staticMeta, outputVideoStreams, + &videoThreshold)); ASSERT_NE(0u, outputVideoStreams.size()); int32_t streamId = 0; - for (auto &blobIter : outputBlobStreams) { - for (auto &videoIter : outputVideoStreams) { - Stream videoStream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (videoIter.width), - static_cast<uint32_t> (videoIter.height), - static_cast<PixelFormat> (videoIter.format), - GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, 0, - StreamRotation::ROTATION_0}; - Stream blobStream = {streamId++, StreamType::OUTPUT, - static_cast<uint32_t> (blobIter.width), - static_cast<uint32_t> (blobIter.height), - static_cast<PixelFormat> (blobIter.format), - GRALLOC1_CONSUMER_USAGE_CPU_READ, 0, - StreamRotation::ROTATION_0}; - ::android::hardware::hidl_vec<Stream> streams = { - videoStream, blobStream}; + for (auto& blobIter : outputBlobStreams) { + for (auto& videoIter : outputVideoStreams) { + Stream videoStream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(videoIter.width), + static_cast<uint32_t>(videoIter.height), + static_cast<PixelFormat>(videoIter.format), + GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, + 0, + StreamRotation::ROTATION_0}; + Stream blobStream = {streamId++, + StreamType::OUTPUT, + static_cast<uint32_t>(blobIter.width), + static_cast<uint32_t>(blobIter.height), + static_cast<PixelFormat>(blobIter.format), + GRALLOC1_CONSUMER_USAGE_CPU_READ, + 0, + StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = {videoStream, blobStream}; StreamConfiguration config = {streams, - StreamConfigurationMode::NORMAL_MODE}; - ret = session->configureStreams(config, - [](Status s, HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(2u, halConfig.streams.size()); - }); + StreamConfigurationMode::NORMAL_MODE}; + if (session3_3 == nullptr) { + ret = session->configureStreams(config, + [](Status s, HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [](Status s, device::V3_3::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + } ASSERT_TRUE(ret.isOk()); } } @@ -2896,76 +2931,89 @@ TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } // Generate and verify a camera capture request TEST_F(CameraHidlTest, processCaptureRequestPreview) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, - static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; - uint64_t bufferId = 1; - uint32_t frameNumber = 1; - ::android::hardware::hidl_vec<uint8_t> settings; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint64_t bufferId = 1; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; bool supportsPartialResults = false; uint32_t partialResultCount = 0; - configurePreviewStream(name, provider.second, &previewThreshold, - &session /*out*/, &previewStream /*out*/, - &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount/*out*/); + configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/, + &previewStream /*out*/, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, + &partialResultCount /*out*/); std::shared_ptr<ResultMetadataQueue> resultQueue; - auto resultQueueRet = session->getCaptureResultMetadataQueue( - [&resultQueue](const auto& descriptor) { - resultQueue = std::make_shared<ResultMetadataQueue>( - descriptor); - if (!resultQueue->isValid() || - resultQueue->availableToWrite() <= 0) { - ALOGE("%s: HAL returns empty result metadata fmq," - " not use it", __func__); - resultQueue = nullptr; - // Don't use the queue onwards. - } - }); + auto resultQueueRet = + session->getCaptureResultMetadataQueue( + [&resultQueue](const auto& descriptor) { + resultQueue = std::make_shared<ResultMetadataQueue>( + descriptor); + if (!resultQueue->isValid() || + resultQueue->availableToWrite() <= 0) { + ALOGE("%s: HAL returns empty result metadata fmq," + " not use it", __func__); + resultQueue = nullptr; + // Don't use the queue onwards. + } + }); ASSERT_TRUE(resultQueueRet.isOk()); InFlightRequest inflightReq = {1, false, supportsPartialResults, - partialResultCount, resultQueue}; + partialResultCount, resultQueue}; RequestTemplate reqTemplate = RequestTemplate::PREVIEW; Return<void> ret; ret = session->constructDefaultRequestSettings(reqTemplate, - [&](auto status, const auto& req) { - ASSERT_EQ(Status::OK, status); - settings = req; }); + [&](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + settings = req; + }); ASSERT_TRUE(ret.isOk()); sp<GraphicBuffer> gb = new GraphicBuffer( previewStream.width, previewStream.height, - static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), - 1, android_convertGralloc1To0Usage( - halStreamConfig.streams[0].producerUsage, - halStreamConfig.streams[0].consumerUsage)); + static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1, + android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage)); ASSERT_NE(nullptr, gb.get()); StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, - bufferId, hidl_handle(gb->getNativeBuffer()->handle), - BufferStatus::OK, nullptr, nullptr}; - ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = { - outputBuffer}; - StreamBuffer emptyInputBuffer = {-1, 0, nullptr, - BufferStatus::ERROR, nullptr, nullptr}; - CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, - settings, emptyInputBuffer, outputBuffers}; + bufferId, + hidl_handle(gb->getNativeBuffer()->handle), + BufferStatus::OK, + nullptr, + nullptr}; + ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer}; + StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, + nullptr}; + CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, + emptyInputBuffer, outputBuffers}; { std::unique_lock<std::mutex> l(mLock); @@ -2977,12 +3025,11 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { uint32_t numRequestProcessed = 0; hidl_vec<BufferCache> cachesToRemove; Return<void> returnStatus = session->processCaptureRequest( - {request}, - cachesToRemove, - [&status, &numRequestProcessed] (auto s, uint32_t n) { - status = s; - numRequestProcessed = n; - }); + {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, + uint32_t n) { + status = s; + numRequestProcessed = n; + }); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, status); ASSERT_EQ(numRequestProcessed, 1u); @@ -2990,39 +3037,37 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { { std::unique_lock<std::mutex> l(mLock); while (!inflightReq.errorCodeValid && - ((0 < inflightReq.numBuffersLeft) || - (!inflightReq.haveResultMetadata))) { + ((0 < inflightReq.numBuffersLeft) || + (!inflightReq.haveResultMetadata))) { auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kStreamBufferTimeoutSec); + std::chrono::seconds(kStreamBufferTimeoutSec); ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout)); } ASSERT_FALSE(inflightReq.errorCodeValid); ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u); - ASSERT_EQ(previewStream.id, - inflightReq.resultOutputBuffers[0].streamId); + ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId); request.frameNumber++; - //Empty settings should be supported after the first call - //for repeating requests. + // Empty settings should be supported after the first call + // for repeating requests. request.settings.setToExternal(nullptr, 0, true); // The buffer has been registered to HAL by bufferId, so per // API contract we should send a null handle for this buffer request.outputBuffers[0].buffer = nullptr; mInflightMap.clear(); - inflightReq = {1, false, supportsPartialResults, - partialResultCount, resultQueue}; + inflightReq = {1, false, supportsPartialResults, partialResultCount, + resultQueue}; mInflightMap.add(request.frameNumber, &inflightReq); } returnStatus = session->processCaptureRequest( - {request}, - cachesToRemove, - [&status, &numRequestProcessed] (auto s, uint32_t n) { - status = s; - numRequestProcessed = n; - }); + {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, + uint32_t n) { + status = s; + numRequestProcessed = n; + }); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, status); ASSERT_EQ(numRequestProcessed, 1u); @@ -3030,23 +3075,32 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { { std::unique_lock<std::mutex> l(mLock); while (!inflightReq.errorCodeValid && - ((0 < inflightReq.numBuffersLeft) || - (!inflightReq.haveResultMetadata))) { + ((0 < inflightReq.numBuffersLeft) || + (!inflightReq.haveResultMetadata))) { auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kStreamBufferTimeoutSec); + std::chrono::seconds(kStreamBufferTimeoutSec); ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout)); } ASSERT_FALSE(inflightReq.errorCodeValid); ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u); - ASSERT_EQ(previewStream.id, - inflightReq.resultOutputBuffers[0].streamId); + ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId); } ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -3054,57 +3108,57 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { // Test whether an incorrect capture request with missing settings will // be reported correctly. TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputPreviewStreams; - AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, - static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; - uint64_t bufferId = 1; - uint32_t frameNumber = 1; - ::android::hardware::hidl_vec<uint8_t> settings; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint64_t bufferId = 1; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; bool supportsPartialResults = false; uint32_t partialResultCount = 0; - configurePreviewStream(name, provider.second, &previewThreshold, - &session /*out*/, &previewStream /*out*/, - &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/, + &previewStream /*out*/, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, + &partialResultCount /*out*/); sp<GraphicBuffer> gb = new GraphicBuffer( previewStream.width, previewStream.height, - static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), - 1, android_convertGralloc1To0Usage( - halStreamConfig.streams[0].producerUsage, - halStreamConfig.streams[0].consumerUsage)); + static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1, + android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage)); StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, - bufferId, hidl_handle(gb->getNativeBuffer()->handle), - BufferStatus::OK, nullptr, nullptr}; - ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = { - outputBuffer}; - StreamBuffer emptyInputBuffer = {-1, 0, nullptr, - BufferStatus::ERROR, nullptr, nullptr}; + bufferId, + hidl_handle(gb->getNativeBuffer()->handle), + BufferStatus::OK, + nullptr, + nullptr}; + ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer}; + StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, + nullptr}; CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, - emptyInputBuffer, outputBuffers}; + emptyInputBuffer, outputBuffers}; - //Settings were not correctly initialized, we should fail here + // Settings were not correctly initialized, we should fail here Status status = Status::OK; uint32_t numRequestProcessed = 0; hidl_vec<BufferCache> cachesToRemove; Return<void> ret = session->processCaptureRequest( - {request}, - cachesToRemove, - [&status, &numRequestProcessed] (auto s, uint32_t n) { - status = s; - numRequestProcessed = n; - }); + {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, + uint32_t n) { + status = s; + numRequestProcessed = n; + }); ASSERT_TRUE(ret.isOk()); ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status); ASSERT_EQ(numRequestProcessed, 0u); @@ -3112,6 +3166,16 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -3119,53 +3183,53 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { // Check whether an invalid capture request with missing output buffers // will be reported correctly. TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputBlobStreams; - AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, - static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; - uint32_t frameNumber = 1; - ::android::hardware::hidl_vec<uint8_t> settings; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputBlobStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; bool supportsPartialResults = false; uint32_t partialResultCount = 0; - configurePreviewStream(name, provider.second, &previewThreshold, - &session /*out*/, &previewStream /*out*/, - &halStreamConfig /*out*/, &supportsPartialResults/*out*/, - &partialResultCount /*out*/); + configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/, + &previewStream /*out*/, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, + &partialResultCount /*out*/); RequestTemplate reqTemplate = RequestTemplate::PREVIEW; Return<void> ret; ret = session->constructDefaultRequestSettings(reqTemplate, - [&](auto status, const auto& req) { - ASSERT_EQ(Status::OK, status); - settings = req; }); + [&](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + settings = req; + }); ASSERT_TRUE(ret.isOk()); ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers; - StreamBuffer emptyInputBuffer = {-1, 0, nullptr, - BufferStatus::ERROR, nullptr, nullptr}; - CaptureRequest request = {frameNumber, 0/* fmqSettingsSize */, - settings, emptyInputBuffer, emptyOutputBuffers}; + StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, + nullptr}; + CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, + emptyInputBuffer, emptyOutputBuffers}; - //Output buffers are missing, we should fail here + // Output buffers are missing, we should fail here Status status = Status::OK; uint32_t numRequestProcessed = 0; hidl_vec<BufferCache> cachesToRemove; ret = session->processCaptureRequest( - {request}, - cachesToRemove, - [&status, &numRequestProcessed] (auto s, uint32_t n) { - status = s; - numRequestProcessed = n; - }); + {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, + uint32_t n) { + status = s; + numRequestProcessed = n; + }); ASSERT_TRUE(ret.isOk()); ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status); ASSERT_EQ(numRequestProcessed, 0u); @@ -3173,76 +3237,89 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) { ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } // Generate, trigger and flush a preview request TEST_F(CameraHidlTest, flushPreviewRequest) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputPreviewStreams; - AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, - static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; - uint64_t bufferId = 1; - uint32_t frameNumber = 1; - ::android::hardware::hidl_vec<uint8_t> settings; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint64_t bufferId = 1; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; bool supportsPartialResults = false; uint32_t partialResultCount = 0; - configurePreviewStream(name, provider.second, &previewThreshold, - &session /*out*/, &previewStream /*out*/, - &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/, + &previewStream /*out*/, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, + &partialResultCount /*out*/); std::shared_ptr<ResultMetadataQueue> resultQueue; - auto resultQueueRet = session->getCaptureResultMetadataQueue( - [&resultQueue](const auto& descriptor) { - resultQueue = std::make_shared<ResultMetadataQueue>( - descriptor); - if (!resultQueue->isValid() || - resultQueue->availableToWrite() <= 0) { - ALOGE("%s: HAL returns empty result metadata fmq," - " not use it", __func__); - resultQueue = nullptr; - // Don't use the queue onwards. - } - }); + auto resultQueueRet = + session->getCaptureResultMetadataQueue( + [&resultQueue](const auto& descriptor) { + resultQueue = std::make_shared<ResultMetadataQueue>( + descriptor); + if (!resultQueue->isValid() || + resultQueue->availableToWrite() <= 0) { + ALOGE("%s: HAL returns empty result metadata fmq," + " not use it", __func__); + resultQueue = nullptr; + // Don't use the queue onwards. + } + }); ASSERT_TRUE(resultQueueRet.isOk()); InFlightRequest inflightReq = {1, false, supportsPartialResults, - partialResultCount, resultQueue}; + partialResultCount, resultQueue}; RequestTemplate reqTemplate = RequestTemplate::PREVIEW; Return<void> ret; ret = session->constructDefaultRequestSettings(reqTemplate, - [&](auto status, const auto& req) { - ASSERT_EQ(Status::OK, status); - settings = req; }); + [&](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + settings = req; + }); ASSERT_TRUE(ret.isOk()); sp<GraphicBuffer> gb = new GraphicBuffer( previewStream.width, previewStream.height, - static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), - 1, android_convertGralloc1To0Usage( - halStreamConfig.streams[0].producerUsage, - halStreamConfig.streams[0].consumerUsage)); + static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1, + android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage)); ASSERT_NE(nullptr, gb.get()); StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, - bufferId, hidl_handle(gb->getNativeBuffer()->handle), - BufferStatus::OK, nullptr, nullptr}; - ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = { - outputBuffer}; + bufferId, + hidl_handle(gb->getNativeBuffer()->handle), + BufferStatus::OK, + nullptr, + nullptr}; + ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer}; const StreamBuffer emptyInputBuffer = {-1, 0, nullptr, - BufferStatus::ERROR, nullptr, nullptr}; - CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, - settings, emptyInputBuffer, outputBuffers}; + BufferStatus::ERROR, nullptr, nullptr}; + CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, + emptyInputBuffer, outputBuffers}; { std::unique_lock<std::mutex> l(mLock); @@ -3254,17 +3331,16 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { uint32_t numRequestProcessed = 0; hidl_vec<BufferCache> cachesToRemove; ret = session->processCaptureRequest( - {request}, - cachesToRemove, - [&status, &numRequestProcessed] (auto s, uint32_t n) { - status = s; - numRequestProcessed = n; - }); + {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, + uint32_t n) { + status = s; + numRequestProcessed = n; + }); ASSERT_TRUE(ret.isOk()); ASSERT_EQ(Status::OK, status); ASSERT_EQ(numRequestProcessed, 1u); - //Flush before waiting for request to complete. + // Flush before waiting for request to complete. Return<Status> returnStatus = session->flush(); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); @@ -3272,29 +3348,28 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { { std::unique_lock<std::mutex> l(mLock); while (!inflightReq.errorCodeValid && - ((0 < inflightReq.numBuffersLeft) || - (!inflightReq.haveResultMetadata))) { + ((0 < inflightReq.numBuffersLeft) || + (!inflightReq.haveResultMetadata))) { auto timeout = std::chrono::system_clock::now() + - std::chrono::seconds(kStreamBufferTimeoutSec); - ASSERT_NE(std::cv_status::timeout, - mResultCondition.wait_until(l, timeout)); + std::chrono::seconds(kStreamBufferTimeoutSec); + ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, + timeout)); } if (!inflightReq.errorCodeValid) { ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u); - ASSERT_EQ(previewStream.id, - inflightReq.resultOutputBuffers[0].streamId); + ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId); } else { switch (inflightReq.errorCode) { case ErrorCode::ERROR_REQUEST: case ErrorCode::ERROR_RESULT: case ErrorCode::ERROR_BUFFER: - //Expected + // Expected break; case ErrorCode::ERROR_DEVICE: default: - FAIL() << "Unexpected error:" << static_cast<uint32_t> ( - inflightReq.errorCode); + FAIL() << "Unexpected error:" + << static_cast<uint32_t>(inflightReq.errorCode); } } @@ -3302,31 +3377,41 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { ASSERT_TRUE(ret.isOk()); } } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } // Verify that camera flushes correctly without any pending requests. TEST_F(CameraHidlTest, flushEmpty) { - for (auto provider : CameraHidlEnvironment::Instance()->mProviders) { - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames( - provider.second); - std::vector<AvailableStream> outputPreviewStreams; - AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, - static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; - - for (const auto& name : cameraDeviceNames) { - if (getCameraDeviceVersion(name, provider.first) == - CAMERA_DEVICE_API_VERSION_3_2) { + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + + for (const auto& name : cameraDeviceNames) { + int deviceVersion = getCameraDeviceVersion(name, mProviderType); + switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_3: + case CAMERA_DEVICE_API_VERSION_3_2: { Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; bool supportsPartialResults = false; uint32_t partialResultCount = 0; - configurePreviewStream(name, provider.second, &previewThreshold, - &session /*out*/, &previewStream /*out*/, - &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/, + &previewStream /*out*/, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, + &partialResultCount /*out*/); Return<Status> returnStatus = session->flush(); ASSERT_TRUE(returnStatus.isOk()); @@ -3335,14 +3420,23 @@ TEST_F(CameraHidlTest, flushEmpty) { { std::unique_lock<std::mutex> l(mLock); auto timeout = std::chrono::system_clock::now() + - std::chrono::milliseconds(kEmptyFlushTimeoutMSec); - ASSERT_EQ(std::cv_status::timeout, - mResultCondition.wait_until(l, timeout)); + std::chrono::milliseconds(kEmptyFlushTimeoutMSec); + ASSERT_EQ(std::cv_status::timeout, mResultCondition.wait_until(l, timeout)); } Return<void> ret = session->close(); ASSERT_TRUE(ret.isOk()); } + break; + case CAMERA_DEVICE_API_VERSION_1_0: { + //Not applicable + } + break; + default: { + ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); + ADD_FAILURE(); + } + break; } } } @@ -3546,7 +3640,7 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, ASSERT_NE(nullptr, partialResultCount); std::vector<AvailableStream> outputPreviewStreams; - ::android::sp<ICameraDevice> device3_2; + ::android::sp<ICameraDevice> device3_x; ALOGI("configureStreams: Testing camera device %s", name.c_str()); Return<void> ret; ret = provider->getCameraDeviceInterface_V3_x( @@ -3556,12 +3650,12 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); sp<DeviceCb> cb = new DeviceCb(this); - ret = device3_2->open( + ret = device3_x->open( cb, [&](auto status, const auto& newSession) { ALOGI("device::open returns status:%d", (int)status); @@ -3571,8 +3665,12 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, }); ASSERT_TRUE(ret.isOk()); + auto castResult = device::V3_3::ICameraDeviceSession::castFrom(*session); + ASSERT_TRUE(castResult.isOk()); + sp<device::V3_3::ICameraDeviceSession> session3_3 = castResult; + camera_metadata_t *staticMeta; - ret = device3_2->getCameraCharacteristics([&] (Status s, + ret = device3_x->getCameraCharacteristics([&] (Status s, CameraMetadata metadata) { ASSERT_EQ(Status::OK, s); staticMeta = clone_camera_metadata( @@ -3604,12 +3702,24 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, ::android::hardware::hidl_vec<Stream> streams = {*previewStream}; StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE}; - ret = (*session)->configureStreams(config, [&] (Status s, - HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(1u, halConfig.streams.size()); - *halStreamConfig = halConfig; - }); + if (session3_3 == nullptr) { + ret = (*session)->configureStreams(config, + [&] (Status s, HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + *halStreamConfig = halConfig; + }); + } else { + ret = session3_3->configureStreams_3_3(config, + [&] (Status s, device::V3_3::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + halStreamConfig->streams.resize(halConfig.streams.size()); + for (size_t i = 0; i < halConfig.streams.size(); i++) { + halStreamConfig->streams[i] = halConfig.streams[i].v3_2; + } + }); + } ASSERT_TRUE(ret.isOk()); } @@ -3617,11 +3727,12 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, void CameraHidlTest::openEmptyDeviceSession(const std::string &name, sp<ICameraProvider> provider, sp<ICameraDeviceSession> *session /*out*/, + sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/, camera_metadata_t **staticMeta /*out*/) { ASSERT_NE(nullptr, session); ASSERT_NE(nullptr, staticMeta); - ::android::sp<ICameraDevice> device3_2; + ::android::sp<ICameraDevice> device3_x; ALOGI("configureStreams: Testing camera device %s", name.c_str()); Return<void> ret; ret = provider->getCameraDeviceInterface_V3_x( @@ -3631,12 +3742,12 @@ void CameraHidlTest::openEmptyDeviceSession(const std::string &name, (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(device, nullptr); - device3_2 = device; + device3_x = device; }); ASSERT_TRUE(ret.isOk()); sp<EmptyDeviceCb> cb = new EmptyDeviceCb(); - ret = device3_2->open(cb, [&](auto status, const auto& newSession) { + ret = device3_x->open(cb, [&](auto status, const auto& newSession) { ALOGI("device::open returns status:%d", (int)status); ASSERT_EQ(Status::OK, status); ASSERT_NE(newSession, nullptr); @@ -3644,7 +3755,7 @@ void CameraHidlTest::openEmptyDeviceSession(const std::string &name, }); ASSERT_TRUE(ret.isOk()); - ret = device3_2->getCameraCharacteristics([&] (Status s, + ret = device3_x->getCameraCharacteristics([&] (Status s, CameraMetadata metadata) { ASSERT_EQ(Status::OK, s); *staticMeta = clone_camera_metadata( @@ -3652,6 +3763,12 @@ void CameraHidlTest::openEmptyDeviceSession(const std::string &name, ASSERT_NE(nullptr, *staticMeta); }); ASSERT_TRUE(ret.isOk()); + + if(session3_3 != nullptr) { + auto castResult = device::V3_3::ICameraDeviceSession::castFrom(*session); + ASSERT_TRUE(castResult.isOk()); + *session3_3 = castResult; + } } // Open a particular camera device. @@ -3783,6 +3900,7 @@ void CameraHidlTest::setParameters( int main(int argc, char **argv) { ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); + CameraHidlEnvironment::Instance()->init(&argc, argv); int status = RUN_ALL_TESTS(); ALOGI("Test result = %d", status); return status; diff --git a/cas/1.0/Android.bp b/cas/1.0/Android.bp new file mode 100644 index 0000000000..6d94793b7e --- /dev/null +++ b/cas/1.0/Android.bp @@ -0,0 +1,87 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.cas@1.0_hal", + srcs: [ + "types.hal", + "ICas.hal", + "ICasListener.hal", + "IDescramblerBase.hal", + "IMediaCasService.hal", + ], +} + +genrule { + name: "android.hardware.cas@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas@1.0", + srcs: [ + ":android.hardware.cas@1.0_hal", + ], + out: [ + "android/hardware/cas/1.0/types.cpp", + "android/hardware/cas/1.0/CasAll.cpp", + "android/hardware/cas/1.0/CasListenerAll.cpp", + "android/hardware/cas/1.0/DescramblerBaseAll.cpp", + "android/hardware/cas/1.0/MediaCasServiceAll.cpp", + ], +} + +genrule { + name: "android.hardware.cas@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas@1.0", + srcs: [ + ":android.hardware.cas@1.0_hal", + ], + out: [ + "android/hardware/cas/1.0/types.h", + "android/hardware/cas/1.0/hwtypes.h", + "android/hardware/cas/1.0/ICas.h", + "android/hardware/cas/1.0/IHwCas.h", + "android/hardware/cas/1.0/BnHwCas.h", + "android/hardware/cas/1.0/BpHwCas.h", + "android/hardware/cas/1.0/BsCas.h", + "android/hardware/cas/1.0/ICasListener.h", + "android/hardware/cas/1.0/IHwCasListener.h", + "android/hardware/cas/1.0/BnHwCasListener.h", + "android/hardware/cas/1.0/BpHwCasListener.h", + "android/hardware/cas/1.0/BsCasListener.h", + "android/hardware/cas/1.0/IDescramblerBase.h", + "android/hardware/cas/1.0/IHwDescramblerBase.h", + "android/hardware/cas/1.0/BnHwDescramblerBase.h", + "android/hardware/cas/1.0/BpHwDescramblerBase.h", + "android/hardware/cas/1.0/BsDescramblerBase.h", + "android/hardware/cas/1.0/IMediaCasService.h", + "android/hardware/cas/1.0/IHwMediaCasService.h", + "android/hardware/cas/1.0/BnHwMediaCasService.h", + "android/hardware/cas/1.0/BpHwMediaCasService.h", + "android/hardware/cas/1.0/BsMediaCasService.h", + ], +} + +cc_library { + name: "android.hardware.cas@1.0", + defaults: ["hidl-module-defaults"], + generated_sources: ["android.hardware.cas@1.0_genc++"], + generated_headers: ["android.hardware.cas@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.cas@1.0_genc++_headers"], + vendor_available: true, + vndk: { + enabled: true, + }, + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +} diff --git a/cas/1.0/CasHal.mk b/cas/1.0/CasHal.mk new file mode 100644 index 0000000000..3cae6bf416 --- /dev/null +++ b/cas/1.0/CasHal.mk @@ -0,0 +1,192 @@ +# +# 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. + + +######################################################################## +# Included by frameworks/base for MediaCas. Hidl HAL can't be linked as +# Java lib from frameworks because it has dependency on frameworks itself. +# + +intermediates := $(TARGET_OUT_COMMON_GEN)/JAVA_LIBRARIES/android.hardware.cas-V1.0-java_intermediates + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +HIDL_PATH := system/libhidl/transport/base/1.0 + +# +# Build types.hal (DebugInfo) +# +GEN := $(intermediates)/android/hidl/base/V1_0/DebugInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hidl:system/libhidl/transport \ + android.hidl.base@1.0::types.DebugInfo + +$(GEN): $(HIDL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IBase.hal +# +GEN := $(intermediates)/android/hidl/base/V1_0/IBase.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IBase.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hidl:system/libhidl/transport \ + android.hidl.base@1.0::IBase + +$(GEN): $(HIDL_PATH)/IBase.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +HIDL_PATH := hardware/interfaces/cas/1.0 + +# +# Build types.hal (HidlCasPluginDescriptor) +# +GEN := $(intermediates)/android/hardware/cas/V1_0/HidlCasPluginDescriptor.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::types.HidlCasPluginDescriptor + +$(GEN): $(HIDL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/cas/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::types.Status + +$(GEN): $(HIDL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build ICas.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/ICas.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICas.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::ICas + +$(GEN): $(HIDL_PATH)/ICas.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build ICasListener.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/ICasListener.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICasListener.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::ICasListener + +$(GEN): $(HIDL_PATH)/ICasListener.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IDescramblerBase.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/IDescramblerBase.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IDescramblerBase.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::IDescramblerBase + +$(GEN): $(HIDL_PATH)/IDescramblerBase.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IMediaCasService.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/IMediaCasService.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IMediaCasService.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICas.hal +$(GEN): $(HIDL_PATH)/ICas.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICasListener.hal +$(GEN): $(HIDL_PATH)/ICasListener.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/IDescramblerBase.hal +$(GEN): $(HIDL_PATH)/IDescramblerBase.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::IMediaCasService + +$(GEN): $(HIDL_PATH)/IMediaCasService.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + diff --git a/cas/1.0/ICas.hal b/cas/1.0/ICas.hal new file mode 100644 index 0000000000..08a92da19e --- /dev/null +++ b/cas/1.0/ICas.hal @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.cas@1.0; + +import android.hardware.cas@1.0::types; + +/** + * 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 { + /** + * Provide the CA private data from a CA_descriptor in the conditional + * access table to a CasPlugin. + * + * @param pvtData a byte array containing the private data, the format of + * which is scheme-specific and opaque to the framework. + * @return status the status of the call. + */ + setPrivateData(vec<uint8_t> pvtData) generates (Status status); + + /** + * Open a session to descramble one or more streams scrambled by the + * conditional access system. + * + * @return status the status of the call. + * @return sessionId the id of the newly opened session. + */ + openSession() generates(Status status, HidlCasSessionId sessionId); + + /** + * Close a session. + * + * @param sessionId the id of the session to be closed. + * @return status the status of the call. + */ + closeSession(HidlCasSessionId sessionId) generates (Status status); + + /** + * Provide the CA private data from a CA_descriptor in the program map + * table to a session. + * + * @param sessionId the id of the session which the private data applies to. + * @param pvtData a byte array containing the private data, the format of + * which is scheme-specific and opaque to the framework. + * @return status the status of the call. + */ + setSessionPrivateData(HidlCasSessionId sessionId, vec<uint8_t> pvtData) + generates (Status status); + + /** + * Process an ECM from the ECM stream for this session’s elementary stream. + * + * @param sessionId the id of the session which the ecm data applies to. + * @param ecm a byte array containing the ecm data. + * @return status the status of the call. + */ + processEcm(HidlCasSessionId sessionId, vec<uint8_t> ecm) + generates (Status status); + + /** + * Process an in-band EMM from the EMM stream. + * + * @param emm a byte array containing the emm data. + * @return status the status of the call. + */ + processEmm(vec<uint8_t> emm) generates (Status status); + + /** + * Send an scheme-specific event to the CasPlugin. + * + * @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. + */ + sendEvent(int32_t event, int32_t arg, vec<uint8_t> eventData) + generates (Status status); + + /** + * Initiate a provisioning operation for a CA system. + * + * @param provisionString string containing information needed for the + * provisioning operation, the format of which is scheme and implementation + * specific. + * @return status the status of the call. + */ + provision(string provisionString) generates (Status status); + + /** + * Notify the CA system to refresh entitlement keys. + * + * @param refreshType the type of the refreshment. + * @param refreshData private data associated with the refreshment. + * @return status the status of the call. + */ + refreshEntitlements(int32_t refreshType, vec<uint8_t> refreshData) + generates (Status status); + + /** + * Release the descrambler instance. + * + * @return status the status of the call. + */ + release() generates (Status status); +}; diff --git a/cas/1.0/ICasListener.hal b/cas/1.0/ICasListener.hal new file mode 100644 index 0000000000..8ae6014d1c --- /dev/null +++ b/cas/1.0/ICasListener.hal @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.cas@1.0; + +interface ICasListener { + /** + * Notify the listener of a scheme-specific event from the CA system. + * + * @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. + */ + onEvent(int32_t event, int32_t arg, vec<uint8_t> data); +}; diff --git a/cas/1.0/IDescramblerBase.hal b/cas/1.0/IDescramblerBase.hal new file mode 100644 index 0000000000..a126084b33 --- /dev/null +++ b/cas/1.0/IDescramblerBase.hal @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.cas@1.0; + +import android.hardware.cas@1.0::types; + +/** + * IDescramblerBase is the API to control the descrambler and is accessible + * from both Java and native level. + */ + +interface IDescramblerBase { + /** + * Associate a MediaCas session with this MediaDescrambler instance. + * + * @param sessionId the id of the session to associate with this descrambler instance. + * @return status the status of the call. + */ + setMediaCasSession(HidlCasSessionId sessionId) generates (Status status); + + /** + * Query if the scrambling scheme requires the use of a secure decoder + * to decode data of the given mime type. + * + * @param mime the mime type of the media data. + * @return result whether the descrambler requires a secure decoder. + */ + requiresSecureDecoderComponent(string mime) generates (bool result); + + /** + * Release the descrambler instance. + * + * @return status the status of the call. + */ + release() generates (Status status); +}; diff --git a/cas/1.0/IMediaCasService.hal b/cas/1.0/IMediaCasService.hal new file mode 100644 index 0000000000..cfeafad2a1 --- /dev/null +++ b/cas/1.0/IMediaCasService.hal @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.cas@1.0; + +import android.hardware.cas@1.0::ICas; +import android.hardware.cas@1.0::ICasListener; +import android.hardware.cas@1.0::IDescramblerBase; + +/** + * 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 { + /** + * List all available CA systems on the device. + * + * @return descriptors an array of descriptors for the available CA systems. + */ + enumeratePlugins() generates (vec<HidlCasPluginDescriptor> descriptors); + + /** + * Query if a certain CA system is supported on this device. + * + * @param CA_system_id the id of the CA system. + * @return result whether the specified CA system is supported on this device. + */ + isSystemIdSupported(int32_t CA_system_id) generates (bool result); + + /** + * Construct a new instance of a CasPlugin given a CA_system_id. + * + * @param CA_system_id 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. + */ + createPlugin(int32_t CA_system_id, ICasListener listener) generates (ICas cas); + + /** + * Query if the descrambling scheme for a CA system is supported on this device. + * + * @param CA_system_id the id of the CA system. + * @return result whether the specified descrambling scheme is supported on this device. + */ + isDescramblerSupported(int32_t CA_system_id) generates (bool result); + + /** + * Construct a new instance of a DescramblerPlugin given a CA_system_id. + * + * @param CA_system_id the id of the CA system. + * @return descrambler the newly created plugin interface. + */ + createDescrambler(int32_t CA_system_id) generates (IDescramblerBase descrambler); +}; diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp new file mode 100644 index 0000000000..6da5cc442c --- /dev/null +++ b/cas/1.0/default/Android.bp @@ -0,0 +1,39 @@ +cc_binary { + name: "android.hardware.cas@1.0-service", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "CasImpl.cpp", + "DescramblerImpl.cpp", + "MediaCasService.cpp", + "service.cpp", + "SharedLibrary.cpp", + "TypeConvert.cpp", + ], + + product_variables: { + treble: { + cflags: ["-DUSE_VNDBINDER"], + }, + }, + + compile_multilib: "32", + init_rc: ["android.hardware.cas@1.0-service.rc"], + + shared_libs: [ + "android.hardware.cas@1.0", + "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", + ], +} diff --git a/cas/1.0/default/CasImpl.cpp b/cas/1.0/default/CasImpl.cpp new file mode 100644 index 0000000000..9d1f4a3268 --- /dev/null +++ b/cas/1.0/default/CasImpl.cpp @@ -0,0 +1,205 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.0-CasImpl" + +#include <android/hardware/cas/1.0/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_0 { +namespace implementation { + +struct CasImpl::PluginHolder : public RefBase { +public: + explicit PluginHolder(CasPlugin *plugin) : mPlugin(plugin) {} + ~PluginHolder() { if (mPlugin != NULL) delete mPlugin; } + CasPlugin* get() { return mPlugin; } + +private: + CasPlugin *mPlugin; + DISALLOW_EVIL_CONSTRUCTORS(PluginHolder); +}; + +CasImpl::CasImpl(const sp<ICasListener> &listener) + : mPluginHolder(NULL), 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); +} + +void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) { + mLibrary = library; + mPluginHolder = new PluginHolder(plugin); +} + +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); +} + +Return<Status> CasImpl::setPrivateData(const HidlCasData& pvtData) { + ALOGV("%s", __FUNCTION__); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->get()->setPrivateData(pvtData)); +} + +Return<void> CasImpl::openSession(openSession_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + CasSessionId sessionId; + + sp<PluginHolder> holder = mPluginHolder; + status_t err = INVALID_OPERATION; + if (holder != NULL) { + err = holder->get()->openSession(&sessionId); + } + + _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()); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + return toStatus( + holder->get()->setSessionPrivateData( + sessionId, pvtData)); +} + +Return<Status> CasImpl::closeSession(const HidlCasSessionId &sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, + sessionIdToString(sessionId).string()); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->get()->closeSession(sessionId)); +} + +Return<Status> CasImpl::processEcm( + const HidlCasSessionId &sessionId, const HidlCasData& ecm) { + ALOGV("%s: sessionId=%s", __FUNCTION__, + sessionIdToString(sessionId).string()); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->get()->processEcm(sessionId, ecm)); +} + +Return<Status> CasImpl::processEmm(const HidlCasData& emm) { + ALOGV("%s", __FUNCTION__); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->get()->processEmm(emm)); +} + +Return<Status> CasImpl::sendEvent( + int32_t event, int32_t arg, + const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->get()->sendEvent(event, arg, eventData); + return toStatus(err); +} + +Return<Status> CasImpl::provision(const hidl_string& provisionString) { + ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str()); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->get()->provision(String8(provisionString.c_str()))); +} + +Return<Status> CasImpl::refreshEntitlements( + int32_t refreshType, + const HidlCasData& refreshData) { + ALOGV("%s", __FUNCTION__); + sp<PluginHolder> holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->get()->refreshEntitlements(refreshType, refreshData); + return toStatus(err); +} + +Return<Status> CasImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, + mPluginHolder != NULL ? mPluginHolder->get() : NULL); + mPluginHolder.clear(); + return Status::OK; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/CasImpl.h b/cas/1.0/default/CasImpl.h new file mode 100644 index 0000000000..841d64e038 --- /dev/null +++ b/cas/1.0/default/CasImpl.h @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_ + +#include <media/stagefright/foundation/ABase.h> +#include <android/hardware/cas/1.0/ICas.h> + +namespace android { +struct CasPlugin; + +namespace hardware { +namespace cas { +namespace V1_0 { +struct ICasListener; +namespace implementation { + +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); + + void init(const sp<SharedLibrary>& library, CasPlugin *plugin); + void onEvent( + 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> 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; + sp<PluginHolder> mPluginHolder; + sp<ICasListener> mListener; + + DISALLOW_EVIL_CONSTRUCTORS(CasImpl); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_ diff --git a/cas/1.0/default/DescramblerImpl.cpp b/cas/1.0/default/DescramblerImpl.cpp new file mode 100644 index 0000000000..3d90809cd0 --- /dev/null +++ b/cas/1.0/default/DescramblerImpl.cpp @@ -0,0 +1,127 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.0-DescramblerImpl" + +#include <hidlmemory/mapping.h> +#include <media/hardware/CryptoAPI.h> +#include <media/cas/DescramblerAPI.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_0 { +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), mPlugin(plugin) { + ALOGV("CTOR: mPlugin=%p", mPlugin); +} + +DescramblerImpl::~DescramblerImpl() { + ALOGV("DTOR: mPlugin=%p", mPlugin); + release(); +} + +Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, + sessionIdToString(sessionId).string()); + + return toStatus(mPlugin->setMediaCasSession(sessionId)); +} + +Return<bool> DescramblerImpl::requiresSecureDecoderComponent( + const hidl_string& mime) { + return mPlugin->requiresSecureDecoderComponent(String8(mime.c_str())); +} + +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__); + + sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase); + 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; + } else { + native_handle_t *handle = const_cast<native_handle_t *>( + dstBuffer.secureMemory.getNativeHandle()); + dstPtr = static_cast<void *>(handle); + } + // Casting hidl SubSample to DescramblerPlugin::SubSample, but need + // to ensure structs are actually idential + + int32_t result = mPlugin->descramble( + dstBuffer.type != BufferType::SHARED_MEMORY, + (DescramblerPlugin::ScramblingControl)scramblingControl, + subSamples.size(), + (DescramblerPlugin::SubSample*)subSamples.data(), + srcPtr, + srcOffset, + dstPtr, + dstOffset, + NULL); + + _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL); + return Void(); +} + +Return<Status> DescramblerImpl::release() { + ALOGV("%s: mPlugin=%p", __FUNCTION__, mPlugin); + + if (mPlugin != NULL) { + delete mPlugin; + mPlugin = NULL; + } + return Status::OK; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/DescramblerImpl.h b/cas/1.0/default/DescramblerImpl.h new file mode 100644 index 0000000000..d3b146ecc7 --- /dev/null +++ b/cas/1.0/default/DescramblerImpl.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_ + +#include <media/stagefright/foundation/ABase.h> +#include <android/hardware/cas/native/1.0/IDescrambler.h> + +namespace android { +struct DescramblerPlugin; +using namespace hardware::cas::native::V1_0; + +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +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; + DescramblerPlugin *mPlugin; + + DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_ diff --git a/cas/1.0/default/FactoryLoader.h b/cas/1.0/default/FactoryLoader.h new file mode 100644 index 0000000000..18c2186dcb --- /dev/null +++ b/cas/1.0/default/FactoryLoader.h @@ -0,0 +1,229 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ +#define ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ + +#include <dirent.h> +#include <dlfcn.h> +#include "SharedLibrary.h" +#include <utils/KeyedVector.h> +#include <utils/Mutex.h> +#include <media/cas/CasAPI.h> + +using namespace std; + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +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_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ diff --git a/cas/1.0/default/MediaCasService.cpp b/cas/1.0/default/MediaCasService.cpp new file mode 100644 index 0000000000..ca4322461e --- /dev/null +++ b/cas/1.0/default/MediaCasService.cpp @@ -0,0 +1,112 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.0-MediaCasService" + +#include <android/hardware/cas/1.0/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_0 { +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<ICas>> MediaCasService::createPlugin( + 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, (uint64_t)casImpl.get(), + &CasImpl::OnEvent, &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_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/MediaCasService.h b/cas/1.0/default/MediaCasService.h new file mode 100644 index 0000000000..77ddac6032 --- /dev/null +++ b/cas/1.0/default/MediaCasService.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_ +#define ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_ + +#include <android/hardware/cas/1.0/IMediaCasService.h> + +#include "FactoryLoader.h" + +namespace android { +struct CasFactory; +struct DescramblerFactory; +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +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<ICas>> createPlugin( + 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_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_ diff --git a/cas/1.0/default/SharedLibrary.cpp b/cas/1.0/default/SharedLibrary.cpp new file mode 100644 index 0000000000..9c7f38554a --- /dev/null +++ b/cas/1.0/default/SharedLibrary.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.0-SharedLibrary" + +#include <dlfcn.h> +#include <media/stagefright/foundation/ADebug.h> +#include "SharedLibrary.h" +#include <utils/Log.h> + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +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_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/SharedLibrary.h b/cas/1.0/default/SharedLibrary.h new file mode 100644 index 0000000000..18130a5441 --- /dev/null +++ b/cas/1.0/default/SharedLibrary.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_ +#define ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_ + +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <media/stagefright/foundation/ABase.h> + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +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_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_ diff --git a/cas/1.0/default/TypeConvert.cpp b/cas/1.0/default/TypeConvert.cpp new file mode 100644 index 0000000000..cd0efdbc2a --- /dev/null +++ b/cas/1.0/default/TypeConvert.cpp @@ -0,0 +1,95 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.0-TypeConvert" + +#include <utils/Log.h> +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +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_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/TypeConvert.h b/cas/1.0/default/TypeConvert.h new file mode 100644 index 0000000000..7c3ddeddbb --- /dev/null +++ b/cas/1.0/default/TypeConvert.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H +#define ANDROID_HARDWARE_CAS_V1_0_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_0 { +namespace implementation { + +Status toStatus(status_t legacyStatus); + +String8 sessionIdToString(const CasSessionId &sessionId); + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc new file mode 100644 index 0000000000..93de79444e --- /dev/null +++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc @@ -0,0 +1,6 @@ +service cas-hal-1-0 /vendor/bin/hw/android.hardware.cas@1.0-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.0/default/service.cpp b/cas/1.0/default/service.cpp new file mode 100644 index 0000000000..3f1df5a511 --- /dev/null +++ b/cas/1.0/default/service.cpp @@ -0,0 +1,50 @@ +/* + * 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 +#define LOG_TAG "android.hardware.cas@1.0-service" + +#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::cas::V1_0::implementation::MediaCasService; +using android::hardware::cas::V1_0::IMediaCasService; + +int main() { + ALOGD("android.hardware.cas@1.0-service starting..."); + +#ifdef USE_VNDBINDER + // The CAS HAL may communicate to other vendor components via + // /dev/vndbinder + android::ProcessState::initWithDriver("/dev/vndbinder"); +#endif // USE_VNDBINDER + + configureRpcThreadpool(8, true /* callerWillJoin */); + + // Setup hwbinder service + android::sp<IMediaCasService> service = new MediaCasService(); + android::status_t status = service->registerAsService(); + LOG_ALWAYS_FATAL_IF( + status != android::OK, + "Error while registering cas service: %d", status); + joinRpcThreadpool(); + return 0; +} diff --git a/cas/1.0/types.hal b/cas/1.0/types.hal new file mode 100644 index 0000000000..7337f0014e --- /dev/null +++ b/cas/1.0/types.hal @@ -0,0 +1,124 @@ +/** + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.cas@1.0; + +enum Status : uint32_t { + /** + * The CAS plugin must return OK when an operation completes without any + * errors. + */ + OK, + + /** + * The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is + * attempted and no license keys have been provided. + */ + ERROR_CAS_NO_LICENSE, + + /** + * ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made + * to use a license and the keys in that license have expired. + */ + ERROR_CAS_LICENSE_EXPIRED, + + /** + * The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an + * attempt is made to use a session that has not been opened. + */ + ERROR_CAS_SESSION_NOT_OPENED, + + /** + * The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported + * data format or operation is attempted. + */ + ERROR_CAS_CANNOT_HANDLE, + + /** + * ERROR_CAS_INVALID_STATE must be returned when the device is in a state + * where it is not able to perform descrambling. + */ + ERROR_CAS_INVALID_STATE, + + /** + * The CAS plugin must return BAD_VALUE whenever an illegal parameter is + * passed to one of the interface functions. + */ + BAD_VALUE, + + /** + * The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device + * has not yet been provisioned. + */ + ERROR_CAS_NOT_PROVISIONED, + + /** + * ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS + * sessions or secure buffers are not available to perform a requested + * operation because they are already in use. + */ + ERROR_CAS_RESOURCE_BUSY, + + /** + * The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION + * when the output protection level enabled on the device is not + * sufficient to meet the requirements in the license policy. HDCP is an + * example of a form of output protection. + */ + ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION, + + /** + * The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to + * tamper with the CAS system is detected. + */ + ERROR_CAS_TAMPER_DETECTED, + + /** + * The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response + * indicates that the device has been revoked. Device revocation means + * that the device is no longer permitted to play content. + */ + ERROR_CAS_DEVICE_REVOKED, + + /** + * The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when + * descrambling is failing because the session is not initialized properly. + */ + ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED, + + /** + * The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's + * descramble operation fails. + */ + ERROR_CAS_DECRYPT, + + /** + * ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no + * other defined error is appropriate. + */ + ERROR_CAS_UNKNOWN, +}; + +typedef vec<uint8_t> HidlCasSessionId; +typedef vec<uint8_t> HidlCasData; + +/** + * Describes a CAS plugin with its system id and name. + */ +struct HidlCasPluginDescriptor { + int32_t caSystemId; + string name; +}; diff --git a/configstore/1.1/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp index 5cfa4839d9..e1e09e9ce8 100644 --- a/configstore/1.1/vts/functional/Android.bp +++ b/cas/1.0/vts/functional/Android.bp @@ -15,20 +15,18 @@ // cc_test { - name: "VtsHalConfigstoreV1_1TargetTest", - defaults: ["hidl_defaults"], - srcs: ["VtsHalConfigstoreV1_1TargetTest.cpp"], + name: "VtsHalCasV1_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalCasV1_0TargetTest.cpp"], + static_libs: [ + "android.hardware.cas@1.0", + "android.hardware.cas.native@1.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlmemory", + ], shared_libs: [ - "libbase", - "libhidlbase", - "liblog", - "libutils", - "android.hardware.configstore@1.1", + "libbinder", ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ] } diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp new file mode 100644 index 0000000000..d3b0f1da3b --- /dev/null +++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp @@ -0,0 +1,623 @@ +/* + * 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. + */ + +#define LOG_TAG "mediacas_hidl_hal_test" + +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> +#include <android/hardware/cas/1.0/ICas.h> +#include <android/hardware/cas/1.0/ICasListener.h> +#include <android/hardware/cas/1.0/IDescramblerBase.h> +#include <android/hardware/cas/1.0/IMediaCasService.h> +#include <android/hardware/cas/1.0/types.h> +#include <android/hardware/cas/native/1.0/IDescrambler.h> +#include <android/hardware/cas/native/1.0/types.h> +#include <binder/MemoryDealer.h> +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> +#include <hidl/Status.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> + +#define CLEAR_KEY_SYSTEM_ID 0xF6D8 +#define INVALID_SYSTEM_ID 0 +#define WAIT_TIMEOUT 3000000000 + +#define PROVISION_STR \ + "{ " \ + " \"id\": 21140844, " \ + " \"name\": \"Test Title\", " \ + " \"lowercase_organization_name\": \"Android\", " \ + " \"asset_key\": { " \ + " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \ + " }, " \ + " \"cas_type\": 1, " \ + " \"track_types\": [ ] " \ + "} " + +using android::Condition; +using android::hardware::cas::V1_0::ICas; +using android::hardware::cas::V1_0::ICasListener; +using android::hardware::cas::V1_0::IDescramblerBase; +using android::hardware::cas::native::V1_0::IDescrambler; +using android::hardware::cas::native::V1_0::SubSample; +using android::hardware::cas::native::V1_0::SharedBuffer; +using android::hardware::cas::native::V1_0::DestinationBuffer; +using android::hardware::cas::native::V1_0::BufferType; +using android::hardware::cas::native::V1_0::ScramblingControl; +using android::hardware::cas::V1_0::IMediaCasService; +using android::hardware::cas::V1_0::HidlCasPluginDescriptor; +using android::hardware::Void; +using android::hardware::hidl_vec; +using android::hardware::hidl_string; +using android::hardware::hidl_handle; +using android::hardware::hidl_memory; +using android::hardware::Return; +using android::hardware::cas::V1_0::Status; +using android::IMemory; +using android::IMemoryHeap; +using android::MemoryDealer; +using android::Mutex; +using android::sp; + +namespace { + +const uint8_t kEcmBinaryBuffer[] = { + 0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00, + 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f, + 0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c, + 0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48, +}; + +const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}}; + +const uint8_t kInBinaryBuffer[] = { + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, 0x01, + 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, 0xc5, 0x8b, + 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xff, + 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, + 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x31, 0x34, 0x32, + 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, + 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, + 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, + 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, + 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x6e, 0x45, 0x21, 0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, + 0x8f, 0x04, 0x49, 0xe5, 0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, + 0x7e, 0x60, 0x5b, 0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, + 0x08, 0xcb, 0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, + 0xe3, 0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80, + 0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c, 0xe1, + 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7, 0x45, 0x58, + 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03, 0xaa, 0xe4, 0x32, + 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49, 0xc8, 0xbf, 0xca, 0x8c, + 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e, 0xb3, 0x2d, 0x1f, 0xb8, 0x35, + 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72, 0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, + 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d, 0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, + 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e, 0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, + 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a, 0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, + 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46, 0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, + 0x6a, 0x12, 0xfa, 0xc4, 0x33, 0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, + 0x8e, 0xf1, 0xbc, 0x3d, 0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, + 0x25, 0x24, 0x7c, 0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, + 0xb1, 0x53, 0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, + 0xb4, 0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80, + 0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0, 0xe3, + 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46, 0x7c, 0x75, + 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0, 0xc5, 0x4c, 0x24, + 0x0e, 0x65, +}; + +const uint8_t kOutRefBinaryBuffer[] = { + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, 0x01, + 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, 0xc5, 0x8b, + 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xff, + 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, + 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x31, 0x34, 0x32, + 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, + 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, + 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, + 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, + 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, + 0x62, 0x61, 0x63, 0x3d, 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, + 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, + 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, + 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, 0x30, + 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, 0x6d, 0x65, + 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, + 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, 0x73, 0x3d, 0x31, 0x20, + 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, + 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, + 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, + 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, + 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, + 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, + 0x69, 0x63, 0x65, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, + 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, + 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, + 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, 0x20, 0x6b, + 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, + 0x6e, 0x65, +}; + +class MediaCasListener : public ICasListener { + public: + virtual Return<void> onEvent(int32_t event, int32_t arg, + const hidl_vec<uint8_t>& data) override { + android::Mutex::Autolock autoLock(mMsgLock); + mEvent = event; + mEventArg = arg; + mEventData = data; + + mEventReceived = true; + mMsgCondition.signal(); + return Void(); + } + + void testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg, + hidl_vec<uint8_t>& eventData); + + private: + int32_t mEvent = -1; + int32_t mEventArg = -1; + bool mEventReceived = false; + hidl_vec<uint8_t> mEventData; + android::Mutex mMsgLock; + android::Condition mMsgCondition; +}; + +void MediaCasListener::testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg, + hidl_vec<uint8_t>& eventData) { + mEventReceived = false; + auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "event not received within timeout"; + return; + } + } + + EXPECT_EQ(mEvent, event); + EXPECT_EQ(mEventArg, eventArg); + EXPECT_TRUE(mEventData == eventData); +} + +class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(); + ASSERT_NE(mService, nullptr); + } + + sp<IMediaCasService> mService; + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp<ICas> mMediaCas; + sp<IDescramblerBase> mDescramblerBase; + sp<MediaCasListener> mCasListener; + + ::testing::AssertionResult createCasPlugin(int32_t caSystemId); + ::testing::AssertionResult openCasSession(std::vector<uint8_t>* sessionId); + ::testing::AssertionResult descrambleTestInputBuffer(const sp<IDescrambler>& descrambler, + Status* descrambleStatus, + sp<IMemory>* hidlInMemory); +}; + +::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) { + auto status = mService->isSystemIdSupported(caSystemId); + if (!status.isOk() || !status) { + return ::testing::AssertionFailure(); + } + status = mService->isDescramblerSupported(caSystemId); + if (!status.isOk() || !status) { + return ::testing::AssertionFailure(); + } + + mCasListener = new MediaCasListener(); + auto pluginStatus = mService->createPlugin(caSystemId, mCasListener); + if (!pluginStatus.isOk()) { + return ::testing::AssertionFailure(); + } + mMediaCas = pluginStatus; + if (mMediaCas == nullptr) { + return ::testing::AssertionFailure(); + } + + auto descramblerStatus = mService->createDescrambler(caSystemId); + if (!descramblerStatus.isOk()) { + return ::testing::AssertionFailure(); + } + mDescramblerBase = descramblerStatus; + return ::testing::AssertionResult(mDescramblerBase != nullptr); +} + +::testing::AssertionResult MediaCasHidlTest::openCasSession(std::vector<uint8_t>* sessionId) { + Status sessionStatus; + auto returnVoid = mMediaCas->openSession([&](Status status, const hidl_vec<uint8_t>& id) { + sessionStatus = status; + *sessionId = id; + }); + return ::testing::AssertionResult(returnVoid.isOk() && (Status::OK == sessionStatus)); +} + +::testing::AssertionResult MediaCasHidlTest::descrambleTestInputBuffer( + const sp<IDescrambler>& descrambler, Status* descrambleStatus, sp<IMemory>* inMemory) { + hidl_vec<SubSample> hidlSubSamples; + hidlSubSamples.setToExternal(const_cast<SubSample*>(kSubSamples), + (sizeof(kSubSamples) / sizeof(SubSample)), false /*own*/); + + sp<MemoryDealer> dealer = new MemoryDealer(sizeof(kInBinaryBuffer), "vts-cas"); + if (nullptr == dealer.get()) { + ALOGE("couldn't get MemoryDealer!"); + return ::testing::AssertionFailure(); + } + + sp<IMemory> mem = dealer->allocate(sizeof(kInBinaryBuffer)); + if (nullptr == mem.get()) { + ALOGE("couldn't allocate IMemory!"); + return ::testing::AssertionFailure(); + } + *inMemory = mem; + + // build hidl_memory from memory heap + ssize_t offset; + size_t size; + sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); + if (nullptr == heap.get()) { + ALOGE("couldn't get memory heap!"); + return ::testing::AssertionFailure(); + } + + native_handle_t* nativeHandle = native_handle_create(1, 0); + if (!nativeHandle) { + ALOGE("failed to create native handle!"); + return ::testing::AssertionFailure(); + } + nativeHandle->data[0] = heap->getHeapID(); + + uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer())); + memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer)); + + SharedBuffer srcBuffer = { + .heapBase = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize()), + .offset = (uint64_t) offset, + .size = (uint64_t) size + }; + + DestinationBuffer dstBuffer; + dstBuffer.type = BufferType::SHARED_MEMORY; + dstBuffer.nonsecureMemory = srcBuffer; + + uint32_t outBytes; + hidl_string detailedError; + auto returnVoid = descrambler->descramble( + ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, 0, dstBuffer, 0, + [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) { + *descrambleStatus = status; + outBytes = bytesWritten; + detailedError = detailedErr; + }); + if (!returnVoid.isOk() || *descrambleStatus != Status::OK) { + ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s", + returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str()); + } + return ::testing::AssertionResult(returnVoid.isOk()); +} + +TEST_F(MediaCasHidlTest, EnumeratePlugins) { + description("Test enumerate plugins"); + hidl_vec<HidlCasPluginDescriptor> descriptors; + EXPECT_TRUE(mService + ->enumeratePlugins([&descriptors]( + hidl_vec<HidlCasPluginDescriptor> const& desc) { descriptors = desc; }) + .isOk()); + + if (descriptors.size() == 0) { + ALOGW("[ WARN ] enumeratePlugins list empty"); + return; + } + + sp<MediaCasListener> casListener = new MediaCasListener(); + for (size_t i = 0; i < descriptors.size(); i++) { + int32_t caSystemId = descriptors[i].caSystemId; + + ASSERT_TRUE(createCasPlugin(caSystemId)); + } +} + +TEST_F(MediaCasHidlTest, TestInvalidSystemIdFails) { + description("Test failure for invalid system ID"); + sp<MediaCasListener> casListener = new MediaCasListener(); + + ASSERT_FALSE(mService->isSystemIdSupported(INVALID_SYSTEM_ID)); + ASSERT_FALSE(mService->isDescramblerSupported(INVALID_SYSTEM_ID)); + + auto pluginStatus = mService->createPlugin(INVALID_SYSTEM_ID, casListener); + ASSERT_TRUE(pluginStatus.isOk()); + sp<ICas> mediaCas = pluginStatus; + EXPECT_EQ(mediaCas, nullptr); + + auto descramblerStatus = mService->createDescrambler(INVALID_SYSTEM_ID); + ASSERT_TRUE(descramblerStatus.isOk()); + sp<IDescramblerBase> descramblerBase = descramblerStatus; + EXPECT_EQ(descramblerBase, nullptr); +} + +TEST_F(MediaCasHidlTest, TestClearKeyPluginInstalled) { + description("Test if ClearKey plugin is installed"); + hidl_vec<HidlCasPluginDescriptor> descriptors; + EXPECT_TRUE(mService + ->enumeratePlugins([&descriptors]( + hidl_vec<HidlCasPluginDescriptor> const& desc) { descriptors = desc; }) + .isOk()); + + if (descriptors.size() == 0) { + ALOGW("[ WARN ] enumeratePlugins list empty"); + } + + for (size_t i = 0; i < descriptors.size(); i++) { + int32_t caSystemId = descriptors[i].caSystemId; + if (CLEAR_KEY_SYSTEM_ID == caSystemId) { + return; + } + } + + ASSERT_TRUE(false) << "ClearKey plugin not installed"; +} + +TEST_F(MediaCasHidlTest, TestClearKeyApis) { + description("Test that valid call sequences succeed"); + + ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); + + auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR)); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec<uint8_t> hidlPvtData; + hidlPvtData.resize(256); + returnStatus = mMediaCas->setPrivateData(hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + std::vector<uint8_t> sessionId; + ASSERT_TRUE(openCasSession(&sessionId)); + returnStatus = mMediaCas->setSessionPrivateData(sessionId, hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + std::vector<uint8_t> streamSessionId; + ASSERT_TRUE(openCasSession(&streamSessionId)); + returnStatus = mMediaCas->setSessionPrivateData(streamSessionId, hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(sessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(streamSessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec<uint8_t> hidlNullPtr; + hidlNullPtr.setToExternal(static_cast<uint8_t*>(nullptr), 0); + returnStatus = mMediaCas->refreshEntitlements(3, hidlNullPtr); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + uint8_t refreshData[] = {0, 1, 2, 3}; + hidl_vec<uint8_t> hidlRefreshData; + hidlRefreshData.setToExternal(static_cast<uint8_t*>(refreshData), sizeof(refreshData)); + returnStatus = mMediaCas->refreshEntitlements(10, hidlRefreshData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + int32_t eventID = 1; + int32_t eventArg = 2; + mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlNullPtr); + + eventID = 3; + eventArg = 4; + uint8_t eventData[] = {'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'}; + hidl_vec<uint8_t> hidlEventData; + hidlEventData.setToExternal(static_cast<uint8_t*>(eventData), sizeof(eventData)); + mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlEventData); + + uint8_t clearKeyEmmData[] = {'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'}; + hidl_vec<uint8_t> hidlClearKeyEmm; + hidlClearKeyEmm.setToExternal(static_cast<uint8_t*>(clearKeyEmmData), sizeof(clearKeyEmmData)); + returnStatus = mMediaCas->processEmm(hidlClearKeyEmm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec<uint8_t> hidlEcm; + hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer)); + returnStatus = mMediaCas->processEcm(sessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + returnStatus = mMediaCas->processEcm(streamSessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("video/avc")); + + sp<IDescrambler> descrambler; + descrambler = IDescrambler::castFrom(mDescramblerBase); + ASSERT_NE(descrambler, nullptr); + + Status descrambleStatus = Status::OK; + sp<IMemory> dataMemory; + + ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory)); + EXPECT_EQ(Status::OK, descrambleStatus); + + ASSERT_NE(nullptr, dataMemory.get()); + uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->pointer())); + + int compareResult = + memcmp(static_cast<const void*>(opBuffer), static_cast<const void*>(kOutRefBinaryBuffer), + sizeof(kOutRefBinaryBuffer)); + EXPECT_EQ(0, compareResult); + + returnStatus = mDescramblerBase->release(); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mMediaCas->release(); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); +} + +TEST_F(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) { + description("Test that all sessions are closed after a MediaCas object is released"); + + ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); + + auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR)); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + std::vector<uint8_t> sessionId; + ASSERT_TRUE(openCasSession(&sessionId)); + std::vector<uint8_t> streamSessionId; + ASSERT_TRUE(openCasSession(&streamSessionId)); + + returnStatus = mMediaCas->release(); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(sessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(streamSessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus); +} + +TEST_F(MediaCasHidlTest, TestClearKeyErrors) { + description("Test that invalid call sequences fail with expected error codes"); + + ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); + + /* + * Test MediaCas error codes + */ + // Provision should fail with an invalid asset string + auto returnStatus = mMediaCas->provision(hidl_string("invalid asset string")); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::ERROR_CAS_NO_LICENSE, returnStatus); + + // Open a session, then close it so that it should become invalid + std::vector<uint8_t> invalidSessionId; + ASSERT_TRUE(openCasSession(&invalidSessionId)); + returnStatus = mMediaCas->closeSession(invalidSessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + // processEcm should fail with an invalid session id + hidl_vec<uint8_t> hidlEcm; + hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer)); + returnStatus = mMediaCas->processEcm(invalidSessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus); + + std::vector<uint8_t> sessionId; + ASSERT_TRUE(openCasSession(&sessionId)); + + // processEcm should fail without provisioning + hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer)); + returnStatus = mMediaCas->processEcm(sessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::ERROR_CAS_NOT_PROVISIONED, returnStatus); + + returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR)); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + // processEcm should fail with ecm buffer that's too short + hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), 8); + returnStatus = mMediaCas->processEcm(sessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::BAD_VALUE, returnStatus); + + // processEcm should fail with ecm with bad descriptor count + uint8_t badDescriptor[sizeof(kEcmBinaryBuffer)]; + memcpy(badDescriptor, kEcmBinaryBuffer, sizeof(kEcmBinaryBuffer)); + badDescriptor[17] = 0x03; // change the descriptor count field to 3 (invalid) + hidlEcm.setToExternal(static_cast<uint8_t*>(badDescriptor), sizeof(badDescriptor)); + returnStatus = mMediaCas->processEcm(sessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::ERROR_CAS_UNKNOWN, returnStatus); + + /* + * Test MediaDescrambler error codes + */ + // setMediaCasSession should fail with an invalid session id + returnStatus = mDescramblerBase->setMediaCasSession(invalidSessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus); + + // descramble should fail without a valid session + sp<IDescrambler> descrambler; + descrambler = IDescrambler::castFrom(mDescramblerBase); + ASSERT_NE(descrambler, nullptr); + + Status descrambleStatus = Status::OK; + sp<IMemory> dataMemory; + + ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory)); + EXPECT_EQ(Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED, descrambleStatus); + + // Now set a valid session, should still fail because no valid ecm is processed + returnStatus = mDescramblerBase->setMediaCasSession(sessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory)); + EXPECT_EQ(Status::ERROR_CAS_DECRYPT, descrambleStatus); + + // Verify that requiresSecureDecoderComponent handles empty mime + EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("")); + + // Verify that requiresSecureDecoderComponent handles invalid mime + EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad")); +} + +} // anonymous namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/cas/Android.bp b/cas/Android.bp new file mode 100644 index 0000000000..8208d3d51e --- /dev/null +++ b/cas/Android.bp @@ -0,0 +1,7 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/vts/functional", + "1.0/default", + "native/1.0", +] diff --git a/cas/native/1.0/Android.bp b/cas/native/1.0/Android.bp new file mode 100644 index 0000000000..e39cab1f7b --- /dev/null +++ b/cas/native/1.0/Android.bp @@ -0,0 +1,68 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.cas.native@1.0_hal", + srcs: [ + "types.hal", + "IDescrambler.hal", + ], +} + +genrule { + name: "android.hardware.cas.native@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas.native@1.0", + srcs: [ + ":android.hardware.cas.native@1.0_hal", + ], + out: [ + "android/hardware/cas/native/1.0/types.cpp", + "android/hardware/cas/native/1.0/DescramblerAll.cpp", + ], +} + +genrule { + name: "android.hardware.cas.native@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas.native@1.0", + srcs: [ + ":android.hardware.cas.native@1.0_hal", + ], + out: [ + "android/hardware/cas/native/1.0/types.h", + "android/hardware/cas/native/1.0/hwtypes.h", + "android/hardware/cas/native/1.0/IDescrambler.h", + "android/hardware/cas/native/1.0/IHwDescrambler.h", + "android/hardware/cas/native/1.0/BnHwDescrambler.h", + "android/hardware/cas/native/1.0/BpHwDescrambler.h", + "android/hardware/cas/native/1.0/BsDescrambler.h", + ], +} + +cc_library { + name: "android.hardware.cas.native@1.0", + defaults: ["hidl-module-defaults"], + generated_sources: ["android.hardware.cas.native@1.0_genc++"], + generated_headers: ["android.hardware.cas.native@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.cas.native@1.0_genc++_headers"], + vendor_available: true, + vndk: { + enabled: true, + }, + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.cas@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.cas@1.0", + ], +} diff --git a/cas/native/1.0/IDescrambler.hal b/cas/native/1.0/IDescrambler.hal new file mode 100644 index 0000000000..4822111d2f --- /dev/null +++ b/cas/native/1.0/IDescrambler.hal @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.cas.native@1.0; + +import android.hardware.cas@1.0::IDescramblerBase; +import android.hardware.cas@1.0::Status; + +/** + * IDescrambler is the native plugin API for descrambling operations. + */ + +interface IDescrambler extends IDescramblerBase { + /** + * Descramble the data in a source SharedBuffer, described by an array of + * SubSample structures. + * + * @param scramblingControl an enumeration indicating the key that the subsamples + * were scrambled with. + * @param subSamples an array of SubSample structures describing the number of + * clear and scrambled bytes within each subsample. + * @param srcBuffer the SharedBuffer containing the source scrambled data. + * @param srcOffset the position where the source scrambled data starts at. + * @param dstBuffer the DestinationBuffer to hold the descrambled data. + * @param dstOffset the position where the descrambled data should start at. + * + * @return status the status of the call. + * @return bytesWritten number of bytes that have been successfully descrambled. + * @return detailedError a detailed message describing the error (if any). + */ + descramble(ScramblingControl scramblingControl, vec<SubSample> subSamples, + SharedBuffer srcBuffer, uint64_t srcOffset, DestinationBuffer dstBuffer, uint64_t dstOffset) + generates(Status status, uint32_t bytesWritten, string detailedError); +}; diff --git a/cas/native/1.0/types.hal b/cas/native/1.0/types.hal new file mode 100644 index 0000000000..d75338b588 --- /dev/null +++ b/cas/native/1.0/types.hal @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.cas.native@1.0; + +/** + * Enumerates the keys used to scramble the content. + */ +enum ScramblingControl : uint32_t { + UNSCRAMBLED = 0, + RESERVED = 1, + EVENKEY = 2, + ODDKEY = 3, +}; + +/** + * A subsample consists of some number of bytes of clear (unscrambled) + * data followed by a number of bytes of scrambled data. + */ +struct SubSample { + uint32_t numBytesOfClearData; + uint32_t numBytesOfEncryptedData; +}; + +/** + * SharedBuffer describes a shared buffer which is defined by a heapBase, an + * offset and a size. The offset is relative to the shared memory base for the + * memory region identified by heapBase. + */ +struct SharedBuffer { + /** + * The shared memory base handle + */ + memory heapBase; + + /** + * The offset from the shared memory base + */ + uint64_t offset; + + /** + * The size of the shared buffer in bytes + */ + uint64_t size; +}; + +/** + * A descrambling destination buffer can be either normal user-space shared + * memory for the non-secure descrambling case, or it can be a secure buffer + * which is referenced by a native-handle. The native handle is allocated + * by the vendor's buffer allocator. + */ +enum BufferType : uint32_t { + SHARED_MEMORY = 0, + NATIVE_HANDLE = 1, +}; + +struct DestinationBuffer { + /** + * The type of the buffer + */ + BufferType type; + + /** + * If type == SHARED_MEMORY, the descrambled data must be written + * to user-space non-secure shared memory. + */ + SharedBuffer nonsecureMemory; + + /** + * If type == NATIVE_HANDLE, the descrambled data must be written + * to secure memory referenced by the vendor's buffer allocator. + */ + handle secureMemory; +}; diff --git a/compatibility_matrix.26.xml b/compatibility_matrix.26.xml index 9aa54188ad..5c81f26616 100644 --- a/compatibility_matrix.26.xml +++ b/compatibility_matrix.26.xml @@ -57,7 +57,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.broadcastradio</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IBroadcastRadioFactory</name> <instance>default</instance> @@ -71,9 +71,17 @@ <instance>legacy/0</instance> </interface> </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.cas</name> + <version>1.0</version> + <interface> + <name>IMediaCasService</name> + <instance>default</instance> + </interface> + </hal> <hal format="hidl" optional="false"> <name>android.hardware.configstore</name> - <version>1.0-1</version> + <version>1.0</version> <interface> <name>ISurfaceFlingerConfigs</name> <instance>default</instance> @@ -204,16 +212,24 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.power</name> + <name>android.hardware.oemlock</name> <version>1.0</version> <interface> + <name>IOemLock</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.power</name> + <version>1.0-1</version> + <interface> <name>IPower</name> <instance>default</instance> </interface> </hal> <hal format="hidl" optional="true"> <name>android.hardware.radio</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IRadio</name> <instance>slot1</instance> @@ -256,9 +272,25 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.thermal</name> + <name>android.hardware.tetheroffload.config</name> + <version>1.0</version> + <interface> + <name>IOffloadConfig</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.tetheroffload.control</name> <version>1.0</version> <interface> + <name>IOffloadControl</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.thermal</name> + <version>1.0-1</version> + <interface> <name>IThermal</name> <instance>default</instance> </interface> @@ -281,7 +313,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.usb</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IUsb</name> <instance>default</instance> @@ -289,7 +321,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.vibrator</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IVibrator</name> <instance>default</instance> @@ -304,14 +336,30 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.wifi</name> + <name>android.hardware.weaver</name> <version>1.0</version> <interface> + <name>IWeaver</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.wifi</name> + <version>1.0-1</version> + <interface> <name>IWifi</name> <instance>default</instance> </interface> </hal> <hal format="hidl" optional="true"> + <name>android.hardware.wifi.offload</name> + <version>1.0</version> + <interface> + <name>IOffload</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> <name>android.hardware.wifi.supplicant</name> <version>1.0</version> <interface> @@ -319,7 +367,4 @@ <instance>default</instance> </interface> </hal> - <kernel version="4.9.0" /> - <kernel version="4.4.0" /> - <kernel version="3.18.0" /> </compatibility-matrix> diff --git a/compatibility_matrix.27.xml b/compatibility_matrix.27.xml new file mode 100644 index 0000000000..5c81f26616 --- /dev/null +++ b/compatibility_matrix.27.xml @@ -0,0 +1,370 @@ +<compatibility-matrix version="1.0" type="framework"> + <hal format="hidl" optional="false"> + <name>android.hardware.audio</name> + <version>2.0</version> + <interface> + <name>IDevicesFactory</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.audio.effect</name> + <version>2.0</version> + <interface> + <name>IEffectsFactory</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.automotive.evs</name> + <version>1.0</version> + <interface> + <name>IEvsEnumerator</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.automotive.vehicle</name> + <version>2.0</version> + <interface> + <name>IVehicle</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.biometrics.fingerprint</name> + <version>2.1</version> + <interface> + <name>IBiometricsFingerprint</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.bluetooth</name> + <version>1.0</version> + <interface> + <name>IBluetoothHci</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.boot</name> + <version>1.0</version> + <interface> + <name>IBootControl</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.broadcastradio</name> + <version>1.0-1</version> + <interface> + <name>IBroadcastRadioFactory</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.camera.provider</name> + <version>2.4</version> + <interface> + <name>ICameraProvider</name> + <instance>legacy/0</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.cas</name> + <version>1.0</version> + <interface> + <name>IMediaCasService</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.configstore</name> + <version>1.0</version> + <interface> + <name>ISurfaceFlingerConfigs</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.contexthub</name> + <version>1.0</version> + <interface> + <name>IContexthub</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.drm</name> + <version>1.0</version> + <interface> + <name>ICryptoFactory</name> + <instance>default</instance> + </interface> + <interface> + <name>IDrmFactory</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.dumpstate</name> + <version>1.0</version> + <interface> + <name>IDumpstateDevice</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.gatekeeper</name> + <version>1.0</version> + <interface> + <name>IGatekeeper</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.gnss</name> + <version>1.0</version> + <interface> + <name>IGnss</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.graphics.allocator</name> + <version>2.0</version> + <interface> + <name>IAllocator</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.graphics.composer</name> + <version>2.1</version> + <interface> + <name>IComposer</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.graphics.mapper</name> + <version>2.0</version> + <interface> + <name>IMapper</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.health</name> + <version>1.0</version> + <interface> + <name>IHealth</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.ir</name> + <version>1.0</version> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.keymaster</name> + <version>3.0</version> + <interface> + <name>IKeymasterDevice</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.light</name> + <version>2.0</version> + <interface> + <name>ILight</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="false"> + <name>android.hardware.media.omx</name> + <version>1.0</version> + <interface> + <name>IOmx</name> + <instance>default</instance> + </interface> + <interface> + <name>IOmxStore</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.memtrack</name> + <version>1.0</version> + <interface> + <name>IMemtrack</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.nfc</name> + <version>1.0</version> + <interface> + <name>INfc</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.oemlock</name> + <version>1.0</version> + <interface> + <name>IOemLock</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.power</name> + <version>1.0-1</version> + <interface> + <name>IPower</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.radio</name> + <version>1.0-1</version> + <interface> + <name>IRadio</name> + <instance>slot1</instance> + </interface> + <interface> + <name>ISap</name> + <instance>slot1</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.radio.deprecated</name> + <version>1.0</version> + <interface> + <name>IOemHook</name> + <instance>slot1</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.renderscript</name> + <version>1.0</version> + <interface> + <name>IDevice</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.sensors</name> + <version>1.0</version> + <interface> + <name>ISensors</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.soundtrigger</name> + <version>2.0</version> + <interface> + <name>ISoundTriggerHw</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.tetheroffload.config</name> + <version>1.0</version> + <interface> + <name>IOffloadConfig</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.tetheroffload.control</name> + <version>1.0</version> + <interface> + <name>IOffloadControl</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.thermal</name> + <version>1.0-1</version> + <interface> + <name>IThermal</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.tv.cec</name> + <version>1.0</version> + <interface> + <name>IHdmiCec</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.tv.input</name> + <version>1.0</version> + <interface> + <name>ITvInput</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.usb</name> + <version>1.0-1</version> + <interface> + <name>IUsb</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.vibrator</name> + <version>1.0-1</version> + <interface> + <name>IVibrator</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.vr</name> + <version>1.0</version> + <interface> + <name>IVr</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.weaver</name> + <version>1.0</version> + <interface> + <name>IWeaver</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.wifi</name> + <version>1.0-1</version> + <interface> + <name>IWifi</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.wifi.offload</name> + <version>1.0</version> + <interface> + <name>IOffload</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.wifi.supplicant</name> + <version>1.0</version> + <interface> + <name>ISupplicant</name> + <instance>default</instance> + </interface> + </hal> +</compatibility-matrix> diff --git a/compatibility_matrix.current.xml b/compatibility_matrix.current.xml index 9603bd6e15..5c81f26616 100644 --- a/compatibility_matrix.current.xml +++ b/compatibility_matrix.current.xml @@ -57,7 +57,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.broadcastradio</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IBroadcastRadioFactory</name> <instance>default</instance> @@ -71,9 +71,17 @@ <instance>legacy/0</instance> </interface> </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.cas</name> + <version>1.0</version> + <interface> + <name>IMediaCasService</name> + <instance>default</instance> + </interface> + </hal> <hal format="hidl" optional="false"> <name>android.hardware.configstore</name> - <version>1.0-1</version> + <version>1.0</version> <interface> <name>ISurfaceFlingerConfigs</name> <instance>default</instance> @@ -206,10 +214,14 @@ <hal format="hidl" optional="true"> <name>android.hardware.oemlock</name> <version>1.0</version> + <interface> + <name>IOemLock</name> + <instance>default</instance> + </interface> </hal> <hal format="hidl" optional="true"> <name>android.hardware.power</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IPower</name> <instance>default</instance> @@ -217,7 +229,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.radio</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IRadio</name> <instance>slot1</instance> @@ -260,9 +272,25 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.thermal</name> + <name>android.hardware.tetheroffload.config</name> + <version>1.0</version> + <interface> + <name>IOffloadConfig</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.tetheroffload.control</name> <version>1.0</version> <interface> + <name>IOffloadControl</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.thermal</name> + <version>1.0-1</version> + <interface> <name>IThermal</name> <instance>default</instance> </interface> @@ -285,7 +313,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.usb</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IUsb</name> <instance>default</instance> @@ -293,7 +321,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.vibrator</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IVibrator</name> <instance>default</instance> @@ -310,16 +338,28 @@ <hal format="hidl" optional="true"> <name>android.hardware.weaver</name> <version>1.0</version> + <interface> + <name>IWeaver</name> + <instance>default</instance> + </interface> </hal> <hal format="hidl" optional="true"> <name>android.hardware.wifi</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IWifi</name> <instance>default</instance> </interface> </hal> <hal format="hidl" optional="true"> + <name>android.hardware.wifi.offload</name> + <version>1.0</version> + <interface> + <name>IOffload</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> <name>android.hardware.wifi.supplicant</name> <version>1.0</version> <interface> @@ -327,7 +367,4 @@ <instance>default</instance> </interface> </hal> - <kernel version="4.9.0" /> - <kernel version="4.4.0" /> - <kernel version="3.18.0" /> </compatibility-matrix> diff --git a/compatibility_matrix.legacy.xml b/compatibility_matrix.legacy.xml index 6167f25eb6..5655fb97d5 100644 --- a/compatibility_matrix.legacy.xml +++ b/compatibility_matrix.legacy.xml @@ -57,7 +57,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.broadcastradio</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IBroadcastRadioFactory</name> <instance>default</instance> @@ -71,9 +71,17 @@ <instance>legacy/0</instance> </interface> </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.cas</name> + <version>1.0</version> + <interface> + <name>IMediaCasService</name> + <instance>default</instance> + </interface> + </hal> <hal format="hidl" optional="false"> <name>android.hardware.configstore</name> - <version>1.0-1</version> + <version>1.0</version> <interface> <name>ISurfaceFlingerConfigs</name> <instance>default</instance> @@ -204,16 +212,24 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.power</name> + <name>android.hardware.oemlock</name> <version>1.0</version> <interface> + <name>IOemLock</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.power</name> + <version>1.0-1</version> + <interface> <name>IPower</name> <instance>default</instance> </interface> </hal> <hal format="hidl" optional="true"> <name>android.hardware.radio</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IRadio</name> <instance>slot1</instance> @@ -256,9 +272,25 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.thermal</name> + <name>android.hardware.tetheroffload.config</name> + <version>1.0</version> + <interface> + <name>IOffloadConfig</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.tetheroffload.control</name> <version>1.0</version> <interface> + <name>IOffloadControl</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.thermal</name> + <version>1.0-1</version> + <interface> <name>IThermal</name> <instance>default</instance> </interface> @@ -281,7 +313,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.usb</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IUsb</name> <instance>default</instance> @@ -289,7 +321,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.vibrator</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IVibrator</name> <instance>default</instance> @@ -304,14 +336,30 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.wifi</name> + <name>android.hardware.weaver</name> <version>1.0</version> <interface> + <name>IWeaver</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.wifi</name> + <version>1.0-1</version> + <interface> <name>IWifi</name> <instance>default</instance> </interface> </hal> <hal format="hidl" optional="true"> + <name>android.hardware.wifi.offload</name> + <version>1.0</version> + <interface> + <name>IOffload</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> <name>android.hardware.wifi.supplicant</name> <version>1.0</version> <interface> @@ -319,7 +367,4 @@ <instance>default</instance> </interface> </hal> - <kernel version="4.9.0" /> - <kernel version="4.4.0" /> - <kernel version="3.18.0" /> </compatibility-matrix> diff --git a/configstore/1.0/default/Android.mk b/configstore/1.0/default/Android.mk new file mode 100644 index 0000000000..8b24031f4c --- /dev/null +++ b/configstore/1.0/default/Android.mk @@ -0,0 +1,34 @@ +LOCAL_PATH := $(call my-dir) + +################################################################################ +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.configstore@1.0-service +LOCAL_REQUIRED_MODULES_arm64 := configstore@1.0.policy +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_INIT_RC := android.hardware.configstore@1.0-service.rc +LOCAL_SRC_FILES:= service.cpp + +include $(LOCAL_PATH)/surfaceflinger.mk + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.configstore@1.0 \ + libhidlbase \ + libhidltransport \ + libbase \ + libhwminijail \ + liblog \ + libutils \ + +include $(BUILD_EXECUTABLE) + +# seccomp filter for configstore +ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm64)) +include $(CLEAR_VARS) +LOCAL_MODULE := configstore@1.0.policy +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy +LOCAL_SRC_FILES := seccomp_policy/configstore@1.0-$(TARGET_ARCH).policy +include $(BUILD_PREBUILT) +endif diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.cpp b/configstore/1.0/default/SurfaceFlingerConfigs.cpp index 5a040f2a89..3239274f9f 100644 --- a/configstore/1.1/default/SurfaceFlingerConfigs.cpp +++ b/configstore/1.0/default/SurfaceFlingerConfigs.cpp @@ -19,7 +19,7 @@ namespace android { namespace hardware { namespace configstore { -namespace V1_1 { +namespace V1_0 { namespace implementation { // Methods from ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs @@ -139,13 +139,10 @@ Return<void> SurfaceFlingerConfigs::startGraphicsAllocatorService( return Void(); } -// Methods from ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs -// follow. - // Methods from ::android::hidl::base::V1_0::IBase follow. } // namespace implementation -} // namespace V1_1 +} // namespace V1_0 } // namespace configstore } // namespace hardware } // namespace android diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.h b/configstore/1.0/default/SurfaceFlingerConfigs.h index 53e8ae8714..32e5fc3928 100644 --- a/configstore/1.1/default/SurfaceFlingerConfigs.h +++ b/configstore/1.0/default/SurfaceFlingerConfigs.h @@ -1,17 +1,17 @@ -#ifndef ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H -#define ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H +#ifndef ANDROID_HARDWARE_CONFIGSTORE_V1_0_SURFACEFLINGERCONFIGS_H +#define ANDROID_HARDWARE_CONFIGSTORE_V1_0_SURFACEFLINGERCONFIGS_H -#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace android { namespace hardware { namespace configstore { -namespace V1_1 { +namespace V1_0 { namespace implementation { -using ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs; +using ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::sp; @@ -32,16 +32,13 @@ struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs { Return<void> maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) override; Return<void> startGraphicsAllocatorService(startGraphicsAllocatorService_cb _hidl_cb) override; - // Methods from - // ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs follow. - // Methods from ::android::hidl::base::V1_0::IBase follow. }; } // namespace implementation -} // namespace V1_1 +} // namespace V1_0 } // namespace configstore } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H +#endif // ANDROID_HARDWARE_CONFIGSTORE_V1_0_SURFACEFLINGERCONFIGS_H diff --git a/configstore/1.0/default/android.hardware.configstore@1.0-service.rc b/configstore/1.0/default/android.hardware.configstore@1.0-service.rc new file mode 100644 index 0000000000..563d8541c3 --- /dev/null +++ b/configstore/1.0/default/android.hardware.configstore@1.0-service.rc @@ -0,0 +1,4 @@ +service configstore-hal-1-0 /vendor/bin/hw/android.hardware.configstore@1.0-service + class hal animation + user system + group system diff --git a/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy b/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy new file mode 100644 index 0000000000..43bf1fac3c --- /dev/null +++ b/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy @@ -0,0 +1,51 @@ +# Copyright (C) 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +futex: 1 +# ioctl: arg1 == BINDER_WRITE_READ +ioctl: arg1 == 0xc0306201 +# prctl: arg0 == PR_SET_NAME || arg0 == PR_SET_VMA || arg0 == PR_SET_TIMERSLACK +# || arg0 == PR_GET_NO_NEW_PRIVS # used by crash_dump +prctl: arg0 == 15 || arg0 == 0x53564d41 || arg0 == 29 || arg0 == 39 +openat: 1 +mmap: 1 +mprotect: 1 +close: 1 +getuid: 1 +read: 1 +faccessat: 1 +write: 1 +fstat: 1 +clone: 1 +munmap: 1 +lseek: 1 +sigaltstack: 1 +writev: 1 +setpriority: 1 +restart_syscall: 1 +exit: 1 +exit_group: 1 +rt_sigreturn: 1 +getrlimit: 1 +madvise: 1 +clock_gettime: 1 + +# used during process crash by crash_dump to dump process info +rt_sigprocmask: 1 +rt_sigaction: 1 +# socket: arg0 == AF_LOCAL +socket: arg0 == 1 +connect: 1 +recvmsg: 1 +rt_tgsigqueueinfo: 1 diff --git a/configstore/1.1/default/service.cpp b/configstore/1.0/default/service.cpp index 3a4cd3fd67..c9c81a07f5 100644 --- a/configstore/1.1/default/service.cpp +++ b/configstore/1.0/default/service.cpp @@ -14,25 +14,28 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.configstore@1.1-service" +#define LOG_TAG "android.hardware.configstore@1.0-service" -#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <hidl/HidlTransportSupport.h> +#include <hwminijail/HardwareMinijail.h> #include "SurfaceFlingerConfigs.h" using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; -using android::hardware::configstore::V1_1::ISurfaceFlingerConfigs; -using android::hardware::configstore::V1_1::implementation::SurfaceFlingerConfigs; +using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs; +using android::hardware::configstore::V1_0::implementation::SurfaceFlingerConfigs; +using android::hardware::SetupMinijail; using android::sp; using android::status_t; using android::OK; int main() { - // TODO(b/34857894): tune the max thread count. configureRpcThreadpool(10, true); + SetupMinijail("/vendor/etc/seccomp_policy/configstore@1.0.policy"); + sp<ISurfaceFlingerConfigs> surfaceFlingerConfigs = new SurfaceFlingerConfigs; status_t status = surfaceFlingerConfigs->registerAsService(); LOG_ALWAYS_FATAL_IF(status != OK, "Could not register ISurfaceFlingerConfigs"); diff --git a/configstore/1.1/default/surfaceflinger.mk b/configstore/1.0/default/surfaceflinger.mk index 3ce768a63e..3ce768a63e 100644 --- a/configstore/1.1/default/surfaceflinger.mk +++ b/configstore/1.0/default/surfaceflinger.mk diff --git a/configstore/1.1/Android.bp b/configstore/1.1/Android.bp deleted file mode 100644 index 3f8d580153..0000000000 --- a/configstore/1.1/Android.bp +++ /dev/null @@ -1,170 +0,0 @@ -// This file is autogenerated by hidl-gen. Do not edit manually. - -filegroup { - name: "android.hardware.configstore@1.1_hal", - srcs: [ - "ISurfaceFlingerConfigs.hal", - ], -} - -genrule { - name: "android.hardware.configstore@1.1_genc++", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.configstore@1.1", - srcs: [ - ":android.hardware.configstore@1.1_hal", - ], - out: [ - "android/hardware/configstore/1.1/SurfaceFlingerConfigsAll.cpp", - ], -} - -genrule { - name: "android.hardware.configstore@1.1_genc++_headers", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.configstore@1.1", - srcs: [ - ":android.hardware.configstore@1.1_hal", - ], - out: [ - "android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h", - "android/hardware/configstore/1.1/IHwSurfaceFlingerConfigs.h", - "android/hardware/configstore/1.1/BnHwSurfaceFlingerConfigs.h", - "android/hardware/configstore/1.1/BpHwSurfaceFlingerConfigs.h", - "android/hardware/configstore/1.1/BsSurfaceFlingerConfigs.h", - ], -} - -cc_library { - name: "android.hardware.configstore@1.1", - defaults: ["hidl-module-defaults"], - generated_sources: ["android.hardware.configstore@1.1_genc++"], - generated_headers: ["android.hardware.configstore@1.1_genc++_headers"], - export_generated_headers: ["android.hardware.configstore@1.1_genc++_headers"], - vendor_available: true, - vndk: { - enabled: true, - }, - shared_libs: [ - "libhidlbase", - "libhidltransport", - "libhwbinder", - "liblog", - "libutils", - "libcutils", - "android.hardware.configstore@1.0", - ], - export_shared_lib_headers: [ - "libhidlbase", - "libhidltransport", - "libhwbinder", - "libutils", - "android.hardware.configstore@1.0", - ], -} - -genrule { - name: "android.hardware.configstore-V1.1-java_gen_java", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Ljava -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.configstore@1.1", - srcs: [ - ":android.hardware.configstore@1.1_hal", - ], - out: [ - "android/hardware/configstore/V1_1/ISurfaceFlingerConfigs.java", - ], -} - -java_library { - name: "android.hardware.configstore-V1.1-java", - no_framework_libs: true, - defaults: ["hidl-java-module-defaults"], - srcs: [":android.hardware.configstore-V1.1-java_gen_java"], - libs: [ - "hwbinder", - "android.hardware.configstore-V1.0-java", - "android.hidl.base-V1.0-java", - ] -} - -// This package does not export any types. Not creating java constants export. - - -genrule { - name: "android.hardware.configstore@1.1-adapter-helper_genc++", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Lc++-adapter-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.configstore@1.1", - srcs: [ - ":android.hardware.configstore@1.1_hal", - ], - out: [ - "android/hardware/configstore/1.1/ASurfaceFlingerConfigs.cpp", - ], -} - -genrule { - name: "android.hardware.configstore@1.1-adapter-helper_genc++_headers", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Lc++-adapter-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.configstore@1.1", - srcs: [ - ":android.hardware.configstore@1.1_hal", - ], - out: [ - "android/hardware/configstore/1.1/ASurfaceFlingerConfigs.h", - ], -} - -cc_library { - name: "android.hardware.configstore@1.1-adapter-helper", - defaults: ["hidl-module-defaults"], - generated_sources: ["android.hardware.configstore@1.1-adapter-helper_genc++"], - generated_headers: ["android.hardware.configstore@1.1-adapter-helper_genc++_headers"], - export_generated_headers: ["android.hardware.configstore@1.1-adapter-helper_genc++_headers"], - vendor_available: true, - shared_libs: [ - "libhidlbase", - "libhidltransport", - "libhwbinder", - "liblog", - "libutils", - "libcutils", - "libhidladapter", - "android.hardware.configstore@1.0", - "android.hardware.configstore@1.1", - "android.hardware.configstore@1.0-adapter-helper", - "android.hidl.base@1.0-adapter-helper", - ], - export_shared_lib_headers: [ - "libhidlbase", - "libhidltransport", - "libhwbinder", - "libutils", - "libhidladapter", - "android.hardware.configstore@1.0", - "android.hardware.configstore@1.1", - "android.hardware.configstore@1.0-adapter-helper", - "android.hidl.base@1.0-adapter-helper", - ], -} - -genrule { - name: "android.hardware.configstore@1.1-adapter_genc++", - tools: ["hidl-gen"], - cmd: "$(location hidl-gen) -o $(genDir) -Lc++-adapter-main -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.configstore@1.1", - out: ["main.cpp"] -} - -cc_test { - name: "android.hardware.configstore@1.1-adapter", - defaults: ["hidl-module-defaults"], - shared_libs: [ - "libhidladapter", - "libhidlbase", - "libhidltransport", - "libutils", - "android.hardware.configstore@1.0", - "android.hardware.configstore@1.1", - "android.hardware.configstore@1.1-adapter-helper", - ], - generated_sources: ["android.hardware.configstore@1.1-adapter_genc++"], -} diff --git a/configstore/1.1/ISurfaceFlingerConfigs.hal b/configstore/1.1/ISurfaceFlingerConfigs.hal deleted file mode 100644 index 5eacbe00ac..0000000000 --- a/configstore/1.1/ISurfaceFlingerConfigs.hal +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.1 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.configstore@1.1; - -import @1.0::ISurfaceFlingerConfigs; - -/** - * New revision of ISurfaceFlingerConfigs - */ - -interface ISurfaceFlingerConfigs extends @1.0::ISurfaceFlingerConfigs { -}; diff --git a/configstore/1.1/default/Android.mk b/configstore/1.1/default/Android.mk deleted file mode 100644 index a3a1041223..0000000000 --- a/configstore/1.1/default/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -################################################################################ -include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.configstore@1.1-service -LOCAL_PROPRIETARY_MODULE := true -LOCAL_MODULE_CLASS := EXECUTABLES -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_INIT_RC := android.hardware.configstore@1.1-service.rc -LOCAL_SRC_FILES:= service.cpp - -include $(LOCAL_PATH)/surfaceflinger.mk - -LOCAL_SHARED_LIBRARIES := \ - libhidlbase \ - libhidltransport \ - libbase \ - liblog \ - libutils \ - android.hardware.configstore@1.0 \ - android.hardware.configstore@1.1 - -include $(BUILD_EXECUTABLE) diff --git a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc b/configstore/1.1/default/android.hardware.configstore@1.1-service.rc deleted file mode 100644 index 018ef102d0..0000000000 --- a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc +++ /dev/null @@ -1,4 +0,0 @@ -service configstore-hal /vendor/bin/hw/android.hardware.configstore@1.1-service - class hal animation - user system - group system diff --git a/configstore/1.1/vts/functional/VtsHalConfigstoreV1_1TargetTest.cpp b/configstore/1.1/vts/functional/VtsHalConfigstoreV1_1TargetTest.cpp deleted file mode 100644 index bd3da4c433..0000000000 --- a/configstore/1.1/vts/functional/VtsHalConfigstoreV1_1TargetTest.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "ConfigstoreHidlHalTest" - -#include <VtsHalHidlTargetTestBase.h> -#include <android-base/logging.h> -#include <android/hardware/configstore/1.0/types.h> -#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> -#include <unistd.h> - -using ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs; -using ::android::sp; - -#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) -#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) - -class ConfigstoreHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - sp<ISurfaceFlingerConfigs> sfConfigs; - - virtual void SetUp() override { - sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<ISurfaceFlingerConfigs>(); - ASSERT_NE(sfConfigs, nullptr); - } - - virtual void TearDown() override {} -}; - -/** - * Placeholder testcase. - */ -TEST_F(ConfigstoreHidlTest, Test) { - ASSERT_TRUE(true); -} - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} diff --git a/configstore/Android.bp b/configstore/Android.bp index 4a783c3d7e..ba3e62e29b 100644 --- a/configstore/Android.bp +++ b/configstore/Android.bp @@ -2,7 +2,5 @@ subdirs = [ "1.0", "1.0/vts/functional", - "1.1", - "1.1/vts/functional", "utils", ] diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp index bf459005b4..3626a0948f 100644 --- a/contexthub/1.0/default/Contexthub.cpp +++ b/contexthub/1.0/default/Contexthub.cpp @@ -440,18 +440,15 @@ Return<Result> Contexthub::loadNanoApp(uint32_t hubId, // Data from the nanoapp header is passed through HIDL as explicit fields, // but the legacy HAL expects it prepended to the binary, therefore we must // reconstruct it here prior to passing to the legacy HAL. - uint32_t targetChreApiVersion = - (appBinary.targetChreApiMajorVersion << 24) | - (appBinary.targetChreApiMinorVersion << 16); const struct nano_app_binary_t header = { .header_version = htole32(1), - .magic = htole32(NANOAPP_MAGIC), - .app_id.id = htole64(appBinary.appId), - .app_version = htole32(appBinary.appVersion), - .flags = htole32(appBinary.flags), - .hw_hub_type = htole64(0), - .reserved[0] = htole32(targetChreApiVersion), - .reserved[1] = 0, + .magic = htole32(NANOAPP_MAGIC), + .app_id.id = htole64(appBinary.appId), + .app_version = htole32(appBinary.appVersion), + .flags = htole32(appBinary.flags), + .hw_hub_type = htole64(0), + .target_chre_api_major_version = appBinary.targetChreApiMajorVersion, + .target_chre_api_minor_version = appBinary.targetChreApiMinorVersion, }; const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header); diff --git a/current.txt b/current.txt index a3ff61e8f2..db34c37bd9 100644 --- a/current.txt +++ b/current.txt @@ -187,13 +187,18 @@ b12ef0bdd8a4d247a8a6e960b227ed32383f2b0241f55d67fcea6eff6a6737fa android.hardwar d8f0877ae1d321c1d884c7631dfe36cab0ec8a4b2863d4b687f85d3549a63bcc android.hardware.wifi.supplicant@1.0::ISupplicantStaNetworkCallback fe3c3c2f572b72f15f8594c538b0577bd5c28722c31879cfe6231330cddb6747 android.hardware.wifi.supplicant@1.0::types -# ABI preserving changes to HALs released in Android O +# ABI preserving changes to HALs during Android O MR1 (Initial Set) +26a4dd19a71f3a28249100af29be470f80e08355165fe6a7173aaa1ef264640d android.hardware.automotive.vehicle@2.0::types +150a338ce11fcec70757c9675d83cf6a5d7b40d0c812741b91671fecce59eac9 android.hardware.broadcastradio@1.0::types +dc7e6d4f537b9943e27edc4f86c5a03bb643b18f18f866f8c3c71c0ac4ea8cbc android.hardware.broadcastradio@1.0::types 760485232f6cce07f8bb05e3475509956996b702f77415ee5bff05e2ec5a5bcc android.hardware.dumpstate@1.0::IDumpstateDevice e822cb7f4a1bdd45689c5e92ccd19a2201c20b771bd4b2ec1ae627e324591f9d android.hardware.radio@1.0::IRadioResponse +6e69adb24d7c0b0ca3a54a38c49a5625b161b3f5d5f7d6fda0befdbbfc8e9e06 android.hardware.radio@1.0::IRadioResponse 28e929b453df3d9f5060af2764e6cdb123ddb893e3e86923c877f6ff7e5f02c9 android.hardware.wifi@1.0::types +df1d7b27e644bfed0a4f606a8c44d35d45cafce82c7c648494c8a25c7cd4a949 android.hardware.wifi@1.0::types -# HALs released in Android O MR1 +# HALs released in Android O MR1 (Initial Set) 4b65763663a94a3920134011691f8fbb42ccb7b7795589efddc049a9106047d6 android.hardware.oemlock@1.0::IOemLock e02cd3722cb5e8fa51179f5defacb4f7866f903c9c7c51dc01a3148473a71525 android.hardware.oemlock@1.0::types @@ -221,5 +226,31 @@ b18caefefcc765092412285d776234fcf213b73bdf07ae1b67a5f71b2d2464e3 android.hardwar c26473e2e4a00af43e28a0ddf9002e5062a7d0940429e5efb6e5513a8abcb75c android.hardware.wifi@1.1::IWifi b056e1defab4071584214584057d0bc73a613081bf1152590549649d4582c13c android.hardware.wifi@1.1::IWifiChip +# ABI preserving changes to HALs during Android O MR1 (Final Set) +2d833aeed0cd1d59437aca210be590a953cf32bcb6683cd63d089762a643fb49 android.hardware.radio@1.0::IRadioResponse +05aa3de6130a9788fdb6f4d3cc57c3ea90f067e77a5e09d6a772ec7f6bca33d2 android.hardware.radio@1.1::IRadioResponse + # HALs released in Android O MR1 (Final Set) +044cb039378b8a0e36f40ff1e6ce04dc0d339da02095f968d5062a051e99d108 android.hardware.broadcastradio@1.1::types +c9699483f8cefe4f9b39b4b9609b76cab2dd1659a06188056b45797d337d4256 android.hardware.broadcastradio@1.1::IBroadcastRadio +b5d62dcd663fc4fcc977b252af59b333043bdfe73de2f11fe6d6a8bf438a0f92 android.hardware.broadcastradio@1.1::IBroadcastRadioFactory +bc7e054a6e93adebedff345aeed44549be89e6b1b6ffe071ff47a61de764b232 android.hardware.broadcastradio@1.1::ITuner +e9139fc755be578693f17c8cd1e27c75f412cfc722157bab5bf03ee68896e31d android.hardware.broadcastradio@1.1::ITunerCallback +63929c99e5755d9e09d9e0fd2527391fbb1609dda0508f5933b7943b92ae0fbc android.hardware.camera.device@3.3::types +bbcfc3f748b078f6a66c4e228084a679d30bd61bfde8bb7a91efd507b91c1bfd android.hardware.camera.device@3.3::ICameraDeviceSession +4a6998cd6793a3f9f03989c29d662589b1bc9d38826c6698c6c17864f7a814f5 android.hardware.cas@1.0::types +0e656ba1bac11461a17096ef752b69d24b000d820ef5652f0150a0f9731d54c2 android.hardware.cas@1.0::ICas +b80e1456b81f80032d0de7cb45652ac15af11e7474d520d757481ecaad796dff android.hardware.cas@1.0::ICasListener +a432d6d9200248dc2126827bcd6cdea31dd65eff39b939f64585d27d915a5857 android.hardware.cas@1.0::IDescramblerBase +86ba9c03978b79a742e990420bc5ced0673d25a939f82572996bef92621e2014 android.hardware.cas@1.0::IMediaCasService +503da837d1a67cbdb7c08a033e927e5430ae1b159d98bf72c6336b4dcc5e76f5 android.hardware.cas.native@1.0::types +619600109232ed64b827c8a11beed8070b1827ae464547d7aa146cf0473b4bca android.hardware.cas.native@1.0::IDescrambler 0a159f81359cd4f71bbe00972ee8403ea79351fb7c0cd48be72ebb3e424dbaef android.hardware.radio@1.0::types +09342041e17c429fce0034b9096d17849122111436a5f0053e7e59500e1cb89c android.hardware.media.omx@1.0::IOmxStore +246a56d37d57a47224562c9d077b4a2886ce6242b9311bd98a17325944c280d7 android.hardware.neuralnetworks@1.0::types +93eb3757ceaf21590fa4cd1d4a7dfe3b3794af5396100a6d25630879352abce9 android.hardware.neuralnetworks@1.0::IDevice +f66f9a38541bf92001d3adcce678cd7e3da2262124befb460b1c9aea9492813b android.hardware.neuralnetworks@1.0::IExecutionCallback +953607822954435874f4b81686440a604e2a88cdd2d9164c6293f3d5772510d7 android.hardware.neuralnetworks@1.0::IPreparedModel +73e03573494ba96f0e711ab7f1956c5b2d54c3da690cd7ecf4d6d0f287447730 android.hardware.neuralnetworks@1.0::IPreparedModelCallback +f4945e397b5dea41bb64518dfde59be71245d8a125fd1e0acffeb57ac7b08fed android.hardware.thermal@1.1::IThermal +c8bc853546dd55584611def2a9fa1d99f657e3366c976d2f60fe6b8aa6d2cb87 android.hardware.thermal@1.1::IThermalCallback diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk index 0cc6e71b2d..99773be385 100644 --- a/drm/1.0/default/Android.mk +++ b/drm/1.0/default/Android.mk @@ -42,6 +42,9 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_C_INCLUDES := \ hardware/interfaces/drm +LOCAL_HEADER_LIBRARIES := \ + media_plugin_headers + # TODO(b/18948909) Some legacy DRM plugins only support 32-bit. They need to be # migrated to 64-bit. Once all of a device's legacy DRM plugins support 64-bit, # that device can turn on TARGET_ENABLE_MEDIADRM_64 to build this service as diff --git a/drm/1.0/default/CryptoFactory.h b/drm/1.0/default/CryptoFactory.h index 6b1d1ffce8..86130dc367 100644 --- a/drm/1.0/default/CryptoFactory.h +++ b/drm/1.0/default/CryptoFactory.h @@ -20,7 +20,6 @@ #include <hidl/Status.h> #include <media/hardware/CryptoAPI.h> #include <PluginLoader.h> -#include <media/SharedLibrary.h> namespace android { namespace hardware { diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp index 591861aeec..fd75dbd3f9 100644 --- a/drm/1.0/default/CryptoPlugin.cpp +++ b/drm/1.0/default/CryptoPlugin.cpp @@ -51,7 +51,11 @@ namespace implementation { Return<void> CryptoPlugin::setSharedBufferBase(const hidl_memory& base, uint32_t bufferId) { - mSharedBufferMap[bufferId] = mapMemory(base); + sp<IMemory> hidlMemory = mapMemory(base); + ALOGE_IF(hidlMemory == nullptr, "mapMemory returns nullptr"); + + // allow mapMemory to return nullptr + mSharedBufferMap[bufferId] = hidlMemory; return Void(); } @@ -107,6 +111,10 @@ namespace implementation { AString detailMessage; sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId]; + if (sourceBase == nullptr) { + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr"); + return Void(); + } if (source.offset + offset + source.size > sourceBase->getSize()) { _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size"); @@ -121,6 +129,11 @@ namespace implementation { if (destination.type == BufferType::SHARED_MEMORY) { const SharedBuffer& destBuffer = destination.nonsecureMemory; sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId]; + if (destBase == nullptr) { + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr"); + return Void(); + } + if (destBuffer.offset + destBuffer.size > destBase->getSize()) { _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size"); return Void(); diff --git a/drm/1.0/default/DrmFactory.h b/drm/1.0/default/DrmFactory.h index 726bf97185..32e192db80 100644 --- a/drm/1.0/default/DrmFactory.h +++ b/drm/1.0/default/DrmFactory.h @@ -20,7 +20,6 @@ #include <hidl/Status.h> #include <media/drm/DrmAPI.h> #include <PluginLoader.h> -#include <media/SharedLibrary.h> namespace android { namespace hardware { diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp index 18aebee4a9..57678fb46c 100644 --- a/drm/1.0/vts/functional/Android.bp +++ b/drm/1.0/vts/functional/Android.bp @@ -21,29 +21,15 @@ cc_test { "drm_hal_clearkey_test.cpp", "drm_hal_vendor_test.cpp", "vendor_modules.cpp" - ], - shared_libs: [ + ], + static_libs: [ "android.hardware.drm@1.0", + "android.hardware.drm@1.0-helper", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", - "libbase", - "libcutils", - "libhidlbase", "libhidlmemory", - "libhidltransport", - "libhwbinder", - "liblog", "libnativehelper", "libssl", "libcrypto", - "libutils", - ], - static_libs: [ - "VtsHalHidlTargetTestBase", - "android.hardware.drm@1.0-helper", - ], - cflags: [ - "-O0", - "-g", ], } diff --git a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp index 84ee5dfc49..4652c76d5d 100644 --- a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp +++ b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp @@ -76,10 +76,15 @@ using std::vector; #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) #define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) -static const uint8_t kClearKeyUUID[16] = { +static const uint8_t kCommonPsshBoxUUID[16] = { 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B}; +// To be used in mpd to specify drm scheme for players +static const uint8_t kClearKeyUUID[16] = { + 0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9, + 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E}; + static const uint8_t kInvalidUUID[16] = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80}; @@ -94,10 +99,10 @@ class DrmHalClearkeyFactoryTest : public ::testing::VtsHalHidlTargetTestBase { drmFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDrmFactory>(); - ASSERT_NE(drmFactory, nullptr); + ASSERT_NE(nullptr, drmFactory.get()); cryptoFactory = ::testing::VtsHalHidlTargetTestBase::getService<ICryptoFactory>(); - ASSERT_NE(cryptoFactory, nullptr); + ASSERT_NE(nullptr, cryptoFactory.get()); } virtual void TearDown() override {} @@ -108,9 +113,12 @@ class DrmHalClearkeyFactoryTest : public ::testing::VtsHalHidlTargetTestBase { }; /** - * Ensure the factory supports the clearkey scheme UUID + * Ensure the factory supports both Common Pssh Box UUID and Clearkey Scheme UUID */ TEST_F(DrmHalClearkeyFactoryTest, ClearKeyPluginSupported) { + EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID)); + EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID)); + EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(kClearKeyUUID)); EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(kClearKeyUUID)); } @@ -158,29 +166,57 @@ TEST_F(DrmHalClearkeyFactoryTest, ValidContentTypeSupported) { } /** - * Ensure clearkey drm plugin can be created + * Ensure clearkey drm plugin can be created using Common Pssh Box UUID + */ +TEST_F(DrmHalClearkeyFactoryTest, CreateClearKeyDrmPluginUsingCommonPsshBoxUuid) { + hidl_string packageName("android.hardware.drm.test"); + auto res = drmFactory->createPlugin( + kCommonPsshBoxUUID, packageName, + [&](Status status, const sp<IDrmPlugin>& plugin) { + EXPECT_EQ(Status::OK, status); + EXPECT_NE(nullptr, plugin.get()); + }); + EXPECT_OK(res); +} + +/** + * Ensure clearkey drm plugin can be created using ClearKey UUID */ -TEST_F(DrmHalClearkeyFactoryTest, CreateClearKeyDrmPlugin) { + TEST_F(DrmHalClearkeyFactoryTest, CreateClearKeyDrmPluginUsingClearKeyUuid) { hidl_string packageName("android.hardware.drm.test"); auto res = drmFactory->createPlugin( kClearKeyUUID, packageName, [&](Status status, const sp<IDrmPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - EXPECT_NE(plugin, nullptr); + EXPECT_NE(nullptr, plugin.get()); }); EXPECT_OK(res); } /** - * Ensure clearkey crypto plugin can be created + * Ensure clearkey crypto plugin can be created using Common Pssh Box UUID */ -TEST_F(DrmHalClearkeyFactoryTest, CreateClearKeyCryptoPlugin) { +TEST_F(DrmHalClearkeyFactoryTest, CreateClearKeyCryptoPluginUsingCommonPsshBoxUuid) { + hidl_vec<uint8_t> initVec; + auto res = cryptoFactory->createPlugin( + kCommonPsshBoxUUID, initVec, + [&](Status status, const sp<ICryptoPlugin>& plugin) { + EXPECT_EQ(Status::OK, status); + EXPECT_NE(nullptr, plugin.get()); + }); + EXPECT_OK(res); +} + +/** + * Ensure clearkey crypto plugin can be created using ClearKey UUID + */ +TEST_F(DrmHalClearkeyFactoryTest, CreateClearKeyCryptoPluginUsingClearKeyUuid) { hidl_vec<uint8_t> initVec; auto res = cryptoFactory->createPlugin( kClearKeyUUID, initVec, [&](Status status, const sp<ICryptoPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - EXPECT_NE(plugin, nullptr); + EXPECT_NE(nullptr, plugin.get()); }); EXPECT_OK(res); } @@ -194,7 +230,7 @@ TEST_F(DrmHalClearkeyFactoryTest, CreateInvalidDrmPlugin) { kInvalidUUID, packageName, [&](Status status, const sp<IDrmPlugin>& plugin) { EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); - EXPECT_EQ(plugin, nullptr); + EXPECT_EQ(nullptr, plugin.get()); }); EXPECT_OK(res); } @@ -208,7 +244,7 @@ TEST_F(DrmHalClearkeyFactoryTest, CreateInvalidCryptoPlugin) { kInvalidUUID, initVec, [&](Status status, const sp<ICryptoPlugin>& plugin) { EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); - EXPECT_EQ(plugin, nullptr); + EXPECT_EQ(nullptr, plugin.get()); }); EXPECT_OK(res); } @@ -219,13 +255,13 @@ class DrmHalClearkeyPluginTest : public DrmHalClearkeyFactoryTest { // Create factories DrmHalClearkeyFactoryTest::SetUp(); - ASSERT_NE(drmFactory, nullptr); + ASSERT_NE(nullptr, drmFactory.get()); hidl_string packageName("android.hardware.drm.test"); auto res = drmFactory->createPlugin( kClearKeyUUID, packageName, [this](Status status, const sp<IDrmPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - ASSERT_NE(plugin, nullptr); + ASSERT_NE(nullptr, plugin.get()); drmPlugin = plugin; }); ASSERT_OK(res); @@ -235,7 +271,7 @@ class DrmHalClearkeyPluginTest : public DrmHalClearkeyFactoryTest { kClearKeyUUID, initVec, [this](Status status, const sp<ICryptoPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - ASSERT_NE(plugin, nullptr); + ASSERT_NE(nullptr, plugin.get()); cryptoPlugin = plugin; }); ASSERT_OK(res); @@ -326,32 +362,29 @@ hidl_vec<uint8_t> DrmHalClearkeyPluginTest::loadKeys( // full box header (version = 1 flags = 0) 0x01, 0x00, 0x00, 0x00, // system id - 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, - 0x52, 0xe2, 0xfb, 0x4b, + 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, + 0x1e, 0x52, 0xe2, 0xfb, 0x4b, // number of key ids 0x00, 0x00, 0x00, 0x01, // key id - 0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0, 0x0d, - 0x1e, 0xd0, 0x0d, 0x1e, + 0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0, + 0x0d, 0x1e, 0xd0, 0x0d, 0x1e, // size of data, must be zero 0x00, 0x00, 0x00, 0x00}; hidl_vec<uint8_t> expectedKeyRequest = { - 0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59, - 0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b, - 0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, - 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x74, - 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d}; + 0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59, 0x41, 0x59, 0x65, + 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, + 0x41, 0x4e, 0x48, 0x67, 0x22, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x22, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d}; hidl_vec<uint8_t> knownKeyResponse = { - 0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, - 0x6b, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c, - 0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, 0x41, 0x59, 0x65, - 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b, 0x56, 0x39, 0x41, - 0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b, - 0x22, 0x3a, 0x22, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65, - 0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, 0x36, 0x34, - 0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a}; + 0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6b, 0x74, 0x79, 0x22, + 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c, 0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, + 0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e, + 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x22, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, + 0x36, 0x34, 0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a}; hidl_string mimeType = "video/mp4"; KeyedVector optionalParameters; @@ -866,7 +899,7 @@ TEST_F(DrmHalClearkeyPluginTest, NotifyResolution) { sp<IMemory> DrmHalClearkeyPluginTest::getDecryptMemory(size_t size, size_t index) { sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem"); - EXPECT_NE(ashmemAllocator, nullptr); + EXPECT_NE(nullptr, ashmemAllocator.get()); hidl_memory hidlMemory; auto res = ashmemAllocator->allocate( @@ -878,6 +911,7 @@ sp<IMemory> DrmHalClearkeyPluginTest::getDecryptMemory(size_t size, EXPECT_OK(res); sp<IMemory> mappedMemory = mapMemory(hidlMemory); + EXPECT_NE(nullptr, mappedMemory.get()); EXPECT_OK(cryptoPlugin->setSharedBufferBase(hidlMemory, index)); return mappedMemory; } @@ -1078,12 +1112,11 @@ void DrmHalClearkeyDecryptTest::aes_cbc_decrypt(uint8_t* dest, uint8_t* src, */ TEST_F(DrmHalClearkeyDecryptTest, TestQueryKeyStatus) { auto sessionId = openSession(); - auto res = drmPlugin->queryKeyStatus(sessionId, - [&](Status status, KeyedVector /* info */) { - // clearkey doesn't support this method - EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); - }); + auto res = drmPlugin->queryKeyStatus( + sessionId, [&](Status status, KeyedVector /* info */) { EXPECT_EQ(Status::OK, status); }); EXPECT_OK(res); + + closeSession(sessionId); } diff --git a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp index 2e080b3050..47c6950cd7 100644 --- a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp +++ b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp @@ -113,7 +113,7 @@ class DrmHalVendorFactoryTest : public testing::TestWithParam<std::string> { test_info->test_case_name(), test_info->name(), GetParam().c_str()); - ASSERT_NE(vendorModule, nullptr); + ASSERT_NE(nullptr, vendorModule.get()); // First try the binderized service name provided by the vendor module. // If that fails, which it can on non-binderized devices, try the default @@ -123,14 +123,14 @@ class DrmHalVendorFactoryTest : public testing::TestWithParam<std::string> { if (drmFactory == nullptr) { drmFactory = VtsTestBase::getService<IDrmFactory>(); } - ASSERT_NE(drmFactory, nullptr); + ASSERT_NE(nullptr, drmFactory.get()); // Do the same for the crypto factory cryptoFactory = VtsTestBase::getService<ICryptoFactory>(name); if (cryptoFactory == nullptr) { cryptoFactory = VtsTestBase::getService<ICryptoFactory>(); } - ASSERT_NE(cryptoFactory, nullptr); + ASSERT_NE(nullptr, cryptoFactory.get()); // If drm scheme not installed skip subsequent tests if (!drmFactory->isCryptoSchemeSupported(getVendorUUID())) { @@ -239,7 +239,7 @@ TEST_P(DrmHalVendorFactoryTest, CreateVendorDrmPlugin) { getVendorUUID(), packageName, [&](Status status, const sp<IDrmPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - EXPECT_NE(plugin, nullptr); + EXPECT_NE(nullptr, plugin.get()); }); EXPECT_OK(res); } @@ -254,7 +254,7 @@ TEST_P(DrmHalVendorFactoryTest, CreateVendorCryptoPlugin) { getVendorUUID(), initVec, [&](Status status, const sp<ICryptoPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - EXPECT_NE(plugin, nullptr); + EXPECT_NE(nullptr, plugin.get()); }); EXPECT_OK(res); } @@ -269,7 +269,7 @@ TEST_P(DrmHalVendorFactoryTest, CreateInvalidDrmPlugin) { kInvalidUUID, packageName, [&](Status status, const sp<IDrmPlugin>& plugin) { EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); - EXPECT_EQ(plugin, nullptr); + EXPECT_EQ(nullptr, plugin.get()); }); EXPECT_OK(res); } @@ -284,7 +284,7 @@ TEST_P(DrmHalVendorFactoryTest, CreateInvalidCryptoPlugin) { kInvalidUUID, initVec, [&](Status status, const sp<ICryptoPlugin>& plugin) { EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); - EXPECT_EQ(plugin, nullptr); + EXPECT_EQ(nullptr, plugin.get()); }); EXPECT_OK(res); } @@ -302,7 +302,7 @@ class DrmHalVendorPluginTest : public DrmHalVendorFactoryTest { getVendorUUID(), packageName, [this](Status status, const sp<IDrmPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - ASSERT_NE(plugin, nullptr); + ASSERT_NE(nullptr, plugin.get()); drmPlugin = plugin; }); ASSERT_OK(res); @@ -312,7 +312,7 @@ class DrmHalVendorPluginTest : public DrmHalVendorFactoryTest { getVendorUUID(), initVec, [this](Status status, const sp<ICryptoPlugin>& plugin) { EXPECT_EQ(Status::OK, status); - ASSERT_NE(plugin, nullptr); + ASSERT_NE(nullptr, plugin.get()); cryptoPlugin = plugin; }); ASSERT_OK(res); @@ -1185,7 +1185,7 @@ TEST_P(DrmHalVendorPluginTest, NotifyResolution) { sp<IMemory> DrmHalVendorPluginTest::getDecryptMemory(size_t size, size_t index) { sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem"); - EXPECT_NE(ashmemAllocator, nullptr); + EXPECT_NE(nullptr, ashmemAllocator.get()); hidl_memory hidlMemory; auto res = ashmemAllocator->allocate( @@ -1198,7 +1198,7 @@ sp<IMemory> DrmHalVendorPluginTest::getDecryptMemory(size_t size, EXPECT_OK(res); sp<IMemory> mappedMemory = mapMemory(hidlMemory); - EXPECT_NE(mappedMemory, nullptr); + EXPECT_NE(nullptr, mappedMemory.get()); res = cryptoPlugin->setSharedBufferBase(hidlMemory, index); EXPECT_OK(res); return mappedMemory; diff --git a/dumpstate/1.0/vts/functional/Android.bp b/dumpstate/1.0/vts/functional/Android.bp index a1c735b1e4..1ab530fec4 100644 --- a/dumpstate/1.0/vts/functional/Android.bp +++ b/dumpstate/1.0/vts/functional/Android.bp @@ -15,18 +15,7 @@ cc_test { name: "VtsHalDumpstateV1_0TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalDumpstateV1_0TargetTest.cpp"], - shared_libs: [ - "android.hardware.dumpstate@1.0", - "libcutils", - "libhidlbase", - "liblog", - "libutils", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ] + static_libs: ["android.hardware.dumpstate@1.0"], } diff --git a/gnss/1.0/default/GnssMeasurement.cpp b/gnss/1.0/default/GnssMeasurement.cpp index 6c9b838b8d..d81f829bcd 100644 --- a/gnss/1.0/default/GnssMeasurement.cpp +++ b/gnss/1.0/default/GnssMeasurement.cpp @@ -182,7 +182,6 @@ void GnssMeasurement::gpsMeasurementCb(GpsData* gpsData) { auto clockVal = gpsData->clock; static uint32_t discontinuity_count_to_handle_old_clock_type = 0; - auto flags = clockVal.flags; gnssData.clock.leapSecond = clockVal.leap_second; /* @@ -205,7 +204,7 @@ void GnssMeasurement::gpsMeasurementCb(GpsData* gpsData) { break; case GPS_CLOCK_TYPE_GPS_TIME: // GPS time, need to convert. - flags |= GPS_CLOCK_HAS_FULL_BIAS; + clockVal.flags |= GPS_CLOCK_HAS_FULL_BIAS; clockVal.full_bias_ns = clockVal.time_ns; clockVal.time_ns = 0; gnssData.clock.hwClockDiscontinuityCount = diff --git a/gnss/1.0/default/OWNERS b/gnss/1.0/default/OWNERS new file mode 100644 index 0000000000..6c25bd7c22 --- /dev/null +++ b/gnss/1.0/default/OWNERS @@ -0,0 +1,3 @@ +wyattriley@google.com +gomo@google.com +smalkos@google.com diff --git a/gnss/1.0/vts/OWNERS b/gnss/1.0/vts/OWNERS new file mode 100644 index 0000000000..937d70aa67 --- /dev/null +++ b/gnss/1.0/vts/OWNERS @@ -0,0 +1,7 @@ +wyattriley@google.com +gomo@google.com +smalkos@google.com + +# VTS team +yim@google.com +trong@google.com
\ No newline at end of file diff --git a/graphics/composer/2.1/default/Hwc.cpp b/graphics/composer/2.1/default/Hwc.cpp index fdb4af88c2..80ec1cdc3f 100644 --- a/graphics/composer/2.1/default/Hwc.cpp +++ b/graphics/composer/2.1/default/Hwc.cpp @@ -30,6 +30,8 @@ using namespace std::chrono_literals; +using namespace std::chrono_literals; + namespace android { namespace hardware { namespace graphics { diff --git a/graphics/composer/2.1/default/IComposerCommandBuffer.h b/graphics/composer/2.1/default/IComposerCommandBuffer.h index 9ee5f4f88d..058709c5ed 100644 --- a/graphics/composer/2.1/default/IComposerCommandBuffer.h +++ b/graphics/composer/2.1/default/IComposerCommandBuffer.h @@ -92,6 +92,23 @@ public: bool writeQueue(bool* outQueueChanged, uint32_t* outCommandLength, hidl_vec<hidl_handle>* outCommandHandles) { + // After data are written to the queue, it may not be read by the + // remote reader when + // + // - the writer does not send them (because of other errors) + // - the hwbinder transaction fails + // - the reader does not read them (because of other errors) + // + // Discard the stale data here. + size_t staleDataSize = mQueue ? mQueue->availableToRead() : 0; + if (staleDataSize > 0) { + ALOGW("discarding stale data from message queue"); + CommandQueueType::MemTransaction tx; + if (mQueue->beginRead(staleDataSize, &tx)) { + mQueue->commitRead(staleDataSize); + } + } + // write data to queue, optionally resizing it if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) { if (!mQueue->write(mData.get(), mDataWritten)) { diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index 2e87144dbb..1ba7c9a1b2 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -44,33 +44,21 @@ cc_library_static { cc_test { name: "VtsHalGraphicsComposerV2_1TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"], + + // TODO(b/64437680): Assume these libs are always available on the device. shared_libs: [ - "android.hardware.graphics.allocator@2.0", - "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.mapper@2.0", - "libbase", - "libcutils", "libfmq", - "libhidlbase", - "libhidltransport", - "liblog", - "libnativehelper", "libsync", - "libutils", ], static_libs: [ - "libhwcomposer-command-buffer", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", "libVtsHalGraphicsComposerTestUtils", "libVtsHalGraphicsMapperTestUtils", - "VtsHalHidlTargetTestBase", + "libhwcomposer-command-buffer", + "libnativehelper", ], - cflags: [ - "-Wall", - "-Wextra", - "-Werror", - "-O0", - "-g", - ] } diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 0f03546558..9a749d7837 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -23,6 +23,7 @@ #include "VtsHalGraphicsMapperTestUtils.h" #include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> #include <unistd.h> #include <algorithm> @@ -50,21 +51,40 @@ using android::hardware::graphics::mapper::V2_0::IMapper; using android::hardware::graphics::mapper::V2_0::tests::Gralloc; using GrallocError = android::hardware::graphics::mapper::V2_0::Error; +// Test environment for graphics.composer +class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GraphicsComposerHidlEnvironment* Instance() { + static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<IComposer>(); } + + private: + GraphicsComposerHidlEnvironment() {} + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); +}; + class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { protected: void SetUp() override { - ASSERT_NO_FATAL_FAILURE(mComposer = std::make_unique<Composer>()); - ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); + ASSERT_NO_FATAL_FAILURE( + mComposer = std::make_unique<Composer>( + GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>())); + ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); - mComposerCallback = new GraphicsComposerCallback; - mComposerClient->registerCallback(mComposerCallback); + mComposerCallback = new GraphicsComposerCallback; + mComposerClient->registerCallback(mComposerCallback); - // assume the first display is primary and is never removed - mPrimaryDisplay = waitForFirstDisplay(); + // assume the first display is primary and is never removed + mPrimaryDisplay = waitForFirstDisplay(); - // explicitly disable vsync - mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); - mComposerCallback->setVsyncAllowed(false); + // explicitly disable vsync + mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); + mComposerCallback->setVsyncAllowed(false); } void TearDown() override { @@ -684,10 +704,11 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) { } // namespace android int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - - return status; + using android::hardware::graphics::composer::V2_1::tests::GraphicsComposerHidlEnvironment; + ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; } diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp index 1c0e4c5a32..ac6cb47a68 100644 --- a/graphics/mapper/2.0/vts/functional/Android.bp +++ b/graphics/mapper/2.0/vts/functional/Android.bp @@ -37,30 +37,16 @@ cc_library_static { cc_test { name: "VtsHalGraphicsMapperV2_0TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGraphicsMapperV2_0TargetTest.cpp"], shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", "libsync", - "libutils", + ], + static_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.common@1.0", - ], - static_libs: [ "libVtsHalGraphicsMapperTestUtils", - "VtsHalHidlTargetTestBase", + "libnativehelper", ], - cflags: [ - "-Wall", - "-Wextra", - "-Werror", - "-O0", - "-g", - ] } diff --git a/health/1.0/default/Android.bp b/health/1.0/default/Android.bp new file mode 100644 index 0000000000..cb2e87d16e --- /dev/null +++ b/health/1.0/default/Android.bp @@ -0,0 +1,20 @@ +cc_library_static { + name: "android.hardware.health@1.0-convert", + vendor_available: true, + srcs: ["convert.cpp"], + include_dirs: [ + "system/core/base/include", + ], + header_libs: ["libhealthd_headers"], + export_header_lib_headers: ["libhealthd_headers"], + export_include_dirs: ["include"], + shared_libs: [ + "libcutils", + "libhidlbase", + "libhidltransport", + "libutils", + "android.hardware.health@1.0", + ], + +} + diff --git a/health/1.0/default/Android.mk b/health/1.0/default/Android.mk index 96ff91fe7b..199ab4120d 100644 --- a/health/1.0/default/Android.mk +++ b/health/1.0/default/Android.mk @@ -4,10 +4,12 @@ include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.health@1.0-impl LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include +LOCAL_C_INCLUDES := system/core/base/include LOCAL_SRC_FILES := \ Health.cpp \ +LOCAL_HEADER_LIBRARIES := libhealthd_headers + LOCAL_SHARED_LIBRARIES := \ libcutils \ libhidlbase \ @@ -23,20 +25,6 @@ LOCAL_HAL_STATIC_LIBRARIES := libhealthd include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.health@1.0-convert -LOCAL_SRC_FILES := convert.cpp -LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libhidlbase \ - libhidltransport \ - libutils \ - android.hardware.health@1.0 \ - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_MODULE := android.hardware.health@1.0-service diff --git a/health/1.0/default/libhealthd/Android.bp b/health/1.0/default/libhealthd/Android.bp new file mode 100644 index 0000000000..ce02e28cc2 --- /dev/null +++ b/health/1.0/default/libhealthd/Android.bp @@ -0,0 +1,10 @@ +// Copyright 2016 The Android Open Source Project + +cc_library_static { + srcs: ["healthd_board_default.cpp"], + name: "libhealthd.default", + vendor_available: true, + cflags: ["-Werror"], + include_dirs: ["system/core/base/include"], + header_libs: ["libhealthd_headers"], +} diff --git a/health/1.0/default/libhealthd/Android.mk b/health/1.0/default/libhealthd/Android.mk deleted file mode 100644 index a5f4445edc..0000000000 --- a/health/1.0/default/libhealthd/Android.mk +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2016 The Android Open Source Project - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := healthd_board_default.cpp -LOCAL_MODULE := libhealthd.default -LOCAL_CFLAGS := -Werror -LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include -include $(BUILD_STATIC_LIBRARY) diff --git a/health/Android.bp b/health/Android.bp index 31e042a982..2c931e591b 100644 --- a/health/Android.bp +++ b/health/Android.bp @@ -1,6 +1,8 @@ // This is an autogenerated file, do not edit. subdirs = [ "1.0", + "1.0/default", + "1.0/default/libhealthd", "1.0/vts/functional", "2.0", ] diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp new file mode 100644 index 0000000000..7d96704f2e --- /dev/null +++ b/keymaster/3.0/vts/functional/Android.bp @@ -0,0 +1,32 @@ +// +// 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. +// + +cc_test { + name: "VtsHalKeymasterV3_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "authorization_set.cpp", + "attestation_record.cpp", + "key_param_output.cpp", + "keymaster_hidl_hal_test.cpp", + "keystore_tags_utils.cpp", + ], + static_libs: [ + "android.hardware.keymaster@3.0", + "libcrypto", + "libsoftkeymasterdevice", + ], +} diff --git a/keymaster/3.0/vts/functional/Android.mk b/keymaster/3.0/vts/functional/Android.mk deleted file mode 100644 index 40986640d4..0000000000 --- a/keymaster/3.0/vts/functional/Android.mk +++ /dev/null @@ -1,39 +0,0 @@ -# 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. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := VtsHalKeymasterV3_0TargetTest -LOCAL_SRC_FILES := \ - authorization_set.cpp \ - attestation_record.cpp \ - key_param_output.cpp \ - keymaster_hidl_hal_test.cpp \ - keystore_tags_utils.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - android.hardware.keymaster@3.0 \ - libcrypto \ - libhidlbase \ - liblog \ - libsoftkeymasterdevice \ - libutils \ - -LOCAL_STATIC_LIBRARIES := \ - VtsHalHidlTargetTestBase \ - -LOCAL_CFLAGS := -Wall -Werror - -include $(BUILD_NATIVE_TEST) diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp index 78353eaf25..3d78f45069 100644 --- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -1774,7 +1774,7 @@ TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) { .Authorization(TAG_NO_AUTH_REQUIRED) .EcdsaSigningKey(224) .Digest(Digest::NONE))); - string message(64 * 1024, 'a'); + string message(2 * 1024, 'a'); SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE)); } @@ -2607,7 +2607,7 @@ TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) { } /* - * EncryptionOperationsTest.RsaNoPaddingTooLong + * EncryptionOperationsTest.RsaNoPaddingTooLarge * * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way. */ @@ -3907,7 +3907,7 @@ TEST_F(AddEntropyTest, AddEmptyEntropy) { * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data. */ TEST_F(AddEntropyTest, AddLargeEntropy) { - EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(16 * 1024, 'a')))); + EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a')))); } typedef KeymasterHidlTest AttestationTest; diff --git a/keymaster/Android.bp b/keymaster/Android.bp index 09b8cb28d3..90a01955f3 100644 --- a/keymaster/Android.bp +++ b/keymaster/Android.bp @@ -1,4 +1,5 @@ // This is an autogenerated file, do not edit. subdirs = [ "3.0", + "3.0/vts/functional", ] diff --git a/media/omx/1.0/IOmxStore.hal b/media/omx/1.0/IOmxStore.hal index a224b0e16f..3ec053578a 100644 --- a/media/omx/1.0/IOmxStore.hal +++ b/media/omx/1.0/IOmxStore.hal @@ -39,7 +39,7 @@ interface IOmxStore { * string: arbitrary string * size: <num>x<num> * ratio: <num>:<num> - * range<type>: <type>-<type> + * range<type>: <type> | <type>-<type> * list<type>: <type> | <type>,<list<type>> */ struct Attribute { @@ -97,7 +97,7 @@ interface IOmxStore { * * Required node attributes for video nodes that are required by Android to * describe measured values for this device: - * key: 'measured-frame-rate-<width>-<height>-range', + * key: 'measured-frame-rate-<width>x<height>-range', * value-type: range<num>; where width: num, height: num * * Optional node attributes for decoders to describe supported values: @@ -111,7 +111,7 @@ interface IOmxStore { * Optional node attributes for encoders to describe supported values: * key: 'complexity-default', value-type: num * key: 'complexity-range', value-type: range<num> - * key: 'feature-bitrate-control', value-type: list<enum<VBR,CBR,CQ>> + * key: 'feature-bitrate-modes', value-type: list<enum<VBR,CBR,CQ>> * key: 'feature-intra-refresh', value-type: enum<0,1> * key: 'quality-default', value-type: num * key: 'quality-range', value-type: range<num> diff --git a/media/omx/1.0/vts/functional/audio/Android.bp b/media/omx/1.0/vts/functional/audio/Android.bp index 66fd20be2c..f517fa1d90 100644 --- a/media/omx/1.0/vts/functional/audio/Android.bp +++ b/media/omx/1.0/vts/functional/audio/Android.bp @@ -16,65 +16,19 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetAudioEncTest", - defaults: ["hidl_defaults"], - srcs: ["VtsHalMediaOmxV1_0TargetAudioEncTest.cpp", - "media_audio_hidl_test_common.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidlmemory", - "libhidltransport", - "libhwbinder", - "libnativehelper", - "libutils", - "libstagefright_foundation", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "android.hardware.media.omx@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase", - "VtsHalMediaOmxV1_0CommonUtil"], - cflags: [ - "-O0", - "-g", - ], - include_dirs: [ - "frameworks/native/include/media/openmax/", - "hardware/interfaces/media/omx/1.0/vts/functional/common", + defaults: ["VtsHalMediaOmxV1_0Defaults"], + srcs: [ + "VtsHalMediaOmxV1_0TargetAudioEncTest.cpp", + "media_audio_hidl_test_common.cpp" ], } cc_test { name: "VtsHalMediaOmxV1_0TargetAudioDecTest", - defaults: ["hidl_defaults"], - srcs: ["VtsHalMediaOmxV1_0TargetAudioDecTest.cpp", - "media_audio_hidl_test_common.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidlmemory", - "libhidltransport", - "libhwbinder", - "libnativehelper", - "libutils", - "libstagefright_foundation", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "android.hardware.media.omx@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase", - "VtsHalMediaOmxV1_0CommonUtil"], - cflags: [ - "-O0", - "-g", - ], - include_dirs: [ - "frameworks/native/include/media/openmax/", - "hardware/interfaces/media/omx/1.0/vts/functional/common", + defaults: ["VtsHalMediaOmxV1_0Defaults"], + srcs: [ + "VtsHalMediaOmxV1_0TargetAudioDecTest.cpp", + "media_audio_hidl_test_common.cpp" ], } diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp index 336cab4832..38cdcd6508 100644 --- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp @@ -15,6 +15,10 @@ */ #define LOG_TAG "media_omx_hidl_audio_dec_test" +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include <android-base/logging.h> #include <android/hardware/media/omx/1.0/IOmx.h> @@ -161,6 +165,7 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { this->omxNode = _nl; }) .isOk()); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; struct StringToName { @@ -171,7 +176,7 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { {"mp3", mp3}, {"amrnb", amrnb}, {"amrwb", amrwb}, {"aac", aac}, {"vorbis", vorbis}, {"opus", opus}, {"pcm", pcm}, {"g711alaw", g711alaw}, {"g711mlaw", g711mlaw}, - {"gsm", gsm}, {"raw", raw}, + {"gsm", gsm}, {"raw", raw}, {"flac", flac}, }; const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]); @@ -204,6 +209,7 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { {g711mlaw, OMX_AUDIO_CodingG711}, {gsm, OMX_AUDIO_CodingGSMFR}, {raw, OMX_AUDIO_CodingPCM}, + {flac, OMX_AUDIO_CodingFLAC}, }; static const size_t kNumCompToCoding = sizeof(kCompToCoding) / sizeof(kCompToCoding[0]); @@ -219,11 +225,15 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { framesReceived = 0; timestampUs = 0; timestampDevTest = false; - if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; + if (disableTest) std::cout << "[ WARN ] Test Disabled \n"; } virtual void TearDown() override { if (omxNode != nullptr) { + // If you have encountered a fatal failure, it is possible that + // freeNode() will not go through. Instead of hanging the app. + // let it pass through and report errors + if (::testing::Test::HasFatalFailure()) return; EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } @@ -263,9 +273,8 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(tsHit, true) << "TimeStamp not recognized"; } else { - std::cerr - << "[ ] Warning ! Received non-zero " - "output / TimeStamp not recognized \n"; + std::cout << "[ INFO ] Received non-zero " + "output / TimeStamp not recognized \n"; } } } @@ -301,6 +310,7 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { g711mlaw, gsm, raw, + flac, unknown_comp, }; @@ -418,6 +428,9 @@ void getInputChannelInfo(sp<IOmxNode> omxNode, OMX_U32 kPortIndexInput, ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); *nChannels = param.nChannels; + // NOTE: For amrnb sample rate is 8k and amrwb sample rate is 16k. + // There is no nSampleRate field in OMX_AUDIO_PARAM_AMRTYPE. Just + // return 8k to avoid returning uninit variable. *nSampleRate = 8000; break; } @@ -431,6 +444,16 @@ void getInputChannelInfo(sp<IOmxNode> omxNode, OMX_U32 kPortIndexInput, *nSampleRate = param.nSampleRate; break; } + case OMX_AUDIO_CodingFLAC: { + OMX_AUDIO_PARAM_FLACTYPE param; + status = getPortParam(omxNode, OMX_IndexParamAudioFlac, + kPortIndexInput, ¶m); + ASSERT_EQ(status, + ::android::hardware::media::omx::V1_0::Status::OK); + *nChannels = param.nChannels; + *nSampleRate = param.nSampleRate; + break; + } default: ASSERT_TRUE(false); break; @@ -472,6 +495,9 @@ void GetURLForComponent(AudioDecHidlTest::standardComp comp, char* mURL, "bbb_gsm_1ch_8khz_13kbps.info"}, {AudioDecHidlTest::standardComp::raw, "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le.info"}, + {AudioDecHidlTest::standardComp::flac, + "bbb_flac_stereo_680kbps_48000hz.flac", + "bbb_flac_stereo_680kbps_48000hz.info"}, }; for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) { @@ -530,13 +556,13 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, // set Port Params int32_t nChannels; int32_t nSampleRate; - getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels, - &nSampleRate); + ASSERT_NO_FATAL_FAILURE(getInputChannelInfo( + omxNode, kPortIndexInput, eEncoding, &nChannels, &nSampleRate)); // Configure output port // SPECIAL CASE: Soft Vorbis, Opus and Raw Decoders do not offer way - // to - // configure output PCM port. The port undergoes auto configuration - // internally basing on parsed elementary stream information. + // to configure output PCM port. The port undergoes auto + // configuration internally basing on parsed elementary stream + // information. if (comp != AudioDecHidlTest::standardComp::vorbis && comp != AudioDecHidlTest::standardComp::opus && comp != AudioDecHidlTest::standardComp::raw) { @@ -545,9 +571,8 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, nSampleRate); } - // If you can disable a port, then you should be able to - // enable - // it as well + // If you can disable a port, then you should be able to enable it + // as well status = omxNode->sendCommand( toRawCommandType(OMX_CommandPortEnable), kPortIndexOutput); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); @@ -558,7 +583,8 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); - allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE( + allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput)); status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); @@ -568,14 +594,14 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, // dispatch output buffers for (size_t i = 0; i < oBuffer->size(); i++) { - dispatchOutputBuffer(omxNode, oBuffer, i); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, i)); } } else { ASSERT_TRUE(false); } } else { - EXPECT_TRUE(false); - return; + ASSERT_TRUE(false); } } @@ -588,18 +614,19 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, AudioDecHidlTest::standardComp comp) { android::hardware::media::omx::V1_0::Status status; Message msg; - int timeOut = TIMEOUT_COUNTER; + int timeOut = TIMEOUT_COUNTER_Q; while (timeOut--) { size_t i = 0; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); if (status == android::hardware::media::omx::V1_0::Status::OK) { - EXPECT_EQ(msg.type, Message::Type::EVENT); + ASSERT_EQ(msg.type, Message::Type::EVENT); packedArgs audioArgs = {eEncoding, comp}; - portReconfiguration(omxNode, observer, iBuffer, oBuffer, - kPortIndexInput, kPortIndexOutput, msg, - PortMode::PRESET_BYTE_BUFFER, &audioArgs); + ASSERT_NO_FATAL_FAILURE( + portReconfiguration(omxNode, observer, iBuffer, oBuffer, + kPortIndexInput, kPortIndexOutput, msg, + PortMode::PRESET_BYTE_BUFFER, &audioArgs)); } // status == TIMED_OUT, it could be due to process time being large // than DEFAULT_TIMEOUT or component needs output buffers to start @@ -612,9 +639,10 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, // Dispatch an output buffer assuming outQueue.empty() is true size_t index; if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index)); + timeOut = TIMEOUT_COUNTER_Q; } - timeOut--; } } @@ -628,51 +656,29 @@ void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, AudioDecHidlTest::standardComp comp, bool signalEOS = true) { android::hardware::media::omx::V1_0::Status status; Message msg; - - // dispatch output buffers - for (size_t i = 0; i < oBuffer->size(); i++) { - dispatchOutputBuffer(omxNode, oBuffer, i); - } - // dispatch input buffers + size_t index; uint32_t flags = 0; int frameID = offset; - for (size_t i = 0; (i < iBuffer->size()) && (frameID < (int)Info->size()) && - (frameID < (offset + range)); - i++) { - char* ipBuffer = static_cast<char*>( - static_cast<void*>((*iBuffer)[i].mMemory->getPointer())); - ASSERT_LE((*Info)[frameID].bytesCount, - static_cast<int>((*iBuffer)[i].mMemory->getSize())); - eleStream.read(ipBuffer, (*Info)[frameID].bytesCount); - ASSERT_EQ(eleStream.gcount(), (*Info)[frameID].bytesCount); - flags = (*Info)[frameID].flags; - if (signalEOS && ((frameID == (int)Info->size() - 1) || - (frameID == (offset + range - 1)))) - flags |= OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, i, (*Info)[frameID].bytesCount, - flags, (*Info)[frameID].timestamp); - frameID++; - } + int timeOut = TIMEOUT_COUNTER_Q; + bool iQueued, oQueued; - int timeOut = TIMEOUT_COUNTER; - bool stall = false; while (1) { + iQueued = oQueued = false; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); // Port Reconfiguration if (status == android::hardware::media::omx::V1_0::Status::OK && msg.type == Message::Type::EVENT) { packedArgs audioArgs = {eEncoding, comp}; - portReconfiguration(omxNode, observer, iBuffer, oBuffer, - kPortIndexInput, kPortIndexOutput, msg, - PortMode::PRESET_BYTE_BUFFER, &audioArgs); + ASSERT_NO_FATAL_FAILURE( + portReconfiguration(omxNode, observer, iBuffer, oBuffer, + kPortIndexInput, kPortIndexOutput, msg, + PortMode::PRESET_BYTE_BUFFER, &audioArgs)); } if (frameID == (int)Info->size() || frameID == (offset + range)) break; // Dispatch input buffer - size_t index = 0; if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) { char* ipBuffer = static_cast<char*>( static_cast<void*>((*iBuffer)[index].mMemory->getPointer())); @@ -681,28 +687,33 @@ void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, eleStream.read(ipBuffer, (*Info)[frameID].bytesCount); ASSERT_EQ(eleStream.gcount(), (*Info)[frameID].bytesCount); flags = (*Info)[frameID].flags; + // Indicate to omx core that the buffer contains a full frame worth + // of data + flags |= OMX_BUFFERFLAG_ENDOFFRAME; + // Indicate the omx core that this is the last buffer it needs to + // process if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1)))) flags |= OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, index, - (*Info)[frameID].bytesCount, flags, - (*Info)[frameID].timestamp); + ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer( + omxNode, iBuffer, index, (*Info)[frameID].bytesCount, flags, + (*Info)[frameID].timestamp)); frameID++; - stall = false; - } else - stall = true; + iQueued = true; + } + // Dispatch output buffer if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); - stall = false; - } else - stall = true; - if (stall) - timeOut--; + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index)); + oQueued = true; + } + // Reset Counters when either input or output buffer is dispatched + if (iQueued || oQueued) + timeOut = TIMEOUT_COUNTER_Q; else - timeOut = TIMEOUT_COUNTER; + timeOut--; if (timeOut == 0) { - EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; - break; + ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite"; } } } @@ -717,7 +728,7 @@ TEST_F(AudioDecHidlTest, SetRole) { } // port format enumeration -TEST_F(AudioDecHidlTest, DISABLED_EnumeratePortFormat) { +TEST_F(AudioDecHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; @@ -766,13 +777,13 @@ TEST_F(AudioDecHidlTest, DecodeTest) { int bytesCount = 0; uint32_t flags = 0; uint32_t timestamp = 0; - timestampDevTest = true; + timestampDevTest = false; while (1) { if (!(eleInfo >> bytesCount)) break; eleInfo >> flags; eleInfo >> timestamp; Info.push_back({bytesCount, flags, timestamp}); - if (flags != OMX_BUFFERFLAG_CODECCONFIG) + if (timestampDevTest && (flags != OMX_BUFFERFLAG_CODECCONFIG)) timestampUslist.push_back(timestamp); } eleInfo.close(); @@ -784,8 +795,8 @@ TEST_F(AudioDecHidlTest, DecodeTest) { setDefaultPortParam(omxNode, kPortIndexInput, eEncoding, 1, 8000, OMX_AUDIO_PCMModeLinear, OMX_NumericalDataSigned, 32); - getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels, - &nSampleRate); + ASSERT_NO_FATAL_FAILURE(getInputChannelInfo( + omxNode, kPortIndexInput, eEncoding, &nChannels, &nSampleRate)); // Configure output port // SPECIAL CASE: Soft Vorbis, Opus and Raw Decoders do not offer way to // configure output PCM port. The port undergoes auto configuration @@ -798,36 +809,37 @@ TEST_F(AudioDecHidlTest, DecodeTest) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // Port Reconfiguration eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, eleStream, &Info, 0, - (int)Info.size(), compName); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, (int)Info.size(), compName)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, compName); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, + kPortIndexInput, kPortIndexOutput, compName)); packedArgs audioArgs = {eEncoding, compName}; - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, nullptr, - portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs); - EXPECT_EQ(timestampUslist.empty(), true); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, nullptr, + portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs)); + if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true); // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // end of sequence test -// SPECIAL CASE; Sending Empty input EOS buffer is not supported across all -// components. For instance soft vorbis and soft opus expects CSD buffers at -// the start. Disabling this test for now. We shall revisit this at a later -// stage -TEST_F(AudioDecHidlTest, DISABLED_EOSTest_M) { +TEST_F(AudioDecHidlTest, EOSTest_M) { description("Test end of stream monkeying"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; @@ -849,8 +861,8 @@ TEST_F(AudioDecHidlTest, DISABLED_EOSTest_M) { setDefaultPortParam(omxNode, kPortIndexInput, eEncoding, 1, 8000, OMX_AUDIO_PCMModeLinear, OMX_NumericalDataSigned, 32); - getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels, - &nSampleRate); + ASSERT_NO_FATAL_FAILURE(getInputChannelInfo( + omxNode, kPortIndexInput, eEncoding, &nChannels, &nSampleRate)); // Configure output port // SPECIAL CASE: Soft Vorbis, Opus and Raw Decoders do not offer way to // configure output PCM port. The port undergoes auto configuration @@ -863,26 +875,31 @@ TEST_F(AudioDecHidlTest, DISABLED_EOSTest_M) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // request EOS at the start packedArgs audioArgs = {eEncoding, compName}; - testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, nullptr, - portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, nullptr, + portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); EXPECT_GE(framesReceived, 0U); framesReceived = 0; timestampUs = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); + // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // end of sequence test @@ -928,8 +945,8 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { setDefaultPortParam(omxNode, kPortIndexInput, eEncoding, 1, 8000, OMX_AUDIO_PCMModeLinear, OMX_NumericalDataSigned, 32); - getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels, - &nSampleRate); + ASSERT_NO_FATAL_FAILURE(getInputChannelInfo( + omxNode, kPortIndexInput, eEncoding, &nChannels, &nSampleRate)); // Configure output port // SPECIAL CASE: Soft Vorbis, Opus and Raw Decoders do not offer way to // configure output PCM port. The port undergoes auto configuration @@ -942,10 +959,11 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // request EOS for thumbnail // signal EOS flag with last frame @@ -953,17 +971,19 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { while (!(Info[i].flags & OMX_BUFFERFLAG_SYNCFRAME)) i++; eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, eleStream, &Info, 0, i + 1, - compName); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, i + 1, compName)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, compName); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, + kPortIndexInput, kPortIndexOutput, compName)); packedArgs audioArgs = {eEncoding, compName}; - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, nullptr, - portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, nullptr, + portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); EXPECT_GE(framesReceived, 1U); framesReceived = 0; timestampUs = 0; @@ -971,25 +991,29 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { // signal EOS flag after last frame eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, eleStream, &Info, 0, i + 1, - compName, false); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, i + 1, compName, false)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, compName); - testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, nullptr, - portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, + kPortIndexInput, kPortIndexOutput, compName)); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, nullptr, + portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); EXPECT_GE(framesReceived, 1U); framesReceived = 0; timestampUs = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // end of sequence test @@ -1035,8 +1059,8 @@ TEST_F(AudioDecHidlTest, SimpleEOSTest) { setDefaultPortParam(omxNode, kPortIndexInput, eEncoding, 1, 8000, OMX_AUDIO_PCMModeLinear, OMX_NumericalDataSigned, 32); - getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels, - &nSampleRate); + ASSERT_NO_FATAL_FAILURE(getInputChannelInfo( + omxNode, kPortIndexInput, eEncoding, &nChannels, &nSampleRate)); // Configure output port // SPECIAL CASE: Soft Vorbis, Opus and Raw Decoders do not offer way to // configure output PCM port. The port undergoes auto configuration @@ -1049,33 +1073,39 @@ TEST_F(AudioDecHidlTest, SimpleEOSTest) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // request EOS at the end eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, eleStream, &Info, 0, - (int)Info.size(), compName, false); + ASSERT_NO_FATAL_FAILURE(decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, + eEncoding, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, + (int)Info.size(), compName, false)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, compName); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, + kPortIndexInput, kPortIndexOutput, compName)); packedArgs audioArgs = {eEncoding, compName}; - testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, nullptr, - portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, nullptr, + portReconfiguration, kPortIndexInput, kPortIndexOutput, &audioArgs)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); framesReceived = 0; timestampUs = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // test input/output port flush @@ -1121,8 +1151,8 @@ TEST_F(AudioDecHidlTest, FlushTest) { setDefaultPortParam(omxNode, kPortIndexInput, eEncoding, 1, 8000, OMX_AUDIO_PCMModeLinear, OMX_NumericalDataSigned, 32); - getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels, - &nSampleRate); + ASSERT_NO_FATAL_FAILURE(getInputChannelInfo( + omxNode, kPortIndexInput, eEncoding, &nChannels, &nSampleRate)); // Configure output port // SPECIAL CASE: Soft Vorbis, Opus and Raw Decoders do not offer way to // configure output PCM port. The port undergoes auto configuration @@ -1135,10 +1165,11 @@ TEST_F(AudioDecHidlTest, FlushTest) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // Decode 128 frames and flush. here 128 is chosen to ensure there is a key // frame after this so that the below section can be convered for all @@ -1146,12 +1177,11 @@ TEST_F(AudioDecHidlTest, FlushTest) { int nFrames = 128; eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, eleStream, &Info, 0, - nFrames, compName, false); - // Note: Assumes 200 ms is enough to end any decode call that started - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, 200000); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, nFrames, compName, false)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); framesReceived = 0; // Seek to next key frame and start decoding till the end @@ -1168,20 +1198,22 @@ TEST_F(AudioDecHidlTest, FlushTest) { index++; } if (keyFrame) { - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding, - kPortIndexInput, kPortIndexOutput, eleStream, &Info, - index, Info.size() - index, compName, false); + ASSERT_NO_FATAL_FAILURE( + decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding, + kPortIndexInput, kPortIndexOutput, eleStream, &Info, + index, Info.size() - index, compName, false)); } - // Note: Assumes 200 ms is enough to end any decode call that started - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, 200000); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); framesReceived = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } int main(int argc, char** argv) { diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp index ae79e82621..953dc7507b 100644 --- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp @@ -15,6 +15,10 @@ */ #define LOG_TAG "media_omx_hidl_audio_enc_test" +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include <android-base/logging.h> #include <android/hardware/media/omx/1.0/IOmx.h> @@ -161,6 +165,7 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { this->omxNode = _nl; }) .isOk()); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; struct StringToName { @@ -206,11 +211,15 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } if (i == kNumCompToCoding) disableTest = true; eosFlag = false; - if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; + if (disableTest) std::cout << "[ WARN ] Test Disabled \n"; } virtual void TearDown() override { if (omxNode != nullptr) { + // If you have encountered a fatal failure, it is possible that + // freeNode() will not go through. Instead of hanging the app. + // let it pass through and report errors + if (::testing::Test::HasFatalFailure()) return; EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } @@ -342,13 +351,13 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, android::Vector<BufferInfo>* oBuffer) { android::hardware::media::omx::V1_0::Status status; Message msg; - int timeOut = TIMEOUT_COUNTER; + int timeOut = TIMEOUT_COUNTER_Q; while (timeOut--) { size_t i = 0; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - EXPECT_EQ(status, + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); // status == TIMED_OUT, it could be due to process time being large // than DEFAULT_TIMEOUT or component needs output buffers to start @@ -361,9 +370,10 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, // Dispatch an output buffer assuming outQueue.empty() is true size_t index; if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index)); + timeOut = TIMEOUT_COUNTER_Q; } - timeOut--; } } @@ -376,43 +386,25 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, bool signalEOS = true) { android::hardware::media::omx::V1_0::Status status; Message msg; - - // dispatch output buffers - for (size_t i = 0; i < oBuffer->size(); i++) { - dispatchOutputBuffer(omxNode, oBuffer, i); - } - // dispatch input buffers + size_t index; int bytesCount = samplesPerFrame * nChannels * 2; int32_t timestampIncr = (int)(((float)samplesPerFrame / nSampleRate) * 1000000); uint64_t timestamp = 0; uint32_t flags = 0; - for (size_t i = 0; i < iBuffer->size() && nFrames != 0; i++) { - char* ipBuffer = static_cast<char*>( - static_cast<void*>((*iBuffer)[i].mMemory->getPointer())); - ASSERT_LE(bytesCount, - static_cast<int>((*iBuffer)[i].mMemory->getSize())); - eleStream.read(ipBuffer, bytesCount); - if (eleStream.gcount() != bytesCount) break; - if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, flags, timestamp); - timestamp += timestampIncr; - nFrames--; - } + int timeOut = TIMEOUT_COUNTER_Q; + bool iQueued, oQueued; - int timeOut = TIMEOUT_COUNTER; - bool stall = false; while (1) { + iQueued = oQueued = false; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); if (status == android::hardware::media::omx::V1_0::Status::OK) ASSERT_TRUE(false); if (nFrames == 0) break; // Dispatch input buffer - size_t index = 0; if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) { char* ipBuffer = static_cast<char*>( static_cast<void*>((*iBuffer)[index].mMemory->getPointer())); @@ -420,27 +412,27 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, static_cast<int>((*iBuffer)[index].mMemory->getSize())); eleStream.read(ipBuffer, bytesCount); if (eleStream.gcount() != bytesCount) break; - if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, flags, - timestamp); + flags = OMX_BUFFERFLAG_ENDOFFRAME; + if (signalEOS && (nFrames == 1)) flags |= OMX_BUFFERFLAG_EOS; + ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer( + omxNode, iBuffer, index, bytesCount, flags, timestamp)); timestamp += timestampIncr; nFrames--; - stall = false; - } else - stall = true; + iQueued = true; + } // Dispatch output buffer if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); - stall = false; - } else - stall = true; - if (stall) - timeOut--; + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index)); + oQueued = true; + } + // Reset Counters when either input or output buffer is dispatched + if (iQueued || oQueued) + timeOut = TIMEOUT_COUNTER_Q; else - timeOut = TIMEOUT_COUNTER; + timeOut--; if (timeOut == 0) { - EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; - break; + ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite"; } } } @@ -455,7 +447,7 @@ TEST_F(AudioEncHidlTest, SetRole) { } // port format enumeration -TEST_F(AudioEncHidlTest, DISABLED_EnumeratePortFormat) { +TEST_F(AudioEncHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; @@ -531,31 +523,39 @@ TEST_F(AudioEncHidlTest, SimpleEncodeTest) { } setupPCMPort(omxNode, kPortIndexInput, nChannels, OMX_NumericalDataSigned, 16, nSampleRate, OMX_AUDIO_PCMModeLinear); + // Configure output port - setDefaultPortParam(omxNode, kPortIndexOutput, eEncoding, compName, - nChannels, nSampleRate, nBitRate); + ASSERT_NO_FATAL_FAILURE(setDefaultPortParam(omxNode, kPortIndexOutput, + eEncoding, compName, nChannels, + nSampleRate, nBitRate)); android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - encodeNFrames(omxNode, observer, &iBuffer, &oBuffer, 128, samplesPerFrame, - nChannels, nSampleRate, eleStream); + ASSERT_NO_FATAL_FAILURE(encodeNFrames(omxNode, observer, &iBuffer, &oBuffer, + 128, samplesPerFrame, nChannels, + nSampleRate, eleStream)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer); - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer)); + ASSERT_NO_FATAL_FAILURE( + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag)); // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } int main(int argc, char** argv) { diff --git a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp index 4c68219b47..9500094d6f 100644 --- a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp @@ -15,6 +15,10 @@ */ #define LOG_TAG "media_omx_hidl_audio_test_common" +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include <android-base/logging.h> #include <android/hardware/media/omx/1.0/IOmx.h> diff --git a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h index 08b3d9cd58..b187d28415 100644 --- a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h +++ b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h @@ -20,11 +20,6 @@ #include <media_hidl_test_common.h> /* - * Random Index used for monkey testing while get/set parameters - */ -#define RANDOM_INDEX 1729 - -/* * Common audio utils */ void enumerateProfile(sp<IOmxNode> omxNode, OMX_U32 portIndex, diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp index 93251fe89b..cdc52fb477 100755..100644 --- a/media/omx/1.0/vts/functional/common/Android.bp +++ b/media/omx/1.0/vts/functional/common/Android.bp @@ -16,18 +16,43 @@ cc_library_static { name: "VtsHalMediaOmxV1_0CommonUtil", - defaults: ["hidl_defaults"], srcs: ["media_hidl_test_common.cpp"], - shared_libs: [ - "liblog", + + header_libs: ["media_plugin_headers"], + export_header_lib_headers: ["media_plugin_headers"], + export_include_dirs: ["."], + + static_libs: [ + "VtsHalHidlTargetTestBase", "libhidlmemory", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "android.hardware.media.omx@1.0", + "android.hardware.graphics.allocator@2.0", ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ "-O0", "-g", ], - include_dirs: [ - "frameworks/native/include/media/openmax/", +} + +cc_defaults { + name: "VtsHalMediaOmxV1_0Defaults", + defaults: ["VtsHalTargetTestDefaults"], + + // Link to these statically as they are not guaranteed to be on the device. + static_libs: [ + "VtsHalMediaOmxV1_0CommonUtil", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.common@1.0", + "android.hardware.media.omx@1.0", + "android.hardware.media@1.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlmemory", + "libnativehelper", + ], + + // TODO(b/64437680): Assume these libs are always available on the device. + shared_libs: [ + "libstagefright_foundation", ], } diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp index 1f67e2b6a5..34a96a0ce7 100755..100644 --- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp @@ -15,13 +15,15 @@ */ #define LOG_TAG "media_omx_hidl_video_test_common" - #ifdef __LP64__ #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS #endif #include <android-base/logging.h> +#include <android/hardware/graphics/allocator/2.0/IAllocator.h> +#include <android/hardware/graphics/mapper/2.0/IMapper.h> +#include <android/hardware/graphics/mapper/2.0/types.h> #include <android/hardware/media/omx/1.0/IOmx.h> #include <android/hardware/media/omx/1.0/IOmxNode.h> #include <android/hardware/media/omx/1.0/IOmxObserver.h> @@ -29,7 +31,10 @@ #include <android/hidl/allocator/1.0/IAllocator.h> #include <android/hidl/memory/1.0/IMapper.h> #include <android/hidl/memory/1.0/IMemory.h> +#include <cutils/atomic.h> +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using ::android::hardware::graphics::common::V1_0::PixelFormat; using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; using ::android::hardware::media::omx::V1_0::IOmxNode; @@ -186,10 +191,157 @@ Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat( return status; } +void allocateGraphicBuffers(sp<IOmxNode> omxNode, OMX_U32 portIndex, + BufferInfo* buffer, uint32_t nFrameWidth, + uint32_t nFrameHeight, int32_t* nStride, + int format) { + android::hardware::media::omx::V1_0::Status status; + sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator = + android::hardware::graphics::allocator::V2_0::IAllocator::getService(); + ASSERT_NE(nullptr, allocator.get()); + + sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper = + android::hardware::graphics::mapper::V2_0::IMapper::getService(); + ASSERT_NE(mapper.get(), nullptr); + + android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo + descriptorInfo; + uint32_t usage; + + descriptorInfo.width = nFrameWidth; + descriptorInfo.height = nFrameHeight; + descriptorInfo.layerCount = 1; + descriptorInfo.format = static_cast<PixelFormat>(format); + descriptorInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN); + omxNode->getGraphicBufferUsage( + portIndex, + [&status, &usage](android::hardware::media::omx::V1_0::Status _s, + uint32_t _n1) { + status = _s; + usage = _n1; + }); + if (status == android::hardware::media::omx::V1_0::Status::OK) { + descriptorInfo.usage |= usage; + } + + ::android::hardware::hidl_vec<uint32_t> descriptor; + android::hardware::graphics::mapper::V2_0::Error error; + mapper->createDescriptor( + descriptorInfo, [&error, &descriptor]( + android::hardware::graphics::mapper::V2_0::Error _s, + ::android::hardware::hidl_vec<uint32_t> _n1) { + error = _s; + descriptor = _n1; + }); + ASSERT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE); + + static volatile int32_t nextId = 0; + uint64_t id = static_cast<uint64_t>(getpid()) << 32; + allocator->allocate( + descriptor, 1, + [&](android::hardware::graphics::mapper::V2_0::Error _s, uint32_t _n1, + const ::android::hardware::hidl_vec< + ::android::hardware::hidl_handle>& _n2) { + ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, + _s); + *nStride = _n1; + buffer->omxBuffer.nativeHandle = _n2[0]; + buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth; + buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight; + buffer->omxBuffer.attr.anwBuffer.stride = _n1; + buffer->omxBuffer.attr.anwBuffer.format = descriptorInfo.format; + buffer->omxBuffer.attr.anwBuffer.usage = descriptorInfo.usage; + buffer->omxBuffer.attr.anwBuffer.layerCount = + descriptorInfo.layerCount; + buffer->omxBuffer.attr.anwBuffer.id = + id | static_cast<uint32_t>(android_atomic_inc(&nextId)); + }); +} + +// allocate buffers needed on a component port +void allocateBuffer(sp<IOmxNode> omxNode, BufferInfo* buffer, OMX_U32 portIndex, + OMX_U32 nBufferSize, PortMode portMode) { + android::hardware::media::omx::V1_0::Status status; + + if (portMode == PortMode::PRESET_SECURE_BUFFER) { + buffer->owner = client; + buffer->omxBuffer.type = CodecBuffer::Type::NATIVE_HANDLE; + omxNode->allocateSecureBuffer( + portIndex, nBufferSize, + [&status, &buffer]( + android::hardware::media::omx::V1_0::Status _s, uint32_t id, + ::android::hardware::hidl_handle const& nativeHandle) { + status = _s; + buffer->id = id; + buffer->omxBuffer.nativeHandle = nativeHandle; + }); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + } else if (portMode == PortMode::PRESET_BYTE_BUFFER || + portMode == PortMode::DYNAMIC_ANW_BUFFER) { + sp<IAllocator> allocator = IAllocator::getService("ashmem"); + ASSERT_NE(allocator.get(), nullptr); + + buffer->owner = client; + buffer->omxBuffer.type = CodecBuffer::Type::SHARED_MEM; + buffer->omxBuffer.attr.preset.rangeOffset = 0; + buffer->omxBuffer.attr.preset.rangeLength = 0; + bool success = false; + if (portMode != PortMode::PRESET_BYTE_BUFFER) { + nBufferSize = sizeof(android::VideoNativeMetadata); + } + allocator->allocate( + nBufferSize, + [&success, &buffer](bool _s, + ::android::hardware::hidl_memory const& mem) { + success = _s; + buffer->omxBuffer.sharedMemory = mem; + }); + ASSERT_EQ(success, true); + ASSERT_EQ(buffer->omxBuffer.sharedMemory.size(), nBufferSize); + buffer->mMemory = mapMemory(buffer->omxBuffer.sharedMemory); + ASSERT_NE(buffer->mMemory, nullptr); + if (portMode == PortMode::DYNAMIC_ANW_BUFFER) { + android::VideoNativeMetadata* metaData = + static_cast<android::VideoNativeMetadata*>( + static_cast<void*>(buffer->mMemory->getPointer())); + metaData->nFenceFd = -1; + buffer->slot = -1; + } + omxNode->useBuffer( + portIndex, buffer->omxBuffer, + [&status, &buffer](android::hardware::media::omx::V1_0::Status _s, + uint32_t id) { + status = _s; + buffer->id = id; + }); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + } else if (portMode == PortMode::PRESET_ANW_BUFFER) { + OMX_PARAM_PORTDEFINITIONTYPE portDef; + status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex, + &portDef); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + int32_t nStride; + buffer->owner = client; + buffer->omxBuffer.type = CodecBuffer::Type::ANW_BUFFER; + ASSERT_NO_FATAL_FAILURE(allocateGraphicBuffers( + omxNode, portIndex, buffer, portDef.format.video.nFrameWidth, + portDef.format.video.nFrameHeight, &nStride, + portDef.format.video.eColorFormat)); + omxNode->useBuffer( + portIndex, buffer->omxBuffer, + [&status, &buffer](android::hardware::media::omx::V1_0::Status _s, + uint32_t id) { + status = _s; + buffer->id = id; + }); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + } +} + // allocate buffers needed on a component port void allocatePortBuffers(sp<IOmxNode> omxNode, android::Vector<BufferInfo>* buffArray, - OMX_U32 portIndex, PortMode portMode) { + OMX_U32 portIndex, PortMode portMode, bool allocGrap) { android::hardware::media::omx::V1_0::Status status; OMX_PARAM_PORTDEFINITIONTYPE portDef; @@ -199,70 +351,18 @@ void allocatePortBuffers(sp<IOmxNode> omxNode, &portDef); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - if (portMode == PortMode::PRESET_SECURE_BUFFER) { - for (size_t i = 0; i < portDef.nBufferCountActual; i++) { - BufferInfo buffer; - buffer.owner = client; - buffer.omxBuffer.type = CodecBuffer::Type::NATIVE_HANDLE; - omxNode->allocateSecureBuffer( - portIndex, portDef.nBufferSize, - [&status, &buffer]( - android::hardware::media::omx::V1_0::Status _s, uint32_t id, - ::android::hardware::hidl_handle const& nativeHandle) { - status = _s; - buffer.id = id; - buffer.omxBuffer.nativeHandle = nativeHandle; - }); - buffArray->push(buffer); - ASSERT_EQ(status, - ::android::hardware::media::omx::V1_0::Status::OK); - } - } else if (portMode == PortMode::PRESET_BYTE_BUFFER || - portMode == PortMode::DYNAMIC_ANW_BUFFER) { - sp<IAllocator> allocator = IAllocator::getService("ashmem"); - EXPECT_NE(allocator.get(), nullptr); - - for (size_t i = 0; i < portDef.nBufferCountActual; i++) { - BufferInfo buffer; - buffer.owner = client; - buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM; - buffer.omxBuffer.attr.preset.rangeOffset = 0; - buffer.omxBuffer.attr.preset.rangeLength = 0; - bool success = false; - if (portMode != PortMode::PRESET_BYTE_BUFFER) { - portDef.nBufferSize = sizeof(android::VideoNativeMetadata); - } - allocator->allocate( - portDef.nBufferSize, - [&success, &buffer]( - bool _s, ::android::hardware::hidl_memory const& mem) { - success = _s; - buffer.omxBuffer.sharedMemory = mem; - }); - ASSERT_EQ(success, true); - ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(), - portDef.nBufferSize); - buffer.mMemory = mapMemory(buffer.omxBuffer.sharedMemory); - ASSERT_NE(buffer.mMemory, nullptr); - if (portMode == PortMode::DYNAMIC_ANW_BUFFER) { - android::VideoNativeMetadata* metaData = - static_cast<android::VideoNativeMetadata*>( - static_cast<void*>(buffer.mMemory->getPointer())); - metaData->nFenceFd = -1; - buffer.slot = -1; - } - omxNode->useBuffer( - portIndex, buffer.omxBuffer, - [&status, &buffer]( - android::hardware::media::omx::V1_0::Status _s, - uint32_t id) { - status = _s; - buffer.id = id; - }); - buffArray->push(buffer); - ASSERT_EQ(status, - ::android::hardware::media::omx::V1_0::Status::OK); + for (size_t i = 0; i < portDef.nBufferCountActual; i++) { + BufferInfo buffer; + ASSERT_NO_FATAL_FAILURE(allocateBuffer(omxNode, &buffer, portIndex, + portDef.nBufferSize, portMode)); + if (allocGrap && portMode == PortMode::DYNAMIC_ANW_BUFFER) { + int32_t nStride; + ASSERT_NO_FATAL_FAILURE(allocateGraphicBuffers( + omxNode, portIndex, &buffer, portDef.format.video.nFrameWidth, + portDef.format.video.nFrameHeight, &nStride, + portDef.format.video.eColorFormat)); } + buffArray->push(buffer); } } @@ -273,7 +373,7 @@ void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer, android::Vector<BufferInfo>* iBuffer, android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, - PortMode* portMode) { + PortMode* portMode, bool allocGrap) { android::hardware::media::omx::V1_0::Status status; Message msg; PortMode defaultPortMode[2], *pm; @@ -292,14 +392,16 @@ void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer, ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); // allocate buffers on input port - allocatePortBuffers(omxNode, iBuffer, kPortIndexInput, pm[0]); + ASSERT_NO_FATAL_FAILURE(allocatePortBuffers( + omxNode, iBuffer, kPortIndexInput, pm[0], allocGrap)); // Dont switch states until the ports are populated status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); // allocate buffers on output port - allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput, pm[1]); + ASSERT_NO_FATAL_FAILURE(allocatePortBuffers( + omxNode, oBuffer, kPortIndexOutput, pm[1], allocGrap)); // As the ports are populated, check if the state transition is complete status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); @@ -439,6 +541,7 @@ void dispatchOutputBuffer(sp<IOmxNode> omxNode, status = omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh); break; + case PortMode::PRESET_ANW_BUFFER: case PortMode::PRESET_SECURE_BUFFER: case PortMode::PRESET_BYTE_BUFFER: t.sharedMemory = android::hardware::hidl_memory(); @@ -545,43 +648,45 @@ void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer, if (signalEOS) { if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) { // signal an empty buffer with flag set to EOS - dispatchInputBuffer(omxNode, iBuffer, i, 0, OMX_BUFFERFLAG_EOS, 0); + ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer(omxNode, iBuffer, i, 0, + OMX_BUFFERFLAG_EOS, 0)); } else { ASSERT_TRUE(false); } } - int timeOut = TIMEOUT_COUNTER; + int timeOut = TIMEOUT_COUNTER_PE; while (timeOut--) { // Dispatch all client owned output buffers to recover remaining frames while (1) { if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, i, pm[1]); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, i, pm[1])); // if dispatch is successful, perhaps there is a latency // in the component. Dont be in a haste to leave. reset timeout // counter - timeOut = TIMEOUT_COUNTER; + timeOut = TIMEOUT_COUNTER_PE; } else { break; } } Message msg; - status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); + status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_PE, iBuffer, + oBuffer); if (status == android::hardware::media::omx::V1_0::Status::OK) { if (msg.data.eventData.event == OMX_EventPortSettingsChanged) { if (fptr) { - (*fptr)(omxNode, observer, iBuffer, oBuffer, - kPortIndexInput, kPortIndexOutput, msg, pm[1], - args); + ASSERT_NO_FATAL_FAILURE((*fptr)( + omxNode, observer, iBuffer, oBuffer, kPortIndexInput, + kPortIndexOutput, msg, pm[1], args)); } else { // something unexpected happened - EXPECT_TRUE(false); + ASSERT_TRUE(false); } } else { // something unexpected happened - EXPECT_TRUE(false); + ASSERT_TRUE(false); } } if (eosFlag == true) break; diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h index 0adea14e80..bec733dc93 100644 --- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h +++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h @@ -1,5 +1,5 @@ /* - * Copyright 2016, The Android Open Source Project + * 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. @@ -33,8 +33,21 @@ #include <media/openmax/OMX_AudioExt.h> #include <media/openmax/OMX_VideoExt.h> +/* TIME OUTS (Wait time in dequeueMessage()) */ + +/* As component is switching states (loaded<->idle<->execute), dequeueMessage() + * expects the events to be received within this duration */ #define DEFAULT_TIMEOUT 100000 -#define TIMEOUT_COUNTER (10000000 / DEFAULT_TIMEOUT) +/* Time interval between successive Input/Output enqueues */ +#define DEFAULT_TIMEOUT_Q 2000 +/* While the component is amidst a process call, asynchronous commands like + * flush, change states can get delayed (at max by process call time). Instead + * of waiting on DEFAULT_TIMEOUT, we give an additional leeway. */ +#define DEFAULT_TIMEOUT_PE 500000 + +/* Breakout Timeout :: 5 sec*/ +#define TIMEOUT_COUNTER_Q (5000000 / DEFAULT_TIMEOUT_Q) +#define TIMEOUT_COUNTER_PE (5000000 / DEFAULT_TIMEOUT_PE) /* * Random Index used for monkey testing while get/set parameters @@ -120,13 +133,15 @@ struct CodecObserver : public IOmxObserver { if (it->type == android::hardware::media::omx::V1_0::Message::Type::EVENT) { *msg = *it; - msgQueue.erase(it); + if (callBack) callBack(*it, nullptr); + it = msgQueue.erase(it); // OMX_EventBufferFlag event is sent when the component has // processed a buffer with its EOS flag set. This event is // not sent by soft omx components. Vendor components can // send this. From IOMX point of view, we will ignore this // event. - if (msg->data.eventData.event == OMX_EventBufferFlag) break; + if (msg->data.eventData.event == OMX_EventBufferFlag) + continue; return ::android::hardware::media::omx::V1_0::Status::OK; } else if (it->type == android::hardware::media::omx::V1_0:: Message::Type::FILL_BUFFER_DONE) { @@ -137,7 +152,7 @@ struct CodecObserver : public IOmxObserver { it->data.bufferData.buffer) { if (callBack) callBack(*it, &(*oBuffers)[i]); oBuffers->editItemAt(i).owner = client; - msgQueue.erase(it); + it = msgQueue.erase(it); break; } } @@ -152,24 +167,22 @@ struct CodecObserver : public IOmxObserver { it->data.bufferData.buffer) { if (callBack) callBack(*it, &(*iBuffers)[i]); iBuffers->editItemAt(i).owner = client; - msgQueue.erase(it); + it = msgQueue.erase(it); break; } } EXPECT_LE(i, iBuffers->size()); } + } else { + EXPECT_TRUE(false) << "Received unexpected message"; + ++it; } - ++it; } - if (finishBy - android::ALooper::GetNowUs() < 0) - return toStatus(android::TIMED_OUT); - android::status_t err = - (timeoutUs < 0) - ? msgCondition.wait(msgLock) - : msgCondition.waitRelative( - msgLock, - (finishBy - android::ALooper::GetNowUs()) * 1000ll); - if (err == android::TIMED_OUT) return toStatus(err); + int64_t delayUs = finishBy - android::ALooper::GetNowUs(); + if (delayUs < 0) return toStatus(android::TIMED_OUT); + (timeoutUs < 0) + ? msgCondition.wait(msgLock) + : msgCondition.waitRelative(msgLock, delayUs * 1000ll); } } @@ -284,16 +297,21 @@ Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat( Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat( sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding); +void allocateBuffer(sp<IOmxNode> omxNode, BufferInfo* buffer, OMX_U32 portIndex, + OMX_U32 nBufferSize, PortMode portMode); + void allocatePortBuffers(sp<IOmxNode> omxNode, android::Vector<BufferInfo>* buffArray, OMX_U32 portIndex, - PortMode portMode = PortMode::PRESET_BYTE_BUFFER); + PortMode portMode = PortMode::PRESET_BYTE_BUFFER, + bool allocGrap = false); void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer, android::Vector<BufferInfo>* iBuffer, android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, - PortMode* portMode = nullptr); + PortMode* portMode = nullptr, + bool allocGrap = false); void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer, android::Vector<BufferInfo>* iBuffer, @@ -322,7 +340,8 @@ void dispatchInputBuffer(sp<IOmxNode> omxNode, void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer, android::Vector<BufferInfo>* iBuffer, android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput, int64_t timeoutUs = DEFAULT_TIMEOUT); + OMX_U32 kPortIndexOutput, + int64_t timeoutUs = DEFAULT_TIMEOUT_PE); typedef void (*portreconfig)(sp<IOmxNode> omxNode, sp<CodecObserver> observer, android::Vector<BufferInfo>* iBuffer, diff --git a/media/omx/1.0/vts/functional/component/Android.bp b/media/omx/1.0/vts/functional/component/Android.bp index fd3210fb91..f76b6e94fa 100644 --- a/media/omx/1.0/vts/functional/component/Android.bp +++ b/media/omx/1.0/vts/functional/component/Android.bp @@ -16,32 +16,7 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetComponentTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidlmemory", - "libhidltransport", - "libhwbinder", - "libnativehelper", - "libutils", - "libstagefright_foundation", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "android.hardware.media.omx@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase", - "VtsHalMediaOmxV1_0CommonUtil"], - cflags: [ - "-O0", - "-g", - ], - include_dirs: [ - "frameworks/native/include/media/openmax/", - "hardware/interfaces/media/omx/1.0/vts/functional/common", - ], } diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp index 2d91e8275d..d66136d212 100644 --- a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp +++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp @@ -15,6 +15,10 @@ */ #define LOG_TAG "media_omx_hidl_component_test" +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include <android-base/logging.h> #include <android/hardware/media/omx/1.0/IOmx.h> @@ -145,6 +149,7 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { this->omxNode = _nl; }) .isOk()); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; struct StringToClass { @@ -181,11 +186,15 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { strlen(gEnv->getComponent().c_str()) - suffixLen, ".secure"); } - if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; + if (disableTest) std::cout << "[ WARN ] Test Disabled \n"; } virtual void TearDown() override { if (omxNode != nullptr) { + // If you have encountered a fatal failure, it is possible that + // freeNode() will not go through. Instead of hanging the app. + // let it pass through and report errors + if (::testing::Test::HasFatalFailure()) return; EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } @@ -213,9 +222,6 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { } }; -// Random Index used for monkey testing while get/set parameters -#define RANDOM_INDEX 1729 - void initPortMode(PortMode* pm, bool isSecure, ComponentHidlTest::standardCompClass compClass) { pm[0] = PortMode::PRESET_BYTE_BUFFER; @@ -232,7 +238,6 @@ void initPortMode(PortMode* pm, bool isSecure, break; } } - return; } // test dispatch message API call @@ -293,7 +298,7 @@ TEST_F(ComponentHidlTest, DISABLED_GetPortIndices) { } // port format enumeration -TEST_F(ComponentHidlTest, DISABLED_EnumeratePortFormat) { +TEST_F(ComponentHidlTest, EnumeratePortFormat) { description("Test Component on Mandatory Port Parameters (Port Format)"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; @@ -374,7 +379,7 @@ TEST_F(ComponentHidlTest, DISABLED_SetDefaultPortParams) { kPortIndexOutput = kPortIndexInput + 1; } - for (size_t i = kPortIndexInput; i < kPortIndexOutput; i++) { + for (size_t i = kPortIndexInput; i <= kPortIndexOutput; i++) { OMX_PARAM_PORTDEFINITIONTYPE portDef; status = getPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); @@ -400,28 +405,31 @@ TEST_F(ComponentHidlTest, DISABLED_SetDefaultPortParams) { EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK); - // Edit Read-Only fields. + // Port Direction - Read Only portDef = mirror; portDef.eDir = static_cast<OMX_DIRTYPE>(RANDOM_INDEX); setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); getPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); + if (portDef.eDir != mirror.eDir) { + std::cerr << "[ ERROR ] port direction has to be read only " + "but is changeable \n"; + } EXPECT_EQ(portDef.eDir, mirror.eDir); setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &mirror); - portDef = mirror; - portDef.nBufferSize >>= 1; - setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); - getPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); - EXPECT_EQ(portDef.nBufferSize, mirror.nBufferSize); - setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &mirror); - + // Port Min BufferCount - Read Only portDef = mirror; portDef.nBufferCountMin += 1; setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); getPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); + if (portDef.nBufferCountMin != mirror.nBufferCountMin) { + std::cerr << "[ ERROR ] port Min BufferCount has to be " + "read only but is changeable \n"; + } EXPECT_EQ(portDef.nBufferCountMin, mirror.nBufferCountMin); setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &mirror); + // Port Actual BufferCount portDef = mirror; portDef.nBufferCountActual += 1; status = setPortParam(omxNode, OMX_IndexParamPortDefinition, i, @@ -432,20 +440,49 @@ TEST_F(ComponentHidlTest, DISABLED_SetDefaultPortParams) { EXPECT_EQ(portDef.nBufferCountActual, mirror.nBufferCountActual + 1); } + setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &mirror); + // Port BufferSize is although read only as per OMX-IL 1.2, android + // doesnt abide by this. + // Decrease buffer size portDef = mirror; - portDef.nBufferSize = mirror.nBufferSize << 1; - status = setPortParam(omxNode, OMX_IndexParamPortDefinition, i, - &portDef); - if (status == ::android::hardware::media::omx::V1_0::Status::OK) { - status = getPortParam(omxNode, OMX_IndexParamPortDefinition, i, - &portDef); - if (portDef.nBufferSize != mirror.nBufferSize) { - std::cout - << "[ ] Warning ! Component input port does " - "not preserve Read-Only fields \n"; + OMX_U32 nBufferSize = portDef.nBufferSize >> 1; + if (nBufferSize != 0) { + if (!strncmp(gEnv->getComponent().c_str(), "OMX.google.", 11)) { + portDef.nBufferSize = nBufferSize; + } else { + // Probable alignment requirements of vendor component + portDef.nBufferSize = ALIGN_POWER_OF_TWO(nBufferSize, 12); + nBufferSize = portDef.nBufferSize; } + } else { + ASSERT_TRUE(false) << "Unexpected buffer size"; } + setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); + getPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); + // SPECIAL CASE: For video decoder, allow configuration of input + // buffer size even if it is less than minimum requirement and + // similarly for encoder allow configuration of output port buffer + // size. + if ((compClass == video_encoder && i == kPortIndexOutput) || + (compClass == video_decoder && i == kPortIndexInput)) { + double dev = (portDef.nBufferSize / (double)nBufferSize); + dev -= 1; + if (dev < 0 || dev > 0.1) { + std::cerr << "[ ERROR ] port buffer size deviation " + "larger than expected \n"; + } + } else { + EXPECT_EQ(portDef.nBufferSize, mirror.nBufferSize); + } + setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &mirror); + + // Increase buffer size + portDef = mirror; + portDef.nBufferSize = mirror.nBufferSize << 1; + setPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); + getPortParam(omxNode, OMX_IndexParamPortDefinition, i, &portDef); + EXPECT_EQ(portDef.nBufferSize, (mirror.nBufferSize << 1)); } } } @@ -470,8 +507,10 @@ TEST_F(ComponentHidlTest, DISABLED_PopulatePort) { portBase = params.nStartPortNumber; } - sp<IAllocator> allocator = IAllocator::getService("ashmem"); - EXPECT_NE(allocator.get(), nullptr); + // set state to idle + status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), + OMX_StateIdle); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); OMX_PARAM_PORTDEFINITIONTYPE portDef; status = @@ -485,30 +524,10 @@ TEST_F(ComponentHidlTest, DISABLED_PopulatePort) { for (size_t i = 0; i < portDef.nBufferCountActual; i++) { BufferInfo buffer; - buffer.owner = client; - buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM; - buffer.omxBuffer.attr.preset.rangeOffset = 0; - buffer.omxBuffer.attr.preset.rangeLength = 0; - bool success = false; - allocator->allocate( - nBufferSize, - [&success, &buffer](bool _s, - ::android::hardware::hidl_memory const& mem) { - success = _s; - buffer.omxBuffer.sharedMemory = mem; - }); - ASSERT_EQ(success, true); - ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(), nBufferSize); - - omxNode->useBuffer( - portBase, buffer.omxBuffer, - [&status, &buffer](android::hardware::media::omx::V1_0::Status _s, - uint32_t id) { - status = _s; - buffer.id = id; - }); + ASSERT_NO_FATAL_FAILURE(allocateBuffer(omxNode, &buffer, portBase, + nBufferSize, + PortMode::PRESET_BYTE_BUFFER)); pBuffer.push(buffer); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } status = @@ -548,44 +567,52 @@ TEST_F(ComponentHidlTest, Flush) { PortMode portMode[2]; initPortMode(portMode, isSecure, compClass); status = omxNode->setPortMode(kPortIndexInput, portMode[0]); - EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); - EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // dispatch buffers for (size_t i = 0; i < oBuffer.size(); i++) { - dispatchOutputBuffer(omxNode, &oBuffer, i, portMode[1]); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, &oBuffer, i, portMode[1])); } // flush port - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); +#if 0 // TODO: Sending empty input buffers is slightly tricky. // Components sometimes process input buffers even when output buffers are // not dispatched. For instance Parsing sequence header does not require // output buffers. In such instances sending 0 size input buffers might // make component to send error events. so lets skip this aspect of testing. // dispatch buffers - // for (size_t i = 0; i < iBuffer.size(); i++) { - // dispatchInputBuffer(omxNode, &iBuffer, i, 0, 0, 0, portMode[0]); - // } - // // flush ports - // flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - // kPortIndexOutput); + for (size_t i = 0; i < iBuffer.size(); i++) { + ASSERT_NO_FATAL_FAILURE( + dispatchInputBuffer(omxNode, &iBuffer, i, 0, 0, 0, portMode[0])); + } + // flush ports + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); +#endif + // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to loaded - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } -// state transitions test -TEST_F(ComponentHidlTest, StateTransitions) { - description("Test State Transitions Loaded<->Idle<->Execute"); +// Flush test - monkeying +TEST_F(ComponentHidlTest, Flush_M) { + description("Test Flush monkeying"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; @@ -611,33 +638,267 @@ TEST_F(ComponentHidlTest, StateTransitions) { PortMode portMode[2]; initPortMode(portMode, isSecure, compClass); status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // // Flush all ports ; receive error OMX_ErrorIncorrectStateOperation + // status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), + // OMX_ALL); + // ASSERT_NE(status, android::hardware::media::omx::V1_0::Status::OK); + + // set state to idle + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode)); + + // // Flush all ports ; receive error OMX_ErrorIncorrectStateOperation + // status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), + // OMX_ALL); + // ASSERT_NE(status, android::hardware::media::omx::V1_0::Status::OK); + + // set state to executing + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); + + // dispatch buffers + for (size_t i = 0; i < oBuffer.size(); i++) { + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, &oBuffer, i, portMode[1])); + } + + // // flush invalid port, expecting OMX_ErrorBadPortIndex + // status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), + // RANDOM_INDEX); + // ASSERT_NE(status, android::hardware::media::omx::V1_0::Status::OK); + + // Flush all ports + status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), OMX_ALL); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + + for (int j = 0; j < 2; j++) { + status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_PE, &iBuffer, + &oBuffer); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(msg.type, Message::Type::EVENT); + ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); + ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush); + if (msg.data.eventData.data2 == kPortIndexInput) { + // test if client got all its buffers back + for (size_t i = 0; i < iBuffer.size(); ++i) { + EXPECT_EQ(iBuffer[i].owner, client); + } + } else if (msg.data.eventData.data2 == kPortIndexOutput) { + // test if client got all its buffers back + for (size_t i = 0; i < oBuffer.size(); ++i) { + EXPECT_EQ(oBuffer[i].owner, client); + } + } else { + EXPECT_TRUE(false) << "Bad port Index"; + } + } + + // SPECIAL CASE: When OMX_ALL is used as argument, Android OMX Core sends + // an additional flush event with argument OMX_ALL. This we believe is + // not recognized by OMX-IL Spec. So read this event and ignore it + status = + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_PE, &iBuffer, &oBuffer); + if (status == android::hardware::media::omx::V1_0::Status::OK) { + ASSERT_EQ(msg.type, Message::Type::EVENT); + ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); + ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush); + ASSERT_EQ(msg.data.eventData.data2, OMX_ALL); + } + + // set state to idle + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); + // set state to loaded + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); +} + +// test port mode configuration when the component is in various states +TEST_F(ComponentHidlTest, PortModeConfig) { + description("Test Port Mode Configuration"); + if (disableTest) return; + android::hardware::media::omx::V1_0::Status status; + uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; + Message msg; + + status = setRole(omxNode, gEnv->getRole().c_str()); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + OMX_PORT_PARAM_TYPE params; + if (compClass == audio_decoder || compClass == audio_encoder) { + status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); + } else { + status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); + } + if (status == ::android::hardware::media::omx::V1_0::Status::OK) { + ASSERT_EQ(params.nPorts, 2U); + kPortIndexInput = params.nStartPortNumber; + kPortIndexOutput = kPortIndexInput + 1; + } + + android::Vector<BufferInfo> iBuffer, oBuffer; + + // set port mode + PortMode portMode[2]; + initPortMode(portMode, isSecure, compClass); + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // set state to idle + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode)); + // Only Allow Port Mode configuration in loaded state + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // set state to executing + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); + // Only Allow Port Mode configuration in loaded state + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // set state to idle + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); + // set state to loaded + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); + + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); +} + +// state transitions test +TEST_F(ComponentHidlTest, StateTransitions) { + description("Test State Transitions Loaded<->Idle<->Execute"); + if (disableTest) return; + android::hardware::media::omx::V1_0::Status status; + uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; + OMX_U32 portBase = 0; + Message msg; + status = setRole(omxNode, gEnv->getRole().c_str()); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + OMX_PORT_PARAM_TYPE params; + if (compClass == audio_decoder || compClass == audio_encoder) { + status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms); + } else { + status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); + } + if (status == ::android::hardware::media::omx::V1_0::Status::OK) { + ASSERT_EQ(params.nPorts, 2U); + portBase = params.nStartPortNumber; + } + kPortIndexInput = portBase; + kPortIndexOutput = portBase + 1; + + android::Vector<BufferInfo> pBuffer[2]; + + // set port mode + PortMode portMode[2]; + initPortMode(portMode, isSecure, compClass); + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // set state to idle + status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), + OMX_StateIdle); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + + for (size_t j = portBase; j < portBase + 2; j++) { + pBuffer[j - portBase].clear(); + OMX_PARAM_PORTDEFINITIONTYPE def; + status = getPortParam(omxNode, OMX_IndexParamPortDefinition, j, &def); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + for (size_t i = 0; i < def.nBufferCountActual; i++) { + // Dont switch states until the ports are populated + status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, + &pBuffer[0], &pBuffer[1]); + ASSERT_EQ(status, + android::hardware::media::omx::V1_0::Status::TIMED_OUT); + + BufferInfo buffer; + ASSERT_NO_FATAL_FAILURE(allocateBuffer( + omxNode, &buffer, j, def.nBufferSize, portMode[j - portBase])); + pBuffer[j - portBase].push(buffer); + } + } + + // As the ports are populated, check if the state transition is complete + status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0], + &pBuffer[1]); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(msg.type, Message::Type::EVENT); + ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); + ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet); + ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle); + + // set state to executing + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); + // dispatch buffers + for (size_t i = 0; i < pBuffer[1].size(); i++) { + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, &pBuffer[1], i, portMode[1])); + } // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1])); +#if 0 // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); + // TODO: Sending empty input buffers is slightly tricky. // dispatch buffers - for (size_t i = 0; i < oBuffer.size(); i++) { - dispatchOutputBuffer(omxNode, &oBuffer, i, portMode[1]); + for (size_t i = 0; i < pBuffer[0].size(); i++) { + ASSERT_NO_FATAL_FAILURE( + dispatchInputBuffer(omxNode, &pBuffer[0], i, 0, 0, 0, portMode[0])); } // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); - // // set state to executing - // changeStateIdletoExecute(omxNode, observer); - // // TODO: Sending empty input buffers is slightly tricky. - // // dispatch buffers - // for (size_t i = 0; i < iBuffer.size(); i++) { - // dispatchInputBuffer(omxNode, &iBuffer, i, 0, 0, 0, portMode[0]); - // } - // // set state to idle - // changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1])); +#endif + // set state to loaded - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), + OMX_StateLoaded); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + + for (size_t j = portBase; j < portBase + 2; j++) { + for (size_t i = 0; i < pBuffer[j].size(); ++i) { + // Dont switch states until the ports are populated + status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, + &pBuffer[0], &pBuffer[1]); + ASSERT_EQ(status, + android::hardware::media::omx::V1_0::Status::TIMED_OUT); + + status = omxNode->freeBuffer(j, pBuffer[j][i].id); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + } + } + + status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0], + &pBuffer[1]); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(msg.type, Message::Type::EVENT); + ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); + ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet); + ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded); } // state transitions test - monkeying @@ -675,8 +936,9 @@ TEST_F(ComponentHidlTest, DISABLED_StateTransitions_M) { EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK); // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); // set state to idle ; receive error OMX_ErrorSameState status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), @@ -684,7 +946,7 @@ TEST_F(ComponentHidlTest, DISABLED_StateTransitions_M) { EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // set state to executing ; receive error OMX_ErrorSameState status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), @@ -696,12 +958,13 @@ TEST_F(ComponentHidlTest, DISABLED_StateTransitions_M) { OMX_StateLoaded); EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK); - // set state to Idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); - - // set state to Loaded - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + // set state to idle + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); + // set state to loaded + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // port enable disable test @@ -784,14 +1047,14 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Idle) { PortMode portMode[2]; initPortMode(portMode, isSecure, compClass); status = omxNode->setPortMode(kPortIndexInput, portMode[0]); - EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); - EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1], - kPortIndexInput, kPortIndexOutput, portMode); - + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1], + kPortIndexInput, kPortIndexOutput, portMode)); for (size_t i = portBase; i < portBase + 2; i++) { status = omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), i); @@ -839,8 +1102,8 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Idle) { ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); - allocatePortBuffers(omxNode, &pBuffer[i - portBase], i, - portMode[i - portBase]); + ASSERT_NO_FATAL_FAILURE(allocatePortBuffers( + omxNode, &pBuffer[i - portBase], i, portMode[i - portBase])); status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0], &pBuffer[1]); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); @@ -854,8 +1117,9 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Idle) { } // set state to Loaded - changeStateIdletoLoaded(omxNode, observer, &pBuffer[0], &pBuffer[1], - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE( + changeStateIdletoLoaded(omxNode, observer, &pBuffer[0], &pBuffer[1], + kPortIndexInput, kPortIndexOutput)); } // port enable disable test @@ -888,20 +1152,20 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Execute) { PortMode portMode[2]; initPortMode(portMode, isSecure, compClass); status = omxNode->setPortMode(kPortIndexInput, portMode[0]); - EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); - EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1], - kPortIndexInput, kPortIndexOutput, portMode); - + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1], + kPortIndexInput, kPortIndexOutput, portMode)); // set state to executing - changeStateIdletoExecute(omxNode, observer); - + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // dispatch buffers for (size_t i = 0; i < pBuffer[1].size(); i++) { - dispatchOutputBuffer(omxNode, &pBuffer[1], i, portMode[1]); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, &pBuffer[1], i, portMode[1])); } for (size_t i = portBase; i < portBase + 2; i++) { @@ -954,8 +1218,8 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Execute) { ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); - allocatePortBuffers(omxNode, &pBuffer[i - portBase], i, - portMode[i - portBase]); + ASSERT_NO_FATAL_FAILURE(allocatePortBuffers( + omxNode, &pBuffer[i - portBase], i, portMode[i - portBase])); status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0], &pBuffer[1]); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); @@ -968,12 +1232,13 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Execute) { } } - // set state to Idle - changeStateExecutetoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1]); - - // set state to Loaded - changeStateIdletoLoaded(omxNode, observer, &pBuffer[0], &pBuffer[1], - kPortIndexInput, kPortIndexOutput); + // set state to idle + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &pBuffer[0], &pBuffer[1])); + // set state to loaded + ASSERT_NO_FATAL_FAILURE( + changeStateIdletoLoaded(omxNode, observer, &pBuffer[0], &pBuffer[1], + kPortIndexInput, kPortIndexOutput)); } // port enable disable test - monkeying diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp index e24b79b8a9..4a45e6923c 100644 --- a/media/omx/1.0/vts/functional/master/Android.bp +++ b/media/omx/1.0/vts/functional/master/Android.bp @@ -16,29 +16,7 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetMasterTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalMediaOmxV1_0Defaults"], srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libhwbinder", - "libnativehelper", - "libutils", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "android.hardware.media.omx@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], - include_dirs: [ - "frameworks/native/include/media/openmax/", - "hardware/interfaces/media/omx/1.0/vts/functional/common", - ], } diff --git a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp index e8f5f77dfd..5a31d691c9 100644 --- a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp +++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp @@ -15,6 +15,10 @@ */ #define LOG_TAG "media_omx_hidl_master_test" +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include <android-base/logging.h> #include <android/hardware/media/omx/1.0/IOmx.h> @@ -146,6 +150,7 @@ TEST_F(MasterHidlTest, ListServiceAttr) { attributes = _nl; }) .isOk()); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); if (attributes.size() == 0) ALOGV("Warning, Attribute list empty"); } @@ -182,6 +187,7 @@ TEST_F(MasterHidlTest, ListNodes) { nodeList = _nl; }) .isOk()); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); if (nodeList.size() == 0) ALOGV("Warning, ComponentInfo list empty"); else { @@ -200,6 +206,7 @@ TEST_F(MasterHidlTest, ListNodes) { omxNode = _nl; }) .isOk()); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); if (omxNode == nullptr) { isPass = false; std::cerr << "[ !OK ] " << nodeList[i].mName.c_str() diff --git a/media/omx/1.0/vts/functional/video/Android.bp b/media/omx/1.0/vts/functional/video/Android.bp index 4e94f3b35b..f0da2b39d0 100644 --- a/media/omx/1.0/vts/functional/video/Android.bp +++ b/media/omx/1.0/vts/functional/video/Android.bp @@ -16,70 +16,21 @@ cc_test { name: "VtsHalMediaOmxV1_0TargetVideoDecTest", - defaults: ["hidl_defaults"], - srcs: ["VtsHalMediaOmxV1_0TargetVideoDecTest.cpp", - "media_video_hidl_test_common.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidlmemory", - "libhidltransport", - "libhwbinder", - "libnativehelper", - "libutils", - "libstagefright_foundation", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "android.hardware.media.omx@1.0", - "android.hardware.graphics.allocator@2.0", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.common@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase", - "VtsHalMediaOmxV1_0CommonUtil"], - cflags: [ - "-O0", - "-g", - ], - include_dirs: [ - "frameworks/native/include/media/openmax/", - "hardware/interfaces/media/omx/1.0/vts/functional/common", + defaults: ["VtsHalMediaOmxV1_0Defaults"], + srcs: [ + "VtsHalMediaOmxV1_0TargetVideoDecTest.cpp", + "media_video_hidl_test_common.cpp" ], } cc_test { name: "VtsHalMediaOmxV1_0TargetVideoEncTest", - defaults: ["hidl_defaults"], - srcs: ["VtsHalMediaOmxV1_0TargetVideoEncTest.cpp", - "media_video_hidl_test_common.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidlmemory", - "libhidltransport", - "libhwbinder", - "libnativehelper", - "libnativewindow", - "libutils", - "libstagefright_foundation", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "android.hardware.media.omx@1.0", - "android.hardware.graphics.bufferqueue@1.0", - "android.hardware.graphics.mapper@2.0", + defaults: ["VtsHalMediaOmxV1_0Defaults"], + srcs: [ + "VtsHalMediaOmxV1_0TargetVideoEncTest.cpp", + "media_video_hidl_test_common.cpp" ], - static_libs: ["VtsHalHidlTargetTestBase", - "VtsHalMediaOmxV1_0CommonUtil"], - cflags: [ - "-O0", - "-g", - ], - include_dirs: [ - "frameworks/native/include/media/openmax/", - "hardware/interfaces/media/omx/1.0/vts/functional/common", + static_libs: [ + "libnativewindow", ], } diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp index 438dd7071e..9b74a339c0 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp @@ -15,11 +15,12 @@ */ #define LOG_TAG "media_omx_hidl_video_dec_test" +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include <android-base/logging.h> -#include <android/hardware/graphics/allocator/2.0/IAllocator.h> -#include <android/hardware/graphics/mapper/2.0/IMapper.h> -#include <android/hardware/graphics/mapper/2.0/types.h> #include <android/hardware/media/omx/1.0/IOmx.h> #include <android/hardware/media/omx/1.0/IOmxNode.h> #include <android/hardware/media/omx/1.0/IOmxObserver.h> @@ -28,8 +29,6 @@ #include <android/hidl/memory/1.0/IMapper.h> #include <android/hidl/memory/1.0/IMemory.h> -using ::android::hardware::graphics::common::V1_0::BufferUsage; -using ::android::hardware::graphics::common::V1_0::PixelFormat; using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; using ::android::hardware::media::omx::V1_0::IOmxNode; @@ -47,6 +46,7 @@ using ::android::sp; #include <VtsHalHidlTargetTestBase.h> #include <getopt.h> +#include <media/hardware/HardwareAPI.h> #include <media_hidl_test_common.h> #include <media_video_hidl_test_common.h> #include <fstream> @@ -166,6 +166,7 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { this->omxNode = _nl; }) .isOk()); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; struct StringToName { @@ -217,6 +218,7 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { timestampUs = 0; timestampDevTest = false; isSecure = false; + portSettingsChange = false; size_t suffixLen = strlen(".secure"); if (strlen(gEnv->getComponent().c_str()) >= suffixLen) { isSecure = @@ -225,11 +227,15 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { ".secure"); } if (isSecure) disableTest = true; - if (disableTest) std::cout << "[ ] Warning ! Test Disabled\n"; + if (disableTest) std::cout << "[ WARN ] Test Disabled \n"; } virtual void TearDown() override { if (omxNode != nullptr) { + // If you have encountered a fatal failure, it is possible that + // freeNode() will not go through. Instead of hanging the app. + // let it pass through and report errors + if (::testing::Test::HasFatalFailure()) return; EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } @@ -269,9 +275,8 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(tsHit, true) << "TimeStamp not recognized"; } else { - std::cout - << "[ ] Warning ! Received non-zero " - "output / TimeStamp not recognized \n"; + std::cout << "[ INFO ] Received non-zero " + "output / TimeStamp not recognized \n"; } } } @@ -293,6 +298,13 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } #endif } + } else if (msg.type == Message::Type::EVENT) { + if (msg.data.eventData.event == OMX_EventPortSettingsChanged) { + if ((msg.data.eventData.data2 == OMX_IndexParamPortDefinition || + msg.data.eventData.data2 == 0)) { + portSettingsChange = true; + } + } } } @@ -320,6 +332,7 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::android::List<uint64_t> timestampUslist; bool timestampDevTest; bool isSecure; + bool portSettingsChange; protected: static void description(const std::string& description) { @@ -367,119 +380,61 @@ void getInputChannelInfo(sp<IOmxNode> omxNode, OMX_U32 kPortIndexInput, } } +// number of elementary streams per component +#define STREAM_COUNT 2 // LookUpTable of clips and metadata for component testing void GetURLForComponent(VideoDecHidlTest::standardComp comp, char* mURL, - char* info) { + char* info, size_t streamIndex = 1) { struct CompToURL { VideoDecHidlTest::standardComp comp; - const char* mURL; - const char* info; + const char mURL[STREAM_COUNT][512]; + const char info[STREAM_COUNT][512]; }; + ASSERT_TRUE(streamIndex < STREAM_COUNT); + static const CompToURL kCompToURL[] = { {VideoDecHidlTest::standardComp::avc, - "bbb_avc_1920x1080_5000kbps_30fps.h264", - "bbb_avc_1920x1080_5000kbps_30fps.info"}, + {"bbb_avc_176x144_300kbps_60fps.h264", + "bbb_avc_1920x1080_5000kbps_30fps.h264"}, + {"bbb_avc_176x144_300kbps_60fps.info", + "bbb_avc_1920x1080_5000kbps_30fps.info"}}, {VideoDecHidlTest::standardComp::hevc, - "bbb_hevc_640x360_1600kbps_30fps.hevc", - "bbb_hevc_640x360_1600kbps_30fps.info"}, + {"bbb_hevc_176x144_176kbps_60fps.hevc", + "bbb_hevc_640x360_1600kbps_30fps.hevc"}, + {"bbb_hevc_176x144_176kbps_60fps.info", + "bbb_hevc_640x360_1600kbps_30fps.info"}}, {VideoDecHidlTest::standardComp::mpeg2, - "bbb_mpeg2_176x144_105kbps_25fps.m2v", - "bbb_mpeg2_176x144_105kbps_25fps.info"}, + {"bbb_mpeg2_176x144_105kbps_25fps.m2v", + "bbb_mpeg2_352x288_1mbps_60fps.m2v"}, + {"bbb_mpeg2_176x144_105kbps_25fps.info", + "bbb_mpeg2_352x288_1mbps_60fps.info"}}, {VideoDecHidlTest::standardComp::h263, - "bbb_h263_352x288_300kbps_12fps.h263", - "bbb_h263_352x288_300kbps_12fps.info"}, + {"", "bbb_h263_352x288_300kbps_12fps.h263"}, + {"", "bbb_h263_352x288_300kbps_12fps.info"}}, {VideoDecHidlTest::standardComp::mpeg4, - "bbb_mpeg4_1280x720_1000kbps_25fps.m4v", - "bbb_mpeg4_1280x720_1000kbps_25fps.info"}, - {VideoDecHidlTest::standardComp::vp8, "bbb_vp8_640x360_2mbps_30fps.vp8", - "bbb_vp8_640x360_2mbps_30fps.info"}, + {"", "bbb_mpeg4_1280x720_1000kbps_25fps.m4v"}, + {"", "bbb_mpeg4_1280x720_1000kbps_25fps.info"}}, + {VideoDecHidlTest::standardComp::vp8, + {"bbb_vp8_176x144_240kbps_60fps.vp8", + "bbb_vp8_640x360_2mbps_30fps.vp8"}, + {"bbb_vp8_176x144_240kbps_60fps.info", + "bbb_vp8_640x360_2mbps_30fps.info"}}, {VideoDecHidlTest::standardComp::vp9, - "bbb_vp9_640x360_1600kbps_30fps.vp9", - "bbb_vp9_640x360_1600kbps_30fps.info"}, + {"bbb_vp9_176x144_285kbps_60fps.vp9", + "bbb_vp9_640x360_1600kbps_30fps.vp9"}, + {"bbb_vp9_176x144_285kbps_60fps.info", + "bbb_vp9_640x360_1600kbps_30fps.info"}}, }; for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) { if (kCompToURL[i].comp == comp) { - strcat(mURL, kCompToURL[i].mURL); - strcat(info, kCompToURL[i].info); + strcat(mURL, kCompToURL[i].mURL[streamIndex]); + strcat(info, kCompToURL[i].info[streamIndex]); return; } } } -void allocateGraphicBuffers(sp<IOmxNode> omxNode, OMX_U32 portIndex, - android::Vector<BufferInfo>* buffArray, - uint32_t nFrameWidth, uint32_t nFrameHeight, - int32_t* nStride, uint32_t count) { - android::hardware::media::omx::V1_0::Status status; - sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator = - android::hardware::graphics::allocator::V2_0::IAllocator::getService(); - ASSERT_NE(nullptr, allocator.get()); - - sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper = - android::hardware::graphics::mapper::V2_0::IMapper::getService(); - ASSERT_NE(mapper.get(), nullptr); - - android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo - descriptorInfo; - uint32_t usage; - - descriptorInfo.width = nFrameWidth; - descriptorInfo.height = nFrameHeight; - descriptorInfo.layerCount = 1; - descriptorInfo.format = PixelFormat::RGBA_8888; - descriptorInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN); - omxNode->getGraphicBufferUsage( - portIndex, - [&status, &usage](android::hardware::media::omx::V1_0::Status _s, - uint32_t _n1) { - status = _s; - usage = _n1; - }); - if (status == android::hardware::media::omx::V1_0::Status::OK) { - descriptorInfo.usage |= usage; - } - - ::android::hardware::hidl_vec<uint32_t> descriptor; - android::hardware::graphics::mapper::V2_0::Error error; - mapper->createDescriptor( - descriptorInfo, [&error, &descriptor]( - android::hardware::graphics::mapper::V2_0::Error _s, - ::android::hardware::hidl_vec<uint32_t> _n1) { - error = _s; - descriptor = _n1; - }); - EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE); - - EXPECT_EQ(buffArray->size(), count); - allocator->allocate( - descriptor, count, - [&](android::hardware::graphics::mapper::V2_0::Error _s, uint32_t _n1, - const ::android::hardware::hidl_vec< - ::android::hardware::hidl_handle>& _n2) { - ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, - _s); - *nStride = _n1; - ASSERT_EQ(count, _n2.size()); - for (uint32_t i = 0; i < count; i++) { - buffArray->editItemAt(i).omxBuffer.nativeHandle = _n2[i]; - buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.width = - nFrameWidth; - buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.height = - nFrameHeight; - buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.stride = _n1; - buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.format = - descriptorInfo.format; - buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.usage = - descriptorInfo.usage; - buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.layerCount = - descriptorInfo.layerCount; - buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.id = - (*buffArray)[i].id; - } - }); -} - // port settings reconfiguration during runtime. reconfigures frame dimensions void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, android::Vector<BufferInfo>* iBuffer, @@ -493,6 +448,21 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, ASSERT_EQ(msg.data.eventData.data1, kPortIndexOutput); if (msg.data.eventData.data2 == OMX_IndexParamPortDefinition || msg.data.eventData.data2 == 0) { + // Components can send various kinds of port settings changed events + // all at once. Before committing to a full port reconfiguration, + // defer any events waiting in the queue to be addressed to a later + // point. + android::List<Message> msgQueueDefer; + while (1) { + status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, + iBuffer, oBuffer); + if (status != + android::hardware::media::omx::V1_0::Status::TIMED_OUT) { + msgQueueDefer.push_back(msg); + continue; + } else + break; + } status = omxNode->sendCommand( toRawCommandType(OMX_CommandPortDisable), kPortIndexOutput); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); @@ -521,17 +491,19 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, // set Port Params uint32_t nFrameWidth, nFrameHeight, xFramerate; - OMX_COLOR_FORMATTYPE eColorFormat = - OMX_COLOR_FormatYUV420Planar; getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight, &xFramerate); + // get configured color format + OMX_PARAM_PORTDEFINITIONTYPE portDef; + status = getPortParam(omxNode, OMX_IndexParamPortDefinition, + kPortIndexOutput, &portDef); setDefaultPortParam(omxNode, kPortIndexOutput, - OMX_VIDEO_CodingUnused, eColorFormat, + OMX_VIDEO_CodingUnused, + portDef.format.video.eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); // If you can disable a port, then you should be able to - // enable - // it as well + // enable it as well status = omxNode->sendCommand( toRawCommandType(OMX_CommandPortEnable), kPortIndexOutput); ASSERT_EQ(status, @@ -544,22 +516,8 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); - allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput, - oPortMode); - if (oPortMode != PortMode::PRESET_BYTE_BUFFER) { - OMX_PARAM_PORTDEFINITIONTYPE portDef; - - status = getPortParam(omxNode, OMX_IndexParamPortDefinition, - kPortIndexOutput, &portDef); - ASSERT_EQ( - status, - ::android::hardware::media::omx::V1_0::Status::OK); - allocateGraphicBuffers(omxNode, kPortIndexOutput, oBuffer, - portDef.format.video.nFrameWidth, - portDef.format.video.nFrameHeight, - &portDef.format.video.nStride, - portDef.nBufferCountActual); - } + ASSERT_NO_FATAL_FAILURE(allocatePortBuffers( + omxNode, oBuffer, kPortIndexOutput, oPortMode, true)); status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); ASSERT_EQ(status, @@ -568,25 +526,36 @@ void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer, ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable); ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput); + // Push back deferred messages to the list + android::List<Message>::iterator it = msgQueueDefer.begin(); + while (it != msgQueueDefer.end()) { + status = omxNode->dispatchMessage(*it); + ASSERT_EQ( + status, + ::android::hardware::media::omx::V1_0::Status::OK); + it++; + } + // dispatch output buffers for (size_t i = 0; i < oBuffer->size(); i++) { - dispatchOutputBuffer(omxNode, oBuffer, i, oPortMode); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, i, oPortMode)); } } else { ASSERT_TRUE(false); } } else if (msg.data.eventData.data2 == OMX_IndexConfigCommonOutputCrop) { - std::cout << "[ ] Warning ! OMX_EventPortSettingsChanged/ " + std::cout << "[ INFO ] OMX_EventPortSettingsChanged/ " "OMX_IndexConfigCommonOutputCrop not handled \n"; } else if (msg.data.eventData.data2 == OMX_IndexVendorStartUnused + 3) { - std::cout << "[ ] Warning ! OMX_EventPortSettingsChanged/ " + std::cout << "[ INFO ] OMX_EventPortSettingsChanged/ " "kDescribeColorAspectsIndex not handled \n"; } } else if (msg.data.eventData.event == OMX_EventError) { - std::cout << "[ ] Warning ! OMX_EventError/ " + std::cerr << "[ ERROR ] OMX_EventError/ " "Decode Frame Call might be failed \n"; - return; + ASSERT_TRUE(false); } else { // something unexpected happened ASSERT_TRUE(false); @@ -601,17 +570,17 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, PortMode oPortMode) { android::hardware::media::omx::V1_0::Status status; Message msg; - int timeOut = TIMEOUT_COUNTER; + int timeOut = TIMEOUT_COUNTER_Q; while (timeOut--) { size_t i = 0; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); if (status == android::hardware::media::omx::V1_0::Status::OK) { - EXPECT_EQ(msg.type, Message::Type::EVENT); - portReconfiguration(omxNode, observer, iBuffer, oBuffer, - kPortIndexInput, kPortIndexOutput, msg, - oPortMode, nullptr); + ASSERT_EQ(msg.type, Message::Type::EVENT); + ASSERT_NO_FATAL_FAILURE(portReconfiguration( + omxNode, observer, iBuffer, oBuffer, kPortIndexInput, + kPortIndexOutput, msg, oPortMode, nullptr)); } // status == TIMED_OUT, it could be due to process time being large // than DEFAULT_TIMEOUT or component needs output buffers to start @@ -624,9 +593,10 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, // Dispatch an output buffer assuming outQueue.empty() is true size_t index; if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode)); + timeOut = TIMEOUT_COUNTER_Q; } - timeOut--; } } @@ -640,50 +610,27 @@ void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, bool signalEOS = true) { android::hardware::media::omx::V1_0::Status status; Message msg; - - // dispatch output buffers - for (size_t i = 0; i < oBuffer->size(); i++) { - dispatchOutputBuffer(omxNode, oBuffer, i, oPortMode); - } - // dispatch input buffers + size_t index; uint32_t flags = 0; int frameID = offset; - for (size_t i = 0; (i < iBuffer->size()) && (frameID < (int)Info->size()) && - (frameID < (offset + range)); - i++) { - char* ipBuffer = static_cast<char*>( - static_cast<void*>((*iBuffer)[i].mMemory->getPointer())); - ASSERT_LE((*Info)[frameID].bytesCount, - static_cast<int>((*iBuffer)[i].mMemory->getSize())); - eleStream.read(ipBuffer, (*Info)[frameID].bytesCount); - ASSERT_EQ(eleStream.gcount(), (*Info)[frameID].bytesCount); - flags = (*Info)[frameID].flags; - if (signalEOS && ((frameID == (int)Info->size() - 1) || - (frameID == (offset + range - 1)))) - flags |= OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, i, (*Info)[frameID].bytesCount, - flags, (*Info)[frameID].timestamp); - frameID++; - } + int timeOut = TIMEOUT_COUNTER_Q; + bool iQueued, oQueued; - int timeOut = TIMEOUT_COUNTER; - bool stall = false; while (1) { + iQueued = oQueued = false; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); // Port Reconfiguration if (status == android::hardware::media::omx::V1_0::Status::OK && msg.type == Message::Type::EVENT) { - portReconfiguration(omxNode, observer, iBuffer, oBuffer, - kPortIndexInput, kPortIndexOutput, msg, - oPortMode, nullptr); + ASSERT_NO_FATAL_FAILURE(portReconfiguration( + omxNode, observer, iBuffer, oBuffer, kPortIndexInput, + kPortIndexOutput, msg, oPortMode, nullptr)); } if (frameID == (int)Info->size() || frameID == (offset + range)) break; // Dispatch input buffer - size_t index = 0; if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) { char* ipBuffer = static_cast<char*>( static_cast<void*>((*iBuffer)[index].mMemory->getPointer())); @@ -692,29 +639,146 @@ void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, eleStream.read(ipBuffer, (*Info)[frameID].bytesCount); ASSERT_EQ(eleStream.gcount(), (*Info)[frameID].bytesCount); flags = (*Info)[frameID].flags; + // Indicate to omx core that the buffer contains a full frame worth + // of data + flags |= OMX_BUFFERFLAG_ENDOFFRAME; + // Indicate the omx core that this is the last buffer it needs to + // process if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1)))) flags |= OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, index, - (*Info)[frameID].bytesCount, flags, - (*Info)[frameID].timestamp); + ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer( + omxNode, iBuffer, index, (*Info)[frameID].bytesCount, flags, + (*Info)[frameID].timestamp)); frameID++; - stall = false; - } else - stall = true; + iQueued = true; + } + // Dispatch output buffer if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode); - stall = false; - } else - stall = true; - if (stall) - timeOut--; + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode)); + oQueued = true; + } + // Reset Counters when either input or output buffer is dispatched + if (iQueued || oQueued) + timeOut = TIMEOUT_COUNTER_Q; else - timeOut = TIMEOUT_COUNTER; + timeOut--; if (timeOut == 0) { - EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; + ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite"; + } + } +} + +// DescribeColorFormatParams Copy Constructor (Borrowed from OMXUtils.cpp) +android::DescribeColorFormatParams::DescribeColorFormatParams( + const android::DescribeColorFormat2Params& params) { + eColorFormat = params.eColorFormat; + nFrameWidth = params.nFrameWidth; + nFrameHeight = params.nFrameHeight; + nStride = params.nStride; + nSliceHeight = params.nSliceHeight; + bUsingNativeBuffers = params.bUsingNativeBuffers; +}; + +bool isColorFormatFlexibleYUV(sp<IOmxNode> omxNode, + OMX_COLOR_FORMATTYPE eColorFormat) { + android::hardware::media::omx::V1_0::Status status; + unsigned int index = OMX_IndexMax, index2 = OMX_IndexMax; + omxNode->getExtensionIndex( + "OMX.google.android.index.describeColorFormat", + [&index](android::hardware::media::omx::V1_0::Status _s, + unsigned int _nl) { + if (_s == ::android::hardware::media::omx::V1_0::Status::OK) + index = _nl; + }); + omxNode->getExtensionIndex( + "OMX.google.android.index.describeColorFormat2", + [&index2](android::hardware::media::omx::V1_0::Status _s, + unsigned int _nl) { + if (_s == ::android::hardware::media::omx::V1_0::Status::OK) + index2 = _nl; + }); + + android::DescribeColorFormat2Params describeParams; + describeParams.eColorFormat = eColorFormat; + describeParams.nFrameWidth = 128; + describeParams.nFrameHeight = 128; + describeParams.nStride = 128; + describeParams.nSliceHeight = 128; + describeParams.bUsingNativeBuffers = OMX_FALSE; + if (index != OMX_IndexMax) { + android::DescribeColorFormatParams describeParamsV1(describeParams); + status = getParam(omxNode, static_cast<OMX_INDEXTYPE>(index), + &describeParamsV1); + if (status == ::android::hardware::media::omx::V1_0::Status::OK) { + android::MediaImage& img = describeParamsV1.sMediaImage; + if (img.mType == android::MediaImage::MEDIA_IMAGE_TYPE_YUV) { + if (img.mNumPlanes == 3 && + img.mPlane[img.Y].mHorizSubsampling == 1 && + img.mPlane[img.Y].mVertSubsampling == 1) { + if (img.mPlane[img.U].mHorizSubsampling == 2 && + img.mPlane[img.U].mVertSubsampling == 2 && + img.mPlane[img.V].mHorizSubsampling == 2 && + img.mPlane[img.V].mVertSubsampling == 2) { + if (img.mBitDepth <= 8) { + return true; + } + } + } + } + } + } else if (index2 != OMX_IndexMax) { + status = getParam(omxNode, static_cast<OMX_INDEXTYPE>(index2), + &describeParams); + android::MediaImage2& img = describeParams.sMediaImage; + if (img.mType == android::MediaImage2::MEDIA_IMAGE_TYPE_YUV) { + if (img.mNumPlanes == 3 && + img.mPlane[img.Y].mHorizSubsampling == 1 && + img.mPlane[img.Y].mVertSubsampling == 1) { + if (img.mPlane[img.U].mHorizSubsampling == 2 && + img.mPlane[img.U].mVertSubsampling == 2 && + img.mPlane[img.V].mHorizSubsampling == 2 && + img.mPlane[img.V].mVertSubsampling == 2) { + if (img.mBitDepth <= 8) { + return true; + } + } + } + } + } + return false; +} + +// get default color format for output port +void getDefaultColorFormat(sp<IOmxNode> omxNode, OMX_U32 kPortIndexOutput, + PortMode oPortMode, + OMX_COLOR_FORMATTYPE* eColorFormat) { + android::hardware::media::omx::V1_0::Status status; + OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat; + *eColorFormat = OMX_COLOR_FormatUnused; + portFormat.nIndex = 0; + while (portFormat.nIndex < 512) { + status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat, + kPortIndexOutput, &portFormat); + if (status != ::android::hardware::media::omx::V1_0::Status::OK) break; + EXPECT_EQ(portFormat.eCompressionFormat, OMX_VIDEO_CodingUnused); + if (oPortMode != PortMode::PRESET_BYTE_BUFFER) { + *eColorFormat = portFormat.eColorFormat; + break; + } + if (isColorFormatFlexibleYUV(omxNode, portFormat.eColorFormat)) { + *eColorFormat = portFormat.eColorFormat; + break; + } + if (OMX_COLOR_FormatYUV420SemiPlanar == portFormat.eColorFormat || + OMX_COLOR_FormatYUV420Planar == portFormat.eColorFormat || + OMX_COLOR_FormatYUV420PackedPlanar == portFormat.eColorFormat || + OMX_COLOR_FormatYUV420PackedSemiPlanar == portFormat.eColorFormat) { + *eColorFormat = portFormat.eColorFormat; break; } + portFormat.nIndex++; } } @@ -788,7 +852,7 @@ TEST_F(VideoDecHidlTest, DecodeTest) { eleInfo >> flags; eleInfo >> timestamp; Info.push_back({bytesCount, flags, timestamp}); - if (flags != OMX_BUFFERFLAG_CODECCONFIG) + if (timestampDevTest && (flags != OMX_BUFFERFLAG_CODECCONFIG)) timestampUslist.push_back(timestamp); if (maxBytesCount < bytesCount) maxBytesCount = bytesCount; } @@ -813,58 +877,59 @@ TEST_F(VideoDecHidlTest, DecodeTest) { // set Port Params uint32_t nFrameWidth, nFrameHeight, xFramerate; - OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight, &xFramerate); + // get default color format + OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused; + getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1], + &eColorFormat); + ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused); + status = + setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, + eColorFormat, xFramerate); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); - // disabling adaptive playback. - omxNode->prepareForAdaptivePlayback(kPortIndexOutput, false, 1920, 1080); - android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, portMode, true)); // set state to executing - changeStateIdletoExecute(omxNode, observer); - - if (portMode[1] != PortMode::PRESET_BYTE_BUFFER) { - OMX_PARAM_PORTDEFINITIONTYPE portDef; - - status = getPortParam(omxNode, OMX_IndexParamPortDefinition, - kPortIndexOutput, &portDef); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - allocateGraphicBuffers( - omxNode, kPortIndexOutput, &oBuffer, - portDef.format.video.nFrameWidth, portDef.format.video.nFrameHeight, - &portDef.format.video.nStride, portDef.nBufferCountActual); - } + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // Port Reconfiguration eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, (int)Info.size(), - portMode[1]); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, (int)Info.size(), portMode[1])); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode[1]); - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode, - portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr); - EXPECT_EQ(timestampUslist.empty(), true); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode[1])); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode, + portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr)); + if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true); // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } -// end of sequence test -TEST_F(VideoDecHidlTest, EOSTest_M) { - description("Test End of stream monkeying"); +// Test for adaptive playback support +TEST_F(VideoDecHidlTest, AdaptivePlaybackTest) { + description("Tests for Adaptive Playback support"); if (disableTest) return; + if (!(compName == avc || compName == hevc || compName == vp8 || + compName == vp9 || compName == mpeg2)) + return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; status = setRole(omxNode, gEnv->getRole().c_str()); @@ -877,44 +942,199 @@ TEST_F(VideoDecHidlTest, EOSTest_M) { kPortIndexOutput = kPortIndexInput + 1; } + // set port mode + portMode[0] = PortMode::PRESET_BYTE_BUFFER; + portMode[1] = PortMode::DYNAMIC_ANW_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + if (status != ::android::hardware::media::omx::V1_0::Status::OK) { + portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + } + + // prepare for adaptive playback + uint32_t adaptiveMaxWidth = 320; + uint32_t adaptiveMaxHeight = 240; + status = omxNode->prepareForAdaptivePlayback( + kPortIndexOutput, true, adaptiveMaxWidth, adaptiveMaxHeight); + if (strncmp(gEnv->getComponent().c_str(), "OMX.google.", 11) == 0) { + // SoftOMX Decoders donot support graphic buffer modes. So for them + // support for adaptive play back is mandatory in Byte Buffer mode + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + } else { + // for vendor codecs, support for adaptive play back is optional + // in byte buffer mode. + if (portMode[1] == PortMode::PRESET_BYTE_BUFFER) return; + if (status != ::android::hardware::media::omx::V1_0::Status::OK) return; + } + + // TODO: Handle this better !!! + // Without the knowledge of the maximum resolution of the frame to be + // decoded it is not possible to choose the size of the input buffer. + // The value below is based on the info. files of clips in res folder. + status = setPortBufferSize(omxNode, kPortIndexInput, 482304); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + // set Port Params uint32_t nFrameWidth, nFrameHeight, xFramerate; - OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight, &xFramerate); + // get default color format + OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused; + getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1], + &eColorFormat); + ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused); + status = + setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, + eColorFormat, xFramerate); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); + android::Vector<BufferInfo> iBuffer, oBuffer; + + // set state to idle + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, portMode, true)); + // set state to executing + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); + + timestampDevTest = true; + uint32_t timestampOffset = 0; + for (uint32_t i = 0; i < STREAM_COUNT * 2; i++) { + std::ifstream eleStream, eleInfo; + char mURL[512], info[512]; + android::Vector<FrameData> Info; + strcpy(mURL, gEnv->getRes().c_str()); + strcpy(info, gEnv->getRes().c_str()); + GetURLForComponent(compName, mURL, info, i % STREAM_COUNT); + eleInfo.open(info); + ASSERT_EQ(eleInfo.is_open(), true); + int bytesCount = 0; + uint32_t flags = 0; + uint32_t timestamp = 0; + uint32_t timestampMax = 0; + while (1) { + if (!(eleInfo >> bytesCount)) break; + eleInfo >> flags; + eleInfo >> timestamp; + timestamp += timestampOffset; + Info.push_back({bytesCount, flags, timestamp}); + if (timestampDevTest && (flags != OMX_BUFFERFLAG_CODECCONFIG)) + timestampUslist.push_back(timestamp); + if (timestampMax < timestamp) timestampMax = timestamp; + } + timestampOffset = timestampMax; + eleInfo.close(); + + // Port Reconfiguration + eleStream.open(mURL, std::ifstream::binary); + ASSERT_EQ(eleStream.is_open(), true); + ASSERT_NO_FATAL_FAILURE( + decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, eleStream, &Info, + 0, (int)Info.size(), portMode[1], false)); + eleStream.close(); + + getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, + &nFrameHeight, &xFramerate); + if ((nFrameWidth > adaptiveMaxWidth) || + (nFrameHeight > adaptiveMaxHeight)) { + if (nFrameWidth > adaptiveMaxWidth) adaptiveMaxWidth = nFrameWidth; + if (nFrameHeight > adaptiveMaxHeight) + adaptiveMaxHeight = nFrameHeight; + EXPECT_TRUE(portSettingsChange); + } else { + // In DynamicANW Buffer mode, its ok to do a complete + // reconfiguration even if a partial reconfiguration is sufficient. + if (portMode[1] != PortMode::DYNAMIC_ANW_BUFFER) + EXPECT_FALSE(portSettingsChange); + } + portSettingsChange = false; + } + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode[1])); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode, + portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr)); + if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true); + // set state to idle + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); + // set state to executing + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); +} + +// end of sequence test +TEST_F(VideoDecHidlTest, EOSTest_M) { + description("Test End of stream monkeying"); + if (disableTest) return; + android::hardware::media::omx::V1_0::Status status; + uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; + status = setRole(omxNode, gEnv->getRole().c_str()); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + OMX_PORT_PARAM_TYPE params; + status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms); + if (status == ::android::hardware::media::omx::V1_0::Status::OK) { + ASSERT_EQ(params.nPorts, 2U); + kPortIndexInput = params.nStartPortNumber; + kPortIndexOutput = kPortIndexInput + 1; + } + // set port mode - PortMode portMode[2]; - portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; status = omxNode->setPortMode(kPortIndexInput, portMode[0]); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + // set Port Params + uint32_t nFrameWidth, nFrameHeight, xFramerate; + getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight, + &xFramerate); + // get default color format + OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused; + getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1], + &eColorFormat); + ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused); + status = + setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, + eColorFormat, xFramerate); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, + eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); + android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, portMode, true)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // request EOS at the start - testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode, - portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode, + portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); EXPECT_GE(framesReceived, 0U); framesReceived = 0; timestampUs = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // end of sequence test @@ -967,67 +1187,75 @@ TEST_F(VideoDecHidlTest, ThumbnailTest) { // set Port Params uint32_t nFrameWidth, nFrameHeight, xFramerate; - OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight, &xFramerate); + // get default color format + OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused; + getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1], + &eColorFormat); + ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused); + status = + setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, + eColorFormat, xFramerate); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); - // set port mode - PortMode portMode[2]; - portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; - status = omxNode->setPortMode(kPortIndexInput, portMode[0]); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, portMode, true)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // request EOS for thumbnail size_t i = 0; while (!(Info[i].flags & OMX_BUFFERFLAG_SYNCFRAME)) i++; eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1]); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1])); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode[1]); - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode, - portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode[1])); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode, + portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); EXPECT_GE(framesReceived, 1U); framesReceived = 0; timestampUs = 0; eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1], - false); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1], false)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode[1]); - testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode, - portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode[1])); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode, + portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); EXPECT_GE(framesReceived, 1U); framesReceived = 0; timestampUs = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // end of sequence test @@ -1073,56 +1301,68 @@ TEST_F(VideoDecHidlTest, SimpleEOSTest) { ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); // set port mode + portMode[0] = PortMode::PRESET_BYTE_BUFFER; + portMode[1] = PortMode::PRESET_ANW_BUFFER; status = omxNode->setPortMode(kPortIndexInput, portMode[0]); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + if (status != ::android::hardware::media::omx::V1_0::Status::OK) { + portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + } // set Port Params uint32_t nFrameWidth, nFrameHeight, xFramerate; - OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight, &xFramerate); + // get default color format + OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused; + getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1], + &eColorFormat); + ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused); + status = + setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, + eColorFormat, xFramerate); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); - // set port mode - PortMode portMode[2]; - portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; - status = omxNode->setPortMode(kPortIndexInput, portMode[0]); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, portMode, true)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // request EOS at the end eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, (int)Info.size(), - portMode[1], false); + ASSERT_NO_FATAL_FAILURE(decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, + eleStream, &Info, 0, (int)Info.size(), + portMode[1], false)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode[1]); - testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode, - portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode[1])); + ASSERT_NO_FATAL_FAILURE(testEOS( + omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode, + portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); framesReceived = 0; timestampUs = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // test input/output port flush @@ -1175,27 +1415,28 @@ TEST_F(VideoDecHidlTest, FlushTest) { // set Port Params uint32_t nFrameWidth, nFrameHeight, xFramerate; - OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight, &xFramerate); + // get default color format + OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused; + getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1], + &eColorFormat); + ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused); + status = + setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, + eColorFormat, xFramerate); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); - // set port mode - PortMode portMode[2]; - portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; - status = omxNode->setPortMode(kPortIndexInput, portMode[0]); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); - ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, portMode, true)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // Decode 128 frames and flush. here 128 is chosen to ensure there is a key // frame after this so that the below section can be convered for all @@ -1203,12 +1444,11 @@ TEST_F(VideoDecHidlTest, FlushTest) { int nFrames = 128; eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, nFrames, portMode[1], - false); - // Note: Assumes 200 ms is enough to end any decode call that started - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, 200000); + ASSERT_NO_FATAL_FAILURE(decodeNFrames( + omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, + kPortIndexOutput, eleStream, &Info, 0, nFrames, portMode[1], false)); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); framesReceived = 0; // Seek to next key frame and start decoding till the end @@ -1225,21 +1465,23 @@ TEST_F(VideoDecHidlTest, FlushTest) { index++; } if (keyFrame) { - decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, index, - Info.size() - index, portMode[1], false); + ASSERT_NO_FATAL_FAILURE( + decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, eleStream, &Info, + index, Info.size() - index, portMode[1], false)); } - // Note: Assumes 200 ms is enough to end any decode call that started eleStream.close(); - flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, 200000); + ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput)); framesReceived = 0; // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } int main(int argc, char** argv) { diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp index 7f9486d953..099658f8ae 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp @@ -179,6 +179,7 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { this->omxNode = _nl; }) .isOk()); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); ASSERT_NE(omxNode, nullptr); ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role"; struct StringToName { @@ -237,11 +238,15 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { ".secure"); } if (isSecure) disableTest = true; - if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; + if (disableTest) std::cout << "[ WARN ] Test Disabled \n"; } virtual void TearDown() override { if (omxNode != nullptr) { + // If you have encountered a fatal failure, it is possible that + // freeNode() will not go through. Instead of hanging the app. + // let it pass through and report errors + if (::testing::Test::HasFatalFailure()) return; EXPECT_TRUE((omxNode->freeNode()).isOk()); omxNode = nullptr; } @@ -278,9 +283,8 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(tsHit, true) << "TimeStamp not recognized"; } else { - std::cerr - << "[ ] Warning ! Received non-zero " - "output / TimeStamp not recognized \n"; + std::cout << "[ INFO ] Received non-zero " + "output / TimeStamp not recognized \n"; } } } @@ -442,7 +446,7 @@ void requestIDR(sp<IOmxNode> omxNode, OMX_U32 portIndex) { status = setPortConfig(omxNode, OMX_IndexConfigVideoIntraVOPRefresh, portIndex, ¶m); if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr << "[ ] Warning ! unable to request IDR \n"; + std::cout << "[ INFO ] unable to request IDR \n"; } // modify bitrate @@ -453,7 +457,7 @@ void changeBitrate(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t nBitrate) { status = setPortConfig(omxNode, OMX_IndexConfigVideoBitrate, portIndex, ¶m); if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr << "[ ] Warning ! unable to change Bitrate \n"; + std::cout << "[ INFO ] unable to change Bitrate \n"; } // modify framerate @@ -465,7 +469,7 @@ Return<android::hardware::media::omx::V1_0::Status> changeFrameRate( status = setPortConfig(omxNode, OMX_IndexConfigVideoFramerate, portIndex, ¶m); if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr << "[ ] Warning ! unable to change Framerate \n"; + std::cout << "[ INFO ] unable to change Framerate \n"; return status; } @@ -479,7 +483,7 @@ void changeRefreshPeriod(sp<IOmxNode> omxNode, OMX_U32 portIndex, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh, portIndex, ¶m); if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr << "[ ] Warning ! unable to change Refresh Period\n"; + std::cout << "[ INFO ] unable to change Refresh Period\n"; } // set intra refresh interval @@ -505,7 +509,7 @@ void setRefreshPeriod(sp<IOmxNode> omxNode, OMX_U32 portIndex, status = setPortParam(omxNode, OMX_IndexParamVideoIntraRefresh, portIndex, ¶m); if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr << "[ ] Warning ! unable to set Refresh Period \n"; + std::cout << "[ INFO ] unable to set Refresh Period \n"; } void setLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t latency) { @@ -515,7 +519,7 @@ void setLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t latency) { status = setPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency, portIndex, ¶m); if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr << "[ ] Warning ! unable to set latency\n"; + std::cout << "[ INFO ] unable to set latency\n"; } void getLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t* latency) { @@ -524,7 +528,7 @@ void getLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t* latency) { status = getPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency, portIndex, ¶m); if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr << "[ ] Warning ! unable to get latency\n"; + std::cout << "[ INFO ] unable to get latency\n"; else *latency = param.nU32; } @@ -532,12 +536,15 @@ void getLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t* latency) { // Set Default port param. void setDefaultPortParam(sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_VIDEO_CODINGTYPE eCompressionFormat, + OMX_U32 nFrameWidth, OMX_U32 nFrameHeight, OMX_U32 nBitrate, OMX_U32 xFramerate) { android::hardware::media::omx::V1_0::Status status; OMX_PARAM_PORTDEFINITIONTYPE portDef; status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex, &portDef); EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + portDef.format.video.nFrameWidth = nFrameWidth; + portDef.format.video.nFrameHeight = nFrameHeight; portDef.format.video.nBitrate = nBitrate; portDef.format.video.xFramerate = xFramerate; portDef.format.video.bFlagErrorConcealment = OMX_TRUE; @@ -609,13 +616,13 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, sp<CodecProducerListener> listener = nullptr) { android::hardware::media::omx::V1_0::Status status; Message msg; - int timeOut = TIMEOUT_COUNTER; + int timeOut = TIMEOUT_COUNTER_Q; while (timeOut--) { size_t i = 0; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - EXPECT_EQ(status, + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); // status == TIMED_OUT, it could be due to process time being large // than DEFAULT_TIMEOUT or component needs output buffers to start @@ -632,7 +639,9 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer, // Dispatch an output buffer assuming outQueue.empty() is true size_t index; if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index)); + timeOut = TIMEOUT_COUNTER_Q; } } } @@ -979,57 +988,25 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, sp<CodecProducerListener> listener = nullptr) { android::hardware::media::omx::V1_0::Status status; Message msg; - uint32_t ipCount = 0; + uint64_t timestamp = 0; + uint32_t flags = 0; + int timeOut = TIMEOUT_COUNTER_Q; + bool iQueued, oQueued; + uint32_t ipCount = 0; if (ipCount == 0) { status = changeFrameRate(omxNode, portIndexOutput, (24U << 16)); if (status == ::android::hardware::media::omx::V1_0::Status::OK) xFramerate = (24U << 16); } - - // dispatch output buffers - for (size_t i = 0; i < oBuffer->size(); i++) { - dispatchOutputBuffer(omxNode, oBuffer, i); - } - // dispatch input buffers int32_t timestampIncr = (int)((float)1000000 / (xFramerate >> 16)); - // timestamp scale = Nano sec - if (inputDataIsMeta) timestampIncr *= 1000; - uint64_t timestamp = 0; - uint32_t flags = 0; - for (size_t i = 0; i < iBuffer->size() && nFrames != 0; i++) { - if (inputDataIsMeta) { - if (listener->freeBuffers > listener->minUnDequeuedCount) { - if (dispatchGraphicBuffer(omxNode, producer, listener, iBuffer, - portIndexInput, eleStream, timestamp)) - break; - timestamp += timestampIncr; - nFrames--; - ipCount++; - } - } else { - char* ipBuffer = static_cast<char*>( - static_cast<void*>((*iBuffer)[i].mMemory->getPointer())); - ASSERT_LE(bytesCount, - static_cast<int>((*iBuffer)[i].mMemory->getSize())); - if (fillByteBuffer(omxNode, ipBuffer, portIndexInput, eleStream)) - break; - if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, flags, - timestamp); - if (timestampUslist) timestampUslist->push_back(timestamp); - timestamp += timestampIncr; - nFrames--; - ipCount++; - } - } + if (inputDataIsMeta) timestampIncr *= 1000; // timestamp scale: Nano sec - int timeOut = TIMEOUT_COUNTER; - bool stall = false; while (1) { + iQueued = oQueued = false; status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer); + // Port Reconfiguration if (status == android::hardware::media::omx::V1_0::Status::OK) { ASSERT_EQ(msg.type, Message::Type::EVENT); if (msg.data.eventData.event == OMX_EventPortSettingsChanged) { @@ -1037,8 +1014,10 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, ASSERT_EQ(msg.data.eventData.data2, OMX_IndexConfigAndroidIntraRefresh); } else if (msg.data.eventData.event == OMX_EventError) { - EXPECT_TRUE(false) << "Received OMX_EventError, not sure why"; - break; + ASSERT_TRUE(false) << "Received OMX_EventError, not sure why"; + } else if (msg.data.eventData.event == OMX_EventDataSpaceChanged) { + // TODO: how am i supposed to respond now? + std::cout << "[ INFO ] OMX_EventDataSpaceChanged \n"; } else { ASSERT_TRUE(false); } @@ -1051,14 +1030,17 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, if (inputDataIsMeta) { if (listener->freeBuffers > listener->minUnDequeuedCount) { if (dispatchGraphicBuffer(omxNode, producer, listener, iBuffer, - portIndexInput, eleStream, timestamp)) - break; + portIndexInput, eleStream, + timestamp)) { + if (::testing::Test::HasFailure()) + ASSERT_TRUE(false); + else + break; + } timestamp += timestampIncr; nFrames--; ipCount++; - stall = false; - } else { - stall = true; + iQueued = true; } } else { if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) { @@ -1070,31 +1052,32 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer, if (fillByteBuffer(omxNode, ipBuffer, portIndexInput, eleStream)) break; - if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; - dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, flags, - timestamp); + flags = OMX_BUFFERFLAG_ENDOFFRAME; + if (signalEOS && (nFrames == 1)) flags |= OMX_BUFFERFLAG_EOS; + ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer( + omxNode, iBuffer, index, bytesCount, flags, timestamp)); if (timestampUslist) timestampUslist->push_back(timestamp); timestamp += timestampIncr; nFrames--; ipCount++; - stall = false; - } else { - stall = true; + iQueued = true; } } + // Dispatch output buffer if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); - stall = false; - } else - stall = true; - if (stall) - timeOut--; + ASSERT_NO_FATAL_FAILURE( + dispatchOutputBuffer(omxNode, oBuffer, index)); + oQueued = true; + } + // Reset Counters when either input or output buffer is dispatched + if (iQueued || oQueued) + timeOut = TIMEOUT_COUNTER_Q; else - timeOut = TIMEOUT_COUNTER; + timeOut--; if (timeOut == 0) { - EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; - break; + ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite"; } + // Runtime Param Configuration if (ipCount == 15) { changeBitrate(omxNode, portIndexOutput, 768000); requestIDR(omxNode, portIndexOutput); @@ -1164,7 +1147,7 @@ TEST_F(VideoEncHidlTest, BufferSourceCallBacks) { xFramerate, eColorFormat); sp<DummyBufferSource> buffersource = new DummyBufferSource(omxNode); - EXPECT_NE(buffersource, nullptr); + ASSERT_NE(buffersource, nullptr); status = omxNode->setInputSurface(buffersource); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); @@ -1178,20 +1161,20 @@ TEST_F(VideoEncHidlTest, BufferSourceCallBacks) { ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &buffersource->iBuffer, - &buffersource->oBuffer, kPortIndexInput, - kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle( + omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer, + kPortIndexInput, kPortIndexOutput, portMode)); // set state to executing - changeStateIdletoExecute(omxNode, observer); - testEOS(omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer, - false, eosFlag); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); + ASSERT_NO_FATAL_FAILURE(testEOS(omxNode, observer, &buffersource->iBuffer, + &buffersource->oBuffer, false, eosFlag)); // set state to idle - changeStateExecutetoIdle(omxNode, observer, &buffersource->iBuffer, - &buffersource->oBuffer); + ASSERT_NO_FATAL_FAILURE(changeStateExecutetoIdle( + omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &buffersource->iBuffer, - &buffersource->oBuffer, kPortIndexInput, - kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded( + omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer, + kPortIndexInput, kPortIndexOutput)); // test for callbacks EXPECT_EQ(buffersource->callback, 31); } @@ -1245,8 +1228,9 @@ TEST_F(VideoEncHidlTest, EncodeTest) { // Configure output port uint32_t nBitRate = 512000; - setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat, nBitRate, - xFramerate); + ASSERT_NO_FATAL_FAILURE( + setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat, + nFrameWidth, nFrameHeight, nBitRate, xFramerate)); setRefreshPeriod(omxNode, kPortIndexOutput, 0); unsigned int index; @@ -1263,8 +1247,7 @@ TEST_F(VideoEncHidlTest, EncodeTest) { status = setParam(omxNode, static_cast<OMX_INDEXTYPE>(index), ¶m); } if (status != ::android::hardware::media::omx::V1_0::Status::OK) - std::cerr - << "[ ] Warning ! unable to prependSPSPPSToIDRFrames\n"; + std::cout << "[ INFO ] unable to prependSPSPPSToIDRFrames\n"; else prependSPSPPS = true; @@ -1283,27 +1266,32 @@ TEST_F(VideoEncHidlTest, EncodeTest) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - encodeNFrames(omxNode, observer, kPortIndexInput, kPortIndexOutput, - &iBuffer, &oBuffer, 32, xFramerate, - (nFrameWidth * nFrameHeight * 3) >> 1, eleStream, - ×tampUslist); + ASSERT_NO_FATAL_FAILURE(encodeNFrames( + omxNode, observer, kPortIndexInput, kPortIndexOutput, &iBuffer, + &oBuffer, 32, xFramerate, (nFrameWidth * nFrameHeight * 3) >> 1, + eleStream, ×tampUslist)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer); - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); - EXPECT_EQ(timestampUslist.empty(), true); + ASSERT_NO_FATAL_FAILURE( + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer)); + ASSERT_NO_FATAL_FAILURE( + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag)); + if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true); // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); } // test raw stream encode (input is ANW buffers) @@ -1330,6 +1318,11 @@ TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0, xFramerate, eColorFormat); + // Configure output port + uint32_t nBitRate = 512000; + ASSERT_NO_FATAL_FAILURE( + setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat, + nFrameWidth, nFrameHeight, nBitRate, xFramerate)); // CreateInputSurface EXPECT_TRUE(omx->createInputSurface( [&](android::hardware::media::omx::V1_0::Status _s, @@ -1436,28 +1429,32 @@ TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); - encodeNFrames(omxNode, observer, kPortIndexInput, kPortIndexOutput, - &iBuffer, &oBuffer, 1024, xFramerate, - (nFrameWidth * nFrameHeight * 3) >> 1, eleStream, nullptr, - false, true, producer, listener); + ASSERT_NO_FATAL_FAILURE(encodeNFrames( + omxNode, observer, kPortIndexInput, kPortIndexOutput, &iBuffer, + &oBuffer, 1024, xFramerate, (nFrameWidth * nFrameHeight * 3) >> 1, + eleStream, nullptr, false, true, producer, listener)); eleStream.close(); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, true, - listener); - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); + ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(omxNode, observer, &iBuffer, + &oBuffer, true, listener)); + ASSERT_NO_FATAL_FAILURE( + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag)); // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); returnval = producer->disconnect( NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API); @@ -1551,24 +1548,28 @@ TEST_F(VideoEncHidlTest, EncodeTestEOS) { android::Vector<BufferInfo> iBuffer, oBuffer; // set state to idle - changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput, portMode); + ASSERT_NO_FATAL_FAILURE( + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode)); // set state to executing - changeStateIdletoExecute(omxNode, observer); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer)); // send EOS status = source->signalEndOfInputStream(); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); - waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, true, - listener); - testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); + ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(omxNode, observer, &iBuffer, + &oBuffer, true, listener)); + ASSERT_NO_FATAL_FAILURE( + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag)); // set state to idle - changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + ASSERT_NO_FATAL_FAILURE( + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer)); EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers); // set state to executing - changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, + &oBuffer, kPortIndexInput, + kPortIndexOutput)); returnval = producer->disconnect( NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API); diff --git a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp index 91aecf22e6..e1b6022f9d 100644 --- a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp @@ -15,7 +15,6 @@ */ #define LOG_TAG "media_omx_hidl_video_test_common" - #ifdef __LP64__ #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS #endif diff --git a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h index c1d7aeae55..55de125877 100644 --- a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h +++ b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h @@ -18,14 +18,8 @@ #define MEDIA_VIDEO_HIDL_TEST_COMMON_H /* - * Random Index used for monkey testing while get/set parameters - */ -#define RANDOM_INDEX 1729 - -/* * Common video utils */ - void enumerateProfileAndLevel(sp<IOmxNode> omxNode, OMX_U32 portIndex, std::vector<int32_t>* arrProfile, std::vector<int32_t>* arrLevel); diff --git a/media/res/bbb_aac_stereo_128kbps_48000hz.aac b/media/res/bbb_aac_stereo_128kbps_48000hz.aac Binary files differindex 831102d223..831102d223 100755..100644 --- a/media/res/bbb_aac_stereo_128kbps_48000hz.aac +++ b/media/res/bbb_aac_stereo_128kbps_48000hz.aac diff --git a/media/res/bbb_aac_stereo_128kbps_48000hz.info b/media/res/bbb_aac_stereo_128kbps_48000hz.info index d124f30dda..d124f30dda 100755..100644 --- a/media/res/bbb_aac_stereo_128kbps_48000hz.info +++ b/media/res/bbb_aac_stereo_128kbps_48000hz.info diff --git a/media/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb b/media/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb Binary files differindex 0d8259378f..0d8259378f 100755..100644 --- a/media/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb +++ b/media/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb diff --git a/media/res/bbb_amrwb_1ch_14kbps_16000hz.info b/media/res/bbb_amrwb_1ch_14kbps_16000hz.info index 71cffefea8..71cffefea8 100755..100644 --- a/media/res/bbb_amrwb_1ch_14kbps_16000hz.info +++ b/media/res/bbb_amrwb_1ch_14kbps_16000hz.info diff --git a/media/res/bbb_avc_176x144_300kbps_60fps.h264 b/media/res/bbb_avc_176x144_300kbps_60fps.h264 Binary files differnew file mode 100644 index 0000000000..da1e75dcd1 --- /dev/null +++ b/media/res/bbb_avc_176x144_300kbps_60fps.h264 diff --git a/media/res/bbb_avc_176x144_300kbps_60fps.info b/media/res/bbb_avc_176x144_300kbps_60fps.info new file mode 100644 index 0000000000..d88b540ef4 --- /dev/null +++ b/media/res/bbb_avc_176x144_300kbps_60fps.info @@ -0,0 +1,62 @@ +28 128 0 +10 128 0 +4780 32 33333 +960 0 100000 +480 0 66666 +246 0 50000 +264 0 83333 +1160 0 166666 +404 0 133333 +237 0 116666 +193 0 150000 +936 0 233333 +384 0 200000 +199 0 183333 +275 0 216666 +1086 0 300000 +520 0 266666 +301 0 250000 +270 0 283333 +1232 0 366666 +559 0 333333 +287 0 316666 +274 0 350000 +1084 0 433333 +485 0 400000 +307 0 383333 +284 0 416666 +1052 0 500000 +504 0 466666 +298 0 450000 +327 0 483333 +1189 0 566666 +358 0 533333 +172 0 516666 +185 0 550000 +1115 0 633333 +463 0 600000 +218 0 583333 +255 0 616666 +1155 0 700000 +622 0 666666 +356 0 650000 +341 0 683333 +1240 0 766666 +610 0 733333 +341 0 716666 +380 0 750000 +1326 0 833333 +620 0 800000 +396 0 783333 +353 0 816666 +1196 0 900000 +623 0 866666 +375 0 850000 +362 0 883333 +1192 0 966666 +654 0 933333 +359 0 916666 +352 0 950000 +828 0 1016666 +436 0 983333 +401 0 1000000 diff --git a/media/res/bbb_flac_stereo_680kbps_48000hz.flac b/media/res/bbb_flac_stereo_680kbps_48000hz.flac Binary files differnew file mode 100644 index 0000000000..db94d8eb04 --- /dev/null +++ b/media/res/bbb_flac_stereo_680kbps_48000hz.flac diff --git a/media/res/bbb_flac_stereo_680kbps_48000hz.info b/media/res/bbb_flac_stereo_680kbps_48000hz.info new file mode 100644 index 0000000000..c57243079d --- /dev/null +++ b/media/res/bbb_flac_stereo_680kbps_48000hz.info @@ -0,0 +1,415 @@ +42 128 0 +1386 32 0 +2401 32 24000 +2321 32 48000 +2367 32 72000 +2370 32 96000 +2334 32 120000 +2396 32 144000 +2375 32 168000 +2431 32 192000 +2428 32 216000 +2334 32 240000 +2261 32 264000 +2124 32 288000 +2152 32 312000 +2295 32 336000 +2183 32 360000 +2393 32 384000 +2400 32 408000 +2246 32 432000 +2289 32 456000 +2400 32 480000 +2335 32 504000 +2294 32 528000 +2260 32 552000 +2206 32 576000 +2185 32 600000 +2155 32 624000 +2118 32 648000 +2094 32 672000 +2050 32 696000 +2059 32 720000 +2030 32 744000 +2022 32 768000 +2078 32 792000 +2082 32 816000 +2094 32 840000 +2111 32 864000 +2043 32 888000 +2023 32 912000 +2024 32 936000 +2056 32 960000 +2108 32 984000 +2138 32 1008000 +2140 32 1032000 +2111 32 1056000 +2110 32 1080000 +2137 32 1104000 +2157 32 1128000 +2174 32 1152000 +2200 32 1176000 +2203 32 1200000 +2237 32 1224000 +2261 32 1248000 +2215 32 1272000 +2133 32 1296000 +2091 32 1320000 +2088 32 1344000 +2122 32 1368000 +2139 32 1392000 +2146 32 1416000 +2231 32 1440000 +2282 32 1464000 +2273 32 1488000 +2304 32 1512000 +2292 32 1536000 +2255 32 1560000 +2181 32 1584000 +2081 32 1608000 +2012 32 1632000 +2011 32 1656000 +2066 32 1680000 +2069 32 1704000 +2120 32 1728000 +2141 32 1752000 +2148 32 1776000 +2181 32 1800000 +2176 32 1824000 +2240 32 1848000 +2297 32 1872000 +2325 32 1896000 +2336 32 1920000 +2329 32 1944000 +2299 32 1968000 +2322 32 1992000 +2347 32 2016000 +2287 32 2040000 +2286 32 2064000 +2269 32 2088000 +2320 32 2112000 +2305 32 2136000 +2384 32 2160000 +2429 32 2184000 +2370 32 2208000 +2365 32 2232000 +2361 32 2256000 +2370 32 2280000 +2393 32 2304000 +2342 32 2328000 +2325 32 2352000 +2334 32 2376000 +2316 32 2400000 +2317 32 2424000 +2305 32 2448000 +2360 32 2472000 +2331 32 2496000 +2332 32 2520000 +2361 32 2544000 +2417 32 2568000 +2438 32 2592000 +2403 32 2616000 +2386 32 2640000 +2382 32 2664000 +2350 32 2688000 +2355 32 2712000 +2383 32 2736000 +2384 32 2760000 +2383 32 2784000 +2373 32 2808000 +2374 32 2832000 +2347 32 2856000 +2353 32 2880000 +2381 32 2904000 +2401 32 2928000 +2401 32 2952000 +2385 32 2976000 +2382 32 3000000 +2328 32 3024000 +2303 32 3048000 +2272 32 3072000 +2270 32 3096000 +2312 32 3120000 +2273 32 3144000 +2330 32 3168000 +2339 32 3192000 +2296 32 3216000 +2317 32 3240000 +2440 32 3264000 +2353 32 3288000 +2346 32 3312000 +2303 32 3336000 +2308 32 3360000 +2287 32 3384000 +2316 32 3408000 +2367 32 3432000 +2335 32 3456000 +2350 32 3480000 +2395 32 3504000 +2408 32 3528000 +2413 32 3552000 +2415 32 3576000 +2468 32 3600000 +2437 32 3624000 +2372 32 3648000 +2371 32 3672000 +2341 32 3696000 +2328 32 3720000 +2273 32 3744000 +2244 32 3768000 +2233 32 3792000 +2229 32 3816000 +2252 32 3840000 +2236 32 3864000 +2217 32 3888000 +2179 32 3912000 +2251 32 3936000 +2192 32 3960000 +2199 32 3984000 +2212 32 4008000 +2190 32 4032000 +2102 32 4056000 +2120 32 4080000 +2167 32 4104000 +2024 32 4128000 +2010 32 4152000 +2067 32 4176000 +2035 32 4200000 +2051 32 4224000 +2012 32 4248000 +2066 32 4272000 +2025 32 4296000 +1987 32 4320000 +1972 32 4344000 +1966 32 4368000 +1999 32 4392000 +1987 32 4416000 +1922 32 4440000 +2020 32 4464000 +2072 32 4488000 +2021 32 4512000 +2017 32 4536000 +2099 32 4560000 +2064 32 4584000 +2109 32 4608000 +2093 32 4632000 +2090 32 4656000 +2148 32 4680000 +2184 32 4704000 +2179 32 4728000 +2152 32 4752000 +2143 32 4776000 +2159 32 4800000 +2123 32 4824000 +2129 32 4848000 +2147 32 4872000 +2192 32 4896000 +2051 32 4920000 +2116 32 4944000 +2124 32 4968000 +2088 32 4992000 +2073 32 5016000 +2146 32 5040000 +2133 32 5064000 +2073 32 5088000 +2059 32 5112000 +2044 32 5136000 +2012 32 5160000 +2034 32 5184000 +2053 32 5208000 +2013 32 5232000 +1981 32 5256000 +2094 32 5280000 +2076 32 5304000 +1968 32 5328000 +2028 32 5352000 +2031 32 5376000 +2020 32 5400000 +2019 32 5424000 +2030 32 5448000 +2015 32 5472000 +1962 32 5496000 +2070 32 5520000 +2087 32 5544000 +1964 32 5568000 +2069 32 5592000 +2034 32 5616000 +1994 32 5640000 +1985 32 5664000 +2030 32 5688000 +2066 32 5712000 +1954 32 5736000 +1733 32 5760000 +1649 32 5784000 +1652 32 5808000 +1631 32 5832000 +1656 32 5856000 +1672 32 5880000 +1667 32 5904000 +1696 32 5928000 +1672 32 5952000 +1701 32 5976000 +1651 32 6000000 +1674 32 6024000 +1695 32 6048000 +1702 32 6072000 +1707 32 6096000 +1694 32 6120000 +1727 32 6144000 +1730 32 6168000 +1708 32 6192000 +1704 32 6216000 +1735 32 6240000 +1758 32 6264000 +1753 32 6288000 +1748 32 6312000 +1763 32 6336000 +1737 32 6360000 +1783 32 6384000 +1839 32 6408000 +1861 32 6432000 +1832 32 6456000 +1947 32 6480000 +1939 32 6504000 +1926 32 6528000 +1896 32 6552000 +1909 32 6576000 +1869 32 6600000 +1900 32 6624000 +1896 32 6648000 +1883 32 6672000 +1903 32 6696000 +1895 32 6720000 +1865 32 6744000 +1878 32 6768000 +1881 32 6792000 +1861 32 6816000 +1791 32 6840000 +1787 32 6864000 +1798 32 6888000 +1811 32 6912000 +1824 32 6936000 +1895 32 6960000 +2079 32 6984000 +2034 32 7008000 +2038 32 7032000 +2018 32 7056000 +2030 32 7080000 +2067 32 7104000 +1982 32 7128000 +1911 32 7152000 +1904 32 7176000 +1874 32 7200000 +1876 32 7224000 +1944 32 7248000 +1977 32 7272000 +1977 32 7296000 +1979 32 7320000 +2012 32 7344000 +1961 32 7368000 +1773 32 7392000 +1780 32 7416000 +1801 32 7440000 +1892 32 7464000 +1869 32 7488000 +1936 32 7512000 +2154 32 7536000 +2226 32 7560000 +2159 32 7584000 +2253 32 7608000 +2286 32 7632000 +2214 32 7656000 +2111 32 7680000 +2027 32 7704000 +1994 32 7728000 +1882 32 7752000 +1887 32 7776000 +1993 32 7800000 +1962 32 7824000 +1982 32 7848000 +1966 32 7872000 +1962 32 7896000 +1928 32 7920000 +1878 32 7944000 +1857 32 7968000 +1885 32 7992000 +1919 32 8016000 +1904 32 8040000 +1909 32 8064000 +1909 32 8088000 +1933 32 8112000 +1824 32 8136000 +1756 32 8160000 +1733 32 8184000 +1705 32 8208000 +1755 32 8232000 +1756 32 8256000 +1725 32 8280000 +1761 32 8304000 +1736 32 8328000 +1706 32 8352000 +1662 32 8376000 +1604 32 8400000 +1613 32 8424000 +1692 32 8448000 +1736 32 8472000 +1779 32 8496000 +1768 32 8520000 +1758 32 8544000 +1708 32 8568000 +1642 32 8592000 +1645 32 8616000 +1581 32 8640000 +1651 32 8664000 +1731 32 8688000 +1743 32 8712000 +1717 32 8736000 +1715 32 8760000 +1646 32 8784000 +1551 32 8808000 +1563 32 8832000 +1649 32 8856000 +1742 32 8880000 +1724 32 8904000 +1676 32 8928000 +1664 32 8952000 +1587 32 8976000 +1497 32 9000000 +1503 32 9024000 +1644 32 9048000 +1658 32 9072000 +1680 32 9096000 +1611 32 9120000 +1694 32 9144000 +1668 32 9168000 +1677 32 9192000 +1604 32 9216000 +1567 32 9240000 +1639 32 9264000 +1552 32 9288000 +1486 32 9312000 +1494 32 9336000 +1480 32 9360000 +1509 32 9384000 +1457 32 9408000 +1423 32 9432000 +1459 32 9456000 +1444 32 9480000 +1424 32 9504000 +1413 32 9528000 +1498 32 9552000 +1455 32 9576000 +1393 32 9600000 +1638 32 9624000 +1919 32 9648000 +1979 32 9672000 +1894 32 9696000 +2002 32 9720000 +2062 32 9744000 +2098 32 9768000 +1919 32 9792000 +1738 32 9816000 +1890 32 9840000 +1971 32 9864000 +2429 32 9888000 +1861 32 9912000 diff --git a/media/res/bbb_g711alaw_1ch_8khz.info b/media/res/bbb_g711alaw_1ch_8khz.info index 2ffe358eb4..2ffe358eb4 100755..100644 --- a/media/res/bbb_g711alaw_1ch_8khz.info +++ b/media/res/bbb_g711alaw_1ch_8khz.info diff --git a/media/res/bbb_g711alaw_1ch_8khz.raw b/media/res/bbb_g711alaw_1ch_8khz.raw index cfc4a11cfe..cfc4a11cfe 100755..100644 --- a/media/res/bbb_g711alaw_1ch_8khz.raw +++ b/media/res/bbb_g711alaw_1ch_8khz.raw diff --git a/media/res/bbb_g711mulaw_1ch_8khz.info b/media/res/bbb_g711mulaw_1ch_8khz.info index 5162a17f0b..5162a17f0b 100755..100644 --- a/media/res/bbb_g711mulaw_1ch_8khz.info +++ b/media/res/bbb_g711mulaw_1ch_8khz.info diff --git a/media/res/bbb_g711mulaw_1ch_8khz.raw b/media/res/bbb_g711mulaw_1ch_8khz.raw index f38f1cae63..f38f1cae63 100755..100644 --- a/media/res/bbb_g711mulaw_1ch_8khz.raw +++ b/media/res/bbb_g711mulaw_1ch_8khz.raw diff --git a/media/res/bbb_gsm_1ch_8khz_13kbps.info b/media/res/bbb_gsm_1ch_8khz_13kbps.info index b15b296a27..b15b296a27 100755..100644 --- a/media/res/bbb_gsm_1ch_8khz_13kbps.info +++ b/media/res/bbb_gsm_1ch_8khz_13kbps.info diff --git a/media/res/bbb_gsm_1ch_8khz_13kbps.raw b/media/res/bbb_gsm_1ch_8khz_13kbps.raw Binary files differindex df903a8d6e..df903a8d6e 100755..100644 --- a/media/res/bbb_gsm_1ch_8khz_13kbps.raw +++ b/media/res/bbb_gsm_1ch_8khz_13kbps.raw diff --git a/media/res/bbb_hevc_176x144_176kbps_60fps.hevc b/media/res/bbb_hevc_176x144_176kbps_60fps.hevc Binary files differnew file mode 100644 index 0000000000..f82236f3a0 --- /dev/null +++ b/media/res/bbb_hevc_176x144_176kbps_60fps.hevc diff --git a/media/res/bbb_hevc_176x144_176kbps_60fps.info b/media/res/bbb_hevc_176x144_176kbps_60fps.info new file mode 100644 index 0000000000..702b853697 --- /dev/null +++ b/media/res/bbb_hevc_176x144_176kbps_60fps.info @@ -0,0 +1,61 @@ +1695 128 0 +1938 32 33333 +471 0 83333 +153 0 66666 +99 0 50000 +657 0 150000 +260 0 116666 +115 0 100000 +99 0 133333 +622 0 216666 +211 0 183333 +79 0 166666 +95 0 200000 +597 0 283333 +288 0 250000 +145 0 233333 +147 0 266666 +676 0 350000 +284 0 316666 +144 0 300000 +131 0 333333 +658 0 416666 +270 0 383333 +101 0 366666 +151 0 400000 +529 0 483333 +257 0 450000 +98 0 433333 +160 0 466666 +664 0 566666 +186 0 533333 +147 0 500000 +67 0 516666 +78 0 550000 +575 0 633333 +230 0 600000 +134 0 583333 +114 0 616666 +629 0 700000 +224 0 666666 +138 0 650000 +129 0 683333 +645 0 750000 +264 0 733333 +145 0 716666 +705 0 816666 +365 0 783333 +156 0 766666 +160 0 800000 +725 0 883333 +330 0 850000 +138 0 833333 +162 0 866666 +638 0 950000 +337 0 916666 +170 0 900000 +133 0 933333 +432 0 1016666 +287 0 983333 +130 0 966666 +136 0 1000000 diff --git a/media/res/bbb_mpeg2_352x288_1mbps_60fps.info b/media/res/bbb_mpeg2_352x288_1mbps_60fps.info new file mode 100644 index 0000000000..d5290d70d3 --- /dev/null +++ b/media/res/bbb_mpeg2_352x288_1mbps_60fps.info @@ -0,0 +1,60 @@ +16680 32 16666 +17017 0 33333 +10534 0 50000 +10289 0 66666 +3698 0 83333 +2776 0 100000 +1936 0 116666 +1493 0 133333 +1217 0 150000 +993 0 166666 +805 0 183333 +857 0 200000 +5082 32 216666 +812 0 233333 +718 0 250000 +746 0 266666 +762 0 283333 +865 0 300000 +782 0 316666 +833 0 333333 +750 0 350000 +819 0 366666 +826 0 383333 +846 0 400000 +4522 32 416666 +678 0 433333 +718 0 450000 +803 0 466666 +769 0 483333 +762 0 500000 +587 0 516666 +635 0 533333 +658 0 550000 +714 0 566666 +677 0 583333 +699 0 600000 +4616 32 616666 +800 0 633333 +831 0 650000 +928 0 666666 +869 0 683333 +931 0 700000 +930 0 716666 +974 0 733333 +978 0 750000 +932 0 766666 +918 0 783333 +978 0 800000 +4655 32 816666 +897 0 833333 +896 0 850000 +883 0 866666 +949 0 883333 +965 0 900000 +951 0 916666 +901 0 933333 +965 0 950000 +955 0 966666 +948 0 983333 +968 0 1000000 diff --git a/media/res/bbb_mpeg2_352x288_1mbps_60fps.m2v b/media/res/bbb_mpeg2_352x288_1mbps_60fps.m2v Binary files differnew file mode 100644 index 0000000000..2f67c2b382 --- /dev/null +++ b/media/res/bbb_mpeg2_352x288_1mbps_60fps.m2v diff --git a/media/res/bbb_opus_stereo_128kbps_48000hz.info b/media/res/bbb_opus_stereo_128kbps_48000hz.info index 12a6b99652..12a6b99652 100755..100644 --- a/media/res/bbb_opus_stereo_128kbps_48000hz.info +++ b/media/res/bbb_opus_stereo_128kbps_48000hz.info diff --git a/media/res/bbb_opus_stereo_128kbps_48000hz.opus b/media/res/bbb_opus_stereo_128kbps_48000hz.opus Binary files differindex 7b763b2c15..7b763b2c15 100755..100644 --- a/media/res/bbb_opus_stereo_128kbps_48000hz.opus +++ b/media/res/bbb_opus_stereo_128kbps_48000hz.opus diff --git a/media/res/bbb_raw_1ch_8khz_s32le.info b/media/res/bbb_raw_1ch_8khz_s32le.info index 933925beae..933925beae 100755..100644 --- a/media/res/bbb_raw_1ch_8khz_s32le.info +++ b/media/res/bbb_raw_1ch_8khz_s32le.info diff --git a/media/res/bbb_raw_1ch_8khz_s32le.raw b/media/res/bbb_raw_1ch_8khz_s32le.raw Binary files differindex fd91b46219..fd91b46219 100755..100644 --- a/media/res/bbb_raw_1ch_8khz_s32le.raw +++ b/media/res/bbb_raw_1ch_8khz_s32le.raw diff --git a/media/res/bbb_vorbis_stereo_128kbps_48000hz.info b/media/res/bbb_vorbis_stereo_128kbps_48000hz.info index 0716643c50..0716643c50 100755..100644 --- a/media/res/bbb_vorbis_stereo_128kbps_48000hz.info +++ b/media/res/bbb_vorbis_stereo_128kbps_48000hz.info diff --git a/media/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis b/media/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis Binary files differindex 404c5f8151..404c5f8151 100755..100644 --- a/media/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis +++ b/media/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis diff --git a/media/res/bbb_vp8_176x144_240kbps_60fps.info b/media/res/bbb_vp8_176x144_240kbps_60fps.info new file mode 100644 index 0000000000..559f42580b --- /dev/null +++ b/media/res/bbb_vp8_176x144_240kbps_60fps.info @@ -0,0 +1,60 @@ +10271 32 0 +106 0 17000 +134 0 33000 +149 0 50000 +152 0 67000 +159 0 83000 +114 0 100000 +723 0 117000 +175 0 133000 +186 0 150000 +201 0 167000 +270 0 183000 +383 0 200000 +255 0 217000 +286 0 233000 +273 0 250000 +1224 0 267000 +220 0 283000 +231 0 300000 +192 0 317000 +182 0 333000 +289 0 350000 +204 0 367000 +237 0 383000 +187 0 400000 +898 0 417000 +231 0 433000 +266 0 450000 +278 0 467000 +205 0 483000 +255 0 500000 +169 0 517000 +233 0 533000 +1011 0 550000 +202 0 567000 +251 0 583000 +223 0 600000 +283 0 617000 +362 0 633000 +217 0 650000 +245 0 667000 +960 0 683000 +233 0 700000 +286 0 717000 +272 0 733000 +254 0 750000 +331 0 767000 +218 0 783000 +261 0 800000 +981 0 817000 +226 0 833000 +226 0 850000 +279 0 867000 +225 0 883000 +295 0 900000 +175 0 917000 +249 0 933000 +996 0 950000 +169 0 967000 +224 0 983000 diff --git a/media/res/bbb_vp8_176x144_240kbps_60fps.vp8 b/media/res/bbb_vp8_176x144_240kbps_60fps.vp8 Binary files differnew file mode 100644 index 0000000000..6eba56ccad --- /dev/null +++ b/media/res/bbb_vp8_176x144_240kbps_60fps.vp8 diff --git a/media/res/bbb_vp9_176x144_285kbps_60fps.info b/media/res/bbb_vp9_176x144_285kbps_60fps.info new file mode 100644 index 0000000000..2f7d35bed2 --- /dev/null +++ b/media/res/bbb_vp9_176x144_285kbps_60fps.info @@ -0,0 +1,60 @@ +6939 32 0 +6818 0 17000 +310 0 33000 +273 0 50000 +267 0 67000 +239 0 83000 +232 0 100000 +222 0 117000 +186 0 133000 +194 0 150000 +189 0 167000 +18 0 183000 +2014 0 200000 +297 0 217000 +287 0 233000 +237 0 250000 +263 0 267000 +238 0 283000 +257 0 300000 +229 0 317000 +187 0 333000 +191 0 350000 +18 0 367000 +2203 0 383000 +265 0 400000 +224 0 417000 +254 0 433000 +252 0 450000 +273 0 467000 +208 0 483000 +154 0 500000 +182 0 517000 +138 0 533000 +18 0 550000 +2502 0 567000 +286 0 583000 +304 0 600000 +341 0 617000 +259 0 633000 +275 0 650000 +222 0 667000 +254 0 683000 +253 0 700000 +225 0 717000 +18 0 733000 +2501 0 750000 +282 0 767000 +298 0 783000 +252 0 800000 +242 0 817000 +250 0 833000 +260 0 850000 +218 0 867000 +213 0 883000 +144 0 900000 +18 0 917000 +233 0 933000 +254 0 950000 +229 0 967000 +239 0 983000 diff --git a/media/res/bbb_vp9_176x144_285kbps_60fps.vp9 b/media/res/bbb_vp9_176x144_285kbps_60fps.vp9 Binary files differnew file mode 100644 index 0000000000..2633c8a6c4 --- /dev/null +++ b/media/res/bbb_vp9_176x144_285kbps_60fps.vp9 diff --git a/neuralnetworks/1.0/Android.bp b/neuralnetworks/1.0/Android.bp new file mode 100644 index 0000000000..ba32d0c396 --- /dev/null +++ b/neuralnetworks/1.0/Android.bp @@ -0,0 +1,87 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.neuralnetworks@1.0_hal", + srcs: [ + "types.hal", + "IDevice.hal", + "IExecutionCallback.hal", + "IPreparedModel.hal", + "IPreparedModelCallback.hal", + ], +} + +genrule { + name: "android.hardware.neuralnetworks@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.neuralnetworks@1.0", + srcs: [ + ":android.hardware.neuralnetworks@1.0_hal", + ], + out: [ + "android/hardware/neuralnetworks/1.0/types.cpp", + "android/hardware/neuralnetworks/1.0/DeviceAll.cpp", + "android/hardware/neuralnetworks/1.0/ExecutionCallbackAll.cpp", + "android/hardware/neuralnetworks/1.0/PreparedModelAll.cpp", + "android/hardware/neuralnetworks/1.0/PreparedModelCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.neuralnetworks@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.neuralnetworks@1.0", + srcs: [ + ":android.hardware.neuralnetworks@1.0_hal", + ], + out: [ + "android/hardware/neuralnetworks/1.0/types.h", + "android/hardware/neuralnetworks/1.0/hwtypes.h", + "android/hardware/neuralnetworks/1.0/IDevice.h", + "android/hardware/neuralnetworks/1.0/IHwDevice.h", + "android/hardware/neuralnetworks/1.0/BnHwDevice.h", + "android/hardware/neuralnetworks/1.0/BpHwDevice.h", + "android/hardware/neuralnetworks/1.0/BsDevice.h", + "android/hardware/neuralnetworks/1.0/IExecutionCallback.h", + "android/hardware/neuralnetworks/1.0/IHwExecutionCallback.h", + "android/hardware/neuralnetworks/1.0/BnHwExecutionCallback.h", + "android/hardware/neuralnetworks/1.0/BpHwExecutionCallback.h", + "android/hardware/neuralnetworks/1.0/BsExecutionCallback.h", + "android/hardware/neuralnetworks/1.0/IPreparedModel.h", + "android/hardware/neuralnetworks/1.0/IHwPreparedModel.h", + "android/hardware/neuralnetworks/1.0/BnHwPreparedModel.h", + "android/hardware/neuralnetworks/1.0/BpHwPreparedModel.h", + "android/hardware/neuralnetworks/1.0/BsPreparedModel.h", + "android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h", + "android/hardware/neuralnetworks/1.0/IHwPreparedModelCallback.h", + "android/hardware/neuralnetworks/1.0/BnHwPreparedModelCallback.h", + "android/hardware/neuralnetworks/1.0/BpHwPreparedModelCallback.h", + "android/hardware/neuralnetworks/1.0/BsPreparedModelCallback.h", + ], +} + +cc_library { + name: "android.hardware.neuralnetworks@1.0", + defaults: ["hidl-module-defaults"], + generated_sources: ["android.hardware.neuralnetworks@1.0_genc++"], + generated_headers: ["android.hardware.neuralnetworks@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.neuralnetworks@1.0_genc++_headers"], + vendor_available: true, + vndk: { + enabled: true, + }, + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +} diff --git a/neuralnetworks/1.0/IDevice.hal b/neuralnetworks/1.0/IDevice.hal new file mode 100644 index 0000000000..49c29674ee --- /dev/null +++ b/neuralnetworks/1.0/IDevice.hal @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.neuralnetworks@1.0; + +import IPreparedModelCallback; + +/** + * This interface represents a device driver. + */ +interface IDevice { + /** + * Gets the capabilities of a driver. + * + * @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 capabilities Capabilities of the driver. + */ + getCapabilities() generates (ErrorStatus status, Capabilities capabilities); + + /** + * Gets the supported operations in a model. + * + * getSupportedSubgraph indicates which operations of a model are fully + * supported by the vendor driver. If an operation may not be supported for + * any reason, getSupportedOperations must return false for that operation. + * + * @param model A model whose operations--and their corresponding + * operands--are to be verified by the driver. + * @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 + * - INVALID_ARGUMENT if provided model is invalid + * @return supportedOperations A list of supported operations, where true + * indicates the operation is supported and + * false indicates the operation is not + * supported. The index of "supported" + * corresponds with the index of the operation + * it is describing. + */ + getSupportedOperations(Model model) + generates (ErrorStatus status, vec<bool> supportedOperations); + + /** + * Creates a prepared model for execution. + * + * prepareModel is used to make any necessary transformations or alternative + * representations to a model for execution, possiblly including + * transformations on the constant data, optimization on the model's graph, + * or compilation into the device's native binary format. The model itself + * is not changed. + * + * The model is prepared asynchronously with respect to the caller. The + * prepareModel function must verify the inputs to the prepareModel function + * are correct. If there is an error, prepareModel 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 prepareModel function are valid and there is no error, prepareModel + * must launch an asynchronous task to prepare the model in the background, + * and immediately return from prepareModel with ErrorStatus::NONE. If the + * asynchronous task fails to launch, prepareModel 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 + * prepareModel. 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 can only be finished when it is paired with a set of + * inputs to the model. Note that the same prepared model object can be + * used with different shapes of inputs on different (possibly concurrent) + * executions. + * + * Multiple threads can call prepareModel on the same model concurrently. + * + * @param model The model to be prepared for execution. + * @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 there is an unspecified error + * - INVALID_ARGUMENT if one of the input arguments is + * invalid + */ + prepareModel(Model model, IPreparedModelCallback callback) + generates (ErrorStatus status); + + /** + * Returns the current status of a driver. + * + * @return status Status of the driver, one of: + * - DeviceStatus::AVAILABLE + * - DeviceStatus::BUSY + * - DeviceStatus::OFFLINE + * - DeviceStatus::UNKNOWN + */ + getStatus() generates (DeviceStatus status); +}; diff --git a/neuralnetworks/1.0/IExecutionCallback.hal b/neuralnetworks/1.0/IExecutionCallback.hal new file mode 100644 index 0000000000..ef0f4549dd --- /dev/null +++ b/neuralnetworks/1.0/IExecutionCallback.hal @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.neuralnetworks@1.0; + +/** + * IExecutionCallback must be used to return the error status result from an + * execution asynchronously launched from IPreparedModel::execute. + */ +interface IExecutionCallback { + + /** + * notify must be invoked immediately after the asynchronous task has + * finished performing the execution. notify must be provided with the + * ErrorStatus resulting from the execution. If the asynchronous task + * is not launched, notify must be invoked with the appropriate error. + * + * @return param Error status returned from launching the asynchronous task + * (if the launch fails) or from the asynchronous task itself + * (if the launch succeeds). Must be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an + * unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is + * not large enough to store the resultant values + * - INVALID_ARGUMENT if one of the input arguments to + * prepareModel is invalid + */ + oneway notify(ErrorStatus status); +}; diff --git a/neuralnetworks/1.0/IPreparedModel.hal b/neuralnetworks/1.0/IPreparedModel.hal new file mode 100644 index 0000000000..ee406fb79b --- /dev/null +++ b/neuralnetworks/1.0/IPreparedModel.hal @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.neuralnetworks@1.0; + +import IExecutionCallback; + +/** + * IPreparedModel describes a model that has been prepared for execution and + * is used to launch executions. + */ +interface IPreparedModel { + /** + * Launches an asynchronous execution on a prepared model. + * + * The execution is performed asynchronously with respect to the caller. + * execute must verify the inputs to the function are correct. If there is + * an error, execute must immediately invoke the callback with the + * appropriate ErrorStatus value, then return with the same ErrorStatus. If + * the inputs to the function are valid and there is no error, execute must + * launch an asynchronous task to perform the execution in the background, + * and immediately return with ErrorStatus::NONE. If the asynchronous task + * fails to launch, execute must immediately invoke the callback with + * ErrorStatus::GENERAL_FAILURE, then return with + * ErrorStatus::GENERAL_FAILURE. + * + * When the asynchronous task has finished its execution, it must + * immediately invoke the callback object provided as an input to the + * execute function. This callback must be provided with the ErrorStatus of + * the execution. + * + * Multiple threads can call the execute function on the same IPreparedModel + * object concurrently with different requests. + * + * @param request The input and output information on which the prepared + * model is to be executed. + * @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 + * unsuccessful. + * @return status Error status of the call, must be: + * - NONE if task is successfully launched + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is + * not large enough to store the resultant values + * - INVALID_ARGUMENT if one of the input arguments is + * invalid + */ + execute(Request request, IExecutionCallback callback) + generates (ErrorStatus status); +}; diff --git a/neuralnetworks/1.0/IPreparedModelCallback.hal b/neuralnetworks/1.0/IPreparedModelCallback.hal new file mode 100644 index 0000000000..fa1bf9d508 --- /dev/null +++ b/neuralnetworks/1.0/IPreparedModelCallback.hal @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.neuralnetworks@1.0; + +import IPreparedModel; + +/** + * IPreparedModelCallback must be used to return a prepared model produced by an + * asynchronous task launched from IDevice::prepareModel. + */ +interface IPreparedModelCallback { + + /** + * notify must be invoked immediately after the asynchronous task holding + * this callback has finished preparing the model. If the model was + * successfully prepared, notify must be invoked with ErrorStatus::NONE and + * the prepared model. If the model was not able to be successfully + * prepared, notify must be invoked with the appropriate ErrorStatus and + * nullptr as the IPreparedModel. If the asynchronous task holding this + * callback fails to launch or if the model provided to + * IDevice::prepareModel is invalid, notify must be invoked with the + * appropriate error as well as nullptr for the IPreparedModel. + * + * @param status Error status returned from the asynchronous model + * preparation task; must be: + * - NONE if the asynchronous task successfully prepared the + * model + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if the asynchronous task resulted in an + * unspecified error + * - INVALID_ARGUMENT if one of the input arguments to + * prepareModel is invalid + * @param preparedModel A model that has been asynchronously prepared for + * execution. If the model was unable to be prepared + * due to an error, nullptr must be passed in place of + * the IPreparedModel object. + */ + oneway notify(ErrorStatus status, IPreparedModel preparedModel); +}; diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal new file mode 100644 index 0000000000..8779723d2f --- /dev/null +++ b/neuralnetworks/1.0/types.hal @@ -0,0 +1,1267 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.neuralnetworks@1.0; + +/** + * Operand types. + * + * The type of an operand in a model. + * + * Types prefaced with TENSOR_* must be used for tensor data (i.e., tensors + * with at least one dimension). Types not prefaced by TENSOR_* represent + * scalar values and must have no dimensions. + */ +enum OperandType : int32_t { + /** + * The following entries are used to declare scalars. + */ + FLOAT32 = 0, + INT32 = 1, + UINT32 = 2, + + /** + * The following entries are used to declare tensors. + */ + TENSOR_FLOAT32 = 3, + TENSOR_INT32 = 4, + + /** + * A tensor of 8 bit integers that represent real numbers. + * + * Attached to this tensor are two numbers that can be used to convert the + * 8 bit integer to the real value and vice versa. These two numbers are: + * - scale: a 32 bit floating point value + * - zero_value: a 32 bit integer + * + * The formula is: + * real_value = (integer_value - zero_value) * scale. + */ + TENSOR_QUANT8_ASYMM = 5, + + /** + * The following entries are OEM specific operand types. + */ + OEM = 10000, + TENSOR_OEM_BYTE = 10001, +}; + +/** + * Operation types. + * + * The type of an operation in a model. + */ +enum OperationType : int32_t { + /** + * Adds two tensors, elment-wise. + * + * Takes two input tensors of identical type and compatible dimensions. The output + * is the sum of both input tensors, optionally modified by an activation function. + * + * Two dimensions are compatible when: + * 1. they are equal, or + * 2. one of them is 1 + * + * The size of the output is the maximum size along each dimension of the input operands. + * It starts with the trailing dimensions, and works its way forward. + * + * Example: + * input1.dimension = {4, 1, 2} + * input2.dimension = {5, 4, 3, 1} + * output.dimension = {5, 4, 3, 2} + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: up to 4 + * + * Inputs: + * 0: A tensor. + * 1: A tensor of the same type, and compatible dimensions as input0. + * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The sum, a tensor of the same type as input0. + */ + ADD = 0, + + /** + * Performs a 2-D average pooling operation. + * + * The output dimensions are functions of the filter dimensions, stride, and padding. + * + * The values in output Tensor is computed as: + * output[batch, row, col, channel] = + * sum_{i, j}(input[batch, row + i, col + j, channel]) / sum(1) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input. + * 1: An INT32 value, specifying the padding on the left, in the ‘width’ dimension. + * 2: An INT32 value, specifying the padding on the right,in the ‘width’ dimension. + * 3: An INT32 value, specifying the padding on the top, in the ‘height’ dimension. + * 4: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension. + * 5: An INT32 value, specifying the output stride in the ‘width’ dimension. + * 6: An INT32 value, specifying the output stride in the ‘height’ dimension. + * 7: An INT32 value, specifying the filter width. + * 8: An INT32 value, specifying the filter height. + * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth]. + */ + AVERAGE_POOL_2D = 1, + + /** + * Concatenates the input tensors along the given dimension. + * + * The input tensors must have identical type and the same dimensions except the + * dimension along the concatenation axis. + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4 + * + * Inputs: + * 0 ~ n: The list on n input tensors, of shape [D0, D1, ..., Daxis(i), ..., Dm] + * n+1: An INT32 value, specifying the concatenation axis. + * n+2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The output, a tensor of the same type as the input tensors. + The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm]. + */ + CONCATENATION = 2, + + /** + * Performs an 2-D convolution operation. + * + * The CONV_2D op sweeps a 2-D filter that can mix channels together over a batch of + * images, applying the filter to each window of each image of the appropriate size. + * + * The output dimensions are functions of the filter dimensions, stride, and padding. + * + * The values in output Tensor is computed as: + * output[batch, row, col, channel] = + * sum_{i, j} ( + * input[batch, row + i, col + j, k] * + * filter[channel, row + i, col + j, k] + + * bias[channel] + * ) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input. + * 1: A 4-D tensor, of shape [depth_out, filter_height, filter_width, depth_in], + * specifying the filter. + * 2: A 1-D tensor, of shape [depth_out], specifying the bias. + * For input tensor of {@link OperandType::TENSOR_FLOAT32} type, the bias should + * also be of {@link OperandType::TENSOR_FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} type, the bias + * should be of {@link OperandType::TENSOR_INT32}. + * 3: An INT32 value, specifying the padding on the left, in the ‘width’ dimension. + * 4: An INT32 value, specifying the padding on the right,in the ‘width’ dimension. + * 5: An INT32 value, specifying the padding on the top, in the ‘height’ dimension. + * 6: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension. + * 7: An INT32 value, specifying the output stride in the ‘width’ dimension. + * 8: An INT32 value, specifying the output stride in the ‘height’ dimension. + * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth_out]. + */ + CONV_2D = 3, + + /** + * Performs an depthwise 2-D convolution operation. + * + * Given an input tensor of shape [batches, height, width, depth_in] and a filter + * tensor of shape [depth_out, filter_height, filter_width, depth_in] containing + * in_channels convolutional filters of depth 1, DEPTHWISE_CONV applies a different + * filter to each input channel (expanding from 1 channel to channel_multiplier channels + * for each), then concatenates the results together. + * + * The output has depth_out = depth_in * depth_multiplier channels. + * The output dimensions are functions of the filter dimensions, stride, and padding. + * + * The values in output Tensor is computed as: + * output[b, i, j, k * channel_multiplier + q] = + * sum_{di, dj} ( + * input[b, strides[1] * i + di, strides[2] * j + dj, k] * + * filter[di, dj, k, q] + * ) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input. + * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out], + * specifying the filter. + * 2: A 1-D tensor, of shape [depth_out], specifying the bias. + * For input tensor of {@link OperandType::TENSOR_FLOAT32} type, the bias should + * also be of {@link OperandType::TENSOR_FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} type, the bias + * should be of {@link OperandType::TENSOR_INT32}. + * 3: An INT32 value, specifying the padding on the left, in the ‘width’ dimension. + * 4: An INT32 value, specifying the padding on the right,in the ‘width’ dimension. + * 5: An INT32 value, specifying the padding on the top, in the ‘height’ dimension. + * 6: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension. + * 7: An INT32 value, specifying the output stride in the ‘width’ dimension. + * 8: An INT32 value, specifying the output stride in the ‘height’ dimension. + * 9: An INT32 value, specifying the depthwise multiplier. + * 10: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth_out]. + */ + DEPTHWISE_CONV_2D = 4, + + /** + * Rearranges data from depth into blocks of spatial data. + * + * More specifically, this op outputs a copy of the input tensor where values from + * the depth dimension are moved in spatial blocks to the height and width dimensions. + * The value block_size indicates the input block size and how the data is moved. + * + * Chunks of data of size block_size * block_size from depth are rearranged into + * non-overlapping blocks of size block_size x block_size. + * + * The width of the output tensor is input_depth * block_size, whereas the height is + * input_height * block_size. + * The depth of the input tensor must be divisible by block_size * block_size + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input. + * 1: An INT32 value, specifying the block_size. block_size must be >=1 and + * block_size * block_size must be a divisor of the input depth. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batch, height*block_size, width*block_size, + * depth/(block_size*block_size)]. + */ + DEPTH_TO_SPACE = 5, + + /** + * Dequantizes the input tensor. + * + * The formula is: + * output = (input - zero_value) * scale. + * + * Supported tensor types: {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4 + * + * Inputs: + * 0: A tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}. + * + * Ouputs: + * 0: The output tensor of same shape as input0, but with type + {@link OperandType::TENSOR_FLOAT32}. + */ + DEQUANTIZE = 6, + + /** + * Looks up items from a given tensor. + * + * Each item in the output is a raw copy of the corresponding item in + * the input “values”. If the the given “lookup” indices are out of bounds, + * the op will fail and an error will be reported. + * + * Inputs: + * * 0: Values. An n-D tensor of any type X (where n >= 2). E.g., if n is 2, + * then the shape would be [lookup_dimension, values_dimension], where + * “lookup_dimension” corresponds to the indexing dimension in the lookup + * table, and “values_dimension” to the contents. + * * 1: Lookups. An 1-D tensor of type T, of shape [lookup_size], where + * “lookup_size” is the number of elements to look for, and each entry + * corresponds to the first dimension of the “values” tensor. + * + * Output: + * * 0: A n-D tensor of type X and the same rank and shape as the “values” + * tensor, except for the first dimension which has size “lookup_size”. + */ + EMBEDDING_LOOKUP = 7, + + /** + * Computes element-wise floor() on the input tensor. + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: up to 4 + * + * Inputs: + * 0: A tensor. + * + * Ouputs: + * 0: The output, a tensor of the same type and dimensions as input0. + */ + FLOOR = 8, + + /** + * Denotes a fully (densely) connected layer, which connects all elements in the input + * tensor with each element in the output tensor. + * + * This layer implements the operation: + * outputs = activation(inputs * weights’ + bias) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4. + * + * Inputs: + * 0: A tensor, specifying the input. If rank is greater than 2, then it gets flattened to + * a 2-D Tensor. The 2-D Tensor is handled as if dimensions corresponded to shape + * [batch_size, input_size], where “batch_size” corresponds to the batching dimension, + * and “input_size” is the size of the input. + * 1: A 2-D tensor, specifying the weights, of shape [num_units, input_size], where “num_units” + * corresponds to the number of output nodes. + * 2: A 1-D tensor, of shape [num_units], specifying the bias. + * For input tensor of {@link OperandType::TENSOR_FLOAT32} type, the bias should + * also be of {@link OperandType::TENSOR_FLOAT32}. + * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} type, the bias + * should be of {@link OperandType::TENSOR_INT32}. + * 3: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The output tensor, of shape [batch_size, num_units]. + */ + FULLY_CONNECTED = 9, + + /** + * Looks up values of a hash table with given keys. + * + * Inputs: + * * 0: Lookups. A 1-D int32 tensor with shape [ k ]. + * * 1: Keys. A 1-D int32 tensor with shape [ n ], *MUST* be sorted in + * ascending order. + * * 2: Values. A tensor with shape [ n … ]. + * + * Outputs: + * * 0: Output. A tensor with shape [ k …]. + * * 1: Hits. A uint8 tensor with shape [ k ] indicates whether the lookup + * hits or not. + */ + HASHTABLE_LOOKUP = 10, + + /** + * Applies L2 normalization along a the depth dimension. + * + * The values in output Tensor is computed as: + * output[batch, row, col, channel] = + * input[batch, row, col, channel] / + * sqrt(sum_{c} pow(input[batch, row, col, c], 2)) + * + * For x with more dimensions, independently normalizes each 1-D slice along dimension dim. + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth]. + */ + L2_NORMALIZATION = 11, + + /** + * Performs an 2-D L2 pooling operation. + * + * The output dimensions are functions of the filter dimensions, stride, and padding. + * + * The values in output Tensor is computed as: + * output[batch, row, col, channel] = + * sqrt(sum_{i, j} pow(input[batch, row + i, col + j, channel], 2) / sum(1)) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input. + * 1: An INT32 value, specifying the padding on the left, in the ‘width’ dimension. + * 2: An INT32 value, specifying the padding on the right,in the ‘width’ dimension. + * 3: An INT32 value, specifying the padding on the top, in the ‘height’ dimension. + * 4: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension. + * 5: An INT32 value, specifying the output stride in the ‘width’ dimension. + * 6: An INT32 value, specifying the output stride in the ‘height’ dimension. + * 7: An INT32 value, specifying the filter width. + * 8: An INT32 value, specifying the filter height. + * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth]. + */ + L2_POOL_2D = 12, + + /** + * Applies Local Response Normalization along the depth dimension. + * + * The 4-D input tensor is treated as a 3-D array of 1-D vectors (along the last + * dimension), and each vector is normalized independently. Within a given vector, + * each component is divided by the weighted, squared sum of inputs within depth_radius. + * + * In details: + * sqr_sum[a, b, c, d] = + * sum(pow(input[a, b, c, d - depth_radius : d + depth_radius + 1], 2) + * output = input / pow((bias + alpha * sqr_sum), beta) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input. + * 1: An INT32 value, specifying the radius of the normalization window. + * 2: A FLOAT32 value, specifying the bias, must not be zero. + * 3: A FLOAT32 value, specifying the scale factor, alpha. + * 4: A FLOAT32 value, specifying the exponent, beta. + * + * Ouputs: + * 0: The output tensor of same shape as input0. + */ + LOCAL_RESPONSE_NORMALIZATION = 13, + + /** + * Computes sigmoid activation on the input tensor element-wise. + * + * In details: + * output = 1 / (1 + exp(-input)) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4. + * + * Inputs: + * 0: A tensor, specifying the input. + * + * Ouputs: + * 0: The output tensor of same shape as input0. + */ + LOGISTIC = 14, + + /** + * Projects an input to a bit vector via locality senstive hashing. + * + * Inputs: + * * 0: Hash functions. Dim.size == 2, DataType: Float. + * Tensor[0].Dim[0]: Number of hash functions. + * Tensor[0].Dim[1]: Number of seeds per hash functions. + * Tensor[0].Dim[1] <= 32 in sparse case. + * + * * 1: Input. Dim.size >= 1, no restriction on DataType. + * * 2: Weight. Optional. Dim.size == 1, DataType: Float. + * If not set, each input element is considered to have the same weight of + * 1.0. + * Tensor[1].Dim[0] == Tensor[2].Dim[0] + * * 3: Type: + * Sparse: Value LSHProjectionType_SPARSE(=1). + * Computed bit vector is considered to be sparse. + * Each output element is an int32 made up of multiple bits computed from + * hash functions. + * + * Dense: Value LSHProjectionType_DENSE(=2). + * Computed bit vector is considered to be dense. Each output element + * represents a bit and can take the value of either 0 or 1. + * + * Outputs: + * * 0: If the projection type is sparse: + * Output.Dim == { Tensor[0].Dim[0] } + * A tensor of int32 that represents hash signatures. + * If the projection type is Dense: + * Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] } + * A flattened tensor that represents projected bit vectors. + */ + LSH_PROJECTION = 15, + + /** + * Long short-term memory unit (LSTM) recurrent network layer. + * + * The default non-peephole implementation is based on: + * http://deeplearning.cs.cmu.edu/pdfs/Hochreiter97_lstm.pdf + * S. Hochreiter and J. Schmidhuber. "Long Short-Term Memory". Neural + * Computation, 9(8):1735-1780, 1997. + * + * The peephole implementation is based on: + * https://research.google.com/pubs/archive/43905.pdf + * Hasim Sak, Andrew Senior, and Francoise Beaufays. "Long short-term memory + * recurrent neural network architectures for large scale acoustic modeling." + * INTERSPEECH, 2014. + * + * The coupling of input and forget gate (CIFG) is based on: + * http://arxiv.org/pdf/1503.04069.pdf + * Greff et al. "LSTM: A Search Space Odyssey" + * + * The class has the following independently optional inputs: + * * If input gate (if CIFG): “input_to_forget_weights”, + * “recurrent_to_input_weights”, “cell_to_input_weights”, “input_gate_bias”. + * * If no peephole connections: “cell_to_input_weights”, + * “cell_to_forget_weights”, “cell_to_output_weights”. + * * If no projection layer: “projection_weights” and “projection_bias”. + * * If no projection bias: “projection_bias”. + * + * Supported tensor types: + * * {@link OperandType::TENSOR_FLOAT32} + * + * Inputs: + * * 0: Input. + * A 2-D tensor of type T, of shape [batch_size, input_size], where + * “batch_size” corresponds to the batching dimension, and “input_size” + * is the size of the input. + * * 1: input_to_input_weights. + * A 2-D tensor of type T, of shape [num_units, input_size], where + * “num_units” corresponds to the number of cell units. + * * 2: input_to_forget_weights. + * A 2-D tensor of type T, of shape [num_units, input_size]. + * * 3: input_to_cell_weights. + * A 2-D tensor of type T, of shape [num_units, input_size]. + * * 4: input_to_output_weights. + * A 2-D tensor of type T, of shape [num_units, input_size]. + * * 5: recurrent_to_input_weights. + * A 2-D tensor of type T, of shape [num_units, output_size], where + * “output_size” corresponds to either the number of cell units (i.e., + * “num_units”), or the second dimension of the “projection_weights”, if + * defined. + * * 6: recurrent_to_forget_weights. + * A 2-D tensor of type T, of shape [num_units, output_size]. + * * 7: recurrent_to_cell_weights. + * A 2-D tensor of type T, of shape [num_units, output_size]. + * * 8: recurrent_to_output_weights. + * A 2-D tensor of type T, of shape [num_units, output_size]. + * * 9: cell_to_input_weights. + * A 1-D tensor of type T, of shape [num_units]. + * * 10:cell_to_forget_weights. + * A 1-D tensor of type T, of shape [num_units]. + * * 11:cell_to_output_weights. + * A 1-D tensor of type T, of shape [num_units]. + * * 12:input_gate_bias. + * A 1-D tensor of type T, of shape [num_units]. + * * 13:forget_gate_bias. + * A 1-D tensor of type T, of shape [num_units]. + * * 14:cell_bias. + * A 1-D tensor of type T, of shape [num_units]. + * * 15:output_gate_bias. + * A 1-D tensor of type T, of shape [num_units]. + * * 16:projection_weights. + * A 2-D tensor of type T, of shape [output_size, num_units]. + * * 17:projection_bias. + * A 1-D tensor of type T, of shape [output_size]. + * + * Parameters: + * * 18:fused_activation_function. + * An (optional) ActivationFunctionType indicating the activation + * function. + * If “NONE” is specified then it results in a linear activation. + * * 19:cell_clip. + * A clipping threshold for the cell state, such that values are bound + * within [-cell_clip, cell_clip]. If set to 0.0 then clipping is + * disabled. + * * 20:proj_clip. + * A clipping threshold for the output from the projection layer, such + * that values are bound within [-proj_clip, proj_clip]. If set to 0.0 + * then clipping is disabled. + * + * Outputs: + * * 0: scratch_buffer. + * A 3-D tensor of type T, of shape [batch_size, num_cell, 4]. + * * 1: output_state. + * A 2-D tensor of type T, of shape [batch_size, output_size]. + * * 2: cell_state. + * A 2-D tensor of type T, of shape [batch_size, num_units]. + * * 3: output. + * A 2-D tensor of type T, of shape [batch_size, output_size]. This is + * effectively the same as the current “output_state” value. + */ + LSTM = 16, + + /** + * Performs an 2-D max pooling operation. + * + * The output dimensions are functions of the filter dimensions, stride, and padding. + * + * The values in output Tensor is computed as: + * output[batch, row, col, channel] = + * max_{i, j} (input[batch, row + i, col + j, channel]) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input. + * 1: An INT32 value, specifying the padding on the left, in the ‘width’ dimension. + * 2: An INT32 value, specifying the padding on the right,in the ‘width’ dimension. + * 3: An INT32 value, specifying the padding on the top, in the ‘height’ dimension. + * 4: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension. + * 5: An INT32 value, specifying the output stride in the ‘width’ dimension. + * 6: An INT32 value, specifying the output stride in the ‘height’ dimension. + * 7: An INT32 value, specifying the filter width. + * 8: An INT32 value, specifying the filter height. + * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth]. + */ + MAX_POOL_2D = 17, + + /** + * Multiplies two tensors, elment-wise. + * + * Takes two input tensors of identical type and compatible dimensions. The output + * is the product of both input tensors, optionally modified by an activation function. + * + * Two dimensions are compatible when: + * 1. they are equal, or + * 2. one of them is 1 + * + * The size of the resulting output is the maximum size along each dimension of the + * input operands. It starts with the trailing dimensions, and works its way forward. + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: up to 4 + * + * Inputs: + * 0: A tensor. + * 1: A tensor of the same type, and compatible dimensions as input0. + * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values. + * Specifies the activation to invoke on the result of each addition. + * + * Ouputs: + * 0: The product, a tensor of the same type as input0. + */ + MUL = 18, + + /** + * Computes rectified linear activation on the input tensor element-wise. + * + * In details: + * output = max(0, input) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4. + * + * Inputs: + * 0: A tensor, specifying the input. + * + * Ouputs: + * 0: The output tensor of same shape as input0. + */ + RELU = 19, + + /** + * Computes rectified linear 1 activation on the input tensor element-wise. + * + * In details: + * output = min(1.f, max(-1.f, input)) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4. + * + * Inputs: + * 0: A tensor, specifying the input. + * + * Ouputs: + * 0: The output tensor of same shape as input0. + */ + RELU1 = 20, + + /** + * Computes rectified linear 6 activation on the input tensor element-wise. + * + * In details: + * output = min(6, max(0, input)) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4. + * + * Inputs: + * 0: A tensor, specifying the input. + * + * Ouputs: + * 0: The output tensor of same shape as input0. + */ + RELU6 = 21, + + /** + * Reshapes a tensor. + * + * Given tensor, this operation returns a tensor that has the same values as tensor, + * but with a newly specified shape. + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: up to 4. + * + * Inputs: + * 0: A tensor, specifying the tensor to be reshaped. + * 1: A 1-D tensor of type {@link OperandType::TENSOR_INT32}, defining the shape + * of the output tensor. The number of elements implied by shape must be the same + * as the number of elements in the input tensor. + * + * Ouputs: + * 0: The output tensor, of shape specified by the input shape. + */ + RESHAPE = 22, + + /** + * Resizes images to given size using the bilinear interpretation. + * + * Resized images will be distorted if their original aspect ratio is not the same as input. + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input. + * 1: An INT32 value, specifying the output width of the output tensor. + * 2: An INT32 value, specifying the output height of the output tensor. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batches, new_height, new_width, depth]. + */ + RESIZE_BILINEAR = 23, + + /** + * A basic recurrent neural network layer. + * + * This layer implements the operation: + * outputs = state = activation(inputs * input_weights + state * recurrent_weights + bias) + * + * Where: + * * “input_weights” is a weight matrix that multiplies the inputs; + * * “recurrent_weights” is a weight matrix that multiplies the current + * “state” which itself is the output from the previous time step + * computation; + * * “bias” is a bias vector (added to each output vector in the batch); + * * “activation” is the function passed as the “fused_activation_function” + * argument (if not “NONE”). + * + * Supported tensor types: + * * {@link OperandType::TENSOR_FLOAT32} + * + * Inputs: + * * 0: input. + * A 2-D tensor of type T, of shape [batch_size, input_size], where + * “batch_size” corresponds to the batching dimension, and “input_size” is + * the size of the input. + * * 1: weights. + * A 2-D tensor of type T, of shape [num_units, input_size], where + * “num_units” corresponds to the number of units. + * * 2: recurrent_weights. + * A 2-D tensor of type T, of shape [num_units, num_units], with columns + * corresponding to the weights from each unit. + * * 3: bias. + * A 1-D tensor of type T, of shape [num_units]. + * + * For FLOAT32 input tensor, bias must also be FLOAT32. + * For UINT8 input tensor, bias must be INT32. + * + * Parameters + * * 4: fused_activation_function. + * An (optional) ActivationFunctionType indicating the activation + * function. If “NONE” is specified then it results in a linear + * activation. + * + * * 5: Hidden state. + * A 2-D tensor of type T, of shape [batch_size, num_units]. + * + * Outputs: + * * 0: output. + * A 2-D tensor of type T, of shape [batch_size, num_units]. This is + * effectively the same as the current state value. + */ + RNN = 24, + + /** + * Computes the softmax activation on the input tensor element-wise, per batch, by + * normalizing the input vector so the maximum coefficient is zero. + * + * In details: + * output[batch, i] = + * exp((input[batch, i] - max(input[batch, :])) * beta) / + * sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)} + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: 2 or 4. + * + * Inputs: + * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. + * 1: A FLOAT32 value, specifying the scaling factor for the exponent, beta. + * + * Ouputs: + * 0: The output tensor of same shape as input0. + */ + SOFTMAX = 25, + + /** + * Rearranges blocks of spatial data, into depth. + * + * More specifically, this op outputs a copy of the input tensor where values from + * the height and width dimensions are moved to the depth dimension. + * The value block_size indicates the input block size and how the data is moved. + * + * Chunks of data of size block_size * block_size from depth are rearranged into + * non-overlapping blocks of size block_size x block_size. + * + * The depth of the output tensor is input_depth * block_size * block_size. + * The input tensor's height and width must be divisible by block_size. + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * {@link OperandType::TENSOR_QUANT8_ASYMM} + * Supported tensor rank: 4, with "NHWC" data layout. + * + * Inputs: + * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input. + * 1: An INT32 value, specifying the block_size. block_size must be >=1 and + * block_size must be a divisor of both the input height and width. + * + * Ouputs: + * 0: The output 4-D tensor, of shape [batch, height/block_size, width/block_size, + * depth*block_size*block_size]. + */ + SPACE_TO_DEPTH = 26, + + /** + * SVDF op is a kind of stateful layer derived from the notion that a + * densely connected layer that's processing a sequence of input frames can + * be approximated by using a singular value decomposition of each of its + * nodes. The implementation is based on: + * + * https://research.google.com/pubs/archive/43813.pdf + * + * P. Nakkiran, R. Alvarez, R. Prabhavalkar, C. Parada. + * “Compressing Deep Neural Networks using a Rank-Constrained Topology”. + * INTERSPEECH, 2015. + * + * It processes the incoming input using a 2-stage filtering mechanism: + * * stage 1 performs filtering on the "features" dimension, whose outputs get + * pushed into a memory of fixed-size memory_size. + * * stage 2 performs filtering on the "time" dimension of the memory_size + * memoized outputs of stage 1. + * + * Specifically, for rank 1, this layer implements the operation: + * + * memory = push(conv1d(inputs, weights_feature, feature_dim, "VALID")); + * outputs = activation(memory * weights_time + bias); + * + * Where: + * * “weights_feature” is a weights matrix that processes the inputs (by + * convolving the input with every “feature filter”), and whose outputs get + * pushed, stacked in order, into the fixed-size “memory” (the oldest entry + * gets dropped); + * * “weights_time” is a weights matrix that processes the “memory” (by a + * batched matrix multiplication on the num_units); + * * “bias” is an optional bias vector (added to each output vector in the + * batch); and + * * “activation” is the function passed as the “fused_activation_function” + * argument (if not “NONE”). + * + * Each rank adds a dimension to the weights matrices by means of stacking + * the filters. + * + * Supported tensor types: + * * {@link OperandType::TENSOR_FLOAT32} + * + * Inputs: + * * 0: input. + * A 2-D tensor of type T, of shape [batch_size, input_size], where + * “batch_size” corresponds to the batching dimension, and “input_size” is + * the size of the input. + * * 1: weights_feature. + * A 2-D tensor of type T, of shape [num_units, input_size], where + * “num_units” corresponds to the number of units. + * * 2: weights_time. + * A 2-D tensor of type T, of shape [num_units, memory_size], where + * “memory_size” corresponds to the fixed-size of the memory. + * * 3: bias. + * A optional 1-D tensor of type T, of shape [num_units]. + * + * For FLOAT32 input tensor, bias must also be FLOAT32. + * For UINT8 input tensor, bias must be INT32. + * + * Parameters: + * * 4: rank. + * The rank of the SVD approximation. + * * 5: fused_activation_function. + * An (optional) ActivationFunctionType indicating the activation function. + * If “NONE” is specified then it results in a linear activation. + * + * Outputs: + * * 0: state. + * A 2-D tensor of type T, of shape [batch_size, (memory_size - 1) * num_units * rank]. + * * 1: output. + * A 2-D tensor of type T, of shape [batch_size, num_units]. + */ + SVDF = 27, + + /** + * Computes hyperbolic tangent of input tensor element-wise. + * + * In details: + * output = tanh(input) + * + * Supported tensor types: {@link OperandType::TENSOR_FLOAT32} + * Supported tensor rank: up to 4. + * + * Inputs: + * 0: A tensor, specifying the input. + * + * Ouputs: + * 0: The output tensor of same shape as input0. + */ + TANH = 28, + + /** + * OEM specific operation. + * + * This operation is OEM specific. It should only be used for OEM applications. + */ + OEM_OPERATION = 10000, +}; + +/** + * Fused activation function types. + */ +enum FusedActivationFunc : int32_t { + NONE = 0, + RELU = 1, + RELU1 = 2, + RELU6 = 3, +}; + +/** + * How an operand is used. + */ +enum OperandLifeTime : int32_t { + /** + * The operand is internal to the model. It's created by an operation + * and consumed by other operations. + */ + TEMPORARY_VARIABLE, + + /** + * The operand is an input of the model. An operand can't be both + * input and output of a model. + */ + MODEL_INPUT, + + /** + * The operand is an output of the model. + */ + MODEL_OUTPUT, + + /** + * The operand is a constant found in Model.operandValues. + */ + CONSTANT_COPY, + + /** + * The operand is a constant that was specified via a Memory object. + */ + CONSTANT_REFERENCE, + + /** + * The operand does not have a value. This is valid only for optional arguments + * of operations. + */ + NO_VALUE, +}; + +/** + * Status of a device. + */ +enum DeviceStatus : int32_t { + AVAILABLE, + BUSY, + OFFLINE, + UNKNOWN, +}; + +/** + * Performance information for the reference workload. + * + * Used by a driver to report its performance characteristics. + */ +struct PerformanceInfo { + /** + * Ratio of the time taken by the driver to execute the + * workload compared to the time the CPU would take for the + * same workload. A lower number is better. + */ + float execTime; + + /** + * Ratio of the energy used by the driver compared to what + * the CPU would use for doing the same workload. A lower number + * is better. + */ + float powerUsage; +}; + +/** + * The capabilities of a driver. + */ +struct Capabilities { + /** + * Driver performance when operating on float32 data. + */ + PerformanceInfo float32Performance; + + /** + * Driver performance when operating on asymmetric 8-bit quantized data. + */ + PerformanceInfo quantized8Performance; +}; + +/** + * Describes the location of a data object. + */ +struct DataLocation { + /** + * The index of the memory pool where this location is found. + */ + uint32_t poolIndex; + + /** + * Offset in bytes from the start of the pool. + */ + uint32_t offset; + + /** + * The length of the data in bytes. + */ + uint32_t length; +}; + +/** + * Describes one operand of the model's graph. + */ +struct Operand { + /** + * Data type of the operand. + */ + OperandType type; + + /** + * Dimensions of the operand. + */ + vec<uint32_t> dimensions; + + /** + * The number of operations that use this operand as input. + */ + uint32_t numberOfConsumers; + + /** + * Quantized scale of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or + * TENSOR_INT32. + */ + float scale; + + /** + * Quantized zero-point offset of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM. + */ + int32_t zeroPoint; + + /** + * How the operand is used. + */ + OperandLifeTime lifetime; + + /** + * Where to find the data for this operand. + * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or NO_VALUE: + * - All the fields will be 0. + * If the lifetime is CONSTANT_COPY: + * - location.poolIndex is 0. + * - location.offset is the offset in bytes into Model.operandValues. + * - location.length is set. + * If the lifetime is CONSTANT_REFERENCE: + * - location.poolIndex is set. + * - location.offset is the offset in bytes into the specified pool. + * - location.length is set. + */ + DataLocation location; +}; + +/** + * Describes one operation of the model's graph. + */ +struct Operation { + /** + * The operation type. + */ + OperationType type; + + /** + * Describes the table that contains the indexes of the inputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec<uint32_t> inputs; + + /** + * Describes the table that contains the indexes of the outputs of the + * operation. The offset is the index in the operandIndexes table. + */ + vec<uint32_t> outputs; +}; + +/** + * A Neural Network Model. + * + * This includes not only the execution graph, but also constant data such as + * weights or scalars added at construction time. The only information that + * might not be known is the shape of the input tensors. + */ +struct Model { + /** + * All operands included in the model. + */ + vec<Operand> operands; + + /** + * All operations included in the model. + * + * The operations are sorted into execution order. + */ + vec<Operation> operations; + + /** + * Input indexes of the model. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec<uint32_t> inputIndexes; + + /** + * Output indexes of the model. + * + * Each value corresponds to the index of the operand in "operands". + */ + vec<uint32_t> outputIndexes; + + /** + * A byte buffer containing operand data that were copied into the model. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_COPY. + */ + vec<uint8_t> operandValues; + + /** + * A collection of shared memory pools containing operand data that were + * registered by the model. + * + * An operand's value must be located here if and only if Operand::lifetime + * equals OperandLifeTime::CONSTANT_REFERENCE. + */ + vec<memory> pools; +}; + +/** + * Metadata information specifying the location of the input or output data and + * any updates to the input or output operand. + */ +struct RequestArgument { + /** + * 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 and + * the dimensions vector is left empty. + */ + bool hasNoValue; + + /** + * The location within one of the memory pools passed in the Request. + */ + DataLocation location; + + /** + * Updated dimension information. + * + * If dimensions.size() > 0, dimension information was provided along with the + * argument. This can be the case for models that accept inputs of varying size. + * This can't change the rank, just the value of the dimensions that were + * unspecified in the model. + */ + vec<uint32_t> dimensions; +}; + +/** + * Inputs to be sent to and outputs to be retrieved from a prepared model. + * + * A Request serves two primary tasks: + * 1) Provides the input and output data to be used when executing the model. + * 2) Specifies any updates to the input operand metadata that were left + * unspecified at model preparation time. + */ +struct Request { + /** + * Input data and information to be used in the execution of a prepared + * model. + * + * The index of the input corresponds to the index in Model.inputIndexes. + * E.g., input[i] corresponds to Model.inputIndexes[i]. + */ + vec<RequestArgument> inputs; + + /** + * Output data and information to be used in the execution of a prepared + * model. + * + * The index of the output corresponds to the index in Model.outputIndexes. + * E.g., output[i] corresponds to Model.outputIndexes[i]. + */ + vec<RequestArgument> outputs; + + /** + * A collection of shared memory pools containing operand data for both the + * inputs and the outputs to a model. + */ + vec<memory> pools; +}; + +/** + * Return status of a function. + */ +enum ErrorStatus : int32_t { + NONE, + DEVICE_UNAVAILABLE, + GENERAL_FAILURE, + OUTPUT_INSUFFICIENT_SIZE, + INVALID_ARGUMENT, +}; diff --git a/neuralnetworks/1.0/vts/OWNERS b/neuralnetworks/1.0/vts/OWNERS new file mode 100644 index 0000000000..59e7c28b64 --- /dev/null +++ b/neuralnetworks/1.0/vts/OWNERS @@ -0,0 +1,11 @@ +# Neuralnetworks team +butlermichael@google.com +dgross@google.com +ijsung@google.com +jeanluc@google.com +miaowang@google.com +yangni@google.com + +# VTS team +yim@google.com +yuexima@google.com diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..e33ee77f12 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -0,0 +1,36 @@ +// +// 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. +// + +cc_test { + name: "VtsHalNeuralnetworksV1_0TargetTest", + srcs: [ + "Callbacks.cpp", + "GeneratedTestHarness.cpp", + "Models.cpp", + "VtsHalNeuralnetworksV1_0TargetTest.cpp", + ], + defaults: ["VtsHalTargetTestDefaults"], + static_libs: [ + "android.hardware.neuralnetworks@1.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libhidlmemory", + ], + header_libs: [ + "libneuralnetworks_generated_test_harness_headers", + "libneuralnetworks_generated_tests", + ], +} diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.cpp b/neuralnetworks/1.0/vts/functional/Callbacks.cpp new file mode 100644 index 0000000000..46bf24350f --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/Callbacks.cpp @@ -0,0 +1,127 @@ +#include "Callbacks.h" +#include <android-base/logging.h> + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace implementation { + +CallbackBase::CallbackBase() : mNotified(false) {} + +CallbackBase::~CallbackBase() { + // Note that we cannot call CallbackBase::join_thread from here: + // CallbackBase is intended to be reference counted, and it is possible that + // the reference count drops to zero in the bound thread, causing the + // bound thread to call this destructor. If a thread tries to join + // itself, it throws an exception, producing a message like the + // following: + // + // terminating with uncaught exception of type std::__1::system_error: + // thread::join failed: Resource deadlock would occur +} + +void CallbackBase::wait() { + std::unique_lock<std::mutex> lock(mMutex); + mCondition.wait(lock, [this]{return mNotified;}); + join_thread_locked(); +} + +bool CallbackBase::on_finish(std::function<bool(void)> post_work) { + std::lock_guard<std::mutex> lock(mMutex); + if (mPostWork != nullptr) { + LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to " + "this callback object"; + return false; + } + if (post_work == nullptr) { + LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid"; + return false; + } + mPostWork = std::move(post_work); + return true; +} + +bool CallbackBase::bind_thread(std::thread&& asyncThread) { + std::lock_guard<std::mutex> lock(mMutex); + if (mThread.joinable()) { + LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this " + "callback object"; + return false; + } + if (!asyncThread.joinable()) { + LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable"; + return false; + } + mThread = std::move(asyncThread); + return true; +} + +void CallbackBase::join_thread() { + std::lock_guard<std::mutex> lock(mMutex); + join_thread_locked(); +} + +void CallbackBase::notify() { + { + std::lock_guard<std::mutex> lock(mMutex); + mNotified = true; + if (mPostWork != nullptr) { + bool success = mPostWork(); + if (!success) { + LOG(ERROR) << "CallbackBase::notify -- post work failed"; + } + } + } + mCondition.notify_all(); +} + +void CallbackBase::join_thread_locked() { + if (mThread.joinable()) { + mThread.join(); + } +} + +PreparedModelCallback::PreparedModelCallback() : + mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {} + +PreparedModelCallback::~PreparedModelCallback() {} + +Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus, + const sp<IPreparedModel>& preparedModel) { + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + CallbackBase::notify(); + return Void(); +} + +ErrorStatus PreparedModelCallback::getStatus() { + wait(); + return mErrorStatus; +} + +sp<IPreparedModel> PreparedModelCallback::getPreparedModel() { + wait(); + return mPreparedModel; +} + +ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {} + +ExecutionCallback::~ExecutionCallback() {} + +Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) { + mErrorStatus = errorStatus; + CallbackBase::notify(); + return Void(); +} + +ErrorStatus ExecutionCallback::getStatus() { + wait(); + return mErrorStatus; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.h b/neuralnetworks/1.0/vts/functional/Callbacks.h new file mode 100644 index 0000000000..0e2ffb324a --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/Callbacks.h @@ -0,0 +1,319 @@ +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H + +#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h> +#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h> +#include <chrono> +#include <condition_variable> +#include <functional> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <mutex> +#include <thread> + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace implementation { + +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::sp; + +/** + * The CallbackBase class is used internally by the NeuralNetworks runtime to + * synchronize between different threads. An asynchronous task is launched + * paired with a callback object. When a client thread requires the output being + * generated by the asynchronous task, the client thread can wait for the result + * and be blocked until it has completed or a timeout condition has been + * reached. Any wait* may safely be called concurrently, even on the same + * callback object. When the asynchronous task has finished its workload, it + * must immediately call "notify". If the asynchronous task has failed to launch, + * the function that tried to launch the asynchronous task must immediately call + * "notify". This "notify" call awakens any client threads waiting on the + * callback object. + * + * callback object. When the asynchronous task has finished its workload or has + * failed to launch, it must immediately call "notify", awakening any client + * threads waiting on the callback object. + * + * The CallbackBase class implements some of the base synchronization common to + * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL + * callback class must inherit from CallbackBase as well as the HIDL callback + * interface it implements. + * + * This class exists to enable synchronization across HIDL. When synchronization + * is only required in the same process, consider using std::future, std::mutex, + * std::condition_variable, or std::experimental::latch instead. + */ +class CallbackBase { + public: + CallbackBase(); + ~CallbackBase(); + + /** + * CallbackBase::wait blocks until notify has been called on the callback + * object. + */ + void wait(); + + /** + * CallbackBase::wait_for blocks until notify has been called on the + * callback object or the time duration from the time the wait_for function + * was called has expired, whichever comes first. + * + * @return Status std::cv_status::no_timeout if the callback was notified + * before the time duration expired, std::cv_status::timeout + * otherwise. + */ + template<class Rep, class Period> + std::cv_status wait_for(const std::chrono::duration<Rep,Period>& timeout_duration); + + /** + * CallbackBase::on_finish binds a function to the callback object. This + * bound function will be executed when CallbackBase::notify is called, + * before any calls to wait* return. (Note that CallbackBase::wait_for can + * return std::cv_status::timeout before CallbackBase::notify is called for + * the first time, and hence before the bound function is executed.) + * + * The bound function must not synchronize with or otherwise access the + * callback object it is bound to, as this could cause a deadlock. + * + * CallbackBase::on_finish can be called at most once on a given callback + * object, and the call to CallbackBase::on_finish must finish before + * CallbackBase::notify is called. + * + * @param post_work Function to be invoked the first time + * CallbackBase::notify is called. Must have a target -- + * i.e., must not compare equal to nullptr. post_work + * returns true if it successfully completes, false if it + * fails. + * @return bool True if the function was successfully bound, false if + * unsuccessful. + * + * TODO: Why does the return value of the callback matter? + */ + bool on_finish(std::function<bool(void)> post_work); + + /** + * CallbackBase::bind_thread binds a thread to the event for later use by + * CallbackBase::join_thread. + * + * The thread must be passed using std::move. + * + * Once a thread is bound with CallbackBase::bind_thread, the client code + * should ensure that one of the following occurs before the event is + * destroyed: + * - CallbackBase::join_thread has been called. + * - CallbackBase::wait has been called. + * - CallbackBase::wait_for has been called and returned other than + * std::cv_status::no_timeout. + * + * The bound thread shall not call any CallbackBase method with the + * exception of CallbackBase::notify, which it must call when the thread has + * finished its computation. + * + * CallbackBase::bind_thread can be called at most once on a given callback + * object. + * + * @param asyncThread Thread to be bound to the callback object. The thread + * object must represent a thread of execution -- i.e., + * asyncThread.joinable() must be true. + * @return bool True if successful, false if thread was not properly bound. + */ + bool bind_thread(std::thread&& asyncThread); + + /** + * CallbackBase::join_thread ensures that the thread (if any) bound to this + * event with CallbackBase::bind_thread has fully finished and cleaned its + * resources. It is legal to call this function multiple times, concurrently + * or sequentially. + */ + void join_thread(); + + protected: + /** + * CallbackBase::notify enables all prior and future wait* calls on the + * callback object to proceed. The call to CallbackBase::notify happens + * before any wait* calls on this callback object return (except in the case + * of wait_for timing out). The asynchronous call the callback object is + * paired with must ensure that any update to state that should be visible + * to the caller of wait* happens before the call to CallbackBase::notify. + * + * CallbackBase::notify must be called exactly once on a given callback + * object. + */ + void notify(); + + private: + // Same as CallbackBase::join_thread but assumes we already hold a lock on + // mMutex. + void join_thread_locked(); + + bool mNotified; + std::mutex mMutex; + std::condition_variable mCondition; + std::function<bool(void)> mPostWork; + std::thread mThread; +}; + +/** + * The PreparedModelCallback class is used to receive the error status of + * preparing a model as well as the prepared model from a task executing + * asynchronously with respect to the runtime. If a calling thread calls wait* + * or get* on a PreparedModelCallback object and the corresponding asynchronous + * task has not finished preparing the model, the calling thread will block + * until the asynchronous task has called notify. For more information on the + * synchronization behavior, refer to the CallbackBase class. + * + * This class inherits the basic blocking and signaling calls from + * CallbackBase, and implements the HIDL notify call from + * IPreparedModelCallback. This callback object is passed as an argument to + * IDevice::prepareModel. + */ +class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback { + public: + PreparedModelCallback(); + ~PreparedModelCallback() override; + + /** + * IPreparedModelCallback::notify marks the callback object with the return + * status of the asynchronous model preparation along with the prepared + * model, and calls CallbackBase::notify, enabling all prior and future + * wait* calls on the PreparedModelCallback object to proceed. For more + * information on the synchronization behavior, refer to the CallbackBase + * class. + * + * IPreparedModelCallback::notify must be called exactly once on a given + * PreparedModelCallback object. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return<void> notify(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IDevice::prepareModel. If IDevice::prepareModel has not finished + * asynchronously preparing the model, this call will block until the + * asynchronous task notifies the object. + * + * @return status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + */ + ErrorStatus getStatus(); + + /** + * Retrieves the model that has been prepared for execution from the + * asynchronous task launched by IDevice::prepareModel. If + * IDevice::prepareModel has not finished asynchronously preparing the + * model, this call will block until the asynchronous task notifies the + * object. + * + * @return preparedModel Returned model that has been prepared for + * execution, nullptr if the model was unable to be + * prepared. + */ + sp<IPreparedModel> getPreparedModel(); + + private: + ErrorStatus mErrorStatus; + sp<IPreparedModel> mPreparedModel; +}; + +/** + * The ExecutionCallback class is used to receive the error status of the + * execution from a task executing asynchronously with respect to the runtime. + * If a calling thread calls wait* or get* on a PreparedModelCallback object and + * the corresponding asynchronous task has not finished the execution, the + * calling thread will block until the asynchronous task has called notify. For + * more information on the synchronization behavior, refer to the CallbackBase + * class. + * + * This class inherits the basic blocking and signaling calls from + * CallbackBase, and implements the HIDL notify call from + * IExecutionCallback. This callback object is passed as an argument to + * IPreparedModel::execute. + */ +class ExecutionCallback : public CallbackBase, public IExecutionCallback { + public: + ExecutionCallback(); + ~ExecutionCallback() override; + + /** + * IExecutionCallback::notify marks the callback object with the return + * status of the asynchronous execution that held this callback and enables + * all prior and future wait* calls on the ExecutionCallback object to + * proceed. For more information on the synchronization behavior, refer to + * the CallbackBase class. + * + * IExecutionCallback::notify must be called exactly once on a given + * ExecutionCallback object. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is + * not large enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid + */ + Return<void> notify(ErrorStatus status) override; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IPreparedModel::execute. If IPreparedModel::execute has not finished + * asynchronously executing, this call will block until the asynchronous task + * notifies the object. + * + * @return status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous execution was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is + * not large enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid + */ + ErrorStatus getStatus(); + + private: + ErrorStatus mErrorStatus; +}; + + +// template function implementation(s) below this point + +template<class Rep, class Period> +std::cv_status CallbackBase::wait_for(const std::chrono::duration<Rep,Period>& timeout_duration) { + std::unique_lock<std::mutex> lock(mMutex); + std::cv_status status = mCondition.wait_for(lock, timeout_duration, [this]{return mNotified;}); + if (status != std::cv_status::timeout) { + join_thread_locked(); + } + return status; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp new file mode 100644 index 0000000000..d740b5f53c --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Callbacks.h" +#include "TestHarness.h" +#include "VtsHalNeuralnetworksV1_0TargetTest.h" + +#include <android-base/logging.h> +#include <android/hidl/memory/1.0/IMemory.h> +#include <hidlmemory/mapping.h> +#include <iostream> + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace vts { +namespace functional { +// allocator helper +hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem"); + +namespace generated_tests { +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using ::generated_tests::filter; +using ::generated_tests::for_all; +using ::generated_tests::for_each; +using ::generated_tests::resize_accordingly; +using ::generated_tests::MixedTyped; +using ::generated_tests::MixedTypedExampleType; +using ::generated_tests::Float32Operands; +using ::generated_tests::Int32Operands; +using ::generated_tests::Quant8Operands; +using ::generated_tests::compare; + +template <typename T> +void copy_back_(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) { + MixedTyped& test = *dst; + for_each<T>(test, [&ra, src](int index, std::vector<T>& m) { + ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T)); + char* begin = src + ra[index].location.offset; + memcpy(m.data(), begin, ra[index].location.length); + }); +} + +void copy_back(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) { + copy_back_<float>(dst, ra, src); + copy_back_<int32_t>(dst, ra, src); + copy_back_<uint8_t>(dst, ra, src); +} + +// Top level driver for models and examples generated by test_generator.py +// Test driver for those generated from ml/nn/runtime/test/spec +void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model, + std::function<bool(int)> is_ignored, + const std::vector<MixedTypedExampleType>& examples) { + const uint32_t INPUT = 0; + const uint32_t OUTPUT = 1; + Model model = create_model(); + + // see if service can handle model + ErrorStatus supportedStatus; + bool fullySupportsModel = false; + Return<void> supportedCall = device->getSupportedOperations( + model, [&](ErrorStatus status, const hidl_vec<bool>& supported) { + supportedStatus = status; + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = + std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedCall.isOk()); + ASSERT_EQ(ErrorStatus::NONE, supportedStatus); + + // launch prepare model + sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + + // retrieve prepared model + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel(); + if (fullySupportsModel) { + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + } else { + EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE || + prepareReturnStatus == ErrorStatus::GENERAL_FAILURE); + } + + // early termination if vendor service cannot fully prepare model + if (!fullySupportsModel && prepareReturnStatus == ErrorStatus::GENERAL_FAILURE) { + 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 " + "prepare model that it does not support." + << std::endl; + return; + } + ASSERT_NE(nullptr, preparedModel.get()); + + int example_no = 1; + for (auto& example : examples) { + SCOPED_TRACE(example_no++); + + const MixedTyped& inputs = example.first; + const MixedTyped& golden = example.second; + + std::vector<RequestArgument> inputs_info, outputs_info; + uint32_t inputSize = 0, outputSize = 0; + + // This function only partially specifies the metadata (vector of RequestArguments). + // The contents are copied over below. + for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) { + if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1); + RequestArgument arg = { + .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)}, + .dimensions = {}, + }; + RequestArgument arg_empty = { + .hasNoValue = true, + }; + inputs_info[index] = s ? arg : arg_empty; + inputSize += s; + }); + // Compute offset for inputs 1 and so on + { + size_t offset = 0; + for (auto& i : inputs_info) { + if (!i.hasNoValue) i.location.offset = offset; + offset += i.location.length; + } + } + + MixedTyped test; // holding test results + + // Go through all outputs, initialize RequestArgument descriptors + resize_accordingly(golden, test); + for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) { + if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1); + RequestArgument arg = { + .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)}, + .dimensions = {}, + }; + outputs_info[index] = arg; + outputSize += s; + }); + // Compute offset for outputs 1 and so on + { + size_t offset = 0; + for (auto& i : outputs_info) { + i.location.offset = offset; + offset += i.location.length; + } + } + std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize), + allocateSharedMemory(outputSize)}; + ASSERT_NE(0ull, pools[INPUT].size()); + ASSERT_NE(0ull, pools[OUTPUT].size()); + + // load data + sp<IMemory> inputMemory = mapMemory(pools[INPUT]); + sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]); + ASSERT_NE(nullptr, inputMemory.get()); + ASSERT_NE(nullptr, outputMemory.get()); + char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer())); + char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer())); + ASSERT_NE(nullptr, inputPtr); + ASSERT_NE(nullptr, outputPtr); + inputMemory->update(); + outputMemory->update(); + + // Go through all inputs, copy the values + for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) { + char* begin = (char*)p; + char* end = begin + s; + // TODO: handle more than one input + std::copy(begin, end, inputPtr + inputs_info[index].location.offset); + }); + + inputMemory->commit(); + outputMemory->commit(); + + // launch execution + sp<ExecutionCallback> executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + Return<ErrorStatus> executionLaunchStatus = preparedModel->execute( + {.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(); + ErrorStatus executionReturnStatus = executionCallback->getStatus(); + EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus); + + // validate results + outputMemory->read(); + copy_back(&test, outputs_info, outputPtr); + outputMemory->commit(); + // Filter out don't cares + MixedTyped filtered_golden = filter(golden, is_ignored); + MixedTyped filtered_test = filter(test, is_ignored); + + // We want "close-enough" results for float + compare(filtered_golden, filtered_test); + } +} + +} // namespace generated_tests + +} // namespace functional +} // namespace vts +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.0/vts/functional/Models.cpp b/neuralnetworks/1.0/vts/functional/Models.cpp new file mode 100644 index 0000000000..8ce4f25938 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/Models.cpp @@ -0,0 +1,207 @@ +/* + * 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. + */ + +#define LOG_TAG "neuralnetworks_hidl_hal_test" + +#include "Models.h" +#include <android/hidl/memory/1.0/IMemory.h> +#include <hidlmemory/mapping.h> +#include <vector> + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace vts { +namespace functional { + +// create a valid model +Model createValidTestModel() { + const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f}; + const uint32_t size = operand2Data.size() * sizeof(float); + + const uint32_t operand1 = 0; + const uint32_t operand2 = 1; + const uint32_t operand3 = 2; + const uint32_t operand4 = 3; + + const std::vector<Operand> operands = { + { + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1, 2, 2, 1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_INPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + { + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1, 2, 2, 1}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = 0, .length = size}, + }, + { + .type = OperandType::INT32, + .dimensions = {}, + .numberOfConsumers = 1, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::CONSTANT_COPY, + .location = {.poolIndex = 0, .offset = size, .length = sizeof(int32_t)}, + }, + { + .type = OperandType::TENSOR_FLOAT32, + .dimensions = {1, 2, 2, 1}, + .numberOfConsumers = 0, + .scale = 0.0f, + .zeroPoint = 0, + .lifetime = OperandLifeTime::MODEL_OUTPUT, + .location = {.poolIndex = 0, .offset = 0, .length = 0}, + }, + }; + + const std::vector<Operation> operations = {{ + .type = OperationType::ADD, .inputs = {operand1, operand2, operand3}, .outputs = {operand4}, + }}; + + const std::vector<uint32_t> inputIndexes = {operand1}; + const std::vector<uint32_t> outputIndexes = {operand4}; + std::vector<uint8_t> operandValues( + reinterpret_cast<const uint8_t*>(operand2Data.data()), + reinterpret_cast<const uint8_t*>(operand2Data.data()) + size); + int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)}; + operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]), + reinterpret_cast<const uint8_t*>(&activation[1])); + + const std::vector<hidl_memory> pools = {}; + + return { + .operands = operands, + .operations = operations, + .inputIndexes = inputIndexes, + .outputIndexes = outputIndexes, + .operandValues = operandValues, + .pools = pools, + }; +} + +// create first invalid model +Model createInvalidTestModel1() { + Model model = createValidTestModel(); + model.operations[0].type = static_cast<OperationType>(0xDEADBEEF); /* INVALID */ + return model; +} + +// create second invalid model +Model createInvalidTestModel2() { + Model model = createValidTestModel(); + const uint32_t operand1 = 0; + const uint32_t operand5 = 4; // INVALID OPERAND + model.inputIndexes = std::vector<uint32_t>({operand1, operand5 /* INVALID OPERAND */}); + return model; +} + +// allocator helper +hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem") { + hidl_memory memory; + + sp<IAllocator> allocator = IAllocator::getService(type); + if (!allocator.get()) { + return {}; + } + + Return<void> ret = allocator->allocate(size, [&](bool success, const hidl_memory& mem) { + ASSERT_TRUE(success); + memory = mem; + }); + if (!ret.isOk()) { + return {}; + } + + return memory; +} + +// create a valid request +Request createValidTestRequest() { + std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f}; + std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f}; + const uint32_t INPUT = 0; + const uint32_t OUTPUT = 1; + + // prepare inputs + uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float)); + uint32_t outputSize = static_cast<uint32_t>(outputData.size() * sizeof(float)); + std::vector<RequestArgument> inputs = {{ + .location = {.poolIndex = INPUT, .offset = 0, .length = inputSize}, .dimensions = {}, + }}; + std::vector<RequestArgument> outputs = {{ + .location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {}, + }}; + std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize), + allocateSharedMemory(outputSize)}; + if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) { + return {}; + } + + // load data + sp<IMemory> inputMemory = mapMemory(pools[INPUT]); + sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]); + if (inputMemory.get() == nullptr || outputMemory.get() == nullptr) { + return {}; + } + float* inputPtr = reinterpret_cast<float*>(static_cast<void*>(inputMemory->getPointer())); + float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer())); + if (inputPtr == nullptr || outputPtr == nullptr) { + return {}; + } + inputMemory->update(); + outputMemory->update(); + std::copy(inputData.begin(), inputData.end(), inputPtr); + std::copy(outputData.begin(), outputData.end(), outputPtr); + inputMemory->commit(); + outputMemory->commit(); + + return {.inputs = inputs, .outputs = outputs, .pools = pools}; +} + +// create first invalid request +Request createInvalidTestRequest1() { + Request request = createValidTestRequest(); + const uint32_t INVALID = 2; + std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f}; + uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float)); + request.inputs[0].location = { + .poolIndex = INVALID /* INVALID */, .offset = 0, .length = inputSize}; + return request; +} + +// create second invalid request +Request createInvalidTestRequest2() { + Request request = createValidTestRequest(); + request.inputs[0].dimensions = std::vector<uint32_t>({1, 2, 3, 4, 5, 6, 7, 8} /* INVALID */); + return request; +} + +} // namespace functional +} // namespace vts +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.0/vts/functional/Models.h b/neuralnetworks/1.0/vts/functional/Models.h new file mode 100644 index 0000000000..e0d57d533b --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/Models.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#define LOG_TAG "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworksV1_0TargetTest.h" + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace vts { +namespace functional { + +// create the model +Model createValidTestModel(); +Model createInvalidTestModel1(); +Model createInvalidTestModel2(); + +// create the request +Request createValidTestRequest(); +Request createInvalidTestRequest1(); +Request createInvalidTestRequest2(); + +} // namespace functional +} // namespace vts +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp new file mode 100644 index 0000000000..b99e20e3b4 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp @@ -0,0 +1,296 @@ +/* + * 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. + */ + +#define LOG_TAG "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworksV1_0TargetTest.h" + +#include "Callbacks.h" +#include "Models.h" +#include "TestHarness.h" + +#include <android-base/logging.h> +#include <android/hidl/memory/1.0/IMemory.h> +#include <hidlmemory/mapping.h> + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace vts { +namespace functional { + +using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback; +using ::generated_tests::MixedTypedExampleType; + +namespace generated_tests { +extern void Execute(const sp<IDevice>&, std::function<Model(void)>, std::function<bool(int)>, + const std::vector<MixedTypedExampleType>&); +} + +// A class for test environment setup +NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {} + +NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {} + +NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() { + // This has to return a "new" object because it is freed inside + // ::testing::AddGlobalTestEnvironment when the gtest is being torn down + static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment(); + return instance; +} + +void NeuralnetworksHidlEnvironment::registerTestServices() { + registerTestService<IDevice>(); +} + +// The main test class for NEURALNETWORK HIDL HAL. +NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {} + +void NeuralnetworksHidlTest::SetUp() { + device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>( + NeuralnetworksHidlEnvironment::getInstance()); + ASSERT_NE(nullptr, device.get()); +} + +void NeuralnetworksHidlTest::TearDown() {} + +sp<IPreparedModel> NeuralnetworksHidlTest::doPrepareModelShortcut() { + Model model = createValidTestModel(); + + sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); + if (preparedModelCallback == nullptr) { + return nullptr; + } + Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); + if (!prepareLaunchStatus.isOk() || prepareLaunchStatus != ErrorStatus::NONE) { + return nullptr; + } + + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel(); + if (prepareReturnStatus != ErrorStatus::NONE || preparedModel == nullptr) { + return nullptr; + } + + return preparedModel; +} + +// create device test +TEST_F(NeuralnetworksHidlTest, CreateDevice) {} + +// status test +TEST_F(NeuralnetworksHidlTest, StatusTest) { + Return<DeviceStatus> status = device->getStatus(); + ASSERT_TRUE(status.isOk()); + EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status)); +} + +// initialization +TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) { + Return<void> ret = + device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LT(0.0f, capabilities.float32Performance.execTime); + EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage); + EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime); + EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage); + }); + EXPECT_TRUE(ret.isOk()); +} + +// supported operations positive test +TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) { + Model model = createValidTestModel(); + Return<void> ret = device->getSupportedOperations( + model, [&](ErrorStatus status, const hidl_vec<bool>& supported) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_EQ(model.operations.size(), supported.size()); + }); + EXPECT_TRUE(ret.isOk()); +} + +// supported operations negative test 1 +TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) { + Model model = createInvalidTestModel1(); + Return<void> ret = device->getSupportedOperations( + model, [&](ErrorStatus status, const hidl_vec<bool>& supported) { + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); + (void)supported; + }); + EXPECT_TRUE(ret.isOk()); +} + +// supported operations negative test 2 +TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) { + Model model = createInvalidTestModel2(); + Return<void> ret = device->getSupportedOperations( + model, [&](ErrorStatus status, const hidl_vec<bool>& supported) { + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); + (void)supported; + }); + EXPECT_TRUE(ret.isOk()); +} + +// prepare simple model positive test +TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) { + Model model = createValidTestModel(); + sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus)); + + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); + sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel(); + EXPECT_NE(nullptr, preparedModel.get()); +} + +// prepare simple model negative test 1 +TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) { + Model model = createInvalidTestModel1(); + sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus)); + + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus); + sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel(); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +// prepare simple model negative test 2 +TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) { + Model model = createInvalidTestModel2(); + sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus)); + + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus); + sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel(); + EXPECT_EQ(nullptr, preparedModel.get()); +} + +// execute simple graph positive test +TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphPositiveTest) { + std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f}; + std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f}; + const uint32_t OUTPUT = 1; + + sp<IPreparedModel> preparedModel = doPrepareModelShortcut(); + ASSERT_NE(nullptr, preparedModel.get()); + Request request = createValidTestRequest(); + + auto postWork = [&] { + sp<IMemory> outputMemory = mapMemory(request.pools[OUTPUT]); + if (outputMemory == nullptr) { + return false; + } + float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer())); + if (outputPtr == nullptr) { + return false; + } + outputMemory->read(); + std::copy(outputPtr, outputPtr + outputData.size(), outputData.begin()); + outputMemory->commit(); + return true; + }; + + sp<ExecutionCallback> executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + executionCallback->on_finish(postWork); + Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback); + ASSERT_TRUE(executeLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executeLaunchStatus)); + + executionCallback->wait(); + ErrorStatus executionReturnStatus = executionCallback->getStatus(); + EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus); + EXPECT_EQ(expectedData, outputData); +} + +// execute simple graph negative test 1 +TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) { + sp<IPreparedModel> preparedModel = doPrepareModelShortcut(); + ASSERT_NE(nullptr, preparedModel.get()); + Request request = createInvalidTestRequest1(); + + sp<ExecutionCallback> executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback); + ASSERT_TRUE(executeLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus)); + + executionCallback->wait(); + ErrorStatus executionReturnStatus = executionCallback->getStatus(); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus); +} + +// execute simple graph negative test 2 +TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) { + sp<IPreparedModel> preparedModel = doPrepareModelShortcut(); + ASSERT_NE(nullptr, preparedModel.get()); + Request request = createInvalidTestRequest2(); + + sp<ExecutionCallback> executionCallback = new ExecutionCallback(); + ASSERT_NE(nullptr, executionCallback.get()); + Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback); + ASSERT_TRUE(executeLaunchStatus.isOk()); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus)); + + executionCallback->wait(); + ErrorStatus executionReturnStatus = executionCallback->getStatus(); + EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus); +} + +// Mixed-typed examples +typedef MixedTypedExampleType MixedTypedExample; + +// in frameworks/ml/nn/runtime/tests/generated/ +#include "all_generated_vts_tests.cpp" + +// TODO: Add tests for execution failure, or wait_for/wait_until timeout. +// Discussion: +// https://googleplex-android-review.git.corp.google.com/#/c/platform/hardware/interfaces/+/2654636/5/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp@222 + +} // namespace functional +} // namespace vts +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment; + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance()); + ::testing::InitGoogleTest(&argc, argv); + NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv); + + int status = RUN_ALL_TESTS(); + return status; +} diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h new file mode 100644 index 0000000000..5cd209ae62 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#ifndef VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H +#define VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H + +#include <android/hardware/neuralnetworks/1.0/IDevice.h> +#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h> +#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h> +#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h> +#include <android/hardware/neuralnetworks/1.0/types.h> +#include <android/hidl/allocator/1.0/IAllocator.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> +#include <gtest/gtest.h> +#include <string> + +using ::android::hardware::neuralnetworks::V1_0::IDevice; +using ::android::hardware::neuralnetworks::V1_0::IPreparedModel; +using ::android::hardware::neuralnetworks::V1_0::Capabilities; +using ::android::hardware::neuralnetworks::V1_0::DeviceStatus; +using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc; +using ::android::hardware::neuralnetworks::V1_0::Model; +using ::android::hardware::neuralnetworks::V1_0::OperationType; +using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hidl::allocator::V1_0::IAllocator; +using ::android::hidl::memory::V1_0::IMemory; +using ::android::sp; + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_0 { +namespace vts { +namespace functional { + +// A class for test environment setup +class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + NeuralnetworksHidlEnvironment(); + NeuralnetworksHidlEnvironment(const NeuralnetworksHidlEnvironment&) = delete; + NeuralnetworksHidlEnvironment(NeuralnetworksHidlEnvironment&&) = delete; + NeuralnetworksHidlEnvironment& operator=(const NeuralnetworksHidlEnvironment&) = delete; + NeuralnetworksHidlEnvironment& operator=(NeuralnetworksHidlEnvironment&&) = delete; + + public: + ~NeuralnetworksHidlEnvironment() override; + static NeuralnetworksHidlEnvironment* getInstance(); + void registerTestServices() override; +}; + +// The main test class for NEURALNETWORKS HIDL HAL. +class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + ~NeuralnetworksHidlTest() override; + void SetUp() override; + void TearDown() override; + + sp<IPreparedModel> doPrepareModelShortcut(); + + sp<IDevice> device; +}; + +} // namespace functional +} // namespace vts + +// pretty-print values for error messages + +template<typename CharT, typename Traits> +::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os, + ErrorStatus errorStatus) { + return os << toString(errorStatus); +} + +template<typename CharT, typename Traits> +::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os, + DeviceStatus deviceStatus) { + return os << toString(deviceStatus); +} + +} // namespace V1_0 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H diff --git a/neuralnetworks/Android.bp b/neuralnetworks/Android.bp new file mode 100644 index 0000000000..33f70ebae2 --- /dev/null +++ b/neuralnetworks/Android.bp @@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/vts/functional", +] diff --git a/oemlock/1.0/vts/functional/Android.bp b/oemlock/1.0/vts/functional/Android.bp index a13b3dc71d..20737a1808 100644 --- a/oemlock/1.0/vts/functional/Android.bp +++ b/oemlock/1.0/vts/functional/Android.bp @@ -16,21 +16,7 @@ cc_test { name: "VtsHalOemLockV1_0TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalOemLockV1_0TargetTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", - "android.hardware.oemlock@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], + static_libs: ["android.hardware.oemlock@1.0"], } diff --git a/power/1.1/default/Power.cpp b/power/1.1/default/Power.cpp deleted file mode 100644 index b5d0c84bcc..0000000000 --- a/power/1.1/default/Power.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "android.hardware.power@1.1-impl" - -#include <log/log.h> - -#include <hardware/hardware.h> -#include <hardware/power.h> - -#include "Power.h" - -namespace android { -namespace hardware { -namespace power { -namespace V1_1 { -namespace implementation { - -using ::android::hardware::power::V1_0::Feature; -using ::android::hardware::power::V1_0::PowerHint; -using ::android::hardware::power::V1_0::PowerStatePlatformSleepState; -using ::android::hardware::power::V1_0::Status; -using ::android::hardware::power::V1_1::PowerStateSubsystem; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; - -Power::Power(power_module_t *module) : mModule(module) { - if (mModule) - mModule->init(mModule); -} - -Power::~Power() { - delete(mModule); -} - -// Methods from ::android::hardware::power::V1_0::IPower follow. -Return<void> Power::setInteractive(bool interactive) { - if (mModule->setInteractive) - mModule->setInteractive(mModule, interactive ? 1 : 0); - return Void(); -} - -Return<void> Power::powerHint(PowerHint hint, int32_t data) { - int32_t param = data; - if (mModule->powerHint) { - if (data) - mModule->powerHint(mModule, static_cast<power_hint_t>(hint), ¶m); - else - mModule->powerHint(mModule, static_cast<power_hint_t>(hint), NULL); - } - return Void(); -} - -Return<void> Power::setFeature(Feature feature, bool activate) { - if (mModule->setFeature) - mModule->setFeature(mModule, static_cast<feature_t>(feature), - activate ? 1 : 0); - return Void(); -} - -Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) { - hidl_vec<PowerStatePlatformSleepState> states; - ssize_t number_platform_modes; - size_t *voters = nullptr; - power_state_platform_sleep_state_t *legacy_states = nullptr; - int ret; - - if (mModule->get_number_of_platform_modes == nullptr || - mModule->get_voter_list == nullptr || - mModule->get_platform_low_power_stats == nullptr) - { - _hidl_cb(states, Status::SUCCESS); - return Void(); - } - - number_platform_modes = mModule->get_number_of_platform_modes(mModule); - if (number_platform_modes) - { - if ((ssize_t) (SIZE_MAX / sizeof(size_t)) <= number_platform_modes) // overflow - goto done; - voters = new (std::nothrow) size_t [number_platform_modes]; - if (voters == nullptr) - goto done; - - ret = mModule->get_voter_list(mModule, voters); - if (ret != 0) - goto done; - - if ((ssize_t) (SIZE_MAX / sizeof(power_state_platform_sleep_state_t)) - <= number_platform_modes) // overflow - goto done; - legacy_states = new (std::nothrow) - power_state_platform_sleep_state_t [number_platform_modes]; - if (legacy_states == nullptr) - goto done; - - for (int i = 0; i < number_platform_modes; i++) - { - legacy_states[i].voters = nullptr; - legacy_states[i].voters = new power_state_voter_t [voters[i]]; - if (legacy_states[i].voters == nullptr) - goto done; - } - - ret = mModule->get_platform_low_power_stats(mModule, legacy_states); - if (ret != 0) - goto done; - - states.resize(number_platform_modes); - for (int i = 0; i < number_platform_modes; i++) - { - power_state_platform_sleep_state_t& legacy_state = legacy_states[i]; - PowerStatePlatformSleepState& state = states[i]; - state.name = legacy_state.name; - state.residencyInMsecSinceBoot = legacy_state.residency_in_msec_since_boot; - state.totalTransitions = legacy_state.total_transitions; - state.supportedOnlyInSuspend = legacy_state.supported_only_in_suspend; - state.voters.resize(voters[i]); - for(size_t j = 0; j < voters[i]; j++) - { - state.voters[j].name = legacy_state.voters[j].name; - state.voters[j].totalTimeInMsecVotedForSinceBoot = legacy_state.voters[j].total_time_in_msec_voted_for_since_boot; - state.voters[j].totalNumberOfTimesVotedSinceBoot = legacy_state.voters[j].total_number_of_times_voted_since_boot; - } - } - } -done: - if (legacy_states) - { - for (int i = 0; i < number_platform_modes; i++) - { - if(legacy_states[i].voters) - delete(legacy_states[i].voters); - } - } - delete[] legacy_states; - delete[] voters; - _hidl_cb(states, Status::SUCCESS); - return Void(); -} - -// Methods from ::android::hardware::power::V1_1::IPower follow. -Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) { - hidl_vec<PowerStateSubsystem> subsystems; - ssize_t number_subsystems = 0; - - //This API will report zero subsystems to support older devices - //For devices that support this API, they will have their own implementation - subsystems.resize(number_subsystems); - _hidl_cb(subsystems, Status::SUCCESS); - return Void(); -} - -Return<void> Power::powerHintAsync(PowerHint hint, int32_t data) { - // just call the normal power hint in this oneway function - return powerHint(hint, data); -} - -} // namespace implementation -} // namespace V1_1 -} // namespace power -} // namespace hardware -} // namespace android diff --git a/power/1.1/default/Power.h b/power/1.1/default/Power.h deleted file mode 100644 index e779d64d37..0000000000 --- a/power/1.1/default/Power.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HARDWARE_POWER_V1_1_POWER_H -#define ANDROID_HARDWARE_POWER_V1_1_POWER_H - -#include <android/hardware/power/1.1/IPower.h> -#include <hidl/MQDescriptor.h> -#include <hidl/Status.h> -#include <hardware/power.h> - -namespace android { -namespace hardware { -namespace power { -namespace V1_1 { -namespace implementation { - -using ::android::hardware::power::V1_0::Feature; -using ::android::hardware::power::V1_0::PowerHint; -using ::android::hardware::power::V1_1::IPower; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct Power : public IPower { - Power(power_module_t* module); - ~Power(); - - // Methods from ::android::hardware::power::V1_0::IPower follow - Return<void> setInteractive(bool interactive) override; - Return<void> powerHint(PowerHint hint, int32_t data) override; - Return<void> setFeature(Feature feature, bool activate) override; - Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override; - - // Methods from ::android::hardware::power::V1_1::IPower follow. - Return<void> getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) override; - Return<void> powerHintAsync(PowerHint hint, int32_t data) override; - - // Methods from ::android::hidl::base::V1_0::IBase follow. - - private: - power_module_t* mModule; -}; - -} // namespace implementation -} // namespace V1_1 -} // namespace power -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_POWER_V1_1_POWER_H diff --git a/power/1.1/default/android.hardware.power@1.1-service.rc b/power/1.1/default/android.hardware.power@1.1-service.rc deleted file mode 100644 index f2512f1b53..0000000000 --- a/power/1.1/default/android.hardware.power@1.1-service.rc +++ /dev/null @@ -1,4 +0,0 @@ -service power-hal-1-1 /vendor/bin/hw/android.hardware.power@1.1-service - class hal - user system - group system diff --git a/power/1.1/default/service.cpp b/power/1.1/default/service.cpp deleted file mode 100644 index 571db2f31c..0000000000 --- a/power/1.1/default/service.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "android.hardware.power@1.1-service" - -#include <android/log.h> -#include <hidl/HidlTransportSupport.h> -#include <android/hardware/power/1.1/IPower.h> -#include <hardware/power.h> -#include "Power.h" - -using android::sp; -using android::status_t; -using android::OK; - -// libhwbinder: -using android::hardware::configureRpcThreadpool; -using android::hardware::joinRpcThreadpool; - -// Generated HIDL files -using android::hardware::power::V1_1::IPower; -using android::hardware::power::V1_1::implementation::Power; - -int main() { - - status_t status; - android::sp<IPower> service = nullptr; - const hw_module_t* hw_module = nullptr; - power_module_t* power_module = nullptr; - int err; - - ALOGI("Power HAL Service 1.1 (Default) is starting."); - - err = hw_get_module(POWER_HARDWARE_MODULE_ID, &hw_module); - if (err) { - ALOGE("hw_get_module %s failed: %d", POWER_HARDWARE_MODULE_ID, err); - goto shutdown; - } - - if (!hw_module->methods || !hw_module->methods->open) { - power_module = reinterpret_cast<power_module_t*>( - const_cast<hw_module_t*>(hw_module)); - } else { - err = hw_module->methods->open(hw_module, POWER_HARDWARE_MODULE_ID, - reinterpret_cast<hw_device_t**>(&power_module)); - if (err) { - ALOGE("Passthrough failed to load legacy HAL."); - goto shutdown; - } - } - - service = new Power(power_module); - if (service == nullptr) { - ALOGE("Can not create an instance of Power HAL Iface, exiting."); - - goto shutdown; - } - - configureRpcThreadpool(1, true /*callerWillJoin*/); - - status = service->registerAsService(); - if (status != OK) { - ALOGE("Could not register service for Power HAL Iface (%d).", status); - goto shutdown; - } - - ALOGI("Power Service is ready"); - joinRpcThreadpool(); - //Should not pass this line - -shutdown: - // In normal operation, we don't expect the thread pool to exit - - ALOGE("Power Service is shutting down"); - return 1; -} diff --git a/power/1.1/vts/functional/Android.bp b/power/1.1/vts/functional/Android.bp index f886bd2c08..604cd36eef 100644 --- a/power/1.1/vts/functional/Android.bp +++ b/power/1.1/vts/functional/Android.bp @@ -16,19 +16,10 @@ cc_test { name: "VtsHalPowerV1_1TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalPowerV1_1TargetTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libhidltransport", - "libutils", + static_libs: [ + "android.hardware.power@1.0", "android.hardware.power@1.1", ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ] } diff --git a/power/Android.bp b/power/Android.bp index 7a315faab3..a5415df348 100644 --- a/power/Android.bp +++ b/power/Android.bp @@ -4,6 +4,5 @@ subdirs = [ "1.0/default", "1.0/vts/functional", "1.1", - "1.1/default", "1.1/vts/functional", ] diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal index a94aac3352..27945cb07f 100644 --- a/radio/1.0/IRadioResponse.hal +++ b/radio/1.0/IRadioResponse.hal @@ -161,6 +161,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway supplyNetworkDepersonalizationResponse(RadioResponseInfo info, int32_t remainingRetries); @@ -544,6 +545,7 @@ interface IRadioResponse { * RadioError:OPERATION_NOT_ALLOWED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway sendSmsResponse(RadioResponseInfo info, SendSmsResult sms); @@ -574,6 +576,7 @@ interface IRadioResponse { * RadioError:OPERATION_NOT_ALLOWED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway sendSMSExpectMoreResponse(RadioResponseInfo info, SendSmsResult sms); @@ -594,6 +597,7 @@ interface IRadioResponse { * RadioError:NO_MEMORY * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway setupDataCallResponse(RadioResponseInfo info, SetupDataCallResult dcResponse); @@ -860,6 +864,7 @@ interface IRadioResponse { * RadioError:NO_MEMORY * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway deactivateDataCallResponse(RadioResponseInfo info); @@ -1166,6 +1171,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway getDataCallListResponse(RadioResponseInfo info, vec<SetupDataCallResult> dcResponse); @@ -1184,6 +1190,7 @@ interface IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway setSuppServiceNotificationsResponse(RadioResponseInfo info); @@ -1210,6 +1217,7 @@ interface IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:CANCELLED * RadioError:INVALID_MODEM_STATE + * RadioError:SIM_ABSENT */ oneway writeSmsToSimResponse(RadioResponseInfo info, int32_t index); @@ -1231,6 +1239,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:INVALID_MODEM_STATE + * RadioError:SIM_ABSENT */ oneway deleteSmsOnSimResponse(RadioResponseInfo info); @@ -1287,6 +1296,7 @@ interface IRadioResponse { * RadioError:INVALID_ARGUMENTS * RadioError:MODEM_ERR * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway sendEnvelopeResponse(RadioResponseInfo info, string commandResponse); @@ -1304,6 +1314,7 @@ interface IRadioResponse { * RadioError:CANCELLED * RadioError:INVALID_MODEM_STATE * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway sendTerminalResponseToSimResponse(RadioResponseInfo info); @@ -1321,6 +1332,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway handleStkCallSetupRequestFromSimResponse(RadioResponseInfo info); @@ -1417,6 +1429,7 @@ interface IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway setLocationUpdatesResponse(RadioResponseInfo info); @@ -1451,6 +1464,7 @@ interface IRadioResponse { * RadioError:OPERATION_NOT_ALLOWED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway setCdmaRoamingPreferenceResponse(RadioResponseInfo info); @@ -1469,6 +1483,7 @@ interface IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway getCdmaRoamingPreferenceResponse(RadioResponseInfo info, CdmaRoamingType type); @@ -1615,6 +1630,7 @@ interface IRadioResponse { * RadioError:ENCODING_ERR * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway sendCdmaSmsResponse(RadioResponseInfo info, SendSmsResult sms); @@ -1792,6 +1808,7 @@ interface IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway getCDMASubscriptionResponse(RadioResponseInfo info, string mdn, string hSid, string hNid, string min, string prl); @@ -1819,6 +1836,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:INVALID_MODEM_STATE + * RadioError:SIM_ABSENT */ oneway writeSmsToRuimResponse(RadioResponseInfo info, uint32_t index); @@ -1839,6 +1857,8 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:INVALID_MODEM_STATE + * RadioError:OPERATION_NOT_ALLOWED + * RadioError:SIM_ABSENT */ oneway deleteSmsOnRuimResponse(RadioResponseInfo info); @@ -1884,6 +1904,7 @@ interface IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway exitEmergencyCallbackModeResponse(RadioResponseInfo info); @@ -1906,6 +1927,7 @@ interface IRadioResponse { * RadioError:OPERATION_NOT_ALLOWED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway getSmscAddressResponse(RadioResponseInfo info, string smsc); @@ -1927,6 +1949,7 @@ interface IRadioResponse { * RadioError:OPERATION_NOT_ALLOWED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway setSmscAddressResponse(RadioResponseInfo info); @@ -1946,6 +1969,7 @@ interface IRadioResponse { * RadioError:REQUEST_NOT_SUPPORTED * RadioError:NO_RESOURCES * RadioError:CANCELLED + * RadioError:SIM_ABSENT */ oneway reportSmsMemoryStatusResponse(RadioResponseInfo info); @@ -1976,6 +2000,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway getCdmaSubscriptionSourceResponse(RadioResponseInfo info, CdmaSubscriptionSource source); @@ -1993,6 +2018,7 @@ interface IRadioResponse { * RadioError:INVALID_MODEM_STATE * RadioError:INVALID_ARGUMENTS * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway requestIsimAuthenticationResponse(RadioResponseInfo info, string response); @@ -2024,6 +2050,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway sendEnvelopeWithStatusResponse(RadioResponseInfo info, IccIoResult iccIo); @@ -2328,6 +2355,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway setDataProfileResponse(RadioResponseInfo info); @@ -2414,6 +2442,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway stopLceServiceResponse(RadioResponseInfo info, LceStatusInfo statusInfo); @@ -2430,6 +2459,7 @@ interface IRadioResponse { * RadioError:NO_RESOURCES * RadioError:CANCELLED * RadioError:REQUEST_NOT_SUPPORTED + * RadioError:SIM_ABSENT */ oneway pullLceDataResponse(RadioResponseInfo info, LceDataInfo lceInfo); diff --git a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp index 9e003e2d77..130064aa52 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp @@ -317,6 +317,7 @@ TEST_F(RadioHidlTest, getIccCardStatus) { radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS || radioRsp->rspInfo.error == RadioError::INVALID_SIM_STATE || radioRsp->rspInfo.error == RadioError::PASSWORD_INCORRECT || - radioRsp->rspInfo.error == RadioError::INTERNAL_ERR); + radioRsp->rspInfo.error == RadioError::INTERNAL_ERR || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp b/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp index c1834c5692..aa9d9871c9 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp @@ -155,7 +155,8 @@ TEST_F(RadioHidlTest, setSuppServiceNotifications) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); if (cardStatus.cardState == CardState::ABSENT) { - EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); + ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -173,7 +174,7 @@ TEST_F(RadioHidlTest, requestIsimAuthentication) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); if (cardStatus.cardState == CardState::ABSENT) { - ASSERT_TRUE(CheckGeneralError()); + ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp index 0507cc98f5..631dff3d1e 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp @@ -70,7 +70,7 @@ TEST_F(RadioHidlTest, getOperator) { TEST_F(RadioHidlTest, setRadioPower) { int serial = GetRandomSerialNumber(); - radio->setRadioPower(serial, 0); + radio->setRadioPower(serial, 1); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type); EXPECT_EQ(serial, radioRsp->rspInfo.serial); @@ -265,7 +265,8 @@ TEST_F(RadioHidlTest, setLocationUpdates) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); if (cardStatus.cardState == CardState::ABSENT) { - ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE); + ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -282,7 +283,8 @@ TEST_F(RadioHidlTest, setCdmaRoamingPreference) { if (cardStatus.cardState == CardState::ABSENT) { ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || - radioRsp->rspInfo.error == RadioError::REQUEST_NOT_SUPPORTED); + radioRsp->rspInfo.error == RadioError::REQUEST_NOT_SUPPORTED || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -299,7 +301,8 @@ TEST_F(RadioHidlTest, getCdmaRoamingPreference) { if (cardStatus.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::NONE || - radioRsp->rspInfo.error == RadioError::MODEM_ERR); + radioRsp->rspInfo.error == RadioError::MODEM_ERR || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -381,7 +384,9 @@ TEST_F(RadioHidlTest, getCDMASubscription) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); if (cardStatus.cardState == CardState::ABSENT) { - ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE); + ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || + radioRsp->rspInfo.error == RadioError::REQUEST_NOT_SUPPORTED || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -414,7 +419,9 @@ TEST_F(RadioHidlTest, exitEmergencyCallbackMode) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); if (cardStatus.cardState == CardState::ABSENT) { - ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE); + ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || + radioRsp->rspInfo.error == RadioError::REQUEST_NOT_SUPPORTED || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -430,7 +437,9 @@ TEST_F(RadioHidlTest, getCdmaSubscriptionSource) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); if (cardStatus.cardState == CardState::ABSENT) { - ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE); + ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || + radioRsp->rspInfo.error == RadioError::REQUEST_NOT_SUPPORTED || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp index f97f5febd6..c3f7549666 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp @@ -38,7 +38,8 @@ TEST_F(RadioHidlTest, sendEnvelope) { ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS || radioRsp->rspInfo.error == RadioError::NONE || - radioRsp->rspInfo.error == RadioError::MODEM_ERR); + radioRsp->rspInfo.error == RadioError::MODEM_ERR || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -61,7 +62,8 @@ TEST_F(RadioHidlTest, sendTerminalResponseToSim) { std::cout << static_cast<int>(radioRsp->rspInfo.error) << std::endl; ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS || - radioRsp->rspInfo.error == RadioError::NONE); + radioRsp->rspInfo.error == RadioError::NONE || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } @@ -81,7 +83,8 @@ TEST_F(RadioHidlTest, handleStkCallSetupRequestFromSim) { if (cardStatus.cardState == CardState::ABSENT) { ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::NONE || radioRsp->rspInfo.error == RadioError::MODEM_ERR || - radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS); + radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS || + radioRsp->rspInfo.error == RadioError::SIM_ABSENT); } } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp index 8d6e200f27..1d2f199de0 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp @@ -366,6 +366,7 @@ TEST_F(RadioHidlTest, sendCDMAFeatureCode) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); if (cardStatus.cardState == CardState::ABSENT) { + std::cout << static_cast<int>(radioRsp->rspInfo.error) << std::endl; ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS || radioRsp->rspInfo.error == RadioError::NONE || diff --git a/radio/1.1/IRadioResponse.hal b/radio/1.1/IRadioResponse.hal index 4e7bf43dec..759602b004 100644 --- a/radio/1.1/IRadioResponse.hal +++ b/radio/1.1/IRadioResponse.hal @@ -16,6 +16,7 @@ package android.hardware.radio@1.1; +import @1.0::RadioResponseInfo; import @1.0::IRadioResponse; /** diff --git a/renderscript/1.0/vts/functional/Android.bp b/renderscript/1.0/vts/functional/Android.bp index 5256c1f9da..bf011e6c17 100644 --- a/renderscript/1.0/vts/functional/Android.bp +++ b/renderscript/1.0/vts/functional/Android.bp @@ -23,21 +23,9 @@ cc_test { "VtsScriptTests.cpp", "bitcode.cpp", ], - defaults: ["hidl_defaults"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", - "libnativewindow", + defaults: ["VtsHalTargetTestDefaults"], + static_libs: [ "android.hardware.renderscript@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", + "libnativewindow", ], } diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp index 75fe3df7e4..2485b058fb 100644 --- a/sensors/1.0/default/Android.bp +++ b/sensors/1.0/default/Android.bp @@ -38,6 +38,9 @@ cc_library_static { "android.hardware.sensors@1.0", ], local_include_dirs: ["include/sensors"], + export_shared_lib_headers: [ + "libhardware", + ], } cc_binary { diff --git a/soundtrigger/2.0/default/OWNERS b/soundtrigger/2.0/default/OWNERS new file mode 100644 index 0000000000..6fdc97ca29 --- /dev/null +++ b/soundtrigger/2.0/default/OWNERS @@ -0,0 +1,3 @@ +elaurent@google.com +krocard@google.com +mnaganov@google.com diff --git a/tetheroffload/config/1.0/vts/functional/Android.bp b/tetheroffload/config/1.0/vts/functional/Android.bp index 2e720c6855..dc95eaa28d 100644 --- a/tetheroffload/config/1.0/vts/functional/Android.bp +++ b/tetheroffload/config/1.0/vts/functional/Android.bp @@ -14,20 +14,7 @@ cc_test { name: "VtsHalTetheroffloadConfigV1_0TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalTetheroffloadConfigV1_0TargetTest.cpp"], - shared_libs: [ - "android.hardware.tetheroffload.config@1.0", - "libbase", - "libcutils", - "libhidlbase", - "libhidltransport", - "liblog", - "libutils", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], + static_libs: ["android.hardware.tetheroffload.config@1.0"], } diff --git a/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp b/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp index fc61e1c1c0..2cbe479dc9 100644 --- a/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp +++ b/tetheroffload/config/1.0/vts/functional/VtsHalTetheroffloadConfigV1_0TargetTest.cpp @@ -91,35 +91,42 @@ class OffloadConfigHidlTest : public testing::VtsHalHidlTargetTestBase { // Ensure handles can be set with correct socket options. TEST_F(OffloadConfigHidlTest, TestSetHandles) { - unique_fd fd1(netlinkSocket(kFd1Groups)); - if (fd1.get() < 0) { - ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); - FAIL(); - } - native_handle_t* const nativeHandle1 = native_handle_create(1, 0); - nativeHandle1->data[0] = fd1.release(); - const hidl_handle h1 = hidl_handle(nativeHandle1); - - unique_fd fd2(netlinkSocket(kFd2Groups)); - if (fd2.get() < 0) { - ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); - FAIL(); + // Try multiple times in a row to see if it provokes file descriptor leaks. + for (int i = 0; i < 1024; i++) { + unique_fd fd1(netlinkSocket(kFd1Groups)); + if (fd1.get() < 0) { + ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); + FAIL(); + } + native_handle_t* const nativeHandle1 = native_handle_create(1, 0); + nativeHandle1->data[0] = fd1.release(); + hidl_handle h1; + h1.setTo(nativeHandle1, true); + + unique_fd fd2(netlinkSocket(kFd2Groups)); + if (fd2.get() < 0) { + ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); + FAIL(); + } + native_handle_t* const nativeHandle2 = native_handle_create(1, 0); + nativeHandle2->data[0] = fd2.release(); + hidl_handle h2; + h2.setTo(nativeHandle2, true); + + const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK); + ASSERT_TRUE(ret.isOk()); } - native_handle_t* const nativeHandle2 = native_handle_create(1, 0); - nativeHandle2->data[0] = fd2.release(); - const hidl_handle h2 = hidl_handle(nativeHandle2); - - const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK); - ASSERT_TRUE(ret.isOk()); } // Passing a handle without an associated file descriptor should return an error // (e.g. "Failed Input Checks"). Check that this occurs when both FDs are empty. TEST_F(OffloadConfigHidlTest, TestSetHandleNone) { native_handle_t* const nativeHandle1 = native_handle_create(0, 0); - const hidl_handle h1 = hidl_handle(nativeHandle1); + hidl_handle h1; + h1.setTo(nativeHandle1, true); native_handle_t* const nativeHandle2 = native_handle_create(0, 0); - const hidl_handle h2 = hidl_handle(nativeHandle2); + hidl_handle h2; + h2.setTo(nativeHandle2, true); const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK); ASSERT_TRUE(ret.isOk()); @@ -135,10 +142,12 @@ TEST_F(OffloadConfigHidlTest, TestSetHandle1Only) { } native_handle_t* const nativeHandle1 = native_handle_create(1, 0); nativeHandle1->data[0] = fd1.release(); - const hidl_handle h1 = hidl_handle(nativeHandle1); + hidl_handle h1; + h1.setTo(nativeHandle1, true); native_handle_t* const nativeHandle2 = native_handle_create(0, 0); - const hidl_handle h2 = hidl_handle(nativeHandle2); + hidl_handle h2; + h2.setTo(nativeHandle2, true); const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK); ASSERT_TRUE(ret.isOk()); @@ -148,7 +157,8 @@ TEST_F(OffloadConfigHidlTest, TestSetHandle1Only) { // (e.g. "Failed Input Checks"). Check that this occurs when FD1 is empty. TEST_F(OffloadConfigHidlTest, TestSetHandle2OnlyNotOk) { native_handle_t* const nativeHandle1 = native_handle_create(0, 0); - const hidl_handle h1 = hidl_handle(nativeHandle1); + hidl_handle h1; + h1.setTo(nativeHandle1, true); unique_fd fd2(netlinkSocket(kFd2Groups)); if (fd2.get() < 0) { @@ -157,7 +167,8 @@ TEST_F(OffloadConfigHidlTest, TestSetHandle2OnlyNotOk) { } native_handle_t* const nativeHandle2 = native_handle_create(1, 0); nativeHandle2->data[0] = fd2.release(); - const hidl_handle h2 = hidl_handle(nativeHandle2); + hidl_handle h2; + h2.setTo(nativeHandle2, true); const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK); ASSERT_TRUE(ret.isOk()); diff --git a/tetheroffload/control/1.0/vts/functional/Android.bp b/tetheroffload/control/1.0/vts/functional/Android.bp index 69fac6e57f..c6216a2f97 100644 --- a/tetheroffload/control/1.0/vts/functional/Android.bp +++ b/tetheroffload/control/1.0/vts/functional/Android.bp @@ -14,21 +14,10 @@ cc_test { name: "VtsHalTetheroffloadControlV1_0TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalTetheroffloadControlV1_0TargetTest.cpp"], - shared_libs: [ + static_libs: [ "android.hardware.tetheroffload.config@1.0", "android.hardware.tetheroffload.control@1.0", - "libbase", - "libcutils", - "libhidlbase", - "libhidltransport", - "liblog", - "libutils", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", ], } diff --git a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp index 3059eac0c2..c009af5d91 100644 --- a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp +++ b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp @@ -46,6 +46,12 @@ using android::hardware::tetheroffload::control::V1_0::NetworkProtocol; using android::hardware::Void; using android::sp; +enum class ExpectBoolean { + Ignored = -1, + False = 0, + True = 1, +}; + // We use #defines here so as to get local lamba captures and error message line numbers #define ASSERT_TRUE_CALLBACK \ [&](bool success, std::string errMsg) { \ @@ -112,7 +118,12 @@ class OffloadControlHidlTestBase : public testing::VtsHalHidlTargetTestBase { prepareControlHal(); } - virtual void TearDown() override { stopOffload(false); } + virtual void TearDown() override { + // For good measure, we should try stopOffload() once more. Since we + // don't know where we are in HAL call test cycle we don't know what + // return code to actually expect, so we just ignore it. + stopOffload(ExpectBoolean::Ignored); + } // The IOffloadConfig HAL is tested more thoroughly elsewhere. He we just // setup everything correctly and verify basic readiness. @@ -127,7 +138,8 @@ class OffloadControlHidlTestBase : public testing::VtsHalHidlTargetTestBase { } native_handle_t* const nativeHandle1 = native_handle_create(1, 0); nativeHandle1->data[0] = fd1.release(); - hidl_handle h1 = hidl_handle(nativeHandle1); + hidl_handle h1; + h1.setTo(nativeHandle1, true); unique_fd fd2(conntrackSocket(NFNLGRP_CONNTRACK_UPDATE | NFNLGRP_CONNTRACK_DESTROY)); if (fd2.get() < 0) { @@ -136,7 +148,8 @@ class OffloadControlHidlTestBase : public testing::VtsHalHidlTargetTestBase { } native_handle_t* const nativeHandle2 = native_handle_create(1, 0); nativeHandle2->data[0] = fd2.release(); - hidl_handle h2 = hidl_handle(nativeHandle2); + hidl_handle h2; + h2.setTo(nativeHandle2, true); const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK); ASSERT_TRUE(ret.isOk()); @@ -166,12 +179,21 @@ class OffloadControlHidlTestBase : public testing::VtsHalHidlTargetTestBase { initOffload(true); } - void stopOffload(const bool expected_result) { + void stopOffload(const ExpectBoolean value) { auto cb = [&](bool success, const hidl_string& errMsg) { if (!success) { ALOGI("Error message: %s", errMsg.c_str()); } - ASSERT_EQ(expected_result, success); + switch (value) { + case ExpectBoolean::False: + ASSERT_EQ(false, success); + break; + case ExpectBoolean::True: + ASSERT_EQ(true, success); + break; + case ExpectBoolean::Ignored: + break; + } }; const Return<void> ret = control->stopOffload(cb); ASSERT_TRUE(ret.isOk()); @@ -209,22 +231,29 @@ TEST_F(OffloadControlHidlTestBase, AdditionalInitsWithoutStopReturnFalse) { initOffload(false); initOffload(false); initOffload(false); - stopOffload(true); // balance out initOffload(true) } // Check that calling stopOffload() without first having called initOffload() returns false. TEST_F(OffloadControlHidlTestBase, MultipleStopsWithoutInitReturnFalse) { - stopOffload(false); - stopOffload(false); - stopOffload(false); + stopOffload(ExpectBoolean::False); + stopOffload(ExpectBoolean::False); + stopOffload(ExpectBoolean::False); } // Check that calling stopOffload() after a complete init/stop cycle returns false. TEST_F(OffloadControlHidlTestBase, AdditionalStopsWithInitReturnFalse) { initOffload(true); - stopOffload(true); // balance out initOffload(true) - stopOffload(false); - stopOffload(false); + // Call setUpstreamParameters() so that "offload" can be reasonably said + // to be both requested and operational. + const hidl_string v4Addr("192.0.0.2"); + const hidl_string v4Gw("192.0.0.1"); + const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1"), hidl_string("fe80::db8:2")}; + const Return<void> upstream = + control->setUpstreamParameters("rmnet_data0", v4Addr, v4Gw, v6Gws, ASSERT_TRUE_CALLBACK); + EXPECT_TRUE(upstream.isOk()); + stopOffload(ExpectBoolean::True); // balance out initOffload(true) + stopOffload(ExpectBoolean::False); + stopOffload(ExpectBoolean::False); } // Check that calling setLocalPrefixes() without first having called initOffload() returns false. @@ -305,7 +334,12 @@ class OffloadControlHidlTest : public OffloadControlHidlTestBase { setupControlHal(); } - virtual void TearDown() override { stopOffload(true); } + virtual void TearDown() override { + // For good measure, we should try stopOffload() once more. Since we + // don't know where we are in HAL call test cycle we don't know what + // return code to actually expect, so we just ignore it. + stopOffload(ExpectBoolean::Ignored); + } }; /* @@ -575,16 +609,24 @@ TEST_F(OffloadControlHidlTest, AddDownstreamBogusPrefixFails) { TEST_F(OffloadControlHidlTest, RemoveDownstreamIPv4) { const hidl_string iface("dummy0"); const hidl_string prefix("192.0.2.0/24"); - const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_TRUE_CALLBACK); - EXPECT_TRUE(ret.isOk()); + // First add the downstream, otherwise removeDownstream logic can reasonably + // return false for downstreams not previously added. + const Return<void> add = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK); + EXPECT_TRUE(add.isOk()); + const Return<void> del = control->removeDownstream(iface, prefix, ASSERT_TRUE_CALLBACK); + EXPECT_TRUE(del.isOk()); } // Test removeDownstream() works given an IPv6 prefix. TEST_F(OffloadControlHidlTest, RemoveDownstreamIPv6) { const hidl_string iface("dummy0"); const hidl_string prefix("2001:db8::/64"); - const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_TRUE_CALLBACK); - EXPECT_TRUE(ret.isOk()); + // First add the downstream, otherwise removeDownstream logic can reasonably + // return false for downstreams not previously added. + const Return<void> add = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK); + EXPECT_TRUE(add.isOk()); + const Return<void> del = control->removeDownstream(iface, prefix, ASSERT_TRUE_CALLBACK); + EXPECT_TRUE(del.isOk()); } // Test removeDownstream() fails given all empty parameters. diff --git a/thermal/1.1/Android.bp b/thermal/1.1/Android.bp new file mode 100644 index 0000000000..0985d947b6 --- /dev/null +++ b/thermal/1.1/Android.bp @@ -0,0 +1,71 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.thermal@1.1_hal", + srcs: [ + "IThermal.hal", + "IThermalCallback.hal", + ], +} + +genrule { + name: "android.hardware.thermal@1.1_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.thermal@1.1", + srcs: [ + ":android.hardware.thermal@1.1_hal", + ], + out: [ + "android/hardware/thermal/1.1/ThermalAll.cpp", + "android/hardware/thermal/1.1/ThermalCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.thermal@1.1_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.thermal@1.1", + srcs: [ + ":android.hardware.thermal@1.1_hal", + ], + out: [ + "android/hardware/thermal/1.1/IThermal.h", + "android/hardware/thermal/1.1/IHwThermal.h", + "android/hardware/thermal/1.1/BnHwThermal.h", + "android/hardware/thermal/1.1/BpHwThermal.h", + "android/hardware/thermal/1.1/BsThermal.h", + "android/hardware/thermal/1.1/IThermalCallback.h", + "android/hardware/thermal/1.1/IHwThermalCallback.h", + "android/hardware/thermal/1.1/BnHwThermalCallback.h", + "android/hardware/thermal/1.1/BpHwThermalCallback.h", + "android/hardware/thermal/1.1/BsThermalCallback.h", + ], +} + +cc_library { + name: "android.hardware.thermal@1.1", + defaults: ["hidl-module-defaults"], + generated_sources: ["android.hardware.thermal@1.1_genc++"], + generated_headers: ["android.hardware.thermal@1.1_genc++_headers"], + export_generated_headers: ["android.hardware.thermal@1.1_genc++_headers"], + vendor_available: true, + vndk: { + enabled: true, + }, + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.thermal@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.thermal@1.0", + ], +} diff --git a/thermal/1.1/Android.mk b/thermal/1.1/Android.mk new file mode 100644 index 0000000000..059ac8bde7 --- /dev/null +++ b/thermal/1.1/Android.mk @@ -0,0 +1,65 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.thermal-V1.1-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hardware.thermal-V1.0-java \ + android.hidl.base-V1.0-java \ + +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES += core-oj hwbinder + +# +# Build IThermal.hal +# +GEN := $(intermediates)/android/hardware/thermal/V1_1/IThermal.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IThermal.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IThermalCallback.hal +$(GEN): $(LOCAL_PATH)/IThermalCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.1::IThermal + +$(GEN): $(LOCAL_PATH)/IThermal.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IThermalCallback.hal +# +GEN := $(intermediates)/android/hardware/thermal/V1_1/IThermalCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IThermalCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.1::IThermalCallback + +$(GEN): $(LOCAL_PATH)/IThermalCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/thermal/1.1/IThermal.hal b/thermal/1.1/IThermal.hal new file mode 100644 index 0000000000..14f35baa00 --- /dev/null +++ b/thermal/1.1/IThermal.hal @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.thermal@1.1; + +import android.hardware.thermal@1.0::IThermal; +import IThermalCallback; + +interface IThermal extends @1.0::IThermal { + /** + * Register an IThermalCallback, used by the Thermal HAL + * to send thermal events to the framework thermal service. + * + * @param callback the IThermalCallback to use for sending + * thermal events, or nullptr to set no callback + */ + registerThermalCallback(IThermalCallback callback); +}; diff --git a/thermal/1.1/IThermalCallback.hal b/thermal/1.1/IThermalCallback.hal new file mode 100644 index 0000000000..f418ec3dd4 --- /dev/null +++ b/thermal/1.1/IThermalCallback.hal @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.thermal@1.1; + +import android.hardware.thermal@1.0::Temperature; + +/** + * IThermalCallback connects vendor code to the framework binder ThermalService. + */ +interface IThermalCallback { + /** + * Send a thermal throttling start/stop event to all ThermalService + * thermal event listeners. + * @param isThrottling true if device is currently throttling + * @param temperature The temperature associated with the throttling + * start/stop event + */ + oneway notifyThrottling(bool isThrottling, Temperature temperature); +}; diff --git a/thermal/1.1/vts/functional/Android.bp b/thermal/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..f5f01faf2c --- /dev/null +++ b/thermal/1.1/vts/functional/Android.bp @@ -0,0 +1,26 @@ +// +// 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. +// + +cc_test { + name: "VtsHalThermalV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalThermalV1_1TargetTest.cpp"], + static_libs: [ + "android.hardware.thermal@1.0", + "android.hardware.thermal@1.1", + ], +} + diff --git a/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp new file mode 100644 index 0000000000..6c1599bdb2 --- /dev/null +++ b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/hardware/thermal/1.1/IThermal.h> +#include <android/hardware/thermal/1.1/IThermalCallback.h> +#include <android/hardware/thermal/1.0/types.h> + +#include <VtsHalHidlTargetCallbackBase.h> +#include <VtsHalHidlTargetTestBase.h> + +using ::android::hardware::thermal::V1_0::Temperature; +using ::android::hardware::thermal::V1_0::TemperatureType; +using ::android::hardware::thermal::V1_1::IThermal; +using ::android::hardware::thermal::V1_1::IThermalCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +constexpr char kCallbackNameNotifyThrottling[] = "notifyThrottling"; +static const Temperature kThrottleTemp = { + .type = TemperatureType::CPU, + .name = "test temperature sensor", + .currentValue = 98.6, + .throttlingThreshold = 58, + .shutdownThreshold = 60, + .vrThrottlingThreshold = 59, +}; + +class ThermalCallbackArgs { + public: + bool isThrottling; + Temperature temperature; +}; + +// Callback class for receiving thermal event notifications from main class +class ThermalCallback + : public ::testing::VtsHalHidlTargetCallbackBase<ThermalCallbackArgs>, + public IThermalCallback { + public: + virtual ~ThermalCallback() = default; + + Return<void> notifyThrottling(bool isThrottling, + const Temperature& temperature) override { + ThermalCallbackArgs args; + args.isThrottling = isThrottling; + args.temperature = temperature; + NotifyFromCallback(kCallbackNameNotifyThrottling, args); + return Void(); + } +}; + +// The main test class for THERMAL HIDL HAL 1.1. +class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(); + ASSERT_NE(mThermal, nullptr); + mThermalCallback = new(std::nothrow) ThermalCallback(); + ASSERT_NE(mThermalCallback, nullptr); + auto ret = mThermal->registerThermalCallback(mThermalCallback); + ASSERT_TRUE(ret.isOk()); + } + + virtual void TearDown() override { + auto ret = mThermal->registerThermalCallback(nullptr); + ASSERT_TRUE(ret.isOk()); + } + + protected: + sp<IThermal> mThermal; + sp<ThermalCallback> mThermalCallback; +}; // class ThermalHidlTest + +// Test ThermalCallback::notifyThrottling(). +// This just calls into and back from our local ThermalCallback impl. +// Note: a real thermal throttling event from the Thermal HAL could be +// inadvertently received here. +TEST_F(ThermalHidlTest, NotifyThrottlingTest) { + auto ret = mThermalCallback->notifyThrottling(true, kThrottleTemp); + ASSERT_TRUE(ret.isOk()); + auto res = mThermalCallback->WaitForCallback(kCallbackNameNotifyThrottling); + EXPECT_TRUE(res.no_timeout); + ASSERT_TRUE(res.args); + EXPECT_EQ(true, res.args->isThrottling); + EXPECT_EQ(kThrottleTemp, res.args->temperature); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + cout << "Test result = " << status << std::endl; + return status; +} diff --git a/thermal/Android.bp b/thermal/Android.bp index ed19a37034..a5415df348 100644 --- a/thermal/Android.bp +++ b/thermal/Android.bp @@ -3,4 +3,6 @@ subdirs = [ "1.0", "1.0/default", "1.0/vts/functional", + "1.1", + "1.1/vts/functional", ] diff --git a/usb/1.1/vts/functional/Android.bp b/usb/1.1/vts/functional/Android.bp index 820f794bfc..4bb3203695 100644 --- a/usb/1.1/vts/functional/Android.bp +++ b/usb/1.1/vts/functional/Android.bp @@ -16,23 +16,11 @@ cc_test { name: "VtsHalUsbV1_1TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalUsbV1_1TargetTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", + static_libs: [ "android.hardware.usb@1.0", "android.hardware.usb@1.1", ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], } diff --git a/vibrator/1.1/vts/functional/Android.bp b/vibrator/1.1/vts/functional/Android.bp index 5baa8ed74a..4f6454b6c1 100644 --- a/vibrator/1.1/vts/functional/Android.bp +++ b/vibrator/1.1/vts/functional/Android.bp @@ -16,19 +16,11 @@ cc_test { name: "VtsHalVibratorV1_1TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalVibratorV1_1TargetTest.cpp"], - shared_libs: [ - "libbase", - "libhidlbase", - "liblog", - "libutils", + static_libs: [ + "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], } diff --git a/weaver/1.0/vts/functional/Android.bp b/weaver/1.0/vts/functional/Android.bp index 9b0ff6df31..0089d89053 100644 --- a/weaver/1.0/vts/functional/Android.bp +++ b/weaver/1.0/vts/functional/Android.bp @@ -16,21 +16,7 @@ cc_test { name: "VtsHalWeaverV1_0TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalWeaverV1_0TargetTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", - "android.hardware.weaver@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], + static_libs: ["android.hardware.weaver@1.0"], } diff --git a/wifi/1.0/README-NAN.md b/wifi/1.0/README-NAN.md new file mode 100644 index 0000000000..f4b3320e33 --- /dev/null +++ b/wifi/1.0/README-NAN.md @@ -0,0 +1,221 @@ +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. + +# Wi-Fi Aware (NAN) HAL API Usage + +The Wi-Fi Aware (NAN) HAL API is defined in (<i>hardware/interfaces/wifi/\<version\>/</i>): + +* IWifiNanIface.hal +* IWifiNanIfaceEventCallback.hal +* types.hal (structure definitions) + +The Wi-Fi Aware (NAN) HAL API surface is very large - only a subset is used from the framework. + +Understanding of the HAL API subset which is actively used by the Android framework can be deduced +by reviewing framework code, specifically (<i>frameworks/opt/net/wif/</i>): + +* WifiAwareNativeApi.java +* WifiAwareNativeCallback.java + +The above framework files determine the API usage - and should be consulted as the authoritative +reference. Please consult the primary HAL file for documentation - they will not be replicated +in this document. APIs which are in the HAL but are not listed in this README file are not used by +the framework. + +Note: the HAL API is translated to the legacy HAL API (<i>wifi_nan.h</i>). This README file covers +the new HAL API only. To understand the mapping between new and legacy HALs please consult +<i>hardware/interfaces/wifi/\<version\>/default/hidl_struct_util.cpp</i>. + +## IWifiNanIface + +Format: +* Hard-coded values are in <b>bold</b>, e.g. <b>true</b> or <b>5</b> +* Assigned but not fixed value are specified using the <i>variable</i> keyword, possibly with some +details/constraints +* Unassigned values are specified using the <i>N/A</i> keyword. Unassigned usually means initialized +to 0. + +APIs: + +* registerEventCallback(IWifiNanIfaceEventCallback callback) +* getCapabilitiesRequest +* enableRequest + * NanEnableRequest + * bool[2] operateInBand + * Index [NanBandIndex.NAN_BAND_24GHZ] = <b>true</b> + * Index [NanBandIndex.NAN_BAND_5GHZ] = <i>variable</i> + * uint8_t hopCountMax = <b>2</b> + * NanConfigRequest configParams + * uint8_t masterPref = <i>variable</i> + * bool disableDiscoveryAddressChangeIndication = <i>variable</i> + * bool disableStartedClusterIndication = <i>variable</i> + * bool disableJoinedClusterIndication = <i>variable</i> + * bool includePublishServiceIdsInBeacon = <b>true</b> + * uint8_t numberOfPublishServiceIdsInBeacon = <b>0</b> + * bool includeSubscribeServiceIdsInBeacon = <b>true</b> + * uint8_t numberOfSubscribeServiceIdsInBeacon = <b>0</b> + * uint16_t rssiWindowSize = <b>8</b> + * uint32_t macAddressRandomizationIntervalSec = <i>variable</i> + * Normal run-time: set to <b>1800</b> (30 minutes) + * Tests: set to <b>120</b> (2 minutes) + * NanBandSpecificConfig[2] bandSpecificConfig + * Index [NanBandIndex.NAN_BAND_24GHZ] + * uint8_t rssiClose = <b>60</b> + * uint8_t rssiMiddle = <b>70</b> + * uint8_t rssiCloseProximity = <b>60</b> + * uint8_t dwellTimeMs = <b>200</b> + * uint16_t scanPeriodSec = <b>20</b> + * bool validDiscoveryWindowIntervalVal = <i>variable</i> + * uint8_t discoveryWindowIntervalVal = <i>variable</i> + * Index [NanBandIndex.NAN_BAND_5GHZ] + * uint8_t rssiClose = <b>60</b> + * uint8_t rssiMiddle = <b>75</b> + * uint8_t rssiCloseProximity = <b>60</b> + * uint8_t dwellTimeMs = <b>200</b> + * uint16_t scanPeriodSec = <b>20</b> + * bool validDiscoveryWindowIntervalVal = <i>variable</i> + * uint8_t discoveryWindowIntervalVal = <i>variable</i> + * NanDebugConfig debugConfigs + * bool validClusterIdVals = <b>true</b> + * uint16_t clusterIdBottomRangeVal = <i>variable</i> + * uint16_t clusterIdTopRangeVal = <i>variable</i> + * bool validIntfAddrVal = <b>false</b> + * MacAddress intfAddrVal = <i>N/A</i> + * bool validOuiVal = <b>false</b> + * uint32_t ouiVal = <i>N/A</i> + * bool validRandomFactorForceVal = <b>false</b> + * uint8_t randomFactorForceVal = <i>N/A</i> + * bool validHopCountForceVal = <b>false</b> + * uint8_t hopCountForceVal = <i>N/A</i> + * bool validDiscoveryChannelVal = <b>false</b> + * WifiChannelInMhz[2] discoveryChannelMhzVal = <i>N/A</i> + * bool validUseBeaconsInBandVal = <b>false</b> + * bool[2] useBeaconsInBandVal = <i>N/A</i> + * bool validUseSdfInBandVal = <b>false</b> + * bool[2] useSdfInBandVal = <i>N/A</i> +* configRequest + * NanConfigRequest: same as for <i>enableRequest</i> +* disableRequest +* startPublishRequest + * NanPublishRequest + * NanDiscoveryCommonConfig baseConfigs + * uint8_t sessionId = <i>variable</i> + * uint16_t ttlSec = <i>variable</i> + * uint16_t discoveryWindowPeriod = <b>1</b> + * uint8_t discoveryCount = <b>0</b> + * vec<uint8_t> serviceName = <i>variable</i> + * NanMatchAlg discoveryMatchIndicator = <b>NanMatchAlg.MATCH_NEVER</b> + * vec<uint8_t> serviceSpecificInfo = <i>variable</i> + * vec<uint8_t> extendedServiceSpecificInfo = <i>N/A</i> + * vec<uint8_t> rxMatchFilter = <i>variable</i> + * vec<uint8_t> txMatchFilter = <i>variable</i> + * bool useRssiThreshold = <b>false</b> + * bool disableDiscoveryTerminationIndication = <i>variable</i> + * bool disableMatchExpirationIndication = <b>true</b> + * bool disableFollowupReceivedIndication = <b>false</b> + * NanDataPathSecurityConfig securityConfig = <b>NanDataPathSecurityType.OPEN</b> + * bool rangingRequired = <b>false</b> + * uint32_t rangingIntervalMsec = <i>N/A</i> + * bitfield<NanRangingIndication> configRangingIndications = <i>N/A</i> + * uint16_t distanceIngressCm = <i>N/A</i> + * uint16_t distanceEgressCm = <i>N/A</i> + * NanPublishType publishType = <i>variable</i> + * NanTxType txType = <b>NanTxType.BROADCAST</b> + * bool autoAcceptDataPathRequests = <b>false</b> +* stopPublishRequest +* startSubscribeRequest + * NanSubscribeRequest + * NanDiscoveryCommonConfig baseConfigs + * Mostly same as <i>publish</i> above except: + * NanMatchAlg discoveryMatchIndicator = <b>NanMatchAlg.MATCH_ONCE</b> + * NanSubscribeType subscribeType = <i>variable</i> + * NanSrfType srfType = <i>N/A</i> + * bool srfRespondIfInAddressSet = <i>N/A</i> + * bool shouldUseSrf = <i>N/A</i> + * bool isSsiRequiredForMatch = <i>N/A</i> + * vec<MacAddress> intfAddr = <i>N/A</i> +* stopSubscribeRequest +* transmitFollowupRequest + * NanTransmitFollowupRequest + * uint8_t discoverySessionId = <i>variable</i> + * uint32_t peerId = <i>variable</i> + * MacAddress addr = <i>variable</i> + * bool isHighPriority = <b>false</b> + * bool shouldUseDiscoveryWindow = <b>true</b> + * vec<uint8_t> serviceSpecificInfo = <i>variable</i> + * vec<uint8_t> extendedServiceSpecificInfo = <i>N/A</i> + * bool disableFollowupResultIndication = <b>false</b> +* createDataInterfaceRequest +* deleteDataInterfaceRequest +* initiateDataPathRequest + * NanInitiateDataPathRequest + * uint32_t peerId = <i>variable</i> + * MacAddress peerDiscMacAddr = <i>variable</i> + * NanDataPathChannelCfg channelRequestType = + <i>NanDataPathChannelCfg.CHANNEL_NOT_REQUESTED</i> + * WifiChannelInMhz channel = <b>2437</b> (note that should be ignored though - + CHANNEL_NOT_REQUESTED!) + * string ifaceName = <i>variable</i> + * NanDataPathSecurityConfig securityConfig = <i>variable</i> + * vec<uint8_t> appInfo = <i>N/A</i> + * vec<uint8_t> serviceNameOutOfBand = <i>variable</i> +* respondToDataPathIndicationRequest + * NanRespondToDataPathIndicationRequest + * bool acceptRequest = <i>variable</i> + * uint32_t ndpInstanceId = <i>variable</i> + * string ifaceName = <i>variable</i> + * NanDataPathSecurityConfig securityConfig = <i>variable</i> + * vec<uint8_t> appInfo = <i>N/A</i> + * vec<uint8_t> serviceNameOutOfBand = <i>variable</i> +* terminateDataPathRequest + +## IWifiNanIfaceEventCallback + +Format: +* Parameters whose values are <i>ignored</i> will be flagged, otherwise the parameter value is used +by the framework. + +API: + +* notifyXxxResponse: all callbacks are used by framework +* eventClusterEvent +* eventDisabled +* eventPublishTerminated +* eventSubscribeTerminated +* eventMatch + * NanMatchInd (all parameters are used except those listed below) + * vec<uint8_t> extendedServiceSpecificInfo: <i>ignored</i> + * bool matchOccuredInBeaconFlag: <i>ignored</i> + * bool outOfResourceFlag: <i>ignored</i> + * uint8_t rssiValue: <i>ignored</i> + * NanCipherSuiteType peerCipherType: <i>ignored</i> + * bool peerRequiresSecurityEnabledInNdp: <i>ignored</i> + * bool peerRequiresRanging: <i>ignored</i> + * uint32_t rangingMeasurementInCm: <i>ignored</i> + * bitfield<NanRangingIndication> rangingIndicationType: <i>ignored</i> +* eventMatchExpired: <i>ignored</i> +* eventFollowupReceived + * NanFollowupReceivedInd (all parameters are used except those listed below) + * bool receivedInFaw: <i>ignored</i> + * vec<uint8_t> extendedServiceSpecificInfo: <i>ignored</i> +* eventTransmitFollowup +* eventDataPathRequest + * NanDataPathRequestInd (all parameters are used except those listed below) + * bool securityRequired: <i>ignored</i> + * vec<uint8_t> appInfo: <i>ignored</i> +* eventDataPathConfirm + * NanDataPathConfirmInd (all parameters are used except those listed below) + * vec<uint8_t> appInfo: <i>ignored</i> +* eventDataPathTerminated + diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal index 1b5f8f7dad..b9fb0bded9 100644 --- a/wifi/1.0/types.hal +++ b/wifi/1.0/types.hal @@ -1355,8 +1355,8 @@ struct NanCapabilities { */ uint32_t maxNdiInterfaces; /** - * Maximum number of data paths (NDP) which can be created concurrently on each individual - * data interface (NDI). + * Maximum number of data paths (NDP) which can be created concurrently on the device, across all + * data interfaces (NDI). */ uint32_t maxNdpSessions; /** diff --git a/wifi/1.1/default/OWNERS b/wifi/1.1/default/OWNERS new file mode 100644 index 0000000000..2878acc7fd --- /dev/null +++ b/wifi/1.1/default/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +quiche@google.com diff --git a/wifi/1.1/default/hidl_return_util.h b/wifi/1.1/default/hidl_return_util.h index 2f95c23d7e..f36c8bda8a 100644 --- a/wifi/1.1/default/hidl_return_util.h +++ b/wifi/1.1/default/hidl_return_util.h @@ -55,6 +55,25 @@ Return<void> validateAndCall( return Void(); } +// Use for HIDL methods which return only an instance of WifiStatus. +// This version passes the global lock acquired to the body of the method. +// Note: Only used by IWifi::stop() currently. +template <typename ObjT, typename WorkFuncT, typename... Args> +Return<void> validateAndCallWithLock( + ObjT* obj, + WifiStatusCode status_code_if_invalid, + WorkFuncT&& work, + const std::function<void(const WifiStatus&)>& hidl_cb, + Args&&... args) { + auto lock = hidl_sync_util::acquireGlobalLock(); + if (obj->isValid()) { + hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...)); + } else { + hidl_cb(createWifiStatus(status_code_if_invalid)); + } + return Void(); +} + // Use for HIDL methods which return instance of WifiStatus and a single return // value. template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args> diff --git a/wifi/1.1/default/wifi.cpp b/wifi/1.1/default/wifi.cpp index 8456b90e9f..c46ef950e9 100644 --- a/wifi/1.1/default/wifi.cpp +++ b/wifi/1.1/default/wifi.cpp @@ -31,6 +31,7 @@ namespace wifi { namespace V1_1 { namespace implementation { using hidl_return_util::validateAndCall; +using hidl_return_util::validateAndCallWithLock; Wifi::Wifi() : legacy_hal_(new legacy_hal::WifiLegacyHal()), @@ -64,8 +65,8 @@ Return<void> Wifi::start(start_cb hidl_status_cb) { } Return<void> Wifi::stop(stop_cb hidl_status_cb) { - return validateAndCall( - this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::stopInternal, hidl_status_cb); + return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN, + &Wifi::stopInternal, hidl_status_cb); } Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) { @@ -120,7 +121,8 @@ WifiStatus Wifi::startInternal() { return wifi_status; } -WifiStatus Wifi::stopInternal() { +WifiStatus Wifi::stopInternal( + /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) { if (run_state_ == RunState::STOPPED) { return createWifiStatus(WifiStatusCode::SUCCESS); } else if (run_state_ == RunState::STOPPING) { @@ -133,7 +135,7 @@ WifiStatus Wifi::stopInternal() { chip_->invalidate(); chip_.clear(); } - WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(); + WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock); if (wifi_status.code == WifiStatusCode::SUCCESS) { for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onStop().isOk()) { @@ -180,11 +182,11 @@ WifiStatus Wifi::initializeLegacyHal() { return createWifiStatus(WifiStatusCode::SUCCESS); } -WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController() { +WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController( + /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) { run_state_ = RunState::STOPPING; - const auto on_complete_callback_ = [&]() { run_state_ = RunState::STOPPED; }; legacy_hal::wifi_error legacy_status = - legacy_hal_->stop(on_complete_callback_); + legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; }); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to stop legacy HAL: " << legacyErrorToString(legacy_status); diff --git a/wifi/1.1/default/wifi.h b/wifi/1.1/default/wifi.h index 1ade2d8b9b..3a64cbd490 100644 --- a/wifi/1.1/default/wifi.h +++ b/wifi/1.1/default/wifi.h @@ -61,12 +61,13 @@ class Wifi : public V1_1::IWifi { WifiStatus registerEventCallbackInternal( const sp<IWifiEventCallback>& event_callback); WifiStatus startInternal(); - WifiStatus stopInternal(); + WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock); std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal(); std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id); WifiStatus initializeLegacyHal(); - WifiStatus stopLegacyHalAndDeinitializeModeController(); + WifiStatus stopLegacyHalAndDeinitializeModeController( + std::unique_lock<std::recursive_mutex>* lock); // Instance is created in this root level |IWifi| HIDL interface object // and shared with all the child HIDL interface objects. diff --git a/wifi/1.1/default/wifi_legacy_hal.cpp b/wifi/1.1/default/wifi_legacy_hal.cpp index 7d683d3fe9..36da6e5351 100644 --- a/wifi/1.1/default/wifi_legacy_hal.cpp +++ b/wifi/1.1/default/wifi_legacy_hal.cpp @@ -15,6 +15,7 @@ */ #include <array> +#include <chrono> #include <android-base/logging.h> #include <cutils/properties.h> @@ -34,6 +35,7 @@ static constexpr uint32_t kMaxGscanFrequenciesForBand = 64; static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128; static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32; static constexpr uint32_t kMaxRingBuffers = 10; +static constexpr uint32_t kMaxStopCompleteWaitMs = 100; // Helper function to create a non-const char* for legacy Hal API's. std::vector<char> makeCharVec(const std::string& str) { @@ -53,7 +55,8 @@ namespace legacy_hal { // Legacy HAL functions accept "C" style function pointers, so use global // functions to pass to the legacy HAL function and store the corresponding // std::function methods to be invoked. -// Callback to be invoked once |stop| is complete. +// +// Callback to be invoked once |stop| is complete std::function<void(wifi_handle handle)> on_stop_complete_internal_callback; void onAsyncStopComplete(wifi_handle handle) { const auto lock = hidl_sync_util::acquireGlobalLock(); @@ -369,6 +372,7 @@ wifi_error WifiLegacyHal::start() { } wifi_error WifiLegacyHal::stop( + /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, const std::function<void()>& on_stop_complete_user_callback) { if (!is_started_) { LOG(DEBUG) << "Legacy HAL already stopped"; @@ -376,19 +380,27 @@ wifi_error WifiLegacyHal::stop( return WIFI_SUCCESS; } LOG(DEBUG) << "Stopping legacy HAL"; - on_stop_complete_internal_callback = [on_stop_complete_user_callback, - this](wifi_handle handle) { + on_stop_complete_internal_callback = + [on_stop_complete_user_callback, this](wifi_handle handle) { CHECK_EQ(global_handle_, handle) << "Handle mismatch"; + LOG(INFO) << "Legacy HAL stop complete callback received"; // Invalidate all the internal pointers now that the HAL is // stopped. invalidate(); iface_tool_.SetWifiUpState(false); on_stop_complete_user_callback(); + is_started_ = false; }; awaiting_event_loop_termination_ = true; global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete); + const auto status = stop_wait_cv_.wait_for( + *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs), + [this] { return !awaiting_event_loop_termination_; }); + if (!status) { + LOG(ERROR) << "Legacy HAL stop failed or timed out"; + return WIFI_ERROR_UNKNOWN; + } LOG(DEBUG) << "Legacy HAL stop complete"; - is_started_ = false; return WIFI_SUCCESS; } @@ -1257,11 +1269,13 @@ wifi_error WifiLegacyHal::retrieveWlanInterfaceHandle() { void WifiLegacyHal::runEventLoop() { LOG(DEBUG) << "Starting legacy HAL event loop"; global_func_table_.wifi_event_loop(global_handle_); + const auto lock = hidl_sync_util::acquireGlobalLock(); if (!awaiting_event_loop_termination_) { LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping"; } LOG(DEBUG) << "Legacy HAL event loop terminated"; awaiting_event_loop_termination_ = false; + stop_wait_cv_.notify_one(); } std::pair<wifi_error, std::vector<wifi_cached_scan_results>> @@ -1284,7 +1298,7 @@ WifiLegacyHal::getGscanCachedResults() { for (int i = 0; i < num_scan_results; i++) { auto& scan_result = cached_scan_result.results[i]; if (scan_result.ie_length > 0) { - LOG(ERROR) << "Cached scan result has non-zero IE length " + LOG(DEBUG) << "Cached scan result has non-zero IE length " << scan_result.ie_length; scan_result.ie_length = 0; } diff --git a/wifi/1.1/default/wifi_legacy_hal.h b/wifi/1.1/default/wifi_legacy_hal.h index caa1bd50fc..549880398f 100644 --- a/wifi/1.1/default/wifi_legacy_hal.h +++ b/wifi/1.1/default/wifi_legacy_hal.h @@ -20,6 +20,7 @@ #include <functional> #include <thread> #include <vector> +#include <condition_variable> #include <wifi_system/interface_tool.h> @@ -149,8 +150,10 @@ class WifiLegacyHal { wifi_error initialize(); // Start the legacy HAL and the event looper thread. wifi_error start(); - // Deinitialize the legacy HAL and stop the event looper thread. - wifi_error stop(const std::function<void()>& on_complete_callback); + // Deinitialize the legacy HAL and wait for the event loop thread to exit + // using a predefined timeout. + wifi_error stop(std::unique_lock<std::recursive_mutex>* lock, + const std::function<void()>& on_complete_callback); // Wrappers for all the functions in the legacy HAL function table. std::pair<wifi_error, std::string> getDriverVersion(); std::pair<wifi_error, std::string> getFirmwareVersion(); @@ -293,6 +296,7 @@ class WifiLegacyHal { wifi_interface_handle wlan_interface_handle_; // Flag to indicate if we have initiated the cleanup of legacy HAL. std::atomic<bool> awaiting_event_loop_termination_; + std::condition_variable_any stop_wait_cv_; // Flag to indicate if the legacy HAL has been started. bool is_started_; wifi_system::InterfaceTool iface_tool_; diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp index 6b0baf7851..1b0c12d68b 100644 --- a/wifi/1.1/vts/functional/Android.bp +++ b/wifi/1.1/vts/functional/Android.bp @@ -16,24 +16,13 @@ cc_test { name: "VtsHalWifiV1_1TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: [ "VtsHalWifiV1_1TargetTest.cpp", "wifi_chip_hidl_test.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", "android.hardware.wifi@1.1", ], - static_libs: ["VtsHalWifiV1_0TargetTestUtil", "VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], } diff --git a/wifi/1.1/vts/functional/OWNERS b/wifi/1.1/vts/functional/OWNERS new file mode 100644 index 0000000000..2878acc7fd --- /dev/null +++ b/wifi/1.1/vts/functional/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +quiche@google.com diff --git a/wifi/Android.bp b/wifi/Android.bp index b4ab98ffef..1153b0c628 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -7,4 +7,5 @@ subdirs = [ "offload/1.0", "offload/1.0/vts/functional", "supplicant/1.0", + "supplicant/1.0/vts/functional", ] diff --git a/wifi/offload/1.0/vts/functional/Android.bp b/wifi/offload/1.0/vts/functional/Android.bp index f907a89559..140e45e2d3 100644 --- a/wifi/offload/1.0/vts/functional/Android.bp +++ b/wifi/offload/1.0/vts/functional/Android.bp @@ -16,21 +16,7 @@ cc_test { name: "VtsHalWifiOffloadV1_0TargetTest", - defaults: ["hidl_defaults"], + defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalWifiOffloadV1_0TargetTest.cpp"], - shared_libs: [ - "libbase", - "liblog", - "libcutils", - "libhidlbase", - "libhidltransport", - "libnativehelper", - "libutils", - "android.hardware.wifi.offload@1.0", - ], - static_libs: ["VtsHalHidlTargetTestBase"], - cflags: [ - "-O0", - "-g", - ], + static_libs: ["android.hardware.wifi.offload@1.0"], } diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..24b9f6f71f --- /dev/null +++ b/wifi/supplicant/1.0/vts/functional/Android.bp @@ -0,0 +1,37 @@ +// +// 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. +// + +cc_test { + name: "VtsHalWifiSupplicantV1_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiSupplicantV1_0TargetTest.cpp", + "supplicant_hidl_test.cpp", + "supplicant_hidl_test_utils.cpp", + "supplicant_p2p_iface_hidl_test.cpp", + "supplicant_sta_iface_hidl_test.cpp", + "supplicant_sta_network_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], +} diff --git a/wifi/supplicant/1.0/vts/functional/Android.mk b/wifi/supplicant/1.0/vts/functional/Android.mk deleted file mode 100644 index c6e39503d4..0000000000 --- a/wifi/supplicant/1.0/vts/functional/Android.mk +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (C) 2016 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := VtsHalWifiSupplicantV1_0TargetTest -LOCAL_CPPFLAGS := -Wall -Werror -Wextra -LOCAL_SRC_FILES := \ - VtsHalWifiSupplicantV1_0TargetTest.cpp \ - supplicant_hidl_test.cpp \ - supplicant_hidl_test_utils.cpp \ - supplicant_p2p_iface_hidl_test.cpp \ - supplicant_sta_iface_hidl_test.cpp \ - supplicant_sta_network_hidl_test.cpp -LOCAL_SHARED_LIBRARIES := \ - android.hardware.wifi.supplicant@1.0 \ - android.hardware.wifi@1.0 \ - libbase \ - libcutils \ - libhidlbase \ - libhidltransport \ - liblog \ - libutils \ - libwifi-system \ - libwifi-system-iface -LOCAL_STATIC_LIBRARIES := \ - libgmock \ - VtsHalHidlTargetTestBase \ - VtsHalWifiV1_0TargetTestUtil -include $(BUILD_NATIVE_TEST) - |