DO NOT MERGE: Merge Oreo MR1 into master

Exempt-From-Owner-Approval: Changes already landed internally
Change-Id: I8318c8bcc6ce5e750326b3315710c96a37838f22
This commit is contained in:
Xin Li
2017-12-06 11:52:04 -08:00
284 changed files with 17390 additions and 9556 deletions

View File

@@ -56,4 +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/lib/vndk-sp/android.hardware.graphics.allocator*)
$(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*)

View File

@@ -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">

View File

@@ -88,8 +88,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)

View File

@@ -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;

View File

@@ -346,14 +346,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();
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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",
],
}

View File

@@ -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
}
}
}

View File

@@ -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",

View File

@@ -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",
],
}

View File

@@ -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");
}
}

View File

@@ -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>

View File

@@ -1,7 +1,11 @@
// This file is autogenerated by hidl-gen. Do not edit manually.
// This file is autogenerated by hidl-gen -Landroidbp.
filegroup {
name: "android.hardware.automotive.evs@1.0_hal",
hidl_interface {
name: "android.hardware.automotive.evs@1.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"types.hal",
"IEvsCamera.hal",
@@ -9,160 +13,16 @@ filegroup {
"IEvsDisplay.hal",
"IEvsEnumerator.hal",
],
interfaces: [
"android.hidl.base@1.0",
],
types: [
"BufferDesc",
"CameraDesc",
"DisplayDesc",
"DisplayState",
"EvsResult",
],
gen_java: false,
}
genrule {
name: "android.hardware.automotive.evs@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.automotive.evs@1.0",
srcs: [
":android.hardware.automotive.evs@1.0_hal",
],
out: [
"android/hardware/automotive/evs/1.0/types.cpp",
"android/hardware/automotive/evs/1.0/EvsCameraAll.cpp",
"android/hardware/automotive/evs/1.0/EvsCameraStreamAll.cpp",
"android/hardware/automotive/evs/1.0/EvsDisplayAll.cpp",
"android/hardware/automotive/evs/1.0/EvsEnumeratorAll.cpp",
],
}
genrule {
name: "android.hardware.automotive.evs@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.automotive.evs@1.0",
srcs: [
":android.hardware.automotive.evs@1.0_hal",
],
out: [
"android/hardware/automotive/evs/1.0/types.h",
"android/hardware/automotive/evs/1.0/hwtypes.h",
"android/hardware/automotive/evs/1.0/IEvsCamera.h",
"android/hardware/automotive/evs/1.0/IHwEvsCamera.h",
"android/hardware/automotive/evs/1.0/BnHwEvsCamera.h",
"android/hardware/automotive/evs/1.0/BpHwEvsCamera.h",
"android/hardware/automotive/evs/1.0/BsEvsCamera.h",
"android/hardware/automotive/evs/1.0/IEvsCameraStream.h",
"android/hardware/automotive/evs/1.0/IHwEvsCameraStream.h",
"android/hardware/automotive/evs/1.0/BnHwEvsCameraStream.h",
"android/hardware/automotive/evs/1.0/BpHwEvsCameraStream.h",
"android/hardware/automotive/evs/1.0/BsEvsCameraStream.h",
"android/hardware/automotive/evs/1.0/IEvsDisplay.h",
"android/hardware/automotive/evs/1.0/IHwEvsDisplay.h",
"android/hardware/automotive/evs/1.0/BnHwEvsDisplay.h",
"android/hardware/automotive/evs/1.0/BpHwEvsDisplay.h",
"android/hardware/automotive/evs/1.0/BsEvsDisplay.h",
"android/hardware/automotive/evs/1.0/IEvsEnumerator.h",
"android/hardware/automotive/evs/1.0/IHwEvsEnumerator.h",
"android/hardware/automotive/evs/1.0/BnHwEvsEnumerator.h",
"android/hardware/automotive/evs/1.0/BpHwEvsEnumerator.h",
"android/hardware/automotive/evs/1.0/BsEvsEnumerator.h",
],
}
cc_library {
name: "android.hardware.automotive.evs@1.0",
defaults: ["hidl-module-defaults"],
generated_sources: ["android.hardware.automotive.evs@1.0_genc++"],
generated_headers: ["android.hardware.automotive.evs@1.0_genc++_headers"],
export_generated_headers: ["android.hardware.automotive.evs@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",
],
}
genrule {
name: "android.hardware.automotive.evs@1.0-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.automotive.evs@1.0",
srcs: [
":android.hardware.automotive.evs@1.0_hal",
],
out: [
"android/hardware/automotive/evs/1.0/AEvsCamera.cpp",
"android/hardware/automotive/evs/1.0/AEvsCameraStream.cpp",
"android/hardware/automotive/evs/1.0/AEvsDisplay.cpp",
"android/hardware/automotive/evs/1.0/AEvsEnumerator.cpp",
],
}
genrule {
name: "android.hardware.automotive.evs@1.0-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.automotive.evs@1.0",
srcs: [
":android.hardware.automotive.evs@1.0_hal",
],
out: [
"android/hardware/automotive/evs/1.0/AEvsCamera.h",
"android/hardware/automotive/evs/1.0/AEvsCameraStream.h",
"android/hardware/automotive/evs/1.0/AEvsDisplay.h",
"android/hardware/automotive/evs/1.0/AEvsEnumerator.h",
],
}
cc_library {
name: "android.hardware.automotive.evs@1.0-adapter-helper",
defaults: ["hidl-module-defaults"],
generated_sources: ["android.hardware.automotive.evs@1.0-adapter-helper_genc++"],
generated_headers: ["android.hardware.automotive.evs@1.0-adapter-helper_genc++_headers"],
export_generated_headers: ["android.hardware.automotive.evs@1.0-adapter-helper_genc++_headers"],
vendor_available: true,
shared_libs: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
"libutils",
"libcutils",
"libhidladapter",
"android.hardware.automotive.evs@1.0",
"android.hidl.base@1.0-adapter-helper",
],
export_shared_lib_headers: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"libutils",
"libhidladapter",
"android.hardware.automotive.evs@1.0",
"android.hidl.base@1.0-adapter-helper",
],
}
genrule {
name: "android.hardware.automotive.evs@1.0-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.automotive.evs@1.0",
out: ["main.cpp"]
}
cc_test {
name: "android.hardware.automotive.evs@1.0-adapter",
defaults: ["hidl-module-defaults"],
shared_libs: [
"libhidladapter",
"libhidlbase",
"libhidltransport",
"libutils",
"android.hardware.automotive.evs@1.0",
"android.hardware.automotive.evs@1.0-adapter-helper",
],
generated_sources: ["android.hardware.automotive.evs@1.0-adapter_genc++"],
}

View File

@@ -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",
],
}

View File

@@ -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 -Wall -Werror
include $(BUILD_EXECUTABLE)

View File

@@ -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",
],
}

View File

@@ -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);
}
}

View File

@@ -1,150 +1,85 @@
// This file is autogenerated by hidl-gen. Do not edit manually.
// This file is autogenerated by hidl-gen -Landroidbp.
filegroup {
name: "android.hardware.automotive.vehicle@2.0_hal",
hidl_interface {
name: "android.hardware.automotive.vehicle@2.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"types.hal",
"IVehicle.hal",
"IVehicleCallback.hal",
],
interfaces: [
"android.hidl.base@1.0",
],
types: [
"DiagnosticFloatSensorIndex",
"DiagnosticIntegerSensorIndex",
"Obd2CommonIgnitionMonitors",
"Obd2CompressionIgnitionMonitors",
"Obd2FuelSystemStatus",
"Obd2FuelType",
"Obd2IgnitionMonitorKind",
"Obd2SecondaryAirStatus",
"Obd2SparkIgnitionMonitors",
"StatusCode",
"SubscribeFlags",
"SubscribeOptions",
"VehicleApPowerBootupReason",
"VehicleApPowerSetState",
"VehicleApPowerState",
"VehicleApPowerStateConfigFlag",
"VehicleApPowerStateIndex",
"VehicleApPowerStateShutdownParam",
"VehicleArea",
"VehicleAreaConfig",
"VehicleAreaDoor",
"VehicleAreaMirror",
"VehicleAreaSeat",
"VehicleAreaWindow",
"VehicleAreaZone",
"VehicleAudioContextFlag",
"VehicleAudioExtFocusFlag",
"VehicleAudioFocusIndex",
"VehicleAudioFocusRequest",
"VehicleAudioFocusState",
"VehicleAudioHwVariantConfigFlag",
"VehicleAudioRoutingPolicyIndex",
"VehicleAudioStream",
"VehicleAudioStreamFlag",
"VehicleAudioVolumeCapabilityFlag",
"VehicleAudioVolumeIndex",
"VehicleAudioVolumeLimitIndex",
"VehicleAudioVolumeState",
"VehicleDisplay",
"VehicleDrivingStatus",
"VehicleGear",
"VehicleHvacFanDirection",
"VehicleHwKeyInputAction",
"VehicleIgnitionState",
"VehicleInstrumentClusterType",
"VehiclePropConfig",
"VehiclePropValue",
"VehicleProperty",
"VehiclePropertyAccess",
"VehiclePropertyChangeMode",
"VehiclePropertyGroup",
"VehiclePropertyOperation",
"VehiclePropertyType",
"VehicleRadioConstants",
"VehicleTurnSignal",
"VehicleUnit",
"VmsAvailabilityStateIntegerValuesIndex",
"VmsBaseMessageIntegerValuesIndex",
"VmsMessageType",
"VmsMessageWithLayerAndPublisherIdIntegerValuesIndex",
"VmsMessageWithLayerIntegerValuesIndex",
"VmsOfferingMessageIntegerValuesIndex",
"VmsSubscriptionsStateIntegerValuesIndex",
"Wheel",
],
gen_java: true,
}
genrule {
name: "android.hardware.automotive.vehicle@2.0_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.0",
srcs: [
":android.hardware.automotive.vehicle@2.0_hal",
],
out: [
"android/hardware/automotive/vehicle/2.0/types.cpp",
"android/hardware/automotive/vehicle/2.0/VehicleAll.cpp",
"android/hardware/automotive/vehicle/2.0/VehicleCallbackAll.cpp",
],
}
genrule {
name: "android.hardware.automotive.vehicle@2.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.automotive.vehicle@2.0",
srcs: [
":android.hardware.automotive.vehicle@2.0_hal",
],
out: [
"android/hardware/automotive/vehicle/2.0/types.h",
"android/hardware/automotive/vehicle/2.0/hwtypes.h",
"android/hardware/automotive/vehicle/2.0/IVehicle.h",
"android/hardware/automotive/vehicle/2.0/IHwVehicle.h",
"android/hardware/automotive/vehicle/2.0/BnHwVehicle.h",
"android/hardware/automotive/vehicle/2.0/BpHwVehicle.h",
"android/hardware/automotive/vehicle/2.0/BsVehicle.h",
"android/hardware/automotive/vehicle/2.0/IVehicleCallback.h",
"android/hardware/automotive/vehicle/2.0/IHwVehicleCallback.h",
"android/hardware/automotive/vehicle/2.0/BnHwVehicleCallback.h",
"android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h",
"android/hardware/automotive/vehicle/2.0/BsVehicleCallback.h",
],
}
cc_library {
name: "android.hardware.automotive.vehicle@2.0",
defaults: ["hidl-module-defaults"],
generated_sources: ["android.hardware.automotive.vehicle@2.0_genc++"],
generated_headers: ["android.hardware.automotive.vehicle@2.0_genc++_headers"],
export_generated_headers: ["android.hardware.automotive.vehicle@2.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",
],
}
genrule {
name: "android.hardware.automotive.vehicle@2.0-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.automotive.vehicle@2.0",
srcs: [
":android.hardware.automotive.vehicle@2.0_hal",
],
out: [
"android/hardware/automotive/vehicle/2.0/AVehicle.cpp",
"android/hardware/automotive/vehicle/2.0/AVehicleCallback.cpp",
],
}
genrule {
name: "android.hardware.automotive.vehicle@2.0-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.automotive.vehicle@2.0",
srcs: [
":android.hardware.automotive.vehicle@2.0_hal",
],
out: [
"android/hardware/automotive/vehicle/2.0/AVehicle.h",
"android/hardware/automotive/vehicle/2.0/AVehicleCallback.h",
],
}
cc_library {
name: "android.hardware.automotive.vehicle@2.0-adapter-helper",
defaults: ["hidl-module-defaults"],
generated_sources: ["android.hardware.automotive.vehicle@2.0-adapter-helper_genc++"],
generated_headers: ["android.hardware.automotive.vehicle@2.0-adapter-helper_genc++_headers"],
export_generated_headers: ["android.hardware.automotive.vehicle@2.0-adapter-helper_genc++_headers"],
vendor_available: true,
shared_libs: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
"libutils",
"libcutils",
"libhidladapter",
"android.hardware.automotive.vehicle@2.0",
"android.hidl.base@1.0-adapter-helper",
],
export_shared_lib_headers: [
"libhidlbase",
"libhidltransport",
"libhwbinder",
"libutils",
"libhidladapter",
"android.hardware.automotive.vehicle@2.0",
"android.hidl.base@1.0-adapter-helper",
],
}
genrule {
name: "android.hardware.automotive.vehicle@2.0-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.automotive.vehicle@2.0",
out: ["main.cpp"]
}
cc_test {
name: "android.hardware.automotive.vehicle@2.0-adapter",
defaults: ["hidl-module-defaults"],
shared_libs: [
"libhidladapter",
"libhidlbase",
"libhidltransport",
"libutils",
"android.hardware.automotive.vehicle@2.0",
"android.hardware.automotive.vehicle@2.0-adapter-helper",
],
generated_sources: ["android.hardware.automotive.vehicle@2.0-adapter_genc++"],
}

File diff suppressed because it is too large Load Diff

View File

@@ -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",
],
}

View File

@@ -1,200 +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_CFLAGS := -Wall -Werror
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_CFLAGS := -Wall -Werror
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
LOCAL_CFLAGS += -Wall -Wextra -Werror
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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -70,8 +70,15 @@ private:
void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
bool isContinuousProperty(int32_t propId) const;
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:
/* Private members */
VehiclePropertyStore* mPropStore;
std::unordered_set<int32_t> mHvacPowerProps;
RecurrentTimer mRecurrentTimer;

View File

@@ -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"]
}

File diff suppressed because it is too large Load Diff

View File

@@ -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",
],
}

View File

@@ -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))

View File

@@ -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 {
};

View File

@@ -1,123 +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_CFLAGS := -Wall -Werror
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)

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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,
};

View File

@@ -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;

View File

@@ -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;
};

View File

@@ -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"

View File

@@ -19,6 +19,7 @@
#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <utils/Log.h>
namespace android {

View File

@@ -22,6 +22,7 @@
#include <fcntl.h>
#include <log/log.h>
#include <sys/uio.h>
#include <unistd.h>
namespace android {
namespace hardware {

View File

@@ -21,6 +21,7 @@
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <utils/Log.h>
namespace {

View File

@@ -20,6 +20,7 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <log/log.h>
namespace android {

View File

@@ -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. */
};

View File

@@ -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);
};

View File

@@ -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 {

View File

@@ -20,6 +20,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
@@ -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,22 +116,9 @@ 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.
*
@@ -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);
};

View File

@@ -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);
};

View File

@@ -1 +0,0 @@
This is experimental interface, do not use it yet.

View File

@@ -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: [
"libhidlbase",
"libhidltransport",
"libutils",
"liblog",
"libhardware",
"android.hardware.broadcastradio@1.0",
"android.hardware.broadcastradio@1.1",
"libradio_metadata",
"libbase",
"libhidlbase",
"libhidltransport",
"liblog",
"libutils",
],
}

View File

@@ -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);
Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) {
ALOGV("%s", __func__);
Properties prop11 = {};
auto& prop10 = prop11.base;
mHwDevice = NULL;
const char *classString = Utils::getClassString(mClassId);
if (classString == NULL) {
ALOGE("invalid class ID %d", mClassId);
mStatus = Result::INVALID_ARGUMENTS;
return;
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;
}
}
int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner)
{
ALOGV("%s", __FUNCTION__);
if (mHwDevice == NULL) {
return -ENODEV;
}
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);
}
exit:
_hidl_cb(Utils::convertHalResult(rc), properties);
_hidl_cb(prop11);
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::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);
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);
auto oldTuner = mTuner.promote();
if (oldTuner != nullptr) {
ALOGI("Force-closing previously opened tuner");
oldTuner->forceClose();
mTuner = nullptr;
}
_hidl_cb(Utils::convertHalResult(rc), tunerImpl);
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();
}
}
_hidl_cb(Result::OK, newTuner);
return Void();
}
} // namespace implementation
Return<void> BroadcastRadio::getImage(int32_t id, getImage_cb _hidl_cb) {
ALOGV("%s(%x)", __func__, id);
if (id == resources::demoPngId) {
_hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
return {};
}
ALOGI("Image %x doesn't exists", id);
_hidl_cb({});
return Void();
}
} // namespace implementation
} // namespace V1_1
} // namespace broadcastradio
} // namespace hardware

View File

@@ -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;
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);
// 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);
Result mStatus;
Class mClassId;
struct radio_hw_device *mHwDevice;
private:
std::mutex mMut;
V1_0::Class mClassId;
ModuleConfig mConfig;
wp<Tuner> mTuner;
};
} // namespace implementation

View File

@@ -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();
}
_hidl_cb(retval, impl);
return Void();
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);
}
}
IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) {
return new BroadcastRadioFactory();
Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) {
ALOGV("%s(%s)", __func__, toString(classId).c_str());
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

View File

@@ -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

View File

@@ -0,0 +1,4 @@
# Automotive team
egranata@google.com
keunyoung@google.com
twasilczyk@google.com

View File

@@ -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;
using namespace std::chrono_literals;
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);
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 {};
}
// 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;
}
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;
if (mCallback1_1 == nullptr) {
mCallback->tuneComplete(Result::OK, mCurrentProgramInfo.base);
} else {
mCallback1_1->tuneComplete_1_1(Result::OK, mCurrentProgramInfo.selector);
mCallback1_1->currentProgramInfoChanged(mCurrentProgramInfo);
}
}
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, {});
}
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;
};
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;
}
}
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;
}
//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);
}
Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
ALOGV("%s", __func__);
lock_guard<mutex> lk(mMut);
if (mIsClosed) return Result::NOT_INITIALIZED;
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__);
}
ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel");
Tuner::~Tuner()
{
ALOGV("%s", __FUNCTION__);
const sp<BroadcastRadio> parentDevice = mParentDevice.promote();
if (parentDevice != 0) {
parentDevice->closeHalTuner(mHalTuner);
}
}
// 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);
}
radio_hal_band_config_t halConfig;
Utils::convertBandConfigToHal(&halConfig, &config);
int rc = mHalTuner->set_configuration(mHalTuner, &halConfig);
return Utils::convertHalResult(rc);
}
Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
int rc;
radio_hal_band_config_t halConfig;
BandConfig config;
ALOGV("%s", __FUNCTION__);
if (mHalTuner == NULL) {
rc = -ENODEV;
goto exit;
}
rc = mHalTuner->get_configuration(mHalTuner, &halConfig);
if (rc == 0) {
Utils::convertBandConfigFromHal(&config, &halConfig);
if (!utils::isAmFm(utils::getType(mCurrentProgram))) {
ALOGE("Can't step in anything else than AM/FM");
return Result::NOT_INITIALIZED;
}
exit:
_hidl_cb(Utils::convertHalResult(rc), config);
return Void();
}
Return<Result> Tuner::scan(Direction direction, bool skipSubChannel) {
if (mHalTuner == NULL) {
return Utils::convertHalResult(-ENODEV);
if (!mIsAmfmConfigSet) {
ALOGW("AM/FM config not set");
return Result::INVALID_STATE;
}
int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
return Utils::convertHalResult(rc);
mIsTuneCompleted = false;
auto task = [this, direction]() {
ALOGI("Performing step %s", toString(direction).c_str());
lock_guard<mutex> lk(mMut);
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::step(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->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
return Utils::convertHalResult(rc);
return tuneByProgramSelector(utils::make_selector(band, channel, subChannel));
}
Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
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->tune(mHalTuner, channel, subChannel);
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::cancel() {
if (mHalTuner == NULL) {
return Utils::convertHalResult(-ENODEV);
}
int rc = mHalTuner->cancel(mHalTuner);
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<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
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", __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;
Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
ALOGV("%s", __func__);
lock_guard<mutex> lk(mMut);
ALOGV("%s", __FUNCTION__);
if (mHalTuner == NULL) {
rc = -ENODEV;
goto exit;
if (mIsClosed) {
_hidl_cb(Result::NOT_INITIALIZED, {});
} else if (mIsTuneCompleted) {
_hidl_cb(Result::OK, mCurrentProgramInfo);
} else {
_hidl_cb(Result::NOT_INITIALIZED, makeDummyProgramInfo(mCurrentProgram));
}
rc = mHalTuner->get_program_information(mHalTuner, &halInfo);
if (rc == 0) {
Utils::convertProgramInfoFromHal(&info, &halInfo);
}
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<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<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) {
// TODO(b/34348946): do the actual implementation.
_hidl_cb(Result::INVALID_STATE, false);
return Void();
ALOGV("%s", __func__);
lock_guard<mutex> lk(mMut);
if (mIsClosed) {
_hidl_cb(Result::NOT_INITIALIZED, false);
} else {
_hidl_cb(Result::OK, mIsAnalogForced);
}
return {};
}
Return<Result> Tuner::setAnalogForced(bool isForced __unused) {
// TODO(b/34348946): do the actual implementation.
return Result::INVALID_STATE;
}
} // namespace implementation
} // namespace implementation
} // namespace V1_1
} // namespace broadcastradio
} // namespace hardware

View File

@@ -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);
void forceClose();
// 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;
// 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;
static void callback(radio_hal_event_t *halEvent, void *cookie);
void onCallback(radio_hal_event_t *halEvent);
private:
std::mutex mMut;
WorkerThread mThread;
bool mIsClosed = false;
void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; }
const struct radio_tuner *getHalTuner() { return mHalTuner; }
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,4 @@
service broadcastradio-hal /vendor/bin/hw/android.hardware.broadcastradio@1.1-service
class hal
user audioserver
group audio

View File

@@ -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

View File

@@ -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
}

View File

@@ -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"],
}

View File

@@ -0,0 +1,8 @@
# Automotive team
egranata@google.com
keunyoung@google.com
twasilczyk@google.com
# VTS team
ryanjcampbell@google.com
yim@google.com

View File

@@ -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

View File

@@ -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.
*
* It may be used for extra features, that's not supported by a platform,
* for example: "preset-slots=6;ultra-hd-capable=false".
* If a program type is supported by radio module, it means it can tune
* to ProgramSelector of a given type.
*
* Front-end application MUST verify vendor/product name from the
* @1.0::Properties struct before doing any interpretation of this value.
* Support for VENDOR program type does not guarantee compatibility, as
* other module properties (implementor, product, version) must be checked.
*/
string vendorExension;
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.
*
* The order is meaningful, ie. the first element may be defined as
* frequency, second as the subchannel etc.
*
* The vector is not serialized (either locally or to the cloud),
* unless it's a VENDOR program type.
*/
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.
* Vendor-specific information.
*
* It may be used for extra features, that's not supported by a platform,
* for example: "paid-service=true;bitrate=320kbps".
*
* 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;
};

View File

@@ -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",
],
}

View File

@@ -0,0 +1,4 @@
# Automotive team
egranata@google.com
keunyoung@google.com
twasilczyk@google.com

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,8 @@
# Automotive team
egranata@google.com
keunyoung@google.com
twasilczyk@google.com
# VTS team
ryanjcampbell@google.com
yim@google.com

View File

@@ -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",
],
}

View File

@@ -14,463 +14,527 @@
* limitations under the License.
*/
#define LOG_TAG "BroadcastRadioHidlHalTest"
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/threads.h>
#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.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>
#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 <chrono>
namespace V1_0 = ::android::hardware::broadcastradio::V1_0;
namespace android {
namespace hardware {
namespace broadcastradio {
namespace V1_1 {
namespace vts {
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;
using namespace std::chrono_literals;
using testing::_;
using testing::AnyNumber;
using testing::ByMove;
using testing::DoAll;
using testing::Invoke;
using testing::SaveArg;
// The main test class for Broadcast Radio HIDL HAL.
using broadcastradio::vts::CallBarrier;
using V1_0::BandConfig;
using V1_0::Class;
using V1_0::MetaData;
using V1_0::MetadataKey;
using V1_0::MetadataType;
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());
}
using std::chrono::steady_clock;
using std::this_thread::sleep_for;
virtual void TearDown() override {
mTuner.clear();
mRadio.clear();
}
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;
class MyCallback : public ITunerCallback {
public:
static constexpr ProgramType kStandardProgramTypes[] = {
ProgramType::AM, ProgramType::FM, ProgramType::AM_HD, ProgramType::FM_HD,
ProgramType::DAB, ProgramType::DRMO, ProgramType::SXM};
// ITunerCallback methods (see doc in ITunerCallback.hal)
virtual Return<void> hardwareFailure() {
ALOGI("%s", __FUNCTION__);
mParentTest->onHwFailureCallback();
return Void();
}
virtual Return<void> configChange(Result result, const BandConfig& config __unused) {
ALOGI("%s result %d", __FUNCTION__, result);
mParentTest->onResultCallback(result);
return Void();
}
virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) {
return Void();
}
virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) {
ALOGI("%s result %d", __FUNCTION__, result);
mParentTest->onResultCallback(result);
return Void();
}
virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) {
return Void();
}
virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) {
return Void();
}
virtual Return<void> antennaStateChange(bool connected) {
ALOGI("%s connected %d", __FUNCTION__, connected);
return Void();
}
virtual Return<void> trafficAnnouncement(bool active) {
ALOGI("%s active %d", __FUNCTION__, active);
return Void();
}
virtual Return<void> emergencyAnnouncement(bool active) {
ALOGI("%s active %d", __FUNCTION__, active);
return Void();
}
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();
}
virtual Return<void> backgroundScanAvailable(bool isAvailable __unused) {
return Void();
}
virtual Return<void> backgroundScanComplete(ProgramListResult result __unused) {
return Void();
}
virtual Return<void> programListChanged() {
return Void();
}
MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
private:
// BroadcastRadioHidlTest instance to which callbacks will be notified.
BroadcastRadioHidlTest *mParentTest;
};
/**
* Method called by MyCallback when a callback with no status or boolean value is received
*/
void onCallback() {
Mutex::Autolock _l(mLock);
onCallback_l();
}
/**
* Method called by MyCallback when hardwareFailure() callback is received
*/
void onHwFailureCallback() {
Mutex::Autolock _l(mLock);
mHwFailure = true;
onCallback_l();
}
/**
* Method called by MyCallback when a callback with status is received
*/
void onResultCallback(Result result) {
Mutex::Autolock _l(mLock);
mResultCallbackData = result;
onCallback_l();
}
/**
* Method called by MyCallback when a boolean indication is received
*/
void onBoolCallback(bool result) {
Mutex::Autolock _l(mLock);
mBoolCallbackData = result;
onCallback_l();
}
BroadcastRadioHidlTest() :
mCallbackCalled(false), mBoolCallbackData(false),
mResultCallbackData(Result::OK), mHwFailure(false) {}
void onCallback_l() {
if (!mCallbackCalled) {
mCallbackCalled = true;
mCallbackCond.broadcast();
}
}
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;
}
bool getProperties();
bool openTuner();
bool checkAntenna();
static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
sp<IBroadcastRadio> mRadio;
Properties mHalProperties;
sp<ITuner> mTuner;
sp<MyCallback> mTunerCallback;
Mutex mLock;
Condition mCallbackCond;
bool mCallbackCalled;
bool mBoolCallbackData;
Result mResultCallbackData;
bool mHwFailure;
};
// 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() {}
};
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;
static void printSkipped(std::string msg) {
std::cout << "[ SKIPPED ] " << msg << std::endl;
}
bool BroadcastRadioHidlTest::openTuner()
{
if (!getProperties()) {
return false;
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&));
};
class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase,
public ::testing::WithParamInterface<Class> {
protected:
virtual void SetUp() override;
virtual void TearDown() override;
bool openTuner();
bool nextBand();
bool getProgramList(std::function<void(const hidl_vec<ProgramInfo>& list)> cb);
Class radioClass;
bool skipped = false;
sp<IBroadcastRadio> mRadioModule;
sp<ITuner> mTuner;
sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
private:
const BandConfig& getBand(unsigned idx);
unsigned currentBandIndex = 0;
hidl_vec<BandConfig> mBands;
};
/**
* 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);
}
if (mTuner.get() == nullptr) {
}
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;
}
void BroadcastRadioHalTest::TearDown() {
mTuner.clear();
mRadioModule.clear();
clearAndWait(mCallback, 1s);
}
bool BroadcastRadioHalTest::openTuner() {
EXPECT_EQ(nullptr, mTuner.get());
if (radioClass == Class::AM_FM) {
EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _);
}
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);
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);
BandConfig halConfig;
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());
mTuner->getConfiguration([&](Result result, const BandConfig& config) {
halResult = result;
halConfig = config;
});
EXPECT_EQ(Result::OK, halResult);
EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
EXPECT_TRUE(halConfig.antennaConnected);
}
EXPECT_NE(nullptr, mTuner.get());
return nullptr != mTuner.get();
}
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;
}
});
const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) {
static const BandConfig dummyBandConfig = {};
return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
}
/**
* Test IBroadcastRadio::getProperties() method
*
* 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
*/
TEST_F(BroadcastRadioHidlTest, GetProperties) {
EXPECT_TRUE(getProperties());
}
/**
* Test IBroadcastRadio::openTuner() method
*
* Verifies that:
* - the HAL implements the method
* - the method returns 0 (no error) and a valid ITuner interface
*/
TEST_F(BroadcastRadioHidlTest, OpenTuner) {
EXPECT_TRUE(openTuner());
}
/**
* Test ITuner::setConfiguration() and getConfiguration methods
*
* 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
*/
TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) {
ASSERT_TRUE(openTuner());
// test setConfiguration
mCallbackCalled = false;
Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
EXPECT_TRUE(hidlResult.isOk());
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
*
* Verifies that:
* - the HAL implements the method
* - the method returns 0 (no error)
* - the tuned callback is received within kTuneCallbacktimeoutNs ns
*/
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 scan DOWN
mCallbackCalled = false;
hidlResult = mTuner->scan(Direction::DOWN, true);
EXPECT_TRUE(hidlResult.isOk());
EXPECT_EQ(Result::OK, hidlResult);
EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
}
/**
* Test ITuner::step
*
* Verifies that:
* - the HAL implements the method
* - the method returns 0 (no error)
* - the tuned callback is received within kTuneCallbacktimeoutNs ns
*/
TEST_F(BroadcastRadioHidlTest, Step) {
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));
}
/**
* Test ITuner::tune, getProgramInformation and cancel methods
*
* Verifies that:
* - the HAL implements the methods
* - the methods return 0 (no error)
* - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
*/
TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
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);
if (radioClass != Class::AM_FM) {
ALOGD("Not AM/FM radio, returning dummy band config");
return dummyBandConfig;
}
// test cancel
mTuner->tune(lowerLimit, 0);
hidlResult = mTuner->cancel();
EXPECT_GT(mBands.size(), idx);
if (mBands.size() <= idx) {
ALOGD("Band index out of bound, returning dummy band config");
return dummyBandConfig;
}
auto& band = mBands[idx];
ALOGD("Returning %s band", toString(band.type).c_str());
return band;
}
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);
return true;
}
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;
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);
}
return !isListEmpty;
}
/**
* 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;
ASSERT_TRUE(openTuner());
auto secondTuner = mTuner;
mTuner.clear();
ASSERT_TRUE(openTuner());
}
/**
* 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());
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;
}
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 that primary vendor identifier isn't used for standard program types.
*
* Verifies that:
* - tuneByProgramSelector fails when VENDORn_PRIMARY is set as a primary
* identifier for program types other than VENDORn.
*/
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 that tune with unknown program type fails.
*
* Verifies that:
* - tuneByProgramSelector fails with INVALID_ARGUMENT when unknown program type is passed.
*/
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 cancelling announcement.
*
* Verifies that:
* - cancelAnnouncement succeeds either when there is an announcement or there is none.
*/
TEST_P(BroadcastRadioHalTest, CancelAnnouncement) {
if (skipped) return;
ASSERT_TRUE(openTuner());
auto hidlResult = mTuner->cancelAnnouncement();
EXPECT_EQ(Result::OK, hidlResult);
}
/**
* Test getImage call with invalid image ID.
*
* Verifies that:
* - getImage call handles argument 0 gracefully.
*/
TEST_P(BroadcastRadioHalTest, GetNoImage) {
if (skipped) return;
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 proper image format in metadata.
*
* Verifies that:
* - all images in metadata are provided out-of-band (by id, not as a binary blob);
* - images are available for getImage call.
*/
TEST_P(BroadcastRadioHalTest, OobImagesOnly) {
if (skipped) return;
ASSERT_TRUE(openTuner());
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 AnalogForced switch.
*
* Verifies that:
* - setAnalogForced results either with INVALID_STATE, or isAnalogForced replying the same.
*/
TEST_P(BroadcastRadioHalTest, AnalogForcedSwitch) {
if (skipped) return;
ASSERT_TRUE(openTuner());
bool forced;
Result halIsResult;
auto isCb = [&](Result result, bool isForced) {
halIsResult = result;
forced = isForced;
};
// 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);

View File

@@ -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",
],
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -20,6 +20,7 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "CameraParameters.h"
#include <system/graphics.h>

View File

@@ -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"
],

View File

@@ -0,0 +1,6 @@
cychen@google.com
epeev@google.com
etalvala@google.com
shuzhenwang@google.com
yinchiayeh@google.com
zhijunhe@google.com

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,6 @@
cychen@google.com
epeev@google.com
etalvala@google.com
shuzhenwang@google.com
yinchiayeh@google.com
zhijunhe@google.com

View File

@@ -0,0 +1,25 @@
// This file is autogenerated by hidl-gen -Landroidbp.
hidl_interface {
name: "android.hardware.camera.device@3.3",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"types.hal",
"ICameraDeviceSession.hal",
],
interfaces: [
"android.hardware.camera.common@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
types: [
"HalStream",
"HalStreamConfiguration",
],
gen_java: false,
}

View File

@@ -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);
};

View File

@@ -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",
]
}

View File

@@ -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

View File

@@ -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

Some files were not shown because too many files have changed in this diff Show More