Merge changes I017d3528,Ie5444041,Iff873784,I1049176a,I8575df02, ...
* changes:
wifi(implementation): Load wifi driver on IWifi.start()
wifi(implementation): Different names for concurrent ifaces
wifi(implementation): Add iface combo for 2018
wifi(implementation): Unit tests for V1 & V2 iface combos
wifi(implementation): Add unit test framework
wifi(implementation): Support multiple ifaces of same type
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
index c016c16..27ae4e9 100644
--- a/broadcastradio/1.1/vts/functional/Android.bp
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -22,7 +22,7 @@
"android.hardware.broadcastradio@1.0",
"android.hardware.broadcastradio@1.1",
"android.hardware.broadcastradio@1.2", // common-utils-lib dependency
- "android.hardware.broadcastradio@common-utils-lib",
+ "android.hardware.broadcastradio@common-utils-1x-lib",
"android.hardware.broadcastradio@vts-utils-lib",
"libgmock",
],
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index bb490c9..823d14c 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -17,15 +17,16 @@
#define LOG_TAG "broadcastradio.vts"
#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
#include <android/hardware/broadcastradio/1.1/ITuner.h>
#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
#include <android/hardware/broadcastradio/1.1/types.h>
-#include <android-base/logging.h>
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <broadcastradio-vts-utils/call-barrier.h>
#include <broadcastradio-vts-utils/mock-timeout.h>
+#include <broadcastradio-vts-utils/pointer-utils.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <gmock/gmock.h>
@@ -56,8 +57,7 @@
using V1_0::MetadataKey;
using V1_0::MetadataType;
-using std::chrono::steady_clock;
-using std::this_thread::sleep_for;
+using broadcastradio::vts::clearAndWait;
static constexpr auto kConfigTimeout = 10s;
static constexpr auto kConnectModuleTimeout = 1s;
@@ -115,27 +115,6 @@
hidl_vec<BandConfig> mBands;
};
-/**
- * Clears strong pointer and waits until the object gets destroyed.
- *
- * @param ptr The pointer to get cleared.
- * @param timeout Time to wait for other references.
- */
-template <typename T>
-static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) {
- wp<T> wptr = ptr;
- ptr.clear();
- auto limit = steady_clock::now() + timeout;
- while (wptr.promote() != nullptr) {
- constexpr auto step = 10ms;
- if (steady_clock::now() + step > limit) {
- FAIL() << "Pointer was not released within timeout";
- break;
- }
- sleep_for(step);
- }
-}
-
void BroadcastRadioHalTest::SetUp() {
radioClass = GetParam();
diff --git a/broadcastradio/1.2/default/Android.bp b/broadcastradio/1.2/default/Android.bp
index e42cb1e..bd4be77 100644
--- a/broadcastradio/1.2/default/Android.bp
+++ b/broadcastradio/1.2/default/Android.bp
@@ -33,6 +33,7 @@
"service.cpp"
],
static_libs: [
+ "android.hardware.broadcastradio@common-utils-1x-lib",
"android.hardware.broadcastradio@common-utils-lib",
],
shared_libs: [
diff --git a/broadcastradio/1.2/default/Tuner.cpp b/broadcastradio/1.2/default/Tuner.cpp
index 6209dc1..f589332 100644
--- a/broadcastradio/1.2/default/Tuner.cpp
+++ b/broadcastradio/1.2/default/Tuner.cpp
@@ -20,7 +20,7 @@
#include "BroadcastRadio.h"
#include "Tuner.h"
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <log/log.h>
namespace android {
diff --git a/broadcastradio/1.2/default/VirtualProgram.cpp b/broadcastradio/1.2/default/VirtualProgram.cpp
index 3284bd1..3594f64 100644
--- a/broadcastradio/1.2/default/VirtualProgram.cpp
+++ b/broadcastradio/1.2/default/VirtualProgram.cpp
@@ -15,7 +15,7 @@
*/
#include "VirtualProgram.h"
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include "resources.h"
@@ -83,13 +83,6 @@
if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value;
- // A little exception for HD Radio subchannel - we check secondary ID too.
- if (utils::hasId(l, IdentifierType::HD_SUBCHANNEL) &&
- utils::hasId(r, IdentifierType::HD_SUBCHANNEL)) {
- return utils::getId(l, IdentifierType::HD_SUBCHANNEL) <
- utils::getId(r, IdentifierType::HD_SUBCHANNEL);
- }
-
return false;
}
diff --git a/broadcastradio/1.2/default/VirtualProgram.h b/broadcastradio/1.2/default/VirtualProgram.h
index 5342c84..c0b20f0 100644
--- a/broadcastradio/1.2/default/VirtualProgram.h
+++ b/broadcastradio/1.2/default/VirtualProgram.h
@@ -17,7 +17,7 @@
#define ANDROID_HARDWARE_BROADCASTRADIO_V1_2_VIRTUALPROGRAM_H
#include <android/hardware/broadcastradio/1.2/types.h>
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
namespace android {
namespace hardware {
diff --git a/broadcastradio/1.2/default/VirtualRadio.cpp b/broadcastradio/1.2/default/VirtualRadio.cpp
index 867726d..8988080 100644
--- a/broadcastradio/1.2/default/VirtualRadio.cpp
+++ b/broadcastradio/1.2/default/VirtualRadio.cpp
@@ -18,7 +18,7 @@
#include "VirtualRadio.h"
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <log/log.h>
namespace android {
diff --git a/broadcastradio/1.2/vts/functional/Android.bp b/broadcastradio/1.2/vts/functional/Android.bp
index 12da14e..fd1c254 100644
--- a/broadcastradio/1.2/vts/functional/Android.bp
+++ b/broadcastradio/1.2/vts/functional/Android.bp
@@ -22,7 +22,6 @@
"android.hardware.broadcastradio@1.0",
"android.hardware.broadcastradio@1.1",
"android.hardware.broadcastradio@1.2",
- "android.hardware.broadcastradio@common-utils-lib",
"android.hardware.broadcastradio@vts-utils-lib",
"libgmock",
],
diff --git a/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp b/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
index f3552a8..085206b 100644
--- a/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
+++ b/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
@@ -17,15 +17,15 @@
#define LOG_TAG "broadcastradio.vts"
#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
#include <android/hardware/broadcastradio/1.2/ITuner.h>
#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
#include <android/hardware/broadcastradio/1.2/types.h>
-#include <android-base/logging.h>
-#include <broadcastradio-utils/Utils.h>
#include <broadcastradio-vts-utils/call-barrier.h>
#include <broadcastradio-vts-utils/mock-timeout.h>
+#include <broadcastradio-vts-utils/pointer-utils.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <gmock/gmock.h>
@@ -61,8 +61,7 @@
using V1_1::ProgramSelector;
using V1_1::Properties;
-using std::chrono::steady_clock;
-using std::this_thread::sleep_for;
+using broadcastradio::vts::clearAndWait;
static constexpr auto kConfigTimeout = 10s;
static constexpr auto kConnectModuleTimeout = 1s;
@@ -111,27 +110,6 @@
hidl_vec<BandConfig> mBands;
};
-/**
- * Clears strong pointer and waits until the object gets destroyed.
- *
- * @param ptr The pointer to get cleared.
- * @param timeout Time to wait for other references.
- */
-template <typename T>
-static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) {
- wp<T> wptr = ptr;
- ptr.clear();
- auto limit = steady_clock::now() + timeout;
- while (wptr.promote() != nullptr) {
- constexpr auto step = 10ms;
- if (steady_clock::now() + step > limit) {
- FAIL() << "Pointer was not released within timeout";
- break;
- }
- sleep_for(step);
- }
-}
-
void BroadcastRadioHalTest::SetUp() {
radioClass = GetParam();
diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp
new file mode 100644
index 0000000..6d4effb
--- /dev/null
+++ b/broadcastradio/2.0/default/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.hardware.broadcastradio@2.0-service",
+ init_rc: ["android.hardware.broadcastradio@2.0-service.rc"],
+ vendor: true,
+ relative_install_path: "hw",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "BroadcastRadio.cpp",
+ "TunerSession.cpp",
+ "VirtualProgram.cpp",
+ "VirtualRadio.cpp",
+ "service.cpp"
+ ],
+ static_libs: [
+ "android.hardware.broadcastradio@common-utils-2x-lib",
+ "android.hardware.broadcastradio@common-utils-lib",
+ ],
+ shared_libs: [
+ "android.hardware.broadcastradio@2.0",
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp
new file mode 100644
index 0000000..5ab517d
--- /dev/null
+++ b/broadcastradio/2.0/default/BroadcastRadio.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.module"
+#define LOG_NDEBUG 0
+
+#include "BroadcastRadio.h"
+
+#include <log/log.h>
+
+#include "resources.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using std::lock_guard;
+using std::map;
+using std::mutex;
+using std::vector;
+
+static Properties initProperties(const VirtualRadio& virtualRadio) {
+ Properties prop = {};
+
+ prop.maker = "Google";
+ prop.product = virtualRadio.getName();
+ prop.supportedIdentifierTypes = hidl_vec<uint32_t>({
+ static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY),
+ static_cast<uint32_t>(IdentifierType::RDS_PI),
+ static_cast<uint32_t>(IdentifierType::HD_STATION_ID_EXT),
+ });
+ prop.vendorInfo = hidl_vec<VendorKeyValue>({
+ {"com.google.dummy", "dummy"},
+ });
+
+ return prop;
+}
+
+BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio)
+ : mVirtualRadio(virtualRadio), mProperties(initProperties(virtualRadio)) {}
+
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
+ ALOGV("%s", __func__);
+ _hidl_cb(mProperties);
+ return {};
+}
+
+Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback,
+ openSession_cb _hidl_cb) {
+ ALOGV("%s", __func__);
+ lock_guard<mutex> lk(mMut);
+
+ auto oldSession = mSession.promote();
+ if (oldSession != nullptr) {
+ ALOGI("Closing previously opened tuner");
+ oldSession->close();
+ mSession = nullptr;
+ }
+
+ sp<TunerSession> newSession = new TunerSession(*this, callback);
+ mSession = newSession;
+
+ _hidl_cb(Result::OK, newSession);
+ return {};
+}
+
+Return<void> BroadcastRadio::getImage(uint32_t id, getImage_cb _hidl_cb) {
+ ALOGV("%s(%x)", __func__, id);
+
+ if (id == resources::demoPngId) {
+ _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
+ return {};
+ }
+
+ ALOGI("Image %x doesn't exists", id);
+ _hidl_cb({});
+ return {};
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/2.0/default/BroadcastRadio.h b/broadcastradio/2.0/default/BroadcastRadio.h
new file mode 100644
index 0000000..fcf0615
--- /dev/null
+++ b/broadcastradio/2.0/default/BroadcastRadio.h
@@ -0,0 +1,52 @@
+/*
+ * 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_V2_0_BROADCASTRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_BROADCASTRADIO_H
+
+#include "TunerSession.h"
+
+#include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+struct BroadcastRadio : public IBroadcastRadio {
+ BroadcastRadio(const VirtualRadio& virtualRadio);
+
+ // V2_0::IBroadcastRadio methods
+ Return<void> getProperties(getProperties_cb _hidl_cb) override;
+ Return<void> openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) override;
+ Return<void> getImage(uint32_t id, getImage_cb _hidl_cb);
+
+ std::reference_wrapper<const VirtualRadio> mVirtualRadio;
+ Properties mProperties;
+
+ private:
+ std::mutex mMut;
+ wp<TunerSession> mSession;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_BROADCASTRADIO_H
diff --git a/broadcastradio/common/utils/OWNERS b/broadcastradio/2.0/default/OWNERS
similarity index 100%
copy from broadcastradio/common/utils/OWNERS
copy to broadcastradio/2.0/default/OWNERS
diff --git a/broadcastradio/2.0/default/TunerSession.cpp b/broadcastradio/2.0/default/TunerSession.cpp
new file mode 100644
index 0000000..f0b98b8
--- /dev/null
+++ b/broadcastradio/2.0/default/TunerSession.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BcRadioDef.tuner"
+#define LOG_NDEBUG 0
+
+#include "TunerSession.h"
+
+#include "BroadcastRadio.h"
+
+#include <broadcastradio-utils-2x/Utils.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using namespace std::chrono_literals;
+
+using utils::tunesTo;
+
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::sort;
+using std::vector;
+
+namespace delay {
+
+static constexpr auto scan = 200ms;
+static constexpr auto step = 100ms;
+static constexpr auto tune = 150ms;
+
+} // namespace delay
+
+TunerSession::TunerSession(BroadcastRadio& module, const sp<ITunerCallback>& callback)
+ : mCallback(callback), mModule(module) {}
+
+// makes ProgramInfo that points to no program
+static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
+ ProgramInfo info = {};
+ info.selector = selector;
+ return info;
+}
+
+void TunerSession::tuneInternalLocked(const ProgramSelector& sel) {
+ VirtualProgram virtualProgram;
+ ProgramInfo programInfo;
+ if (virtualRadio().getProgram(sel, virtualProgram)) {
+ mCurrentProgram = virtualProgram.selector;
+ programInfo = virtualProgram;
+ } else {
+ mCurrentProgram = sel;
+ programInfo = makeDummyProgramInfo(sel);
+ }
+ mIsTuneCompleted = true;
+
+ mCallback->onCurrentProgramInfoChanged(programInfo);
+}
+
+const VirtualRadio& TunerSession::virtualRadio() const {
+ return mModule.get().mVirtualRadio;
+}
+
+Return<Result> TunerSession::tune(const ProgramSelector& sel) {
+ ALOGV("%s(%s)", __func__, toString(sel).c_str());
+ lock_guard<mutex> lk(mMut);
+ if (mIsClosed) return Result::INVALID_STATE;
+
+ if (!utils::isSupported(mModule.get().mProperties, sel)) {
+ ALOGW("Selector not supported");
+ return Result::NOT_SUPPORTED;
+ }
+
+ if (!utils::isValid(sel)) {
+ ALOGE("ProgramSelector is not valid");
+ return Result::INVALID_ARGUMENTS;
+ }
+
+ mIsTuneCompleted = false;
+ auto task = [this, sel]() {
+ lock_guard<mutex> lk(mMut);
+ tuneInternalLocked(sel);
+ };
+ mThread.schedule(task, delay::tune);
+
+ return Result::OK;
+}
+
+Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) {
+ ALOGV("%s", __func__);
+ lock_guard<mutex> lk(mMut);
+ if (mIsClosed) return Result::INVALID_STATE;
+
+ auto list = virtualRadio().getProgramList();
+
+ if (list.empty()) {
+ mIsTuneCompleted = false;
+ auto task = [this, directionUp]() {
+ ALOGI("Performing failed scan up=%d", directionUp);
+
+ mCallback->onTuneFailed(Result::TIMEOUT, {});
+ };
+ mThread.schedule(task, delay::scan);
+
+ return Result::OK;
+ }
+
+ // Not optimal (O(sort) instead of O(n)), but not a big deal here;
+ // also, it's likely that list is already sorted (so O(n) anyway).
+ sort(list.begin(), list.end());
+ auto current = mCurrentProgram;
+ auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
+ if (directionUp) {
+ if (found < list.end() - 1) {
+ if (tunesTo(current, found->selector)) found++;
+ } else {
+ found = list.begin();
+ }
+ } else {
+ if (found > list.begin() && found != list.end()) {
+ found--;
+ } else {
+ found = list.end() - 1;
+ }
+ }
+ auto tuneTo = found->selector;
+
+ mIsTuneCompleted = false;
+ auto task = [this, tuneTo, directionUp]() {
+ ALOGI("Performing scan up=%d", directionUp);
+
+ lock_guard<mutex> lk(mMut);
+ tuneInternalLocked(tuneTo);
+ };
+ mThread.schedule(task, delay::scan);
+
+ return Result::OK;
+}
+
+Return<Result> TunerSession::step(bool directionUp) {
+ ALOGV("%s", __func__);
+ lock_guard<mutex> lk(mMut);
+ if (mIsClosed) return Result::INVALID_STATE;
+
+ if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) {
+ ALOGE("Can't step in anything else than AM/FM");
+ return Result::NOT_SUPPORTED;
+ }
+
+ mIsTuneCompleted = false;
+
+ auto stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
+#if 0
+ // TODO(b/69958423): handle regions
+ if (directionUp) {
+ stepTo += mAmfmConfig.spacings[0];
+ } else {
+ stepTo -= mAmfmConfig.spacings[0];
+ }
+
+ if (stepTo > mAmfmConfig.upperLimit) stepTo = mAmfmConfig.lowerLimit;
+ if (stepTo < mAmfmConfig.lowerLimit) stepTo = mAmfmConfig.upperLimit;
+#else
+ if (directionUp) {
+ stepTo += 100;
+ } else {
+ stepTo -= 100;
+ }
+#endif
+
+ auto task = [this, stepTo]() {
+ ALOGI("Performing step to %s", std::to_string(stepTo).c_str());
+
+ lock_guard<mutex> lk(mMut);
+
+ tuneInternalLocked(utils::make_selector_amfm(stepTo));
+ };
+ mThread.schedule(task, delay::step);
+
+ return Result::OK;
+}
+
+Return<void> TunerSession::cancel() {
+ ALOGV("%s", __func__);
+ lock_guard<mutex> lk(mMut);
+ if (mIsClosed) return {};
+
+ mThread.cancelAll();
+ return {};
+}
+
+Return<void> TunerSession::setParameters(const hidl_vec<VendorKeyValue>& /* parameters */,
+ setParameters_cb _hidl_cb) {
+ ALOGV("%s", __func__);
+
+ _hidl_cb({});
+ return {};
+}
+
+Return<void> TunerSession::getParameters(const hidl_vec<hidl_string>& /* keys */,
+ getParameters_cb _hidl_cb) {
+ ALOGV("%s", __func__);
+
+ _hidl_cb({});
+ return {};
+}
+
+Return<void> TunerSession::close() {
+ ALOGV("%s", __func__);
+ lock_guard<mutex> lk(mMut);
+ if (mIsClosed) return {};
+
+ mIsClosed = true;
+ mThread.cancelAll();
+ return {};
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/2.0/default/TunerSession.h b/broadcastradio/2.0/default/TunerSession.h
new file mode 100644
index 0000000..08a7588
--- /dev/null
+++ b/broadcastradio/2.0/default/TunerSession.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_TUNER_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_TUNER_H
+
+#include "VirtualRadio.h"
+
+#include <android/hardware/broadcastradio/2.0/ITunerCallback.h>
+#include <android/hardware/broadcastradio/2.0/ITunerSession.h>
+#include <broadcastradio-utils/WorkerThread.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+struct BroadcastRadio;
+
+struct TunerSession : public ITunerSession {
+ TunerSession(BroadcastRadio& module, const sp<ITunerCallback>& callback);
+
+ // V2_0::ITunerSession methods
+ virtual Return<Result> tune(const ProgramSelector& program) override;
+ virtual Return<Result> scan(bool directionUp, bool skipSubChannel) override;
+ virtual Return<Result> step(bool directionUp) override;
+ virtual Return<void> cancel() override;
+ virtual Return<void> setParameters(const hidl_vec<VendorKeyValue>& parameters,
+ setParameters_cb _hidl_cb) override;
+ virtual Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+ getParameters_cb _hidl_cb) override;
+ virtual Return<void> close() override;
+
+ private:
+ std::mutex mMut;
+ WorkerThread mThread;
+ bool mIsClosed = false;
+
+ const sp<ITunerCallback> mCallback;
+
+ std::reference_wrapper<BroadcastRadio> mModule;
+ bool mIsTuneCompleted = false;
+ ProgramSelector mCurrentProgram = {};
+
+ void tuneInternalLocked(const ProgramSelector& sel);
+ const VirtualRadio& virtualRadio() const;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_TUNER_H
diff --git a/broadcastradio/2.0/default/VirtualProgram.cpp b/broadcastradio/2.0/default/VirtualProgram.cpp
new file mode 100644
index 0000000..1acd4d3
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualProgram.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "VirtualProgram.h"
+
+#include "resources.h"
+
+#include <broadcastradio-utils-2x/Utils.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using utils::getType;
+using utils::make_metadata;
+
+using std::vector;
+
+VirtualProgram::operator ProgramInfo() const {
+ ProgramInfo info = {};
+
+ info.selector = selector;
+
+ auto pType = getType(selector.primaryId);
+ auto isDigital = (pType != IdentifierType::AMFM_FREQUENCY && pType != IdentifierType::RDS_PI);
+
+ info.infoFlags |= ProgramInfoFlags::TUNED;
+ info.infoFlags |= ProgramInfoFlags::STEREO;
+ info.signalQuality = isDigital ? 100 : 80;
+
+ info.metadata = hidl_vec<Metadata>({
+ make_metadata(MetadataKey::RDS_PS, programName),
+ make_metadata(MetadataKey::SONG_TITLE, songTitle),
+ make_metadata(MetadataKey::SONG_ARTIST, songArtist),
+ make_metadata(MetadataKey::STATION_ICON, resources::demoPngId),
+ make_metadata(MetadataKey::ALBUM_ART, resources::demoPngId),
+ });
+
+ info.vendorInfo = hidl_vec<VendorKeyValue>({
+ {"com.google.dummy", "dummy"},
+ {"com.google.dummy.VirtualProgram", std::to_string(reinterpret_cast<uintptr_t>(this))},
+ });
+
+ return info;
+}
+
+bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
+ auto& l = lhs.selector;
+ auto& r = rhs.selector;
+
+ // Two programs with the same primaryId are considered the same.
+ if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
+ if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value;
+
+ return false;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/2.0/default/VirtualProgram.h b/broadcastradio/2.0/default/VirtualProgram.h
new file mode 100644
index 0000000..e1c4f75
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualProgram.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALPROGRAM_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALPROGRAM_H
+
+#include <android/hardware/broadcastradio/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+/**
+ * A radio program mock.
+ *
+ * This represents broadcast waves flying over the air,
+ * not an entry for a captured station in the radio tuner memory.
+ */
+struct VirtualProgram {
+ ProgramSelector selector;
+
+ std::string programName = "";
+ std::string songArtist = "";
+ std::string songTitle = "";
+
+ operator ProgramInfo() const;
+
+ /**
+ * Defines order on how virtual programs appear on the "air" with
+ * ITunerSession::scan operation.
+ *
+ * It's for default implementation purposes, may not be complete or correct.
+ */
+ friend bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALPROGRAM_H
diff --git a/broadcastradio/2.0/default/VirtualRadio.cpp b/broadcastradio/2.0/default/VirtualRadio.cpp
new file mode 100644
index 0000000..f601d41
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualRadio.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.VirtualRadio"
+//#define LOG_NDEBUG 0
+
+#include "VirtualRadio.h"
+
+#include <broadcastradio-utils-2x/Utils.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::vector;
+using utils::make_selector_amfm;
+
+VirtualRadio gAmFmRadio(
+ "AM/FM radio mock",
+ {
+ {make_selector_amfm(94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
+ {make_selector_amfm(96500), "KOIT", "Celine Dion", "All By Myself"},
+ {make_selector_amfm(97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+ {make_selector_amfm(99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+ {make_selector_amfm(101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
+ {make_selector_amfm(103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
+ {make_selector_amfm(106100), "106 KMEL", "Drake", "Marvins Room"},
+ });
+
+VirtualRadio::VirtualRadio(const std::string& name, const vector<VirtualProgram>& initialList)
+ : mName(name), mPrograms(initialList) {}
+
+std::string VirtualRadio::getName() const {
+ return mName;
+}
+
+vector<VirtualProgram> VirtualRadio::getProgramList() const {
+ lock_guard<mutex> lk(mMut);
+ return mPrograms;
+}
+
+bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram& programOut) const {
+ lock_guard<mutex> lk(mMut);
+ for (auto&& program : mPrograms) {
+ if (utils::tunesTo(selector, program.selector)) {
+ programOut = program;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/2.0/default/VirtualRadio.h b/broadcastradio/2.0/default/VirtualRadio.h
new file mode 100644
index 0000000..9c07816
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualRadio.h
@@ -0,0 +1,61 @@
+/*
+ * 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_V2_0_VIRTUALRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALRADIO_H
+
+#include "VirtualProgram.h"
+
+#include <mutex>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+/**
+ * A radio frequency space mock.
+ *
+ * This represents all broadcast waves in the air for a given radio technology,
+ * not a captured station list in the radio tuner memory.
+ *
+ * It's meant to abstract out radio content from default tuner implementation.
+ */
+class VirtualRadio {
+ public:
+ VirtualRadio(const std::string& name, const std::vector<VirtualProgram>& initialList);
+
+ std::string getName() const;
+ std::vector<VirtualProgram> getProgramList() const;
+ bool getProgram(const ProgramSelector& selector, VirtualProgram& program) const;
+
+ private:
+ mutable std::mutex mMut;
+ std::string mName;
+ std::vector<VirtualProgram> mPrograms;
+};
+
+/** AM/FM virtual radio space. */
+extern VirtualRadio gAmFmRadio;
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALRADIO_H
diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
new file mode 100644
index 0000000..7d68b6c
--- /dev/null
+++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
@@ -0,0 +1,4 @@
+service broadcastradio-hal2 /vendor/bin/hw/android.hardware.broadcastradio@2.0-service
+ class hal
+ user audioserver
+ group audio
diff --git a/broadcastradio/2.0/default/resources.h b/broadcastradio/2.0/default/resources.h
new file mode 100644
index 0000000..97360dd
--- /dev/null
+++ b/broadcastradio/2.0/default/resources.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_RESOURCES_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_RESOURCES_H
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+namespace resources {
+
+constexpr int32_t demoPngId = 123456;
+constexpr uint8_t demoPng[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
+ 0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x08, 0x02, 0x00, 0x00, 0x00, 0x25,
+ 0x0b, 0xe6, 0x89, 0x00, 0x00, 0x00, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9,
+ 0xc1, 0x09, 0x00, 0x30, 0x08, 0x04, 0xc1, 0x33, 0xfd, 0xf7, 0x6c, 0x6a, 0xc8, 0x23, 0x04,
+ 0xc9, 0x6c, 0x01, 0xc2, 0x20, 0xbe, 0x4c, 0x86, 0x57, 0x49, 0xba, 0xfb, 0xd6, 0xf4, 0xba,
+ 0x3e, 0x7f, 0x4d, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x00, 0xbd, 0xce, 0x7f,
+ 0xc0, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xb8, 0x0d, 0x32, 0xd4, 0x0c, 0x77, 0xbd,
+ 0xfb, 0xc1, 0xce, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+
+} // namespace resources
+} // namespace implementation
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_RESOURCES_H
diff --git a/broadcastradio/2.0/default/service.cpp b/broadcastradio/2.0/default/service.cpp
new file mode 100644
index 0000000..7e677a1
--- /dev/null
+++ b/broadcastradio/2.0/default/service.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.service"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "BroadcastRadio.h"
+#include "VirtualRadio.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::broadcastradio::V2_0::implementation::BroadcastRadio;
+using android::hardware::broadcastradio::V2_0::implementation::gAmFmRadio;
+
+int main(int /* argc */, char** /* argv */) {
+ configureRpcThreadpool(4, true);
+
+ BroadcastRadio broadcastRadio(gAmFmRadio);
+ auto status = broadcastRadio.registerAsService();
+ CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation";
+
+ joinRpcThreadpool();
+ return 1; // joinRpcThreadpool shouldn't exit
+}
diff --git a/broadcastradio/common/tests/OWNERS b/broadcastradio/2.0/vts/OWNERS
similarity index 100%
rename from broadcastradio/common/tests/OWNERS
rename to broadcastradio/2.0/vts/OWNERS
diff --git a/broadcastradio/2.0/vts/functional/Android.bp b/broadcastradio/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..6017b15
--- /dev/null
+++ b/broadcastradio/2.0/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalBroadcastradioV2_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBroadcastradioV2_0TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.broadcastradio@2.0",
+ "android.hardware.broadcastradio@common-utils-2x-lib",
+ "android.hardware.broadcastradio@vts-utils-lib",
+ "android.hardware.broadcastradio@vts-utils-lib",
+ "libgmock",
+ ],
+}
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
new file mode 100644
index 0000000..a12afd6
--- /dev/null
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BcRadio.vts"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/2.0/ITunerCallback.h>
+#include <android/hardware/broadcastradio/2.0/ITunerSession.h>
+#include <android/hardware/broadcastradio/2.0/types.h>
+#include <broadcastradio-utils-2x/Utils.h>
+#include <broadcastradio-vts-utils/call-barrier.h>
+#include <broadcastradio-vts-utils/mock-timeout.h>
+#include <broadcastradio-vts-utils/pointer-utils.h>
+#include <gmock/gmock.h>
+
+#include <chrono>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace vts {
+
+using namespace std::chrono_literals;
+
+using std::vector;
+using testing::_;
+using testing::AnyNumber;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Invoke;
+using testing::SaveArg;
+
+using broadcastradio::vts::CallBarrier;
+using broadcastradio::vts::clearAndWait;
+using utils::make_identifier;
+using utils::make_selector_amfm;
+
+namespace timeout {
+
+static constexpr auto tune = 30s;
+
+} // namespace timeout
+
+struct TunerCallbackMock : public ITunerCallback {
+ TunerCallbackMock() {
+ // we expect the antenna is connected through the whole test
+ EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
+ }
+
+ MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&));
+ MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged, Return<void>(const ProgramInfo&));
+ MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected));
+ MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
+};
+
+class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ bool openSession();
+
+ sp<IBroadcastRadio> mModule;
+ Properties mProperties;
+ sp<ITunerSession> mSession;
+ sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
+};
+
+void BroadcastRadioHalTest::SetUp() {
+ EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
+
+ // lookup HIDL service (radio module)
+ mModule = getService<IBroadcastRadio>();
+ ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation";
+
+ // get module properties
+ auto propResult = mModule->getProperties([&](const Properties& p) { mProperties = p; });
+ ASSERT_TRUE(propResult.isOk());
+
+ EXPECT_FALSE(mProperties.maker.empty());
+ EXPECT_FALSE(mProperties.product.empty());
+ EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
+}
+
+void BroadcastRadioHalTest::TearDown() {
+ mSession.clear();
+ mModule.clear();
+ clearAndWait(mCallback, 1s);
+}
+
+bool BroadcastRadioHalTest::openSession() {
+ EXPECT_EQ(nullptr, mSession.get()) << "Session is already open";
+
+ Result halResult = Result::UNKNOWN_ERROR;
+ auto openCb = [&](Result result, const sp<ITunerSession>& session) {
+ halResult = result;
+ if (result != Result::OK) return;
+ mSession = session;
+ };
+ auto hidlResult = mModule->openSession(mCallback, openCb);
+
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_NE(nullptr, mSession.get());
+
+ return nullptr != mSession.get();
+}
+
+/**
+ * Test session opening.
+ *
+ * Verifies that:
+ * - the method succeeds on a first and subsequent calls;
+ * - the method succeeds when called for the second time without
+ * closing previous session.
+ */
+TEST_F(BroadcastRadioHalTest, OpenSession) {
+ // simply open session for the first time
+ ASSERT_TRUE(openSession());
+
+ // drop (without explicit close) and re-open the session
+ mSession.clear();
+ ASSERT_TRUE(openSession());
+
+ // open the second session (the first one should be forcibly closed)
+ auto secondSession = mSession;
+ mSession.clear();
+ ASSERT_TRUE(openSession());
+}
+
+/**
+ * Test tuning with FM selector.
+ *
+ * Verifies that:
+ * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
+ * - if it is supported, the method succeeds;
+ * - after a successful tune call, onCurrentProgramInfoChanged callback is
+ * invoked carrying a proper selector;
+ * - program changes exactly to what was requested.
+ */
+TEST_F(BroadcastRadioHalTest, FmTune) {
+ ASSERT_TRUE(openSession());
+
+ uint64_t freq = 100100; // 100.1 FM
+ auto sel = make_selector_amfm(freq);
+
+ // try tuning
+ ProgramInfo infoCb = {};
+ EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _)
+ .Times(AnyNumber())
+ .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
+ auto result = mSession->tune(sel);
+
+ // expect a failure if it's not supported
+ if (!utils::isSupported(mProperties, sel)) {
+ EXPECT_EQ(Result::NOT_SUPPORTED, result);
+ return;
+ }
+
+ // expect a callback if it succeeds
+ EXPECT_EQ(Result::OK, result);
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+
+ // it should tune exactly to what was requested
+ auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY);
+ EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq));
+}
+
+/**
+ * Test tuning with invalid selectors.
+ *
+ * Verifies that:
+ * - if the selector is not supported, it's ignored;
+ * - if it is supported, an invalid value results with INVALID_ARGUMENTS;
+ */
+TEST_F(BroadcastRadioHalTest, TuneFailsWithInvalid) {
+ ASSERT_TRUE(openSession());
+
+ vector<ProgramIdentifier> invalid = {
+ make_identifier(IdentifierType::AMFM_FREQUENCY, 0),
+ make_identifier(IdentifierType::RDS_PI, 0x10000),
+ make_identifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
+ make_identifier(IdentifierType::DAB_SID_EXT, 0),
+ make_identifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
+ make_identifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
+ };
+
+ for (auto&& id : invalid) {
+ ProgramSelector sel{id, {}};
+
+ auto result = mSession->tune(sel);
+
+ if (utils::isSupported(mProperties, sel)) {
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+ } else {
+ EXPECT_EQ(Result::NOT_SUPPORTED, result);
+ }
+ }
+}
+
+/**
+ * Test tuning with empty program selector.
+ *
+ * Verifies that:
+ * - tune fails with NOT_SUPPORTED when program selector is not initialized.
+ */
+TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) {
+ ASSERT_TRUE(openSession());
+
+ // Program type is 1-based, so 0 will always be invalid.
+ ProgramSelector sel = {};
+ auto result = mSession->tune(sel);
+ ASSERT_EQ(Result::NOT_SUPPORTED, result);
+}
+
+/**
+ * Test scanning to next/prev station.
+ *
+ * Verifies that:
+ * - the method succeeds;
+ * - the program info is changed within timeout::tune;
+ * - works both directions and with or without skipping sub-channel.
+ */
+TEST_F(BroadcastRadioHalTest, Scan) {
+ ASSERT_TRUE(openSession());
+
+ EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
+ auto result = mSession->scan(true /* up */, true /* skip subchannel */);
+ EXPECT_EQ(Result::OK, result);
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+
+ EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
+ result = mSession->scan(false /* down */, false /* don't skip subchannel */);
+ EXPECT_EQ(Result::OK, result);
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+}
+
+/**
+ * Test step operation.
+ *
+ * Verifies that:
+ * - the method succeeds or returns NOT_SUPPORTED;
+ * - the program info is changed within timeout::tune if the method succeeded;
+ * - works both directions.
+ */
+TEST_F(BroadcastRadioHalTest, Step) {
+ ASSERT_TRUE(openSession());
+
+ EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _).Times(AnyNumber());
+ auto result = mSession->step(true /* up */);
+ if (result == Result::NOT_SUPPORTED) return;
+ EXPECT_EQ(Result::OK, result);
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+
+ EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
+ result = mSession->step(false /* down */);
+ EXPECT_EQ(Result::OK, result);
+ EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+}
+
+/**
+ * Test tune cancellation.
+ *
+ * Verifies that:
+ * - the method does not crash after being invoked multiple times.
+ */
+TEST_F(BroadcastRadioHalTest, Cancel) {
+ ASSERT_TRUE(openSession());
+
+ for (int i = 0; i < 10; i++) {
+ auto scanResult = mSession->scan(true /* up */, true /* skip subchannel */);
+ ASSERT_EQ(Result::OK, scanResult);
+
+ auto cancelResult = mSession->cancel();
+ ASSERT_TRUE(cancelResult.isOk());
+ }
+}
+
+/**
+ * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
+ *
+ * Verifies that:
+ * - callback is called for empty parameters set.
+ */
+TEST_F(BroadcastRadioHalTest, NoParameters) {
+ ASSERT_TRUE(openSession());
+
+ hidl_vec<VendorKeyValue> halResults = {};
+ bool wasCalled = false;
+ auto cb = [&](hidl_vec<VendorKeyValue> results) {
+ wasCalled = true;
+ halResults = results;
+ };
+
+ auto hidlResult = mSession->setParameters({}, cb);
+ ASSERT_TRUE(hidlResult.isOk());
+ ASSERT_TRUE(wasCalled);
+ ASSERT_EQ(0u, halResults.size());
+
+ wasCalled = false;
+ hidlResult = mSession->getParameters({}, cb);
+ ASSERT_TRUE(hidlResult.isOk());
+ ASSERT_TRUE(wasCalled);
+ ASSERT_EQ(0u, halResults.size());
+}
+
+/**
+ * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
+ *
+ * Verifies that:
+ * - unknown parameters are ignored;
+ * - callback is called also for empty results set.
+ */
+TEST_F(BroadcastRadioHalTest, UnknownParameters) {
+ ASSERT_TRUE(openSession());
+
+ hidl_vec<VendorKeyValue> halResults = {};
+ bool wasCalled = false;
+ auto cb = [&](hidl_vec<VendorKeyValue> results) {
+ wasCalled = true;
+ halResults = results;
+ };
+
+ auto hidlResult = mSession->setParameters({{"com.google.unknown", "dummy"}}, cb);
+ ASSERT_TRUE(hidlResult.isOk());
+ ASSERT_TRUE(wasCalled);
+ ASSERT_EQ(0u, halResults.size());
+
+ wasCalled = false;
+ hidlResult = mSession->getParameters({{"com.google.unknown*", "dummy"}}, cb);
+ ASSERT_TRUE(hidlResult.isOk());
+ ASSERT_TRUE(wasCalled);
+ ASSERT_EQ(0u, halResults.size());
+}
+
+/**
+ * Test session closing.
+ *
+ * Verifies that:
+ * - the method does not crash after being invoked multiple times.
+ */
+TEST_F(BroadcastRadioHalTest, Close) {
+ ASSERT_TRUE(openSession());
+
+ for (int i = 0; i < 10; i++) {
+ auto cancelResult = mSession->close();
+ ASSERT_TRUE(cancelResult.isOk());
+ }
+}
+
+/**
+ * Test geting image of invalid ID.
+ *
+ * Verifies that:
+ * - getImage call handles argument 0 gracefully.
+ */
+TEST_F(BroadcastRadioHalTest, GetNoImage) {
+ size_t len = 0;
+ auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(0u, len);
+}
+
+} // namespace vts
+} // namespace V2_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/broadcastradio/common/utils/OWNERS b/broadcastradio/common/OWNERS
similarity index 100%
rename from broadcastradio/common/utils/OWNERS
rename to broadcastradio/common/OWNERS
diff --git a/broadcastradio/common/tests/Android.bp b/broadcastradio/common/tests/Android.bp
index 4456602..bbad527 100644
--- a/broadcastradio/common/tests/Android.bp
+++ b/broadcastradio/common/tests/Android.bp
@@ -26,4 +26,25 @@
"WorkerThread_test.cpp",
],
static_libs: ["android.hardware.broadcastradio@common-utils-lib"],
-}
\ No newline at end of file
+}
+
+cc_test {
+ name: "android.hardware.broadcastradio@common-utils-xx-tests",
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "CommonXX_test.cpp",
+ ],
+ static_libs: [
+ "android.hardware.broadcastradio@common-utils-1x-lib",
+ "android.hardware.broadcastradio@common-utils-2x-lib",
+ ],
+ shared_libs: [
+ "android.hardware.broadcastradio@1.2",
+ "android.hardware.broadcastradio@2.0",
+ ],
+}
diff --git a/broadcastradio/common/tests/CommonXX_test.cpp b/broadcastradio/common/tests/CommonXX_test.cpp
new file mode 100644
index 0000000..d19204e
--- /dev/null
+++ b/broadcastradio/common/tests/CommonXX_test.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <broadcastradio-utils-1x/Utils.h>
+#include <broadcastradio-utils-2x/Utils.h>
diff --git a/broadcastradio/common/utils/Android.bp b/broadcastradio/common/utils/Android.bp
index d29d05c..33ba7da 100644
--- a/broadcastradio/common/utils/Android.bp
+++ b/broadcastradio/common/utils/Android.bp
@@ -24,11 +24,12 @@
"-Werror",
],
srcs: [
- "Utils.cpp",
"WorkerThread.cpp",
],
export_include_dirs: ["include"],
shared_libs: [
- "android.hardware.broadcastradio@1.2",
+ "libbase",
+ "liblog",
+ "libutils",
],
}
diff --git a/broadcastradio/common/utils1x/Android.bp b/broadcastradio/common/utils1x/Android.bp
new file mode 100644
index 0000000..127c15a
--- /dev/null
+++ b/broadcastradio/common/utils1x/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+ name: "android.hardware.broadcastradio@common-utils-1x-lib",
+ vendor_available: true,
+ relative_install_path: "hw",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "Utils.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "android.hardware.broadcastradio@1.2",
+ ],
+}
diff --git a/broadcastradio/common/utils/Utils.cpp b/broadcastradio/common/utils1x/Utils.cpp
similarity index 97%
rename from broadcastradio/common/utils/Utils.cpp
rename to broadcastradio/common/utils1x/Utils.cpp
index 22a6970..7a59d6a 100644
--- a/broadcastradio/common/utils/Utils.cpp
+++ b/broadcastradio/common/utils1x/Utils.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "BroadcastRadioDefault.utils"
//#define LOG_NDEBUG 0
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
#include <log/log.h>
@@ -59,9 +59,7 @@
/* We should check all Ids of a given type (ie. other AF),
* but it doesn't matter for default implementation.
*/
- auto aId = getId(a, type);
- auto bId = getId(b, type);
- return aId == bId;
+ return getId(a, type) == getId(b, type);
}
bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
@@ -242,14 +240,16 @@
namespace V1_0 {
bool operator==(const BandConfig& l, const BandConfig& r) {
+ using namespace utils;
+
if (l.type != r.type) return false;
if (l.antennaConnected != r.antennaConnected) return false;
if (l.lowerLimit != r.lowerLimit) return false;
if (l.upperLimit != r.upperLimit) return false;
if (l.spacings != r.spacings) return false;
- if (utils::isAm(l.type)) {
+ if (isAm(l.type)) {
return l.ext.am == r.ext.am;
- } else if (utils::isFm(l.type)) {
+ } else if (isFm(l.type)) {
return l.ext.fm == r.ext.fm;
} else {
ALOGW("Unsupported band config type: %s", toString(l.type).c_str());
diff --git a/broadcastradio/common/utils/include/broadcastradio-utils/Utils.h b/broadcastradio/common/utils1x/include/broadcastradio-utils-1x/Utils.h
similarity index 88%
rename from broadcastradio/common/utils/include/broadcastradio-utils/Utils.h
rename to broadcastradio/common/utils1x/include/broadcastradio-utils-1x/Utils.h
index 9cdc629..5884b5a 100644
--- a/broadcastradio/common/utils/include/broadcastradio-utils/Utils.h
+++ b/broadcastradio/common/utils1x/include/broadcastradio-utils-1x/Utils.h
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_H
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_1X_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_1X_H
#include <android/hardware/broadcastradio/1.2/types.h>
#include <chrono>
@@ -68,8 +68,8 @@
V1_1::ProgramSelector make_selector(V1_0::Band band, uint32_t channel, uint32_t subChannel = 0);
-bool getLegacyChannel(const V1_1::ProgramSelector& sel,
- uint32_t* channelOut, uint32_t* subChannelOut);
+bool getLegacyChannel(const V1_1::ProgramSelector& sel, uint32_t* channelOut,
+ uint32_t* subChannelOut);
bool isDigital(const V1_1::ProgramSelector& sel);
@@ -85,4 +85,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_H
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_1X_H
diff --git a/broadcastradio/common/utils2x/Android.bp b/broadcastradio/common/utils2x/Android.bp
new file mode 100644
index 0000000..c6b94af
--- /dev/null
+++ b/broadcastradio/common/utils2x/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+ name: "android.hardware.broadcastradio@common-utils-2x-lib",
+ vendor_available: true,
+ relative_install_path: "hw",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "Utils.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "android.hardware.broadcastradio@2.0",
+ ],
+}
diff --git a/broadcastradio/common/utils2x/Utils.cpp b/broadcastradio/common/utils2x/Utils.cpp
new file mode 100644
index 0000000..d157108
--- /dev/null
+++ b/broadcastradio/common/utils2x/Utils.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.utils"
+//#define LOG_NDEBUG 0
+
+#include <broadcastradio-utils-2x/Utils.h>
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace utils {
+
+using V2_0::IdentifierType;
+using V2_0::Metadata;
+using V2_0::MetadataKey;
+using V2_0::ProgramIdentifier;
+using V2_0::ProgramSelector;
+
+using std::string;
+using std::vector;
+
+IdentifierType getType(const ProgramIdentifier& id) {
+ return static_cast<IdentifierType>(id.type);
+}
+
+static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
+ const IdentifierType type) {
+ return hasId(a, type) && hasId(b, type);
+}
+
+static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
+ const IdentifierType type) {
+ if (!bothHaveId(a, b, type)) return false;
+ /* We should check all Ids of a given type (ie. other AF),
+ * but it doesn't matter for default implementation.
+ */
+ return getId(a, type) == getId(b, type);
+}
+
+static int getHdSubchannel(const ProgramSelector& sel) {
+ auto hdsidext = getId(sel, IdentifierType::HD_STATION_ID_EXT, 0);
+ hdsidext >>= 32; // Station ID number
+ return hdsidext & 0xF; // HD Radio subchannel
+}
+
+bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
+ auto type = getType(b.primaryId);
+
+ switch (type) {
+ case IdentifierType::HD_STATION_ID_EXT:
+ case IdentifierType::RDS_PI:
+ case IdentifierType::AMFM_FREQUENCY:
+ if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
+ if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
+ return getHdSubchannel(b) == 0 && haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
+ case IdentifierType::DAB_SID_EXT:
+ return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
+ case IdentifierType::DRMO_SERVICE_ID:
+ return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
+ case IdentifierType::SXM_SERVICE_ID:
+ return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
+ default: // includes all vendor types
+ ALOGW("Unsupported program type: %s", toString(type).c_str());
+ return false;
+ }
+}
+
+static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
+ auto itype = static_cast<uint32_t>(type);
+
+ if (sel.primaryId.type == itype) {
+ if (val) *val = sel.primaryId.value;
+ return true;
+ }
+
+ // not optimal, but we don't care in default impl
+ for (auto&& id : sel.secondaryIds) {
+ if (id.type == itype) {
+ if (val) *val = id.value;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType type) {
+ return maybeGetId(sel, type, nullptr);
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
+ uint64_t val;
+
+ if (maybeGetId(sel, type, &val)) {
+ return val;
+ }
+
+ ALOGW("Identifier %s not found", toString(type).c_str());
+ return 0;
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
+ if (!hasId(sel, type)) return defval;
+ return getId(sel, type);
+}
+
+vector<uint64_t> getAllIds(const ProgramSelector& sel, const IdentifierType type) {
+ vector<uint64_t> ret;
+ auto itype = static_cast<uint32_t>(type);
+
+ if (sel.primaryId.type == itype) ret.push_back(sel.primaryId.value);
+
+ for (auto&& id : sel.secondaryIds) {
+ if (id.type == itype) ret.push_back(id.value);
+ }
+
+ return ret;
+}
+
+bool isSupported(const V2_0::Properties& prop, const V2_0::ProgramSelector& sel) {
+ // Not optimal, but it doesn't matter for default impl nor VTS tests.
+ for (auto&& idTypeI : prop.supportedIdentifierTypes) {
+ auto idType = static_cast<IdentifierType>(idTypeI);
+ if (hasId(sel, idType)) return true;
+ }
+ return false;
+}
+
+static bool isValid(const ProgramIdentifier& id) {
+ auto val = id.value;
+ bool valid = true;
+
+ auto expect = [&valid](bool condition, std::string message) {
+ if (!condition) {
+ valid = false;
+ ALOGE("Identifier not valid, expected %s", message.c_str());
+ }
+ };
+
+ switch (static_cast<IdentifierType>(id.type)) {
+ case IdentifierType::AMFM_FREQUENCY:
+ case IdentifierType::DAB_FREQUENCY:
+ case IdentifierType::DRMO_FREQUENCY:
+ expect(val > 100u, "f > 100kHz");
+ expect(val < 10000000u, "f < 10GHz");
+ break;
+ case IdentifierType::RDS_PI:
+ expect(val != 0u, "RDS PI != 0");
+ expect(val <= 0xFFFFu, "16bit id");
+ break;
+ case IdentifierType::HD_STATION_ID_EXT: {
+ auto stationId = val & 0xFFFFFFFF; // 32bit
+ val >>= 32;
+ auto subchannel = val & 0xF; // 4bit
+ val >>= 4;
+ auto freq = val & 0x3FFFF; // 18bit
+ expect(stationId != 0u, "HD station id != 0");
+ expect(subchannel < 8u, "HD subch < 8");
+ expect(freq > 100u, "f > 100kHz");
+ expect(freq < 10000000u, "f < 10GHz");
+ break;
+ }
+ case IdentifierType::DAB_SID_EXT: {
+ auto sid = val & 0xFFFF; // 16bit
+ val >>= 16;
+ auto ecc = val & 0xFF; // 8bit
+ expect(sid != 0u, "DAB SId != 0");
+ expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
+ break;
+ }
+ case IdentifierType::DAB_ENSEMBLE:
+ expect(val != 0u, "DAB ensemble != 0");
+ expect(val <= 0xFFFFu, "16bit id");
+ break;
+ case IdentifierType::DAB_SCID:
+ expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
+ expect(val <= 0xFFFu, "12bit id");
+ break;
+ case IdentifierType::DRMO_SERVICE_ID:
+ expect(val != 0u, "DRM SId != 0");
+ expect(val <= 0xFFFFFFu, "24bit id");
+ break;
+ case IdentifierType::SXM_SERVICE_ID:
+ expect(val != 0u, "SXM SId != 0");
+ expect(val <= 0xFFFFFFFFu, "32bit id");
+ break;
+ case IdentifierType::SXM_CHANNEL:
+ expect(val < 1000u, "SXM channel < 1000");
+ break;
+ case IdentifierType::VENDOR_START:
+ case IdentifierType::VENDOR_END:
+ // skip
+ break;
+ }
+
+ return valid;
+}
+
+bool isValid(const V2_0::ProgramSelector& sel) {
+ if (!isValid(sel.primaryId)) return false;
+ for (auto&& id : sel.secondaryIds) {
+ if (!isValid(id)) return false;
+ }
+ return true;
+}
+
+ProgramIdentifier make_identifier(IdentifierType type, uint64_t value) {
+ return {static_cast<uint32_t>(type), value};
+}
+
+ProgramSelector make_selector_amfm(uint32_t frequency) {
+ ProgramSelector sel = {};
+ sel.primaryId = make_identifier(IdentifierType::AMFM_FREQUENCY, frequency);
+ return sel;
+}
+
+Metadata make_metadata(MetadataKey key, int64_t value) {
+ Metadata meta = {};
+ meta.key = static_cast<uint32_t>(key);
+ meta.intValue = value;
+ return meta;
+}
+
+Metadata make_metadata(MetadataKey key, string value) {
+ Metadata meta = {};
+ meta.key = static_cast<uint32_t>(key);
+ meta.stringValue = value;
+ return meta;
+}
+
+} // namespace utils
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h
new file mode 100644
index 0000000..dd01852
--- /dev/null
+++ b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h
@@ -0,0 +1,85 @@
+/*
+ * 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_COMMON_UTILS_2X_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_2X_H
+
+#include <android/hardware/broadcastradio/2.0/types.h>
+#include <chrono>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace utils {
+
+V2_0::IdentifierType getType(const V2_0::ProgramIdentifier& id);
+
+/**
+ * Checks, if {@code pointer} tunes to {@channel}.
+ *
+ * For example, having a channel {AMFM_FREQUENCY = 103.3}:
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 0} can tune to this channel;
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 1} can't.
+ *
+ * @param pointer selector we're trying to match against channel.
+ * @param channel existing channel.
+ */
+bool tunesTo(const V2_0::ProgramSelector& pointer, const V2_0::ProgramSelector& channel);
+
+bool hasId(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns 0 and emits a warning.
+ */
+uint64_t getId(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns default value.
+ */
+uint64_t getId(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type, uint64_t defval);
+
+/**
+ * Returns all IDs of a given type.
+ */
+std::vector<uint64_t> getAllIds(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type);
+
+/**
+ * Checks, if a given selector is supported by the radio module.
+ *
+ * @param prop Module description.
+ * @param sel The selector to check.
+ * @return True, if the selector is supported, false otherwise.
+ */
+bool isSupported(const V2_0::Properties& prop, const V2_0::ProgramSelector& sel);
+
+bool isValid(const V2_0::ProgramSelector& sel);
+
+V2_0::ProgramIdentifier make_identifier(V2_0::IdentifierType type, uint64_t value);
+V2_0::ProgramSelector make_selector_amfm(uint32_t frequency);
+V2_0::Metadata make_metadata(V2_0::MetadataKey key, int64_t value);
+V2_0::Metadata make_metadata(V2_0::MetadataKey key, std::string value);
+
+} // namespace utils
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_2X_H
diff --git a/broadcastradio/common/vts/utils/OWNERS b/broadcastradio/common/vts/utils/OWNERS
deleted file mode 100644
index 12adf57..0000000
--- a/broadcastradio/common/vts/utils/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-# Automotive team
-egranata@google.com
-twasilczyk@google.com
-
-# VTS team
-yuexima@google.com
-yim@google.com
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h
new file mode 100644
index 0000000..0b6f5eb
--- /dev/null
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_VTS_POINTER_UTILS
+#define ANDROID_HARDWARE_BROADCASTRADIO_VTS_POINTER_UTILS
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace vts {
+
+/**
+ * Clears strong pointer and waits until the object gets destroyed.
+ *
+ * @param ptr The pointer to get cleared.
+ * @param timeout Time to wait for other references.
+ */
+template <typename T>
+static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) {
+ using std::chrono::steady_clock;
+
+ constexpr auto step = 10ms;
+
+ wp<T> wptr = ptr;
+ ptr.clear();
+
+ auto limit = steady_clock::now() + timeout;
+ while (wptr.promote() != nullptr) {
+ if (steady_clock::now() + step > limit) {
+ FAIL() << "Pointer was not released within timeout";
+ break;
+ }
+ std::this_thread::sleep_for(step);
+ }
+}
+
+} // namespace vts
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_VTS_POINTER_UTILS
diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp
index 6da5cc4..544162b 100644
--- a/cas/1.0/default/Android.bp
+++ b/cas/1.0/default/Android.bp
@@ -12,12 +12,6 @@
"TypeConvert.cpp",
],
- product_variables: {
- treble: {
- cflags: ["-DUSE_VNDBINDER"],
- },
- },
-
compile_multilib: "32",
init_rc: ["android.hardware.cas@1.0-service.rc"],
diff --git a/cas/1.0/default/CasImpl.cpp b/cas/1.0/default/CasImpl.cpp
index 9d1f4a3..2ac1c4f 100644
--- a/cas/1.0/default/CasImpl.cpp
+++ b/cas/1.0/default/CasImpl.cpp
@@ -103,6 +103,7 @@
status_t err = INVALID_OPERATION;
if (holder != NULL) {
err = holder->get()->openSession(&sessionId);
+ holder.clear();
}
_hidl_cb(toStatus(err), sessionId);
diff --git a/cas/1.0/default/service.cpp b/cas/1.0/default/service.cpp
index 3f1df5a..04a8ad9 100644
--- a/cas/1.0/default/service.cpp
+++ b/cas/1.0/default/service.cpp
@@ -31,11 +31,9 @@
int main() {
ALOGD("android.hardware.cas@1.0-service starting...");
-#ifdef USE_VNDBINDER
// The CAS HAL may communicate to other vendor components via
// /dev/vndbinder
android::ProcessState::initWithDriver("/dev/vndbinder");
-#endif // USE_VNDBINDER
configureRpcThreadpool(8, true /* callerWillJoin */);
diff --git a/compatibility_matrix.27.xml b/compatibility_matrix.1.xml
similarity index 83%
copy from compatibility_matrix.27.xml
copy to compatibility_matrix.1.xml
index 80001f7..6ba87c0 100644
--- a/compatibility_matrix.27.xml
+++ b/compatibility_matrix.1.xml
@@ -1,4 +1,4 @@
-<compatibility-matrix version="1.0" type="framework">
+<compatibility-matrix version="1.0" type="framework" level="1">
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>2.0</version>
@@ -57,7 +57,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.broadcastradio</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IBroadcastRadioFactory</name>
<instance>default</instance>
@@ -71,14 +71,6 @@
<instance>legacy/0</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.cas</name>
- <version>1.0</version>
- <interface>
- <name>IMediaCasService</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="hidl" optional="false">
<name>android.hardware.configstore</name>
<version>1.0</version>
@@ -164,14 +156,6 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.health</name>
- <version>2.0</version>
- <interface>
- <name>IHealth</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.ir</name>
<version>1.0</version>
</hal>
@@ -220,16 +204,8 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.oemlock</name>
- <version>1.0</version>
- <interface>
- <name>IOemLock</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.power</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IPower</name>
<instance>default</instance>
@@ -237,7 +213,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.radio</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IRadio</name>
<instance>slot1</instance>
@@ -280,24 +256,8 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.tetheroffload.config</name>
- <version>1.0</version>
- <interface>
- <name>IOffloadConfig</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.tetheroffload.control</name>
- <version>1.0</version>
- <interface>
- <name>IOffloadControl</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.thermal</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IThermal</name>
<instance>default</instance>
@@ -321,7 +281,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.usb</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IUsb</name>
<instance>default</instance>
@@ -329,7 +289,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.vibrator</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
@@ -344,30 +304,14 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.weaver</name>
- <version>1.0</version>
- <interface>
- <name>IWeaver</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.wifi</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IWifi</name>
<instance>default</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.wifi.offload</name>
- <version>1.0</version>
- <interface>
- <name>IOffload</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.wifi.supplicant</name>
<version>1.0</version>
<interface>
diff --git a/compatibility_matrix.27.xml b/compatibility_matrix.2.xml
similarity index 97%
rename from compatibility_matrix.27.xml
rename to compatibility_matrix.2.xml
index 80001f7..ea8dde8 100644
--- a/compatibility_matrix.27.xml
+++ b/compatibility_matrix.2.xml
@@ -1,4 +1,4 @@
-<compatibility-matrix version="1.0" type="framework">
+<compatibility-matrix version="1.0" type="framework" level="2">
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>2.0</version>
@@ -164,14 +164,6 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.health</name>
- <version>2.0</version>
- <interface>
- <name>IHealth</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.ir</name>
<version>1.0</version>
</hal>
diff --git a/compatibility_matrix.26.xml b/compatibility_matrix.26.xml
deleted file mode 100644
index 940588f..0000000
--- a/compatibility_matrix.26.xml
+++ /dev/null
@@ -1,378 +0,0 @@
-<compatibility-matrix version="1.0" type="framework">
- <hal format="hidl" optional="false">
- <name>android.hardware.audio</name>
- <version>2.0</version>
- <interface>
- <name>IDevicesFactory</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.audio.effect</name>
- <version>2.0</version>
- <interface>
- <name>IEffectsFactory</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.automotive.evs</name>
- <version>1.0</version>
- <interface>
- <name>IEvsEnumerator</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.automotive.vehicle</name>
- <version>2.0</version>
- <interface>
- <name>IVehicle</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.biometrics.fingerprint</name>
- <version>2.1</version>
- <interface>
- <name>IBiometricsFingerprint</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.bluetooth</name>
- <version>1.0</version>
- <interface>
- <name>IBluetoothHci</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.boot</name>
- <version>1.0</version>
- <interface>
- <name>IBootControl</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.broadcastradio</name>
- <version>1.0-1</version>
- <interface>
- <name>IBroadcastRadioFactory</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.camera.provider</name>
- <version>2.4</version>
- <interface>
- <name>ICameraProvider</name>
- <instance>legacy/0</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.cas</name>
- <version>1.0</version>
- <interface>
- <name>IMediaCasService</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.configstore</name>
- <version>1.0-1</version>
- <interface>
- <name>ISurfaceFlingerConfigs</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.contexthub</name>
- <version>1.0</version>
- <interface>
- <name>IContexthub</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.drm</name>
- <version>1.0</version>
- <interface>
- <name>ICryptoFactory</name>
- <instance>default</instance>
- </interface>
- <interface>
- <name>IDrmFactory</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.dumpstate</name>
- <version>1.0</version>
- <interface>
- <name>IDumpstateDevice</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.gatekeeper</name>
- <version>1.0</version>
- <interface>
- <name>IGatekeeper</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.gnss</name>
- <version>1.0</version>
- <interface>
- <name>IGnss</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.graphics.allocator</name>
- <version>2.0</version>
- <interface>
- <name>IAllocator</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.graphics.composer</name>
- <version>2.1</version>
- <interface>
- <name>IComposer</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.graphics.mapper</name>
- <version>2.0</version>
- <interface>
- <name>IMapper</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.health</name>
- <version>1.0</version>
- <interface>
- <name>IHealth</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.health</name>
- <version>2.0</version>
- <interface>
- <name>IHealth</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.ir</name>
- <version>1.0</version>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.keymaster</name>
- <version>3.0</version>
- <interface>
- <name>IKeymasterDevice</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.light</name>
- <version>2.0</version>
- <interface>
- <name>ILight</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="false">
- <name>android.hardware.media.omx</name>
- <version>1.0</version>
- <interface>
- <name>IOmx</name>
- <instance>default</instance>
- </interface>
- <interface>
- <name>IOmxStore</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.memtrack</name>
- <version>1.0</version>
- <interface>
- <name>IMemtrack</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.nfc</name>
- <version>1.0</version>
- <interface>
- <name>INfc</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.oemlock</name>
- <version>1.0</version>
- <interface>
- <name>IOemLock</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.power</name>
- <version>1.0-1</version>
- <interface>
- <name>IPower</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.radio</name>
- <version>1.0-1</version>
- <interface>
- <name>IRadio</name>
- <instance>slot1</instance>
- </interface>
- <interface>
- <name>ISap</name>
- <instance>slot1</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.radio.deprecated</name>
- <version>1.0</version>
- <interface>
- <name>IOemHook</name>
- <instance>slot1</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.renderscript</name>
- <version>1.0</version>
- <interface>
- <name>IDevice</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.sensors</name>
- <version>1.0</version>
- <interface>
- <name>ISensors</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.soundtrigger</name>
- <version>2.0</version>
- <interface>
- <name>ISoundTriggerHw</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.tetheroffload.config</name>
- <version>1.0</version>
- <interface>
- <name>IOffloadConfig</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.tetheroffload.control</name>
- <version>1.0</version>
- <interface>
- <name>IOffloadControl</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.thermal</name>
- <version>1.0-1</version>
- <interface>
- <name>IThermal</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.tv.cec</name>
- <version>1.0</version>
- <interface>
- <name>IHdmiCec</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.tv.input</name>
- <version>1.0</version>
- <interface>
- <name>ITvInput</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.usb</name>
- <version>1.0-1</version>
- <interface>
- <name>IUsb</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.vibrator</name>
- <version>1.0-1</version>
- <interface>
- <name>IVibrator</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.vr</name>
- <version>1.0</version>
- <interface>
- <name>IVr</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.weaver</name>
- <version>1.0</version>
- <interface>
- <name>IWeaver</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.wifi</name>
- <version>1.0-1</version>
- <interface>
- <name>IWifi</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.wifi.offload</name>
- <version>1.0</version>
- <interface>
- <name>IOffload</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.wifi.supplicant</name>
- <version>1.0</version>
- <interface>
- <name>ISupplicant</name>
- <instance>default</instance>
- </interface>
- </hal>
-</compatibility-matrix>
diff --git a/compatibility_matrix.current.xml b/compatibility_matrix.current.xml
index 5a2563c..5b033e7 100644
--- a/compatibility_matrix.current.xml
+++ b/compatibility_matrix.current.xml
@@ -1,4 +1,4 @@
-<compatibility-matrix version="1.0" type="framework">
+<compatibility-matrix version="1.0" type="framework" level="3">
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>2.0</version>
diff --git a/compatibility_matrix.legacy.xml b/compatibility_matrix.legacy.xml
index d562fd0..6792598 100644
--- a/compatibility_matrix.legacy.xml
+++ b/compatibility_matrix.legacy.xml
@@ -1,4 +1,4 @@
-<compatibility-matrix version="1.0" type="framework">
+<compatibility-matrix version="1.0" type="framework" level="legacy">
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>2.0</version>
@@ -57,7 +57,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.broadcastradio</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IBroadcastRadioFactory</name>
<instance>default</instance>
@@ -71,17 +71,9 @@
<instance>legacy/0</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.cas</name>
- <version>1.0</version>
- <interface>
- <name>IMediaCasService</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="hidl" optional="false">
<name>android.hardware.configstore</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>ISurfaceFlingerConfigs</name>
<instance>default</instance>
@@ -164,14 +156,6 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.health</name>
- <version>2.0</version>
- <interface>
- <name>IHealth</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.ir</name>
<version>1.0</version>
</hal>
@@ -220,16 +204,8 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.oemlock</name>
- <version>1.0</version>
- <interface>
- <name>IOemLock</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.power</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IPower</name>
<instance>default</instance>
@@ -237,7 +213,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.radio</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IRadio</name>
<instance>slot1</instance>
@@ -280,24 +256,8 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.tetheroffload.config</name>
- <version>1.0</version>
- <interface>
- <name>IOffloadConfig</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.tetheroffload.control</name>
- <version>1.0</version>
- <interface>
- <name>IOffloadControl</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.thermal</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IThermal</name>
<instance>default</instance>
@@ -321,7 +281,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.usb</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IUsb</name>
<instance>default</instance>
@@ -329,7 +289,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.vibrator</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
@@ -344,30 +304,14 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.weaver</name>
- <version>1.0</version>
- <interface>
- <name>IWeaver</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.wifi</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IWifi</name>
<instance>default</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.wifi.offload</name>
- <version>1.0</version>
- <interface>
- <name>IOffload</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.wifi.supplicant</name>
<version>1.0</version>
<interface>
diff --git a/health/2.0/default/Android.bp b/health/2.0/default/Android.bp
new file mode 100644
index 0000000..8eb02e0
--- /dev/null
+++ b/health/2.0/default/Android.bp
@@ -0,0 +1,28 @@
+cc_library_static {
+ name: "android.hardware.health@2.0-impl",
+ vendor_available: true,
+ srcs: [
+ "Health.cpp",
+ "healthd_common.cpp",
+ ],
+
+ cflags: ["-DHEALTHD_USE_HEALTH_2_0"],
+
+ export_include_dirs: ["include"],
+
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.health@2.0",
+ ],
+
+ static_libs: [
+ "libbatterymonitor",
+ "android.hardware.health@1.0-convert",
+ ],
+}
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
new file mode 100644
index 0000000..4710c90
--- /dev/null
+++ b/health/2.0/default/Health.cpp
@@ -0,0 +1,183 @@
+#define LOG_TAG "android.hardware.health@2.0-impl"
+#include <android-base/logging.h>
+
+#include <health2/Health.h>
+
+#include <hidl/HidlTransportSupport.h>
+
+extern void healthd_battery_update_internal(bool);
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+namespace implementation {
+
+sp<Health> Health::instance_;
+
+Health::Health(struct healthd_config* c) {
+ // TODO(b/69268160): remove when libhealthd is removed.
+ healthd_board_init(c);
+ battery_monitor_ = std::make_unique<BatteryMonitor>();
+ battery_monitor_->init(c);
+}
+
+// Methods from IHealth follow.
+Return<Result> Health::registerCallback(const sp<IHealthInfoCallback>& callback) {
+ if (callback == nullptr) {
+ return Result::SUCCESS;
+ }
+
+ {
+ std::lock_guard<std::mutex> _lock(callbacks_lock_);
+ callbacks_.push_back(callback);
+ // unlock
+ }
+
+ auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
+ if (!linkRet.withDefault(false)) {
+ LOG(WARNING) << __func__ << "Cannot link to death: "
+ << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
+ // ignore the error
+ }
+
+ return update();
+}
+
+bool Health::unregisterCallbackInternal(const sp<IBase>& callback) {
+ if (callback == nullptr) return false;
+
+ bool removed = false;
+ std::lock_guard<std::mutex> _lock(callbacks_lock_);
+ for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+ if (interfacesEqual(*it, callback)) {
+ it = callbacks_.erase(it);
+ removed = true;
+ } else {
+ ++it;
+ }
+ }
+ (void)callback->unlinkToDeath(this).isOk(); // ignore errors
+ return removed;
+}
+
+Return<Result> Health::unregisterCallback(const sp<IHealthInfoCallback>& callback) {
+ return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
+}
+
+template <typename T>
+void getProperty(const std::unique_ptr<BatteryMonitor>& monitor, int id, T defaultValue,
+ const std::function<void(Result, T)>& callback) {
+ struct BatteryProperty prop;
+ T ret = defaultValue;
+ Result result = Result::SUCCESS;
+ status_t err = monitor->getProperty(static_cast<int>(id), &prop);
+ if (err != OK) {
+ LOG(DEBUG) << "getProperty(" << id << ")"
+ << " fails: (" << err << ") " << strerror(-err);
+ } else {
+ ret = static_cast<T>(prop.valueInt64);
+ }
+ switch (err) {
+ case OK:
+ result = Result::SUCCESS;
+ break;
+ case NAME_NOT_FOUND:
+ result = Result::NOT_SUPPORTED;
+ break;
+ default:
+ result = Result::UNKNOWN;
+ break;
+ }
+ callback(result, static_cast<T>(ret));
+}
+
+Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
+ getProperty(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, INT32_MIN, _hidl_cb);
+ return Void();
+}
+
+Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
+ getProperty(battery_monitor_, BATTERY_PROP_CURRENT_NOW, INT32_MIN, _hidl_cb);
+ return Void();
+}
+
+Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
+ getProperty(battery_monitor_, BATTERY_PROP_CURRENT_AVG, INT32_MIN, _hidl_cb);
+ return Void();
+}
+
+Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
+ getProperty(battery_monitor_, BATTERY_PROP_CAPACITY, INT32_MIN, _hidl_cb);
+ return Void();
+}
+
+Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+ getProperty(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, INT64_MIN, _hidl_cb);
+ return Void();
+}
+
+Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
+ getProperty(battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN, _hidl_cb);
+ return Void();
+}
+
+Return<Result> Health::update() {
+ if (!healthd_mode_ops || !healthd_mode_ops->battery_update) {
+ LOG(WARNING) << "health@2.0: update: not initialized. "
+ << "update() should not be called in charger / recovery.";
+ return Result::UNKNOWN;
+ }
+
+ // Retrieve all information and call healthd_mode_ops->battery_update, which calls
+ // notifyListeners.
+ bool chargerOnline = battery_monitor_->update();
+
+ // adjust uevent / wakealarm periods
+ healthd_battery_update_internal(chargerOnline);
+
+ return Result::SUCCESS;
+}
+
+void Health::notifyListeners(const HealthInfo& info) {
+ std::lock_guard<std::mutex> _lock(callbacks_lock_);
+ for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+ auto ret = (*it)->healthInfoChanged(info);
+ if (!ret.isOk() && ret.isDeadObject()) {
+ it = callbacks_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+ if (handle != nullptr && handle->numFds >= 1) {
+ int fd = handle->data[0];
+ battery_monitor_->dumpState(fd);
+ fsync(fd);
+ }
+ return Void();
+}
+
+void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
+ (void)unregisterCallbackInternal(who.promote());
+}
+
+sp<IHealth> Health::initInstance(struct healthd_config* c) {
+ if (instance_ == nullptr) {
+ instance_ = new Health(c);
+ }
+ return instance_;
+}
+
+sp<Health> Health::getImplementation() {
+ CHECK(instance_ != nullptr);
+ return instance_;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/2.0/default/healthd_common.cpp b/health/2.0/default/healthd_common.cpp
new file mode 100644
index 0000000..8ff409d
--- /dev/null
+++ b/health/2.0/default/healthd_common.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.health@2.0-impl"
+#define KLOG_LEVEL 6
+
+#include <healthd/BatteryMonitor.h>
+#include <healthd/healthd.h>
+
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <utils/Errors.h>
+
+#include <health2/Health.h>
+
+using namespace android;
+
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+
+static struct healthd_config healthd_config = {
+ .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+ .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+ .batteryStatusPath = String8(String8::kEmptyString),
+ .batteryHealthPath = String8(String8::kEmptyString),
+ .batteryPresentPath = String8(String8::kEmptyString),
+ .batteryCapacityPath = String8(String8::kEmptyString),
+ .batteryVoltagePath = String8(String8::kEmptyString),
+ .batteryTemperaturePath = String8(String8::kEmptyString),
+ .batteryTechnologyPath = String8(String8::kEmptyString),
+ .batteryCurrentNowPath = String8(String8::kEmptyString),
+ .batteryCurrentAvgPath = String8(String8::kEmptyString),
+ .batteryChargeCounterPath = String8(String8::kEmptyString),
+ .batteryFullChargePath = String8(String8::kEmptyString),
+ .batteryCycleCountPath = String8(String8::kEmptyString),
+ .energyCounter = NULL,
+ .boot_min_cap = 0,
+ .screen_on = NULL,
+};
+
+static int eventct;
+static int epollfd;
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+// epoll_create() parameter is actually unused
+#define MAX_EPOLL_EVENTS 40
+static int uevent_fd;
+static int wakealarm_fd;
+
+// -1 for no epoll timeout
+static int awake_poll_interval = -1;
+
+static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
+
+using ::android::hardware::health::V2_0::implementation::Health;
+
+struct healthd_mode_ops* healthd_mode_ops = nullptr;
+
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+ struct epoll_event ev;
+
+ ev.events = EPOLLIN;
+
+ if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
+
+ ev.data.ptr = (void*)handler;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
+ return -1;
+ }
+
+ eventct++;
+ return 0;
+}
+
+static void wakealarm_set_interval(int interval) {
+ struct itimerspec itval;
+
+ if (wakealarm_fd == -1) return;
+
+ wakealarm_wake_interval = interval;
+
+ if (interval == -1) interval = 0;
+
+ itval.it_interval.tv_sec = interval;
+ itval.it_interval.tv_nsec = 0;
+ itval.it_value.tv_sec = interval;
+ itval.it_value.tv_nsec = 0;
+
+ if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
+ KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+void healthd_battery_update_internal(bool charger_online) {
+ // Fast wake interval when on charger (watch for overheat);
+ // slow wake interval when on battery (watch for drained battery).
+
+ int new_wake_interval = charger_online ? healthd_config.periodic_chores_interval_fast
+ : healthd_config.periodic_chores_interval_slow;
+
+ if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval);
+
+ // During awake periods poll at fast rate. If wake alarm is set at fast
+ // rate then just use the alarm; if wake alarm is set at slow rate then
+ // poll at fast rate while awake and let alarm wake up at slow rate when
+ // asleep.
+
+ if (healthd_config.periodic_chores_interval_fast == -1)
+ awake_poll_interval = -1;
+ else
+ awake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast
+ ? -1
+ : healthd_config.periodic_chores_interval_fast * 1000;
+}
+
+static void healthd_battery_update(void) {
+ Health::getImplementation()->update();
+}
+
+static void periodic_chores() {
+ healthd_battery_update();
+}
+
+#define UEVENT_MSG_LEN 2048
+static void uevent_event(uint32_t /*epevents*/) {
+ char msg[UEVENT_MSG_LEN + 2];
+ char* cp;
+ int n;
+
+ n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
+ if (n <= 0) return;
+ if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+ return;
+
+ msg[n] = '\0';
+ msg[n + 1] = '\0';
+ cp = msg;
+
+ while (*cp) {
+ if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+ healthd_battery_update();
+ break;
+ }
+
+ /* advance to after the next \0 */
+ while (*cp++)
+ ;
+ }
+}
+
+static void uevent_init(void) {
+ uevent_fd = uevent_open_socket(64 * 1024, true);
+
+ if (uevent_fd < 0) {
+ KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+ return;
+ }
+
+ fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+ if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
+ KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+ unsigned long long wakeups;
+
+ if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+ KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+ return;
+ }
+
+ periodic_chores();
+}
+
+static void wakealarm_init(void) {
+ wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
+ if (wakealarm_fd == -1) {
+ KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+ return;
+ }
+
+ if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
+ KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
+
+ wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
+}
+
+static void healthd_mainloop(void) {
+ int nevents = 0;
+ while (1) {
+ struct epoll_event events[eventct];
+ int timeout = awake_poll_interval;
+ int mode_timeout;
+
+ /* Don't wait for first timer timeout to run periodic chores */
+ if (!nevents) periodic_chores();
+
+ healthd_mode_ops->heartbeat();
+
+ mode_timeout = healthd_mode_ops->preparetowait();
+ if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
+ nevents = epoll_wait(epollfd, events, eventct, timeout);
+ if (nevents == -1) {
+ if (errno == EINTR) continue;
+ KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+ break;
+ }
+
+ for (int n = 0; n < nevents; ++n) {
+ if (events[n].data.ptr) (*(void (*)(int))events[n].data.ptr)(events[n].events);
+ }
+ }
+
+ return;
+}
+
+static int healthd_init() {
+ epollfd = epoll_create(MAX_EPOLL_EVENTS);
+ if (epollfd == -1) {
+ KLOG_ERROR(LOG_TAG, "epoll_create failed; errno=%d\n", errno);
+ return -1;
+ }
+
+ healthd_mode_ops->init(&healthd_config);
+ wakealarm_init();
+ uevent_init();
+
+ return 0;
+}
+
+int healthd_main() {
+ int ret;
+
+ klog_set_level(KLOG_LEVEL);
+
+ if (!healthd_mode_ops) {
+ KLOG_ERROR("healthd ops not set, exiting\n");
+ exit(1);
+ }
+
+ ret = healthd_init();
+ if (ret) {
+ KLOG_ERROR("Initialization failed, exiting\n");
+ exit(2);
+ }
+
+ healthd_mainloop();
+ KLOG_ERROR("Main loop terminated, exiting\n");
+ return 3;
+}
diff --git a/health/2.0/default/include/health2/Health.h b/health/2.0/default/include/health2/Health.h
new file mode 100644
index 0000000..ab42ae7
--- /dev/null
+++ b/health/2.0/default/include/health2/Health.h
@@ -0,0 +1,69 @@
+#ifndef ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
+#define ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
+
+#include <memory>
+#include <vector>
+
+#include <android/hardware/health/1.0/types.h>
+#include <android/hardware/health/2.0/IHealth.h>
+#include <healthd/BatteryMonitor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+namespace implementation {
+
+using V1_0::BatteryStatus;
+using V1_0::HealthInfo;
+
+using ::android::hidl::base::V1_0::IBase;
+
+struct Health : public IHealth, hidl_death_recipient {
+ public:
+ static sp<IHealth> initInstance(struct healthd_config* c);
+ // Should only be called by implementation itself (-impl, -service).
+ // Clients should not call this function. Instead, initInstance() initializes and returns the
+ // global instance that has fewer functions.
+ // TODO(b/62229583): clean up and hide these functions after update() logic is simplified.
+ static sp<Health> getImplementation();
+
+ Health(struct healthd_config* c);
+
+ // TODO(b/62229583): clean up and hide these functions after update() logic is simplified.
+ void notifyListeners(const HealthInfo& info);
+
+ // Methods from IHealth follow.
+ Return<Result> registerCallback(const sp<IHealthInfoCallback>& callback) override;
+ Return<Result> unregisterCallback(const sp<IHealthInfoCallback>& callback) override;
+ Return<Result> update() override;
+ Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+ Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+ Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+ Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+ Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+ Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+ void serviceDied(uint64_t cookie, const wp<IBase>& /* who */) override;
+
+ private:
+ static sp<Health> instance_;
+
+ std::mutex callbacks_lock_;
+ std::vector<sp<IHealthInfoCallback>> callbacks_;
+ std::unique_ptr<BatteryMonitor> battery_monitor_;
+
+ bool unregisterCallbackInternal(const sp<IBase>& cb);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace health
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index 6b57ae3..52af575 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -35,7 +35,7 @@
import @1.1::ScanType;
enum RadioConst : @1.0::RadioConst {
- RADIO_ACCESS_SPEFICIER_MAX_SIZE = 8,
+ RADIO_ACCESS_SPECIFIER_MAX_SIZE = 8,
};
/**
@@ -74,7 +74,7 @@
/**
* Networks with bands/channels to scan
* Maximum length of the vector is
- * RadioConst:RADIO_ACCESS_SPEFICIER_MAX_SIZE
+ * RadioConst:RADIO_ACCESS_SPECIFIER_MAX_SIZE
*/
vec<RadioAccessSpecifier> specifiers;
@@ -220,4 +220,4 @@
* Valid only if type = tdscdma and size = 1 else must be empty.
*/
vec<CellInfoTdscdma> tdscdma;
-};
\ No newline at end of file
+};
diff --git a/tests/bar/1.0/default/Bar.cpp b/tests/bar/1.0/default/Bar.cpp
index 6a8a360..4614428 100644
--- a/tests/bar/1.0/default/Bar.cpp
+++ b/tests/bar/1.0/default/Bar.cpp
@@ -19,6 +19,11 @@
}
// Methods from ::android::hardware::tests::foo::V1_0::IFoo follow.
+Return<void> Bar::convertToBoolIfSmall(Discriminator d, const hidl_vec<Union>& u,
+ convertToBoolIfSmall_cb _hidl_cb) {
+ return mFoo->convertToBoolIfSmall(d, u, _hidl_cb);
+}
+
Return<void> Bar::doThis(float param) {
return mFoo->doThis(param);
}
diff --git a/tests/bar/1.0/default/Bar.h b/tests/bar/1.0/default/Bar.h
index b276823..acb976f 100644
--- a/tests/bar/1.0/default/Bar.h
+++ b/tests/bar/1.0/default/Bar.h
@@ -31,6 +31,8 @@
Bar();
// Methods from ::android::hardware::tests::foo::V1_0::IFoo follow.
+ virtual Return<void> convertToBoolIfSmall(Discriminator d, const hidl_vec<Union>& u,
+ convertToBoolIfSmall_cb _hidl_cb) override;
virtual Return<void> doThis(float param) override;
virtual Return<int32_t> doThatAndReturnSomething(int64_t param) override;
virtual Return<double> doQuiteABit(int32_t a, int64_t b, float c, double d) override;
diff --git a/tests/foo/1.0/IFoo.hal b/tests/foo/1.0/IFoo.hal
index c1ce7b0..4a930a2 100644
--- a/tests/foo/1.0/IFoo.hal
+++ b/tests/foo/1.0/IFoo.hal
@@ -122,6 +122,19 @@
bitfield<BitField> bf;
};
+ enum Discriminator : uint8_t {
+ BOOL,
+ INT,
+ };
+ union Union {
+ bool boolValue;
+ int64_t intValue;
+ };
+ struct ContainsUnion {
+ Discriminator discriminator;
+ Union value;
+ };
+
typedef int32_t[5][6][7] multidimArrayOne;
typedef multidimArrayOne[8][9][10] multidimArrayTwo;
typedef multidimArrayTwo[2][3][4] multidimArrayThree;
@@ -144,6 +157,16 @@
InnerTestEnumTypedef foo;
};
+ /**
+ * If d is INT, converts all values to bools which are small enough (0 or 1).
+ * If d is BOOL, should leave all values as BOOLs.
+ *
+ * @param d discriminator for all values in u
+ * @param u values to be expanded
+ * @return c must have same length as u unless there is an error in which case it will be empty.
+ */
+ convertToBoolIfSmall(Discriminator d, vec<Union> u) generates (vec<ContainsUnion> c);
+
doThis(float param);
doThatAndReturnSomething(int64_t param) generates (int32_t result);
doQuiteABit(int32_t a, int64_t b, float c, double d) generates (double something);
diff --git a/tests/foo/1.0/default/Foo.cpp b/tests/foo/1.0/default/Foo.cpp
index a860ce7..a31ab9f 100644
--- a/tests/foo/1.0/default/Foo.cpp
+++ b/tests/foo/1.0/default/Foo.cpp
@@ -15,6 +15,30 @@
namespace implementation {
// Methods from ::android::hardware::tests::foo::V1_0::IFoo follow.
+Return<void> Foo::convertToBoolIfSmall(Discriminator d, const hidl_vec<Union>& u,
+ convertToBoolIfSmall_cb _hidl_cb) {
+ hidl_vec<ContainsUnion> res(u.size());
+ for (size_t i = 0; i < u.size(); i++) {
+ ContainsUnion& outValue = res[i];
+
+ if (d == Discriminator::BOOL) {
+ outValue.discriminator = Discriminator::BOOL;
+ outValue.value.boolValue = u[i].boolValue;
+ } else {
+ uint64_t value = u[i].intValue;
+ if (value == 0 || value == 1) {
+ outValue.discriminator = Discriminator::BOOL;
+ outValue.value.boolValue = static_cast<bool>(value);
+ } else {
+ outValue.discriminator = Discriminator::INT;
+ outValue.value.intValue = value;
+ }
+ }
+ }
+ _hidl_cb(res);
+ return Void();
+}
+
Return<void> Foo::doThis(float param) {
LOG(INFO) << "SERVER(Foo) doThis(" << param << ")";
diff --git a/tests/foo/1.0/default/Foo.h b/tests/foo/1.0/default/Foo.h
index 4558a73..7dd672b 100644
--- a/tests/foo/1.0/default/Foo.h
+++ b/tests/foo/1.0/default/Foo.h
@@ -22,9 +22,14 @@
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;
+using ContainsUnion = ::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion;
+using Discriminator = ::android::hardware::tests::foo::V1_0::IFoo::Discriminator;
+using Union = ::android::hardware::tests::foo::V1_0::IFoo::Union;
struct Foo : public IFoo {
// Methods from ::android::hardware::tests::foo::V1_0::IFoo follow.
+ virtual Return<void> convertToBoolIfSmall(Discriminator d, const hidl_vec<Union>& u,
+ convertToBoolIfSmall_cb _hidl_cb) override;
virtual Return<void> doThis(float param) override;
virtual Return<int32_t> doThatAndReturnSomething(int64_t param) override;
virtual Return<double> doQuiteABit(int32_t a, int64_t b, float c, double d) override;
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp
index 3b056b0..9abe514 100644
--- a/wifi/1.2/default/wifi_legacy_hal.cpp
+++ b/wifi/1.2/default/wifi_legacy_hal.cpp
@@ -309,6 +309,15 @@
on_nan_event_range_report_user_callback(*event);
}
}
+
+std::function<void(const NanDataPathScheduleUpdateInd&)>
+ on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_schedule_update_user_callback && event) {
+ on_nan_event_schedule_update_user_callback(*event);
+ }
+}
// End of the free-standing "C" style callbacks.
WifiLegacyHal::WifiLegacyHal()
@@ -1061,6 +1070,8 @@
user_callbacks.on_event_range_request;
on_nan_event_range_report_user_callback =
user_callbacks.on_event_range_report;
+ on_nan_event_schedule_update_user_callback =
+ user_callbacks.on_event_schedule_update;
return global_func_table_.wifi_nan_register_handler(
getIfaceHandle(iface_name),
@@ -1072,7 +1083,7 @@
onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
- onAysncNanEventRangeReport});
+ onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
}
wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
@@ -1330,6 +1341,7 @@
on_nan_event_transmit_follow_up_user_callback = nullptr;
on_nan_event_range_request_user_callback = nullptr;
on_nan_event_range_report_user_callback = nullptr;
+ on_nan_event_schedule_update_user_callback = nullptr;
}
} // namespace legacy_hal
diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h
index 64a3f0a..da88f6b 100644
--- a/wifi/1.2/default/wifi_legacy_hal.h
+++ b/wifi/1.2/default/wifi_legacy_hal.h
@@ -100,6 +100,7 @@
on_event_transmit_follow_up;
std::function<void(const NanRangeRequestInd&)> on_event_range_request;
std::function<void(const NanRangeReportInd&)> on_event_range_report;
+ std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
};
// Full scan results contain IE info and are hence passed by reference, to
diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.2/default/wifi_nan_iface.cpp
index 7a597ae..12e4d7b 100644
--- a/wifi/1.2/default/wifi_nan_iface.cpp
+++ b/wifi/1.2/default/wifi_nan_iface.cpp
@@ -467,6 +467,11 @@
LOG(ERROR) << "on_event_range_report - should not be called";
};
+ callback_handlers.on_event_schedule_update =
+ [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& /* msg */) {
+ LOG(ERROR) << "on_event_schedule_update - should not be called";
+ };
+
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
callback_handlers);