Merge "Enable java backend for occupant awareness iface."
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
index 2347696..c2e310c 100644
--- a/audio/6.0/IDevice.hal
+++ b/audio/6.0/IDevice.hal
@@ -168,6 +168,25 @@
generates (Result retval, AudioPatchHandle patch);
/**
+ * Updates an audio patch.
+ *
+ * Use of this function is preferred to releasing and re-creating a patch
+ * as the HAL module can figure out a way of switching the route without
+ * causing audio disruption.
+ *
+ * @param previousPatch handle of the previous patch to update.
+ * @param sources new patch sources.
+ * @param sinks new patch sinks.
+ * @return retval operation completion status.
+ * @return patch updated patch handle.
+ */
+ updateAudioPatch(
+ AudioPatchHandle previousPatch,
+ vec<AudioPortConfig> sources,
+ vec<AudioPortConfig> sinks) generates (
+ Result retval, AudioPatchHandle patch);
+
+ /**
* Release an audio patch.
*
* @param patch patch handle.
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
index ddd4d1c..0407d69 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -361,6 +361,7 @@
method public String getRawName();
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ASSISTANT;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index 3fab7dc..05c8ab4 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -551,6 +551,7 @@
<xs:enumeration value="AUDIO_STREAM_DTMF"/>
<xs:enumeration value="AUDIO_STREAM_TTS"/>
<xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
<xs:enumeration value="AUDIO_STREAM_REROUTING"/>
<xs:enumeration value="AUDIO_STREAM_PATCH"/>
</xs:restriction>
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
index e69d969..563e05d 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -106,6 +106,7 @@
TTS = 9, // Transmitted Through Speaker. Plays over speaker
// only, silent on other devices
ACCESSIBILITY = 10, // For accessibility talk back prompts
+ ASSISTANT = 11, // For virtual assistant service
};
@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index ad841ca..47e31c1 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -269,12 +269,21 @@
Return<void> Device::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks,
createAudioPatch_cb _hidl_cb) {
+ auto [retval, patch] = createOrUpdateAudioPatch(
+ static_cast<AudioPatchHandle>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE), sources,
+ sinks);
+ _hidl_cb(retval, patch);
+ return Void();
+}
+
+std::tuple<Result, AudioPatchHandle> Device::createOrUpdateAudioPatch(
+ AudioPatchHandle patch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks) {
Result retval(Result::NOT_SUPPORTED);
- AudioPatchHandle patch = 0;
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources));
std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks));
- audio_patch_handle_t halPatch = AUDIO_PATCH_HANDLE_NONE;
+ audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch);
retval = analyzeStatus("create_audio_patch",
mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
sinks.size(), &halSinks[0], &halPatch));
@@ -282,8 +291,7 @@
patch = static_cast<AudioPatchHandle>(halPatch);
}
}
- _hidl_cb(retval, patch);
- return Void();
+ return {retval, patch};
}
Return<Result> Device::releaseAudioPatch(int32_t patch) {
@@ -438,6 +446,19 @@
}
}
+Return<void> Device::updateAudioPatch(int32_t previousPatch,
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) {
+ if (previousPatch != static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE)) {
+ auto [retval, patch] = createOrUpdateAudioPatch(previousPatch, sources, sinks);
+ _hidl_cb(retval, patch);
+ } else {
+ _hidl_cb(Result::INVALID_ARGUMENTS, previousPatch);
+ }
+ return Void();
+}
+
#endif
} // namespace implementation
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index 0f1aba0..679f85d 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -176,6 +176,13 @@
Return<Result> PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
return mDevice->removeDeviceEffect(device, effectId);
}
+
+Return<void> PrimaryDevice::updateAudioPatch(int32_t previousPatch,
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ updateAudioPatch_cb _hidl_cb) {
+ return mDevice->updateAudioPatch(previousPatch, sources, sinks, _hidl_cb);
+}
#endif
// Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow.
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index 80a9638..b0e72d9 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -118,6 +118,9 @@
Return<Result> close() override;
Return<Result> addDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
Return<Result> removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return<void> updateAudioPatch(int32_t previousPatch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) override;
#endif
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
@@ -136,6 +139,9 @@
virtual ~Device();
Result doClose();
+ std::tuple<Result, AudioPatchHandle> createOrUpdateAudioPatch(
+ AudioPatchHandle patch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks);
// Methods from ParametersUtil.
char* halGetParameters(const char* keys) override;
diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
index 9fc90c3..ccdb7b2 100644
--- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
+++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
@@ -100,6 +100,9 @@
Return<Result> close() override;
Return<Result> addDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
Return<Result> removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return<void> updateAudioPatch(int32_t previousPatch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ updateAudioPatch_cb _hidl_cb) override;
#endif
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 2afbbb8..09ef330 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -181,3 +181,12 @@
ASSERT_OK(getDevice()->close());
ASSERT_TRUE(resetDevice());
}
+
+TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) {
+ doc::test("Verify that passing an invalid handle to updateAudioPatch is checked");
+ AudioPatchHandle ignored;
+ ASSERT_OK(getDevice()->updateAudioPatch(
+ static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE),
+ hidl_vec<AudioPortConfig>(), hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, res);
+}
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
index 2021639..2dfcb9b 100644
--- a/audio/effect/6.0/xml/api/current.txt
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -82,6 +82,7 @@
public enum StreamOutputType {
method public String getRawName();
enum_constant public static final audio.effects.V6_0.StreamOutputType alarm;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType assistant;
enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco;
enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf;
enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible;
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/6.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
new file mode 100644
index 0000000..a7ff20b
--- /dev/null
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -0,0 +1,230 @@
+<?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:enumeration value="voice_performance"/>
+ </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:enumeration value="assistant"/>
+ </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|aec:effects/aec:effectProxy"/>
+ <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>
\ No newline at end of file
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 86df5dc..8fb09eb 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -25,12 +25,7 @@
#include <linux/can/error.h>
#include <linux/can/raw.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
/** Whether to log sent/received packets. */
static constexpr bool kSuperVerbose = false;
@@ -47,6 +42,8 @@
struct canfd_frame frame = {};
frame.can_id = message.id;
+ if (message.isExtendedId) frame.can_id |= CAN_EFF_FLAG;
+ if (message.remoteTransmissionRequest) frame.can_id |= CAN_RTR_FLAG;
frame.len = message.payload.size();
memcpy(frame.data, message.payload.data(), message.payload.size());
@@ -231,8 +228,8 @@
static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
// TODO(b/144458917) add testing for this to VTS tests
if (filterFlag == FilterFlag::DONT_CARE) return true;
- if (filterFlag == FilterFlag::REQUIRE) return flag;
- if (filterFlag == FilterFlag::EXCLUDE) return !flag;
+ if (filterFlag == FilterFlag::SET) return flag;
+ if (filterFlag == FilterFlag::NOT_SET) return !flag;
return false;
}
@@ -246,25 +243,26 @@
* \param id Message id to filter
* \return true if the message id matches the filter, false otherwise
*/
-static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isExtendedId,
- bool isRtr) {
+static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isRtr,
+ bool isExtendedId) {
if (filter.size() == 0) return true;
- bool anyNonInvertedPresent = false;
- bool anyNonInvertedSatisfied = false;
+ bool anyNonExcludeRulePresent = false;
+ bool anyNonExcludeRuleSatisfied = false;
for (auto& rule : filter) {
- const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted &&
+ const bool satisfied = ((id & rule.mask) == rule.id) &&
satisfiesFilterFlag(rule.rtr, isRtr) &&
satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
- if (rule.inverted) {
- // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
- if (!satisfied) return false;
+
+ if (rule.exclude) {
+ // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+ if (satisfied) return false;
} else {
- anyNonInvertedPresent = true;
- if (satisfied) anyNonInvertedSatisfied = true;
+ anyNonExcludeRulePresent = true;
+ if (satisfied) anyNonExcludeRuleSatisfied = true;
}
}
- return !anyNonInvertedPresent || anyNonInvertedSatisfied;
+ return !anyNonExcludeRulePresent || anyNonExcludeRuleSatisfied;
}
void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) {
@@ -345,9 +343,4 @@
if (errcb != nullptr) errcb();
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
index da3fc5a..8b73258 100644
--- a/automotive/can/1.0/default/CanBus.h
+++ b/automotive/can/1.0/default/CanBus.h
@@ -26,12 +26,7 @@
#include <atomic>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBus : public ICanBus {
using ErrorCallback = std::function<void()>;
@@ -114,9 +109,4 @@
ErrorCallback mErrCb;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp
index 365b749..88f9175 100644
--- a/automotive/can/1.0/default/CanBusNative.cpp
+++ b/automotive/can/1.0/default/CanBusNative.cpp
@@ -20,12 +20,7 @@
#include <libnetdevice/can.h>
#include <libnetdevice/libnetdevice.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
CanBusNative::CanBusNative(const std::string& ifname, uint32_t baudrate)
: CanBus(ifname), mBaudrate(baudrate) {}
@@ -49,9 +44,4 @@
return ICanController::Result::OK;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusNative.h b/automotive/can/1.0/default/CanBusNative.h
index 126f1cb..7eda683 100644
--- a/automotive/can/1.0/default/CanBusNative.h
+++ b/automotive/can/1.0/default/CanBusNative.h
@@ -18,12 +18,7 @@
#include "CanBus.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBusNative : public CanBus {
CanBusNative(const std::string& ifname, uint32_t baudrate);
@@ -35,9 +30,4 @@
const uint32_t mBaudrate;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
index 7dce838..29d9d3c 100644
--- a/automotive/can/1.0/default/CanBusSlcan.cpp
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -25,12 +25,7 @@
#include <sys/stat.h>
#include <termios.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
namespace slcanprotocol {
static const std::string kOpenCommand = "O\r";
@@ -158,9 +153,4 @@
return true;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h
index 2713da8..3328a9f 100644
--- a/automotive/can/1.0/default/CanBusSlcan.h
+++ b/automotive/can/1.0/default/CanBusSlcan.h
@@ -22,12 +22,7 @@
#include <termios.h>
#include "CanBus.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBusSlcan : public CanBus {
CanBusSlcan(const std::string& uartName, uint32_t bitrate);
@@ -42,9 +37,4 @@
base::unique_fd mFd;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusVirtual.cpp b/automotive/can/1.0/default/CanBusVirtual.cpp
index cc59fa9..32fe8d6 100644
--- a/automotive/can/1.0/default/CanBusVirtual.cpp
+++ b/automotive/can/1.0/default/CanBusVirtual.cpp
@@ -19,12 +19,7 @@
#include <android-base/logging.h>
#include <libnetdevice/libnetdevice.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
@@ -52,9 +47,4 @@
return true;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusVirtual.h b/automotive/can/1.0/default/CanBusVirtual.h
index c2d5794..3990b20 100644
--- a/automotive/can/1.0/default/CanBusVirtual.h
+++ b/automotive/can/1.0/default/CanBusVirtual.h
@@ -18,12 +18,7 @@
#include "CanBus.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBusVirtual : public CanBus {
CanBusVirtual(const std::string& ifname);
@@ -36,9 +31,4 @@
bool mWasCreated = false;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
index ffdc912..cd17dd8 100644
--- a/automotive/can/1.0/default/CanController.cpp
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -25,12 +25,7 @@
#include <regex>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
@@ -139,9 +134,4 @@
return success;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h
index 0674d0e..99a551a 100644
--- a/automotive/can/1.0/default/CanController.h
+++ b/automotive/can/1.0/default/CanController.h
@@ -20,12 +20,7 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanController : public ICanController {
Return<void> getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override;
@@ -39,9 +34,4 @@
std::map<std::string, sp<CanBus>> mCanBuses GUARDED_BY(mCanBusesGuard);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
index 86e12d1..86ccc0e 100644
--- a/automotive/can/1.0/default/CanSocket.cpp
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -24,12 +24,7 @@
#include <chrono>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
using namespace std::chrono_literals;
@@ -152,9 +147,4 @@
LOG(VERBOSE) << "Reader thread stopped";
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
index c98330b..fd956b5 100644
--- a/automotive/can/1.0/default/CanSocket.h
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -24,12 +24,7 @@
#include <chrono>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
/** Wrapper around SocketCAN socket. */
struct CanSocket {
@@ -71,9 +66,4 @@
DISALLOW_COPY_AND_ASSIGN(CanSocket);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CloseHandle.cpp b/automotive/can/1.0/default/CloseHandle.cpp
index aba2c49..e1ffe2b 100644
--- a/automotive/can/1.0/default/CloseHandle.cpp
+++ b/automotive/can/1.0/default/CloseHandle.cpp
@@ -16,12 +16,7 @@
#include "CloseHandle.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
@@ -37,9 +32,4 @@
return {};
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h
index eade109..c332d74 100644
--- a/automotive/can/1.0/default/CloseHandle.h
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -19,12 +19,7 @@
#include <android-base/macros.h>
#include <android/hardware/automotive/can/1.0/ICloseHandle.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
/** Generic ICloseHandle implementation ignoring double-close events. */
struct CloseHandle : public ICloseHandle {
@@ -49,9 +44,4 @@
DISALLOW_COPY_AND_ASSIGN(CloseHandle);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
index 9845bc7..556debf 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
@@ -18,9 +18,7 @@
#include <android-base/logging.h>
-namespace android {
-namespace netdevice {
-namespace impl {
+namespace android::netdevice::impl {
static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
return reinterpret_cast<struct rtattr*>( //
@@ -53,6 +51,4 @@
nest->rta_len = nestLen;
}
-} // namespace impl
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice::impl
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
index ba9b65b..3e28d78 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -21,8 +21,7 @@
#include <string>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
typedef unsigned short rtattrtype_t; // as in rtnetlink.h
typedef __u16 nlmsgtype_t; // as in netlink.h
@@ -151,5 +150,4 @@
}
};
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
index 0514764..6a7f506 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -18,8 +18,7 @@
#include <android-base/logging.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
NetlinkSocket::NetlinkSocket(int protocol) {
mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
@@ -110,5 +109,4 @@
return false;
}
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
index 90e1f3f..2b40ea2 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -23,8 +23,7 @@
#include <linux/netlink.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
/**
* A wrapper around AF_NETLINK sockets.
@@ -64,5 +63,4 @@
DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
};
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index 6452d9b..06d45d3 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -28,9 +28,7 @@
#include <linux/can/netlink.h>
#include <linux/can/raw.h>
-namespace android {
-namespace netdevice {
-namespace can {
+namespace android::netdevice::can {
static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
@@ -95,6 +93,4 @@
return sock.send(req) && sock.receiveAck();
}
-} // namespace can
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
index 3deac3e..5c62443 100644
--- a/automotive/can/1.0/default/libnetdevice/common.cpp
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -20,8 +20,7 @@
#include <net/if.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
unsigned int nametoindex(const std::string& ifname) {
const auto ifidx = if_nametoindex(ifname.c_str());
@@ -34,5 +33,4 @@
return 0;
}
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 9bdff4d..8097f37 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -18,8 +18,7 @@
#include <string>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
/**
* Returns the index of a given network interface.
@@ -32,5 +31,4 @@
*/
unsigned int nametoindex(const std::string& ifname);
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
index d75361e..3886acf 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -20,9 +20,7 @@
#include <string>
-namespace android {
-namespace netdevice {
-namespace can {
+namespace android::netdevice::can {
/**
* Opens and binds SocketCAN socket.
@@ -40,6 +38,4 @@
*/
bool setBitrate(std::string ifname, uint32_t bitrate);
-} // namespace can
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index e22eafb..3818a31 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -19,8 +19,7 @@
#include <optional>
#include <string>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
/**
* Checks, if the network interface exists.
@@ -71,5 +70,4 @@
*/
bool del(std::string dev);
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index fc2b193..aee8205 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -25,8 +25,7 @@
#include <linux/can.h>
#include <net/if.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
bool exists(std::string ifname) {
return nametoindex(ifname) != 0;
@@ -96,5 +95,4 @@
return sock.send(req) && sock.receiveAck();
}
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
index ebc2f8c..b52a54a 100644
--- a/automotive/can/1.0/default/service.cpp
+++ b/automotive/can/1.0/default/service.cpp
@@ -19,12 +19,7 @@
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
static void canControllerService() {
base::SetDefaultTag("CanController");
@@ -42,12 +37,7 @@
joinRpcThreadpool();
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
int main() {
::android::hardware::automotive::can::V1_0::implementation::canControllerService();
diff --git a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
index 039f971..f63d43c 100644
--- a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
+++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
@@ -16,10 +16,7 @@
#pragma once
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace hidl_utils {
+namespace android::hardware::automotive::hidl_utils {
/**
* Helper functor to fetch results from multi-return HIDL calls.
@@ -61,7 +58,4 @@
}
};
-} // namespace hidl_utils
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::hidl_utils
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
index fa1048d..5c9849b 100644
--- a/automotive/can/1.0/tools/canhalctrl.cpp
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -22,10 +22,7 @@
#include <iostream>
#include <string>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
+namespace android::hardware::automotive::can {
using ICanController = V1_0::ICanController;
@@ -170,10 +167,7 @@
}
}
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can
int main(int argc, char* argv[]) {
if (argc < 1) return -1;
diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp
index 55b2a34..2f5ca61 100644
--- a/automotive/can/1.0/tools/canhaldump.cpp
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -27,10 +27,7 @@
#include <string>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
+namespace android::hardware::automotive::can {
using namespace std::chrono_literals;
@@ -128,10 +125,7 @@
return candump(argv[0]);
}
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can
int main(int argc, char* argv[]) {
if (argc < 1) return -1;
diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp
index 29330c9..7e6833a 100644
--- a/automotive/can/1.0/tools/canhalsend.cpp
+++ b/automotive/can/1.0/tools/canhalsend.cpp
@@ -21,10 +21,7 @@
#include <iostream>
#include <string>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
+namespace android::hardware::automotive::can {
using ICanBus = V1_0::ICanBus;
using Result = V1_0::Result;
@@ -125,10 +122,7 @@
return cansend(busname, msgid, payload);
}
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can
int main(int argc, char* argv[]) {
if (argc < 1) return -1;
diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal
index f09c940..5eeed53 100644
--- a/automotive/can/1.0/types.hal
+++ b/automotive/can/1.0/types.hal
@@ -73,23 +73,22 @@
* Single filter rule for CAN messages.
*
* A filter is satisfied if:
- * ((receivedId & mask) == (id & mask)) == !inverted
+ * ((receivedId & mask) == (id & mask)) == !exclude
*
- * In order for set of filters to match, at least one non-inverted filters must match (if there is
- * one) and all inverted filters must match. In other words:
- * - a single matching non-inverted filter makes the whole set matching;
- * - a single non-matching inverted filter makes the whole set non-matching.
- *
- * Additional less common options for filtering include:
- * rtr - Remote Transmission Request; another ECU requests DLC bytes of data on this message ID
- * extendedFormat - 29 bit message ID is used instead of 11 bits
+ * In order for set of filters to match, at least one non-exclude filters must match (if there is
+ * one) and all exclude filters must match. In other words:
+ * - a single matching non-exclude filter makes the whole set matching;
+ * - a single non-matching excluded filter makes the whole set non-matching.
*/
struct CanMessageFilter {
CanMessageId id;
uint32_t mask;
- bool inverted;
+ /** Remote Transmission Request; another ECU requests <DLC> bytes of data on this message ID */
FilterFlag rtr;
+ /** 29 bit message ID is used instead of 11 bits */
FilterFlag extendedFormat;
+ /** 'exclude' *DOES* apply to rtr and extendedFormat! */
+ bool exclude;
};
@@ -100,9 +99,9 @@
/** Default, FilterFlag doesn't effect what messages filtered */
DONT_CARE = 0,
/** This FilterFlag MUST be present in received messages to pass though the filter */
- REQUIRE,
+ SET,
/** This FilterFlag must NOT be present in received messages to pass though the filter */
- EXCLUDE,
+ NOT_SET,
};
enum Result : uint8_t {
diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp
index b4d9132..e3e770b 100644
--- a/automotive/can/1.0/vts/functional/Android.bp
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -16,13 +16,16 @@
cc_defaults {
name: "android.hardware.automotive.can@vts-defaults",
- defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.automotive.can@defaults",
+ ],
header_libs: [
"android.hardware.automotive.can@hidl-utils-lib",
- "android.hardware.automotive.can@vts-utils-lib",
],
static_libs: [
"android.hardware.automotive.can@1.0",
+ "android.hardware.automotive.can@vts-utils-lib",
"libgmock",
],
test_suites: ["general-tests"],
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
index 250caf2..cdea8b6 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -24,12 +24,7 @@
#include <gmock/gmock.h>
#include <hidl-utils/hidl-utils.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
+namespace android::hardware::automotive::can::V1_0::vts {
using hardware::hidl_vec;
@@ -83,7 +78,7 @@
TEST_F(CanBusHalTest, SendNoPayload) {
CanMessage msg = {};
msg.id = 0x123;
-
+ ASSERT_NE(mCanBus, nullptr);
const auto result = mCanBus->send(msg);
ASSERT_EQ(Result::OK, result);
}
@@ -123,9 +118,9 @@
TEST_F(CanBusHalTest, ListenSomeFilter) {
hidl_vec<CanMessageFilter> filters = {
- {0x123, 0x1FF, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
- {0x001, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
- {0x200, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+ {0x123, 0x1FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x001, 0x00F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x200, 0x100, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
};
const auto [result, closeHandle] = listen(filters, new CanMessageListener());
@@ -173,22 +168,23 @@
ASSERT_NE(nullptr, closeHandle.get());
}
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::vts
/**
+ * This test requires that you bring up a valid bus first.
+ *
+ * Before running:
+ * mma -j && adb root && adb remount && adb sync
+ *
* Example manual invocation:
* adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \
- * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test
+ * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/<NAME_OF_VALID_BUS>
*/
int main(int argc, char** argv) {
using android::hardware::automotive::can::V1_0::ICanBus;
using android::hardware::automotive::can::V1_0::vts::gEnv;
using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
android::base::SetDefaultTag("CanBusVts");
android::base::SetMinimumLogSeverity(android::base::VERBOSE);
gEnv = new SimpleHidlEnvironment<ICanBus>;
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index 695b9fb..efaad53 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -21,6 +21,7 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
#include <android/hardware/automotive/can/1.0/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
#include <can-vts-utils/can-hal-printers.h>
#include <can-vts-utils/environment-utils.h>
#include <gmock/gmock.h>
@@ -31,12 +32,7 @@
#include <chrono>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
+namespace android::hardware::automotive::can::V1_0::vts {
using namespace std::chrono_literals;
@@ -125,6 +121,7 @@
}
void send(const CanMessage& msg) {
+ EXPECT_NE(mBus, nullptr);
const auto result = mBus->send(msg);
EXPECT_EQ(Result::OK, result);
}
@@ -144,18 +141,26 @@
Bus makeBus();
+ protected:
+ static hidl_vec<hidl_string> mBusNames;
+
private:
unsigned mLastIface = 0;
static sp<ICanController> mCanController;
static bool mVirtualSupported;
+ static bool mTestCaseInitialized;
};
sp<ICanController> CanBusVirtualHalTest::mCanController = nullptr;
bool CanBusVirtualHalTest::mVirtualSupported;
+hidl_vec<hidl_string> CanBusVirtualHalTest::mBusNames;
+bool CanBusVirtualHalTest::mTestCaseInitialized = false;
-static CanMessage makeMessage(CanMessageId id) {
+static CanMessage makeMessage(CanMessageId id, bool rtr, bool extended) {
CanMessage msg = {};
msg.id = id;
+ msg.remoteTransmissionRequest = rtr;
+ msg.isExtendedId = extended;
return msg;
}
@@ -165,6 +170,7 @@
void CanBusVirtualHalTest::SetUp() {
if (!mVirtualSupported) GTEST_SKIP();
+ ASSERT_TRUE(mTestCaseInitialized);
}
void CanBusVirtualHalTest::SetUpTestCase() {
@@ -175,6 +181,11 @@
hidl_vec<InterfaceType> supported;
mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk();
mVirtualSupported = supported.contains(InterfaceType::VIRTUAL);
+
+ mBusNames = utils::getBusNames();
+ ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+ mTestCaseInitialized = true;
}
void CanBusVirtualHalTest::TearDownTestCase() {
@@ -182,10 +193,11 @@
}
Bus CanBusVirtualHalTest::makeBus() {
- const auto idx = ++mLastIface;
+ const auto idx = mLastIface++;
+ EXPECT_LT(idx, mBusNames.size());
ICanController::BusConfiguration config = {};
- config.name = "test" + std::to_string(idx);
+ config.name = mBusNames[idx];
config.iftype = InterfaceType::VIRTUAL;
config.interfaceId.address("vcan50");
@@ -212,6 +224,7 @@
}
TEST_F(CanBusVirtualHalTest, SendAndRecv) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
auto bus1 = makeBus();
auto bus2 = makeBus();
@@ -231,6 +244,8 @@
}
TEST_F(CanBusVirtualHalTest, DownOneOfTwo) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+
auto bus1 = makeBus();
auto bus2 = makeBus();
@@ -239,63 +254,624 @@
bus1.send({});
}
-TEST_F(CanBusVirtualHalTest, Filter) {
+TEST_F(CanBusVirtualHalTest, FilterPositive) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
auto bus1 = makeBus();
auto bus2 = makeBus();
+ /* clang-format off */
+ /* id, mask, rtr, eff, exclude */
hidl_vec<CanMessageFilter> filterPositive = {
- {0x101, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
- {0x010, 0x0F0, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+ {0x334, 0x73F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x49D, 0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x325, 0x7FC, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, false},
+ {0x246, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, false},
+ {0x1A2, 0x7FB, FilterFlag::SET, FilterFlag::NOT_SET, false},
+ {0x607, 0x7C9, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false},
+ {0x7F4, 0x777, FilterFlag::NOT_SET, FilterFlag::NOT_SET, false},
+ {0x1BF19EAF, 0x10F0F0F0, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x12E99200, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, false},
+ {0x06B70270, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::DONT_CARE, false},
+ {0x096CFD2B, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, false},
+ {0x1BDCB008, 0x0F0F0F0F, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false},
+ {0x08318B46, 0x10F0F0F0, FilterFlag::NOT_SET, FilterFlag::SET, false},
+ {0x06B, 0x70F, FilterFlag::DONT_CARE, FilterFlag::SET, false},
+ {0x750, 0x70F, FilterFlag::SET, FilterFlag::SET, false},
+ {0x5CF, 0x70F, FilterFlag::NOT_SET, FilterFlag::SET, false},
};
+ /* clang-format on */
auto listenerPositive = bus2.listen(filterPositive);
- hidl_vec<CanMessageFilter> filterNegative = {
- {0x123, 0x0FF, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
- {0x004, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
- };
- auto listenerNegative = bus2.listen(filterNegative);
+ // 334:73F, DNC, DNC
+ bus1.send(makeMessage(0x3F4, false, false));
+ bus1.send(makeMessage(0x334, false, true));
+ bus1.send(makeMessage(0x374, true, false));
+ bus1.send(makeMessage(0x3F4, true, true));
- bus1.send(makeMessage(0));
- bus1.send(makeMessage(0x1A0));
- bus1.send(makeMessage(0x1A1));
- bus1.send(makeMessage(0x2A0));
- bus1.send(makeMessage(0x3A0));
- bus1.send(makeMessage(0x010));
- bus1.send(makeMessage(0x123));
- bus1.send(makeMessage(0x023));
- bus1.send(makeMessage(0x124));
+ // 49D:700, DNC, DNC
+ bus1.send(makeMessage(0x404, false, false));
+ bus1.send(makeMessage(0x4A5, false, true));
+ bus1.send(makeMessage(0x4FF, true, false));
+ bus1.send(makeMessage(0x46B, true, true));
+
+ // 325:7FC, DNC, NS
+ bus1.send(makeMessage(0x324, false, false));
+ bus1.send(makeMessage(0x325, false, true)); // filtered out
+ bus1.send(makeMessage(0x326, true, false));
+ bus1.send(makeMessage(0x327, true, true)); // filtered out
+
+ // 246:7FF, SET, DNC
+ bus1.send(makeMessage(0x246, false, false)); // filtered out
+ bus1.send(makeMessage(0x246, false, true)); // filtered out
+ bus1.send(makeMessage(0x246, true, false));
+ bus1.send(makeMessage(0x246, true, true));
+
+ // 1A2:7FB, SET, NS
+ bus1.send(makeMessage(0x1A2, false, false)); // filtered out
+ bus1.send(makeMessage(0x1A6, false, true)); // filtered out
+ bus1.send(makeMessage(0x1A2, true, false));
+ bus1.send(makeMessage(0x1A6, true, true)); // filtered out
+
+ // 607:7C9, NS, DNC
+ bus1.send(makeMessage(0x607, false, false));
+ bus1.send(makeMessage(0x613, false, true));
+ bus1.send(makeMessage(0x625, true, false)); // filtered out
+ bus1.send(makeMessage(0x631, true, true)); // filtered out
+
+ // 7F4:777, NS, NS
+ bus1.send(makeMessage(0x774, false, false));
+ bus1.send(makeMessage(0x7F4, false, true)); // filtered out
+ bus1.send(makeMessage(0x77C, true, false)); // filtered out
+ bus1.send(makeMessage(0x7FC, true, false)); // filtered out
+
+ // 1BF19EAF:10F0F0F0, DNC, DNC
+ bus1.send(makeMessage(0x11F293A4, false, false));
+ bus1.send(makeMessage(0x15F697A8, false, true));
+ bus1.send(makeMessage(0x19FA9BAC, true, false));
+ bus1.send(makeMessage(0x1DFE9FA0, true, true));
+
+ // 12E99200:1FFFFFFF, DNC, SET
+ bus1.send(makeMessage(0x12E99200, false, false)); // filtered out
+ bus1.send(makeMessage(0x12E99200, false, true));
+ bus1.send(makeMessage(0x12E99200, true, false)); // filtered out
+ bus1.send(makeMessage(0x12E99200, true, true));
+
+ // 06B70270:1FFFFFFF, SET, DNC
+ bus1.send(makeMessage(0x06B70270, false, false)); // filtered out
+ bus1.send(makeMessage(0x06B70270, false, true)); // filtered out
+ bus1.send(makeMessage(0x06B70270, true, false));
+ bus1.send(makeMessage(0x06B70270, true, true));
+
+ // 096CFD2B:1FFFFFFF, SET, SET
+ bus1.send(makeMessage(0x096CFD2B, false, false)); // filtered out
+ bus1.send(makeMessage(0x096CFD2B, false, true)); // filtered out
+ bus1.send(makeMessage(0x096CFD2B, true, false)); // filtered out
+ bus1.send(makeMessage(0x096CFD2B, true, true));
+
+ // 1BDCB008:0F0F0F0F, NS, DNC
+ bus1.send(makeMessage(0x1B2C3048, false, false));
+ bus1.send(makeMessage(0x0B5C6078, false, true));
+ bus1.send(makeMessage(0x1B8C90A8, true, false)); // filtered out
+ bus1.send(makeMessage(0x0BBCC0D8, true, true)); // filtered out
+
+ // 08318B46:10F0F0F0, NS, SET
+ bus1.send(makeMessage(0x0F3E8D4C, false, false)); // filtered out
+ bus1.send(makeMessage(0x0B3A8948, false, true));
+ bus1.send(makeMessage(0x07368544, true, false)); // filtered out
+ bus1.send(makeMessage(0x03328140, true, true)); // filtered out
+
+ // 06B:70F, DNC, SET
+ bus1.send(makeMessage(0x00B, false, false)); // filtered out
+ bus1.send(makeMessage(0x04B, false, true));
+ bus1.send(makeMessage(0x08B, true, false)); // filtered out
+ bus1.send(makeMessage(0x0FB, true, true));
+
+ // 750:70F, SET, SET
+ bus1.send(makeMessage(0x7F0, false, false)); // filtered out
+ bus1.send(makeMessage(0x780, false, true)); // filtered out
+ bus1.send(makeMessage(0x740, true, false)); // filtered out
+ bus1.send(makeMessage(0x700, true, true));
+
+ // 5CF:70F, NS, SET
+ bus1.send(makeMessage(0x51F, false, false)); // filtered out
+ bus1.send(makeMessage(0x53F, false, true));
+ bus1.send(makeMessage(0x57F, true, false)); // filtered out
+ bus1.send(makeMessage(0x5FF, true, true)); // filtered out
std::vector<can::V1_0::CanMessage> expectedPositive{
- makeMessage(0x1A0), //
- makeMessage(0x1A1), //
- makeMessage(0x3A0), //
- makeMessage(0x010), //
- makeMessage(0x123), //
- makeMessage(0x124), //
- };
- std::vector<can::V1_0::CanMessage> expectedNegative{
- makeMessage(0), //
- makeMessage(0x1A0), //
- makeMessage(0x1A1), //
- makeMessage(0x2A0), //
- makeMessage(0x3A0), //
- makeMessage(0x010), //
+ makeMessage(0x3F4, false, false), // 334:73F, DNC, DNC
+ makeMessage(0x334, false, true), // 334:73F, DNC, DNC
+ makeMessage(0x374, true, false), // 334:73F, DNC, DNC
+ makeMessage(0x3F4, true, true), // 334:73F, DNC, DNC
+ makeMessage(0x404, false, false), // 49D:700, DNC, DNC
+ makeMessage(0x4A5, false, true), // 49D:700, DNC, DNC
+ makeMessage(0x4FF, true, false), // 49D:700, DNC, DNC
+ makeMessage(0x46B, true, true), // 49D:700, DNC, DNC
+ makeMessage(0x324, false, false), // 325:7FC, DNC, NS
+ makeMessage(0x326, true, false), // 325:7FC, DNC, NS
+ makeMessage(0x246, true, false), // 246:7FF, SET, DNC
+ makeMessage(0x246, true, true), // 246:7FF, SET, DNC
+ makeMessage(0x1A2, true, false), // 1A2:7FB, SET, NS
+ makeMessage(0x607, false, false), // 607:7C9, NS, DNC
+ makeMessage(0x613, false, true), // 607:7C9, NS, DNC
+ makeMessage(0x774, false, false), // 7F4:777, NS, NS
+ makeMessage(0x11F293A4, false, false), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x15F697A8, false, true), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x19FA9BAC, true, false), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x1DFE9FA0, true, true), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x12E99200, false, true), // 12E99200:1FFFFFFF, DNC, SET
+ makeMessage(0x12E99200, true, true), // 12E99200:1FFFFFFF, DNC, SET
+ makeMessage(0x06B70270, true, false), // 06B70270:1FFFFFFF, SET, DNC
+ makeMessage(0x06B70270, true, true), // 06B70270:1FFFFFFF, SET, DNC
+ makeMessage(0x096CFD2B, true, true), // 096CFD2B:1FFFFFFF, SET, SET
+ makeMessage(0x1B2C3048, false, false), // 1BDCB008:0F0F0F0F, NS, DNC
+ makeMessage(0x0B5C6078, false, true), // 1BDCB008:0F0F0F0F, NS, DNC
+ makeMessage(0x0B3A8948, false, true), // 08318B46:10F0F0F0, NS, SET
+ makeMessage(0x04B, false, true), // 06B:70F, DNC, SET
+ makeMessage(0x0FB, true, true), // 06B:70F, DNC, SET
+ makeMessage(0x700, true, true), // 750:70F, SET, SET
+ makeMessage(0x53F, false, true), // 5CF:70F, NS, SET
};
- auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
- clearTimestamps(messagesNegative);
clearTimestamps(messagesPositive);
- ASSERT_EQ(expectedNegative, messagesNegative);
ASSERT_EQ(expectedPositive, messagesPositive);
}
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+TEST_F(CanBusVirtualHalTest, FilterNegative) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ /* clang-format off */
+ /* id, mask, rtr, eff exclude */
+ hidl_vec<CanMessageFilter> filterNegative = {
+ {0x063, 0x7F3, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x0A1, 0x78F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x18B, 0x7E3, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x1EE, 0x7EC, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x23F, 0x7A5, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x31F, 0x77F, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x341, 0x77F, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x196573DB, 0x1FFFFF7F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x1CFCB417, 0x1FFFFFEC, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x17CCC433, 0x1FFFFFEC, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x0BC2F508, 0x1FFFFFC3, FilterFlag::SET, FilterFlag::SET, true},
+ {0x1179B5D2, 0x1FFFFFC3, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x082AF63D, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x66D, 0x76F, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x748, 0x7CC, FilterFlag::SET, FilterFlag::SET, true},
+ {0x784, 0x7CC, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ };
+ /* clang-format on */
+
+ auto listenerNegative = bus2.listen(filterNegative);
+
+ // 063:7F3, DNC, DNC: ~06[3,7,B,F]
+ bus1.send(makeMessage(0x063, false, false)); // filtered out
+ bus1.send(makeMessage(0x060, false, true));
+ bus1.send(makeMessage(0x05B, true, false));
+ bus1.send(makeMessage(0x06F, true, true)); // filtered out
+
+ // 0A1:78F, DNC, DNC: ~0[8-F]1
+ bus1.send(makeMessage(0x081, false, false)); // filtered out
+ bus1.send(makeMessage(0x031, false, true));
+ bus1.send(makeMessage(0x061, true, false));
+ bus1.send(makeMessage(0x071, true, true));
+
+ // 18B:7E3, DNC, NS: ~1[8-9][7,B,F]
+ bus1.send(makeMessage(0x18B, false, false)); // filtered out
+ bus1.send(makeMessage(0x188, false, true));
+ bus1.send(makeMessage(0x123, true, false));
+ bus1.send(makeMessage(0x1D5, true, true));
+
+ // 1EE:7EC, SET, DNC: ~1[E-F][C-F]
+ bus1.send(makeMessage(0x17E, false, false));
+ bus1.send(makeMessage(0x138, false, true));
+ bus1.send(makeMessage(0x123, true, false));
+ bus1.send(makeMessage(0x1EC, true, true)); // filtered out
+
+ // 23F:7A5, SET, NS: ~2[2,3,6,7][5,7,D,F]
+ bus1.send(makeMessage(0x222, false, false));
+ bus1.send(makeMessage(0x275, false, true));
+ bus1.send(makeMessage(0x23f, true, false)); // filtered out
+ bus1.send(makeMessage(0x241, true, false));
+ bus1.send(makeMessage(0x2FF, true, true));
+
+ // 31F:77F, NS, DNC: ~3[1,9]F
+ bus1.send(makeMessage(0x32F, false, false));
+ bus1.send(makeMessage(0x31F, false, true)); // filtered out
+ bus1.send(makeMessage(0x36F, false, true));
+ bus1.send(makeMessage(0x31F, true, false));
+ bus1.send(makeMessage(0x3F3, true, true));
+
+ // 341:77F, NS, NS: ~3[4,C]1
+ bus1.send(makeMessage(0x341, false, false)); // filtered out
+ bus1.send(makeMessage(0x352, false, false));
+ bus1.send(makeMessage(0x3AA, false, true));
+ bus1.send(makeMessage(0x3BC, true, false));
+ bus1.send(makeMessage(0x3FF, true, true));
+
+ // 196573DB:1FFFFF7F, DNC, DNC: ~196573[5,D]B
+ bus1.send(makeMessage(0x1965733B, false, false));
+ bus1.send(makeMessage(0x1965734B, false, true));
+ bus1.send(makeMessage(0x1965735B, true, false)); // filtered out
+ bus1.send(makeMessage(0x1965736B, true, true));
+
+ // 1CFCB417:1FFFFFEC, DNC, SET: ~1CFCB4[0-1][4-7]
+ bus1.send(makeMessage(0x1CFCB407, false, false));
+ bus1.send(makeMessage(0x1CFCB4FF, false, true));
+ bus1.send(makeMessage(0x1CFCB414, true, false));
+ bus1.send(makeMessage(0x1CFCB407, true, true)); // filtered out
+
+ // 17CCC433:1FFFFFEC, SET, DNC: ~17CCC4[2-3][0-3]
+ bus1.send(makeMessage(0x17CCC430, false, false));
+ bus1.send(makeMessage(0x17CCC423, false, true));
+ bus1.send(makeMessage(0x17CCC420, true, false)); // filtered out
+ bus1.send(makeMessage(0x17CCC444, true, true));
+
+ // 0BC2F508:1FFFFFC3, SET, SET: ~5[0-3][0,4,8,C]
+ bus1.send(makeMessage(0x0BC2F504, false, false));
+ bus1.send(makeMessage(0x0BC2F518, false, true));
+ bus1.send(makeMessage(0x0BC2F52C, true, false));
+ bus1.send(makeMessage(0x0BC2F500, true, true)); // filtered out
+ bus1.send(makeMessage(0x0BC2F543, true, true));
+
+ // 1179B5D2:1FFFFFC3, NS, DNC: ~5[C-F][2,6,A,E]
+ bus1.send(makeMessage(0x1179B5BB, false, false));
+ bus1.send(makeMessage(0x1179B5EA, false, true)); // filtered out
+ bus1.send(makeMessage(0x1179B5C2, true, false));
+ bus1.send(makeMessage(0x1179B5DA, true, true));
+
+ // 082AF63D:1FFFFF6F, NS, SET: ~6[2,3,A,B]D
+ bus1.send(makeMessage(0x082AF62D, false, false));
+ bus1.send(makeMessage(0x082AF63D, false, true)); // filtered out
+ bus1.send(makeMessage(0x082AF60D, false, true));
+ bus1.send(makeMessage(0x082AF6AD, true, false));
+ bus1.send(makeMessage(0x082AF6BD, true, true));
+
+ // 66D:76F, DNC, SET: ~6[6,7,E,F]D
+ bus1.send(makeMessage(0x66D, false, false));
+ bus1.send(makeMessage(0x68D, false, true));
+ bus1.send(makeMessage(0x67D, true, false));
+ bus1.send(makeMessage(0x6ED, true, true)); // filtered out
+
+ // 748:7CC, SET, SET: ~0x7[4-7][8-F]
+ bus1.send(makeMessage(0x749, false, false));
+ bus1.send(makeMessage(0x75A, false, true));
+ bus1.send(makeMessage(0x76B, true, false));
+ bus1.send(makeMessage(0x748, true, true)); // filtered out
+ bus1.send(makeMessage(0x788, true, true));
+
+ // 784:7CC, NS, SET: ~0x7[8-F][4-7]
+ bus1.send(makeMessage(0x795, false, false));
+ bus1.send(makeMessage(0x784, false, true)); // filtered out
+ bus1.send(makeMessage(0x71B, false, true));
+ bus1.send(makeMessage(0x769, true, false));
+ bus1.send(makeMessage(0x784, true, true));
+
+ std::vector<can::V1_0::CanMessage> expectedNegative{
+ makeMessage(0x060, false, true), // 063:7F3, DNC, DNC
+ makeMessage(0x05B, true, false), // 063:7F3, DNC, DNC
+ makeMessage(0x031, false, true), // 0A1:78F, DNC, DNC
+ makeMessage(0x061, true, false), // 0A1:78F, DNC, DNC
+ makeMessage(0x071, true, true), // 0A1:78F, DNC, DNC
+ makeMessage(0x188, false, true), // 18B:7E3, DNC, NS
+ makeMessage(0x123, true, false), // 18B:7E3, DNC, NS
+ makeMessage(0x1D5, true, true), // 18B:7E3, DNC, NS
+ makeMessage(0x17E, false, false), // 1EE:7EC, SET, DNC
+ makeMessage(0x138, false, true), // 1EE:7EC, SET, DNC
+ makeMessage(0x123, true, false), // 1EE:7EC, SET, DNC
+ makeMessage(0x222, false, false), // 23F:7A5, SET, NS
+ makeMessage(0x275, false, true), // 23F:7A5, SET, NS
+ makeMessage(0x241, true, false), // 23F:7A5, SET, NS
+ makeMessage(0x2FF, true, true), // 23F:7A5, SET, NS
+ makeMessage(0x32F, false, false), // 31F:77F, NS, DNC
+ makeMessage(0x36F, false, true), // 31F:77F, NS, DNC
+ makeMessage(0x31F, true, false), // 31F:77F, NS, DNC
+ makeMessage(0x3F3, true, true), // 31F:77F, NS, DNC
+ makeMessage(0x352, false, false), // 341:77F, NS, NS
+ makeMessage(0x3AA, false, true), // 341:77F, NS, NS
+ makeMessage(0x3BC, true, false), // 341:77F, NS, NS
+ makeMessage(0x3FF, true, true), // 341:77F, NS, NS
+ makeMessage(0x1965733B, false, false), // 196573DB:1FFFFF7F, DNC, DNC
+ makeMessage(0x1965734B, false, true), // 196573DB:1FFFFF7F, DNC, DNC
+ makeMessage(0x1965736B, true, true), // 196573DB:1FFFFF7F, DNC, DNC
+ makeMessage(0x1CFCB407, false, false), // 1CFCB417:1FFFFFEC, DNC, SET
+ makeMessage(0x1CFCB4FF, false, true), // 1CFCB417:1FFFFFEC, DNC, SET
+ makeMessage(0x1CFCB414, true, false), // 1CFCB417:1FFFFFEC, DNC, SET
+ makeMessage(0x17CCC430, false, false), // 17CCC433:1FFFFFEC, SET, DNC
+ makeMessage(0x17CCC423, false, true), // 17CCC433:1FFFFFEC, SET, DNC
+ makeMessage(0x17CCC444, true, true), // 17CCC433:1FFFFFEC, SET, DNC
+ makeMessage(0x0BC2F504, false, false), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x0BC2F518, false, true), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x0BC2F52C, true, false), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x0BC2F543, true, true), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x1179B5BB, false, false), // 1179B5D2:1FFFFFC3, NS, DNC
+ makeMessage(0x1179B5C2, true, false), // 1179B5D2:1FFFFFC3, NS, DNC
+ makeMessage(0x1179B5DA, true, true), // 1179B5D2:1FFFFFC3, NS, DNC
+ makeMessage(0x082AF62D, false, false), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x082AF60D, false, true), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x082AF6AD, true, false), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x082AF6BD, true, true), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x66D, false, false), // 66D:76F, DNC, SET
+ makeMessage(0x68D, false, true), // 66D:76F, DNC, SET
+ makeMessage(0x67D, true, false), // 66D:76F, DNC, SET
+ makeMessage(0x749, false, false), // 748:7CC, SET, SET
+ makeMessage(0x75A, false, true), // 748:7CC, SET, SET
+ makeMessage(0x76B, true, false), // 748:7CC, SET, SET
+ makeMessage(0x788, true, true), // 748:7CC, SET, SET
+ makeMessage(0x795, false, false), // 784:7CC, NS, SET
+ makeMessage(0x71B, false, true), // 784:7CC, NS, SET
+ makeMessage(0x769, true, false), // 784:7CC, NS, SET
+ makeMessage(0x784, true, true), // 784:7CC, NS, SET
+ };
+
+ auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
+ clearTimestamps(messagesNegative);
+ ASSERT_EQ(expectedNegative, messagesNegative);
+}
+
+TEST_F(CanBusVirtualHalTest, FilterMixed) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ /* clang-format off */
+ /* id, mask, rtr, eff exclude */
+ hidl_vec<CanMessageFilter> filterMixed = {
+ {0x000, 0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x0D5, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x046, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x11D89097, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x0AB, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x00D, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x0F82400E, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x08F, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x0BE, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0A271011, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x0BE, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x100, 0x700, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, false},
+ {0x138, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x1BF, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x13AB6165, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x17A, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x13C, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x102C5197, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x19B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x1B8, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0D6D5185, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x1B8, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x096A2200, 0x1FFFFF00, FilterFlag::DONT_CARE, FilterFlag::SET, false},
+ {0x201, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x22A, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x1D1C3238, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x2C0, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x23C, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x016182C6, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x27B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x2A5, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x160EB24B, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x2A5, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x300, 0x700, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false},
+ {0x339, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x3D4, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x182263BE, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x327, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x36B, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x1A1D8374, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x319, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x39E, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x1B657332, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x39E, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x06C5D400, 0x1FFFFF00, FilterFlag::NOT_SET, FilterFlag::SET, false},
+ {0x492, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x4EE, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x07725454, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x4D5, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x402, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x139714A7, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x464, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x454, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0EF4B46F, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x454, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x500, 0x700, FilterFlag::SET, FilterFlag::DONT_CARE, false},
+ {0x503, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x566, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x137605E7, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x564, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x58E, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x05F9052D, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x595, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x563, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x13358537, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x563, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x600, 0x700, FilterFlag::SET, FilterFlag::NOT_SET, false},
+ {0x64D, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x620, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x1069A676, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x62D, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x6C4, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x14C76629, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x689, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x6A4, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0BCCA6C2, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x6A4, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x04BB1700, 0x1FFFFF00, FilterFlag::SET, FilterFlag::SET, false},
+ {0x784, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x7F9, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x0200F77D, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x783, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x770, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x06602719, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x76B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x7DF, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x1939E736, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x7DF, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ };
+ /* clang-format on */
+
+ auto listenerMixed = bus2.listen(filterMixed);
+
+ bus1.send(makeMessage(0x000, true, true)); // positive filter
+ bus1.send(makeMessage(0x0D5, false, false));
+ bus1.send(makeMessage(0x046, true, false));
+ bus1.send(makeMessage(0x046, false, false));
+ bus1.send(makeMessage(0x11D89097, true, true));
+ bus1.send(makeMessage(0x11D89097, false, true));
+ bus1.send(makeMessage(0x0AB, false, false));
+ bus1.send(makeMessage(0x0AB, false, true));
+ bus1.send(makeMessage(0x00D, false, false));
+ bus1.send(makeMessage(0x0F82400E, false, true));
+ bus1.send(makeMessage(0x08F, true, false));
+ bus1.send(makeMessage(0x08F, true, true));
+ bus1.send(makeMessage(0x0BE, true, false));
+ bus1.send(makeMessage(0x0A271011, true, true));
+ bus1.send(makeMessage(0x0BE, false, true)); // not filtered
+ bus1.send(makeMessage(0x100, false, false)); // positive filter
+ bus1.send(makeMessage(0x138, false, true));
+ bus1.send(makeMessage(0x138, true, false));
+ bus1.send(makeMessage(0x1BF, false, false));
+ bus1.send(makeMessage(0x1BF, true, false));
+ bus1.send(makeMessage(0x13AB6165, false, true));
+ bus1.send(makeMessage(0x13AB6165, true, true));
+ bus1.send(makeMessage(0x17A, false, false));
+ bus1.send(makeMessage(0x17A, false, true));
+ bus1.send(makeMessage(0x13C, false, false));
+ bus1.send(makeMessage(0x102C5197, false, true));
+ bus1.send(makeMessage(0x19B, true, false));
+ bus1.send(makeMessage(0x19B, true, true));
+ bus1.send(makeMessage(0x1B8, true, false));
+ bus1.send(makeMessage(0x0D6D5185, true, true));
+ bus1.send(makeMessage(0x1B8, false, true)); // not filtered
+ bus1.send(makeMessage(0x096A2200, false, true)); // positive filter
+ bus1.send(makeMessage(0x201, false, true));
+ bus1.send(makeMessage(0x201, true, false));
+ bus1.send(makeMessage(0x22A, false, false));
+ bus1.send(makeMessage(0x22A, true, false));
+ bus1.send(makeMessage(0x1D1C3238, false, true));
+ bus1.send(makeMessage(0x1D1C3238, true, true));
+ bus1.send(makeMessage(0x2C0, false, false));
+ bus1.send(makeMessage(0x2C0, false, true));
+ bus1.send(makeMessage(0x23C, false, false));
+ bus1.send(makeMessage(0x016182C6, false, true));
+ bus1.send(makeMessage(0x27B, true, false));
+ bus1.send(makeMessage(0x27B, true, true));
+ bus1.send(makeMessage(0x2A5, true, false));
+ bus1.send(makeMessage(0x160EB24B, true, true));
+ bus1.send(makeMessage(0x2A5, false, true)); // not filtereed
+ bus1.send(makeMessage(0x300, false, false)); // positive filter
+ bus1.send(makeMessage(0x339, false, true));
+ bus1.send(makeMessage(0x339, false, false));
+ bus1.send(makeMessage(0x3D4, true, false));
+ bus1.send(makeMessage(0x182263BE, false, true));
+ bus1.send(makeMessage(0x182263BE, true, true));
+ bus1.send(makeMessage(0x327, false, false));
+ bus1.send(makeMessage(0x327, false, true));
+ bus1.send(makeMessage(0x36B, false, false));
+ bus1.send(makeMessage(0x1A1D8374, false, true));
+ bus1.send(makeMessage(0x319, true, false));
+ bus1.send(makeMessage(0x319, true, true));
+ bus1.send(makeMessage(0x39E, true, false));
+ bus1.send(makeMessage(0x1B657332, true, true));
+ bus1.send(makeMessage(0x39E, false, true)); // not filtered
+ bus1.send(makeMessage(0x06C5D400, false, true)); // positive filter
+ bus1.send(makeMessage(0x492, false, true));
+ bus1.send(makeMessage(0x492, true, false));
+ bus1.send(makeMessage(0x4EE, false, false));
+ bus1.send(makeMessage(0x4EE, true, false));
+ bus1.send(makeMessage(0x07725454, false, true));
+ bus1.send(makeMessage(0x07725454, true, true));
+ bus1.send(makeMessage(0x4D5, false, false));
+ bus1.send(makeMessage(0x4D5, false, true));
+ bus1.send(makeMessage(0x402, false, false));
+ bus1.send(makeMessage(0x139714A7, false, true));
+ bus1.send(makeMessage(0x464, true, false));
+ bus1.send(makeMessage(0x464, true, true));
+ bus1.send(makeMessage(0x454, true, false));
+ bus1.send(makeMessage(0x0EF4B46F, true, true));
+ bus1.send(makeMessage(0x454, false, true)); // not filtered
+ bus1.send(makeMessage(0x500, true, false)); // positive filter
+ bus1.send(makeMessage(0x503, false, true));
+ bus1.send(makeMessage(0x503, true, false));
+ bus1.send(makeMessage(0x566, false, false));
+ bus1.send(makeMessage(0x566, true, false));
+ bus1.send(makeMessage(0x137605E7, false, true));
+ bus1.send(makeMessage(0x137605E7, true, true));
+ bus1.send(makeMessage(0x564, false, false));
+ bus1.send(makeMessage(0x564, false, true));
+ bus1.send(makeMessage(0x58E, false, false));
+ bus1.send(makeMessage(0x05F9052D, false, true));
+ bus1.send(makeMessage(0x595, true, false));
+ bus1.send(makeMessage(0x595, true, true));
+ bus1.send(makeMessage(0x563, true, false));
+ bus1.send(makeMessage(0x13358537, true, true));
+ bus1.send(makeMessage(0x563, false, true)); // not filtered
+ bus1.send(makeMessage(0x600, true, false)); // positive filter
+ bus1.send(makeMessage(0x64D, false, true));
+ bus1.send(makeMessage(0x64D, true, false));
+ bus1.send(makeMessage(0x620, false, false));
+ bus1.send(makeMessage(0x620, true, false));
+ bus1.send(makeMessage(0x1069A676, false, true));
+ bus1.send(makeMessage(0x1069A676, true, true));
+ bus1.send(makeMessage(0x62D, false, false));
+ bus1.send(makeMessage(0x62D, false, true));
+ bus1.send(makeMessage(0x6C4, false, false));
+ bus1.send(makeMessage(0x14C76629, false, true));
+ bus1.send(makeMessage(0x689, true, false));
+ bus1.send(makeMessage(0x689, true, true));
+ bus1.send(makeMessage(0x6A4, true, false));
+ bus1.send(makeMessage(0x0BCCA6C2, true, true));
+ bus1.send(makeMessage(0x6A4, false, true)); // not filtered
+ bus1.send(makeMessage(0x04BB1700, true, true)); // positive filter
+ bus1.send(makeMessage(0x784, false, true));
+ bus1.send(makeMessage(0x784, true, false));
+ bus1.send(makeMessage(0x7F9, false, false));
+ bus1.send(makeMessage(0x7F9, true, false));
+ bus1.send(makeMessage(0x0200F77D, false, true));
+ bus1.send(makeMessage(0x0200F77D, true, true));
+ bus1.send(makeMessage(0x783, false, false));
+ bus1.send(makeMessage(0x783, false, true));
+ bus1.send(makeMessage(0x770, false, false));
+ bus1.send(makeMessage(0x06602719, false, true));
+ bus1.send(makeMessage(0x76B, true, false));
+ bus1.send(makeMessage(0x76B, true, true));
+ bus1.send(makeMessage(0x7DF, true, false));
+ bus1.send(makeMessage(0x1939E736, true, true));
+ bus1.send(makeMessage(0x7DF, false, true)); // not filtered
+
+ std::vector<can::V1_0::CanMessage> expectedMixed{
+ makeMessage(0x000, true, true), // 0x000:0x700, DONT_CARE, DONT_CARE
+ makeMessage(0x0BE, false, true),
+ makeMessage(0x100, false, false), // 0x100:0x700, DONT_CARE, NOT_SET
+ makeMessage(0x1B8, false, true),
+ makeMessage(0x096A2200, false, true), // 0x096A2200:0x1FFFFF00, DONT_CARE, SET
+ makeMessage(0x2A5, false, true),
+ makeMessage(0x300, false, false), // 0x300:0x700, NOT_SET, DONT_CARE
+ makeMessage(0x39E, false, true),
+ makeMessage(0x06C5D400, false, true), // 0x06C5D400:0x1FFFFF00, NOT_SET, SET
+ makeMessage(0x454, false, true),
+ makeMessage(0x500, true, false), // 0x500:0x700, SET, DONT_CARE
+ makeMessage(0x563, false, true),
+ makeMessage(0x600, true, false), // 0x600:0x700, SET, NOT_SET
+ makeMessage(0x6A4, false, true),
+ makeMessage(0x04BB1700, true, true), // 0x04BB1700:0x1FFFFF00, SET, SET
+ makeMessage(0x7DF, false, true),
+ };
+
+ auto messagesMixed = listenerMixed->fetchMessages(100ms, expectedMixed.size());
+ clearTimestamps(messagesMixed);
+ ASSERT_EQ(expectedMixed, messagesMixed);
+}
+
+} // namespace android::hardware::automotive::can::V1_0::vts
/**
* Example manual invocation:
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index 64e7a96..9bc789a 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -21,17 +21,13 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
#include <android/hardware/automotive/can/1.0/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
#include <can-vts-utils/can-hal-printers.h>
#include <can-vts-utils/environment-utils.h>
#include <gmock/gmock.h>
#include <hidl-utils/hidl-utils.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
+namespace android::hardware::automotive::can::V1_0::vts {
using hardware::hidl_vec;
using InterfaceType = ICanController::InterfaceType;
@@ -42,6 +38,7 @@
protected:
virtual void SetUp() override;
virtual void TearDown() override;
+ static void SetUpTestCase();
hidl_vec<InterfaceType> getSupportedInterfaceTypes();
bool isSupported(InterfaceType iftype);
@@ -51,9 +48,18 @@
void assertRegistered(const std::string srvname, bool expectRegistered);
sp<ICanController> mCanController;
+ static hidl_vec<hidl_string> mBusNames;
+
+ private:
+ static bool mTestCaseInitialized;
};
+hidl_vec<hidl_string> CanControllerHalTest::mBusNames;
+bool CanControllerHalTest::mTestCaseInitialized = false;
+
void CanControllerHalTest::SetUp() {
+ ASSERT_TRUE(mTestCaseInitialized);
+
const auto serviceName = gEnv->getServiceName<ICanController>();
mCanController = getService<ICanController>(serviceName);
ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
@@ -63,6 +69,13 @@
mCanController.clear();
}
+void CanControllerHalTest::SetUpTestCase() {
+ mBusNames = utils::getBusNames();
+ ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+ mTestCaseInitialized = true;
+}
+
hidl_vec<InterfaceType> CanControllerHalTest::getSupportedInterfaceTypes() {
hidl_vec<InterfaceType> iftypesResult;
mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk();
@@ -109,7 +122,7 @@
}
TEST_F(CanControllerHalTest, BringUpDown) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP();
@@ -127,7 +140,7 @@
}
TEST_F(CanControllerHalTest, UpTwice) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP();
@@ -216,7 +229,7 @@
}
TEST_F(CanControllerHalTest, FailBadVirtualAddress) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
@@ -224,7 +237,7 @@
}
TEST_F(CanControllerHalTest, FailBadSocketcanAddress) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
@@ -233,12 +246,7 @@
assertRegistered(name, false);
}
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::vts
/**
* Example manual invocation:
diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp
index e925c8f..d03ead3 100644
--- a/automotive/can/1.0/vts/utils/Android.bp
+++ b/automotive/can/1.0/vts/utils/Android.bp
@@ -14,7 +14,17 @@
// limitations under the License.
//
-cc_library_headers {
+cc_library_static {
name: "android.hardware.automotive.can@vts-utils-lib",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "bus-enumerator.cpp",
+ ],
export_include_dirs: ["include"],
+ header_libs: [
+ "android.hardware.automotive.can@hidl-utils-lib",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@1.0",
+ ],
}
diff --git a/automotive/can/1.0/vts/utils/bus-enumerator.cpp b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
new file mode 100644
index 0000000..c012dd2
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames() {
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ hidl_vec<hidl_string> services;
+ manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services));
+ return services;
+}
+
+} // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
new file mode 100644
index 0000000..ef385eb
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames();
+
+} // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
index 0923998..3c30744 100644
--- a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
@@ -18,11 +18,7 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
+namespace android::hardware::automotive::can::V1_0 {
/**
* Define gTest printer for a given HIDL type, but skip definition for Return<T>.
@@ -48,8 +44,4 @@
#undef DEFINE_CAN_HAL_PRINTER
#undef DEFINE_CAN_HAL_PRINTER_SIMPLE
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
index a722dd0..3eb9cc1 100644
--- a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
@@ -18,13 +18,7 @@
#include <VtsHalHidlTargetTestEnvBase.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
-namespace utils {
+namespace android::hardware::automotive::can::V1_0::vts::utils {
/**
* Simple test environment.
@@ -63,10 +57,4 @@
}
};
-} // namespace utils
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index 975b6c6..fc68e60 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -34,6 +34,23 @@
getCameraInfo_1_1() generates (CameraDesc info);
/**
+ * Returns the description of the physical camera device that backs this
+ * logical camera.
+ *
+ * If a requested device does not either exist or back this logical device,
+ * this method returns a null camera descriptor. And, if this is called on
+ * a physical camera device, this method is the same as getCameraInfo_1_1()
+ * method if a given device ID is matched. Otherwise, this will return a
+ * null camera descriptor.
+ *
+ * @param deviceId Physical camera device identifier string.
+ * @return info The description of a member physical camera device.
+ * This must be the same value as reported by
+ * EvsEnumerator::getCameraList_1_1().
+ */
+ getPhysicalCameraInfo(string deviceId) generates (CameraDesc info);
+
+ /**
* Requests to pause EVS camera stream events.
*
* Like stopVideoStream(), events may continue to arrive for some time
@@ -51,7 +68,7 @@
resumeVideoStream() generates (EvsResult result);
/**
- * Returns a frame that was delivered by to the IEvsCameraStream.
+ * Returns frame that were delivered by to the IEvsCameraStream.
*
* When done consuming a frame delivered to the IEvsCameraStream
* interface, it must be returned to the IEvsCamera for reuse.
@@ -59,10 +76,10 @@
* as one), and if the supply is exhausted, no further frames may be
* delivered until a buffer is returned.
*
- * @param buffer A buffer to be returned.
+ * @param buffer Buffers to be returned.
* @return result Return EvsResult::OK if this call is successful.
*/
- doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result);
+ doneWithFrame_1_1(vec<BufferDesc> buffer) generates (EvsResult result);
/**
* Requests to be a master client.
@@ -127,8 +144,13 @@
generates (int32_t min, int32_t max, int32_t step);
/**
- * Requests to set a camera parameter. Only a request from the master
- * client will be processed successfully.
+ * Requests to set a camera parameter.
+ *
+ * Only a request from the master client will be processed successfully.
+ * When this method is called on a logical camera device, it will be forwarded
+ * to each physical device and, if it fails to program any physical device,
+ * it will return an error code with the same number of effective values as
+ * the number of backing camera devices.
*
* @param id The identifier of camera parameter, CameraParam enum.
* value A desired parameter value.
@@ -138,21 +160,22 @@
* parameter is not supported.
* EvsResult::UNDERLYING_SERVICE_ERROR if it fails to
* program a value by any other reason.
- * effectiveValue A programmed parameter value. This may differ
+ * effectiveValue Programmed parameter values. This may differ
* from what the client gives if, for example, the
* driver does not support a target parameter.
*/
setIntParameter(CameraParam id, int32_t value)
- generates (EvsResult result, int32_t effectiveValue);
+ generates (EvsResult result, vec<int32_t> effectiveValue);
/**
- * Retrieves a value of given camera parameter.
+ * Retrieves values of given camera parameter.
*
* @param id The identifier of camera parameter, CameraParam enum.
* @return result EvsResult::OK if it succeeds to read a parameter.
* EvsResult::INVALID_ARG if either a requested parameter is
* not supported.
- * value A value of requested camera parameter.
+ * value Values of requested camera parameter, the same number of
+ * values as backing camera devices.
*/
- getIntParameter(CameraParam id) generates(EvsResult result, int32_t value);
+ getIntParameter(CameraParam id) generates(EvsResult result, vec<int32_t> value);
};
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
index 9e4ea19..aa35c62 100644
--- a/automotive/evs/1.1/IEvsCameraStream.hal
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -18,7 +18,7 @@
import @1.0::IEvsCameraStream;
import @1.1::BufferDesc;
-import @1.1::EvsEvent;
+import @1.1::EvsEventDesc;
/**
* Implemented on client side to receive asynchronous streaming event deliveries.
@@ -26,7 +26,7 @@
interface IEvsCameraStream extends @1.0::IEvsCameraStream {
/**
- * Receives calls from the HAL each time a video frame is ready for inspection.
+ * Receives calls from the HAL each time video frames is ready for inspection.
* Buffer handles received by this method must be returned via calls to
* IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call
* to IEvsCamera::stopVideoStream(), this callback may continue to happen for
@@ -35,14 +35,19 @@
* event must be delivered. No further frame deliveries may happen
* thereafter.
*
- * @param buffer a buffer descriptor of a delivered image frame.
+ * A camera device will deliver the same number of frames as number of
+ * backing physical camera devices; it means, a physical camera device
+ * sends always a single frame and a logical camera device sends multiple
+ * frames as many as number of backing physical camera devices.
+ *
+ * @param buffer Buffer descriptors of delivered image frames.
*/
- oneway deliverFrame_1_1(BufferDesc buffer);
+ oneway deliverFrame_1_1(vec<BufferDesc> buffer);
/**
* Receives calls from the HAL each time an event happens.
*
* @param event EVS event with possible event information.
*/
- oneway notify(EvsEvent event);
+ oneway notify(EvsEventDesc event);
};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index 41cb426..88fd657 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -16,7 +16,7 @@
shared_libs: [
"android.hardware.automotive.evs@1.0",
"android.hardware.automotive.evs@1.1",
- "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
"libbase",
"libbinder",
"liblog",
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
index 96a2f98..986793e 100644
--- a/automotive/evs/1.1/default/ConfigManager.cpp
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -42,55 +42,32 @@
while (curElem != nullptr) {
if (!strcmp(curElem->Name(), "group")) {
/* camera group identifier */
- const char *group_id = curElem->FindAttribute("group_id")->Value();
+ const char *id = curElem->FindAttribute("id")->Value();
- /* create CameraGroup */
- unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+ /* create a camera group to be filled */
+ CameraGroupInfo *aCamera = new CameraGroupInfo();
- /* add a camera device to its group */
- addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
-
- /* a list of camera stream configurations */
- const XMLElement *childElem =
- curElem->FirstChildElement("caps")->FirstChildElement("stream");
- while (childElem != nullptr) {
- /* read 5 attributes */
- const XMLAttribute *idAttr = childElem->FindAttribute("id");
- const XMLAttribute *widthAttr = childElem->FindAttribute("width");
- const XMLAttribute *heightAttr = childElem->FindAttribute("height");
- const XMLAttribute *fmtAttr = childElem->FindAttribute("format");
- const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate");
-
- const int32_t id = stoi(idAttr->Value());
- int32_t framerate = 0;
- if (fpsAttr != nullptr) {
- framerate = stoi(fpsAttr->Value());
- }
-
- int32_t pixFormat;
- if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
- pixFormat)) {
- RawStreamConfiguration cfg = {
- id,
- stoi(widthAttr->Value()),
- stoi(heightAttr->Value()),
- pixFormat,
- ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
- framerate
- };
- aCameraGroup->streamConfigurations[id] = cfg;
- }
-
- childElem = childElem->NextSiblingElement("stream");
+ /* read camera device information */
+ if (!readCameraDeviceInfo(aCamera, curElem)) {
+ ALOGW("Failed to read a camera information of %s", id);
+ delete aCamera;
+ continue;
}
/* camera group synchronization */
const char *sync = curElem->FindAttribute("synchronized")->Value();
- aCameraGroup->synchronized =
- static_cast<bool>(strcmp(sync, "false"));
+ if (!strcmp(sync, "CALIBRATED")) {
+ aCamera->synchronized =
+ ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
+ } else if (!strcmp(sync, "APPROXIMATE")) {
+ aCamera->synchronized =
+ ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
+ } else {
+ aCamera->synchronized = 0; // Not synchronized
+ }
/* add a group to hash map */
- mCameraGroups[group_id] = std::move(aCameraGroup);
+ mCameraGroupInfos.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
} else if (!strcmp(curElem->Name(), "device")) {
/* camera unique identifier */
const char *id = curElem->FindAttribute("id")->Value();
@@ -98,8 +75,18 @@
/* camera mount location */
const char *pos = curElem->FindAttribute("position")->Value();
+ /* create a camera device to be filled */
+ CameraInfo *aCamera = new CameraInfo();
+
+ /* read camera device information */
+ if (!readCameraDeviceInfo(aCamera, curElem)) {
+ ALOGW("Failed to read a camera information of %s", id);
+ delete aCamera;
+ continue;
+ }
+
/* store read camera module information */
- mCameraInfo[id] = readCameraDeviceInfo(curElem);
+ mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
/* assign a camera device to a position group */
mCameraPosition[pos].emplace(id);
@@ -113,15 +100,13 @@
}
-unique_ptr<ConfigManager::CameraInfo>
-ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
- if (aDeviceElem == nullptr) {
- return nullptr;
+bool
+ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera,
+ const XMLElement *aDeviceElem) {
+ if (aCamera == nullptr || aDeviceElem == nullptr) {
+ return false;
}
- /* create a CameraInfo to be filled */
- unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
-
/* size information to allocate camera_metadata_t */
size_t totalEntries = 0;
size_t totalDataSize = 0;
@@ -145,14 +130,15 @@
"allocated memory was not large enough");
}
- return aCamera;
+ return true;
}
-size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
- unique_ptr<ConfigManager::CameraInfo> &aCamera,
- size_t &dataSize) {
- if (aCapElem == nullptr) {
+size_t
+ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+ CameraInfo *aCamera,
+ size_t &dataSize) {
+ if (aCapElem == nullptr || aCamera == nullptr) {
return 0;
}
@@ -214,7 +200,7 @@
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
framerate
};
- aCamera->streamConfigurations[id] = cfg;
+ aCamera->streamConfigurations.insert_or_assign(id, cfg);
}
curElem = curElem->NextSiblingElement("stream");
@@ -232,10 +218,11 @@
}
-size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
- unique_ptr<ConfigManager::CameraInfo> &aCamera,
- size_t &dataSize) {
- if (aParamElem == nullptr) {
+size_t
+ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+ CameraInfo *aCamera,
+ size_t &dataSize) {
+ if (aParamElem == nullptr || aCamera == nullptr) {
return 0;
}
@@ -258,8 +245,9 @@
count
);
- aCamera->cameraMetadata[tag] =
- make_pair(make_unique<void *>(data), count);
+ aCamera->cameraMetadata.insert_or_assign(
+ tag, make_pair(make_unique<void *>(data), count)
+ );
++numEntries;
dataSize += calculate_camera_metadata_entry_data_size(
@@ -269,6 +257,52 @@
break;
}
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
+ camera_metadata_enum_android_request_available_capabilities_t *data =
+ new camera_metadata_enum_android_request_available_capabilities_t[1];
+ if (ConfigManagerUtil::convertToCameraCapability(
+ curElem->FindAttribute("value")->Value(), *data)) {
+ curElem->FindAttribute("value")->Value(),
+ aCamera->cameraMetadata.insert_or_assign(
+ tag, make_pair(make_unique<void *>(data), 1)
+ );
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), 1
+ );
+ }
+ break;
+ }
+
+ case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
+ /* a comma-separated list of physical camera devices */
+ size_t len = strlen(curElem->FindAttribute("value")->Value());
+ char *data = new char[len + 1];
+ memcpy(data,
+ curElem->FindAttribute("value")->Value(),
+ len * sizeof(char));
+
+ /* replace commas with null char */
+ char *p = data;
+ while (*p != '\0') {
+ if (*p == ',') {
+ *p = '\0';
+ }
+ ++p;
+ }
+
+ aCamera->cameraMetadata.insert_or_assign(
+ tag, make_pair(make_unique<void *>(data), len)
+ );
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), len
+ );
+ break;
+ }
+
default:
ALOGW("Parameter %s is not supported",
curElem->FindAttribute("name")->Value());
@@ -283,10 +317,11 @@
}
-bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
- const size_t totalEntries,
- const size_t totalDataSize) {
- if (!aCamera->allocate(totalEntries, totalDataSize)) {
+bool
+ConfigManager::constructCameraMetadata(CameraInfo *aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize) {
+ if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
ALOGE("Failed to allocate memory for camera metadata");
return false;
}
@@ -401,14 +436,14 @@
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
0 // unused
};
- dpy->streamConfigurations[id] = cfg;
+ dpy->streamConfigurations.insert_or_assign(id, cfg);
}
curStream = curStream->NextSiblingElement("stream");
}
}
- mDisplayInfo[id] = std::move(dpy);
+ mDisplayInfo.insert_or_assign(id, std::move(dpy));
curDev = curDev->NextSiblingElement("device");
}
@@ -457,16 +492,6 @@
}
-void ConfigManager::addCameraDevices(const char *devices,
- unique_ptr<CameraGroup> &aGroup) {
- stringstream device_list(devices);
- string token;
- while (getline(device_list, token, ',')) {
- aGroup->devices.emplace(token);
- }
-}
-
-
std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
index 0275f90..870af1c 100644
--- a/automotive/evs/1.1/default/ConfigManager.h
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -82,9 +82,6 @@
unordered_map<CameraParam,
tuple<int32_t, int32_t, int32_t>> controls;
- /* List of supported frame rates */
- unordered_set<int32_t> frameRates;
-
/*
* List of supported output stream configurations; each array stores
* format, width, height, and direction values in the order.
@@ -102,21 +99,15 @@
camera_metadata_t *characteristics;
};
- class CameraGroup {
+ class CameraGroupInfo : public CameraInfo {
public:
- CameraGroup() {}
+ CameraGroupInfo() {}
/* ID of member camera devices */
unordered_set<string> devices;
/* The capture operation of member camera devices are synchronized */
bool synchronized = false;
-
- /*
- * List of stream configurations that are supposed by all camera devices
- * in this group.
- */
- unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
};
class SystemInfo {
@@ -165,11 +156,11 @@
/*
* Return a list of cameras
*
- * @return CameraGroup
+ * @return CameraGroupInfo
* A pointer to a camera group identified by a given id.
*/
- unique_ptr<CameraGroup>& getCameraGroup(const string& gid) {
- return mCameraGroups[gid];
+ unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const string& gid) {
+ return mCameraGroupInfos[gid];
}
@@ -203,8 +194,8 @@
/* Internal data structure for camera device information */
unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
- /* Camera groups are stored in <groud id, CameraGroup> hash map */
- unordered_map<string, unique_ptr<CameraGroup>> mCameraGroups;
+ /* Camera groups are stored in <groud id, CameraGroupInfo> hash map */
+ unordered_map<string, unique_ptr<CameraGroupInfo>> mCameraGroupInfos;
/*
* Camera positions are stored in <position, camera id set> hash map.
@@ -253,16 +244,19 @@
/*
* read camera device information
*
- * @param aDeviceElem
+ * @param aCamera
+ * A pointer to CameraInfo that will be completed by this
+ * method.
+ * aDeviceElem
* A pointer to "device" XML element that contains camera module
* capability info and its characteristics.
*
- * @return unique_ptr<CameraInfo>
- * A pointer to CameraInfo class that contains camera module
- * capability and characteristics. Please note that this transfers
- * the ownership of created CameraInfo to the caller.
+ * @return bool
+ * Return false upon any failure in reading and processing camera
+ * device information.
*/
- unique_ptr<CameraInfo> readCameraDeviceInfo(const XMLElement *aDeviceElem);
+ bool readCameraDeviceInfo(CameraInfo *aCamera,
+ const XMLElement *aDeviceElem);
/*
* read camera metadata
@@ -280,7 +274,7 @@
* Number of camera metadata entries
*/
size_t readCameraCapabilities(const XMLElement * const aCapElem,
- unique_ptr<CameraInfo> &aCamera,
+ CameraInfo *aCamera,
size_t &dataSize);
/*
@@ -298,7 +292,7 @@
* Number of camera metadata entries
*/
size_t readCameraMetadata(const XMLElement * const aParamElem,
- unique_ptr<CameraInfo> &aCamera,
+ CameraInfo *aCamera,
size_t &dataSize);
/*
@@ -316,21 +310,9 @@
* or its size is not large enough to add all found camera metadata
* entries.
*/
- bool constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+ bool constructCameraMetadata(CameraInfo *aCamera,
const size_t totalEntries,
const size_t totalDataSize);
-
- /*
- * parse a comma-separated list of camera devices and add them to
- * CameraGroup.
- *
- * @param devices
- * A comma-separated list of camera device identifiers.
- * @param aGroup
- * Camera group which cameras will be added to.
- */
- void addCameraDevices(const char *devices,
- unique_ptr<CameraGroup> &aGroup);
};
#endif // CONFIG_MANAGER_H
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
index 8206daa..d10f236 100644
--- a/automotive/evs/1.1/default/ConfigManagerUtil.cpp
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -90,6 +90,30 @@
aTag = ANDROID_LENS_POSE_ROTATION;
} else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
aTag = ANDROID_LENS_POSE_TRANSLATION;
+ } else if (!strcmp(name, "REQUEST_AVAILABLE_CAPABILITIES")) {
+ aTag = ANDROID_REQUEST_AVAILABLE_CAPABILITIES;
+ } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA_PHYSICAL_IDS")) {
+ aTag = ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+
+bool ConfigManagerUtil::convertToCameraCapability(
+ const char *name,
+ camera_metadata_enum_android_request_available_capabilities_t &cap) {
+
+ if (!strcmp(name, "DEPTH_OUTPUT")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT;
+ } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+ } else if (!strcmp(name, "MONOCHROME")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME;
+ } else if (!strcmp(name, "SECURE_IMAGE_DATA")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;
} else {
return false;
}
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
index 8c89ae7..1710cac 100644
--- a/automotive/evs/1.1/default/ConfigManagerUtil.h
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -55,6 +55,14 @@
*/
static string trimString(const string &src,
const string &ws = " \n\r\t\f\v");
+
+ /**
+ * Convert a given string to corresponding camera capabilities
+ */
+ static bool convertToCameraCapability(
+ const char *name,
+ camera_metadata_enum_android_request_available_capabilities_t &cap);
+
};
#endif // CONFIG_MANAGER_UTIL_H
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 5ba753d..b7e4efa 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -21,7 +21,7 @@
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
-
+#include <utils/SystemClock.h>
namespace android {
namespace hardware {
@@ -240,9 +240,23 @@
}
-Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) {
+Return<void> EvsCamera::getPhysicalCameraInfo(const hidl_string& id,
+ getCameraInfo_1_1_cb _hidl_cb) {
+ ALOGD("%s", __FUNCTION__);
+
+ // This works exactly same as getCameraInfo_1_1() in default implementation.
+ (void)id;
+ _hidl_cb(mDescription);
+ return Void();
+}
+
+
+Return<EvsResult> EvsCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
std::lock_guard <std::mutex> lock(mAccessLock);
- returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
+
+ for (auto&& buffer : buffers) {
+ returnBuffer(buffer.bufferId, buffer.buffer.nativeHandle);
+ }
return EvsResult::OK;
}
@@ -490,12 +504,17 @@
newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
newBuffer.pixelSize = sizeof(uint32_t);
newBuffer.bufferId = idx;
+ newBuffer.deviceId = mDescription.v1.cameraId;
+ newBuffer.timestamp = elapsedRealtimeNano();
// Write test data into the image buffer
fillTestFrame(newBuffer);
// Issue the (asynchronous) callback to the client -- can't be holding the lock
- auto result = mStream->deliverFrame_1_1(newBuffer);
+ hidl_vec<BufferDesc_1_1> frames;
+ frames.resize(1);
+ frames[0] = newBuffer;
+ auto result = mStream->deliverFrame_1_1(frames);
if (result.isOk()) {
ALOGD("Delivered %p as id %d",
newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
@@ -527,7 +546,7 @@
}
// If we've been asked to stop, send an event to signal the actual end of stream
- EvsEvent event;
+ EvsEventDesc event;
event.aType = EvsEventType::STREAM_STOPPED;
auto result = mStream->notify(event);
if (!result.isOk()) {
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index c15b4b1..72a1b57 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -62,9 +62,11 @@
// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
Return<void> getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override;
+ Return<void> getPhysicalCameraInfo(const hidl_string& id,
+ getPhysicalCameraInfo_cb _hidl_cb) override;
Return<EvsResult> pauseVideoStream() override;
Return<EvsResult> resumeVideoStream() override;
- Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
+ Return<EvsResult> doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
Return<EvsResult> setMaster() override;
Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
Return<EvsResult> unsetMaster() override;
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
index 692102e..a79e7c2 100644
--- a/automotive/evs/1.1/default/resources/evs_default_configuration.xml
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -28,8 +28,31 @@
<num_cameras value='1'/>
</system>
- <!-- camera device information -->
+ <!-- camera information -->
<camera>
+ <!-- camera group starts -->
+ <group id='group1' synchronized='APPROXIMATE'>
+ <caps>
+ <stream id='0' width='640' height='360' format='RGBA_8888' framerate='30'/>
+ </caps>
+
+ <!-- list of parameters -->
+ <characteristics>
+ <parameter
+ name='REQUEST_AVAILABLE_CAPABILITIES'
+ type='enum'
+ size='1'
+ value='LOGICAL_MULTI_CAMERA'
+ />
+ <parameter
+ name='LOGICAL_MULTI_CAMERA_PHYSICAL_IDS'
+ type='byte[]'
+ size='1'
+ value='/dev/video1'
+ />
+ </characteristics>
+ </group>
+
<!-- camera device starts -->
<device id='/dev/video1' position='rear'>
<caps>
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index dcb2abb..f88d223 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -61,6 +61,14 @@
* Opaque value from driver
*/
uint32_t bufferId;
+ /**
+ * Unique identifier of the physical camera device that produces this buffer.
+ */
+ string deviceId;
+ /**
+ * Time that this buffer is being filled.
+ */
+ int64_t timestamp;
};
/**
@@ -97,12 +105,16 @@
/**
* Structure that describes informative events occurred during EVS is streaming
*/
-struct EvsEvent {
+struct EvsEventDesc {
/**
* Type of an informative event
*/
EvsEventType aType;
/**
+ * Device identifier
+ */
+ string deviceId;
+ /**
* Possible additional information
*/
uint32_t[4] payload;
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index 6d53652..ebf488a 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -80,7 +80,7 @@
asyncStopStream();
// Wait until the stream has actually stopped
- std::unique_lock<std::mutex> lock(mLock);
+ std::unique_lock<std::mutex> lock(mEventLock);
if (mRunning) {
mEventSignal.wait(lock, [this]() { return !mRunning; });
}
@@ -88,7 +88,7 @@
bool FrameHandler::returnHeldBuffer() {
- std::unique_lock<std::mutex> lock(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
// Return the oldest buffer we're holding
if (mHeldBuffers.empty()) {
@@ -96,16 +96,16 @@
return false;
}
- BufferDesc_1_1 buffer = mHeldBuffers.front();
+ hidl_vec<BufferDesc_1_1> buffers = mHeldBuffers.front();
mHeldBuffers.pop();
- mCamera->doneWithFrame_1_1(buffer);
+ mCamera->doneWithFrame_1_1(buffers);
return true;
}
bool FrameHandler::isRunning() {
- std::unique_lock<std::mutex> lock(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
return mRunning;
}
@@ -120,7 +120,7 @@
void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
- std::unique_lock<std::mutex> lock(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
if (received) {
*received = mFramesReceived;
@@ -138,11 +138,17 @@
}
-Return<void> FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) {
+Return<void> FrameHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
+ mLock.lock();
+ // For VTS tests, FrameHandler uses a single frame among delivered frames.
+ auto bufferIdx = mFramesDisplayed % buffers.size();
+ auto buffer = buffers[bufferIdx];
+ mLock.unlock();
+
const AHardwareBuffer_Desc* pDesc =
- reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&buffer.buffer.description);
ALOGD("Received a frame from the camera (%p)",
- bufDesc.buffer.nativeHandle.getNativeHandle());
+ buffer.buffer.nativeHandle.getNativeHandle());
// Store a dimension of a received frame.
mFrameWidth = pDesc->width;
@@ -150,6 +156,7 @@
// If we were given an opened display at construction time, then send the received
// image back down the camera.
+ bool displayed = false;
if (mDisplay.get()) {
// Get the output buffer we'll use to display the imagery
BufferDesc_1_0 tgtBuffer = {};
@@ -163,7 +170,7 @@
ALOGE("Didn't get requested output buffer -- skipping this frame.");
} else {
// Copy the contents of the of buffer.memHandle into tgtBuffer
- copyBufferContents(tgtBuffer, bufDesc);
+ copyBufferContents(tgtBuffer, buffer);
// Send the target buffer back for display
Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
@@ -179,40 +186,42 @@
} else {
// Everything looks good!
// Keep track so tests or watch dogs can monitor progress
- mLock.lock();
- mFramesDisplayed++;
- mLock.unlock();
+ displayed = true;
}
}
}
+ mLock.lock();
+ // increases counters
+ ++mFramesReceived;
+ mFramesDisplayed += (int)displayed;
+ mLock.unlock();
+ mFrameSignal.notify_all();
switch (mReturnMode) {
case eAutoReturn:
// Send the camera buffer back now that the client has seen it
ALOGD("Calling doneWithFrame");
- mCamera->doneWithFrame_1_1(bufDesc);
+ mCamera->doneWithFrame_1_1(buffers);
break;
case eNoAutoReturn:
- // Hang onto the buffer handle for now -- the client will return it explicitly later
- mHeldBuffers.push(bufDesc);
+ // Hang onto the buffer handles for now -- the client will return it explicitly later
+ mHeldBuffers.push(buffers);
+ break;
}
- mLock.lock();
- ++mFramesReceived;
- mLock.unlock();
- mFrameSignal.notify_all();
-
ALOGD("Frame handling complete");
return Void();
}
-Return<void> FrameHandler::notify(const EvsEvent& event) {
+Return<void> FrameHandler::notify(const EvsEventDesc& event) {
// Local flag we use to keep track of when the stream is stopping
- mLock.lock();
- mLatestEventDesc = event;
+ std::unique_lock<std::mutex> lock(mEventLock);
+ mLatestEventDesc.aType = event.aType;
+ mLatestEventDesc.payload[0] = event.payload[0];
+ mLatestEventDesc.payload[1] = event.payload[1];
if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
// Signal that the last frame has been received and the stream is stopped
mRunning = false;
@@ -222,8 +231,8 @@
} else {
ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
}
- mLock.unlock();
- mEventSignal.notify_all();
+ lock.unlock();
+ mEventSignal.notify_one();
return Void();
}
@@ -342,25 +351,34 @@
}
}
-bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent,
- EvsEvent &event) {
+bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent,
+ EvsEventDesc& aReceivedEvent,
+ bool ignorePayload) {
// Wait until we get an expected parameter change event.
- std::unique_lock<std::mutex> lock(mLock);
+ std::unique_lock<std::mutex> lock(mEventLock);
auto now = std::chrono::system_clock::now();
- bool result = mEventSignal.wait_until(lock, now + 5s,
- [this, aTargetEvent, &event](){
- bool flag = mLatestEventDesc.aType == aTargetEvent;
- if (flag) {
- event.aType = mLatestEventDesc.aType;
- event.payload[0] = mLatestEventDesc.payload[0];
- event.payload[1] = mLatestEventDesc.payload[1];
+ bool found = false;
+ while (!found) {
+ bool result = mEventSignal.wait_until(lock, now + 5s,
+ [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found](){
+ found = (mLatestEventDesc.aType == aTargetEvent.aType) &&
+ (ignorePayload || (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] &&
+ mLatestEventDesc.payload[1] == aTargetEvent.payload[1]));
+
+ aReceivedEvent.aType = mLatestEventDesc.aType;
+ aReceivedEvent.payload[0] = mLatestEventDesc.payload[0];
+ aReceivedEvent.payload[1] = mLatestEventDesc.payload[1];
+ return found;
}
+ );
- return flag;
+ if (!result) {
+ ALOGW("A timer is expired before a target event has happened.");
+ break;
}
- );
+ }
- return !result;
+ return found;
}
const char *FrameHandler::eventToString(const EvsEventType aType) {
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index e5f1b8f..21e85fe 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -73,8 +73,9 @@
bool isRunning();
void waitForFrameCount(unsigned frameCount);
- bool waitForEvent(const EvsEventType aTargetEvent,
- EvsEvent &eventDesc);
+ bool waitForEvent(const EvsEventDesc& aTargetEvent,
+ EvsEventDesc& aReceivedEvent,
+ bool ignorePayload = false);
void getFramesCounters(unsigned* received, unsigned* displayed);
void getFrameDimension(unsigned* width, unsigned* height);
@@ -83,8 +84,8 @@
Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
// Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
- Return<void> deliverFrame_1_1(const BufferDesc_1_1& buffer) override;
- Return<void> notify(const EvsEvent& event) override;
+ Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
+ Return<void> notify(const EvsEventDesc& event) override;
// Local implementation details
bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
@@ -99,17 +100,18 @@
// Since we get frames delivered to us asynchronously via the IEvsCameraStream interface,
// we need to protect all member variables that may be modified while we're streaming
// (ie: those below)
- std::mutex mLock;
- std::condition_variable mEventSignal;
- std::condition_variable mFrameSignal;
+ std::mutex mLock;
+ std::mutex mEventLock;
+ std::condition_variable mEventSignal;
+ std::condition_variable mFrameSignal;
+ std::queue<hidl_vec<BufferDesc_1_1>> mHeldBuffers;
- std::queue<BufferDesc_1_1> mHeldBuffers;
bool mRunning = false;
unsigned mFramesReceived = 0; // Simple counter -- rolls over eventually!
unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually!
unsigned mFrameWidth = 0;
unsigned mFrameHeight = 0;
- EvsEvent mLatestEventDesc;
+ EvsEventDesc mLatestEventDesc;
};
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 1d3fd87..4fc4e4c 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -41,6 +41,8 @@
#include <cstdio>
#include <cstring>
#include <cstdlib>
+#include <thread>
+#include <unordered_set>
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/ProcessState.h>
@@ -67,6 +69,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::sp;
+using ::android::wp;
using ::android::hardware::camera::device::V3_2::Stream;
using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
using ::android::hardware::automotive::evs::V1_0::DisplayState;
@@ -117,7 +120,15 @@
mIsHwModule = !service_name.compare(kEnumeratorName);
}
- virtual void TearDown() override {}
+ virtual void TearDown() override {
+ // Attempt to close any active camera
+ for (auto &&c : activeCameras) {
+ sp<IEvsCamera_1_1> cam = c.promote();
+ if (cam != nullptr) {
+ pEnumerator->closeCamera(cam);
+ }
+ }
+ }
protected:
void loadCameraList() {
@@ -141,10 +152,90 @@
ASSERT_GE(cameraInfo.size(), 1u);
}
- sp<IEvsEnumerator> pEnumerator; // Every test needs access to the service
- std::vector <CameraDesc> cameraInfo; // Empty unless/until loadCameraList() is called
- bool mIsHwModule; // boolean to tell current module under testing
- // is HW module implementation.
+ bool isLogicalCamera(const camera_metadata_t *metadata) {
+ if (metadata == nullptr) {
+ // A logical camera device must have a valid camera metadata.
+ return false;
+ }
+
+ // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
+ camera_metadata_ro_entry_t entry;
+ int rc = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ &entry);
+ if (0 != rc) {
+ // No capabilities are found.
+ return false;
+ }
+
+ for (size_t i = 0; i < entry.count; ++i) {
+ uint8_t cap = entry.data.u8[i];
+ if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ std::unordered_set<std::string> getPhysicalCameraIds(const std::string& id,
+ bool& flag) {
+ std::unordered_set<std::string> physicalCameras;
+
+ auto it = cameraInfo.begin();
+ while (it != cameraInfo.end()) {
+ if (it->v1.cameraId == id) {
+ break;
+ }
+ ++it;
+ }
+
+ if (it == cameraInfo.end()) {
+ // Unknown camera is requested. Return an empty list.
+ return physicalCameras;
+ }
+
+ const camera_metadata_t *metadata =
+ reinterpret_cast<camera_metadata_t *>(&it->metadata[0]);
+ flag = isLogicalCamera(metadata);
+ if (!flag) {
+ // EVS assumes that the device w/o a valid metadata is a physical
+ // device.
+ ALOGI("%s is not a logical camera device.", id.c_str());
+ physicalCameras.emplace(id);
+ return physicalCameras;
+ }
+
+ // Look for physical camera identifiers
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(metadata,
+ ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+ &entry);
+ ALOGE_IF(rc, "No physical camera ID is found for a logical camera device");
+
+ const uint8_t *ids = entry.data.u8;
+ size_t start = 0;
+ for (size_t i = 0; i < entry.count; ++i) {
+ if (ids[i] == '\0') {
+ if (start != i) {
+ std::string id(reinterpret_cast<const char *>(ids + start));
+ physicalCameras.emplace(id);
+ }
+ start = i + 1;
+ }
+ }
+
+ ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size());
+ return physicalCameras;
+ }
+
+
+ sp<IEvsEnumerator> pEnumerator; // Every test needs access to the service
+ std::vector<CameraDesc> cameraInfo; // Empty unless/until loadCameraList() is called
+ bool mIsHwModule; // boolean to tell current module under testing
+ // is HW module implementation.
+ std::deque<wp<IEvsCamera_1_1>> activeCameras; // A list of active camera handles that are
+ // needed to be cleaned up.
};
@@ -168,12 +259,32 @@
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+
for (int pass = 0; pass < 2; pass++) {
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ for (auto&& devName : devices) {
+ bool matched = false;
+ pCam->getPhysicalCameraInfo(devName,
+ [&devName, &matched](const CameraDesc& info) {
+ matched = devName == info.v1.cameraId;
+ });
+ ASSERT_TRUE(matched);
+ }
+
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Verify that this camera self-identifies correctly
pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
ALOGD("Found camera %s", desc.v1.cameraId.c_str());
@@ -206,11 +317,22 @@
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Verify that this camera self-identifies correctly
pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
ALOGD("Found camera %s", desc.v1.cameraId.c_str());
@@ -221,9 +343,13 @@
sp<IEvsCamera_1_1> pCam2 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCam, pCam2);
ASSERT_NE(pCam2, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam2);
+
+ ASSERT_NE(pCam, pCam2);
+
Return<EvsResult> result = pCam->setMaxFramesInFlight(2);
if (mIsHwModule) {
// Verify that the old camera rejects calls via HW module.
@@ -268,11 +394,22 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Set up a frame receiver object which will fire up its own thread
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
nullptr,
@@ -280,6 +417,7 @@
// Start the camera's video stream
nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+
bool startResult = frameHandler->startStream();
ASSERT_TRUE(startResult);
@@ -287,9 +425,17 @@
frameHandler->waitForFrameCount(1);
nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start;
- EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame), kMaxStreamStartMilliseconds);
- printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds);
- ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds);
+
+ // Extra delays are expected when we attempt to start a video stream on
+ // the logical camera device. The amount of delay is expected the
+ // number of physical camera devices multiplied by
+ // kMaxStreamStartMilliseconds at most.
+ EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame),
+ kMaxStreamStartMilliseconds * devices.size());
+ printf("%s: Measured time to first frame %0.2f ms\n",
+ cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
+ ALOGI("%s: Measured time to first frame %0.2f ms",
+ cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
// Check aspect ratio
unsigned width = 0, height = 0;
@@ -299,6 +445,13 @@
// Wait a bit, then ensure we get at least the required minimum number of frames
sleep(5);
nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Even when the camera pointer goes out of scope, the FrameHandler object will
+ // keep the stream alive unless we tell it to shutdown.
+ // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+ // we have to break that cycle in order for either of them to get cleaned up.
+ frameHandler->shutdown();
+
unsigned framesReceived = 0;
frameHandler->getFramesCounters(&framesReceived, nullptr);
framesReceived = framesReceived - 1; // Back out the first frame we already waited for
@@ -308,12 +461,6 @@
ALOGI("Measured camera rate %3.2f fps", framesPerSecond);
EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
- // Even when the camera pointer goes out of scope, the FrameHandler object will
- // keep the stream alive unless we tell it to shutdown.
- // Also note that the FrameHandle and the Camera have a mutual circular reference, so
- // we have to break that cycle in order for either of them to get cleaned up.
- frameHandler->shutdown();
-
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
}
@@ -340,12 +487,22 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Ask for a crazy number of buffers in flight to ensure it errors correctly
Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
@@ -366,7 +523,7 @@
// Check that the video stream stalls once we've gotten exactly the number of buffers
// we requested since we told the frameHandler not to return them.
- sleep(2); // 1 second should be enough for at least 5 frames to be delivered worst case
+ sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case
unsigned framesReceived = 0;
frameHandler->getFramesCounters(&framesReceived, nullptr);
ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
@@ -416,11 +573,22 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Set up a frame receiver object which will fire up its own thread.
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
pDisplay,
@@ -484,17 +652,24 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCam0 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
sp<IEvsCamera_1_1> pCam1 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam1);
+
// Set up per-client frame receiver objects which will fire up its own thread
sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
nullptr,
@@ -554,6 +729,11 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam0);
pEnumerator->closeCamera(pCam1);
+
+ // TODO(b/145459970, b/145457727): below sleep() is added to ensure the
+ // destruction of active camera objects; this may be related with two
+ // issues.
+ sleep(1);
}
}
@@ -575,12 +755,25 @@
// Test each reported camera
Return<EvsResult> result = EvsResult::OK;
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
// Create a camera client
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera
+ activeCameras.push_back(pCam);
+
// Get the parameter list
std::vector<CameraParam> cmds;
pCam->getParameterList([&cmds](hidl_vec<CameraParam> cmdList) {
@@ -626,48 +819,54 @@
EvsResult result = EvsResult::OK;
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
- int32_t val1 = 0;
- pCam->getIntParameter(CameraParam::AUTO_FOCUS,
- [&result, &val1](auto status, auto value) {
+ std::vector<int32_t> values;
+ pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
}
});
- if (val1 != 0) {
- pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
}
}
// Try to program a parameter with a random value [minVal, maxVal]
int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
- int32_t val1 = 0;
+ std::vector<int32_t> values;
// Rounding down
val0 = val0 - (val0 % step);
pCam->setIntParameter(cmd, val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
+ values.clear();
pCam->getIntParameter(cmd,
- [&result, &val1](auto status, auto value) {
+ [&result, &values](auto status, auto readValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : readValues) {
+ values.push_back(v);
+ }
}
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
}
result = pCam->unsetMaster();
@@ -704,16 +903,33 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
+
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamMaster);
+
sp<IEvsCamera_1_1> pCamNonMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamNonMaster);
+
// Set up per-client frame receiver objects which will fire up its own thread
sp<FrameHandler> frameHandlerMaster =
new FrameHandler(pCamMaster, cam,
@@ -750,13 +966,45 @@
// Non-master client expects to receive a master role relesed
// notification.
- EvsEvent aNotification = {};
+ EvsEventDesc aTargetEvent = {};
+ EvsEventDesc aNotification = {};
+
+ bool listening = false;
+ std::mutex eventLock;
+ std::condition_variable eventCond;
+ std::thread listener = std::thread(
+ [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+ // Notify that a listening thread is running.
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+
+ }
+ );
+
+ // Wait until a listening thread starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ timer += 1s;
+ eventCond.wait_until(lock, timer);
+ }
+ lock.unlock();
// Release a master role.
pCamMaster->unsetMaster();
- // Verify a change notification.
- frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
ASSERT_EQ(EvsEventType::MASTER_RELEASED,
static_cast<EvsEventType>(aNotification.aType));
@@ -768,23 +1016,49 @@
result = pCamMaster->setMaster();
ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+ listening = false;
+ listener = std::thread(
+ [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+ // Notify that a listening thread is running.
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+
+ }
+ );
+
+ // Wait until a listening thread starts.
+ timer = std::chrono::system_clock::now();
+ lock.lock();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
// Closing current master client.
frameHandlerNonMaster->shutdown();
- // Verify a change notification.
- frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
ASSERT_EQ(EvsEventType::MASTER_RELEASED,
static_cast<EvsEventType>(aNotification.aType));
- // Closing another stream.
+ // Closing streams.
frameHandlerMaster->shutdown();
// Explicitly release the camera
pEnumerator->closeCamera(pCamMaster);
pEnumerator->closeCamera(pCamNonMaster);
}
-
-
}
@@ -810,16 +1084,33 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
+
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamMaster);
+
sp<IEvsCamera_1_1> pCamNonMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamNonMaster);
+
// Get the parameter list
std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
@@ -879,7 +1170,9 @@
frameHandlerNonMaster->waitForFrameCount(1);
int32_t val0 = 0;
- int32_t val1 = 0;
+ std::vector<int32_t> values;
+ EvsEventDesc aNotification0 = {};
+ EvsEventDesc aNotification1 = {};
for (auto &cmd : camMasterCmds) {
// Get a valid parameter value range
int32_t minVal, maxVal, step;
@@ -895,60 +1188,143 @@
EvsResult result = EvsResult::OK;
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
- int32_t val1 = 1;
+ values.clear();
pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
+ }
}
- // Try to program a parameter
+ // Calculate a parameter value to program.
val0 = minVal + (std::rand() % (maxVal - minVal));
-
- // Rounding down
val0 = val0 - (val0 % step);
+
+ // Prepare and start event listeners.
+ bool listening0 = false;
+ bool listening1 = false;
+ std::condition_variable eventCond;
+ std::thread listener0 = std::thread(
+ [cmd, val0,
+ &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ listening0 = true;
+ if (listening1) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+ std::thread listener1 = std::thread(
+ [cmd, val0,
+ &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ listening1 = true;
+ if (listening0) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a listening thread starts.
+ std::mutex eventLock;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening0 || !listening1) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to program a parameter
+ values.clear();
pCamMaster->setIntParameter(cmd, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
-
- // Wait a moment
- sleep(1);
-
- // Non-master client expects to receive a parameter change notification
- // whenever a master client adjusts it.
- EvsEvent aNotification = {};
-
- pCamMaster->getIntParameter(cmd,
- [&result, &val1](auto status, auto value) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
+ });
+
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
+
+ // Join a listening thread.
+ if (listener0.joinable()) {
+ listener0.join();
+ }
+ if (listener1.joinable()) {
+ listener1.join();
+ }
+
+ // Verify a change notification
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification0.aType));
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification1.aType));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification0.payload[0]));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification1.payload[0]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification0.payload[1]));
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification1.payload[1]));
+ }
+
+ // Clients expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ values.clear();
+ pCamMaster->getIntParameter(cmd,
+ [&result, &values](auto status, auto readValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : readValues) {
+ values.push_back(v);
+ }
}
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
-
- // Verify a change notification
- frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
- static_cast<EvsEventType>(aNotification.aType));
- ASSERT_EQ(cmd,
- static_cast<CameraParam>(aNotification.payload[0]));
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
}
// Try to adjust a parameter via non-master client
+ values.clear();
pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
@@ -957,14 +1333,48 @@
ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
// Master client retires from a master role
+ bool listening = false;
+ std::condition_variable eventCond;
+ std::thread listener = std::thread(
+ [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ std::mutex eventLock;
+ auto timer = std::chrono::system_clock::now();
+ unique_lock<std::mutex> lock(eventLock);
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
result = pCamMaster->unsetMaster();
ASSERT_EQ(EvsResult::OK, result);
+ if (listener.joinable()) {
+ listener.join();
+ }
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification0.aType));
+
// Try to adjust a parameter after being retired
+ values.clear();
pCamMaster->setIntParameter(camMasterCmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
@@ -986,55 +1396,128 @@
);
EvsResult result = EvsResult::OK;
+ values.clear();
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
- int32_t val1 = 1;
+ values.clear();
pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
+ }
}
- // Try to program a parameter
+ // Calculate a parameter value to program. This is being rounding down.
val0 = minVal + (std::rand() % (maxVal - minVal));
-
- // Rounding down
val0 = val0 - (val0 % step);
+
+ // Prepare and start event listeners.
+ bool listening0 = false;
+ bool listening1 = false;
+ std::condition_variable eventCond;
+ std::thread listener0 = std::thread(
+ [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ listening0 = true;
+ if (listening1) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+ std::thread listener1 = std::thread(
+ [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ listening1 = true;
+ if (listening0) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a listening thread starts.
+ std::mutex eventLock;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening0 || !listening1) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to program a parameter
+ values.clear();
pCamNonMaster->setIntParameter(cmd, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
-
- // Wait a moment
- sleep(1);
-
- // Non-master client expects to receive a parameter change notification
- // whenever a master client adjusts it.
- EvsEvent aNotification = {};
-
- pCamNonMaster->getIntParameter(cmd,
- [&result, &val1](auto status, auto value) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
}
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+ // Clients expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ values.clear();
+ pCamNonMaster->getIntParameter(cmd,
+ [&result, &values](auto status, auto readValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : readValues) {
+ values.push_back(v);
+ }
+ }
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
+
+ // Join a listening thread.
+ if (listener0.joinable()) {
+ listener0.join();
+ }
+ if (listener1.joinable()) {
+ listener1.join();
+ }
// Verify a change notification
- frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
- static_cast<EvsEventType>(aNotification.aType));
+ static_cast<EvsEventType>(aNotification0.aType));
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification1.aType));
ASSERT_EQ(cmd,
- static_cast<CameraParam>(aNotification.payload[0]));
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ static_cast<CameraParam>(aNotification0.payload[0]));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification1.payload[0]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification0.payload[1]));
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification1.payload[1]));
+ }
}
// New master retires from a master role
@@ -1078,17 +1561,25 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
+
// Create two clients
sp<IEvsCamera_1_1> pCam0 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
sp<IEvsCamera_1_1> pCam1 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam1);
+
// Get the parameter list; this test will use the first command in both
// lists.
std::vector<CameraParam> cam0Cmds, cam1Cmds;
@@ -1144,108 +1635,260 @@
}
);
- if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
- // Try to turn off auto-focus
- int32_t val1 = 0;
- pCam1->getIntParameter(CameraParam::AUTO_FOCUS,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- if (val1 != 0) {
- pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
- }
- }
-
- // Try to program a parameter with a random value [minVal, maxVal]
- int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
- int32_t val1 = 0;
-
- // Rounding down
- val0 = val0 - (val0 % step);
-
+ // Client1 becomes a master
result = pCam1->setMaster();
ASSERT_EQ(EvsResult::OK, result);
+ std::vector<int32_t> values;
+ EvsEventDesc aTargetEvent = {};
+ EvsEventDesc aNotification = {};
+ bool listening = false;
+ std::mutex eventLock;
+ std::condition_variable eventCond;
+ if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ std::thread listener = std::thread(
+ [&frameHandler0, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+ aTargetEvent.payload[1] = 0;
+ if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to turn off auto-focus
+ pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &values](auto status, auto effectiveValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Make sure AUTO_FOCUS is off.
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal] after
+ // rounding it down.
+ int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+ val0 = val0 - (val0 % step);
+
+ std::thread listener = std::thread(
+ [&frameHandler1, &aNotification, &listening, &eventCond, &cam1Cmds, val0] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ listening = false;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ values.clear();
pCam1->setIntParameter(cam1Cmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
// Verify a change notification
- EvsEvent aNotification = {};
- bool timeout =
- frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
EvsEventType::PARAMETER_CHANGED);
ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
cam1Cmds[0]);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+ }
+
+ listener = std::thread(
+ [&frameHandler1, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ listening = false;
+ lock.lock();
+ timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
// Client 0 steals a master role
ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
- frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
EvsEventType::MASTER_RELEASED);
// Client 0 programs a parameter
val0 = minVal + (std::rand() % (maxVal - minVal));
- val1 = 0;
// Rounding down
val0 = val0 - (val0 % step);
if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ std::thread listener = std::thread(
+ [&frameHandler1, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+ aTargetEvent.payload[1] = 0;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
// Try to turn off auto-focus
- int32_t val1 = 0;
- pCam0->getIntParameter(CameraParam::AUTO_FOCUS,
- [&result, &val1](auto status, auto value) {
+ values.clear();
+ pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
}
});
- if (val1 != 0) {
- pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
}
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Make sure AUTO_FOCUS is off.
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
}
+ listener = std::thread(
+ [&frameHandler0, &aNotification, &listening, &eventCond, &cam0Cmds, val0] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ listening = false;
+ timer = std::chrono::system_clock::now();
+ lock.lock();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ values.clear();
pCam0->setIntParameter(cam0Cmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
// Verify a change notification
- timeout =
- frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
EvsEventType::PARAMETER_CHANGED);
ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
cam0Cmds[0]);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+ }
// Turn off the display (yes, before the stream stops -- it should be handled)
pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
@@ -1282,6 +1925,7 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -1324,6 +1968,9 @@
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Set up a frame receiver object which will fire up its own thread.
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
pDisplay,
@@ -1383,6 +2030,7 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -1427,6 +2075,9 @@
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
// Try to create the second camera client with different stream
// configuration.
int32_t id = targetCfg.id;
@@ -1436,6 +2087,9 @@
.withDefault(nullptr);
ASSERT_EQ(pCam1, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
// Try again with same stream configuration.
targetCfg.id = id;
pCam1 =
@@ -1506,6 +2160,30 @@
}
+/*
+ * LogicalCameraMetadata:
+ * Opens logical camera reported by the enumerator and validate its metadata by
+ * checking its capability and locating supporting physical camera device
+ * identifiers.
+ */
+TEST_F(EvsHidlTest, LogicalCameraMetadata) {
+ ALOGI("Starting LogicalCameraMetadata test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Open and close each camera twice
+ for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ ASSERT_GE(devices.size(), 1) <<
+ "Logical camera device must have at least one physical camera device ID in its metadata.";
+ }
+ }
+}
+
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index f9c25d1..2050038 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -62,6 +62,7 @@
"impl/vhal_v2_0/EmulatedVehicleHal.cpp",
"impl/vhal_v2_0/VehicleEmulator.cpp",
"impl/vhal_v2_0/PipeComm.cpp",
+ "impl/vhal_v2_0/ProtoMessageConverter.cpp",
"impl/vhal_v2_0/SocketComm.cpp",
"impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
"impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
@@ -98,6 +99,21 @@
test_suites: ["general-tests"],
}
+cc_test {
+ name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests",
+ vendor: true,
+ defaults: ["vhal_v2_0_defaults"],
+ srcs: [
+ "impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "android.hardware.automotive.vehicle@2.0-libproto-native",
+ "libprotobuf-cpp-lite",
+ ],
+ test_suites: ["general-tests"],
+}
+
cc_binary {
name: "android.hardware.automotive.vehicle@2.0-service",
defaults: ["vhal_v2_0_defaults"],
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
index 56ecd67..d40f122 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -57,10 +57,14 @@
virtual std::vector<VehiclePropConfig> getAllPropertyConfig() const = 0;
// Send the set property request to server
- virtual StatusCode setProperty(const VehiclePropValue& value) = 0;
+ // updateStatus indicate if VHal should change the status of the value
+ // it should be false except injecting values for e2e tests
+ virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0;
// Receive a new property value from server
- virtual void onPropertyValue(const VehiclePropValue& value) = 0;
+ // updateStatus is true if and only if the value is
+ // generated by car (ECU/fake generator/injected)
+ virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0;
};
/**
@@ -84,11 +88,15 @@
// Receive the set property request from HAL.
// Process the setting and return the status code
- virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0;
+ // updateStatus indicate if VHal should change the status of the value
+ // it should be false except injecting values for e2e tests
+ virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0;
// Receive a new property value from car (via direct connection to the car bus or the emulator)
// and forward the value to HAL
- virtual void onPropertyValueFromCar(const VehiclePropValue& value) = 0;
+ // updateStatus is true if and only if the value is
+ // generated by car (ECU/fake generator/injected)
+ virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0;
};
/**
@@ -118,12 +126,12 @@
return this->onGetAllPropertyConfig();
}
- StatusCode setProperty(const VehiclePropValue& value) override {
- return this->onSetProperty(value);
+ StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override {
+ return this->onSetProperty(value, updateStatus);
}
- void onPropertyValueFromCar(const VehiclePropValue& value) override {
- return this->onPropertyValue(value);
+ void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
+ return this->onPropertyValue(value, updateStatus);
}
// To be implemented:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
index bf1de81..136b2e0 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
@@ -41,7 +41,7 @@
}
}
-void CommConn::sendMessage(emulator::EmulatorMessage const& msg) {
+void CommConn::sendMessage(vhal_proto::EmulatorMessage const& msg) {
int numBytes = msg.ByteSize();
std::vector<uint8_t> buffer(static_cast<size_t>(numBytes));
if (!msg.SerializeToArray(buffer.data(), numBytes)) {
@@ -61,9 +61,9 @@
break;
}
- emulator::EmulatorMessage rxMsg;
+ vhal_proto::EmulatorMessage rxMsg;
if (rxMsg.ParseFromArray(buffer.data(), static_cast<int32_t>(buffer.size()))) {
- emulator::EmulatorMessage respMsg;
+ vhal_proto::EmulatorMessage respMsg;
mMessageProcessor->processMessage(rxMsg, respMsg);
sendMessage(respMsg);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
index 87b0dfc..6d36da4 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
@@ -44,8 +44,8 @@
* Process a single message received over a CommConn. Populate the given respMsg with the reply
* message we should send.
*/
- virtual void processMessage(emulator::EmulatorMessage const& rxMsg,
- emulator::EmulatorMessage& respMsg) = 0;
+ virtual void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+ vhal_proto::EmulatorMessage& respMsg) = 0;
};
/**
@@ -93,7 +93,7 @@
/**
* Serialized and send the given message to the other side.
*/
- void sendMessage(emulator::EmulatorMessage const& msg);
+ void sendMessage(vhal_proto::EmulatorMessage const& msg);
protected:
std::unique_ptr<std::thread> mReadThread;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
index 168999d..222fe5e 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -30,12 +30,12 @@
namespace impl {
-void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value) {
+void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
if (!mPropCallback) {
LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
return;
}
- return mPropCallback(value);
+ return mPropCallback(value, updateStatus);
}
void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
@@ -65,12 +65,13 @@
}
void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) {
+ constexpr bool updateStatus = true;
LOG(DEBUG) << __func__ << ": " << toString(value);
auto updatedPropValue = getValuePool()->obtain(value);
if (updatedPropValue) {
updatedPropValue->timestamp = value.timestamp;
updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
- onPropertyValueFromCar(*updatedPropValue);
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
}
}
@@ -86,6 +87,8 @@
}
StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+ constexpr bool updateStatus = true;
+
LOG(INFO) << __func__;
const auto& v = request.value;
if (!v.int32Values.size()) {
@@ -153,9 +156,11 @@
int32_t display = request.value.int32Values[3];
// Send back to HAL
onPropertyValueFromCar(
- *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
+ updateStatus);
onPropertyValueFromCar(
- *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
+ updateStatus);
break;
}
default: {
@@ -191,9 +196,41 @@
return keyEvent;
}
-StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) {
+StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
// Some properties need to be treated non-trivially
switch (value.prop) {
+ case kGenerateFakeDataControllingProperty:
+ return handleGenerateFakeDataRequest(value);
+
+ // set the value from vehcile side, used in end to end test.
+ case kSetIntPropertyFromVehcileForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
+ updatedPropValue->prop = value.value.int32Values[0];
+ updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+ case kSetFloatPropertyFromVehcileForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
+ updatedPropValue->prop = value.value.int32Values[0];
+ updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+ case kSetBooleanPropertyFromVehcileForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
+ updatedPropValue->prop = value.value.int32Values[1];
+ updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+
case AP_POWER_STATE_REPORT:
switch (value.value.int32Values[0]) {
case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
@@ -201,15 +238,18 @@
case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
// CPMS is in WAIT_FOR_VHAL state, simply move to ON
// Send back to HAL
- onPropertyValueFromCar(
- *createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
+ // ALWAYS update status for generated property value
+ onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
+ true /* updateStatus */);
break;
case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
// CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
// Send back to HAL
+ // ALWAYS update status for generated property value
onPropertyValueFromCar(
- *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
+ *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
+ true /* updateStatus */);
break;
case toInt(VehicleApPowerStateReport::ON):
case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
@@ -226,19 +266,12 @@
}
// In the real vhal, the value will be sent to Car ECU.
- // We just pretend it is done here.
- return StatusCode::OK;
-}
+ // We just pretend it is done here and send back to HAL
+ auto updatedPropValue = getValuePool()->obtain(value);
+ updatedPropValue->timestamp = elapsedRealtimeNano();
-StatusCode EmulatedVehicleServer::onSetPropertyFromVehicle(const VehiclePropValue& value) {
- if (value.prop == kGenerateFakeDataControllingProperty) {
- auto status = handleGenerateFakeDataRequest(value);
- return status;
- } else {
- // Send back to HAL
- onPropertyValueFromCar(value);
- return StatusCode::OK;
- }
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
}
EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
index d424cd8..5fc6493 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -35,13 +35,10 @@
class EmulatedVehicleClient : public IVehicleClient {
public:
// Type of callback function for handling the new property values
- using PropertyCallBackType = std::function<void(const VehiclePropValue&)>;
+ using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
// Method from IVehicleClient
- void onPropertyValue(const VehiclePropValue& value) override;
-
- // Request to change the value on the VEHICLE side (for testing)
- virtual StatusCode setPropertyFromVehicle(const VehiclePropValue& value) = 0;
+ void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
void registerPropertyValueCallback(PropertyCallBackType&& callback);
@@ -55,10 +52,7 @@
std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
- StatusCode onSetProperty(const VehiclePropValue& value) override;
-
- // Process the request to change the value on the VEHICLE side (for testing)
- StatusCode onSetPropertyFromVehicle(const VehiclePropValue& value);
+ StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
// Set the Property Value Pool used in this server
void setValuePool(VehiclePropValuePool* valuePool);
@@ -85,16 +79,10 @@
VehiclePropValuePool* mValuePool{nullptr};
};
-class EmulatedPassthroughConnector
- : public IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer> {
- public:
- StatusCode setPropertyFromVehicle(const VehiclePropValue& value) override {
- return this->onSetPropertyFromVehicle(value);
- }
-};
-
// Helper functions
+using EmulatedPassthroughConnector =
+ IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer>;
using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 6508efe..5c16bf7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -98,8 +98,9 @@
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
mPropStore->registerProperty(kVehicleProperties[i].config);
}
- mVehicleClient->registerPropertyValueCallback(
- std::bind(&EmulatedVehicleHal::onPropertyValue, this, std::placeholders::_1));
+ mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
+ this, std::placeholders::_1,
+ std::placeholders::_2));
}
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
@@ -131,41 +132,15 @@
}
StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
- static constexpr bool shouldUpdateStatus = false;
-
- // set the value from vehcile side, used in end to end test.
- if (propValue.prop == kSetIntPropertyFromVehcileForTest) {
- auto mockValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
- mockValue->prop = propValue.value.int32Values[0];
- mockValue->value.int32Values[0] = propValue.value.int32Values[1];
- mockValue->timestamp = propValue.value.int64Values[0];
- mockValue->areaId = propValue.areaId;
- setPropertyFromVehicle(*mockValue);
- return StatusCode::OK;
- }
-
- if (propValue.prop == kSetFloatPropertyFromVehcileForTest) {
- auto mockValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
- mockValue->prop = propValue.value.int32Values[0];
- mockValue->value.floatValues[0] = propValue.value.floatValues[0];
- mockValue->timestamp = propValue.value.int64Values[0];
- mockValue->areaId = propValue.areaId;
- setPropertyFromVehicle(*mockValue);
- return StatusCode::OK;
- }
- if (propValue.prop == kSetBooleanPropertyFromVehcileForTest) {
- auto mockValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
- mockValue->prop = propValue.value.int32Values[1];
- mockValue->value.int32Values[0] = propValue.value.int32Values[0];
- mockValue->timestamp = propValue.value.int64Values[0];
- mockValue->areaId = propValue.areaId;
- setPropertyFromVehicle(*mockValue);
- return StatusCode::OK;
- }
+ constexpr bool updateStatus = false;
if (propValue.prop == kGenerateFakeDataControllingProperty) {
- // send the generator controlling request to the server
- auto status = mVehicleClient->setPropertyFromVehicle(propValue);
+ // Send the generator controlling request to the server.
+ // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case)
+ // instead of the generated values triggered by it. 'propValue' works as a control signal
+ // here, since we never send the control signal back, the value of 'updateStatus' flag
+ // does not matter here.
+ auto status = mVehicleClient->setProperty(propValue, updateStatus);
if (status != StatusCode::OK) {
return status;
}
@@ -212,22 +187,13 @@
* After checking all conditions, such as the property is available, a real vhal will
* sent the events to Car ECU to take actions.
*/
- VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue);
- updatedPropValue->timestamp = elapsedRealtimeNano();
// Send the value to the vehicle server, the server will talk to the (real or emulated) car
- auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue);
+ auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
if (setValueStatus != StatusCode::OK) {
return setValueStatus;
}
- if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
- return StatusCode::INTERNAL_ERROR;
- }
-
- getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
- doHalEvent(std::move(updatedPropValue));
-
return StatusCode::OK;
}
@@ -314,7 +280,6 @@
}
if (v.get()) {
- v->timestamp = elapsedRealtimeNano();
doHalEvent(std::move(v));
}
}
@@ -347,18 +312,19 @@
}
bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
- return mVehicleClient->setPropertyFromVehicle(propValue) == StatusCode::OK;
+ constexpr bool updateStatus = true;
+ return mVehicleClient->setProperty(propValue, updateStatus) == StatusCode::OK;
}
std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
return mPropStore->readAllValues();
}
-void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value) {
- static constexpr bool shouldUpdateStatus = true;
+void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
- if (mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
+ if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
+ getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
doHalEvent(std::move(updatedPropValue));
}
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index 98315ec..a8378da 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -68,7 +68,7 @@
}
StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
- void onPropertyValue(const VehiclePropValue& value);
+ void onPropertyValue(const VehiclePropValue& value, bool updateStatus);
void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
bool isContinuousProperty(int32_t propId) const;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
new file mode 100644
index 0000000..77cb114
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ProtoMsgConverter"
+
+#include <memory>
+#include <vector>
+
+#include <log/log.h>
+
+#include <vhal_v2_0/VehicleUtils.h>
+
+#include "ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// If protobuf class PROTO_VALUE has value in field PROTO_VARNAME,
+// then casting the value by CAST and copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VARNAME, CAST) \
+ if (PROTO_VALUE.has_##PROTO_VARNAME()) { \
+ (VHAL_TYPE_VALUE)->VHAL_TYPE_VARNAME = CAST(PROTO_VALUE.PROTO_VARNAME()); \
+ }
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME, every element of PROTO_VECNAME
+// is casted by CAST
+#define CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VECNAME, CAST) \
+ do { \
+ (VHAL_TYPE_VALUE)->VHAL_TYPE_VECNAME.resize(PROTO_VALUE.PROTO_VECNAME##_size()); \
+ size_t idx = 0; \
+ for (auto& value : PROTO_VALUE.PROTO_VECNAME()) { \
+ VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME[idx++] = CAST(value); \
+ } \
+ } while (0)
+
+// If protobuf message has value in field PROTO_VARNAME,
+// then copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VARNAME) \
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE( \
+ PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VARNAME, /*NO CAST*/)
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME
+#define COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VECNAME) \
+ CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE( \
+ PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VECNAME, /*NO CAST*/)
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) {
+ protoCfg->set_prop(cfg.prop);
+ protoCfg->set_access(toInt(cfg.access));
+ protoCfg->set_change_mode(toInt(cfg.changeMode));
+ protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
+
+ for (auto& configElement : cfg.configArray) {
+ protoCfg->add_config_array(configElement);
+ }
+
+ if (cfg.configString.size() > 0) {
+ protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
+ }
+
+ protoCfg->clear_area_configs();
+ for (auto& areaConfig : cfg.areaConfigs) {
+ auto* protoACfg = protoCfg->add_area_configs();
+ protoACfg->set_area_id(areaConfig.areaId);
+
+ switch (getPropType(cfg.prop)) {
+ case VehiclePropertyType::STRING:
+ case VehiclePropertyType::BOOLEAN:
+ case VehiclePropertyType::INT32_VEC:
+ case VehiclePropertyType::INT64_VEC:
+ case VehiclePropertyType::FLOAT_VEC:
+ case VehiclePropertyType::BYTES:
+ case VehiclePropertyType::MIXED:
+ // Do nothing. These types don't have min/max values
+ break;
+ case VehiclePropertyType::INT64:
+ protoACfg->set_min_int64_value(areaConfig.minInt64Value);
+ protoACfg->set_max_int64_value(areaConfig.maxInt64Value);
+ break;
+ case VehiclePropertyType::FLOAT:
+ protoACfg->set_min_float_value(areaConfig.minFloatValue);
+ protoACfg->set_max_float_value(areaConfig.maxFloatValue);
+ break;
+ case VehiclePropertyType::INT32:
+ protoACfg->set_min_int32_value(areaConfig.minInt32Value);
+ protoACfg->set_max_int32_value(areaConfig.maxInt32Value);
+ break;
+ default:
+ ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
+ break;
+ }
+ }
+
+ protoCfg->set_min_sample_rate(cfg.minSampleRate);
+ protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+}
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg) {
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, prop, cfg, prop);
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, access, cfg, access,
+ static_cast<VehiclePropertyAccess>);
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, change_mode, cfg, changeMode,
+ static_cast<VehiclePropertyChangeMode>);
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, config_array, cfg, configArray);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, config_string, cfg, configString);
+
+ auto cast_to_acfg = [](const vhal_proto::VehicleAreaConfig& protoAcfg) {
+ VehicleAreaConfig acfg;
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, area_id, &acfg, areaId);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int32_value, &acfg, minInt32Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int32_value, &acfg, maxInt32Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int64_value, &acfg, minInt64Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int64_value, &acfg, maxInt64Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_float_value, &acfg, minFloatValue);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_float_value, &acfg, maxFloatValue);
+ return acfg;
+ };
+
+ CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, area_configs, cfg, areaConfigs, cast_to_acfg);
+
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, min_sample_rate, cfg, minSampleRate);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, max_sample_rate, cfg, maxSampleRate);
+}
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val) {
+ protoVal->set_prop(val.prop);
+ protoVal->set_value_type(toInt(getPropType(val.prop)));
+ protoVal->set_timestamp(val.timestamp);
+ protoVal->set_status((vhal_proto::VehiclePropStatus)(val.status));
+ protoVal->set_area_id(val.areaId);
+
+ // Copy value data if it is set.
+ // - for bytes and strings, this is indicated by size > 0
+ // - for int32, int64, and float, copy the values if vectors have data
+ if (val.value.stringValue.size() > 0) {
+ protoVal->set_string_value(val.value.stringValue.c_str(), val.value.stringValue.size());
+ }
+
+ if (val.value.bytes.size() > 0) {
+ protoVal->set_bytes_value(val.value.bytes.data(), val.value.bytes.size());
+ }
+
+ for (auto& int32Value : val.value.int32Values) {
+ protoVal->add_int32_values(int32Value);
+ }
+
+ for (auto& int64Value : val.value.int64Values) {
+ protoVal->add_int64_values(int64Value);
+ }
+
+ for (auto& floatValue : val.value.floatValues) {
+ protoVal->add_float_values(floatValue);
+ }
+}
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal) {
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, prop, val, prop);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, timestamp, val, timestamp);
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, status, val, status,
+ static_cast<VehiclePropertyStatus>);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, area_id, val, areaId);
+
+ // Copy value data
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, string_value, val, value.stringValue);
+
+ auto cast_proto_bytes_to_vec = [](auto&& bytes) {
+ return std::vector<uint8_t>(bytes.begin(), bytes.end());
+ };
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, bytes_value, val, value.bytes,
+ cast_proto_bytes_to_vec);
+
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int32_values, val, value.int32Values);
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int64_values, val, value.int64Values);
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, float_values, val, value.floatValues);
+}
+
+#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+
+} // namespace proto_msg_converter
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h
new file mode 100644
index 0000000..01f3beb
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// VehiclePropConfig
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg);
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg);
+
+// VehiclePropValue
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val);
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal);
+
+} // namespace proto_msg_converter
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
index 068333c..916c320 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -60,7 +60,7 @@
}
}
-void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) {
+void SocketComm::sendMessage(vhal_proto::EmulatorMessage const& msg) {
std::lock_guard<std::mutex> lock(mMutex);
for (std::unique_ptr<SocketConn> const& conn : mOpenConnections) {
conn->sendMessage(msg);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
index 88b852b..52326b9 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
@@ -47,7 +47,7 @@
/**
* Serialized and send the given message to all connected clients.
*/
- void sendMessage(emulator::EmulatorMessage const& msg);
+ void sendMessage(vhal_proto::EmulatorMessage const& msg);
private:
int mListenFd;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 9dc7085..263ca62 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -24,6 +24,7 @@
#include <vhal_v2_0/VehicleUtils.h>
#include "PipeComm.h"
+#include "ProtoMessageConverter.h"
#include "SocketComm.h"
#include "VehicleEmulator.h"
@@ -62,11 +63,11 @@
* changed.
*/
void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
- emulator::EmulatorMessage msg;
- emulator::VehiclePropValue *val = msg.add_value();
+ vhal_proto::EmulatorMessage msg;
+ vhal_proto::VehiclePropValue* val = msg.add_value();
populateProtoVehiclePropValue(val, &propValue);
- msg.set_status(emulator::RESULT_OK);
- msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
+ msg.set_status(vhal_proto::RESULT_OK);
+ msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC);
mSocketComm->sendMessage(msg);
if (mPipeComm) {
@@ -77,17 +78,17 @@
void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
- emulator::VehiclePropGet getProp = rxMsg.prop(0);
+ vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
- respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
- respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+ respMsg.set_msg_type(vhal_proto::GET_CONFIG_RESP);
+ respMsg.set_status(vhal_proto::ERROR_INVALID_PROPERTY);
for (auto& config : configs) {
// Find the config we are looking for
if (config.prop == getProp.prop()) {
- emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
- respMsg.set_status(emulator::RESULT_OK);
+ respMsg.set_status(vhal_proto::RESULT_OK);
break;
}
}
@@ -97,11 +98,11 @@
VehicleEmulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
- respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
- respMsg.set_status(emulator::RESULT_OK);
+ respMsg.set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP);
+ respMsg.set_status(vhal_proto::RESULT_OK);
for (auto& config : configs) {
- emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
}
}
@@ -109,11 +110,11 @@
void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
int32_t areaId = 0;
- emulator::VehiclePropGet getProp = rxMsg.prop(0);
+ vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
int32_t propId = getProp.prop();
- emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
+ vhal_proto::Status status = vhal_proto::ERROR_INVALID_PROPERTY;
- respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
+ respMsg.set_msg_type(vhal_proto::GET_PROPERTY_RESP);
if (getProp.has_area_id()) {
areaId = getProp.area_id();
@@ -127,9 +128,9 @@
StatusCode halStatus;
auto val = mHal->get(request, &halStatus);
if (val != nullptr) {
- emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, val.get());
- status = emulator::RESULT_OK;
+ status = vhal_proto::RESULT_OK;
}
}
@@ -138,12 +139,12 @@
void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */,
VehicleEmulator::EmulatorMessage& respMsg) {
- respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
- respMsg.set_status(emulator::RESULT_OK);
+ respMsg.set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP);
+ respMsg.set_status(vhal_proto::RESULT_OK);
{
for (const auto& prop : mHal->getAllProperties()) {
- emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, &prop);
}
}
@@ -151,7 +152,7 @@
void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
- emulator::VehiclePropValue protoVal = rxMsg.value(0);
+ vhal_proto::VehiclePropValue protoVal = rxMsg.value(0);
VehiclePropValue val = {
.timestamp = elapsedRealtimeNano(),
.areaId = protoVal.area_id(),
@@ -159,7 +160,7 @@
.status = (VehiclePropertyStatus)protoVal.status(),
};
- respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
+ respMsg.set_msg_type(vhal_proto::SET_PROPERTY_RESP);
// Copy value data if it is set. This automatically handles complex data types if needed.
if (protoVal.has_string_value()) {
@@ -187,120 +188,42 @@
}
bool halRes = mHal->setPropertyFromVehicle(val);
- respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY);
+ respMsg.set_status(halRes ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY);
}
-void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg,
- emulator::EmulatorMessage& respMsg) {
+void VehicleEmulator::processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+ vhal_proto::EmulatorMessage& respMsg) {
switch (rxMsg.msg_type()) {
- case emulator::GET_CONFIG_CMD:
+ case vhal_proto::GET_CONFIG_CMD:
doGetConfig(rxMsg, respMsg);
break;
- case emulator::GET_CONFIG_ALL_CMD:
+ case vhal_proto::GET_CONFIG_ALL_CMD:
doGetConfigAll(rxMsg, respMsg);
break;
- case emulator::GET_PROPERTY_CMD:
+ case vhal_proto::GET_PROPERTY_CMD:
doGetProperty(rxMsg, respMsg);
break;
- case emulator::GET_PROPERTY_ALL_CMD:
+ case vhal_proto::GET_PROPERTY_ALL_CMD:
doGetPropertyAll(rxMsg, respMsg);
break;
- case emulator::SET_PROPERTY_CMD:
+ case vhal_proto::SET_PROPERTY_CMD:
doSetProperty(rxMsg, respMsg);
break;
default:
ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
- respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
+ respMsg.set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD);
break;
}
}
-void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+void VehicleEmulator::populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg) {
- protoCfg->set_prop(cfg.prop);
- protoCfg->set_access(toInt(cfg.access));
- protoCfg->set_change_mode(toInt(cfg.changeMode));
- protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
-
- for (auto& configElement : cfg.configArray) {
- protoCfg->add_config_array(configElement);
- }
-
- if (cfg.configString.size() > 0) {
- protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
- }
-
- // Populate the min/max values based on property type
- switch (getPropType(cfg.prop)) {
- case VehiclePropertyType::STRING:
- case VehiclePropertyType::BOOLEAN:
- case VehiclePropertyType::INT32_VEC:
- case VehiclePropertyType::INT64_VEC:
- case VehiclePropertyType::FLOAT_VEC:
- case VehiclePropertyType::BYTES:
- case VehiclePropertyType::MIXED:
- // Do nothing. These types don't have min/max values
- break;
- case VehiclePropertyType::INT64:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
- aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
- }
- break;
- case VehiclePropertyType::FLOAT:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
- aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
- }
- break;
- case VehiclePropertyType::INT32:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
- aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
- }
- break;
- default:
- ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
- break;
- }
-
- protoCfg->set_min_sample_rate(cfg.minSampleRate);
- protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+ return proto_msg_converter::toProto(protoCfg, cfg);
}
-void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+void VehicleEmulator::populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
const VehiclePropValue* val) {
- protoVal->set_prop(val->prop);
- protoVal->set_value_type(toInt(getPropType(val->prop)));
- protoVal->set_timestamp(val->timestamp);
- protoVal->set_status((emulator::VehiclePropStatus)(val->status));
- protoVal->set_area_id(val->areaId);
-
- // Copy value data if it is set.
- // - for bytes and strings, this is indicated by size > 0
- // - for int32, int64, and float, copy the values if vectors have data
- if (val->value.stringValue.size() > 0) {
- protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
- }
-
- if (val->value.bytes.size() > 0) {
- protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
- }
-
- for (auto& int32Value : val->value.int32Values) {
- protoVal->add_int32_values(int32Value);
- }
-
- for (auto& int64Value : val->value.int64Values) {
- protoVal->add_int64_values(int64Value);
- }
-
- for (auto& floatValue : val->value.floatValues) {
- protoVal->add_float_values(floatValue);
- }
+ return proto_msg_converter::toProto(protoVal, *val);
}
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
index 58e387a..82947be 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
@@ -72,21 +72,21 @@
virtual ~VehicleEmulator();
void doSetValueFromClient(const VehiclePropValue& propValue);
- void processMessage(emulator::EmulatorMessage const& rxMsg,
- emulator::EmulatorMessage& respMsg) override;
+ void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+ vhal_proto::EmulatorMessage& respMsg) override;
private:
friend class ConnectionThread;
- using EmulatorMessage = emulator::EmulatorMessage;
+ using EmulatorMessage = vhal_proto::EmulatorMessage;
void doGetConfig(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doGetConfigAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doGetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doGetPropertyAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doSetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
- void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+ void populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg);
- void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+ void populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
const VehiclePropValue* val);
private:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 04df5a8..4902a5d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -16,7 +16,7 @@
syntax = "proto2";
-package emulator;
+package vhal_proto;
// CMD messages are from workstation --> VHAL
// RESP messages are from VHAL --> workstation
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
index 7ce3c32..2cc6595 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-syntax = "proto2";
+syntax = "proto3";
-package emulator;
+package vhal_proto;
import "google/protobuf/empty.proto";
import "VehicleHalProto.proto";
@@ -32,7 +32,7 @@
}
message VehicleHalCallStatus {
- required VehicleHalStatusCode status_code = 1;
+ VehicleHalStatusCode status_code = 1;
}
service VehicleServer {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
new file mode 100644
index 0000000..3817e44
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <utils/SystemClock.h>
+
+#include "vhal_v2_0/DefaultConfig.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+#include "vhal_v2_0/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+namespace proto_msg_converter {
+
+namespace {
+
+void CheckPropConfigConversion(const VehiclePropConfig& config) {
+ vhal_proto::VehiclePropConfig protoCfg;
+ VehiclePropConfig tmpConfig;
+
+ toProto(&protoCfg, config);
+ fromProto(&tmpConfig, protoCfg);
+
+ EXPECT_EQ(config.prop, tmpConfig.prop);
+ EXPECT_EQ(config.access, tmpConfig.access);
+ EXPECT_EQ(config.changeMode, tmpConfig.changeMode);
+ EXPECT_EQ(config.configString, tmpConfig.configString);
+ EXPECT_EQ(config.minSampleRate, tmpConfig.minSampleRate);
+ EXPECT_EQ(config.maxSampleRate, tmpConfig.maxSampleRate);
+ EXPECT_EQ(config.configArray, tmpConfig.configArray);
+
+ EXPECT_EQ(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+
+ auto cfgType = getPropType(config.prop);
+ for (size_t idx = 0; idx < std::min(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+ ++idx) {
+ auto& lhs = config.areaConfigs[idx];
+ auto& rhs = tmpConfig.areaConfigs[idx];
+ EXPECT_EQ(lhs.areaId, rhs.areaId);
+ switch (cfgType) {
+ case VehiclePropertyType::INT64:
+ EXPECT_EQ(lhs.minInt64Value, rhs.minInt64Value);
+ EXPECT_EQ(lhs.maxInt64Value, rhs.maxInt64Value);
+ break;
+ case VehiclePropertyType::FLOAT:
+ EXPECT_EQ(lhs.minFloatValue, rhs.minFloatValue);
+ EXPECT_EQ(lhs.maxFloatValue, rhs.maxFloatValue);
+ break;
+ case VehiclePropertyType::INT32:
+ EXPECT_EQ(lhs.minInt32Value, rhs.minInt32Value);
+ EXPECT_EQ(lhs.maxInt32Value, rhs.maxInt32Value);
+ break;
+ default:
+ // ignore min/max values
+ break;
+ }
+ }
+}
+
+void CheckPropValueConversion(const VehiclePropValue& val) {
+ vhal_proto::VehiclePropValue protoVal;
+ VehiclePropValue tmpVal;
+
+ toProto(&protoVal, val);
+ fromProto(&tmpVal, protoVal);
+
+ EXPECT_EQ(val, tmpVal);
+}
+
+TEST(ProtoMessageConverterTest, basic) {
+ for (auto& property : impl::kVehicleProperties) {
+ CheckPropConfigConversion(property.config);
+
+ VehiclePropValue prop;
+ prop.timestamp = elapsedRealtimeNano();
+ prop.areaId = 123;
+ prop.prop = property.config.prop;
+ prop.value = property.initialValue;
+ prop.status = VehiclePropertyStatus::ERROR;
+ CheckPropValueConversion(prop);
+ }
+}
+
+} // namespace
+
+} // namespace proto_msg_converter
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.6/Android.bp b/camera/device/3.6/Android.bp
new file mode 100644
index 0000000..8766b93
--- /dev/null
+++ b/camera/device/3.6/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.device@3.6",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ICameraDeviceSession.hal",
+ "ICameraOfflineSession.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/camera/device/3.6/ICameraDeviceSession.hal b/camera/device/3.6/ICameraDeviceSession.hal
new file mode 100644
index 0000000..00ebcc3
--- /dev/null
+++ b/camera/device/3.6/ICameraDeviceSession.hal
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.6;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.5::ICameraDeviceSession;
+import @3.5::StreamConfiguration;
+import ICameraOfflineSession;
+
+/**
+ * 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.5::ICameraDeviceSession {
+ /**
+ * configureStreams_3_6:
+ *
+ * Identical to @3.5::ICameraDeviceSession.configureStreams, except that:
+ *
+ * - a boolean supportOffline is added to HalStreamConfiguration to indicate
+ * if this stream can be switched to offline mode later.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On successful stream configuration.
+ * INTERNAL_ERROR:
+ * If there has been a fatal error and the device is no longer
+ * operational. Only close() can be called successfully by the
+ * framework after this error is returned.
+ * ILLEGAL_ARGUMENT:
+ * If the requested stream configuration is invalid. Some examples
+ * of invalid stream configurations include:
+ * - Including more than 1 INPUT stream
+ * - Not including any OUTPUT streams
+ * - Including streams with unsupported formats, or an unsupported
+ * size for that format.
+ * - Including too many output streams of a certain format.
+ * - Unsupported rotation configuration
+ * - Stream sizes/formats don't satisfy the
+ * StreamConfigurationMode requirements
+ * for non-NORMAL mode, or the requested operation_mode is not
+ * supported by the HAL.
+ * - Unsupported usage flag
+ * The camera service cannot filter out all possible illegal stream
+ * configurations, since some devices may support more simultaneous
+ * streams or larger stream resolutions than the minimum required
+ * for a given camera device hardware level. The HAL must return an
+ * ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+ * ready to accept a future valid stream configuration in a later
+ * configureStreams call.
+ * @return halConfiguration The stream parameters desired by the HAL for
+ * each stream, including maximum buffers, the usage flags, and the
+ * override format.
+ */
+ configureStreams_3_6(@3.5::StreamConfiguration requestedConfiguration)
+ generates (Status status, HalStreamConfiguration halConfiguration);
+
+ /**
+ * switchToOffline:
+ *
+ * Switch the current running session from actively streaming mode to the
+ * offline mode. See ICameraOfflineSession for more details.
+ *
+ * The streamsToKeep argument contains list of streams IDs where application
+ * still needs its output. For all streams application does not need anymore,
+ * camera HAL can send ERROR_BUFFER to speed up the transition, or even send
+ * ERROR_REQUEST if all output targets of a request is not needed. By the
+ * time this call returns, camera HAL must have returned all buffers coming
+ * from streams no longer needed and have erased buffer caches of such streams.
+ *
+ * For all requests that are going to be transferred to offline session,
+ * the ICameraDeviceSession is responsible to capture all input buffers from
+ * the image sensor before the switchToOffline call returns. Before
+ * switchToOffline returns, camera HAL must have completed all requests not
+ * switching to offline mode, and collected information on what streams and
+ * requests are going to continue in the offline session, in the
+ * offlineSessionInfo output argument.
+ *
+ * If there are no requests qualified to be transferred to offline session,
+ * the camera HAL must return a null ICameraOfflineSession object with OK
+ * status. In this scenario, the camera HAL still must flush all inflight
+ * requests and unconfigure all streams before returning this call.
+ *
+ * After switchToOffline returns, the ICameraDeviceSession must be back to
+ * unconfigured state as if it is just created and no streams are configured.
+ * Also, camera HAL must not call any methods in ICameraDeviceCallback since
+ * all unfinished requests are now transferred to the offline session.
+ * After the call returns, camera service may then call close to close
+ * the camera device, or call configureStream* again to reconfigure the
+ * camera and then send new capture requests with processCaptureRequest. In
+ * the latter case, it is legitimate for camera HAL to call methods in
+ * ICameraDeviceCallback again in response to the newly submitted capture
+ * requests.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On switching to offline session and unconfiguring streams
+ * successfully.
+ * ILLEGAL_ARGUMENT:
+ * If camera does not support offline mode in any one of streams
+ * in streamsToKeep argument. Note that the camera HAL must report
+ * if a stream supports offline mode in HalStreamConfiguration
+ * output of configureStreams_3_6 method. If all streams in
+ * streamsToKeep argument support offline mode, then the camera HAL
+ * must not return this error.
+ *
+ *
+ * @return offlineSessionInfo Information on what streams and requests will
+ * be transferred to offline session to continue processing.
+ *
+ * @return offlineSession The offline session object camera service will use
+ * to interact with.
+ */
+ switchToOffline(vec<int32_t> streamsToKeep) generates (Status status,
+ CameraOfflineSessionInfo offlineSessionInfo, ICameraOfflineSession offlineSession);
+};
diff --git a/camera/device/3.6/ICameraOfflineSession.hal b/camera/device/3.6/ICameraOfflineSession.hal
new file mode 100644
index 0000000..03cea64
--- /dev/null
+++ b/camera/device/3.6/ICameraOfflineSession.hal
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.6;
+
+import @3.5::ICameraDeviceCallback;
+
+/**
+ * Camera device offline session interface.
+ *
+ * Obtained via ICameraDeviceSession::switchToOffline(), this interface contains
+ * the methods and callback interfaces that define how camera service interacts
+ * with an offline session.
+ *
+ * An offline session contains some unfinished capture requests that were submitted
+ * to the parent ICameraDeviceSession before calling switchToOffline, and is
+ * responsible for delivering these capture results back to camera service regardless
+ * of whether the parent camera device is still opened or not. An offline session must
+ * not have access to the camera device's image sensor. During switchToOffline
+ * call, camera HAL must capture all necessary frames from the image sensor that
+ * is needed for completing the requests offline later.
+ */
+interface ICameraOfflineSession {
+ /**
+ * Set the callbacks for offline session to communicate with camera service.
+ *
+ * Offline session is responsible to store all callbacks the camera HAL
+ * generated after the return of ICameraDeviceSession::switchToOffline, and
+ * send them to camera service once this method is called.
+ *
+ * Camera service must not call this method more than once, so these
+ * callbacks can be assumed to be constant after the first setCallback call.
+ */
+ setCallback(ICameraDeviceCallback cb);
+
+ /**
+ * getCaptureResultMetadataQueue:
+ *
+ * Retrieves the queue used along with
+ * ICameraDeviceCallback#processCaptureResult.
+ *
+ * Clients to ICameraOfflineSession must:
+ * - Call getCaptureRequestMetadataQueue to retrieve the fast message queue;
+ * - In implementation of ICameraDeviceCallback, test whether
+ * .fmqResultSize field is zero.
+ * - If .fmqResultSize != 0, read result metadata from the fast message
+ * queue;
+ * - otherwise, read result metadata in CaptureResult.result.
+ *
+ * @return queue the queue that implementation writes result metadata to.
+ */
+ getCaptureResultMetadataQueue() generates (fmq_sync<uint8_t> queue);
+
+ /**
+ * Close the offline session and release all resources.
+ *
+ * Camera service may call this method before or after the offline session
+ * has finished all requests it needs to handle. If there are still unfinished
+ * requests when close is called, camera HAL must send ERROR_REQUEST for
+ * all unfinished requests and return all buffers via
+ * ICameraDeviceCallback#processCaptureResult or
+ * ICameraDeviceCallback#returnStreamBuffers.
+ * Also, all buffer caches maintained by the offline session must be erased
+ * before the close call returns.
+ */
+ close();
+};
diff --git a/camera/device/3.6/types.hal b/camera/device/3.6/types.hal
new file mode 100644
index 0000000..743b139
--- /dev/null
+++ b/camera/device/3.6/types.hal
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.6;
+
+import @3.2::BufferCache;
+import @3.4::HalStream;
+
+/**
+ * OfflineRequest:
+ *
+ * Information about a capture request being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineRequest {
+ /**
+ * Must match a inflight CaptureRequest sent by camera service
+ */
+ uint32_t frameNumber;
+
+ /**
+ * Stream IDs for outputs that will be returned via ICameraDeviceCallback.
+ * The stream ID must be within one of offline stream listed in
+ * CameraOfflineSessionInfo.
+ * Camera service will validate these pending buffers are matching camera
+ * service's record to make sure no buffers are leaked during the
+ * switchToOffline call.
+ */
+ vec<int32_t> pendingStreams;
+};
+
+/**
+ * OfflineStream:
+ *
+ * Information about a stream being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineStream {
+ /**
+ * IDs of a stream to be transferred to offline session.
+ *
+ * For devices that do not support HAL buffer management, this must be
+ * one of stream ID listed in streamsToKeep argument of the
+ * switchToOffline call.
+ * For devices that support HAL buffer management, this could be any stream
+ * that was configured right before calling switchToOffline.
+ */
+ int32_t id;
+
+ /**
+ * Number of outstanding buffers that will be returned via offline session
+ */
+ uint32_t numOutstandingBuffers;
+
+ /**
+ * Buffer ID of buffers currently cached between camera service and this
+ * stream, which may or may not be owned by the camera HAL right now.
+ * See StreamBuffer#bufferId for more details.
+ */
+ vec<uint64_t> circulatingBufferIds;
+};
+
+/**
+ * CameraOfflineSessionInfo:
+ *
+ * Information about pending outputs that's being transferred to an offline
+ * session from an active session using the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct CameraOfflineSessionInfo {
+ /**
+ * Information on what streams will be preserved in offline session.
+ * Streams not listed here will be removed by camera service after
+ * switchToOffline call returns.
+ */
+ vec<OfflineStream> offlineStreams;
+
+ /**
+ * Information for requests that will be handled by offline session
+ * Camera service will validate this matches what camera service has on
+ * record.
+ */
+ vec<OfflineRequest> offlineRequests;
+};
+
+/**
+ * HalStream:
+ *
+ * The camera HAL's response to each requested stream configuration.
+ *
+ * This version extends the @3.4 HalStream with the physicalCameraId
+ * field
+ */
+struct HalStream {
+ /**
+ * The definition of HalStream from the prior version.
+ */
+ @3.4::HalStream v3_4;
+
+ /**
+ * Whether this stream can be switch to offline mode.
+ *
+ * For devices that does not support the OFFLINE_PROCESSING capability, this
+ * fields will always be false.
+ *
+ * For devices support the OFFLINE_PROCESSING capability: any input stream
+ * and any output stream that can be output of the input stream must set
+ * this field to true. Also any stream of YUV420_888 format or JPEG format,
+ * with CPU_READ usage flag, must set this field to true. All other streams
+ * are up to camera HAL to advertise support or not, though it is not
+ * recommended to list support for streams with hardware composer or video
+ * encoder usage flags as these streams tend to be targeted continuously and
+ * can lead to long latency when trying to switch to offline.
+ *
+ */
+ bool supportOffline;
+};
+
+/**
+ * HalStreamConfiguration:
+ *
+ * Identical to @3.4::HalStreamConfiguration, except that it contains @3.6::HalStream entries.
+ *
+ */
+struct HalStreamConfiguration {
+ vec<HalStream> streams;
+};
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
index cef0397..f5034cc 100644
--- a/camera/metadata/3.2/types.hal
+++ b/camera/metadata/3.2/types.hal
@@ -410,7 +410,7 @@
*
* <p>List of the maximum number of regions that can be used for metering in
* auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
- * this corresponds to the the maximum number of elements in
+ * this corresponds to the maximum number of elements in
* ANDROID_CONTROL_AE_REGIONS, ANDROID_CONTROL_AWB_REGIONS,
* and ANDROID_CONTROL_AF_REGIONS.</p>
*
diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
index 4ebd069..224c369 100644
--- a/camera/metadata/3.5/Android.bp
+++ b/camera/metadata/3.5/Android.bp
@@ -16,4 +16,3 @@
],
gen_java: true,
}
-
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
index b9451c8..62899ec 100644
--- a/camera/metadata/3.5/types.hal
+++ b/camera/metadata/3.5/types.hal
@@ -35,12 +35,22 @@
* '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
*/
enum CameraMetadataTag : @3.4::CameraMetadataTag {
- /** android.control.availableBokehCapabilities [static, int32[], public]
+ /** android.control.availableBokehMaxSizes [static, int32[], ndk_public]
*
- * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
- * maximum streaming (non-stall) size with bokeh effect.</p>
+ * <p>The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera
+ * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
+ *
+ * @see ANDROID_CONTROL_BOKEH_MODE
*/
- ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+
+ /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public]
+ *
+ * <p>The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.</p>
+ *
+ * @see ANDROID_CONTROL_BOKEH_MODE
+ */
+ ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES,
/** android.control.bokehMode [dynamic, enum, public]
*
@@ -48,6 +58,18 @@
*/
ANDROID_CONTROL_BOKEH_MODE,
+ /** android.control.zoomRatioRange [static, float[], public]
+ *
+ * <p>Minimum and maximum zoom ratios supported by this camera device.</p>
+ */
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE,
+
+ /** android.control.zoomRatio [dynamic, float, public]
+ *
+ * <p>The desired zoom ratio</p>
+ */
+ ANDROID_CONTROL_ZOOM_RATIO,
+
ANDROID_CONTROL_END_3_5,
};
@@ -71,4 +93,5 @@
enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
@3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING,
};
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 69ec0d9..650ec8b 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -20,6 +20,7 @@
#include <chrono>
#include <mutex>
#include <regex>
+#include <string>
#include <unordered_map>
#include <unordered_set>
#include <condition_variable>
@@ -755,6 +756,7 @@
const hidl_vec<hidl_string>& deviceNames);
void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
void verifyBokehCharacteristics(const camera_metadata_t* metadata);
+ void verifyZoomCharacteristics(const camera_metadata_t* metadata);
void verifyRecommendedConfigs(const CameraMetadata& metadata);
void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
void verifyMonochromeCameraResult(
@@ -776,6 +778,8 @@
void verifySessionReconfigurationQuery(sp<device::V3_5::ICameraDeviceSession> session3_5,
camera_metadata* oldSessionParams, camera_metadata* newSessionParams);
+ void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate);
+
bool isDepthOnly(camera_metadata_t* staticMeta);
static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta,
@@ -2857,13 +2861,7 @@
metadata, &expectedSize);
ASSERT_TRUE((result == 0) ||
(result == CAMERA_METADATA_VALIDATION_SHIFTED));
- size_t entryCount =
- get_camera_metadata_entry_count(metadata);
- // TODO: we can do better than 0 here. Need to check how many required
- // request keys we've defined for each template
- ASSERT_GT(entryCount, 0u);
- ALOGI("template %u metadata entry count is %zu",
- t, entryCount);
+ verifyRequestTemplate(metadata, reqTemplate);
} else {
ASSERT_EQ(0u, req.size());
}
@@ -5671,6 +5669,11 @@
return;
}
+ camera_metadata_ro_entry entry;
+ int retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
std::string version, cameraId;
ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
std::unordered_set<std::string> physicalIds;
@@ -5678,15 +5681,37 @@
for (auto physicalId : physicalIds) {
ASSERT_NE(physicalId, cameraId);
bool isPublicId = false;
+ std::string fullPublicId;
for (auto& deviceName : deviceNames) {
std::string publicVersion, publicId;
ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
if (physicalId == publicId) {
isPublicId = true;
+ fullPublicId = deviceName;
break;
}
}
if (isPublicId) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> subDevice;
+ Return<void> ret;
+ ret = mProvider->getCameraDeviceInterface_V3_x(
+ fullPublicId, [&](auto status, const auto& device) {
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ subDevice = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = subDevice->getCameraCharacteristics(
+ [&](auto status, const auto& chars) {
+ ASSERT_EQ(Status::OK, status);
+ retcode = find_camera_metadata_ro_entry(
+ (const camera_metadata_t *)chars.data(),
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+ ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+ });
+ ASSERT_TRUE(ret.isOk());
continue;
}
@@ -5702,6 +5727,12 @@
[&](auto status, const auto& chars) {
verifyCameraCharacteristics(status, chars);
verifyMonochromeCharacteristics(chars, deviceVersion);
+
+ retcode = find_camera_metadata_ro_entry(
+ (const camera_metadata_t *)chars.data(),
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+ ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
});
ASSERT_TRUE(ret.isOk());
@@ -5721,8 +5752,7 @@
// Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in
// result keys.
if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) {
- camera_metadata_ro_entry entry;
- int retcode = find_camera_metadata_ro_entry(metadata,
+ retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
if ((0 == retcode) && (entry.count > 0)) {
ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
@@ -5822,6 +5852,7 @@
}
verifyBokehCharacteristics(metadata);
+ verifyZoomCharacteristics(metadata);
}
void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) {
@@ -5852,38 +5883,51 @@
retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
- bool hasBokehCharacteristicsKey = false;
+ bool hasBokehMaxSizesKey = false;
+ bool hasBokehZoomRatioRangesKey = false;
if ((0 == retcode) && (entry.count > 0)) {
- hasBokehCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
- ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES) != entry.data.i32+entry.count;
+ hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count;
+ hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES) != entry.data.i32+entry.count;
} else {
ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
}
+
+ camera_metadata_ro_entry maxSizesEntry;
retcode = find_camera_metadata_ro_entry(metadata,
- ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES, &entry);
- bool hasAvailableBokehCaps = (0 == retcode && entry.count > 0);
+ ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES, &maxSizesEntry);
+ bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+
+ camera_metadata_ro_entry zoomRatioRangesEntry;
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry);
+ bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
// Bokeh keys must all be available, or all be unavailable.
- bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehCharacteristicsKey &&
- !hasAvailableBokehCaps;
+ bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey &&
+ !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges;
if (noBokeh) {
return;
}
- bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehCharacteristicsKey &&
- hasAvailableBokehCaps;
+ bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey &&
+ hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges;
ASSERT_TRUE(hasBokeh);
// Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
- ASSERT_TRUE(entry.count == 6 || entry.count == 9);
+ // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and
+ // {OFF, CONTINUOUS, STILL_CAPTURE}.
+ ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
+ (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
bool hasOffMode = false;
bool hasStillCaptureMode = false;
bool hasContinuousMode = false;
std::vector<AvailableStream> outputStreams;
ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
- for (int i = 0; i < entry.count; i += 3) {
- int32_t mode = entry.data.i32[i];
- int32_t maxWidth = entry.data.i32[i+1];
- int32_t maxHeight = entry.data.i32[i+2];
+ for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) {
+ int32_t mode = maxSizesEntry.data.i32[i];
+ int32_t maxWidth = maxSizesEntry.data.i32[i+1];
+ int32_t maxHeight = maxSizesEntry.data.i32[i+2];
switch (mode) {
case ANDROID_CONTROL_BOKEH_MODE_OFF:
hasOffMode = true;
@@ -5891,9 +5935,11 @@
break;
case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE:
hasStillCaptureMode = true;
+ j += 2;
break;
case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
hasContinuousMode = true;
+ j += 2;
break;
default:
ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
@@ -5901,6 +5947,7 @@
}
if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+ // Make sure size is supported.
bool sizeSupported = false;
for (const auto& stream : outputStreams) {
if ((stream.format == static_cast<int32_t>(PixelFormat::YCBCR_420_888) ||
@@ -5911,12 +5958,102 @@
}
}
ASSERT_TRUE(sizeSupported);
+
+ // Make sure zoom range is valid
+ float minZoomRatio = zoomRatioRangesEntry.data.f[0];
+ float maxZoomRatio = zoomRatioRangesEntry.data.f[1];
+ ASSERT_GT(minZoomRatio, 0.0f);
+ ASSERT_LE(minZoomRatio, maxZoomRatio);
}
}
ASSERT_TRUE(hasOffMode);
ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
}
+void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) {
+ camera_metadata_ro_entry entry;
+ int retcode = 0;
+
+ // Check key availability in capabilities, request and result.
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &entry);
+ float maxDigitalZoom = 1.0;
+ if ((0 == retcode) && (entry.count == 1)) {
+ maxDigitalZoom = entry.data.f[0];
+ } else {
+ ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+ bool hasZoomRequestKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasZoomRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+ } else {
+ ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+ bool hasZoomResultKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasZoomResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+ } else {
+ ADD_FAILURE() << "Get camera availableResultKeys failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+ bool hasZoomCharacteristicsKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasZoomCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE) != entry.data.i32+entry.count;
+ } else {
+ ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
+ // Zoom keys must all be available, or all be unavailable.
+ bool noZoomRatio = !hasZoomRequestKey && !hasZoomResultKey && !hasZoomCharacteristicsKey &&
+ !hasZoomRatioRange;
+ if (noZoomRatio) {
+ return;
+ }
+ bool hasZoomRatio = hasZoomRequestKey && hasZoomResultKey && hasZoomCharacteristicsKey &&
+ hasZoomRatioRange;
+ ASSERT_TRUE(hasZoomRatio);
+
+ float minZoomRatio = entry.data.f[0];
+ float maxZoomRatio = entry.data.f[1];
+ if (maxDigitalZoom != maxZoomRatio) {
+ ADD_FAILURE() << "Maximum zoom ratio is different than maximum digital zoom!";
+ }
+ if (minZoomRatio > maxZoomRatio) {
+ ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!";
+ }
+ if (minZoomRatio > 1.0f) {
+ ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!";
+ }
+ if (maxZoomRatio < 1.0f) {
+ ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!";
+ }
+
+ // Make sure CROPPING_TYPE is CENTER_ONLY
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_CROPPING_TYPE, &entry);
+ if ((0 == retcode) && (entry.count == 1)) {
+ int8_t croppingType = entry.data.u8[0];
+ ASSERT_EQ(croppingType, ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY);
+ } else {
+ ADD_FAILURE() << "Get camera scalerCroppingType failed!";
+ }
+}
+
void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
int deviceVersion) {
const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
@@ -6415,6 +6552,26 @@
}
}
+void CameraHidlTest::verifyRequestTemplate(const camera_metadata_t* metadata,
+ RequestTemplate requestTemplate) {
+ ASSERT_NE(nullptr, metadata);
+ size_t entryCount =
+ get_camera_metadata_entry_count(metadata);
+ ALOGI("template %u metadata entry count is %zu", (int32_t)requestTemplate, entryCount);
+ // TODO: we can do better than 0 here. Need to check how many required
+ // request keys we've defined for each template
+ ASSERT_GT(entryCount, 0u);
+
+ // Check zoomRatio
+ camera_metadata_ro_entry zoomRatioEntry;
+ int foundZoomRatio = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_ZOOM_RATIO, &zoomRatioEntry);
+ if (foundZoomRatio == 0) {
+ ASSERT_EQ(zoomRatioEntry.count, 1);
+ ASSERT_EQ(zoomRatioEntry.data.f[0], 1.0f);
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(
PerInstance, CameraHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)),
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
new file mode 100644
index 0000000..6f2d292
--- /dev/null
+++ b/common/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+ name: "vintf-common",
+ host_supported: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "android/hardware/common/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/common/aidl/android/hardware/common/NativeHandle.aidl b/common/aidl/android/hardware/common/NativeHandle.aidl
new file mode 100644
index 0000000..2c250a2
--- /dev/null
+++ b/common/aidl/android/hardware/common/NativeHandle.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.common;
+
+/**
+ * Representation of a native handle.
+ */
+@VintfStability
+parcelable NativeHandle {
+ ParcelFileDescriptor[] fds;
+ int[] ints;
+}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index f5acdd4..1e3f743 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -388,6 +388,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.rebootescrow</name>
+ <interface>
+ <name>IRebootEscrow</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.secure_element</name>
<version>1.0</version>
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
index aef0340..9e99c33 100644
--- a/contexthub/1.0/vts/functional/Android.bp
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -19,6 +19,8 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
static_libs: ["android.hardware.contexthub@1.0"],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
-
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index 045cc4e..161b2f0 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -4,5 +4,5 @@
stange@google.com
#VTS team
-yim@google.com
+dshi@google.com
trong@google.com
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index 629477a..a1d173b 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -16,13 +16,14 @@
#define LOG_TAG "contexthub_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/contexthub/1.0/IContexthub.h>
#include <android/hardware/contexthub/1.0/IContexthubCallback.h>
#include <android/hardware/contexthub/1.0/types.h>
#include <android/log.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
#include <cinttypes>
@@ -76,69 +77,44 @@
}
// Gets a list of valid hub IDs in the system
-std::vector<uint32_t> getHubIds() {
- static std::vector<uint32_t> hubIds;
+std::vector<std::string> getHubIds(const std::string& service_name) {
+ std::vector<std::string> hubIds;
- if (hubIds.size() == 0) {
- sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>();
+ sp<IContexthub> hubApi = IContexthub::getService(service_name);
if (hubApi != nullptr) {
- for (const ContextHub& hub : getHubsSync(hubApi)) {
- hubIds.push_back(hub.hubId);
- }
+ for (const ContextHub& hub : getHubsSync(hubApi)) {
+ hubIds.push_back(std::to_string(hub.hubId));
+ }
}
- }
- ALOGD("Running tests against all %zu reported hubs", hubIds.size());
- return hubIds;
+ ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(),
+ service_name.c_str());
+ return hubIds;
}
-// Test environment for Contexthub HIDL HAL.
-class ContexthubHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static ContexthubHidlEnvironment* Instance() {
- static ContexthubHidlEnvironment* instance = new ContexthubHidlEnvironment;
- return instance;
- }
+// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle
+// available.
+class ContexthubHidlTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ hubApi = IContexthub::getService(std::get<0>(GetParam()));
+ ASSERT_NE(hubApi, nullptr);
- virtual void registerTestServices() override { registerTestService<IContexthub>(); }
- private:
- ContexthubHidlEnvironment() {}
-};
+ // getHubs() must be called at least once for proper initialization of the
+ // HAL implementation
+ getHubsSync(hubApi);
+ }
-// Base test fixture that initializes the HAL and makes the context hub API
-// handle available
-class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>(
- ContexthubHidlEnvironment::Instance()->getServiceName<IContexthub>());
- ASSERT_NE(hubApi, nullptr);
+ uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
- // getHubs() must be called at least once for proper initialization of the
- // HAL implementation
- getHubsSync(hubApi);
- }
+ Result registerCallback(sp<IContexthubCallback> cb) {
+ Result result = hubApi->registerCallback(getHubId(), cb);
+ ALOGD("Registered callback, result %" PRIu32, result);
+ return result;
+ }
- virtual void TearDown() override {}
-
- sp<IContexthub> hubApi;
-};
-
-// Test fixture parameterized by hub ID
-class ContexthubHidlTest : public ContexthubHidlTestBase,
- public ::testing::WithParamInterface<uint32_t> {
- public:
- uint32_t getHubId() {
- return GetParam();
- }
-
- Result registerCallback(sp<IContexthubCallback> cb) {
- Result result = hubApi->registerCallback(getHubId(), cb);
- ALOGD("Registered callback, result %" PRIu32, result);
- return result;
- }
+ sp<IContexthub> hubApi;
};
// Base callback implementation that just logs all callbacks by default
@@ -202,24 +178,24 @@
}
// Ensures that the metadata reported in getHubs() is sane
-TEST_F(ContexthubHidlTestBase, TestGetHubs) {
- hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
- ALOGD("System reports %zu hubs", hubs.size());
+TEST_P(ContexthubHidlTest, TestGetHubs) {
+ hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
+ ALOGD("System reports %zu hubs", hubs.size());
- for (const ContextHub& hub : hubs) {
- ALOGD("Checking hub ID %" PRIu32, hub.hubId);
+ for (const ContextHub& hub : hubs) {
+ ALOGD("Checking hub ID %" PRIu32, hub.hubId);
- EXPECT_FALSE(hub.name.empty());
- EXPECT_FALSE(hub.vendor.empty());
- EXPECT_FALSE(hub.toolchain.empty());
- EXPECT_GT(hub.peakMips, 0);
- EXPECT_GE(hub.stoppedPowerDrawMw, 0);
- EXPECT_GE(hub.sleepPowerDrawMw, 0);
- EXPECT_GT(hub.peakPowerDrawMw, 0);
+ EXPECT_FALSE(hub.name.empty());
+ EXPECT_FALSE(hub.vendor.empty());
+ EXPECT_FALSE(hub.toolchain.empty());
+ EXPECT_GT(hub.peakMips, 0);
+ EXPECT_GE(hub.stoppedPowerDrawMw, 0);
+ EXPECT_GE(hub.sleepPowerDrawMw, 0);
+ EXPECT_GT(hub.peakPowerDrawMw, 0);
- // Minimum 128 byte MTU as required by CHRE API v1.0
- EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
- }
+ // Minimum 128 byte MTU as required by CHRE API v1.0
+ EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
+ }
}
TEST_P(ContexthubHidlTest, TestRegisterCallback) {
@@ -388,20 +364,28 @@
cb->promise.get_future()));
}
-// Parameterize all SingleContexthubTest tests against each valid hub ID
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubHidlTest,
- ::testing::ValuesIn(getHubIds()));
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubTxnTest,
- ::testing::ValuesIn(getHubIds()));
+// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub
+// id: <service name of IContexthub, hub id of the IContexthub service>
+static std::vector<std::tuple<std::string, std::string>> get_parameters() {
+ std::vector<std::tuple<std::string, std::string>> parameters;
+ std::vector<std::string> service_names =
+ android::hardware::getAllHalInstanceNames(IContexthub::descriptor);
+ for (const std::string& service_name : service_names) {
+ std::vector<std::string> ids = getHubIds(service_name);
+ for (const std::string& id : ids) {
+ parameters.push_back(std::make_tuple(service_name, id));
+ }
+ }
-} // anonymous namespace
-
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(ContexthubHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- ContexthubHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI ("Test result = %d", status);
- return status;
+ return parameters;
}
+static std::vector<std::tuple<std::string, std::string>> kTestParameters = get_parameters();
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
+} // anonymous namespace
diff --git a/current.txt b/current.txt
index 999b207..68e4713 100644
--- a/current.txt
+++ b/current.txt
@@ -585,6 +585,7 @@
f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator
d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types
2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
+cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types
@@ -598,14 +599,14 @@
# HALs released in Android R
e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
-4540d12fe1cea996f21bd1712d4ae0906dcbd58177dac494efc605b004902d43 android.hardware.audio@6.0::IDevice
+dd3e9280be60a5e042331c1046d13938e2cc323dc4b267cc74d544bf62fc0314 android.hardware.audio@6.0::IDevice
2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream
2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn
78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut
997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
-1349686814402fa10f711cc5763bc629aafc64a5f5843b4b21b8cd86ffb923e6 android.hardware.audio.common@6.0::types
+8c4232772efeb9905b4c287723e0ee8b2c4bf5ba11728d051171b070e3d79144 android.hardware.audio.common@6.0::types
817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
@@ -649,17 +650,17 @@
94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
-03d37dfebbc27b13adce1ed6389ac483bf7cf32488ca14037c5569bc3e903e4f android.hardware.wifi.hostapd@1.2::IHostapd
-2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types
+9bc274c9d73aae170fd9e18df2476ade4c19b629cfb38dd03dd237a6cc2d932b android.hardware.wifi.hostapd@1.2::IHostapd
+11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
-44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
-619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
-9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types
-0e3c23f1c815469fdcdc39bc33a486817771c7c6b6e5303f2f25569499fc6c69 android.hardware.radio@1.5::types
-52abfa4c94104189fa4b2bc3132fc7c9852b7428283463b020d1a3671a4f374c android.hardware.radio@1.5::IRadio
-3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication
-957ffbaf195aa046431ebe05a5906d215e80650e8e4933b394d6454b217ef3a9 android.hardware.radio@1.5::IRadioResponse
+c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+5477f8bafb29548875622fa83f1c0a29cee641acee613315eb747731001f4aff android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types
+d9044563a5ac5a17a239303b8dec1e51167761ac46e965f61e31654cc034d31b android.hardware.radio@1.5::types
+afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio
+bc59237dbd93949238081f762710552e76670cb648c0e198138551460ac54b1e android.hardware.radio@1.5::IRadioIndication
+f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse
55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 24de37d..88fbff8 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -172,7 +172,14 @@
hasGnssHalVersion_2_0 = registered.size() != 0;
});
- return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
+ bool hasGnssHalVersion_2_1 = false;
+ manager->listManifestByInterface(
+ "android.hardware.gnss@2.1::IGnss",
+ [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+ hasGnssHalVersion_2_1 = registered.size() != 0;
+ });
+
+ return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
}
GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 8ca3f68..b3a3203 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -16,11 +16,14 @@
#define LOG_TAG "GnssHalTest"
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <gnss_hal_test.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
#include <chrono>
#include "Utils.h"
-#include <gtest/gtest.h>
+using ::android::hardware::hidl_string;
using ::android::hardware::gnss::common::Utils;
@@ -99,7 +102,6 @@
EXPECT_TRUE(result.isOk());
EXPECT_TRUE(result);
-
/*
* GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
* so allow time to demodulate ephemeris over the air.
@@ -148,6 +150,27 @@
}
}
+bool GnssHalTest::IsGnssHalVersion_2_0() const {
+ using ::android::hidl::manager::V1_2::IServiceManager;
+ sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
+
+ bool hasGnssHalVersion_2_0 = false;
+ manager->listManifestByInterface(
+ "android.hardware.gnss@2.0::IGnss",
+ [&hasGnssHalVersion_2_0](const hidl_vec<hidl_string>& registered) {
+ hasGnssHalVersion_2_0 = registered.size() != 0;
+ });
+
+ bool hasGnssHalVersion_2_1 = false;
+ manager->listManifestByInterface(
+ "android.hardware.gnss@2.1::IGnss",
+ [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+ hasGnssHalVersion_2_1 = registered.size() != 0;
+ });
+
+ return hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
+}
+
GnssHalTest::GnssCallback::GnssCallback()
: info_cbq_("system_info"),
name_cbq_("name"),
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 4f7b87a..55dc1bc 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -181,6 +181,12 @@
void StopAndClearLocations();
/*
+ * IsGnssHalVersion_2_0:
+ * returns true if the GNSS HAL version is exactly 2.0.
+ */
+ bool IsGnssHalVersion_2_0() const;
+
+ /*
* SetPositionMode:
* Helper function to set positioning mode and verify output
*/
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index c442cc6..0fa08b9 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -182,6 +182,10 @@
* 3. state is valid.
*/
TEST_P(GnssHalTest, TestGnssMeasurementFields) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test GnssMeasurementFields skipped. GNSS HAL version is greater than 2.0.");
+ return;
+ }
const int kFirstGnssMeasurementTimeoutSeconds = 10;
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -464,7 +468,7 @@
}
EXPECT_LE(location_called_count, i);
if (location_called_count != i) {
- ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
+ ALOGW("GetLocationLowPower test - too many locations received. %d vs. %d expected ",
location_called_count, i);
}
@@ -601,6 +605,11 @@
* formerly strongest satellite
*/
TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 2.0.");
+ return;
+ }
+
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
" not supported.");
@@ -746,6 +755,11 @@
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
TEST_P(GnssHalTest, BlacklistConstellation) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0.");
+ return;
+ }
+
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
return;
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 57233aa..7ef9990 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -23,8 +23,9 @@
srcs: [
"Gnss.cpp",
"GnssMeasurement.cpp",
+ "GnssMeasurementCorrections.cpp",
"GnssConfiguration.cpp",
- "service.cpp"
+ "service.cpp",
],
shared_libs: [
"libhidlbase",
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
index fd7a9df..6b61a82 100644
--- a/gnss/2.1/default/Gnss.cpp
+++ b/gnss/2.1/default/Gnss.cpp
@@ -18,11 +18,14 @@
#include "Gnss.h"
#include "GnssMeasurement.h"
+#include "GnssMeasurementCorrections.h"
#include "Utils.h"
#include <log/log.h>
using ::android::hardware::gnss::common::Utils;
+using ::android::hardware::gnss::measurement_corrections::V1_0::implementation::
+ GnssMeasurementCorrections;
namespace android {
namespace hardware {
@@ -87,7 +90,8 @@
}
Return<void> Gnss::cleanup() {
- // TODO implement
+ sGnssCallback_2_1 = nullptr;
+ sGnssCallback_2_0 = nullptr;
return Void();
}
@@ -170,8 +174,9 @@
}
Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
- V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t,
- uint32_t, bool) {
+ V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
+ uint32_t, uint32_t, bool) {
+ mMinIntervalMs = minIntervalMs;
return true;
}
@@ -215,7 +220,7 @@
ALOGE("%s: Unable to invoke callback", __func__);
}
- auto gnssName = "Google Mock GNSS Implementation v2.0";
+ auto gnssName = "Google Mock GNSS Implementation v2.1";
ret = sGnssCallback_2_0->gnssNameCb(gnssName);
if (!ret.isOk()) {
ALOGE("%s: Unable to invoke callback", __func__);
@@ -251,8 +256,8 @@
Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
Gnss::getExtensionMeasurementCorrections() {
- // TODO implement
- return ::android::sp<measurement_corrections::V1_0::IMeasurementCorrections>{};
+ ALOGD("Gnss::getExtensionMeasurementCorrections()");
+ return new GnssMeasurementCorrections();
}
Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() {
@@ -266,7 +271,7 @@
}
Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) {
- // TODO implement
+ // TODO(b/124012850): Implement function.
return bool{};
}
@@ -316,6 +321,7 @@
void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
std::unique_lock<std::mutex> lock(mMutex);
+ // TODO(skz): update this to call 2_0 callback if non-null
if (sGnssCallback_2_1 == nullptr) {
ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
return;
@@ -328,13 +334,20 @@
void Gnss::reportLocation(const V2_0::GnssLocation& location) const {
std::unique_lock<std::mutex> lock(mMutex);
- if (sGnssCallback_2_1 == nullptr) {
- ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+ if (sGnssCallback_2_1 != nullptr) {
+ auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v2.1", __func__);
+ }
return;
}
- auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+ if (sGnssCallback_2_0 == nullptr) {
+ ALOGE("%s: No non-null callback", __func__);
+ return;
+ }
+ auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
+ ALOGE("%s: Unable to invoke callback v2.0", __func__);
}
}
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
index ebfa7dd..34e20e5 100644
--- a/gnss/2.1/default/GnssMeasurement.cpp
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -29,7 +29,8 @@
namespace V2_1 {
namespace implementation {
-sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr;
+sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_1 = nullptr;
+sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_0 = nullptr;
GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {}
@@ -48,7 +49,8 @@
ALOGD("close");
std::unique_lock<std::mutex> lock(mMutex);
stop();
- sCallback = nullptr;
+ sCallback_2_1 = nullptr;
+ sCallback_2_0 = nullptr;
return Void();
}
@@ -61,9 +63,18 @@
// Methods from V2_0::IGnssMeasurement follow.
Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
- const sp<V2_0::IGnssMeasurementCallback>&, bool) {
- // TODO implement
- return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+ const sp<V2_0::IGnssMeasurementCallback>& callback, bool) {
+ ALOGD("setCallback_2_0");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback_2_0 = callback;
+
+ if (mIsActive) {
+ ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+ stop();
+ }
+ start();
+
+ return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
}
// Methods from V2_1::IGnssMeasurement follow.
@@ -71,7 +82,7 @@
const sp<V2_1::IGnssMeasurementCallback>& callback, bool) {
ALOGD("setCallback_2_1");
std::unique_lock<std::mutex> lock(mMutex);
- sCallback = callback;
+ sCallback_2_1 = callback;
if (mIsActive) {
ALOGW("GnssMeasurement callback already set. Resetting the callback...");
@@ -87,8 +98,13 @@
mIsActive = true;
mThread = std::thread([this]() {
while (mIsActive == true) {
- auto measurement = Utils::getMockMeasurementV2_1();
- this->reportMeasurement(measurement);
+ if (sCallback_2_1 != nullptr) {
+ auto measurement = Utils::getMockMeasurementV2_1();
+ this->reportMeasurement(measurement);
+ } else {
+ auto measurement = Utils::getMockMeasurementV2_0();
+ this->reportMeasurement(measurement);
+ }
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
}
@@ -103,14 +119,27 @@
}
}
+void GnssMeasurement::reportMeasurement(const GnssDataV2_0& data) {
+ ALOGD("reportMeasurement()");
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (sCallback_2_0 == nullptr) {
+ ALOGE("%s: GnssMeasurement::sCallback_2_0 is null.", __func__);
+ return;
+ }
+ auto ret = sCallback_2_0->gnssMeasurementCb_2_0(data);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
void GnssMeasurement::reportMeasurement(const GnssDataV2_1& data) {
ALOGD("reportMeasurement()");
std::unique_lock<std::mutex> lock(mMutex);
- if (sCallback == nullptr) {
- ALOGE("%s: GnssMeasurement::sCallback is null.", __func__);
+ if (sCallback_2_1 == nullptr) {
+ ALOGE("%s: GnssMeasurement::sCallback_2_1 is null.", __func__);
return;
}
- auto ret = sCallback->gnssMeasurementCb_2_1(data);
+ auto ret = sCallback_2_1->gnssMeasurementCb_2_1(data);
if (!ret.isOk()) {
ALOGE("%s: Unable to invoke callback", __func__);
}
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h
index ee32903..3ed7bc5 100644
--- a/gnss/2.1/default/GnssMeasurement.h
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -30,6 +30,7 @@
namespace implementation {
using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
using ::android::sp;
using ::android::hardware::hidl_array;
@@ -62,9 +63,11 @@
private:
void start();
void stop();
+ void reportMeasurement(const GnssDataV2_0&);
void reportMeasurement(const GnssDataV2_1&);
- static sp<IGnssMeasurementCallback> sCallback;
+ static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
+ static sp<V2_0::IGnssMeasurementCallback> sCallback_2_0;
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
std::thread mThread;
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp
new file mode 100644
index 0000000..2bf5601
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssMeasurementCorrections"
+
+#include "GnssMeasurementCorrections.h"
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from V1_0::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections(const MeasurementCorrections& corrections) {
+ ALOGD("setCorrections");
+ ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
+ "satCorrections.size: %d",
+ corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters,
+ corrections.horizontalPositionUncertaintyMeters,
+ corrections.verticalPositionUncertaintyMeters,
+ static_cast<unsigned long long>(corrections.toaGpsNanosecondsOfWeek),
+ static_cast<int>(corrections.satCorrections.size()));
+ for (auto singleSatCorrection : corrections.satCorrections) {
+ ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f,"
+ " epl: %f, eplUnc: %f",
+ static_cast<int>(singleSatCorrection.singleSatCorrectionFlags),
+ static_cast<int>(singleSatCorrection.constellation),
+ static_cast<int>(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz,
+ singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+ singleSatCorrection.excessPathLengthUncertaintyMeters);
+ ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+ singleSatCorrection.reflectingPlane.latitudeDegrees,
+ singleSatCorrection.reflectingPlane.longitudeDegrees,
+ singleSatCorrection.reflectingPlane.altitudeMeters,
+ singleSatCorrection.reflectingPlane.azimuthDegrees);
+ }
+
+ return true;
+}
+
+Return<bool> GnssMeasurementCorrections::setCallback(
+ const sp<V1_0::IMeasurementCorrectionsCallback>& callback) {
+ using Capabilities = V1_0::IMeasurementCorrectionsCallback::Capabilities;
+ auto ret =
+ callback->setCapabilitiesCb(Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH |
+ Capabilities::REFLECTING_PLANE);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ return false;
+ }
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace measurement_corrections
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/2.1/default/GnssMeasurementCorrections.h
new file mode 100644
index 0000000..4339bed
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct GnssMeasurementCorrections : public IMeasurementCorrections {
+ // Methods from V1_0::IMeasurementCorrections follow.
+ Return<bool> setCorrections(const MeasurementCorrections& corrections) override;
+ Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace measurement_corrections
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal
index 9931685..7934867 100644
--- a/graphics/allocator/4.0/IAllocator.hal
+++ b/graphics/allocator/4.0/IAllocator.hal
@@ -20,14 +20,6 @@
interface IAllocator {
/**
- * Retrieves implementation-defined debug information, which will be
- * displayed during, for example, `dumpsys SurfaceFlinger`.
- *
- * @return debugInfo is a string of debug information.
- */
- dumpDebugInfo() generates (string debugInfo);
-
- /**
* Allocates buffers with the properties specified by the descriptor.
*
* Allocations should be optimized for usage bits provided in the
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index e0c7674..fcd4efc 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -10,6 +10,9 @@
"android/hardware/graphics/common/*.aidl",
],
stability: "vintf",
+ imports: [
+ "vintf-common"
+ ],
backend: {
java: {
enabled: false,
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
new file mode 100644
index 0000000..5f9888a
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Buffer usage definitions.
+ */
+@VintfStability
+@Backing(type="long")
+enum BufferUsage {
+ /** bit 0-3 is an enum */
+ CPU_READ_MASK = 0xf,
+ /** buffer is never read by CPU */
+ CPU_READ_NEVER = 0,
+ /** buffer is rarely read by CPU */
+ CPU_READ_RARELY = 2,
+ /** buffer is often read by CPU */
+ CPU_READ_OFTEN = 3,
+
+ /** bit 4-7 is an enum */
+ CPU_WRITE_MASK = 0xf << 4,
+ /** buffer is never written by CPU */
+ CPU_WRITE_NEVER = 0 << 4,
+ /** buffer is rarely written by CPU */
+ CPU_WRITE_RARELY = 2 << 4,
+ /** buffer is often written by CPU */
+ CPU_WRITE_OFTEN = 3 << 4,
+
+ /** buffer is used as a GPU texture */
+ GPU_TEXTURE = 1 << 8,
+
+ /** buffer is used as a GPU render target */
+ GPU_RENDER_TARGET = 1 << 9,
+
+ /** bit 10 must be zero */
+
+ /** buffer is used as a composer HAL overlay layer */
+ COMPOSER_OVERLAY = 1 << 11,
+ /** buffer is used as a composer HAL client target */
+ COMPOSER_CLIENT_TARGET = 1 << 12,
+
+ /** bit 13 must be zero */
+
+ /**
+ * Buffer is allocated with hardware-level protection against copying the
+ * contents (or information derived from the contents) into unprotected
+ * memory.
+ */
+ PROTECTED = 1 << 14,
+
+ /** buffer is used as a hwcomposer HAL cursor layer */
+ COMPOSER_CURSOR = 1 << 15,
+
+ /** buffer is used as a video encoder input */
+ VIDEO_ENCODER = 1 << 16,
+
+ /** buffer is used as a camera HAL output */
+ CAMERA_OUTPUT = 1 << 17,
+
+ /** buffer is used as a camera HAL input */
+ CAMERA_INPUT = 1 << 18,
+
+ /** bit 19 must be zero */
+
+ /** buffer is used as a renderscript allocation */
+ RENDERSCRIPT = 1 << 20,
+
+ /** bit 21 must be zero */
+
+ /** buffer is used as a video decoder output */
+ VIDEO_DECODER = 1 << 22,
+
+ /** buffer is used as a sensor direct report output */
+ SENSOR_DIRECT_DATA = 1 << 23,
+
+ /** buffer is used as a cube map texture */
+ GPU_CUBE_MAP = 1 << 25,
+
+ /** buffer contains a complete mipmap hierarchy */
+ GPU_MIPMAP_COMPLETE = 1 << 26,
+
+ /**
+ * Buffer is used as input for HEIC encoder.
+ */
+ HW_IMAGE_ENCODER = 1 << 27,
+
+ /**
+ * buffer is used as as an OpenGL shader storage or uniform
+ * buffer object
+ */
+ GPU_DATA_BUFFER = 1 << 24,
+
+ /** bits 25-27 must be zero and are reserved for future versions */
+ /** bits 28-31 are reserved for vendor extensions */
+ VENDOR_MASK = 0xf << 28,
+
+ /** bits 32-47 must be zero and are reserved for future versions */
+ /** bits 48-63 are reserved for vendor extensions */
+ VENDOR_MASK_HI = 0xffff << 48,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
new file mode 100644
index 0000000..4fbc6b2
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * HDR static metadata extension as specified by CTA-861.3.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_cta861_3`.
+ */
+@VintfStability
+parcelable Cta861_3 {
+ /**
+ * Maximum content light level.
+ */
+ float maxContentLightLevel;
+ /**
+ * Maximum frame average light level.
+ */
+ float maxFrameAverageLightLevel;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
index 81a21ab..42cdd81 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -208,8 +208,6 @@
*/
STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
-
-
TRANSFER_SHIFT = 22,
/**
@@ -396,9 +394,7 @@
* The values are encoded using the full range ([0,255] for 8-bit) for all
* components.
*/
- SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // deprecated, use V0_SRGB_LINEAR
-
- V0_SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+ SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
/**
@@ -413,7 +409,7 @@
* Values beyond the range [0.0 - 1.0] would correspond to other colors
* spaces and/or HDR content.
*/
- V0_SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+ SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
/**
@@ -429,9 +425,7 @@
*
* Use full range and BT.709 standard.
*/
- SRGB = 1 << 16 | 2 << 22 | 1 << 27, // deprecated, use V0_SRGB
-
- V0_SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+ SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
/**
@@ -446,7 +440,7 @@
* Values beyond the range [0.0 - 1.0] would correspond to other colors
* spaces and/or HDR content.
*/
- V0_SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+ SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
/**
* YCbCr Colorspaces
@@ -464,22 +458,18 @@
*
* Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
*
- * Use full range, BT.601 transfer and BT.601_625 standard.
+ * Use full range, SMPTE 170M transfer and BT.601_625 standard.
*/
- JFIF = 2 << 16 | 3 << 22 | 1 << 27, // deprecated, use V0_JFIF
-
- V0_JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+ JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
/**
* ITU-R Recommendation 601 (BT.601) - 625-line
*
* Standard-definition television, 625 Lines (PAL)
*
- * Use limited range, BT.601 transfer and BT.601_625 standard.
+ * Use limited range, SMPTE 170M transfer and BT.601_625 standard.
*/
- BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_625
-
- V0_BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
/**
@@ -487,22 +477,18 @@
*
* Standard-definition television, 525 Lines (NTSC)
*
- * Use limited range, BT.601 transfer and BT.601_525 standard.
+ * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
*/
- BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_525
-
- V0_BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
/**
* ITU-R Recommendation 709 (BT.709)
*
* High-definition television
*
- * Use limited range, BT.709 transfer and BT.709 standard.
+ * Use limited range, SMPTE 170M transfer and BT.709 standard.
*/
- BT709 = 1 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT709
-
- V0_BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
/**
@@ -570,7 +556,7 @@
*
* Ultra High-definition television
*
- * Use full range, BT.709 transfer and BT2020 standard
+ * Use full range, SMPTE 170M transfer and BT2020 standard
*/
BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
@@ -622,7 +608,7 @@
*
* Ultra High-definition television
*
- * Use limited range, BT.709 transfer and BT2020 standard
+ * Use limited range, SMPTE 170M transfer and BT2020 standard
*/
BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED
@@ -679,4 +665,13 @@
* according to ISO/IEC 23008-12.
*/
HEIF = 0x1004,
+
+ /**
+ * ITU-R Recommendation 709 (BT.709)
+ *
+ * High-definition television
+ *
+ * Use full range, SMPTE 170M transfer and BT.709 standard.
+ */
+ BT709_FULL_RANGE = 1 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_FULL
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
new file mode 100644
index 0000000..5a22c0f
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.graphics.common.HardwareBufferDescription;
+
+/**
+ * Stable AIDL counterpart of AHardwareBuffer.
+ *
+ * @note This is different from the public HardwareBuffer.
+ * @sa +ndk libnativewindow#AHardwareBuffer
+ */
+@VintfStability
+parcelable HardwareBuffer {
+ HardwareBufferDescription description;
+ NativeHandle handle;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
new file mode 100644
index 0000000..e1e3492
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+/**
+ * Stable AIDL counterpart of AHardwareBuffer_Desc.
+ *
+ * @sa +ndk libnativewindow#AHardwareBuffer_Desc
+ */
+@VintfStability
+parcelable HardwareBufferDescription {
+ int width;
+ int height;
+ int layers;
+ PixelFormat format;
+ BufferUsage usage;
+ int stride;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
new file mode 100644
index 0000000..4942462
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -0,0 +1,516 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Pixel formats for graphics buffers.
+ */
+@VintfStability
+@Backing(type="int")
+enum PixelFormat {
+ /**
+ * This value may be used in an operation where the format is optional.
+ */
+ UNSPECIFIED = 0,
+ /**
+ * 32-bit format that has 8-bit R, G, B, and A components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGBA_8888 = 0x1,
+
+ /**
+ * 32-bit format that has 8-bit R, G, B, and unused components, in that
+ * order, from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGBX_8888 = 0x2,
+
+ /**
+ * 24-bit format that has 8-bit R, G, and B components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGB_888 = 0x3,
+
+ /**
+ * 16-bit packed format that has 5-bit R, 6-bit G, and 5-bit B components,
+ * in that order, from the most-sigfinicant bits to the least-significant
+ * bits.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGB_565 = 0x4,
+
+ /**
+ * 32-bit format that has 8-bit B, G, R, and A components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ BGRA_8888 = 0x5,
+
+ /**
+ * Legacy formats deprecated in favor of YCBCR_420_888.
+ */
+ YCBCR_422_SP = 0x10, // NV16
+ YCRCB_420_SP = 0x11, // NV21
+ YCBCR_422_I = 0x14, // YUY2
+
+ /**
+ * 64-bit format that has 16-bit R, G, B, and A components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are signed floats, whose interpretation is defined
+ * by the dataspace.
+ */
+ RGBA_FP16 = 0x16,
+
+ /**
+ * RAW16 is a single-channel, 16-bit, little endian format, typically
+ * representing raw Bayer-pattern images from an image sensor, with minimal
+ * processing.
+ *
+ * The exact pixel layout of the data in the buffer is sensor-dependent, and
+ * needs to be queried from the camera device.
+ *
+ * Generally, not all 16 bits are used; more common values are 10 or 12
+ * bits. If not all bits are used, the lower-order bits are filled first.
+ * All parameters to interpret the raw data (black and white points,
+ * color space, etc) must be queried from the camera device.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ * - strides are specified in pixels, not in bytes
+ *
+ * size = stride * height * 2
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW16 is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data, layout is as
+ * | defined above.
+ * Dataspace::DEPTH | Unprocessed implementation-dependent raw
+ * | depth measurements, opaque with 16 bit
+ * | samples.
+ * Other | Unsupported
+ */
+ RAW16 = 0x20,
+
+ /**
+ * BLOB is used to carry task-specific data which does not have a standard
+ * image structure. The details of the format are left to the two
+ * endpoints.
+ *
+ * A typical use case is for transporting JPEG-compressed images from the
+ * Camera HAL to the framework or to applications.
+ *
+ * Buffers of this format must have a height of 1, and width equal to their
+ * size in bytes.
+ *
+ * The mapping of the dataspace to buffer contents for BLOB is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::JFIF | An encoded JPEG image
+ * Dataspace::DEPTH | An android_depth_points buffer
+ * Dataspace::SENSOR | Sensor event data.
+ * Other | Unsupported
+ */
+ BLOB = 0x21,
+
+ /**
+ * A format indicating that the choice of format is entirely up to the
+ * allocator.
+ *
+ * The allocator should examine the usage bits passed in when allocating a
+ * buffer with this format, and it should derive the pixel format from
+ * those usage flags. This format must never be used with any of the
+ * BufferUsage::CPU_* usage flags.
+ *
+ * Even when the internally chosen format has an alpha component, the
+ * clients must assume the alpha vlaue to be 1.0.
+ *
+ * The interpretation of the component values is defined by the dataspace.
+ */
+ IMPLEMENTATION_DEFINED = 0x22,
+
+ /**
+ * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
+ * buffer layout, while still describing the general format in a
+ * layout-independent manner. While called YCbCr, it can be used to
+ * describe formats with either chromatic ordering, as well as
+ * whole planar or semiplanar layouts.
+ *
+ * This format must be accepted by the allocator when BufferUsage::CPU_*
+ * are set.
+ *
+ * Buffers with this format must be locked with IMapper::lockYCbCr.
+ * Locking with IMapper::lock must return an error.
+ *
+ * The interpretation of the component values is defined by the dataspace.
+ */
+ YCBCR_420_888 = 0x23,
+
+ /**
+ * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
+ * image sensor. The actual structure of buffers of this format is
+ * implementation-dependent.
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW_OPAQUE is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data.
+ * Other | Unsupported
+ */
+ RAW_OPAQUE = 0x24,
+
+ /**
+ * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
+ * unprocessed format, usually representing raw Bayer-pattern images coming from
+ * an image sensor.
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
+ * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
+ * contains the 2 least significant bits of the 4 pixels, the exact layout data
+ * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
+ * bit of the ith pixel):
+ *
+ * bit 7 bit 0
+ * =====|=====|=====|=====|=====|=====|=====|=====|
+ * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
+ * ===============================================
+ *
+ * This format assumes
+ * - a width multiple of 4 pixels
+ * - an even height
+ * - a vertical stride equal to the height
+ * - strides are specified in bytes, not in pixels
+ *
+ * size = stride * height
+ *
+ * When stride is equal to width * (10 / 8), there will be no padding bytes at
+ * the end of each row, the entire image data is densely packed. When stride is
+ * larger than width * (10 / 8), padding bytes will be present at the end of each
+ * row (including the last row).
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW10 is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data.
+ * Other | Unsupported
+ */
+ RAW10 = 0x25,
+
+ /**
+ * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
+ * unprocessed format, usually representing raw Bayer-pattern images coming from
+ * an image sensor.
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
+ * and second byte contains the top 8 bits of first and second pixel. The third
+ * byte contains the 4 least significant bits of the two pixels, the exact layout
+ * data for each two consecutive pixels is illustrated below (Pi[j] stands for
+ * the jth bit of the ith pixel):
+ *
+ * bit 7 bit 0
+ * ======|======|======|======|======|======|======|======|
+ * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
+ * |------|------|------|------|------|------|------|------|
+ * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
+ * |------|------|------|------|------|------|------|------|
+ * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
+ * =======================================================
+ *
+ * This format assumes:
+ * - a width multiple of 4 pixels
+ * - an even height
+ * - a vertical stride equal to the height
+ * - strides are specified in bytes, not in pixels
+ *
+ * size = stride * height
+ *
+ * When stride is equal to width * (12 / 8), there will be no padding bytes at
+ * the end of each row, the entire image data is densely packed. When stride is
+ * larger than width * (12 / 8), padding bytes will be present at the end of
+ * each row (including the last row).
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW12 is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data.
+ * Other | Unsupported
+ */
+ RAW12 = 0x26,
+
+ /** 0x27 to 0x2A are reserved for flexible formats */
+
+ /**
+ * 32-bit packed format that has 2-bit A, 10-bit B, G, and R components,
+ * in that order, from the most-sigfinicant bits to the least-significant
+ * bits.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGBA_1010102 = 0x2B,
+
+ /**
+ * 0x100 - 0x1FF
+ *
+ * This range is reserved for vendor extensions. Formats in this range
+ * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not
+ * have an alpha component.
+ */
+
+ /**
+ * Y8 is a YUV planar format comprised of a WxH Y plane, with each pixel
+ * being represented by 8 bits. It is equivalent to just the Y plane from
+ * YV12.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ *
+ * size = stride * height
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ Y8 = 0x20203859,
+
+ /**
+ * Y16 is a YUV planar format comprised of a WxH Y plane, with each pixel
+ * being represented by 16 bits. It is just like Y8, but has double the
+ * bits per pixel (little endian).
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ * - strides are specified in pixels, not in bytes
+ *
+ * size = stride * height * 2
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace. When the dataspace is
+ * Dataspace::DEPTH, each pixel is a distance value measured by a depth
+ * camera, plus an associated confidence value.
+ */
+ Y16 = 0x20363159,
+
+ /**
+ * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
+ * by (W/2) x (H/2) Cr and Cb planes.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ *
+ * y_size = stride * height
+ * c_stride = ALIGN(stride/2, 16)
+ * c_size = c_stride * height/2
+ * size = y_size + c_size * 2
+ * cr_offset = y_size
+ * cb_offset = y_size + c_size
+ *
+ * This range is reserved for vendor extensions. Formats in this range
+ * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not
+ * have an alpha component.
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::GPU_TEXTURE
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ YV12 = 0x32315659, // YCrCb 4:2:0 Planar
+
+ /**
+ * 16-bit format that has a single 16-bit depth component.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ DEPTH_16 = 0x30,
+
+ /**
+ * 32-bit format that has a single 24-bit depth component and, optionally,
+ * 8 bits that are unused.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ DEPTH_24 = 0x31,
+
+ /**
+ * 32-bit format that has a 24-bit depth component and an 8-bit stencil
+ * component packed into 32-bits.
+ *
+ * The depth component values are unsigned normalized to the range [0, 1],
+ * whose interpretation is defined by the dataspace. The stencil values are
+ * unsigned integers, whose interpretation is defined by the dataspace.
+ */
+ DEPTH_24_STENCIL_8 = 0x32,
+
+ /**
+ * 32-bit format that has a single 32-bit depth component.
+ *
+ * The component values are signed floats, whose interpretation is defined
+ * by the dataspace.
+ */
+ DEPTH_32F = 0x33,
+
+ /**
+ * Two-component format that has a 32-bit depth component, an 8-bit stencil
+ * component, and optionally 24-bits unused.
+ *
+ * The depth component values are signed floats, whose interpretation is
+ * defined by the dataspace. The stencil bits are unsigned integers, whose
+ * interpretation is defined by the dataspace.
+ */
+ DEPTH_32F_STENCIL_8 = 0x34,
+
+ /**
+ * 8-bit format that has a single 8-bit stencil component.
+ *
+ * The component values are unsigned integers, whose interpretation is
+ * defined by the dataspace.
+ */
+ STENCIL_8 = 0x35,
+
+ /**
+ * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+ * followed immediately by a Wx(H/2) CbCr plane. Each sample is
+ * represented by a 16-bit little-endian value, with the lower 6 bits set
+ * to zero.
+ *
+ * This format assumes
+ * - an even height
+ * - a vertical stride equal to the height
+ *
+ * stride_in_bytes = stride * 2
+ * y_size = stride_in_bytes * height
+ * cbcr_size = stride_in_bytes * (height / 2)
+ * cb_offset = y_size
+ * cr_offset = cb_offset + 2
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::VIDEO_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::GPU_TEXTURE
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ *
+ * This format is appropriate for 10bit video content.
+ *
+ * Buffers with this format must be locked with IMapper::lockYCbCr
+ * or with IMapper::lock.
+ */
+ YCBCR_P010 = 0x36,
+
+ /**
+ * 24-bit format that has 8-bit H, S, and V components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ HSV_888 = 0x37,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
new file mode 100644
index 0000000..60614cd
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+import android.hardware.graphics.common.XyColor;
+
+/**
+ * Mastering display metadata as specified by SMPTE ST 2086.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_smpte2086`.
+ */
+@VintfStability
+parcelable Smpte2086 {
+ /**
+ * CIE XYZ chromaticity for red in the RGB primaries.
+ */
+ XyColor primaryRed;
+ /**
+ * CIE XYZ chromaticity for green in the RGB primaries.
+ */
+ XyColor primaryGreen;
+ /**
+ * CIE XYZ chromaticity for blue in the RGB primaries.
+ */
+ XyColor primaryBlue;
+ /**
+ * CIE XYZ chromaticity for the white point.
+ */
+ XyColor whitePoint;
+ /**
+ * Maximum luminance in candelas per square meter.
+ */
+ float maxLuminance;
+ /**
+ * Minimum luminance in candelas per square meter.
+ */
+ float minLuminance;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 060d12c..43cf672 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -24,6 +24,15 @@
*
* IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may
* support setting these standard buffer metadata types as well.
+ *
+ * When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is
+ * is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by
+ * writing the length of MetadataType.name using 8 bytes in little endian, followed by a char
+ * array of MetadataType.name's characters. The char array is not null terminated. Finally,
+ * MetadataType.value is represented by 8 bytes written in little endian.
+ *
+ * The StandardMetadataType encode/decode support library can be found in:
+ * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
*/
@VintfStability
@Backing(type="long")
@@ -279,4 +288,43 @@
* 4 bytes written in little endian.
*/
BLEND_MODE = 17,
+
+ /**
+ * Can be used to get or set static HDR metadata specified by SMPTE ST 2086.
+ *
+ * This metadata is a stable aidl android.hardware.graphics.common.Smpte2086.
+ *
+ * This is not used in tone mapping until it has been set for the first time.
+ *
+ * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+ * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor.
+ * If this is unset when encoded into a byte stream, the byte stream is empty.
+ */
+ SMPTE2086 = 18,
+
+ /**
+ * Can be used to get or set static HDR metadata specified by CTA 861.3.
+ *
+ * This metadata is a stable aidl android.hardware.graphics.common.Cta861_3.
+ *
+ * This is not used in tone mapping until it has been set for the first time.
+ *
+ * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+ * little endian. The ordering of float values follows the definition of Cta861_3.
+ * If this is unset when encoded into a byte stream, the byte stream is empty.
+ */
+ CTA861_3 = 19,
+
+ /**
+ * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016.
+ *
+ * This metadata is uint8_t byte array.
+ *
+ * This is not used in tone mapping until it has been set for the first time.
+ *
+ * When it is encoded into a byte stream, the length of the HDR metadata byte array is written
+ * using 8 bytes in little endian. It is followed by the uint8_t byte array.
+ * If this is unset when encoded into a byte stream, the byte stream is empty.
+ */
+ SMPTE2094_40 = 20,
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
new file mode 100644
index 0000000..9571273
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Chromaticity based on 2 parameters.
+ *
+ * This is an AIDL counterpart of the NDK struct `AColor_xy`.
+ *
+ * @note This can be used to represent any 2-dimensional chromaticity.
+ */
+@VintfStability
+parcelable XyColor {
+ float x;
+ float y;
+}
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index f23536c..06b4c5e 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -48,6 +48,12 @@
* with protected buffers.
*/
PROTECTED_CONTENTS = 4,
+
+ /**
+ * Indicates that both the composer HAL implementation and the given display
+ * support a low latency mode, such as HDMI 2.1 Auto Low Latency Mode.
+ */
+ AUTO_LOW_LATENCY_MODE = 5,
};
/**
@@ -64,6 +70,18 @@
EXTERNAL = 1,
};
+ enum ContentType : uint32_t {
+ NONE = 0,
+
+ /**
+ * These modes correspond to those found in the HDMI 1.4 specification.
+ */
+ GRAPHICS = 1,
+ PHOTO = 2,
+ CINEMA = 3,
+ GAME = 4,
+ };
+
/**
* Constraints for changing vsync period.
*/
@@ -172,4 +190,60 @@
setActiveConfigWithConstraints(Display display, Config config,
VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints)
generates (Error error, VsyncPeriodChangeTimeline timeline);
+
+ /**
+ * Requests the display to enable/disable its low latency mode.
+ *
+ * If the display is connected via HDMI 2.1, then Auto Low Latency Mode should be triggered. If
+ * the display is internally connected and a custom low latency mode is available, that should
+ * be triggered.
+ *
+ * This function should only be called if the display reports support for
+ * DisplayCapability::AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * UNSUPPORTED when AUTO_LOW_LATENCY_MODE is not supported by the composer
+ * implementation or the given display
+ */
+ setAutoLowLatencyMode(Display display, bool on)
+ generates (Error error);
+
+ /**
+ * Provides a list of all the content types supported by this display (any of
+ * ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after
+ * initialization.
+ *
+ * Content types are introduced in HDMI 1.4 and supporting them is optional. The
+ * ContentType::NONE is always supported and will not be returned by this method..
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return supportedContentTypes is a list of supported content types.
+ */
+ getSupportedContentTypes(Display display)
+ generates(Error error, vec<ContentType> supportedContentTypes);
+
+ /**
+ * Instructs the connected display that the content being shown is of the given type - one of
+ * GRAPHICS, PHOTO, CINEMA, GAME.
+ *
+ * Content types are introduced in HDMI 1.4 and supporting them is optional. If they are
+ * supported, this signal should switch the display to a mode that is optimal for the given
+ * type of content. See HDMI 1.4 specification for more information.
+ *
+ * If the display is internally connected (not through HDMI), and such modes are available,
+ * this method should trigger them.
+ *
+ * This function should only be called if the display reports support for the corresponding
+ * content type (ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}) from getSupportedContentTypes.
+ * ContentType::NONE is supported by default and can always be set.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * UNSUPPORTED when the given content type is not supported by the composer
+ * implementation or the given display
+ */
+ setContentType(Display display, ContentType type)
+ generates (Error error);
};
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
index 4160ed9..dcd959d 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -139,6 +139,24 @@
return Void();
}
+ Return<Error> setAutoLowLatencyMode(Display display, bool on) override {
+ return mHal->setAutoLowLatencyMode(display, on);
+ }
+
+ Return<void> getSupportedContentTypes(
+ Display display, IComposerClient::getSupportedContentTypes_cb hidl_cb) override {
+ std::vector<IComposerClient::ContentType> supportedContentTypes;
+ Error error = mHal->getSupportedContentTypes(display, &supportedContentTypes);
+
+ hidl_cb(error, supportedContentTypes);
+ return Void();
+ }
+
+ Return<Error> setContentType(Display display,
+ IComposerClient::ContentType contentType) override {
+ return mHal->setContentType(display, contentType);
+ }
+
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
auto client = std::make_unique<ComposerClientImpl>(hal);
return client->init() ? std::move(client) : nullptr;
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
index 89dbe66..a1e56ae 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -67,6 +67,11 @@
Display display, Config config,
const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* timeline) = 0;
+ virtual Error setAutoLowLatencyMode(Display display, bool on) = 0;
+ virtual Error getSupportedContentTypes(
+ Display display,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) = 0;
+ virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
index d59d0d5..a27582a 100644
--- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -167,6 +167,57 @@
return Error::NONE;
}
+ Error setAutoLowLatencyMode(Display display, bool on) override {
+ if (!mDispatch.setAutoLowLatencyMode) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error = mDispatch.setAutoLowLatencyMode(mDevice, display, on);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
+ Error getSupportedContentTypes(
+ Display display,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override {
+ if (!mDispatch.getSupportedContentTypes) {
+ return Error::UNSUPPORTED;
+ }
+
+ uint32_t count = 0;
+ int32_t error = mDispatch.getSupportedContentTypes(mDevice, display, &count, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+
+ outSupportedContentTypes->resize(count);
+
+ error = mDispatch.getSupportedContentTypes(
+ mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<IComposerClient::ContentType>::type*>(
+ outSupportedContentTypes->data()));
+ if (error != HWC2_ERROR_NONE) {
+ *outSupportedContentTypes = std::vector<IComposerClient::ContentType>();
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
+ Error setContentType(Display display, IComposerClient::ContentType contentType) override {
+ if (!mDispatch.setContentType) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error =
+ mDispatch.setContentType(mDevice, display, static_cast<int32_t>(contentType));
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_3::initDispatch()) {
@@ -179,6 +230,11 @@
&mDispatch.getDisplayVsyncPeriod);
this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS,
&mDispatch.setActiveConfigWithConstraints);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE,
+ &mDispatch.setAutoLowLatencyMode);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES,
+ &mDispatch.getSupportedContentTypes);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
return true;
}
@@ -222,6 +278,9 @@
HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType;
HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod;
HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints;
+ HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode;
+ HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
+ HWC2_PFN_SET_CONTENT_TYPE setContentType;
} mDispatch = {};
hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
index 35ac23f..5b06d6d 100644
--- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -106,6 +106,25 @@
return error;
}
+Error ComposerClient::setAutoLowLatencyMode(Display display, bool on) {
+ return mClient->setAutoLowLatencyMode(display, on);
+}
+
+Error ComposerClient::getSupportedContentTypes(
+ Display display, std::vector<IComposerClient::ContentType>* outSupportedContentTypes) {
+ Error error = Error::NONE;
+ mClient->getSupportedContentTypes(
+ display, [&](const auto& tmpError, const auto& tmpSupportedContentTypes) {
+ error = tmpError;
+ *outSupportedContentTypes = tmpSupportedContentTypes;
+ });
+ return error;
+}
+
+Error ComposerClient::setContentType(Display display, IComposerClient::ContentType contentType) {
+ return mClient->setContentType(display, contentType);
+}
+
} // namespace vts
} // namespace V2_4
} // namespace composer
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
index 83e74ed..b094bc8 100644
--- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -84,6 +84,13 @@
const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* timeline);
+ Error setAutoLowLatencyMode(Display display, bool on);
+
+ Error getSupportedContentTypes(
+ Display display, std::vector<IComposerClient::ContentType>* outSupportedContentTypes);
+
+ Error setContentType(Display display, IComposerClient::ContentType contentType);
+
private:
const sp<IComposerClient> mClient;
};
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index f038f55..5a96d77 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -47,6 +47,9 @@
using mapper::V2_0::IMapper;
using mapper::V2_0::vts::Gralloc;
+using ContentType = IComposerClient::ContentType;
+using DisplayCapability = IComposerClient::DisplayCapability;
+
class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
protected:
void SetUp() override {
@@ -117,6 +120,11 @@
void Test_setActiveConfigWithConstraints(
const IComposerClient::VsyncPeriodChangeConstraints& constraints);
+ void Test_setContentType(const ContentType& contentType, const char* contentTypeStr);
+ void Test_setContentTypeForDisplay(const Display& display,
+ const std::vector<ContentType>& capabilities,
+ const ContentType& contentType, const char* contentTypeStr);
+
std::unique_ptr<Composer> mComposer;
std::unique_ptr<ComposerClient> mComposerClient;
sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
@@ -184,6 +192,13 @@
EXPECT_EQ(Error::BAD_DISPLAY, error);
}
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilities) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ EXPECT_EQ(Error::NONE, mComposerClient->getDisplayCapabilities(display, &capabilities));
+ }
+}
+
TEST_P(GraphicsComposerHidlTest, getDisplayConnectionType) {
IComposerClient::DisplayConnectionType type;
EXPECT_EQ(Error::BAD_DISPLAY,
@@ -377,6 +392,117 @@
Test_setActiveConfigWithConstraints(constraints);
}
+TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) {
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true));
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, false));
+}
+
+TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ std::vector<DisplayCapability> capabilities;
+ const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities);
+ EXPECT_EQ(Error::NONE, error);
+
+ const bool allmSupport =
+ std::find(capabilities.begin(), capabilities.end(),
+ DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end();
+
+ if (!allmSupport) {
+ EXPECT_EQ(Error::UNSUPPORTED,
+ mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
+ EXPECT_EQ(Error::UNSUPPORTED,
+ mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+ GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
+ << to_string(display) << ", skipping test";
+ return;
+ }
+
+ EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
+ EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, getSupportedContentTypesBadDisplay) {
+ std::vector<ContentType> supportedContentTypes;
+ const auto error =
+ mComposerClient->getSupportedContentTypes(mInvalidDisplayId, &supportedContentTypes);
+ EXPECT_EQ(Error::BAD_DISPLAY, error);
+}
+
+TEST_P(GraphicsComposerHidlTest, getSupportedContentTypes) {
+ std::vector<ContentType> supportedContentTypes;
+ for (Display display : mComposerCallback->getDisplays()) {
+ supportedContentTypes.clear();
+ const auto error =
+ mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+ const bool noneSupported =
+ std::find(supportedContentTypes.begin(), supportedContentTypes.end(),
+ ContentType::NONE) != supportedContentTypes.end();
+ EXPECT_EQ(Error::NONE, error);
+ EXPECT_FALSE(noneSupported);
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setContentTypeNoneAlwaysAccepted) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ const auto error = mComposerClient->setContentType(display, ContentType::NONE);
+ EXPECT_NE(Error::UNSUPPORTED, error);
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setContentTypeBadDisplay) {
+ const auto types = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO,
+ ContentType::CINEMA, ContentType::GAME};
+ for (auto type : types) {
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setContentType(mInvalidDisplayId, type));
+ }
+}
+
+void GraphicsComposerHidlTest::Test_setContentTypeForDisplay(
+ const Display& display, const std::vector<ContentType>& capabilities,
+ const ContentType& contentType, const char* contentTypeStr) {
+ const bool contentTypeSupport =
+ std::find(capabilities.begin(), capabilities.end(), contentType) != capabilities.end();
+
+ if (!contentTypeSupport) {
+ EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType));
+ GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
+ << to_string(display) << ", skipping test";
+ return;
+ }
+
+ EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, contentType));
+ EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, ContentType::NONE));
+}
+
+void GraphicsComposerHidlTest::Test_setContentType(const ContentType& contentType,
+ const char* contentTypeStr) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ std::vector<ContentType> supportedContentTypes;
+ const auto error =
+ mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+ EXPECT_EQ(Error::NONE, error);
+
+ Test_setContentTypeForDisplay(display, supportedContentTypes, contentType, contentTypeStr);
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setGraphicsContentType) {
+ Test_setContentType(ContentType::GRAPHICS, "GRAPHICS");
+}
+
+TEST_P(GraphicsComposerHidlTest, setPhotoContentType) {
+ Test_setContentType(ContentType::PHOTO, "PHOTO");
+}
+
+TEST_P(GraphicsComposerHidlTest, setCinemaContentType) {
+ Test_setContentType(ContentType::CINEMA, "CINEMA");
+}
+
+TEST_P(GraphicsComposerHidlTest, setGameContentType) {
+ Test_setContentType(ContentType::GAME, "GAME");
+}
+
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index 03dfef1..93c85bd 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -206,6 +206,9 @@
* outside of @p accessRegion is undefined, except that it must not cause
* process termination.
*
+ * An accessRegion of all-zeros means the entire buffer. That is, it is
+ * equivalent to '(0,0)-(buffer width, buffer height)'.
+ *
* This function can lock both single-planar and multi-planar formats. The caller
* should use get() to get information about the buffer they are locking.
* get() can be used to get information about the planes, offsets, stride,
@@ -478,7 +481,7 @@
* particular Metadata field.
*
* The framework may attempt to set the following StandardMetadataType
- * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE.
+ * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
* We strongly encourage everyone to support setting as many of those fields as
* possible. If a device's Composer implementation supports a field, it should be
* supported here. Over time these metadata fields will be moved out of
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 8a5f54e..cb90fa0 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -71,13 +71,6 @@
return mAllocator;
}
-std::string Gralloc::dumpDebugInfo() {
- std::string debugInfo;
- mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
- return debugInfo;
-}
-
const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
EXPECT_NE(nullptr, bufferHandle);
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index 1c635c4..cd40aa4 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -45,8 +45,6 @@
sp<IAllocator> getAllocator() const;
- std::string dumpDebugInfo();
-
// When import is false, this simply calls IAllocator::allocate. When import
// is true, the returned buffers are also imported into the mapper.
//
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 7dc733c..2aad242 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -44,11 +44,13 @@
using android::hardware::graphics::common::V1_2::PixelFormat;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
using aidl::android::hardware::graphics::common::BlendMode;
+using aidl::android::hardware::graphics::common::Cta861_3;
using aidl::android::hardware::graphics::common::Dataspace;
using aidl::android::hardware::graphics::common::ExtendableType;
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using aidl::android::hardware::graphics::common::Smpte2086;
using aidl::android::hardware::graphics::common::StandardMetadataType;
using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
@@ -306,13 +308,6 @@
};
/**
- * Test IAllocator::dumpDebugInfo by calling it.
- */
-TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
- mGralloc->dumpDebugInfo();
-}
-
-/**
* Test IAllocator::allocate with valid buffer descriptors.
*/
TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
@@ -1027,6 +1022,42 @@
}
/**
+ * Test IMapper::get(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2086) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Smpte2086> smpte2086;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+ EXPECT_FALSE(smpte2086.has_value());
+ });
+}
+
+/**
+ * Test IMapper::get(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetCta861_3) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Cta861_3> cta861_3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+ EXPECT_FALSE(cta861_3.has_value());
+ });
+}
+
+/**
+ * Test IMapper::get(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2094_40) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<std::vector<uint8_t>> smpte2094_40;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+ EXPECT_FALSE(smpte2094_40.has_value());
+ });
+}
+
+/**
* Test IMapper::get(metadata) with a bad buffer
*/
TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) {
@@ -1079,6 +1110,15 @@
ASSERT_EQ(Error::BAD_BUFFER,
mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec));
ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec));
+ ASSERT_EQ(0, vec.size());
}
/**
@@ -1406,7 +1446,7 @@
* Test IMapper::set(Dataspace)
*/
TEST_P(GraphicsMapperHidlTest, SetDataspace) {
- Dataspace dataspace = Dataspace::V0_SRGB_LINEAR;
+ Dataspace dataspace = Dataspace::SRGB_LINEAR;
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec));
@@ -1435,6 +1475,90 @@
}
/**
+ * Test IMapper::set(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2086) {
+ /**
+ * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+ * the D65 white point and the SRGB transfer functions.
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ */
+ std::optional<Smpte2086> smpte2086;
+ smpte2086->primaryRed.x = 0.680;
+ smpte2086->primaryRed.y = 0.320;
+ smpte2086->primaryGreen.x = 0.265;
+ smpte2086->primaryGreen.y = 0.690;
+ smpte2086->primaryBlue.x = 0.150;
+ smpte2086->primaryBlue.y = 0.060;
+ smpte2086->whitePoint.x = 0.3127;
+ smpte2086->whitePoint.y = 0.3290;
+ smpte2086->maxLuminance = 100.0;
+ smpte2086->minLuminance = 0.1;
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Smpte2086> realSmpte2086;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086));
+ ASSERT_TRUE(realSmpte2086.has_value());
+ EXPECT_EQ(smpte2086->primaryRed.x, realSmpte2086->primaryRed.x);
+ EXPECT_EQ(smpte2086->primaryRed.y, realSmpte2086->primaryRed.y);
+ EXPECT_EQ(smpte2086->primaryGreen.x, realSmpte2086->primaryGreen.x);
+ EXPECT_EQ(smpte2086->primaryGreen.y, realSmpte2086->primaryGreen.y);
+ EXPECT_EQ(smpte2086->primaryBlue.x, realSmpte2086->primaryBlue.x);
+ EXPECT_EQ(smpte2086->primaryBlue.y, realSmpte2086->primaryBlue.y);
+ EXPECT_EQ(smpte2086->whitePoint.x, realSmpte2086->whitePoint.x);
+ EXPECT_EQ(smpte2086->whitePoint.y, realSmpte2086->whitePoint.y);
+ EXPECT_EQ(smpte2086->maxLuminance, realSmpte2086->maxLuminance);
+ EXPECT_EQ(smpte2086->minLuminance, realSmpte2086->minLuminance);
+ });
+}
+
+/**
+ * Test IMapper::set(Cta8613)
+ */
+TEST_P(GraphicsMapperHidlTest, SetCta861_3) {
+ std::optional<Cta861_3> cta861_3;
+ cta861_3->maxContentLightLevel = 78.0;
+ cta861_3->maxFrameAverageLightLevel = 62.0;
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Cta861_3> realCta861_3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3));
+ ASSERT_TRUE(realCta861_3.has_value());
+ EXPECT_EQ(cta861_3->maxContentLightLevel, realCta861_3->maxContentLightLevel);
+ EXPECT_EQ(cta861_3->maxFrameAverageLightLevel,
+ realCta861_3->maxFrameAverageLightLevel);
+ });
+}
+
+/**
+ * Test IMapper::set(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2094_40) {
+ hidl_vec<uint8_t> vec;
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<std::vector<uint8_t>> realSmpte2094_40;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40));
+ EXPECT_FALSE(realSmpte2094_40.has_value());
+ });
+}
+
+/**
* Test IMapper::set(metadata) with a bad buffer
*/
TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) {
@@ -1469,6 +1593,11 @@
mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
ASSERT_EQ(Error::BAD_BUFFER,
mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec));
}
/**
@@ -1528,6 +1657,10 @@
mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
ASSERT_EQ(Error::UNSUPPORTED,
mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
}
/**
@@ -1760,6 +1893,45 @@
}
/**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, &vec));
+
+ std::optional<Smpte2086> smpte2086;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+ EXPECT_FALSE(smpte2086.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, &vec));
+
+ std::optional<Cta861_3> cta861_3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+ EXPECT_FALSE(cta861_3.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+ gralloc4::MetadataType_Smpte2094_40, &vec));
+ std::optional<std::vector<uint8_t>> smpte2094_40;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+ EXPECT_FALSE(smpte2094_40.has_value());
+}
+
+/**
* Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata
*/
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) {
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 07409f6..7241984 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -201,22 +201,6 @@
CheckedDeleteKey(&key_blob_);
}
-void KeymasterHidlTest::CheckCreationDateTime(
- const AuthorizationSet& sw_enforced,
- std::chrono::time_point<std::chrono::system_clock> creation) {
- for (int i = 0; i < sw_enforced.size(); i++) {
- if (sw_enforced[i].tag == TAG_CREATION_DATETIME) {
- std::chrono::time_point<std::chrono::system_clock> now =
- std::chrono::system_clock::now();
- std::chrono::time_point<std::chrono::system_clock> reported_time{
- std::chrono::milliseconds(sw_enforced[i].f.dateTime)};
- // The test is flaky for EC keys, so a buffer time of 120 seconds will be added.
- EXPECT_LE(creation - std::chrono::seconds(120), reported_time);
- EXPECT_LE(reported_time, now + std::chrono::seconds(1));
- }
- }
-}
-
void KeymasterHidlTest::CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
const HidlBuf& app_data,
KeyCharacteristics* key_characteristics) {
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index adceead..4bd8b26 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -113,9 +113,6 @@
void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
void CheckedDeleteKey();
- static void CheckCreationDateTime(const AuthorizationSet& sw_enforced,
- std::chrono::time_point<std::chrono::system_clock> creation);
-
void CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
const HidlBuf& app_data, KeyCharacteristics* key_characteristics);
ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 35a2fb1..66132ad 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -320,8 +320,7 @@
bool verify_attestation_record(const string& challenge, const string& app_id,
AuthorizationSet expected_sw_enforced,
AuthorizationSet expected_hw_enforced, SecurityLevel security_level,
- const hidl_vec<uint8_t>& attestation_cert,
- std::chrono::time_point<std::chrono::system_clock> creation_time) {
+ const hidl_vec<uint8_t>& attestation_cert) {
X509_Ptr cert(parse_cert_blob(attestation_cert));
EXPECT_TRUE(!!cert.get());
if (!cert.get()) return false;
@@ -405,8 +404,6 @@
EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- KeymasterHidlTest::CheckCreationDateTime(att_sw_enforced, creation_time);
-
if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
// For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
@@ -423,27 +420,33 @@
EXPECT_EQ(ErrorCode::OK, error);
if (avb_verification_enabled()) {
- property_get("ro.boot.vbmeta.digest", property_value, "nogood");
- EXPECT_NE(strcmp(property_value, "nogood"), 0);
+ EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
string prop_string(property_value);
EXPECT_EQ(prop_string.size(), 64);
EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
- property_get("ro.boot.vbmeta.device_state", property_value, "nogood");
- EXPECT_NE(strcmp(property_value, "nogood"), 0);
+ EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
if (!strcmp(property_value, "unlocked")) {
EXPECT_FALSE(device_locked);
} else {
EXPECT_TRUE(device_locked);
}
+
+ // Check that the expected result from VBMeta matches the build type. Only a user build
+ // should have AVB reporting the device is locked.
+ EXPECT_NE(property_get("ro.build.type", property_value, ""), 0);
+ if (!strcmp(property_value, "user")) {
+ EXPECT_TRUE(device_locked);
+ } else {
+ EXPECT_FALSE(device_locked);
+ }
}
// Verified boot key should be all 0's if the boot state is not verified or self signed
std::string empty_boot_key(32, '\0');
std::string verified_boot_key_str((const char*)verified_boot_key.data(),
verified_boot_key.size());
- property_get("ro.boot.verifiedbootstate", property_value, "nogood");
- EXPECT_NE(property_value, "nogood");
+ EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
if (!strcmp(property_value, "green")) {
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_VERIFIED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
@@ -546,31 +549,13 @@
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
<< "Key size " << key_size << "missing";
- EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 3U));
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
CheckedDeleteKey(&key_blob);
}
}
/*
- * NewKeyGenerationTest.RsaCheckCreationDateTime
- *
- * Verifies that creation date time is correct.
- */
-TEST_P(NewKeyGenerationTest, RsaCheckCreationDateTime) {
- KeyCharacteristics key_characteristics;
- auto creation_time = std::chrono::system_clock::now();
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaSigningKey(2048, 3)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)));
- GetCharacteristics(key_blob_, &key_characteristics);
- AuthorizationSet sw_enforced = key_characteristics.softwareEnforced;
- CheckCreationDateTime(sw_enforced, creation_time);
-}
-
-/*
* NewKeyGenerationTest.NoInvalidRsaSizes
*
* Verifies that keymaster cannot generate any RSA key sizes that are designated as invalid.
@@ -635,23 +620,6 @@
}
/*
- * NewKeyGenerationTest.EcCheckCreationDateTime
- *
- * Verifies that creation date time is correct.
- */
-TEST_P(NewKeyGenerationTest, EcCheckCreationDateTime) {
- KeyCharacteristics key_characteristics;
- auto creation_time = std::chrono::system_clock::now();
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
- .Digest(Digest::NONE)));
- GetCharacteristics(key_blob_, &key_characteristics);
- AuthorizationSet sw_enforced = key_characteristics.softwareEnforced;
- CheckCreationDateTime(sw_enforced, creation_time);
-}
-
-/*
* NewKeyGenerationTest.EcdsaDefaultSize
*
* Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
@@ -2639,8 +2607,10 @@
.Padding(PaddingMode::NONE));
ASSERT_EQ(ErrorCode::OK, err) << "Got " << err;
- err = Begin(KeyPurpose::DECRYPT,
- AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+ err = Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128));
EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
CheckedDeleteKey();
@@ -2653,8 +2623,10 @@
.Authorization(TAG_MIN_MAC_LENGTH, 128)
.Padding(PaddingMode::NONE)));
- err = Begin(KeyPurpose::ENCRYPT,
- AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+ err = Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128));
EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
}
@@ -4232,7 +4204,6 @@
* Verifies that attesting to RSA keys works and generates the expected output.
*/
TEST_P(AttestationTest, RsaAttestation) {
- auto creation_time = std::chrono::system_clock::now();
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -4257,7 +4228,7 @@
EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
key_characteristics_.softwareEnforced, //
key_characteristics_.hardwareEnforced, //
- SecLevel(), cert_chain[0], creation_time));
+ SecLevel(), cert_chain[0]));
}
/*
@@ -4286,7 +4257,6 @@
* Verifies that attesting to EC keys works and generates the expected output.
*/
TEST_P(AttestationTest, EcAttestation) {
- auto creation_time = std::chrono::system_clock::now();
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -4308,7 +4278,7 @@
EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
key_characteristics_.softwareEnforced, //
key_characteristics_.hardwareEnforced, //
- SecLevel(), cert_chain[0], creation_time));
+ SecLevel(), cert_chain[0]));
}
/*
@@ -4341,7 +4311,6 @@
TEST_P(AttestationTest, AttestationApplicationIDLengthProperlyEncoded) {
std::vector<uint32_t> app_id_lengths{143, 258};
for (uint32_t length : app_id_lengths) {
- auto creation_time = std::chrono::system_clock::now();
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -4359,7 +4328,7 @@
EXPECT_TRUE(verify_attestation_record("challenge", app_id, //
key_characteristics_.softwareEnforced, //
key_characteristics_.hardwareEnforced, //
- SecLevel(), cert_chain[0], creation_time));
+ SecLevel(), cert_chain[0]));
CheckedDeleteKey();
}
}
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index be894f2..e3c5376 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -452,7 +452,7 @@
EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE);
} break;
case TestKind::QUANTIZATION_COUPLING: {
- ASSERT_TRUE(testModel.hasQuant8AsymmOperands());
+ ASSERT_TRUE(testModel.hasQuant8CoupledOperands());
createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false);
TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
sp<IPreparedModel> preparedCoupledModel;
@@ -521,7 +521,7 @@
[](const TestModel& testModel) { return !testModel.expectFailure; });
INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) {
- return testModel.hasQuant8AsymmOperands() && testModel.operations.size() == 1;
+ return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1;
});
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 65880b7..14ab897 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -330,6 +330,8 @@
// - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
// - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
// - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
+ // - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of
+ // TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED.
switch (operation.type) {
case OperationType::LSH_PROJECTION: {
if (operand == operation.inputs[1]) {
@@ -385,6 +387,13 @@
return true;
}
} break;
+ case OperationType::AXIS_ALIGNED_BBOX_TRANSFORM: {
+ if (operand == operation.inputs[1] &&
+ (type == OperandType::TENSOR_QUANT8_ASYMM ||
+ type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) {
+ return true;
+ }
+ } break;
default:
break;
}
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index a3a3d90..fafc6e2 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -18,8 +18,10 @@
import @1.2::DataRequestReason;
import @1.4::IRadio;
+import @1.4::DataProfileInfo;
import @1.5::AccessNetwork;
import @1.5::DataProfileInfo;
+import @1.5::LinkAddress;
import @1.5::NetworkScanRequest;
import @1.5::RadioAccessSpecifier;
import @1.5::SignalThresholdInfo;
@@ -149,12 +151,8 @@
* @param reason The request reason. Must be DataRequestReason.NORMAL or
* DataRequestReason.HANDOVER.
* @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
- * addresses of the existing data connection. The format is IP address with optional "/"
- * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
- * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
- * the prefix length is absent, then the addresses are assumed to be point to point with
- * IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored
- * unless reason is DataRequestReason.HANDOVER.
+ * addresses of the existing data connection. This parameter must be ignored unless reason
+ * is DataRequestReason.HANDOVER.
* @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
* addresses of the existing data connection. The format is defined in RFC-4291 section
* 2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless
@@ -163,11 +161,11 @@
* Response function is IRadioResponse.setupDataCallResponse_1_5()
*
* Note this API is the same as the 1.4 version except using the
- * 1.5 AccessNetwork and DataProfileInto as the input param.
+ * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param.
*/
oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork,
DataProfileInfo dataProfileInfo, bool roamingAllowed,
- DataRequestReason reason, vec<string> addresses, vec<string> dnses);
+ DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
/**
* Set an apn to initial attach network
@@ -194,4 +192,31 @@
* as the input param.
*/
oneway setDataProfile_1_5(int32_t serial, vec<DataProfileInfo> profiles);
+
+ /**
+ * Toggle radio on and off (for "airplane" mode)
+ * If the radio is turned off/on the radio modem subsystem
+ * is expected return to an initialized state. For instance,
+ * any voice and data calls must be terminated and all associated
+ * lists emptied.
+ *
+ * When setting radio power on to exit from airplane mode to place an emergency call on this
+ * logical modem, powerOn, forEmergencyCall and preferredForEmergencyCall must be true. In
+ * this case, this modem is optimized to scan only emergency call bands, until:
+ * 1) Emergency call is completed; or
+ * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or
+ * preferredForEmergencyCall being false; or
+ * 3) Timeout after a long period of time.
+ *
+ * @param serial Serial number of request.
+ * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false.
+ * @param forEmergencyCall To indication to radio if this request is due to emergency call.
+ * No effect if powerOn is false.
+ * @param preferredForEmergencyCall indicate whether the following emergency call will be sent
+ * on this modem or not. No effect if forEmergencyCall is false, or powerOn is false.
+ *
+ * Response callback is IRadioConfigResponse. setRadioPowerResponse_1_5.
+ */
+ oneway setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+ bool preferredForEmergencyCall);
};
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
index 81452ab..879e9ad 100644
--- a/radio/1.5/IRadioIndication.hal
+++ b/radio/1.5/IRadioIndication.hal
@@ -30,4 +30,33 @@
* @param enabled whether uiccApplications are enabled, or disabled
*/
oneway uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
+
+ /**
+ * Report that Registration or a Location/Routing/Tracking Area update has failed.
+ *
+ * <p>Indicate whenever a registration procedure, including a location, routing, or tracking
+ * area update fails. This includes procedures that do not necessarily result in a change of
+ * the modem's registration status. If the modem's registration status changes, that is
+ * reflected in the onNetworkStateChanged() and subsequent get{Voice/Data}RegistrationState().
+ *
+ * @param cellIdentity the CellIdentity, which must include the globally unique identifier for
+ * the cell (for example, all components of the CGI or ECGI).
+ * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the
+ * cell that was chosen for the failed registration attempt.
+ * @param domain Domain::CS, Domain::PS, or both in case of a combined procedure.
+ * @param causeCode the primary failure cause code of the procedure.
+ * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95
+ * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147
+ * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+ * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2
+ * MAX_INT if this value is unused.
+ * @param additionalCauseCode the cause code of any secondary/combined procedure if appropriate.
+ * For UMTS, if a combined attach succeeds for PS only, then the GMM cause code shall be
+ * included as an additionalCauseCode.
+ * For LTE (ESM), cause codes are in TS 24.301 9.9.4.4
+ * MAX_INT if this value is unused.
+ */
+ oneway registrationFailed(
+ RadioIndicationType type, CellIdentity cellIdentity, string chosenPlmn,
+ bitfield<Domain> domain, int32_t causeCode, int32_t additionalCauseCode);
};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 11ec265..968948b 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -18,7 +18,7 @@
import @1.0::RadioResponseInfo;
import @1.4::IRadioResponse;
-import @1.4::SetupDataCallResult;
+import @1.5::SetupDataCallResult;
/**
* Interface declaring response functions to solicited radio requests.
@@ -135,4 +135,14 @@
* RadioError:SIM_ABSENT
*/
oneway setDataProfileResponse_1_5(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:INTERNAL_ERR
+ * RadioError:INVALID_ARGUMENTS
+ */
+ oneway setRadioPowerResponse_1_5(RadioResponseInfo info);
};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 5795f7b..7d6ec41 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -22,10 +22,21 @@
import @1.1::RadioAccessSpecifier;
import @1.1::ScanType;
import @1.1::UtranBands;
+import @1.2::CellIdentityCdma;
+import @1.2::CellIdentityGsm;
+import @1.2::CellIdentityWcdma;
+import @1.2::CellIdentityTdscdma;
+import @1.2::CellIdentityLte;
import @1.2::NetworkScanRequest;
import @1.4::AccessNetwork;
import @1.4::ApnTypes;
+import @1.4::CellIdentityNr;
+import @1.4::DataCallFailCause;
+import @1.4::DataConnActiveStatus;
import @1.4::DataProfileInfo;
+import @1.4::PdpProtocolType;
+
+import android.hidl.safe_union@1.0::Monostate;
/**
* Defining signal strength type.
@@ -54,9 +65,9 @@
RSRP = 3,
/**
* Reference Signal Received Quality
- * Range: -20 dB to -3 dB;
+ * Range: -34 dB to 3 dB;
* Used RAN: EUTRAN
- * Reference: 3GPP TS 36.133 9.1.7
+ * Reference: 3GPP TS 36.133 v12.6.0 section 9.1.7
*/
RSRQ = 4,
/**
@@ -289,3 +300,127 @@
/** Supported APN types bitmap. See ApnTypes for the value of each bit. */
bitfield<ApnTypes> supportedApnTypesBitmap;
};
+
+/**
+ * The properties of the link address. This enum reflects the definition in
+ * if_addr.h in Linux kernel.
+ */
+enum AddressProperty : int32_t {
+ NONE = 0,
+
+ /** Indicates this address is deprecated */
+ DEPRECATED = 0x20,
+};
+
+/**
+ * Describes a data link address for mobile data connection.
+ */
+struct LinkAddress {
+ /**
+ * The format is IP address with optional "/"
+ * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
+ * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
+ * the prefix length is absent, then the addresses are assumed to be point to point with
+ * IPv4 with prefix length 32 or IPv6 with prefix length 128.
+ */
+ string address;
+
+ /**
+ * The properties of the link address
+ */
+ bitfield<AddressProperty> properties;
+
+ /**
+ * The UTC time that this link address will be deprecated. 0 indicates this information is not
+ * available.
+ */
+ uint64_t deprecatedTime;
+
+ /**
+ * The UTC time that this link address will expire and no longer valid. 0 indicates this
+ * information is not available.
+ */
+ uint64_t expiredTime;
+};
+
+/**
+ * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
+ * version. In 1.5 the type of addresses changes to vector of LinkAddress.
+ */
+struct SetupDataCallResult {
+ /** Data call fail cause. DataCallFailCause.NONE if no error. */
+ DataCallFailCause cause;
+
+ /**
+ * If status != DataCallFailCause.NONE, this field indicates the suggested retry back-off timer
+ * value RIL wants to override the one pre-configured in FW. The unit is milliseconds.
+ * The value < 0 means no value is suggested.
+ * The value 0 means retry must be done ASAP.
+ * The value of INT_MAX(0x7fffffff) means no retry.
+ */
+ int32_t suggestedRetryTime;
+
+ /** Context ID, uniquely identifies this call. */
+ int32_t cid;
+
+ /** Data connection active status. */
+ DataConnActiveStatus active;
+
+ /**
+ * PDP_type values. If cause is DataCallFailCause.ONLY_SINGLE_BEARER_ALLOWED, this is the type
+ * supported such as "IP" or "IPV6".
+ */
+ PdpProtocolType type;
+
+ /** The network interface name. */
+ string ifname;
+
+ /**
+ * List of link address.
+ */
+ vec<LinkAddress> addresses;
+
+ /**
+ * List of DNS server addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1". Empty if no dns
+ * server addresses returned.
+ */
+ vec<string> dnses;
+
+ /**
+ * List of default gateway addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+ * When empty, the addresses represent point to point connections.
+ */
+ vec<string> gateways;
+
+ /**
+ * List of P-CSCF(Proxy Call State Control Function) addresses via PCO(Protocol Configuration
+ * Option), e.g., "2001:db8::1 2001:db8::2 2001:db8::3". Empty if not IMS client.
+ */
+ vec<string> pcscf;
+
+ /**
+ * MTU received from network. Value <= 0 means network has either not sent a value or sent an
+ * invalid value.
+ */
+ int32_t mtu;
+};
+
+enum Domain : int32_t {
+ /** Circuit-switched */
+ CS = 1 << 0,
+
+ /** Packet-switched */
+ PS = 1 << 1,
+};
+
+/** A union representing the CellIdentity of a single cell */
+safe_union CellIdentity {
+ Monostate noinit;
+
+ CellIdentityGsm gsm;
+ CellIdentityWcdma wcdma;
+ CellIdentityTdscdma tdscdma;
+ CellIdentityCdma cdma;
+ CellIdentityLte lte;
+ CellIdentityNr nr;
+};
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 1243bed..77d9a02 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -853,10 +853,11 @@
bool roamingAllowed = false;
+ std::vector<::android::hardware::radio::V1_5::LinkAddress> addresses = {};
+ std::vector<hidl_string> dnses = {};
+
::android::hardware::radio::V1_2::DataRequestReason reason =
::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
- std::vector<hidl_string> addresses = {""};
- std::vector<hidl_string> dnses = {""};
Return<void> res = radio_v1_5->setupDataCall_1_5(serial, accessNetwork, dataProfileInfo,
roamingAllowed, reason, addresses, dnses);
@@ -958,3 +959,31 @@
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
}
}
+
+TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) {
+ // Set radio power to off.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, false, false, false);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ // Set radio power to on with forEmergencyCall being true. This should put modem to only scan
+ // emergency call bands.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, true, true, true);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ // Set radio power to on with forEmergencyCall being false. This should put modem in regular
+ // operation modem.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, true, false, false);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+}
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index f7526d9..49a315d 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -544,11 +544,13 @@
Return<void> setupDataCallResponse_1_5(
const RadioResponseInfo& info,
- const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
+ const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse);
Return<void> setInitialAttachApnResponse_1_5(const RadioResponseInfo& info);
Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
+
+ Return<void> setRadioPowerResponse_1_5(const RadioResponseInfo& info);
};
/* Callback class for radio indication */
@@ -737,6 +739,13 @@
Return<void> modemReset(RadioIndicationType type,
const ::android::hardware::hidl_string& reason);
+
+ Return<void> registrationFailed(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
+ const ::android::hardware::hidl_string& chosenPlmn,
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> domain,
+ int32_t causeCode, int32_t additionalCauseCode);
};
// Test environment for Radio HIDL HAL.
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
index acffbbe..2416605 100644
--- a/radio/1.5/vts/functional/radio_indication.cpp
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -333,3 +333,12 @@
bool /*enabled*/) {
return Void();
}
+
+Return<void> RadioIndication_v1_5::registrationFailed(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
+ const ::android::hardware::hidl_string& /*chosenPlmn*/,
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/,
+ int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) {
+ return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 5dee191..a0b3d5f 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -931,7 +931,7 @@
Return<void> RadioResponse_v1_5::setupDataCallResponse_1_5(
const RadioResponseInfo& info,
- const android::hardware::radio::V1_4::SetupDataCallResult& /* dcResponse */) {
+ const android::hardware::radio::V1_5::SetupDataCallResult& /* dcResponse */) {
rspInfo = info;
parent_v1_5.notify(info.serial);
return Void();
@@ -948,3 +948,9 @@
parent_v1_5.notify(info.serial);
return Void();
}
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse_1_5(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
\ No newline at end of file
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
new file mode 100644
index 0000000..7bc8d6f
--- /dev/null
+++ b/rebootescrow/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+ name: "vintf-rebootescrow",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/rebootescrow/IRebootEscrow.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
new file mode 100644
index 0000000..edc695d
--- /dev/null
+++ b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.rebootescrow;
+
+/**
+ * This HAL defines the interface to the device-specific implementation
+ * of retaining a secret to unlock the Synthetic Password stored during
+ * a reboot to perform an OTA update. The implementation of this interface
+ * should never store the key on any non-volatile medium. The key should be
+ * overwritten with zeroes when destroyKey() is called. All care should be given
+ * to provide the shortest lifetime for the storage of the key in volatile and
+ * erasable storage.
+ *
+ * This HAL is optional so does not require an implementation on device.
+ */
+@VintfStability
+interface IRebootEscrow {
+ /**
+ * Store the key for reboot.
+ */
+ void storeKey(in byte[] kek);
+
+ /**
+ * Retrieve the possible keys. If the implementation is probabalistic, it
+ * should return the keys in order from most-probable to least-probable.
+ * There is not a hard limit to the number of keys, but it is suggested to
+ * keep the number of key possibilities less than 32.
+ */
+ byte[] retrieveKey();
+}
diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp
new file mode 100644
index 0000000..c8cbf48
--- /dev/null
+++ b/rebootescrow/aidl/default/Android.bp
@@ -0,0 +1,88 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+ name: "librebootescrowdefaultimpl",
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "vintf-rebootescrow-ndk_platform",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "RebootEscrow.cpp",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.rebootescrow-service.default",
+ init_rc: ["rebootescrow-default.rc"],
+ relative_install_path: "hw",
+ vintf_fragments: ["rebootescrow-default.xml"],
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "vintf-rebootescrow-ndk_platform",
+ ],
+ static_libs: [
+ "libhadamardutils",
+ "librebootescrowdefaultimpl",
+ ],
+}
+
+cc_library_static {
+ name: "libhadamardutils",
+ vendor_available: true,
+ host_supported: true,
+ shared_libs: [
+ "libbase",
+ ],
+ srcs: [
+ "HadamardUtils.cpp",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_test {
+ name: "HadamardUtilsTest",
+ host_supported: true,
+ srcs: [
+ "HadamardUtilsTest.cpp",
+ ],
+ static_libs: [
+ "libhadamardutils",
+ "libgtest_prod",
+ ],
+ shared_libs: [
+ "liblog",
+ "libbase",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp
new file mode 100644
index 0000000..d2422b9
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <HadamardUtils.h>
+
+#include <limits>
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+static inline uint8_t read_bit(const std::vector<uint8_t>& input, size_t bit) {
+ return (input[bit >> 3] >> (bit & 7)) & 1u;
+}
+
+// Use a simple LCG which is easy to run in reverse.
+// https://www.johndcook.com/blog/2017/07/05/simple-random-number-generator/
+constexpr uint64_t RNG_MODULUS = 0x7fffffff;
+constexpr uint64_t RNG_MUL = 742938285;
+constexpr uint64_t RNG_SEED = 20170705;
+constexpr uint64_t RNG_INV_MUL = 1413043504; // (mul * inv_mul) % modulus == 1
+constexpr uint64_t RNG_INV_SEED = 1173538311; // (seed * mul**65534) % modulus
+
+// Apply an error correcting encoding.
+//
+// The error correcting code used is an augmented Hadamard code with
+// k=15, so it takes a 16-bit input and produces a 2^15-bit output.
+// We break the 32-byte key into 16 16-bit codewords and encode
+// each codeword to a 2^15-bit output.
+//
+// To better defend against clustered errors, we stripe together the encoded
+// codewords. Thus if a single 512-byte DRAM line is lost, instead of losing
+// 2^11 bits from the encoding of a single code word, we lose 2^7 bits
+// from the encoding of each of the 16 codewords.
+// In addition we apply a Fisher-Yates shuffle to the bytes of the encoding;
+// Hadamard encoding recovers much better from random errors than systematic
+// ones, and this ensures that errors will be random.
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input) {
+ CHECK_EQ(input.size(), KEY_SIZE_IN_BYTES);
+ std::vector<uint8_t> result(OUTPUT_SIZE_BYTES, 0);
+ static_assert(OUTPUT_SIZE_BYTES == 64 * 1024);
+ // Transpose the key so that each row contains one bit from each codeword
+ uint16_t wordmatrix[CODEWORD_BITS];
+ for (size_t i = 0; i < CODEWORD_BITS; i++) {
+ uint16_t word = 0;
+ for (size_t j = 0; j < KEY_CODEWORDS; j++) {
+ word |= read_bit(input, i + j * CODEWORD_BITS) << j;
+ }
+ wordmatrix[i] = word;
+ }
+ // Fill in the encodings in Gray code order for speed.
+ uint16_t val = wordmatrix[CODEWORD_BITS - 1];
+ size_t ix = 0;
+ for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+ for (size_t b = 0; b < CODEWORD_BITS; b++) {
+ if (i & (1 << b)) {
+ ix ^= (1 << b);
+ val ^= wordmatrix[b];
+ break;
+ }
+ }
+ result[ix * KEY_CODEWORD_BYTES] = val & 0xffu;
+ result[ix * KEY_CODEWORD_BYTES + 1] = val >> 8u;
+ }
+ // Apply the inverse shuffle here; we apply the forward shuffle in decoding.
+ uint64_t rng_state = RNG_INV_SEED;
+ for (size_t i = OUTPUT_SIZE_BYTES - 1; i > 0; i--) {
+ auto j = rng_state % (i + 1);
+ auto t = result[i];
+ result[i] = result[j];
+ result[j] = t;
+ rng_state *= RNG_INV_MUL;
+ rng_state %= RNG_MODULUS;
+ }
+ return result;
+}
+
+// Decode a single codeword. Because of the way codewords are striped together
+// this takes the entire input, plus an offset telling it which word to decode.
+static uint16_t DecodeWord(size_t word, const std::vector<uint8_t>& encoded) {
+ std::vector<int32_t> scores;
+ scores.reserve(ENCODE_LENGTH);
+ // Convert x -> -1^x in the encoded bits. e.g [1, 0, 0, 1] -> [-1, 1, 1, -1]
+ for (uint32_t i = 0; i < ENCODE_LENGTH; i++) {
+ scores.push_back(1 - 2 * read_bit(encoded, i * KEY_CODEWORDS + word));
+ }
+
+ // Multiply the hadamard matrix by the transformed input.
+ // |1 1 1 1| |-1| | 0|
+ // |1 -1 1 -1| * | 1| = | 0|
+ // |1 1 -1 -1| | 1| | 0|
+ // |1 -1 -1 1| |-1| |-4|
+ for (uint32_t i = 0; i < CODE_K; i++) {
+ uint16_t step = 1u << i;
+ for (uint32_t j = 0; j < ENCODE_LENGTH; j += 2 * step) {
+ for (uint32_t k = j; k < j + step; k++) {
+ auto a0 = scores[k];
+ auto a1 = scores[k + step];
+ scores[k] = a0 + a1;
+ scores[k + step] = a0 - a1;
+ }
+ }
+ }
+ auto hiscore = std::numeric_limits<int32_t>::min();
+ uint16_t winner;
+ // TODO(b/146520538): this needs to be constant time
+ for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+ if (scores[i] > hiscore) {
+ winner = i;
+ hiscore = scores[i];
+
+ } else if (-scores[i] > hiscore) {
+ winner = i | (1 << CODE_K);
+ hiscore = -scores[i];
+ }
+ }
+ return winner;
+}
+
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& shuffled) {
+ CHECK_EQ(OUTPUT_SIZE_BYTES, shuffled.size());
+ // Apply the forward Fisher-Yates shuffle.
+ std::vector<uint8_t> encoded(OUTPUT_SIZE_BYTES, 0);
+ encoded[0] = shuffled[0];
+ uint64_t rng_state = RNG_SEED;
+ for (size_t i = 1; i < OUTPUT_SIZE_BYTES; i++) {
+ auto j = rng_state % (i + 1);
+ encoded[i] = encoded[j];
+ encoded[j] = shuffled[i];
+ rng_state *= RNG_MUL;
+ rng_state %= RNG_MODULUS;
+ }
+ std::vector<uint8_t> result(KEY_SIZE_IN_BYTES, 0);
+ for (size_t i = 0; i < KEY_CODEWORDS; i++) {
+ uint16_t val = DecodeWord(i, encoded);
+ result[i * CODEWORD_BYTES] = val & 0xffu;
+ result[i * CODEWORD_BYTES + 1] = val >> 8u;
+ }
+ return result;
+}
+
+} // namespace hadamard
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h
new file mode 100644
index 0000000..e04f7d5
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+constexpr auto BYTE_LENGTH = 8u;
+constexpr auto CODEWORD_BYTES = 2u; // uint16_t
+constexpr auto CODEWORD_BITS = CODEWORD_BYTES * BYTE_LENGTH;
+constexpr uint32_t CODE_K = CODEWORD_BITS - 1;
+constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K;
+constexpr auto KEY_CODEWORD_BYTES = 2u; // uint16_t (after transpose)
+constexpr auto KEY_CODEWORDS = KEY_CODEWORD_BYTES * BYTE_LENGTH;
+constexpr auto KEY_SIZE_IN_BYTES = KEY_CODEWORDS * CODEWORD_BYTES;
+constexpr auto OUTPUT_SIZE_BYTES = ENCODE_LENGTH * KEY_CODEWORD_BYTES;
+
+// Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the
+// encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB.
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input);
+
+// Given a byte array representation of the encoded keys, decodes it and return the result.
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& encoded);
+
+} // namespace hadamard
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtilsTest.cpp b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
new file mode 100644
index 0000000..1c9a2fb
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <random>
+
+#include <gtest/gtest.h>
+
+#include <HadamardUtils.h>
+
+using namespace aidl::android::hardware::rebootescrow::hadamard;
+
+class HadamardTest : public testing::Test {};
+
+static void AddError(std::vector<uint8_t>* data) {
+ for (size_t i = 0; i < data->size(); i++) {
+ for (size_t j = 0; j < BYTE_LENGTH; j++) {
+ if (random() % 100 < 47) {
+ (*data)[i] ^= (1 << j);
+ }
+ }
+ }
+}
+
+TEST_F(HadamardTest, Decode_error_correction) {
+ constexpr auto iteration = 10;
+ for (int i = 0; i < iteration; i++) {
+ std::vector<uint8_t> key;
+ for (int j = 0; j < KEY_SIZE_IN_BYTES; j++) {
+ key.emplace_back(random() & 0xff);
+ }
+ auto encoded = EncodeKey(key);
+ ASSERT_EQ(64 * 1024, encoded.size());
+ AddError(&encoded);
+ auto decoded = DecodeKey(encoded);
+ ASSERT_EQ(key, std::vector<uint8_t>(decoded.begin(), decoded.begin() + key.size()));
+ }
+}
diff --git a/rebootescrow/aidl/default/OWNERS b/rebootescrow/aidl/default/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/default/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp
new file mode 100644
index 0000000..94d0901
--- /dev/null
+++ b/rebootescrow/aidl/default/RebootEscrow.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include "HadamardUtils.h"
+#include "rebootescrow-impl/RebootEscrow.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+using ::android::base::unique_fd;
+
+ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector<int8_t>& kek) {
+ int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd fd(rawFd);
+ if (fd.get() < 0) {
+ LOG(WARNING) << "Could not open reboot escrow device";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ std::vector<uint8_t> ukek(kek.begin(), kek.end());
+ auto encoded = hadamard::EncodeKey(ukek);
+
+ if (!::android::base::WriteFully(fd, encoded.data(), encoded.size())) {
+ LOG(WARNING) << "Could not write data fully to character device";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector<int8_t>* _aidl_return) {
+ int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd fd(rawFd);
+ if (fd.get() < 0) {
+ LOG(WARNING) << "Could not open reboot escrow device";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ std::string encodedString;
+ if (!::android::base::ReadFdToString(fd, &encodedString)) {
+ LOG(WARNING) << "Could not read device to string";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ std::vector<uint8_t> encodedBytes(encodedString.begin(), encodedString.end());
+ auto keyBytes = hadamard::DecodeKey(encodedBytes);
+
+ std::vector<int8_t> signedKeyBytes(keyBytes.begin(), keyBytes.end());
+ *_aidl_return = signedKeyBytes;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
new file mode 100644
index 0000000..1ed7397
--- /dev/null
+++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/rebootescrow/BnRebootEscrow.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+static const char* REBOOT_ESCROW_DEVICE = "/dev/access-kregistry";
+
+class RebootEscrow : public BnRebootEscrow {
+ ndk::ScopedAStatus storeKey(const std::vector<int8_t>& kek) override;
+ ndk::ScopedAStatus retrieveKey(std::vector<int8_t>* _aidl_return) override;
+};
+
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc
new file mode 100644
index 0000000..e7a9cfc
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.rc
@@ -0,0 +1,9 @@
+service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow-service.default
+ interface aidl android.hardware.rebootescrow.IRebootEscrow/default
+ class hal
+ user system
+ group system
+
+on boot
+ chmod 770 /dev/access-kregistry
+ chown system system /dev/access-kregistry
diff --git a/rebootescrow/aidl/default/rebootescrow-default.xml b/rebootescrow/aidl/default/rebootescrow-default.xml
new file mode 100644
index 0000000..0499fcc
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.rebootescrow</name>
+ <fqname>IRebootEscrow/default</fqname>
+ </hal>
+</manifest>
diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp
new file mode 100644
index 0000000..bd2378e
--- /dev/null
+++ b/rebootescrow/aidl/default/service.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "rebootescrow-impl/RebootEscrow.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::rebootescrow::RebootEscrow;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto re = ndk::SharedRefBase::make<RebootEscrow>();
+ const std::string instance = std::string() + RebootEscrow::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE;
+}
diff --git a/rebootescrow/aidl/vts/OWNERS b/rebootescrow/aidl/vts/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/vts/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..dadf250
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalRebootEscrowTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalRebootEscrowTargetTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "vintf-rebootescrow-cpp",
+ ],
+ test_suites: [
+ "vts-core",
+ ],
+ require_root: true,
+}
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
new file mode 100644
index 0000000..f69cf87
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/rebootescrow/BnRebootEscrow.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+using android::sp;
+using android::String16;
+using android::hardware::rebootescrow::IRebootEscrow;
+
+/**
+ * This tests that the key can be written, read, and removed. It does not test
+ * that the key survives a reboot. That needs a host-based test.
+ *
+ * atest VtsHalRebootEscrowV1_0TargetTest
+ */
+class RebootEscrowAidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ rebootescrow = android::waitForDeclaredService<IRebootEscrow>(String16(GetParam().c_str()));
+ ASSERT_NE(rebootescrow, nullptr);
+ }
+
+ sp<IRebootEscrow> rebootescrow;
+
+ std::vector<uint8_t> KEY_1{
+ 0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A,
+ 0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83,
+ 0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F,
+ };
+ std::vector<uint8_t> KEY_2{
+ 0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA,
+ 0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF,
+ 0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18,
+ };
+ std::vector<uint8_t> EMPTY_KEY{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+};
+
+TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) {
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_1);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) {
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_1);
+
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_1);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) {
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk());
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_2);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreEmpty_AfterGetEmptyKey_Success) {
+ rebootescrow->storeKey(KEY_1);
+ rebootescrow->storeKey(EMPTY_KEY);
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, EMPTY_KEY);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ RebootEscrow, RebootEscrowAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IRebootEscrow::descriptor)),
+ android::PrintInstanceNameToString);
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
index 3ed09f6..94e3c0c 100644
--- a/tv/tuner/1.0/IFilter.hal
+++ b/tv/tuner/1.0/IFilter.hal
@@ -104,11 +104,11 @@
*
* It is used by the client to ask the hardware resource id for the filter.
*
- * @param filterId the hardware resource Id for the filter.
* @return result Result status of the operation.
* SUCCESS if successful,
* INVALID_STATE if failed for wrong state.
* UNKNOWN_ERROR if failed for other reasons.
+ * @return filterId the hardware resource Id for the filter.
*/
getId() generates (Result result, uint32_t filterId);
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 71a26ab..43c4e3a 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -51,7 +51,8 @@
mFrontendSourceFile = mFrontend->getSourceFile();
mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
- return startBroadcastInputLoop();
+
+ return startFrontendInputLoop();
}
Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
@@ -136,14 +137,14 @@
return Void();
}
- sp<Dvr> dvr = new Dvr(type, bufferSize, cb, this);
+ mDvr = new Dvr(type, bufferSize, cb, this);
- if (!dvr->createDvrMQ()) {
- _hidl_cb(Result::UNKNOWN_ERROR, dvr);
+ if (!mDvr->createDvrMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, mDvr);
return Void();
}
- _hidl_cb(Result::SUCCESS, dvr);
+ _hidl_cb(Result::SUCCESS, mDvr);
return Void();
}
@@ -166,13 +167,14 @@
// resetFilterRecords(filterId);
mUsedFilterIds.erase(filterId);
+ mRecordFilterIds.erase(filterId);
mUnusedFilterIds.insert(filterId);
mFilters.erase(filterId);
return Result::SUCCESS;
}
-void Demux::startTsFilter(vector<uint8_t> data) {
+void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
set<uint32_t>::iterator it;
for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
@@ -185,7 +187,17 @@
}
}
-bool Demux::startFilterDispatcher() {
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
+ set<uint32_t>::iterator it;
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (DEBUG_FILTER) {
+ ALOGW("update record filter output");
+ }
+ mFilters[*it]->updateRecordOutput(data);
+ }
+}
+
+bool Demux::startBroadcastFilterDispatcher() {
set<uint32_t>::iterator it;
// Handle the output data per filter type
@@ -198,6 +210,18 @@
return true;
}
+bool Demux::startRecordFilterDispatcher() {
+ set<uint32_t>::iterator it;
+
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
Result Demux::startFilterHandler(uint32_t filterId) {
return mFilters[filterId]->startFilterHandler();
}
@@ -210,22 +234,22 @@
return mFilters[filterId]->getTpid();
}
-Result Demux::startBroadcastInputLoop() {
- pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this);
- pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread");
+Result Demux::startFrontendInputLoop() {
+ pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
+ pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
return Result::SUCCESS;
}
-void* Demux::__threadLoopBroadcast(void* user) {
+void* Demux::__threadLoopFrontend(void* user) {
Demux* const self = static_cast<Demux*>(user);
- self->broadcastInputThreadLoop();
+ self->frontendInputThreadLoop();
return 0;
}
-void Demux::broadcastInputThreadLoop() {
- std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
- mBroadcastInputThreadRunning = true;
+void Demux::frontendInputThreadLoop() {
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+ mFrontendInputThreadRunning = true;
mKeepFetchingDataFromFrontend = true;
// open the stream and get its length
@@ -234,20 +258,20 @@
int packetSize = 188;
int writePacketAmount = 6;
char* buffer = new char[packetSize];
- ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str());
+ ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str());
if (!inputData.is_open()) {
- mBroadcastInputThreadRunning = false;
+ mFrontendInputThreadRunning = false;
ALOGW("[Demux] Error %s", strerror(errno));
}
- while (mBroadcastInputThreadRunning) {
+ while (mFrontendInputThreadRunning) {
// move the stream pointer for packet size * 6 every read until the end
while (mKeepFetchingDataFromFrontend) {
for (int i = 0; i < writePacketAmount; i++) {
inputData.read(buffer, packetSize);
if (!inputData) {
mKeepFetchingDataFromFrontend = false;
- mBroadcastInputThreadRunning = false;
+ mFrontendInputThreadRunning = false;
break;
}
// filter and dispatch filter output
@@ -256,23 +280,61 @@
for (int index = 0; index < byteBuffer.size(); index++) {
byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
}
- startTsFilter(byteBuffer);
+ if (mIsRecording) {
+ // Feed the data into the Dvr recording input
+ sendFrontendInputToRecord(byteBuffer);
+ } else {
+ // Feed the data into the broadcast demux filter
+ startBroadcastTsFilter(byteBuffer);
+ }
}
- startFilterDispatcher();
+ if (mIsRecording) {
+ // Dispatch the data into the broadcasting filters.
+ startRecordFilterDispatcher();
+ } else {
+ // Dispatch the data into the broadcasting filters.
+ startBroadcastFilterDispatcher();
+ }
usleep(100);
}
}
- ALOGW("[Demux] Broadcast Input thread end.");
+ ALOGW("[Demux] Frontend Input thread end.");
delete[] buffer;
inputData.close();
}
-void Demux::stopBroadcastInput() {
+void Demux::stopFrontendInput() {
ALOGD("[Demux] stop frontend on demux");
mKeepFetchingDataFromFrontend = false;
- mBroadcastInputThreadRunning = false;
- std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+ mFrontendInputThreadRunning = false;
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+}
+
+void Demux::setIsRecording(bool isRecording) {
+ mIsRecording = isRecording;
+}
+
+bool Demux::attachRecordFilter(int filterId) {
+ if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+ return false;
+ }
+
+ mRecordFilterIds.insert(filterId);
+ mFilters[filterId]->attachFilterToRecord(mDvr);
+
+ return true;
+}
+
+bool Demux::detachRecordFilter(int filterId) {
+ if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+ return false;
+ }
+
+ mRecordFilterIds.erase(filterId);
+ mFilters[filterId]->detachFilterFromRecord();
+
+ return true;
}
} // namespace implementation
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 037429d..1405d0c 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -81,11 +81,14 @@
virtual Return<Result> disconnectCiCam() override;
// Functions interacts with Tuner Service
- void stopBroadcastInput();
+ void stopFrontendInput();
Result removeFilter(uint32_t filterId);
+ bool attachRecordFilter(int filterId);
+ bool detachRecordFilter(int filterId);
Result startFilterHandler(uint32_t filterId);
void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
uint16_t getFilterTpid(uint32_t filterId);
+ void setIsRecording(bool isRecording);
private:
// Tuner service
@@ -101,9 +104,9 @@
uint32_t filterId;
};
- Result startBroadcastInputLoop();
- static void* __threadLoopBroadcast(void* user);
- void broadcastInputThreadLoop();
+ Result startFrontendInputLoop();
+ static void* __threadLoopFrontend(void* user);
+ void frontendInputThreadLoop();
/**
* To create a FilterMQ with the the next available Filter ID.
@@ -117,9 +120,13 @@
/**
* A dispatcher to read and dispatch input data to all the started filters.
* Each filter handler handles the data filtering/output writing/filterEvent updating.
+ * Note that recording filters are not included.
*/
- bool startFilterDispatcher();
- void startTsFilter(vector<uint8_t> data);
+ bool startBroadcastFilterDispatcher();
+ void startBroadcastTsFilter(vector<uint8_t> data);
+
+ void sendFrontendInputToRecord(vector<uint8_t> data);
+ bool startRecordFilterDispatcher();
uint32_t mDemuxId;
uint32_t mCiCamId;
@@ -141,26 +148,40 @@
*/
set<uint32_t> mUnusedFilterIds;
/**
+ * Record all the attached record filter Ids.
+ * Any removed filter id should be removed from this set.
+ */
+ set<uint32_t> mRecordFilterIds;
+ /**
* A list of created FilterMQ ptrs.
* The array number is the filter ID.
*/
std::map<uint32_t, sp<Filter>> mFilters;
+ /**
+ * Local reference to the opened DVR object.
+ */
+ sp<Dvr> mDvr;
+
// Thread handlers
- pthread_t mBroadcastInputThread;
+ pthread_t mFrontendInputThread;
/**
* If a specific filter's writing loop is still running
*/
- bool mBroadcastInputThreadRunning;
+ bool mFrontendInputThreadRunning;
bool mKeepFetchingDataFromFrontend;
/**
+ * If the dvr recording is running.
+ */
+ bool mIsRecording = false;
+ /**
* Lock to protect writes to the FMQs
*/
std::mutex mWriteLock;
/**
* Lock to protect writes to the input status
*/
- std::mutex mBroadcastInputThreadLock;
+ std::mutex mFrontendInputThreadLock;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index eb38f90..3088a9d 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -70,7 +70,14 @@
return status;
}
+ // check if the attached filter is a record filter
+
mFilters[filterId] = filter;
+ mIsRecordFilterAttached = true;
+ if (!mDemux->attachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
return Result::SUCCESS;
}
@@ -95,6 +102,15 @@
it = mFilters.find(filterId);
if (it != mFilters.end()) {
mFilters.erase(filterId);
+ if (!mDemux->detachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+ }
+
+ // If all the filters are detached, record can't be started
+ if (mFilters.empty()) {
+ mIsRecordFilterAttached = false;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
}
return Result::SUCCESS;
@@ -115,8 +131,9 @@
pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
pthread_setname_np(mDvrThread, "playback_waiting_loop");
} else if (mType == DvrType::RECORD) {
- /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
- pthread_setname_np(mInputThread, "playback_waiting_loop");*/
+ mRecordStatus = RecordStatus::DATA_READY;
+ mIsRecordStarted = true;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
}
// TODO start another thread to send filter status callback to the framework
@@ -131,12 +148,17 @@
std::lock_guard<std::mutex> lock(mDvrThreadLock);
+ mIsRecordStarted = false;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
+
return Result::SUCCESS;
}
Return<Result> Dvr::flush() {
ALOGV("%s", __FUNCTION__);
+ mRecordStatus = RecordStatus::DATA_READY;
+
return Result::SUCCESS;
}
@@ -272,6 +294,45 @@
return true;
}
+bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
+ std::lock_guard<std::mutex> lock(mWriteLock);
+ ALOGW("[Dvr] write record FMQ");
+ if (mDvrMQ->write(data.data(), data.size())) {
+ mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ maySendRecordStatusCallback();
+ return true;
+ }
+
+ maySendRecordStatusCallback();
+ return false;
+}
+
+void Dvr::maySendRecordStatusCallback() {
+ std::lock_guard<std::mutex> lock(mRecordStatusLock);
+ int availableToRead = mDvrMQ->availableToRead();
+ int availableToWrite = mDvrMQ->availableToWrite();
+
+ RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
+ mDvrSettings.record().highThreshold,
+ mDvrSettings.record().lowThreshold);
+ if (mRecordStatus != newStatus) {
+ mCallback->onRecordStatus(newStatus);
+ mRecordStatus = newStatus;
+ }
+}
+
+RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold) {
+ if (availableToWrite == 0) {
+ return DemuxFilterStatus::OVERFLOW;
+ } else if (availableToRead > highThreshold) {
+ return DemuxFilterStatus::HIGH_WATER;
+ } else if (availableToRead < lowThreshold) {
+ return DemuxFilterStatus::LOW_WATER;
+ }
+ return mRecordStatus;
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index fbb778c..f39d8db 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -79,6 +79,8 @@
* Return false is any of the above processes fails.
*/
bool createDvrMQ();
+ void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
+ bool writeRecordFMQ(const std::vector<uint8_t>& data);
private:
// Demux service
@@ -95,6 +97,8 @@
void maySendRecordStatusCallback();
PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
uint32_t highThreshold, uint32_t lowThreshold);
+ RecordStatus checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold);
/**
* A dispatcher to read and dispatch input data to all the started filters.
* Each filter handler handles the data filtering/output writing/filterEvent updating.
@@ -103,9 +107,9 @@
void startTpidFilter(vector<uint8_t> data);
bool startFilterDispatcher();
static void* __threadLoopPlayback(void* user);
- static void* __threadLoopBroadcast(void* user);
+ static void* __threadLoopRecord(void* user);
void playbackThreadLoop();
- void broadcastInputThreadLoop();
+ void recordThreadLoop();
unique_ptr<DvrMQ> mDvrMQ;
EventFlag* mDvrEventFlag;
@@ -121,6 +125,7 @@
// FMQ status local records
PlaybackStatus mPlaybackStatus;
+ RecordStatus mRecordStatus;
/**
* If a specific filter's writing loop is still running
*/
@@ -135,10 +140,16 @@
* Lock to protect writes to the input status
*/
std::mutex mPlaybackStatusLock;
+ std::mutex mRecordStatusLock;
std::mutex mBroadcastInputThreadLock;
std::mutex mDvrThreadLock;
const bool DEBUG_DVR = false;
+
+ // Booleans to check if recording is running.
+ // Recording is ready when both of the following are set to true.
+ bool mIsRecordStarted = false;
+ bool mIsRecordFilterAttached = false;
};
} // namespace implementation
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index befd1e6..b3160fc 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -265,10 +265,16 @@
void Filter::updateFilterOutput(vector<uint8_t> data) {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
- ALOGD("[Filter] handler output updated");
+ ALOGD("[Filter] filter output updated");
mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
}
+void Filter::updateRecordOutput(vector<uint8_t> data) {
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ ALOGD("[Filter] record filter output updated");
+ mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
+}
+
Result Filter::startFilterHandler() {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
switch (mType.mainType) {
@@ -292,12 +298,11 @@
case DemuxTsFilterType::PCR:
startPcrFilterHandler();
break;
- case DemuxTsFilterType::RECORD:
- startRecordFilterHandler();
- break;
case DemuxTsFilterType::TEMI:
startTemiFilterHandler();
break;
+ default:
+ break;
}
break;
case DemuxFilterMainType::MMTP:
@@ -342,12 +347,16 @@
if (mPesSizeLeft == 0) {
uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
mFilterOutput[i + 6];
- ALOGD("[Filter] prefix %d", prefix);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] prefix %d", prefix);
+ }
if (prefix == 0x000001) {
// TODO handle mulptiple Pes filters
mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
mPesSizeLeft += 6;
- ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ }
} else {
continue;
}
@@ -360,7 +369,9 @@
mPesOutput.insert(mPesOutput.end(), first, last);
// size does not match then continue
mPesSizeLeft -= endPoint;
- ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ }
if (mPesSizeLeft > 0) {
continue;
}
@@ -377,7 +388,9 @@
.streamId = mPesOutput[3],
.dataLength = static_cast<uint16_t>(mPesOutput.size()),
};
- ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+ }
int size = mFilterEvent.events.size();
mFilterEvent.events.resize(size + 1);
@@ -413,13 +426,23 @@
}
Result Filter::startRecordFilterHandler() {
- DemuxFilterTsRecordEvent tsRecordEvent;
+ /*DemuxFilterTsRecordEvent tsRecordEvent;
tsRecordEvent.pid.tPid(0);
tsRecordEvent.indexMask.tsIndexMask(0x01);
mFilterEvent.events.resize(1);
mFilterEvent.events[0].tsRecord(tsRecordEvent);
+*/
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ if (mRecordFilterOutput.empty()) {
+ return Result::SUCCESS;
+ }
- mFilterOutput.clear();
+ if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) {
+ ALOGD("[Filter] dvr fails to write into record FMQ.");
+ return Result::UNKNOWN_ERROR;
+ }
+
+ mRecordFilterOutput.clear();
return Result::SUCCESS;
}
@@ -462,6 +485,14 @@
return false;
}
+void Filter::attachFilterToRecord(const sp<Dvr> dvr) {
+ mDvr = dvr;
+}
+
+void Filter::detachFilterFromRecord() {
+ mDvr = nullptr;
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index fbd965a..d397f73 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -22,6 +22,7 @@
#include <math.h>
#include <set>
#include "Demux.h"
+#include "Dvr.h"
#include "Frontend.h"
using namespace std;
@@ -44,6 +45,7 @@
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
class Demux;
+class Dvr;
class Filter : public IFilter {
public:
@@ -80,11 +82,17 @@
bool createFilterMQ();
uint16_t getTpid();
void updateFilterOutput(vector<uint8_t> data);
+ void updateRecordOutput(vector<uint8_t> data);
Result startFilterHandler();
+ Result startRecordFilterHandler();
+ void attachFilterToRecord(const sp<Dvr> dvr);
+ void detachFilterFromRecord();
private:
// Tuner service
sp<Demux> mDemux;
+ // Dvr reference once the filter is attached to any
+ sp<Dvr> mDvr = nullptr;
/**
* Filter callbacks used on filter events or FMQ status
*/
@@ -99,6 +107,7 @@
sp<IFilter> mDataSource;
bool mIsDataSourceDemux = true;
vector<uint8_t> mFilterOutput;
+ vector<uint8_t> mRecordFilterOutput;
unique_ptr<FilterMQ> mFilterMQ;
EventFlag* mFilterEventFlag;
DemuxFilterEvent mFilterEvent;
@@ -120,6 +129,8 @@
*/
const uint16_t SECTION_WRITE_COUNT = 10;
+ bool DEBUG_FILTER = false;
+
/**
* Filter handlers to handle the data filtering.
* They are also responsible to write the filtered output into the filter FMQ
@@ -129,7 +140,6 @@
Result startPesFilterHandler();
Result startTsFilterHandler();
Result startMediaFilterHandler();
- Result startRecordFilterHandler();
Result startPcrFilterHandler();
Result startTemiFilterHandler();
Result startFilterLoop();
@@ -165,6 +175,7 @@
std::mutex mFilterStatusLock;
std::mutex mFilterThreadLock;
std::mutex mFilterOutputLock;
+ std::mutex mRecordFilterOutputLock;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index f86b28d..c143d61 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -148,7 +148,7 @@
uint32_t demuxId;
if (it != mFrontendToDemux.end()) {
demuxId = it->second;
- mDemuxes[demuxId]->stopBroadcastInput();
+ mDemuxes[demuxId]->stopFrontendInput();
}
}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 707f5df..fa3c08b 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1197,6 +1197,7 @@
/**
* Scan type for Frontend.
*/
+@export
enum FrontendScanType : uint32_t {
SCAN_UNDEFINED = 0,
SCAN_AUTO = 1 << 0,
@@ -1206,6 +1207,7 @@
/**
* Scan Message Type for Frontend.
*/
+@export
enum FrontendScanMessageType : uint32_t {
/**
* Scan locked the signal.
@@ -2230,8 +2232,6 @@
DemuxFilterSectionSettings section;
- DemuxFilterPesDataSettings pesData;
-
/**
* true if the data from IP subtype go to next filter directly
*/
@@ -2248,7 +2248,7 @@
/**
* true if the filtered data is commpressed ip packet
*/
- bool bIsCompressedIpPacket;
+ bool isCompressedIpPacket;
safe_union FilterSettings {
/**
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index da3e300..7977f25 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -65,6 +65,7 @@
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
@@ -95,6 +96,7 @@
using android::hardware::tv::tuner::V1_0::ITuner;
using android::hardware::tv::tuner::V1_0::PlaybackSettings;
using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
using android::hardware::tv::tuner::V1_0::RecordStatus;
using android::hardware::tv::tuner::V1_0::Result;
@@ -379,7 +381,20 @@
class DvrCallback : public IDvrCallback {
public:
- virtual Return<void> onRecordStatus(RecordStatus /*status*/) override { return Void(); }
+ virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
+ ALOGW("[vts] record status %hhu", status);
+ switch (status) {
+ case DemuxFilterStatus::DATA_READY:
+ break;
+ case DemuxFilterStatus::LOW_WATER:
+ break;
+ case DemuxFilterStatus::HIGH_WATER:
+ case DemuxFilterStatus::OVERFLOW:
+ ALOGW("[vts] record overflow. Flushing");
+ break;
+ }
+ return Void();
+ }
virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
// android::Mutex::Autolock autoLock(mMsgLock);
@@ -401,10 +416,17 @@
void testFilterDataOutput();
void stopPlaybackThread();
+ void testRecordOutput();
+ void stopRecordThread();
void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
+ void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor);
static void* __threadLoopPlayback(void* threadArgs);
+ static void* __threadLoopRecord(void* threadArgs);
void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
+ void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
+
+ bool readRecordFMQ();
private:
struct PlaybackThreadArgs {
@@ -412,22 +434,31 @@
PlaybackConf* playbackConf;
bool* keepWritingPlaybackFMQ;
};
+ struct RecordThreadArgs {
+ DvrCallback* user;
+ RecordSettings* recordSetting;
+ bool* keepReadingRecordFMQ;
+ };
uint16_t mDataLength = 0;
std::vector<uint8_t> mDataOutputBuffer;
std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
std::unique_ptr<FilterMQ> mPlaybackMQ;
+ std::unique_ptr<FilterMQ> mRecordMQ;
std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
- EventFlag* mPlaybackMQEventFlag;
android::Mutex mMsgLock;
android::Mutex mPlaybackThreadLock;
+ android::Mutex mRecordThreadLock;
android::Condition mMsgCondition;
bool mKeepWritingPlaybackFMQ = true;
+ bool mKeepReadingRecordFMQ = true;
bool mPlaybackThreadRunning;
+ bool mRecordThreadRunning;
pthread_t mPlaybackThread;
+ pthread_t mRecordThread;
int mPidFilterOutputCount = 0;
};
@@ -516,6 +547,92 @@
inputData.close();
}
+void DvrCallback::testRecordOutput() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mDataOutputBuffer.empty()) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
+ return;
+ }
+ }
+ stopRecordThread();
+ ALOGW("[vts] record pass and stop");
+}
+
+void DvrCallback::startRecordOutputThread(RecordSettings recordSetting,
+ MQDesc& recordMQDescriptor) {
+ mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
+ EXPECT_TRUE(mRecordMQ);
+ struct RecordThreadArgs* threadArgs =
+ (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
+ threadArgs->user = this;
+ threadArgs->recordSetting = &recordSetting;
+ threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
+
+ pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
+ pthread_setname_np(mRecordThread, "test_record_input_loop");
+}
+
+void* DvrCallback::__threadLoopRecord(void* threadArgs) {
+ DvrCallback* const self =
+ static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
+ self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting,
+ ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
+ return 0;
+}
+
+void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) {
+ ALOGD("[vts] DvrCallback record threadLoop start.");
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
+ mRecordThreadRunning = true;
+
+ // Create the EventFlag that is used to signal the HAL impl that data have been
+ // read from the Record FMQ
+ EventFlag* recordMQEventFlag;
+ EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
+ android::OK);
+
+ while (mRecordThreadRunning) {
+ while (*keepReadingRecordFMQ) {
+ uint32_t efState = 0;
+ android::status_t status = recordMQEventFlag->wait(
+ static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+ true /* retry on spurious wake */);
+ if (status != android::OK) {
+ ALOGD("[vts] wait for data ready on the record FMQ");
+ continue;
+ }
+ // Our current implementation filter the data and write it into the filter FMQ
+ // immediately after the DATA_READY from the VTS/framework
+ if (!readRecordFMQ()) {
+ ALOGD("[vts] record data failed to be filtered. Ending thread");
+ mRecordThreadRunning = false;
+ break;
+ }
+ }
+ }
+
+ mRecordThreadRunning = false;
+ ALOGD("[vts] record thread ended.");
+}
+
+bool DvrCallback::readRecordFMQ() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ bool result = false;
+ mDataOutputBuffer.clear();
+ mDataOutputBuffer.resize(mRecordMQ->availableToRead());
+ result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+ EXPECT_TRUE(result) << "can't read from Record MQ";
+ mMsgCondition.signal();
+ return result;
+}
+
+void DvrCallback::stopRecordThread() {
+ mKeepReadingRecordFMQ = false;
+ mRecordThreadRunning = false;
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
+}
+
// Test environment for Tuner HIDL HAL.
class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -555,6 +672,7 @@
sp<DvrCallback> mDvrCallback;
MQDesc mFilterMQDescriptor;
MQDesc mPlaybackMQDescriptor;
+ MQDesc mRecordMQDescriptor;
vector<uint32_t> mUsedFilterIds;
uint32_t mDemuxId;
@@ -572,6 +690,8 @@
FrontendSettings settings);
::testing::AssertionResult getPlaybackMQDescriptor();
::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
+ ::testing::AssertionResult getRecordMQDescriptor();
+ ::testing::AssertionResult addRecordToDemux(RecordSettings setting);
::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
::testing::AssertionResult getFilterMQDescriptor();
::testing::AssertionResult closeDemux();
@@ -581,6 +701,9 @@
::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
PlaybackConf playbackConf,
vector<string> goldenOutputFiles);
+ ::testing::AssertionResult recordDataFlowTest(vector<FilterConf> filterConf,
+ RecordSettings recordSetting,
+ vector<string> goldenOutputFiles);
::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
vector<string> goldenOutputFiles);
};
@@ -766,6 +889,49 @@
return ::testing::AssertionResult(status == Result::SUCCESS);
}
+::testing::AssertionResult TunerHidlTest::addRecordToDemux(RecordSettings setting) {
+ Result status;
+
+ if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ // Create dvr callback
+ mDvrCallback = new DvrCallback();
+
+ // Add playback input to the local demux
+ mDemux->openDvr(DvrType::RECORD, FMQ_SIZE_1M, mDvrCallback,
+ [&](Result result, const sp<IDvr>& dvr) {
+ mDvr = dvr;
+ status = result;
+ });
+
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ DvrSettings dvrSetting;
+ dvrSetting.record(setting);
+ status = mDvr->configure(dvrSetting);
+
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getRecordMQDescriptor() {
+ Result status;
+
+ if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
+ return ::testing::AssertionFailure();
+ }
+
+ mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+ mRecordMQDescriptor = dvrMQDesc;
+ status = result;
+ });
+
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
DemuxFilterSettings setting) {
Result status;
@@ -997,6 +1163,82 @@
return closeDemux();
}
+::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector<FilterConf> filterConf,
+ RecordSettings recordSetting,
+ vector<string> /*goldenOutputFiles*/) {
+ Result status;
+ hidl_vec<FrontendId> feIds;
+
+ mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+ status = result;
+ feIds = frontendIds;
+ });
+
+ if (feIds.size() == 0) {
+ ALOGW("[ WARN ] Frontend isn't available");
+ return ::testing::AssertionFailure();
+ }
+
+ FrontendDvbtSettings dvbt{
+ .frequency = 1000,
+ };
+ FrontendSettings settings;
+ settings.dvbt(dvbt);
+
+ int filterIdsSize;
+ // Filter Configuration Module
+ for (int i = 0; i < filterConf.size(); i++) {
+ if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
+ ::testing::AssertionFailure() ||
+ // TODO use a map to save the FMQs/EvenFlags and pass to callback
+ getFilterMQDescriptor() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+ filterIdsSize = mUsedFilterIds.size();
+ mUsedFilterIds.resize(filterIdsSize + 1);
+ mUsedFilterIds[filterIdsSize] = mFilterId;
+ mFilters[mFilterId] = mFilter;
+ }
+
+ // Record Config Module
+ if (addRecordToDemux(recordSetting) == ::testing::AssertionFailure() ||
+ getRecordMQDescriptor() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+ for (int i = 0; i <= filterIdsSize; i++) {
+ if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ }
+
+ mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor);
+ status = mDvr->start();
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
+ return ::testing::AssertionFailure();
+ }
+
+ // Data Verify Module
+ mDvrCallback->testRecordOutput();
+
+ // Clean Up Module
+ for (int i = 0; i <= filterIdsSize; i++) {
+ if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ }
+ if (mFrontend->stopTune() != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ mUsedFilterIds.clear();
+ mFilterCallbacks.clear();
+ mFilters.clear();
+ return closeDemux();
+}
+
/*
* API STATUS TESTS
*/
@@ -1203,6 +1445,44 @@
ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
}
+TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+ description("Feed ts data from frontend to recording and test with ts record filter");
+
+ // todo modulize the filter conf parser
+ vector<FilterConf> filterConf;
+ filterConf.resize(1);
+
+ DemuxFilterSettings filterSetting;
+ DemuxTsFilterSettings tsFilterSetting{
+ .tpid = 119,
+ };
+ DemuxFilterRecordSettings recordFilterSetting;
+ tsFilterSetting.filterSettings.record(recordFilterSetting);
+ filterSetting.ts(tsFilterSetting);
+
+ DemuxFilterType type{
+ .mainType = DemuxFilterMainType::TS,
+ };
+ type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+ FilterConf recordFilterConf{
+ .type = type,
+ .setting = filterSetting,
+ };
+ filterConf[0] = recordFilterConf;
+
+ RecordSettings recordSetting{
+ .statusMask = 0xf,
+ .lowThreshold = 0x1000,
+ .highThreshold = 0x07fff,
+ .dataFormat = DataFormat::TS,
+ .packetSize = 188,
+ };
+
+ vector<string> goldenOutputFiles;
+
+ ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles));
+}
+
} // namespace
int main(int argc, char** argv) {
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f47b10d..0e2b3e1 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -34,18 +34,10 @@
using android::hardware::vibrator::EffectStrength;
using android::hardware::vibrator::IVibrator;
-// TODO(b/143992652): autogenerate
-const std::vector<Effect> kEffects = {
- Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD,
- Effect::POP, Effect::HEAVY_CLICK, Effect::RINGTONE_1, Effect::RINGTONE_2,
- Effect::RINGTONE_3, Effect::RINGTONE_4, Effect::RINGTONE_5, Effect::RINGTONE_6,
- Effect::RINGTONE_7, Effect::RINGTONE_8, Effect::RINGTONE_9, Effect::RINGTONE_10,
- Effect::RINGTONE_11, Effect::RINGTONE_12, Effect::RINGTONE_13, Effect::RINGTONE_14,
- Effect::RINGTONE_15, Effect::TEXTURE_TICK};
-
-// TODO(b/143992652): autogenerate
-const std::vector<EffectStrength> kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM,
- EffectStrength::STRONG};
+const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
+ android::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
+ android::enum_range<EffectStrength>().end()};
const std::vector<Effect> kInvalidEffects = {
static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index ec96fcf..62874ef 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -543,12 +543,16 @@
const auto& status_and_rtt_controller =
HIDL_INVOKE(wifi_chip_, createRttController, iface);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_rtt_controller.first.code);
- EXPECT_NE(nullptr, status_and_rtt_controller.second.get());
+ if (status_and_rtt_controller.first.code !=
+ WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ EXPECT_EQ(WifiStatusCode::SUCCESS,
+ status_and_rtt_controller.first.code);
+ EXPECT_NE(nullptr, status_and_rtt_controller.second.get());
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(
android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index d584d4b..26e4821 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -209,23 +209,6 @@
return status_and_iface.second;
}
-sp<IWifiRttController> getWifiRttController(const std::string& instance_name) {
- sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
- if (!wifi_chip.get()) {
- return nullptr;
- }
- sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
- if (!wifi_sta_iface.get()) {
- return nullptr;
- }
- const auto& status_and_controller =
- HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface);
- if (status_and_controller.first.code != WifiStatusCode::SUCCESS) {
- return nullptr;
- }
- return status_and_controller.second;
-}
-
bool configureChipToSupportIfaceType(const sp<IWifiChip>& wifi_chip,
IfaceType type,
ChipModeId* configured_mode_id) {
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index bdee2ec..8660134 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -44,8 +44,6 @@
const std::string& instance_name = "");
android::sp<android::hardware::wifi::V1_0::IWifiStaIface> getWifiStaIface(
const std::string& instance_name = "");
-android::sp<android::hardware::wifi::V1_0::IWifiRttController>
-getWifiRttController(const std::string& instance_name = "");
// Configure the chip in a mode to support the creation of the provided
// iface type.
bool configureChipToSupportIfaceType(
diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
index e1ee34f..6c01995 100644
--- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -22,11 +22,15 @@
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
+#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
using ::android::sp;
using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
using ::android::hardware::wifi::V1_0::IWifiRttController;
+using ::android::hardware::wifi::V1_0::IWifiStaIface;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
/**
* Fixture to use for all RTT controller HIDL interface tests.
@@ -48,11 +52,26 @@
*/
TEST_P(WifiRttControllerHidlTest, Create) {
stopWifi(GetInstanceName());
- EXPECT_NE(nullptr, getWifiRttController(GetInstanceName()).get());
+
+ const std::string& instance_name = GetInstanceName();
+
+ sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
+ EXPECT_NE(nullptr, wifi_chip.get());
+
+ sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
+ EXPECT_NE(nullptr, wifi_sta_iface.get());
+
+ const auto& status_and_controller =
+ HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface);
+ if (status_and_controller.first.code !=
+ WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
+ EXPECT_NE(nullptr, status_and_controller.second.get());
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiRttControllerHidlTest,
testing::ValuesIn(
android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
index 47faec8..93aa0f3 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -176,11 +176,15 @@
sp<WifiChipEventCallback> wifiChipEventCallback = new WifiChipEventCallback();
const auto& status =
HIDL_INVOKE(wifi_chip_, registerEventCallback_1_2, wifiChipEventCallback);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+
+ if (status.code != WifiStatusCode::SUCCESS) {
+ EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+ return;
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
::android::hardware::wifi::V1_2::IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
index f3f76e1..d5d87ce 100644
--- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -481,15 +481,18 @@
callbackType = INVALID;
NanEnableRequest nanEnableRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::SUCCESS,
- HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
- nanEnableRequest, nanConfigRequestSupp)
- .code);
- // wait for a callback
- ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
- ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
- ASSERT_EQ(id, inputCmdId);
- ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+ ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ }
}
/*
@@ -502,10 +505,12 @@
nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
128; // must be <= 127
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
- HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
- nanEnableRequest, nanConfigRequestSupp)
- .code);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+ }
}
/*
@@ -516,15 +521,19 @@
callbackType = INVALID;
NanConfigRequest nanConfigRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::SUCCESS,
- HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
- nanConfigRequest, nanConfigRequestSupp)
- .code);
- // wait for a callback
- ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
- ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
- ASSERT_EQ(id, inputCmdId);
- ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp);
+
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+ ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ }
}
/*
@@ -536,14 +545,16 @@
NanConfigRequest nanConfigRequest = {};
nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
- HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
- nanConfigRequest, nanConfigRequestSupp)
- .code);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiNanIfaceHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
::android::hardware::wifi::V1_2::IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index a70457b..3498510 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -992,7 +992,7 @@
std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
WifiChip::createRttControllerInternal(const sp<IWifiIface>& /*bound_iface*/) {
LOG(ERROR) << "createRttController is not supported on this HAL";
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
}
std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index 1804d8c..345cf31 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -233,7 +233,11 @@
TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
getIfaceParamsWithoutAcs(), getPskNwParams());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+ // longer supported (replaced by an upgraded API)
+ if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ }
}
/**
@@ -243,7 +247,11 @@
TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
getIfaceParamsWithoutAcs(), getOpenNwParams());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+ // longer supported (replaced by an upgraded API)
+ if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ }
}
/**
@@ -269,10 +277,14 @@
TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
getIfaceParamsWithoutAcs(), getPskNwParams());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
- status =
- HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+ // longer supported (replaced by an upgraded API)
+ if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ }
}
/**
diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal
index 31ade13..c296cd5 100644
--- a/wifi/hostapd/1.2/IHostapd.hal
+++ b/wifi/hostapd/1.2/IHostapd.hal
@@ -16,16 +16,98 @@
package android.hardware.wifi.hostapd@1.2;
+import @1.0::IHostapd.NetworkParams;
import @1.1::IHostapd;
import HostapdStatus;
import MacAddress;
import Ieee80211ReasonCode;
+import DebugLevel;
/**
* Top-level object for managing SoftAPs.
*/
interface IHostapd extends @1.1::IHostapd {
/**
+ * Band bitmMask to use for the SoftAp operations.
+ * A combinatoin of these bits are used to identify the allowed bands
+ * to start the softAp
+ */
+ enum BandMask : uint32_t {
+ /**
+ * 2.4 GHz band.
+ */
+ BAND_2_GHZ = 1 << 0,
+ /**
+ * 5 GHz band.
+ */
+ BAND_5_GHZ = 1 << 1,
+ /**
+ * 6 GHz band.
+ */
+ BAND_6_GHZ = 1 << 2,
+ };
+
+ /**
+ * Parameters to control the HW mode for the interface.
+ */
+ struct HwModeParams {
+ /**
+ * Whether IEEE 802.11ax (HE) is enabled or not.
+ * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+ * used with HE.
+ */
+ bool enable80211AX;
+ /**
+ * Whether 6GHz band enabled or not on softAp.
+ * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+ * used.
+ */
+ bool enable6GhzBand;
+ };
+
+ /**
+ * Parameters to control the channel selection for the interface.
+ */
+ struct ChannelParams {
+ /**
+ * Band to use for the SoftAp operations.
+ */
+ bitfield<BandMask> bandMask;
+ };
+
+ /**
+ * Parameters to use for setting up the access point interface.
+ */
+ struct IfaceParams {
+ /**
+ * Baseline information as defined in HAL 1.1.
+ */
+ @1.1::IHostapd.IfaceParams V1_1;
+ /** Additional Hw mode params for the interface */
+ HwModeParams hwModeParams;
+ /** Additional Channel params for the interface */
+ ChannelParams channelParams;
+ };
+
+ /**
+ * Adds a new access point for hostapd to control.
+ *
+ * This should trigger the setup of an access point with the specified
+ * interface and network params.
+ *
+ * @param ifaceParams AccessPoint Params for the access point.
+ * @param nwParams Network Params for the access point.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|,
+ * |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+ */
+ addAccessPoint_1_2(IfaceParams ifaceParams, NetworkParams nwParams)
+ generates(HostapdStatus status);
+
+ /**
* force one of the hotspot clients disconnect..
*
* @param ifaceName Name of the interface.
@@ -39,4 +121,17 @@
*/
forceClientDisconnect(string ifaceName, MacAddress clientAddress,
Ieee80211ReasonCode reasonCode) generates (HostapdStatus status);
+
+ /**
+ * Set debug parameters for the hostapd.
+ *
+ * @param level Debug logging level for the hostapd.
+ * (one of |DebugLevel| values).
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|
+ */
+ setDebugParams(DebugLevel level)
+ generates (HostapdStatus status);
};
diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal
index 06e890b..54e6529 100644
--- a/wifi/hostapd/1.2/types.hal
+++ b/wifi/hostapd/1.2/types.hal
@@ -53,3 +53,17 @@
*/
string debugMessage;
};
+
+/**
+ * Debug levels for the hostapd.
+ * Only log messages with a level greater than the set level
+ * (via |setDebugParams|) will be logged.
+ */
+enum DebugLevel : uint32_t {
+ EXCESSIVE = 0,
+ MSGDUMP = 1,
+ DEBUG = 2,
+ INFO = 3,
+ WARNING = 4,
+ ERROR = 5
+};
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
index 0d37221..8245f8f 100644
--- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -31,6 +31,7 @@
using ::android::hardware::hidl_string;
using ::android::hardware::Return;
using ::android::hardware::Void;
+using ::android::hardware::wifi::hostapd::V1_2::DebugLevel;
using ::android::hardware::wifi::hostapd::V1_2::HostapdStatusCode;
using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode;
using ::android::hardware::wifi::hostapd::V1_2::IHostapd;
@@ -39,7 +40,9 @@
namespace {
constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
'2', '3', '4', '5'};
+constexpr char kNwPassphrase[] = "test12345";
constexpr int kIfaceChannel = 6;
+constexpr int kIfaceInvalidChannel = 567;
constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
constexpr Ieee80211ReasonCode kTestDisconnectReasonCode =
Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
@@ -73,7 +76,9 @@
IHostapd::IfaceParams getIfaceParamsWithoutAcs() {
::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams
iface_params;
- IHostapd::IfaceParams iface_params_1_1;
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::IfaceParams
+ iface_params_1_1;
+ IHostapd::IfaceParams iface_params_1_2;
iface_params.ifaceName = getPrimaryWlanIfaceName();
iface_params.hwModeParams.enable80211N = true;
@@ -81,9 +86,52 @@
iface_params.channelParams.enableAcs = false;
iface_params.channelParams.acsShouldExcludeDfs = false;
iface_params.channelParams.channel = kIfaceChannel;
- iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ;
iface_params_1_1.V1_0 = iface_params;
- return iface_params_1_1;
+ iface_params_1_2.V1_1 = iface_params_1_1;
+ // Newly added attributes in V1_2
+ iface_params_1_2.hwModeParams.enable80211AX = false;
+ iface_params_1_2.hwModeParams.enable6GhzBand = false;
+ iface_params_1_2.channelParams.bandMask = 0;
+ iface_params_1_2.channelParams.bandMask |=
+ IHostapd::BandMask::BAND_2_GHZ;
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcs() {
+ // First get the settings for WithoutAcs and then make changes
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+ iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true;
+ iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true;
+ iface_params_1_2.V1_1.V1_0.channelParams.channel = 0;
+ iface_params_1_2.channelParams.bandMask |=
+ IHostapd::BandMask::BAND_5_GHZ;
+
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() {
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::ChannelParams
+ channelParams;
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange
+ acsChannelRange;
+ acsChannelRange.start = 1;
+ acsChannelRange.end = 11;
+ std::vector<
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange>
+ vec_acsChannelRange;
+ vec_acsChannelRange.push_back(acsChannelRange);
+ channelParams.acsChannelRanges = vec_acsChannelRange;
+ iface_params_1_2.V1_1.channelParams = channelParams;
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() {
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithAcsAndChannelRange();
+ iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].start = 222;
+ iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].end = 999;
+ return iface_params_1_2;
}
IHostapd::NetworkParams getOpenNwParams() {
@@ -95,6 +143,31 @@
return nw_params;
}
+ IHostapd::NetworkParams getPskNwParams() {
+ IHostapd::NetworkParams nw_params;
+ nw_params.ssid =
+ std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+ nw_params.isHidden = false;
+ nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params.pskPassphrase = kNwPassphrase;
+ return nw_params;
+ }
+
+ IHostapd::NetworkParams getInvalidPskNwParams() {
+ IHostapd::NetworkParams nw_params;
+ nw_params.ssid =
+ std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+ nw_params.isHidden = false;
+ nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+ return nw_params;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() {
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+ iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel;
+ return iface_params_1_2;
+ }
+
// IHostapd object used for all tests in this fixture.
sp<IHostapd> hostapd_;
std::string wifi_instance_name_;
@@ -102,6 +175,125 @@
};
/**
+ * Adds an access point with PSK network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(), getPskNwParams());
+ // TODO: b/140172237, fix this in R.
+ // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config, ACS enabled & channel Range.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcsAndChannelRange(), getPskNwParams());
+ // TODO: b/140172237, fix this in R
+ // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid channel range.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcsAndInvalidChannelRange(),
+ getPskNwParams());
+ // TODO: b/140172237, fix this in R
+ // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(), getOpenNwParams());
+ // TODO: b/140172237, fix this in R
+ // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(), getOpenNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS enabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(), getPskNwParams());
+ // TODO: b/140172237, fix this in R
+ /*
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ */
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS disabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+ auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+ auto status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(
+ android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+ status.code);
+}
+
+/**
+ * Adds an access point with invalid channel.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithInvalidChannel(), getPskNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid PSK network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+ getInvalidPskNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
* forceClientDisconnect should return FAILURE_IFACE_UNKNOWN
* when hotspot interface doesn't init..
*/
@@ -117,19 +309,25 @@
* when hotspot interface available.
*/
TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) {
- auto status_1_0 =
- HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(),
- getOpenNwParams());
- EXPECT_EQ(
- android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
- status_1_0.code);
-
auto status_1_2 =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+ getOpenNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+
+ status_1_2 =
HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
kTestZeroMacAddr, kTestDisconnectReasonCode);
EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
}
+/*
+ * SetDebugParams
+ */
+TEST_P(HostapdHidlTest, SetDebugParams) {
+ auto status = HIDL_INVOKE(hostapd_, setDebugParams, DebugLevel::EXCESSIVE);
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
INSTANTIATE_TEST_CASE_P(
PerInstance, HostapdHidlTest,
testing::Combine(
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 15525bb..332ee4a 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -19,7 +19,7 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["supplicant_hidl_test_utils.cpp"],
export_include_dirs: [
- "."
+ ".",
],
static_libs: [
"VtsHalWifiV1_0TargetTestUtil",
@@ -51,14 +51,17 @@
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
cc_test {
name: "VtsHalWifiSupplicantP2pV1_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
- "VtsHalWifiSupplicantV1_0TargetTest.cpp",
+ "VtsHalWifiSupplicantP2pV1_0TargetTest.cpp",
"supplicant_p2p_iface_hidl_test.cpp",
],
static_libs: [
@@ -71,5 +74,8 @@
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
new file mode 100644
index 0000000..a132707
--- /dev/null
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include "supplicant_hidl_test_utils.h"
+
+// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
+
+int main(int argc, char** argv) {
+ if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct"))
+ return 0;
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp
index b7949d1..7e9d4f6 100644
--- a/wifi/supplicant/1.2/vts/functional/Android.bp
+++ b/wifi/supplicant/1.2/vts/functional/Android.bp
@@ -51,6 +51,7 @@
"android.hardware.wifi.supplicant@1.0",
"android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant@1.2",
+ "android.hardware.wifi.supplicant@1.3",
"android.hardware.wifi@1.0",
"android.hardware.wifi@1.1",
"libgmock",
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 2ff7751..6272d30 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -22,6 +22,8 @@
#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
#include <android/hardware/wifi/supplicant/1.2/types.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/types.h>
#include <hidl/HidlSupport.h>
#include <hidl/Status.h>
@@ -318,6 +320,19 @@
return;
}
+ /* Check if the underlying HAL version is 1.3 or higher and skip the test
+ * in this case. The 1.3 HAL uses different callbacks which are not
+ * supported by 1.2. This will cause this test to fail because the callbacks
+ * it is waiting for will never be called. Note that this test is also
+ * implemented in the 1.3 VTS test.
+ */
+ sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 =
+ ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface::
+ castFrom(sta_iface_);
+ if (v1_3 != nullptr) {
+ GTEST_SKIP() << "Test not supported with this HAL version";
+ }
+
hidl_string uri =
"DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
"0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
@@ -369,6 +384,21 @@
return;
}
+ /* Check if the underlying HAL version is 1.3 or higher and skip the test
+ * in this case. The 1.3 HAL uses different callbacks which are not
+ * supported by 1.2. This will cause this test to fail because the callbacks
+ * it is waiting for will never be called. Note that this test is also
+ * implemented in the 1.3 VTS test.
+ */
+ sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 =
+ ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface::
+ castFrom(sta_iface_);
+
+ if (v1_3 != nullptr) {
+ GTEST_SKIP() << "Test not supported with this HAL version";
+ return;
+ }
+
hidl_string uri =
"DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
"0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
index bfd8946..58ef165 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -18,6 +18,7 @@
import @1.0::SupplicantStatus;
import @1.2::ISupplicantStaIface;
+import ISupplicantStaNetwork;
import ISupplicantStaIfaceCallback;
/**
@@ -76,4 +77,17 @@
* |SupplicantStatusCode.FAILURE_UNKNOWN|
*/
setMboCellularDataStatus(bool available) generates (SupplicantStatus status);
+
+ /**
+ * Get Key management capabilities of the device
+ *
+ * @return status Status of the operation, and a bitmap of key management mask.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ getKeyMgmtCapabilities_1_3()
+ generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
index 107e0fc..72ba160 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
@@ -28,6 +28,121 @@
*/
interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback {
/**
+ * IEEE Std 802.11-2016 - Table 9-357.
+ * BTM status code filled in BSS transition management response frame.
+ */
+ enum BssTmStatusCode : uint8_t {
+ ACCEPT = 0,
+ REJECT_UNSPECIFIED = 1,
+ REJECT_INSUFFICIENT_BEACON = 2,
+ REJECT_INSUFFICIENT_CAPABITY = 3,
+ REJECT_BSS_TERMINATION_UNDESIRED = 4,
+ REJECT_BSS_TERMINATION_DELAY_REQUEST = 5,
+ REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+ REJECT_NO_SUITABLE_CANDIDATES = 7,
+ REJECT_LEAVING_ESS = 8,
+ };
+
+ /**
+ * Bitmask of various information retrieved from BSS transition management request frame.
+ */
+ enum BssTmDataFlagsMask : uint32_t {
+ /**
+ * Preferred candidate list included.
+ */
+ WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = 1 << 0,
+ /**
+ * Abridged.
+ */
+ WNM_MODE_ABRIDGED = 1 << 1,
+ /**
+ * Disassociation Imminent.
+ */
+ WNM_MODE_DISASSOCIATION_IMMINENT = 1 << 2,
+ /**
+ * BSS termination included.
+ */
+ WNM_MODE_BSS_TERMINATION_INCLUDED = 1 << 3,
+ /**
+ * ESS Disassociation Imminent.
+ */
+ WNM_MODE_ESS_DISASSOCIATION_IMMINENT = 1 << 4,
+ /**
+ * MBO transition reason code included.
+ */
+ MBO_TRANSITION_REASON_CODE_INCLUDED = 1 << 5,
+ /**
+ * MBO retry delay time included.
+ */
+ MBO_ASSOC_RETRY_DELAY_INCLUDED = 1 << 6,
+ /**
+ * MBO cellular data connection preference value included.
+ */
+ MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = 1 << 7,
+ };
+
+ /**
+ * MBO spec v1.2, 4.2.6 Table 18: MBO transition reason code attribute
+ * values.
+ */
+ enum MboTransitionReasonCode : uint8_t {
+ UNSPECIFIED = 0,
+ EXCESSIVE_FRAME_LOSS = 1,
+ EXCESSIVE_TRAFFIC_DELAY = 2,
+ INSUFFICIENT_BANDWIDTH = 3,
+ LOAD_BALANCING = 4,
+ LOW_RSSI = 5,
+ RX_EXCESSIVE_RETRIES = 6,
+ HIGH_INTERFERENCE = 7,
+ GRAY_ZONE = 8,
+ TRANSITION_TO_PREMIUM_AP = 9,
+ };
+
+ /**
+ * MBO spec v1.2, 4.2.5 Table 16: MBO Cellular Data connection preference
+ * attribute values. AP use this to indicate STA, its preference for the
+ * STA to move from BSS to cellular network.
+ */
+ enum MboCellularDataConnectionPrefValue : uint8_t {
+ EXCLUDED = 0,
+ NOT_PREFERRED = 1,
+ /*
+ * 2-254 Reserved.
+ */
+ PREFERRED = 255,
+ };
+
+ /**
+ * Data retrieved from received BSS transition management request frame.
+ */
+ struct BssTmData {
+ /*
+ * Status code filled in BSS transition management response frame
+ */
+ BssTmStatusCode status;
+
+ /*
+ * Bitmask of BssTmDataFlagsMask
+ */
+ bitfield<BssTmDataFlagsMask> flags;
+
+ /*
+ * Duration for which STA shouldn't try to re-associate.
+ */
+ uint32_t assocRetryDelayMs;
+
+ /*
+ * Reason for BSS transition request.
+ */
+ MboTransitionReasonCode mboTransitionReason;
+
+ /*
+ * Cellular Data Connection preference value.
+ */
+ MboCellularDataConnectionPrefValue mboCellPreference;
+ };
+
+ /**
* Indicates PMK cache added event.
*
* @param expirationTimeInSec expiration time in seconds
@@ -35,4 +150,39 @@
* opaque for the framework and depends on the native implementation.
*/
oneway onPmkCacheAdded(int64_t expirationTimeInSec, vec<uint8_t> serializedEntry);
+
+ /**
+ * Indicates a DPP success event.
+ */
+ oneway onDppSuccess(DppSuccessCode code);
+
+ /**
+ * Indicates a DPP progress event.
+ */
+ oneway onDppProgress_1_3(DppProgressCode code);
+
+ /**
+ * Indicates a DPP failure event.
+ *
+ * ssid: A string indicating the SSID for the AP that the Enrollee attempted to connect.
+ * channelList: A string containing a list of operating channels and operating classes
+ * indicating the channels that the Enrollee scanned in attempting to discover the AP.
+ * The list conforms to the following ABNF syntax:
+ * channel-list2 = class-and-channels *(“,” class-and-channels)
+ * class-and-channels = class “/” channel *(“,” channel)
+ * class = 1*3DIGIT
+ * channel = 1*3DIGIT
+ * bandList: A list of band parameters that are supported by the Enrollee expressed as the
+ * Operating Class.
+ */
+ oneway onDppFailure_1_3(DppFailureCode code, string ssid, string channelList,
+ vec<uint16_t> bandList);
+
+ /**
+ * Indicates BTM request frame handling status.
+ *
+ * @param BssTmData Data retrieved from received BSS transition management
+ * request frame.
+ */
+ oneway onBssTmHandlingDone(BssTmData tmData);
};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
index ab08cff..c18bffc 100644
--- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -16,6 +16,7 @@
package android.hardware.wifi.supplicant@1.3;
+import @1.0::ISupplicantStaNetwork;
import @1.0::SupplicantStatus;
import @1.2::ISupplicantStaNetwork;
@@ -25,6 +26,47 @@
*/
interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork {
/**
+ * Possble mask of values for Proto param.
+ */
+ enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask {
+ WAPI = 1 << 2,
+ };
+
+ /**
+ * Possble mask of values for KeyMgmt param.
+ */
+ enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask {
+ /*
+ * WAPI Psk
+ */
+ WAPI_PSK = 1 << 12,
+ /**
+ * WAPI Cert
+ */
+ WAPI_CERT = 1 << 13,
+ };
+
+ /**
+ * Possble mask of values for PairwiseCipher param.
+ */
+ enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask {
+ /**
+ * SMS4 Pairwise Cipher
+ */
+ SMS4 = 1 << 7,
+ };
+
+ /**
+ * Possble mask of values for GroupCipher param.
+ */
+ enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask {
+ /**
+ * SMS4 Group Cipher
+ */
+ SMS4 = 1 << 7,
+ };
+
+ /**
* Set OCSP (Online Certificate Status Protocol) type for this network.
*
* @param ocspType value to set.
@@ -49,6 +91,139 @@
getOcsp() generates (SupplicantStatus status, OcspType ocspType);
/**
+ * Set key management mask for the network.
+ *
+ * @param keyMgmtMask value to set.
+ * Combination of |KeyMgmtMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setKeyMgmt_1_3(bitfield<KeyMgmtMask> keyMgmtMask) generates (SupplicantStatus status);
+
+ /**
+ * Get the key mgmt mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return keyMgmtMask Combination of |KeyMgmtMask| values.
+ */
+ getKeyMgmt_1_3() generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+
+ /**
+ * Set proto mask for the network.
+ *
+ * @param protoMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setProto_1_3(bitfield<ProtoMask> protoMask) generates (SupplicantStatus status);
+
+ /**
+ * Get the proto mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return protoMask Combination of |ProtoMask| values.
+ */
+ getProto_1_3() generates (SupplicantStatus status, bitfield<ProtoMask> protoMask);
+
+ /**
+ * Set group cipher mask for the network.
+ *
+ * @param groupCipherMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setGroupCipher_1_3(bitfield<GroupCipherMask> groupCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the pairwise cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values.
+ */
+ getPairwiseCipher_1_3()
+ generates (SupplicantStatus status, bitfield<PairwiseCipherMask> pairwiseCipherMask);
+
+ /**
+ * Set pairwise cipher mask for the network.
+ *
+ * @param pairwiseCipherMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setPairwiseCipher_1_3(bitfield<PairwiseCipherMask> pairwiseCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the group cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return groupCipherMask Combination of |GroupCipherMask| values.
+ */
+ getGroupCipher_1_3()
+ generates (SupplicantStatus status, bitfield<GroupCipherMask> groupCipherMask);
+
+ /**
+ * Set WAPI certificate suite for this network.
+ *
+ * @param suite value to set.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setWapiCertSuite(string suite) generates (SupplicantStatus status);
+
+ /**
+ * Get WAPI certificate suite set for this network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return suite The name of a suite.
+ */
+ getWapiCertSuite() generates (SupplicantStatus status, string suite);
+
+ /**
* Add a PMK into supplicant PMK cache.
*
* @param serializedEntry is serialized PMK cache entry, the content is
diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal
index 4e01ab1..05f4760 100644
--- a/wifi/supplicant/1.3/types.hal
+++ b/wifi/supplicant/1.3/types.hal
@@ -16,6 +16,9 @@
package android.hardware.wifi.supplicant@1.3;
+import @1.2::DppProgressCode;
+import @1.2::DppFailureCode;
+
/**
* OcspType: The type of OCSP request.
*/
@@ -72,3 +75,31 @@
*/
OCE = 1 << 1,
};
+
+/**
+ * DppProgressCode: Progress codes for DPP (Easy Connect)
+ */
+enum DppProgressCode : @1.2::DppProgressCode {
+ CONFIGURATION_SENT_WAITING_RESPONSE,
+ CONFIGURATION_ACCEPTED,
+};
+
+/**
+ * DppSuccessCode: Success codes for DPP (Easy Connect) Configurator
+ */
+enum DppSuccessCode : uint32_t {
+ /*
+ * Replaces @1.2::onDppSuccessConfigSent()
+ */
+ CONFIGURATION_SENT,
+ CONFIGURATION_APPLIED,
+};
+
+/**
+ * DppFailureCode: Error codes for DPP (Easy Connect)
+ */
+enum DppFailureCode : @1.2::DppFailureCode {
+ CONFIGURATION_REJECTED,
+ CANNOT_FIND_NETWORK,
+ ENROLLEE_AUTHENTICATION,
+};
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 2cf5881..adc955e 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -36,13 +36,18 @@
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
using ::android::hardware::wifi::supplicant::V1_2::DppAkm;
using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode;
+using ::android::hardware::wifi::supplicant::V1_2::DppNetRole;
using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode;
using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
+using ::android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
using ::android::hardware::wifi::supplicant::V1_3::WpaDriverCapabilitiesMask;
+#define TIMEOUT_PERIOD 60
+class IfaceDppCallback;
+
class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
@@ -57,9 +62,66 @@
int64_t pmkCacheExpirationTimeInSec;
std::vector<uint8_t> serializedPmkCacheEntry;
+ // Data retrieved from BSS transition management frame.
+ ISupplicantStaIfaceCallback::BssTmData tmData;
+
+ enum DppCallbackType {
+ ANY_CALLBACK = -2,
+ INVALID = -1,
+
+ EVENT_SUCCESS = 0,
+ EVENT_PROGRESS,
+ EVENT_FAILURE,
+ };
+
+ DppCallbackType dppCallbackType;
+ uint32_t code;
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ count_++;
+ cv_.notify_one();
+ }
+
+ /* Test code calls this function to wait for data/event callback */
+ inline std::cv_status wait(DppCallbackType waitForCallbackType) {
+ std::unique_lock<std::mutex> lock(mtx_);
+ EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a
+ // non-void-returning method
+ auto now = std::chrono::system_clock::now();
+ std::cv_status status =
+ cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ return status;
+ }
+
+ private:
+ // synchronization objects
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_;
+
protected:
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
+ bool isDppSupported() {
+ uint32_t keyMgmtMask = 0;
+
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
+ // DPP not supported
+ return false;
+ }
+
+ return true;
+ }
};
class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -150,11 +212,29 @@
Return<void> onDppFailure(DppFailureCode /* code */) override {
return Void();
}
+ Return<void> onDppSuccess(DppSuccessCode /* code */) override {
+ return Void();
+ }
+ Return<void> onDppProgress_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppProgressCode /* code */)
+ override {
+ return Void();
+ }
+ Return<void> onDppFailure_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppFailureCode /* code */,
+ const hidl_string& /* ssid */, const hidl_string& /* channelList */,
+ const hidl_vec<uint16_t>& /* bandList */) override {
+ return Void();
+ }
Return<void> onPmkCacheAdded(
int64_t /* expirationTimeInSec */,
const hidl_vec<uint8_t>& /* serializedEntry */) override {
return Void();
}
+ Return<void> onBssTmHandlingDone(
+ const ISupplicantStaIfaceCallback::BssTmData& /* data */) override {
+ return Void();
+ }
};
class IfacePmkCacheCallback : public IfaceCallback {
@@ -172,6 +252,53 @@
: parent_(parent) {}
};
+class IfaceDppCallback : public IfaceCallback {
+ SupplicantStaIfaceHidlTest& parent_;
+ Return<void> onDppSuccess(DppSuccessCode code) override {
+ parent_.code = (uint32_t)code;
+ parent_.dppCallbackType =
+ SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_SUCCESS;
+ parent_.notify();
+ return Void();
+ }
+ Return<void> onDppProgress_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppProgressCode code)
+ override {
+ parent_.code = (uint32_t)code;
+ parent_.dppCallbackType =
+ SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_PROGRESS;
+ parent_.notify();
+ return Void();
+ }
+ Return<void> onDppFailure_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppFailureCode code,
+ const hidl_string& ssid __attribute__((unused)),
+ const hidl_string& channelList __attribute__((unused)),
+ const hidl_vec<uint16_t>& bandList __attribute__((unused))) override {
+ parent_.code = (uint32_t)code;
+ parent_.dppCallbackType =
+ SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE;
+ parent_.notify();
+ return Void();
+ }
+
+ public:
+ IfaceDppCallback(SupplicantStaIfaceHidlTest& parent) : parent_(parent){};
+};
+
+class IfaceBssTmHandlingDoneCallback : public IfaceCallback {
+ SupplicantStaIfaceHidlTest& parent_;
+ Return<void> onBssTmHandlingDone(
+ const ISupplicantStaIfaceCallback::BssTmData& data) override {
+ parent_.tmData = data;
+ return Void();
+ }
+
+ public:
+ IfaceBssTmHandlingDoneCallback(SupplicantStaIfaceHidlTest& parent)
+ : parent_(parent) {}
+};
+
/*
* RegisterCallback_1_3
*/
@@ -227,3 +354,129 @@
EXPECT_EQ(expectedStatusCode, status.code);
});
}
+
+/*
+ * GetKeyMgmtCapabilities_1_3
+ */
+TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) {
+ sta_iface_->getKeyMgmtCapabilities_1_3([&](const SupplicantStatus& status,
+ uint32_t keyMgmtMask) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ // Even though capabilities vary, these two are always set in HAL
+ // v1.3
+ EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE);
+ EXPECT_TRUE(keyMgmtMask &
+ ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
+ }
+ });
+}
+
+/*
+ * StartDppEnrolleeInitiator
+ */
+TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) {
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ if (!isDppSupported()) {
+ // DPP not supported
+ return;
+ }
+
+ hidl_string uri =
+ "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+ "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
+ uint32_t peer_id = 0;
+
+ // Register callbacks
+ sta_iface_->registerCallback_1_3(
+ new IfaceDppCallback(*this), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Add a peer URI
+ sta_iface_->addDppPeerUri(
+ uri, [&](const SupplicantStatus& status, uint32_t id) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_NE(0, id);
+ EXPECT_NE(-1, id);
+
+ peer_id = id;
+ });
+
+ // Start DPP as Enrollee-Initiator. Since this operation requires two
+ // devices, we start the operation and expect a timeout.
+ sta_iface_->startDppEnrolleeInitiator(
+ peer_id, 0, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Wait for the timeout callback
+ ASSERT_EQ(std::cv_status::no_timeout,
+ wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE));
+ ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE,
+ dppCallbackType);
+
+ // ...and then remove the peer URI.
+ sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * StartDppConfiguratorInitiator
+ */
+TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) {
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ if (!isDppSupported()) {
+ // DPP not supported
+ return;
+ }
+
+ hidl_string uri =
+ "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+ "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
+ uint32_t peer_id = 0;
+
+ // Register callbacks
+ sta_iface_->registerCallback_1_3(
+ new IfaceDppCallback(*this), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Add a peer URI
+ sta_iface_->addDppPeerUri(
+ uri, [&](const SupplicantStatus& status, uint32_t id) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_NE(0, id);
+ EXPECT_NE(-1, id);
+
+ peer_id = id;
+ });
+
+ std::string ssid =
+ "6D795F746573745F73736964"; // 'my_test_ssid' encoded in hex
+ std::string password = "746F70736563726574"; // 'topsecret' encoded in hex
+
+ // Start DPP as Configurator-Initiator. Since this operation requires two
+ // devices, we start the operation and expect a timeout.
+ sta_iface_->startDppConfiguratorInitiator(
+ peer_id, 0, ssid, password, NULL, DppNetRole::STA, DppAkm::PSK,
+ [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Wait for the timeout callback
+ ASSERT_EQ(std::cv_status::no_timeout,
+ wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE));
+ ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE,
+ dppCallbackType);
+
+ // ...and then remove the peer URI.
+ sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
index 07bc9d8..d6f55f5 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -17,15 +17,18 @@
#include <android-base/logging.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
#include "supplicant_hidl_test_utils.h"
#include "supplicant_hidl_test_utils_1_3.h"
using ::android::sp;
+using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
using ::android::hardware::wifi::supplicant::V1_3::OcspType;
namespace {
@@ -39,15 +42,37 @@
virtual void SetUp() override {
startSupplicantAndWaitForHidlService();
EXPECT_TRUE(turnOnExcessiveLogging());
+ sta_iface_ = getSupplicantStaIface_1_3();
+ ASSERT_NE(nullptr, sta_iface_.get());
sta_network_ = createSupplicantStaNetwork_1_3();
- ASSERT_NE(sta_network_.get(), nullptr);
+ ASSERT_NE(nullptr, sta_network_.get());
}
virtual void TearDown() override { stopSupplicant(); }
protected:
+ sp<ISupplicantStaIface> sta_iface_;
// ISupplicantStaNetwork object used for all tests in this fixture.
sp<ISupplicantStaNetwork> sta_network_;
+
+ bool isWapiSupported() {
+ uint32_t keyMgmtMask = 0;
+
+ // We need to first get the key management capabilities from the device.
+ // If WAPI is not supported, we just pass the test.
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK)) {
+ // WAPI not supported
+ return false;
+ }
+
+ return true;
+ }
};
/*
@@ -84,3 +109,160 @@
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}
+
+/*
+ * SetGetKeyMgmt_1_3, check new WAPI proto support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) {
+ uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK;
+
+ sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getKeyMgmt_1_3(
+ [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(keyMgmtOut, keyMgmt);
+ }
+ });
+
+ keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT;
+ sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getKeyMgmt_1_3(
+ [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(keyMgmtOut, keyMgmt);
+ }
+ });
+}
+
+/*
+ * SetGetProto_1_3, check new WAPI proto support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetProto_1_3) {
+ uint32_t wapiProto = (uint32_t)ISupplicantStaNetwork::ProtoMask::WAPI;
+ sta_network_->setProto(wapiProto, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+ sta_network_->getProto([&](const SupplicantStatus &status, uint32_t proto) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(proto, wapiProto);
+ }
+ });
+}
+
+/*
+ * SetGetGroupCipher_1_3, check new WAPI support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) {
+ uint32_t groupCipher =
+ (uint32_t)ISupplicantStaNetwork::GroupCipherMask::SMS4;
+
+ sta_network_->setGroupCipher_1_3(
+ groupCipher, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getGroupCipher_1_3(
+ [&groupCipher](const SupplicantStatus &status,
+ uint32_t groupCipherOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(groupCipherOut, groupCipher);
+ }
+ });
+}
+
+/*
+ * SetGetPairwiseCipher_1_3, check new WAPI support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) {
+ uint32_t pairwiseCipher =
+ (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::SMS4;
+
+ sta_network_->setPairwiseCipher_1_3(
+ pairwiseCipher, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getPairwiseCipher_1_3(
+ [&pairwiseCipher](const SupplicantStatus &status,
+ uint32_t pairwiseCipherOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+ }
+ });
+}
+
+/*
+ * SetGetWapiCertSuite
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) {
+ hidl_string testWapiCertSuite = "suite";
+
+ if (isWapiSupported()) {
+ sta_network_->setWapiCertSuite(
+ testWapiCertSuite, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN,
+ status.code);
+ }
+ });
+
+ sta_network_->getWapiCertSuite([testWapiCertSuite](
+ const SupplicantStatus &status,
+ const hidl_string &wapiCertSuite) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(testWapiCertSuite, wapiCertSuite);
+ }
+ });
+ } else {
+ sta_network_->setWapiCertSuite(
+ testWapiCertSuite, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+
+ sta_network_->getWapiCertSuite(
+ [testWapiCertSuite](const SupplicantStatus &status,
+ const hidl_string &wapiCertSuite __unused) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+ }
+}