Merge "Compile health hal with the VNDK."
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp
index 8a370cd..b3002a4 100644
--- a/audio/effect/2.0/vts/functional/Android.bp
+++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -17,7 +17,8 @@
cc_test {
name: "VtsHalAudioEffectV2_0TargetTest",
defaults: ["hidl_defaults"],
- srcs: ["VtsHalAudioEffectV2_0TargetTest.cpp"],
+ srcs: ["VtsHalAudioEffectV2_0TargetTest.cpp",
+ "ValidateAudioEffectsConfiguration.cpp"],
shared_libs: [
"libbase",
"liblog",
@@ -26,7 +27,9 @@
"libhidltransport",
"libnativehelper",
"libutils",
+ "libxml2",
"android.hardware.audio.common@2.0",
+ "android.hardware.audio.common.test.utility",
"android.hardware.audio.effect@2.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
@@ -35,5 +38,6 @@
cflags: [
"-O0",
"-g",
+ "-Wextra",
],
}
diff --git a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
new file mode 100644
index 0000000..fdc1347
--- /dev/null
+++ b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+#include "utility/ValidateXml.h"
+
+TEST(CheckConfig, audioEffectsConfigurationValidation) {
+ RecordProperty("description",
+ "Verify that the effects configuration file is valid according to the schema");
+ const char* xmlConfigFile = "/vendor/etc/audio_effects.xml";
+ // Not every device uses XML configuration, so only validate
+ // if the XML configuration actually exists.
+ if (access(xmlConfigFile, F_OK) == 0) {
+ ASSERT_VALID_XML(xmlConfigFile, "/data/local/tmp/audio_effects_conf_V2_0.xsd");
+ }
+}
diff --git a/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd b/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd
new file mode 100644
index 0000000..ca6a7dc
--- /dev/null
+++ b/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://schemas.android.com/audio/audio_effects_conf/v2_0"
+ xmlns:aec="http://schemas.android.com/audio/audio_effects_conf/v2_0"
+ elementFormDefault="qualified">
+
+ <!-- Simple types -->
+ <xs:simpleType name="versionType">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="2.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="uuidType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="streamInputType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="mic"/>
+ <xs:enumeration value="voice_uplink"/>
+ <xs:enumeration value="voice_downlink"/>
+ <xs:enumeration value="voice_call"/>
+ <xs:enumeration value="camcorder"/>
+ <xs:enumeration value="voice_recognition"/>
+ <xs:enumeration value="voice_communication"/>
+ <xs:enumeration value="unprocessed"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="streamOutputType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="voice_call"/>
+ <xs:enumeration value="system"/>
+ <xs:enumeration value="ring"/>
+ <xs:enumeration value="music"/>
+ <xs:enumeration value="alarm"/>
+ <xs:enumeration value="notification"/>
+ <xs:enumeration value="bluetooth_sco"/>
+ <xs:enumeration value="enforced_audible"/>
+ <xs:enumeration value="dtmf"/>
+ <xs:enumeration value="tts"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="relativePathType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[^/].*"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <!-- Complex types -->
+ <xs:complexType name="librariesType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List of effect libraries to load. Each library element must have "name" and
+ "path" attributes. The latter is giving the path of the library .so file
+ relative to the standard effect folders: /(vendor|odm|system)/lib(64)?/soundfx/
+
+ Example for a library in "/vendor/lib/soundfx/lib.so":
+ <library name="name" path="lib.so"/>
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="library" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="path" type="aec:relativePathType" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="effectImplType">
+ <xs:attribute name="library" type="xs:string" use="required"/>
+ <xs:attribute name="uuid" type="aec:uuidType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="effectType">
+ <xs:complexContent>
+ <xs:extension base="aec:effectImplType">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="effectProxyType">
+ <xs:complexContent>
+ <xs:extension base="aec:effectType">
+ <xs:sequence>
+ <xs:element name="libsw" type="aec:effectImplType"/>
+ <xs:element name="libhw" type="aec:effectImplType"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="effectsType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List of effects to load. Each effect element must contain "name",
+ "library", and "uuid" attrs. The value of the "library" attr must
+ correspond to the name of a "library" element. The name of the effect
+ element is indicative, only the value of the "uuid" element designates
+ the effect for the audio framework. The uuid is the implementation
+ specific UUID as specified by the effect vendor. This is not the generic
+ effect type UUID.
+
+ For effect proxy implementations, SW and HW implemetations of the effect
+ can be specified.
+
+ Example:
+
+ <effect name="name" library="lib" uuid="uuuu"/>
+ <effectProxy name="proxied" library="proxy" uuid="xxxx">
+ <libsw library="sw_bundle" uuid="yyyy"/>
+ <libhw library="offload_bundle" uuid="zzzz"/>
+ </effectProxy>
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="effect" type="aec:effectType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="effectProxy" type="aec:effectProxyType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:choice>
+ </xs:complexType>
+ <xs:complexType name="streamProcessingType">
+ <xs:sequence>
+ <xs:element name="apply" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="effect" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="streamPreprocessType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio preprocessing configuration. The processing configuration consists
+ of a list of elements each describing processing settings for a given
+ input stream. Valid input stream types are listed in "streamInputType".
+
+ Each stream element contains a list of "apply" elements. The value of the
+ "effect" attr must correspond to the name of an "effect" element.
+
+ Example:
+
+ <stream type="voice_communication">
+ <apply effect="effect1"/>
+ <apply effect="effect2"/>
+ </stream>
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="aec:streamProcessingType">
+ <xs:attribute name="type" type="aec:streamInputType" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="streamPostprocessType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio postprocessing configuration. The processing configuration consists
+ of a list of elements each describing processing settings for a given
+ output stream. Valid output stream types are listed in "streamOutputType".
+
+ Each stream element contains a list of "apply" elements. The value of the
+ "effect" attr must correspond to the name of an "effect" element.
+
+ Example:
+
+ <stream type="music">
+ <apply effect="effect1"/>
+ </stream>
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="aec:streamProcessingType">
+ <xs:attribute name="type" type="aec:streamOutputType" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <!-- Root element -->
+ <xs:element name="audio_effects_conf">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="libraries" type="aec:librariesType"/>
+ <xs:element name="effects" type="aec:effectsType"/>
+ <xs:element name="postprocess" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="stream" type="aec:streamPostprocessType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="preprocess" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="stream" type="aec:streamPreprocessType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="version" type="aec:versionType" use="required"/>
+ </xs:complexType>
+
+ <!-- Keys and references -->
+ <xs:key name="libraryName">
+ <xs:selector xpath="aec:libraries/aec:library"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="libraryNameRef1" refer="aec:libraryName">
+ <xs:selector xpath="aec:effects/aec:effect"/>
+ <xs:field xpath="@library"/>
+ </xs:keyref>
+ <xs:keyref name="libraryNameRef2" refer="aec:libraryName">
+ <xs:selector xpath="aec:effects/aec:effect/aec:libsw"/>
+ <xs:field xpath="@library"/>
+ </xs:keyref>
+ <xs:keyref name="libraryNameRef3" refer="aec:libraryName">
+ <xs:selector xpath="aec:effects/aec:effect/aec:libhw"/>
+ <xs:field xpath="@library"/>
+ </xs:keyref>
+ <xs:key name="effectName">
+ <xs:selector xpath="aec:effects/aec:effect"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="effectNamePreRef" refer="aec:effectName">
+ <xs:selector xpath="aec:preprocess/aec:stream/aec:apply"/>
+ <xs:field xpath="@effect"/>
+ </xs:keyref>
+ <xs:keyref name="effectNamePostRef" refer="aec:effectName">
+ <xs:selector xpath="aec:postprocess/aec:stream/aec:apply"/>
+ <xs:field xpath="@effect"/>
+ </xs:keyref>
+ </xs:element>
+</xs:schema>
diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc
index bc0bc92..78676b2 100644
--- a/bluetooth/1.0/default/async_fd_watcher.cc
+++ b/bluetooth/1.0/default/async_fd_watcher.cc
@@ -24,7 +24,7 @@
#include <map>
#include <mutex>
#include <thread>
-#include <utils/Log.h>
+#include <log/log.h>
#include <vector>
#include "fcntl.h"
#include "sys/select.h"
diff --git a/bluetooth/1.0/default/bluetooth_address.cc b/bluetooth/1.0/default/bluetooth_address.cc
index 65dc6a6..fd53e78 100644
--- a/bluetooth/1.0/default/bluetooth_address.cc
+++ b/bluetooth/1.0/default/bluetooth_address.cc
@@ -19,6 +19,7 @@
#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
+#include <unistd.h>
#include <utils/Log.h>
namespace android {
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index 2008b00..054ed39 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -22,6 +22,7 @@
#include <fcntl.h>
#include <log/log.h>
#include <sys/uio.h>
+#include <unistd.h>
namespace android {
namespace hardware {
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 2da1254..fde08ac 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -21,6 +21,7 @@
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
+#include <unistd.h>
#include <utils/Log.h>
namespace {
diff --git a/bluetooth/1.0/default/hci_protocol.cc b/bluetooth/1.0/default/hci_protocol.cc
index 5d6f1d1..bf94dfe 100644
--- a/bluetooth/1.0/default/hci_protocol.cc
+++ b/bluetooth/1.0/default/hci_protocol.cc
@@ -20,6 +20,7 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <unistd.h>
#include <log/log.h>
namespace android {
diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp
index 3aac127..1119ffd 100644
--- a/broadcastradio/1.1/default/BroadcastRadio.cpp
+++ b/broadcastradio/1.1/default/BroadcastRadio.cpp
@@ -121,7 +121,7 @@
Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused,
const sp<V1_0::ITunerCallback>& callback,
openTuner_cb _hidl_cb) {
- ALOGV("%s", __func__);
+ ALOGV("%s(%s)", __func__, toString(config.type).c_str());
lock_guard<mutex> lk(mMut);
auto oldTuner = mTuner.promote();
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
index c2c1158..f57bc79 100644
--- a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
+++ b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
@@ -48,7 +48,7 @@
}
Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) {
- ALOGV("%s", __func__);
+ ALOGV("%s(%s)", __func__, toString(classId).c_str());
auto moduleIt = mRadioModules.find(classId);
if (moduleIt == mRadioModules.end()) {
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
index bb07f36..a36ec3f 100644
--- a/broadcastradio/1.1/default/Tuner.cpp
+++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -105,9 +105,14 @@
return info11;
}
+bool Tuner::isFmLocked() {
+ if (!utils::isAmFm(utils::getType(mCurrentProgram))) return false;
+ return mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM;
+}
+
void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
VirtualRadio* virtualRadio = nullptr;
- if (mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM) {
+ if (isFmLocked()) {
virtualRadio = &mVirtualFm;
}
@@ -132,11 +137,11 @@
lock_guard<mutex> lk(mMut);
vector<VirtualProgram> list;
- if (mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM) {
+ if (isFmLocked()) {
list = mVirtualFm.getProgramList();
}
- if (list.size() == 0) {
+ if (list.empty()) {
mIsTuneCompleted = false;
auto task = [this, direction]() {
ALOGI("Performing failed scan %s", toString(direction).c_str());
@@ -288,14 +293,17 @@
Return<void> Tuner::getProgramList(const hidl_string& filter __unused, getProgramList_cb _hidl_cb) {
ALOGV("%s", __func__);
+ lock_guard<mutex> lk(mMut);
auto& virtualRadio = mVirtualFm;
- if (mAmfmConfig.type != Band::FM_HD && mAmfmConfig.type != Band::FM) {
+ if (!isFmLocked()) {
+ ALOGI("bands other than FM are not supported yet");
_hidl_cb(ProgramListResult::OK, {});
return Void();
}
auto list = virtualRadio.getProgramList();
+ ALOGD("returning a list of %zu programs", list.size());
_hidl_cb(ProgramListResult::OK, vector<ProgramInfo>(list.begin(), list.end()));
return Void();
}
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h
index 17ee99f..5c8a7e5 100644
--- a/broadcastradio/1.1/default/Tuner.h
+++ b/broadcastradio/1.1/default/Tuner.h
@@ -65,6 +65,7 @@
ProgramInfo mCurrentProgramInfo = {};
void tuneInternalLocked(const ProgramSelector& sel);
+ bool isFmLocked(); // TODO(b/36864090): make it generic, not FM only
};
} // namespace implementation
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
index a4c0849..c136019 100644
--- a/broadcastradio/1.1/vts/functional/Android.bp
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -29,9 +29,27 @@
"android.hardware.broadcastradio@1.0",
"android.hardware.broadcastradio@1.1",
],
- static_libs: ["VtsHalHidlTargetTestBase"],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "broadcastradio-vts-call-barrier",
+ "libgmock",
+ ],
cflags: [
+ "-Wextra",
"-O0",
"-g",
],
}
+
+cc_library_static {
+ name: "broadcastradio-vts-call-barrier",
+ srcs: [
+ "call-barrier.cpp",
+ ],
+ export_include_dirs: ["."],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index 0de6fa5..6e6ab44 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -14,480 +14,236 @@
* limitations under the License.
*/
-#define LOG_TAG "BroadcastRadioHidlHalTest"
+#define LOG_TAG "broadcastradio.vts"
+
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
+#include <call-barrier.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
+#include <gmock/gmock.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/threads.h>
+#include <chrono>
+
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
-#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
#include <android/hardware/broadcastradio/1.1/ITuner.h>
#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
#include <android/hardware/broadcastradio/1.1/types.h>
+#include "mock-timeout.h"
-namespace V1_0 = ::android::hardware::broadcastradio::V1_0;
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace vts {
-using ::android::sp;
-using ::android::Mutex;
-using ::android::Condition;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::broadcastradio::V1_0::BandConfig;
-using ::android::hardware::broadcastradio::V1_0::Class;
-using ::android::hardware::broadcastradio::V1_0::Direction;
-using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
-using ::android::hardware::broadcastradio::V1_0::MetaData;
-using ::android::hardware::broadcastradio::V1_0::Properties;
-using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory;
-using ::android::hardware::broadcastradio::V1_1::ITuner;
-using ::android::hardware::broadcastradio::V1_1::ITunerCallback;
-using ::android::hardware::broadcastradio::V1_1::ProgramInfo;
-using ::android::hardware::broadcastradio::V1_1::Result;
-using ::android::hardware::broadcastradio::V1_1::ProgramListResult;
-using ::android::hardware::hidl_vec;
+using namespace std::chrono_literals;
-// The main test class for Broadcast Radio HIDL HAL.
+using testing::_;
+using testing::AnyNumber;
+using testing::ByMove;
+using testing::DoAll;
+using testing::SaveArg;
-class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- protected:
- virtual void SetUp() override {
- auto factory = ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>();
- ASSERT_NE(nullptr, factory.get());
- Result halResult;
- factory->connectModule(Class::AM_FM, [&](Result retval, const sp<IBroadcastRadio>& result) {
- halResult = retval;
- if (retval == Result::OK) {
- mRadio = IBroadcastRadio::castFrom(result);
- }
- });
- ASSERT_EQ(Result::OK, halResult);
- mTunerCallback = new MyCallback(this);
- ASSERT_NE(nullptr, mRadio.get());
- ASSERT_NE(nullptr, mTunerCallback.get());
- }
+using broadcastradio::vts::CallBarrier;
+using V1_0::BandConfig;
+using V1_0::Class;
+using V1_0::MetaData;
- virtual void TearDown() override {
- mTuner.clear();
- mRadio.clear();
- }
+static constexpr auto kConfigTimeout = 10s;
+static constexpr auto kConnectModuleTimeout = 1s;
+static constexpr auto kTuneTimeout = 30s;
+static constexpr auto kFullScanTimeout = 1min;
- class MyCallback : public ITunerCallback {
- public:
-
- // ITunerCallback methods (see doc in ITunerCallback.hal)
- virtual Return<void> hardwareFailure() {
- ALOGI("%s", __FUNCTION__);
- mParentTest->onHwFailureCallback();
- return Void();
- }
-
- virtual Return<void> configChange(Result result, const BandConfig& config __unused) {
- ALOGI("%s result %d", __FUNCTION__, result);
- mParentTest->onResultCallback(result);
- return Void();
- }
-
- virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) {
- return Void();
- }
-
- virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) {
- ALOGI("%s result %d", __FUNCTION__, result);
- mParentTest->onResultCallback(result);
- return Void();
- }
-
- virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) {
- return Void();
- }
-
- virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) {
- return Void();
- }
-
- virtual Return<void> antennaStateChange(bool connected) {
- ALOGI("%s connected %d", __FUNCTION__, connected);
- return Void();
- }
-
- virtual Return<void> trafficAnnouncement(bool active) {
- ALOGI("%s active %d", __FUNCTION__, active);
- return Void();
- }
-
- virtual Return<void> emergencyAnnouncement(bool active) {
- ALOGI("%s active %d", __FUNCTION__, active);
- return Void();
- }
-
- virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
- const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
- ALOGI("%s", __FUNCTION__);
- return Void();
- }
-
- virtual Return<void> backgroundScanAvailable(bool isAvailable __unused) {
- return Void();
- }
-
- virtual Return<void> backgroundScanComplete(ProgramListResult result) {
- ALOGV("%s", __func__);
- mParentTest->onProgramListResultCallback(result);
- return Void();
- }
-
- virtual Return<void> programListChanged() {
- return Void();
- }
-
- MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
-
- private:
- // BroadcastRadioHidlTest instance to which callbacks will be notified.
- BroadcastRadioHidlTest *mParentTest;
- };
-
-
- /**
- * Method called by MyCallback when a callback with no status or boolean value is received
- */
- void onCallback() {
- Mutex::Autolock _l(mLock);
- onCallback_l();
- }
-
- /**
- * Method called by MyCallback when hardwareFailure() callback is received
- */
- void onHwFailureCallback() {
- Mutex::Autolock _l(mLock);
- mHwFailure = true;
- onCallback_l();
- }
-
- /**
- * Method called by MyCallback when a callback with status is received
- */
- void onResultCallback(Result result) {
- Mutex::Autolock _l(mLock);
- mResultCallbackData = result;
- onCallback_l();
- }
-
- /**
- * Method called by MyCallback when a callback with status is received
- */
- void onProgramListResultCallback(ProgramListResult result) {
- Mutex::Autolock _l(mLock);
- mProgramListResultCallbackData = result;
- onCallback_l();
- }
-
- /**
- * Method called by MyCallback when a boolean indication is received
- */
- void onBoolCallback(bool result) {
- Mutex::Autolock _l(mLock);
- mBoolCallbackData = result;
- onCallback_l();
- }
-
-
- BroadcastRadioHidlTest() :
- mCallbackCalled(false), mBoolCallbackData(false),
- mResultCallbackData(Result::OK), mHwFailure(false) {}
-
- void onCallback_l() {
- if (!mCallbackCalled) {
- mCallbackCalled = true;
- mCallbackCond.broadcast();
- }
- }
-
-
- bool waitForCallback(nsecs_t reltime = 0) {
- Mutex::Autolock _l(mLock);
- nsecs_t endTime = systemTime() + reltime;
- while (!mCallbackCalled) {
- if (reltime == 0) {
- mCallbackCond.wait(mLock);
- } else {
- nsecs_t now = systemTime();
- if (now > endTime) {
- return false;
- }
- mCallbackCond.waitRelative(mLock, endTime - now);
- }
- }
- return true;
- }
-
- bool getProperties();
- bool openTuner();
- bool checkAntenna();
-
- static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
- static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
- static const nsecs_t kFullScanTimeoutNs = seconds_to_nanoseconds(60);
-
- sp<IBroadcastRadio> mRadio;
- Properties mHalProperties;
- sp<ITuner> mTuner;
- sp<MyCallback> mTunerCallback;
- Mutex mLock;
- Condition mCallbackCond;
- bool mCallbackCalled;
- bool mBoolCallbackData;
- Result mResultCallbackData;
- ProgramListResult mProgramListResultCallbackData;
- bool mHwFailure;
-};
-
-// A class for test environment setup (kept since this file is a template).
-class BroadcastRadioHidlEnvironment : public ::testing::Environment {
- public:
- virtual void SetUp() {}
- virtual void TearDown() {}
-};
-
-bool BroadcastRadioHidlTest::getProperties()
-{
- if (mHalProperties.bands.size() == 0) {
- Result halResult = Result::NOT_INITIALIZED;
- Return<void> hidlReturn =
- mRadio->getProperties([&](Result result, const Properties& properties) {
- halResult = result;
- if (result == Result::OK) {
- mHalProperties = properties;
- }
- });
-
- EXPECT_TRUE(hidlReturn.isOk());
- EXPECT_EQ(Result::OK, halResult);
- EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
- EXPECT_GT(mHalProperties.numTuners, 0u);
- EXPECT_GT(mHalProperties.bands.size(), 0u);
- }
- return mHalProperties.bands.size() > 0;
+static void printSkipped(std::string msg) {
+ std::cout << "[ SKIPPED ] " << msg << std::endl;
}
-bool BroadcastRadioHidlTest::openTuner()
-{
- if (!getProperties()) {
- return false;
+class TunerCallbackMock : public ITunerCallback {
+ public:
+ MOCK_METHOD0(hardwareFailure, Return<void>());
+ MOCK_TIMEOUT_METHOD2(configChange, Return<void>(Result, const BandConfig&));
+ MOCK_METHOD2(tuneComplete, Return<void>(Result, const V1_0::ProgramInfo&));
+ MOCK_TIMEOUT_METHOD2(tuneComplete_1_1, Return<void>(Result, const ProgramInfo&));
+ MOCK_METHOD1(afSwitch, Return<void>(const V1_0::ProgramInfo&));
+ MOCK_METHOD1(afSwitch_1_1, Return<void>(const ProgramInfo&));
+ MOCK_METHOD1(antennaStateChange, Return<void>(bool connected));
+ MOCK_METHOD1(trafficAnnouncement, Return<void>(bool active));
+ MOCK_METHOD1(emergencyAnnouncement, Return<void>(bool active));
+ MOCK_METHOD3(newMetadata, Return<void>(uint32_t ch, uint32_t subCh, const hidl_vec<MetaData>&));
+ MOCK_METHOD1(backgroundScanAvailable, Return<void>(bool));
+ MOCK_TIMEOUT_METHOD1(backgroundScanComplete, Return<void>(ProgramListResult));
+ MOCK_METHOD0(programListChanged, Return<void>());
+};
+
+class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase,
+ public ::testing::WithParamInterface<Class> {
+ protected:
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ // TODO(b/36864490): check all bands for good test conditions (ie. FM is more likely to have
+ // any stations on the list, so don't pick AM blindly).
+ bool openTuner(unsigned band);
+ const BandConfig& getBand(unsigned idx);
+
+ Class radioClass;
+ bool skipped = false;
+
+ sp<IBroadcastRadio> mRadioModule;
+ sp<ITuner> mTuner;
+ sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
+
+ private:
+ hidl_vec<BandConfig> mBands;
+};
+
+void BroadcastRadioHalTest::SetUp() {
+ radioClass = GetParam();
+
+ // set general expectations for a callback
+ EXPECT_CALL(*mCallback, hardwareFailure()).Times(0);
+
+ // lookup HIDL service
+ auto factory = getService<IBroadcastRadioFactory>();
+ ASSERT_NE(nullptr, factory.get());
+
+ // connect radio module
+ Result connectResult;
+ CallBarrier onConnect;
+ factory->connectModule(radioClass, [&](Result ret, const sp<V1_0::IBroadcastRadio>& radio) {
+ connectResult = ret;
+ if (ret == Result::OK) mRadioModule = IBroadcastRadio::castFrom(radio);
+ onConnect.call();
+ });
+ ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout));
+
+ if (connectResult == Result::INVALID_ARGUMENTS) {
+ printSkipped("This device class is not supported.");
+ skipped = true;
+ return;
}
- if (mTuner.get() == nullptr) {
+ ASSERT_EQ(connectResult, Result::OK);
+ ASSERT_NE(nullptr, mRadioModule.get());
+
+ // get module properties
+ Properties prop11;
+ auto& prop10 = prop11.base;
+ auto propResult =
+ mRadioModule->getProperties_1_1([&](const Properties& properties) { prop11 = properties; });
+
+ ASSERT_TRUE(propResult.isOk());
+ EXPECT_EQ(radioClass, prop10.classId);
+ EXPECT_GT(prop10.numTuners, 0u);
+ if (radioClass == Class::AM_FM) {
+ EXPECT_GT(prop10.bands.size(), 0u);
+ }
+ mBands = prop10.bands;
+}
+
+void BroadcastRadioHalTest::TearDown() {
+ mTuner.clear();
+ mRadioModule.clear();
+ // TODO(b/36864490): wait (with timeout) until mCallback has only one reference
+}
+
+bool BroadcastRadioHalTest::openTuner(unsigned band) {
+ EXPECT_EQ(nullptr, mTuner.get());
+
+ if (radioClass == Class::AM_FM) {
+ EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _);
+ }
+
+ Result halResult = Result::NOT_INITIALIZED;
+ auto openCb = [&](Result result, const sp<V1_0::ITuner>& tuner) {
+ halResult = result;
+ if (result != Result::OK) return;
+ mTuner = ITuner::castFrom(tuner);
+ };
+ auto hidlResult = mRadioModule->openTuner(getBand(band), true, mCallback, openCb);
+
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_NE(nullptr, mTuner.get());
+ if (radioClass == Class::AM_FM && mTuner != nullptr) {
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
+
+ BandConfig halConfig;
Result halResult = Result::NOT_INITIALIZED;
- auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
- [&](Result result, const sp<V1_0::ITuner>& tuner) {
- halResult = result;
- if (result == Result::OK) {
- mTuner = ITuner::castFrom(tuner);
- }
- });
- EXPECT_TRUE(hidlReturn.isOk());
+ mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ halConfig = config;
+ });
EXPECT_EQ(Result::OK, halResult);
- EXPECT_NE(nullptr, mTuner.get());
- EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+ EXPECT_TRUE(halConfig.antennaConnected);
}
+
EXPECT_NE(nullptr, mTuner.get());
return nullptr != mTuner.get();
}
-bool BroadcastRadioHidlTest::checkAntenna()
-{
- BandConfig halConfig;
- Result halResult = Result::NOT_INITIALIZED;
- Return<void> hidlReturn =
- mTuner->getConfiguration([&](Result result, const BandConfig& config) {
- halResult = result;
- if (result == Result::OK) {
- halConfig = config;
- }
- });
+const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) {
+ static const BandConfig dummyBandConfig = {};
- return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
-}
-
-
-/**
- * Test IBroadcastRadio::getProperties() method
- *
- * Verifies that:
- * - the HAL implements the method
- * - the method returns 0 (no error)
- * - the implementation class is AM_FM
- * - the implementation supports at least one tuner
- * - the implementation supports at one band
- */
-TEST_F(BroadcastRadioHidlTest, GetProperties) {
- EXPECT_TRUE(getProperties());
-}
-
-/**
- * Test IBroadcastRadio::openTuner() method
- *
- * Verifies that:
- * - the HAL implements the method
- * - the method returns 0 (no error) and a valid ITuner interface
- */
-TEST_F(BroadcastRadioHidlTest, OpenTuner) {
- EXPECT_TRUE(openTuner());
-}
-
-/**
- * Test ITuner::setConfiguration() and getConfiguration methods
- *
- * Verifies that:
- * - the HAL implements both methods
- * - the methods return 0 (no error)
- * - the configuration callback is received within kConfigCallbacktimeoutNs ns
- * - the configuration read back from HAl has the same class Id
- */
-TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) {
- ASSERT_TRUE(openTuner());
- // test setConfiguration
- mCallbackCalled = false;
- Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
- EXPECT_TRUE(hidlResult.isOk());
- EXPECT_EQ(Result::OK, hidlResult);
- EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
- EXPECT_EQ(Result::OK, mResultCallbackData);
-
- // test getConfiguration
- BandConfig halConfig;
- Result halResult;
- Return<void> hidlReturn =
- mTuner->getConfiguration([&](Result result, const BandConfig& config) {
- halResult = result;
- if (result == Result::OK) {
- halConfig = config;
- }
- });
- EXPECT_TRUE(hidlReturn.isOk());
- EXPECT_EQ(Result::OK, halResult);
- EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
-}
-
-/**
- * Test ITuner::scan
- *
- * Verifies that:
- * - the HAL implements the method
- * - the method returns 0 (no error)
- * - the tuned callback is received within kTuneCallbacktimeoutNs ns
- */
-TEST_F(BroadcastRadioHidlTest, Scan) {
- ASSERT_TRUE(openTuner());
- ASSERT_TRUE(checkAntenna());
- // test scan UP
- mCallbackCalled = false;
- Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
- EXPECT_TRUE(hidlResult.isOk());
- EXPECT_EQ(Result::OK, hidlResult);
- EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
-
- // test scan DOWN
- mCallbackCalled = false;
- hidlResult = mTuner->scan(Direction::DOWN, true);
- EXPECT_TRUE(hidlResult.isOk());
- EXPECT_EQ(Result::OK, hidlResult);
- EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
-}
-
-/**
- * Test ITuner::step
- *
- * Verifies that:
- * - the HAL implements the method
- * - the method returns 0 (no error)
- * - the tuned callback is received within kTuneCallbacktimeoutNs ns
- */
-TEST_F(BroadcastRadioHidlTest, Step) {
- ASSERT_TRUE(openTuner());
- ASSERT_TRUE(checkAntenna());
- // test step UP
- mCallbackCalled = false;
- Return<Result> hidlResult = mTuner->step(Direction::UP, true);
- EXPECT_TRUE(hidlResult.isOk());
- EXPECT_EQ(Result::OK, hidlResult);
- EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
-
- // test step DOWN
- mCallbackCalled = false;
- hidlResult = mTuner->step(Direction::DOWN, true);
- EXPECT_TRUE(hidlResult.isOk());
- EXPECT_EQ(Result::OK, hidlResult);
- EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
-}
-
-/**
- * Test ITuner::tune, getProgramInformation and cancel methods
- *
- * Verifies that:
- * - the HAL implements the methods
- * - the methods return 0 (no error)
- * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
- */
-TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
- ASSERT_TRUE(openTuner());
- ASSERT_TRUE(checkAntenna());
-
- // test tune
- ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
- ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
-
- // test scan UP
- uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
- uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
- uint32_t spacing = mHalProperties.bands[0].spacings[0];
-
- uint32_t channel =
- lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
- mCallbackCalled = false;
- mResultCallbackData = Result::NOT_INITIALIZED;
- Return<Result> hidlResult = mTuner->tune(channel, 0);
- EXPECT_TRUE(hidlResult.isOk());
- EXPECT_EQ(Result::OK, hidlResult);
- EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
-
- // test getProgramInformation
- ProgramInfo halInfo;
- Result halResult = Result::NOT_INITIALIZED;
- Return<void> hidlReturn = mTuner->getProgramInformation_1_1(
- [&](Result result, const ProgramInfo& info) {
- halResult = result;
- if (result == Result::OK) {
- halInfo = info;
- }
- });
- EXPECT_TRUE(hidlReturn.isOk());
- EXPECT_EQ(Result::OK, halResult);
- auto &halInfo_1_1 = halInfo.base;
- if (mResultCallbackData == Result::OK) {
- EXPECT_LE(halInfo_1_1.channel, upperLimit);
- EXPECT_GE(halInfo_1_1.channel, lowerLimit);
+ if (radioClass != Class::AM_FM) {
+ ALOGD("Not AM/FM radio, returning dummy band config");
+ return dummyBandConfig;
}
- // test cancel
- mTuner->tune(lowerLimit, 0);
- hidlResult = mTuner->cancel();
- EXPECT_TRUE(hidlResult.isOk());
- EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_GT(mBands.size(), idx);
+ if (mBands.size() <= idx) {
+ ALOGD("Band index out of bound, returning dummy band config");
+ return dummyBandConfig;
+ }
+
+ auto& band = mBands[idx];
+ ALOGD("Returning %s band", toString(band.type).c_str());
+ return band;
}
-TEST_F(BroadcastRadioHidlTest, TuneFromProgramList) {
- ASSERT_TRUE(openTuner());
- ASSERT_TRUE(checkAntenna());
+/**
+ * Test IBroadcastRadio::openTuner() method called twice.
+ *
+ * Verifies that:
+ * - the openTuner method succeeds when called for the second time without
+ * deleting previous ITuner instance.
+ *
+ * This is a more strict requirement than in 1.0, where a second openTuner
+ * might fail.
+ */
+TEST_P(BroadcastRadioHalTest, OpenTunerTwice) {
+ if (skipped) return;
+ ASSERT_TRUE(openTuner(0));
+
+ Result halResult = Result::NOT_INITIALIZED;
+ auto openCb = [&](Result result, const sp<V1_0::ITuner>&) { halResult = result; };
+ auto hidlResult = mRadioModule->openTuner(getBand(0), true, mCallback, openCb);
+ ASSERT_TRUE(hidlResult.isOk());
+ ASSERT_EQ(Result::OK, halResult);
+}
+
+/**
+ * Test tuning to program list entry.
+ *
+ * Verifies that:
+ * - getProgramList either succeeds or returns NOT_STARTED/NOT_READY status;
+ * - if the program list is NOT_STARTED, startBackgroundScan makes it completed
+ * within a full scan timeout and the next getProgramList call succeeds;
+ * - if the program list is not empty, tune_1_1 call succeeds.
+ */
+TEST_P(BroadcastRadioHalTest, TuneFromProgramList) {
+ if (skipped) return;
+ ASSERT_TRUE(openTuner(0));
ProgramInfo firstProgram;
bool isListEmpty;
ProgramListResult getListResult = ProgramListResult::NOT_INITIALIZED;
auto getListCb = [&](ProgramListResult result, const hidl_vec<ProgramInfo>& list) {
+ ALOGD("getListCb(%s, ProgramInfo[%zu])", toString(result).c_str(), list.size());
getListResult = result;
if (result != ProgramListResult::OK) return;
isListEmpty = (list.size() == 0);
@@ -496,40 +252,50 @@
};
// first try...
- auto hidlReturn = mTuner->getProgramList("", getListCb);
- ASSERT_TRUE(hidlReturn.isOk());
+ EXPECT_TIMEOUT_CALL(*mCallback, backgroundScanComplete, ProgramListResult::OK)
+ .Times(AnyNumber());
+ auto hidlResult = mTuner->getProgramList("", getListCb);
+ ASSERT_TRUE(hidlResult.isOk());
if (getListResult == ProgramListResult::NOT_STARTED) {
auto result = mTuner->startBackgroundScan();
- ASSERT_TRUE(result.isOk());
ASSERT_EQ(ProgramListResult::OK, result);
getListResult = ProgramListResult::NOT_READY; // continue as in NOT_READY case
}
if (getListResult == ProgramListResult::NOT_READY) {
- ASSERT_TRUE(waitForCallback(kFullScanTimeoutNs));
- ASSERT_EQ(ProgramListResult::OK, mProgramListResultCallbackData);
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, backgroundScanComplete, kFullScanTimeout);
// second (last) try...
- hidlReturn = mTuner->getProgramList("", getListCb);
- ASSERT_TRUE(hidlReturn.isOk());
+ hidlResult = mTuner->getProgramList("", getListCb);
+ ASSERT_TRUE(hidlResult.isOk());
ASSERT_EQ(ProgramListResult::OK, getListResult);
}
if (isListEmpty) {
- std::cout << "[ SKIPPED ] Program list is empty. " << std::endl;
+ printSkipped("Program list is empty.");
return;
}
+ ProgramInfo infoCb;
+ EXPECT_CALL(*mCallback, tuneComplete(_, _));
+ EXPECT_TIMEOUT_CALL(*mCallback, tuneComplete_1_1, Result::OK, _)
+ .WillOnce(DoAll(SaveArg<1>(&infoCb), testing::Return(ByMove(Void()))));
auto tuneResult = mTuner->tune_1_1(firstProgram.selector);
- ASSERT_TRUE(tuneResult.isOk());
- EXPECT_EQ(Result::OK, tuneResult);
- EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
- // TODO(b/36864490): check this too, when mProgramInfoCallbackData is cherry-picked from 1.0
- // EXPECT_EQ(firstProgram.selector.primaryId, mProgramInfoCallbackData.selector.primaryId);
+ ASSERT_EQ(Result::OK, tuneResult);
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, tuneComplete_1_1, kTuneTimeout);
+ EXPECT_EQ(firstProgram.selector.primaryId, infoCb.selector.primaryId);
}
+INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
+ ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
+
+} // namespace vts
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
::testing::InitGoogleTest(&argc, argv);
int status = RUN_ALL_TESTS();
ALOGI("Test result = %d", status);
diff --git a/broadcastradio/1.1/vts/functional/call-barrier.cpp b/broadcastradio/1.1/vts/functional/call-barrier.cpp
new file mode 100644
index 0000000..fede297
--- /dev/null
+++ b/broadcastradio/1.1/vts/functional/call-barrier.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "call-barrier.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace vts {
+
+using std::lock_guard;
+using std::mutex;
+using std::unique_lock;
+
+void CallBarrier::call() {
+ lock_guard<mutex> lk(mMut);
+ mWasCalled = true;
+ mCond.notify_all();
+}
+
+bool CallBarrier::waitForCall(std::chrono::milliseconds timeout) {
+ unique_lock<mutex> lk(mMut);
+
+ if (mWasCalled) return true;
+
+ auto status = mCond.wait_for(lk, timeout);
+ return status == std::cv_status::no_timeout;
+}
+
+} // namespace vts
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.1/vts/functional/call-barrier.h b/broadcastradio/1.1/vts/functional/call-barrier.h
new file mode 100644
index 0000000..462396a
--- /dev/null
+++ b/broadcastradio/1.1/vts/functional/call-barrier.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_CALL_BARRIER
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_CALL_BARRIER
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace vts {
+
+/**
+ * A barrier for thread synchronization, where one should wait for another to
+ * reach a specific point in execution.
+ */
+class CallBarrier {
+ public:
+ /**
+ * Notify the other thread it may continue execution.
+ *
+ * This may be called before the other thread starts waiting on the barrier.
+ */
+ void call();
+
+ /**
+ * Wait for the other thread to reach call() execution point.
+ *
+ * @param timeout a maximum time to wait.
+ * @returns {@code false} if timed out, {@code true} otherwise.
+ */
+ bool waitForCall(std::chrono::milliseconds timeout);
+
+ private:
+ bool mWasCalled = false;
+ std::mutex mMut;
+ std::condition_variable mCond;
+};
+
+} // namespace vts
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_CALL_BARRIER
diff --git a/broadcastradio/1.1/vts/functional/mock-timeout.h b/broadcastradio/1.1/vts/functional/mock-timeout.h
new file mode 100644
index 0000000..fa1114f
--- /dev/null
+++ b/broadcastradio/1.1/vts/functional/mock-timeout.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
+
+#include <gmock/gmock.h>
+#include <thread>
+
+/**
+ * Common helper objects for gmock timeout extension.
+ *
+ * INTERNAL IMPLEMENTATION - don't use in user code.
+ */
+#define EGMOCK_TIMEOUT_METHOD_DEF_(Method, ...) \
+ std::atomic<bool> egmock_called_##Method; \
+ std::mutex egmock_mut_##Method; \
+ std::condition_variable egmock_cond_##Method;
+
+/**
+ * Common method body for gmock timeout extension.
+ *
+ * INTERNAL IMPLEMENTATION - don't use in user code.
+ */
+#define EGMOCK_TIMEOUT_METHOD_BODY_(Method, ...) \
+ auto ret = egmock_##Method(__VA_ARGS__); \
+ { \
+ std::lock_guard<std::mutex> lk(egmock_mut_##Method); \
+ egmock_called_##Method = true; \
+ egmock_cond_##Method.notify_all(); \
+ } \
+ return ret;
+
+/**
+ * Gmock MOCK_METHOD1 timeout-capable extension.
+ */
+#define MOCK_TIMEOUT_METHOD1(Method, ...) \
+ MOCK_METHOD1(egmock_##Method, __VA_ARGS__); \
+ EGMOCK_TIMEOUT_METHOD_DEF_(Method); \
+ virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \
+ EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1); \
+ }
+
+/**
+ * Gmock MOCK_METHOD2 timeout-capable extension.
+ */
+#define MOCK_TIMEOUT_METHOD2(Method, ...) \
+ MOCK_METHOD2(egmock_##Method, __VA_ARGS__); \
+ EGMOCK_TIMEOUT_METHOD_DEF_(Method); \
+ virtual GMOCK_RESULT_(, __VA_ARGS__) \
+ Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \
+ EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2); \
+ }
+
+/**
+ * Gmock EXPECT_CALL timeout-capable extension.
+ *
+ * It has slightly different syntax from the original macro, to make method name accessible.
+ * So, instead of typing
+ * EXPECT_CALL(account, charge(100, Currency::USD));
+ * you need to inline arguments
+ * EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD);
+ */
+#define EXPECT_TIMEOUT_CALL(obj, Method, ...) \
+ (obj).egmock_called_##Method = false; \
+ EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__))
+
+/**
+ * Waits for an earlier EXPECT_TIMEOUT_CALL to execute.
+ *
+ * It does not fully support special constraints of the EXPECT_CALL clause, just proceeds when the
+ * first call to a given method comes. For example, in the following code:
+ * EXPECT_TIMEOUT_CALL(account, charge, 100, _);
+ * account.charge(50, Currency::USD);
+ * EXPECT_TIMEOUT_CALL_WAIT(account, charge, 500ms);
+ * the wait clause will just continue, as the charge method was called.
+ *
+ * @param obj object for a call
+ * @param Method the method to wait for
+ * @param timeout the maximum time for waiting
+ */
+#define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout) \
+ { \
+ std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method); \
+ if (!(obj).egmock_called_##Method) { \
+ auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \
+ EXPECT_EQ(std::cv_status::no_timeout, status); \
+ } \
+ }
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index 1a349d6..e0b31f0 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -26,6 +26,9 @@
static_libs: [
"android.hardware.camera.common@1.0-helper"
],
+ header_libs: [
+ "media_plugin_headers",
+ ],
include_dirs: [
"frameworks/native/include/media/openmax"
],
diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp
index 953aa37..6da5cc4 100644
--- a/cas/1.0/default/Android.bp
+++ b/cas/1.0/default/Android.bp
@@ -32,4 +32,8 @@
"liblog",
"libutils",
],
+ header_libs: [
+ "libstagefright_foundation_headers",
+ "media_plugin_headers",
+ ],
}
diff --git a/current.txt b/current.txt
index a5b5930..c6a1e2d 100644
--- a/current.txt
+++ b/current.txt
@@ -196,7 +196,6 @@
# HALs released in Android O MR1
-37a00ee36a2e38f9ff87cf71a37a49c13fe194fbed123c6b05c69fc76071f5c9 android.hardware.configstore@1.1::ISurfaceFlingerConfigs
4b65763663a94a3920134011691f8fbb42ccb7b7795589efddc049a9106047d6 android.hardware.oemlock@1.0::IOemLock
e02cd3722cb5e8fa51179f5defacb4f7866f903c9c7c51dc01a3148473a71525 android.hardware.oemlock@1.0::types
9f69e783fa2c482d90b2f799ddd33378a92d22a261983df6b492358e01f4d791 android.hardware.power@1.1::IPower
diff --git a/tests/Android.bp b/tests/Android.bp
index ddf300b..9583bfd 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -20,6 +20,8 @@
"memory/1.0/default",
"msgq/1.0",
"msgq/1.0/default",
+ "multithread/1.0",
+ "multithread/1.0/default",
"pointer/1.0",
"pointer/1.0/default",
"pointer/1.0/default/lib",
diff --git a/tests/multithread/1.0/Android.bp b/tests/multithread/1.0/Android.bp
new file mode 100644
index 0000000..c3782a0
--- /dev/null
+++ b/tests/multithread/1.0/Android.bp
@@ -0,0 +1,59 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.tests.multithread@1.0_hal",
+ srcs: [
+ "IMultithread.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tests.multithread@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.multithread@1.0",
+ srcs: [
+ ":android.hardware.tests.multithread@1.0_hal",
+ ],
+ out: [
+ "android/hardware/tests/multithread/1.0/MultithreadAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tests.multithread@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.multithread@1.0",
+ srcs: [
+ ":android.hardware.tests.multithread@1.0_hal",
+ ],
+ out: [
+ "android/hardware/tests/multithread/1.0/IMultithread.h",
+ "android/hardware/tests/multithread/1.0/IHwMultithread.h",
+ "android/hardware/tests/multithread/1.0/BnHwMultithread.h",
+ "android/hardware/tests/multithread/1.0/BpHwMultithread.h",
+ "android/hardware/tests/multithread/1.0/BsMultithread.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.tests.multithread@1.0",
+ defaults: ["hidl-module-defaults"],
+ generated_sources: ["android.hardware.tests.multithread@1.0_genc++"],
+ generated_headers: ["android.hardware.tests.multithread@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.tests.multithread@1.0_genc++_headers"],
+ vendor_available: true,
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ ],
+}
diff --git a/tests/multithread/1.0/Android.mk b/tests/multithread/1.0/Android.mk
new file mode 100644
index 0000000..f63381d
--- /dev/null
+++ b/tests/multithread/1.0/Android.mk
@@ -0,0 +1,76 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tests.multithread-V1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base-V1.0-java \
+
+
+#
+# Build IMultithread.hal
+#
+GEN := $(intermediates)/android/hardware/tests/multithread/V1_0/IMultithread.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMultithread.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.multithread@1.0::IMultithread
+
+$(GEN): $(LOCAL_PATH)/IMultithread.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tests.multithread-V1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base-V1.0-java-static \
+
+
+#
+# Build IMultithread.hal
+#
+GEN := $(intermediates)/android/hardware/tests/multithread/V1_0/IMultithread.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMultithread.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.multithread@1.0::IMultithread
+
+$(GEN): $(LOCAL_PATH)/IMultithread.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/multithread/1.0/IMultithread.hal b/tests/multithread/1.0/IMultithread.hal
new file mode 100644
index 0000000..19dc4f6
--- /dev/null
+++ b/tests/multithread/1.0/IMultithread.hal
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tests.multithread@1.0;
+
+/**
+ * IMultithread tests configureRpcThreadpool
+ *
+ * Makes calls finish only when specific number of them are running in parallel
+ */
+interface IMultithread {
+ /**
+ * Sets up controller
+ * Must be called for each test
+ * @param maxThreads arg passed to configureRpcThreadpool
+ * Could not be decremented by future calls
+ * @param numThreads number of calls in parallel to finish
+ */
+ setNumThreads(int32_t maxThreads, int32_t numThreads);
+
+ /**
+ * Makes a new call
+ * @return noTimeout numThreads appeared in parallel before timeout
+ * Shall return the same value for one setNumThreads call
+ */
+ runNewThread() generates (bool noTimeout);
+};
diff --git a/tests/multithread/1.0/default/Android.bp b/tests/multithread/1.0/default/Android.bp
new file mode 100644
index 0000000..72b9e91
--- /dev/null
+++ b/tests/multithread/1.0/default/Android.bp
@@ -0,0 +1,17 @@
+cc_library_shared {
+ name: "android.hardware.tests.multithread@1.0-impl",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ proprietary: true,
+ srcs: [
+ "Multithread.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.tests.multithread@1.0",
+ ],
+}
diff --git a/tests/multithread/1.0/default/Multithread.cpp b/tests/multithread/1.0/default/Multithread.cpp
new file mode 100644
index 0000000..1fb267c
--- /dev/null
+++ b/tests/multithread/1.0/default/Multithread.cpp
@@ -0,0 +1,63 @@
+#define LOG_TAG "hidl_test"
+
+#include <android-base/logging.h>
+#include "Multithread.h"
+#include <inttypes.h>
+#include <thread>
+
+#include <hidl/HidlTransportSupport.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace multithread {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::tests::multithread::V1_0::IMultithread follow.
+Return<void> Multithread::setNumThreads(int32_t maxThreads, int32_t numThreads) {
+ LOG(INFO) << "SERVER(Multithread) setNumThreads("
+ << maxThreads << ", " << numThreads << ")";
+
+ LOG(INFO) << "SERVER(Multithread) call configureRpcThreadpool("
+ << maxThreads << ")";
+ ::android::hardware::configureRpcThreadpool(maxThreads, /*willjoin*/ false);
+
+ mNumThreads = numThreads;
+ mNoTimeout = true;
+
+ return Void();
+}
+
+Return<bool> Multithread::runNewThread() {
+ LOG(INFO) << "SERVER(Multithread) runNewThread()";
+
+ std::unique_lock<std::mutex> lk(mCvMutex);
+ --mNumThreads;
+
+ LOG(INFO) << "SERVER(Multithread) runNewThread()";
+ LOG(INFO) << mNumThreads << "threads left";
+
+ mCv.notify_all();
+ bool noTimeout = mCv.wait_for(lk, kTimeoutDuration,
+ [&] { return mNumThreads <= 0 || !mNoTimeout; });
+
+ if (!noTimeout) {
+ mNoTimeout = false;
+ mCv.notify_all();
+ }
+ return mNoTimeout;
+}
+
+IMultithread* HIDL_FETCH_IMultithread(const char* /* name */) {
+ return new Multithread();
+}
+
+decltype(Multithread::kTimeoutDuration) Multithread::kTimeoutDuration;
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace multithread
+} // namespace tests
+} // namespace hardware
+} // namespace android
diff --git a/tests/multithread/1.0/default/Multithread.h b/tests/multithread/1.0/default/Multithread.h
new file mode 100644
index 0000000..0d4a007
--- /dev/null
+++ b/tests/multithread/1.0/default/Multithread.h
@@ -0,0 +1,48 @@
+#ifndef ANDROID_HARDWARE_TESTS_MULTITHREAD_V1_0_MULTITHREAD_H
+#define ANDROID_HARDWARE_TESTS_MULTITHREAD_V1_0_MULTITHREAD_H
+
+#include <android/hardware/tests/multithread/1.0/IMultithread.h>
+#include <hidl/Status.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace multithread {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tests::multithread::V1_0::IMultithread;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using namespace std::chrono_literals;
+
+struct Multithread : public IMultithread {
+ // Methods from ::android::hardware::tests::multithread::V1_0::IMultithread follow.
+ virtual Return<void> setNumThreads(int32_t maxThreads, int32_t numThreads) override;
+ virtual Return<bool> runNewThread() override;
+
+ private:
+ int32_t mNumThreads;
+ bool mNoTimeout;
+
+ std::condition_variable mCv;
+ std::mutex mCvMutex;
+
+ static constexpr auto kTimeoutDuration = 100ms;
+};
+
+extern "C" IMultithread* HIDL_FETCH_IMultithread(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace multithread
+} // namespace tests
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TESTS_MULTITHREAD_V1_0_MULTITHREAD_H
diff --git a/wifi/1.1/default/hidl_struct_util.cpp b/wifi/1.1/default/hidl_struct_util.cpp
index e40a7d8..a413cbb 100644
--- a/wifi/1.1/default/hidl_struct_util.cpp
+++ b/wifi/1.1/default/hidl_struct_util.cpp
@@ -17,6 +17,9 @@
#include <android-base/logging.h>
#include <utils/SystemClock.h>
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/1.1/IWifiChip.h>
+
#include "hidl_struct_util.h"
namespace android {
@@ -66,6 +69,17 @@
return {};
}
+V1_1::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+ uint32_t feature) {
+ using HidlChipCaps = V1_1::IWifiChip::ChipCapabilityMask;
+ switch (feature) {
+ case WIFI_FEATURE_SET_TX_POWER_LIMIT:
+ return HidlChipCaps::SET_TX_POWER_LIMIT;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
IWifiStaIface::StaIfaceCapabilityMask
convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
@@ -102,7 +116,9 @@
}
bool convertLegacyFeaturesToHidlChipCapabilities(
- uint32_t legacy_logger_feature_set, uint32_t* hidl_caps) {
+ uint32_t legacy_feature_set,
+ uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps) {
if (!hidl_caps) {
return false;
}
@@ -117,6 +133,11 @@
*hidl_caps |= convertLegacyLoggerFeatureToHidlChipCapability(feature);
}
}
+ for (const auto feature : {WIFI_FEATURE_SET_TX_POWER_LIMIT}) {
+ if (feature & legacy_feature_set) {
+ *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
+ }
+ }
// There are no flags for these 3 in the legacy feature set. Adding them to
// the set because all the current devices support it.
*hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
@@ -241,7 +262,6 @@
return false;
}
*hidl_caps = {};
- *hidl_caps = 0;
using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
if (feature & legacy_logger_feature_set) {
diff --git a/wifi/1.1/default/hidl_struct_util.h b/wifi/1.1/default/hidl_struct_util.h
index a04f636..7a840f9 100644
--- a/wifi/1.1/default/hidl_struct_util.h
+++ b/wifi/1.1/default/hidl_struct_util.h
@@ -19,7 +19,7 @@
#include <vector>
-#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.0/types.h>
#include "wifi_legacy_hal.h"
@@ -39,7 +39,9 @@
// Chip conversion methods.
bool convertLegacyFeaturesToHidlChipCapabilities(
- uint32_t legacy_logger_feature_set, uint32_t* hidl_caps);
+ uint32_t legacy_feature_set,
+ uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps);
bool convertLegacyDebugRingBufferStatusToHidl(
const legacy_hal::wifi_ring_buffer_status& legacy_status,
WifiDebugRingBufferStatus* hidl_status);
diff --git a/wifi/1.1/default/wifi_chip.cpp b/wifi/1.1/default/wifi_chip.cpp
index 87985c0..2beac26 100644
--- a/wifi/1.1/default/wifi_chip.cpp
+++ b/wifi/1.1/default/wifi_chip.cpp
@@ -387,7 +387,13 @@
std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
+ uint32_t legacy_feature_set;
uint32_t legacy_logger_feature_set;
+ std::tie(legacy_status, legacy_feature_set) =
+ legacy_hal_.lock()->getSupportedFeatureSet();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), 0};
+ }
std::tie(legacy_status, legacy_logger_feature_set) =
legacy_hal_.lock()->getLoggerSupportedFeatureSet();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
@@ -395,7 +401,7 @@
}
uint32_t hidl_caps;
if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
- legacy_logger_feature_set, &hidl_caps)) {
+ legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
}
return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
@@ -818,16 +824,14 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-WifiStatus WifiChip::setTxPowerLimitInternal(int32_t /* powerInDbm */) {
- // TODO(b/62437848): Implement this method once we are ready with the
- // header changes in legacy HAL.
- return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+WifiStatus WifiChip::setTxPowerLimitInternal(int32_t powerInDbm) {
+ auto legacy_status = legacy_hal_.lock()->setTxPowerLimit(powerInDbm);
+ return createWifiStatusFromLegacyError(legacy_status);
}
WifiStatus WifiChip::resetTxPowerLimitInternal() {
- // TODO(b/62437848): Implement this method once we are ready with the
- // header changes in legacy HAL.
- return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+ auto legacy_status = legacy_hal_.lock()->resetTxPowerLimit();
+ return createWifiStatusFromLegacyError(legacy_status);
}
WifiStatus WifiChip::handleChipConfiguration(ChipModeId mode_id) {
diff --git a/wifi/1.1/default/wifi_legacy_hal.cpp b/wifi/1.1/default/wifi_legacy_hal.cpp
index c1e1cd3..052aafb 100644
--- a/wifi/1.1/default/wifi_legacy_hal.cpp
+++ b/wifi/1.1/default/wifi_legacy_hal.cpp
@@ -752,6 +752,15 @@
oui_internal.data());
}
+wifi_error WifiLegacyHal::setTxPowerLimit(int32_t tx_level_dbm) {
+ return global_func_table_.wifi_set_tx_power_limit(wlan_interface_handle_,
+ tx_level_dbm);
+}
+
+wifi_error WifiLegacyHal::resetTxPowerLimit() {
+ return global_func_table_.wifi_reset_tx_power_limit(wlan_interface_handle_);
+}
+
std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet() {
uint32_t supported_features;
wifi_error status = global_func_table_.wifi_get_logger_supported_feature_set(
diff --git a/wifi/1.1/default/wifi_legacy_hal.h b/wifi/1.1/default/wifi_legacy_hal.h
index fef7999..8d9144d 100644
--- a/wifi/1.1/default/wifi_legacy_hal.h
+++ b/wifi/1.1/default/wifi_legacy_hal.h
@@ -205,6 +205,8 @@
uint32_t period_in_ms);
wifi_error stopSendingOffloadedPacket(uint32_t cmd_id);
wifi_error setScanningMacOui(const std::array<uint8_t, 3>& oui);
+ wifi_error setTxPowerLimit(int32_t tx_level_dbm);
+ wifi_error resetTxPowerLimit();
// Logger/debug functions.
std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet();
wifi_error startPktFateMonitoring();
diff --git a/wifi/1.1/default/wifi_legacy_hal_stubs.cpp b/wifi/1.1/default/wifi_legacy_hal_stubs.cpp
index a5a5d48..24ed548 100644
--- a/wifi/1.1/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.1/default/wifi_legacy_hal_stubs.cpp
@@ -132,6 +132,8 @@
populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
populateStubFor(&hal_fn->wifi_configure_roaming);
+ populateStubFor(&hal_fn->wifi_set_tx_power_limit);
+ populateStubFor(&hal_fn->wifi_reset_tx_power_limit);
return true;
}
} // namespace legacy_hal