Merge "Add VTS tests for the primary audio hal"
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
index cdc8ded..6ccdbcd 100644
--- a/audio/2.0/default/StreamOut.cpp
+++ b/audio/2.0/default/StreamOut.cpp
@@ -79,10 +79,6 @@
ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
if (writeResult >= 0) {
mStatus.reply.written = writeResult;
- // Diagnostics of the cause of b/35813113.
- ALOGE_IF(writeResult > availToRead,
- "legacy hal reports more bytes written than asked for: %lld > %lld",
- (long long)writeResult, (long long)availToRead);
} else {
mStatus.retval = Stream::analyzeStatus("write", writeResult);
}
diff --git a/audio/common/2.0/types.hal b/audio/common/2.0/types.hal
index ae7f545..93b898b 100644
--- a/audio/common/2.0/types.hal
+++ b/audio/common/2.0/types.hal
@@ -537,6 +537,7 @@
/* audio bus implemented by the audio system (e.g an MOST stereo channel) */
OUT_BUS = 0x1000000,
OUT_PROXY = 0x2000000,
+ OUT_USB_HEADSET = 0x4000000,
OUT_DEFAULT = BIT_DEFAULT,
OUT_ALL = (OUT_EARPIECE |
OUT_SPEAKER |
@@ -603,6 +604,7 @@
/* audio bus implemented by the audio system (e.g an MOST stereo channel) */
IN_BUS = BIT_IN | 0x100000,
IN_PROXY = BIT_IN | 0x1000000,
+ IN_USB_HEADSET = BIT_IN | 0x2000000,
IN_DEFAULT = BIT_IN | BIT_DEFAULT,
IN_ALL = (IN_COMMUNICATION |
@@ -670,6 +672,7 @@
DIRECT_PCM = 0x2000, // Audio stream containing PCM data that needs
// to pass through compress path for DSP post proc.
MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+ VOIP_CALL_RX = 0x8000, // preferred output for VoIP calls.
};
/*
@@ -680,12 +683,13 @@
*/
@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
enum AudioInputFlag : int32_t {
- NONE = 0x0, // no attributes
- FAST = 0x1, // prefer an input that supports "fast tracks"
- HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
- RAW = 0x4, // minimize signal processing
- SYNC = 0x8, // synchronize I/O streams
- MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
+ NONE = 0x0, // no attributes
+ FAST = 0x1, // prefer an input that supports "fast tracks"
+ HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
+ RAW = 0x4, // minimize signal processing
+ SYNC = 0x8, // synchronize I/O streams
+ MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
+ VOIP_CALL_TX = 0x20, // preferred input for VoIP calls.
};
@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
index ba4a6cd..9b3323d 100644
--- a/automotive/vehicle/2.0/default/Android.mk
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -118,6 +118,7 @@
LOCAL_SRC_FILES:= \
tests/AccessControlConfigParser_test.cpp \
+ tests/RecurrentTimer_test.cpp \
tests/SubscriptionManager_test.cpp \
tests/VehicleHalManager_test.cpp \
tests/VehicleObjectPool_test.cpp \
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
new file mode 100644
index 0000000..be25adc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
@@ -0,0 +1,149 @@
+/*
+ * 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_automotive_vehicle_V2_0_RecurrentTimer_H_
+#define android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <functional>
+#include <list>
+#include <mutex>
+#include <set>
+#include <thread>
+#include <unordered_map>
+
+/**
+ * This class allows to specify multiple time intervals to receive
+ * notifications. A single thread is used internally.
+ */
+class RecurrentTimer {
+private:
+ using Nanos = std::chrono::nanoseconds;
+ using Clock = std::chrono::steady_clock;
+ using TimePoint = std::chrono::time_point<Clock, Nanos>;
+public:
+ using Action = std::function<void(const std::vector<int32_t>& cookies)>;
+
+ RecurrentTimer(const Action& action) : mAction(action) {
+ mTimerThread = std::thread(&RecurrentTimer::loop, this, action);
+ }
+
+ virtual ~RecurrentTimer() {
+ stop();
+ }
+
+ /**
+ * Registers recurrent event for a given interval. Registred events are distinguished by
+ * cookies thus calling this method multiple times with the same cookie will override the
+ * interval provided before.
+ */
+ void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) {
+ TimePoint now = Clock::now();
+ // Align event time point among all intervals. Thus if we have two intervals 1ms and 2ms,
+ // during every second wake-up both intervals will be triggered.
+ TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());
+
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime };
+ }
+ mCond.notify_one();
+ }
+
+ void unregisterRecurrentEvent(int32_t cookie) {
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ mCookieToEventsMap.erase(cookie);
+ }
+ mCond.notify_one();
+ }
+
+
+private:
+
+ struct RecurrentEvent {
+ Nanos interval;
+ int32_t cookie;
+ TimePoint absoluteTime; // Absolute time of the next event.
+
+ void updateNextEventTime(TimePoint now) {
+ // We want to move time to next event by adding some number of intervals (usually 1)
+ // to previous absoluteTime.
+ int intervalMultiplier = (now - absoluteTime) / interval;
+ if (intervalMultiplier <= 0) intervalMultiplier = 1;
+ absoluteTime += intervalMultiplier * interval;
+ }
+ };
+
+ void loop(const Action& action) {
+ static constexpr auto kInvalidTime = TimePoint(Nanos::max());
+
+ std::vector<int32_t> cookies;
+
+ while (!mStopRequested) {
+ auto now = Clock::now();
+ auto nextEventTime = kInvalidTime;
+ cookies.clear();
+
+ {
+ std::unique_lock<std::mutex> g(mLock);
+
+ for (auto&& it : mCookieToEventsMap) {
+ RecurrentEvent& event = it.second;
+ if (event.absoluteTime <= now) {
+ event.updateNextEventTime(now);
+ cookies.push_back(event.cookie);
+ }
+
+ if (nextEventTime > event.absoluteTime) {
+ nextEventTime = event.absoluteTime;
+ }
+ }
+ }
+
+ if (cookies.size() != 0) {
+ action(cookies);
+ }
+
+ std::unique_lock<std::mutex> g(mLock);
+ mCond.wait_until(g, nextEventTime); // nextEventTime can be nanoseconds::max()
+ }
+ }
+
+ void stop() {
+ mStopRequested = true;
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ mCookieToEventsMap.clear();
+ }
+ mCond.notify_one();
+ if (mTimerThread.joinable()) {
+ mTimerThread.join();
+ }
+ }
+private:
+ mutable std::mutex mLock;
+ std::thread mTimerThread;
+ std::condition_variable mCond;
+ std::atomic_bool mStopRequested { false };
+ Action mAction;
+ std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap;
+};
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
index 6a12b77..a808c66 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
@@ -23,6 +23,7 @@
#include <list>
#include <android/log.h>
+#include <hidl/HidlSupport.h>
#include <hwbinder/IPCThreadState.h>
#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
@@ -50,10 +51,8 @@
}
void addOrUpdateSubscription(const SubscribeOptions &opts);
-
- bool isSubscribed(int32_t propId,
- int32_t areaId,
- SubscribeFlags flags);
+ bool isSubscribed(int32_t propId, int32_t areaId, SubscribeFlags flags);
+ std::vector<int32_t> getSubscribedProperties() const;
private:
const sp<IVehicleCallback> mCallback;
@@ -85,15 +84,29 @@
class SubscriptionManager {
public:
- virtual ~SubscriptionManager() {}
+ using OnPropertyUnsubscribed = std::function<void(int32_t)>;
+
+ /**
+ * Constructs SubscriptionManager
+ *
+ * @param onPropertyUnsubscribed - this callback function will be called when there are no
+ * more client subscribed to particular property.
+ */
+ SubscriptionManager(const OnPropertyUnsubscribed& onPropertyUnsubscribed)
+ : mOnPropertyUnsubscribed(onPropertyUnsubscribed),
+ mCallbackDeathRecipient(new DeathRecipient(
+ std::bind(&SubscriptionManager::onCallbackDead, this, std::placeholders::_1)))
+ {}
+
+ ~SubscriptionManager() = default;
/**
* Updates subscription. Returns the vector of properties subscription that
* needs to be updated in VehicleHAL.
*/
- std::list<SubscribeOptions> addOrUpdateSubscription(
- const sp<IVehicleCallback>& callback,
- const hidl_vec<SubscribeOptions>& optionList);
+ StatusCode addOrUpdateSubscription(const sp<IVehicleCallback>& callback,
+ const hidl_vec<SubscribeOptions>& optionList,
+ std::list<SubscribeOptions>* outUpdatedOptions);
/**
* Returns a list of IVehicleCallback -> list of VehiclePropValue ready for
@@ -103,30 +116,48 @@
const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
SubscribeFlags flags) const;
- std::list<sp<HalClient>> getSubscribedClients(
- int32_t propId, int32_t area, SubscribeFlags flags) const;
-
+ std::list<sp<HalClient>> getSubscribedClients(int32_t propId,
+ int32_t area,
+ SubscribeFlags flags) const;
/**
- * Returns true the client was unsubscribed successfully and there are
- * no more clients subscribed to given propId.
+ * If there are no clients subscribed to given properties than callback function provided
+ * in the constructor will be called.
*/
- bool unsubscribe(const sp<IVehicleCallback>& callback,
- int32_t propId);
+ void unsubscribe(const sp<IVehicleCallback>& callback, int32_t propId);
private:
- std::list<sp< HalClient>> getSubscribedClientsLocked(
- int32_t propId, int32_t area, SubscribeFlags flags) const;
+ std::list<sp<HalClient>> getSubscribedClientsLocked(int32_t propId,
+ int32_t area,
+ SubscribeFlags flags) const;
- bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts,
- SubscribeOptions *out);
+ bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts, SubscribeOptions* out);
- void addClientToPropMapLocked(int32_t propId,
- const sp<HalClient> &client);
+ void addClientToPropMapLocked(int32_t propId, const sp<HalClient>& client);
- sp<HalClientVector> getClientsForPropertyLocked(
- int32_t propId) const;
+ sp<HalClientVector> getClientsForPropertyLocked(int32_t propId) const;
- sp<HalClient> getOrCreateHalClientLocked(
- const sp<IVehicleCallback> &callback);
+ sp<HalClient> getOrCreateHalClientLocked(const sp<IVehicleCallback> &callback);
+
+ void onCallbackDead(uint64_t cookie);
+
+private:
+ using OnClientDead = std::function<void(uint64_t)>;
+
+ class DeathRecipient : public hidl_death_recipient {
+ public:
+ DeathRecipient(const OnClientDead& onClientDead)
+ : mOnClientDead(onClientDead) {}
+ ~DeathRecipient() = default;
+
+ DeathRecipient(const DeathRecipient& ) = delete;
+ DeathRecipient& operator=(const DeathRecipient&) = delete;
+
+ void serviceDied(uint64_t cookie,
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+ mOnClientDead(cookie);
+ }
+ private:
+ OnClientDead mOnClientDead;
+ };
private:
using MuxGuard = std::lock_guard<std::mutex>;
@@ -136,6 +167,9 @@
std::map<sp<IVehicleCallback>, sp<HalClient>> mClients;
std::map<int32_t, sp<HalClientVector>> mPropToClients;
std::map<int32_t, SubscribeOptions> mHalEventSubscribeOptions;
+
+ OnPropertyUnsubscribed mOnPropertyUnsubscribed;
+ sp<DeathRecipient> mCallbackDeathRecipient;
};
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
index 4bff4d1..b8ab309 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -56,7 +56,9 @@
class VehicleHalManager : public IVehicle {
public:
VehicleHalManager(VehicleHal* vehicleHal)
- : mHal(vehicleHal) {
+ : mHal(vehicleHal),
+ mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed,
+ this, std::placeholders::_1)) {
init();
}
@@ -105,6 +107,8 @@
int32_t propertyId,
VehiclePropertyAccess requiredAccess) const;
+ void onAllClientsUnsubscribed(int32_t propertyId);
+
static bool isSubscribable(const VehiclePropConfig& config,
SubscribeFlags flags);
static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
diff --git a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
index f6f2758..4493a41 100644
--- a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
@@ -19,6 +19,7 @@
#include "SubscriptionManager.h"
#include <cmath>
+#include <inttypes.h>
#include <android/log.h>
@@ -58,6 +59,8 @@
}
void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts) {
+ ALOGI("%s opts.propId: 0x%x", __func__, opts.propId);
+
auto it = mSubscriptions.find(opts.propId);
if (it == mSubscriptions.end()) {
mSubscriptions.emplace(opts.propId, opts);
@@ -84,17 +87,33 @@
return res;
}
-std::list<SubscribeOptions> SubscriptionManager::addOrUpdateSubscription(
+std::vector<int32_t> HalClient::getSubscribedProperties() const {
+ std::vector<int32_t> props;
+ for (const auto& subscription : mSubscriptions) {
+ ALOGI("%s propId: 0x%x, propId: 0x%x", __func__, subscription.first, subscription.second.propId);
+ props.push_back(subscription.first);
+ }
+ return props;
+}
+
+StatusCode SubscriptionManager::addOrUpdateSubscription(
const sp<IVehicleCallback> &callback,
- const hidl_vec<SubscribeOptions> &optionList) {
- std::list<SubscribeOptions> updatedSubscriptions;
+ const hidl_vec<SubscribeOptions> &optionList,
+ std::list<SubscribeOptions>* outUpdatedSubscriptions) {
+ outUpdatedSubscriptions->clear();
MuxGuard g(mLock);
+ ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get());
+
const sp<HalClient>& client = getOrCreateHalClientLocked(callback);
+ if (client.get() == nullptr) {
+ return StatusCode::INTERNAL_ERROR;
+ }
for (size_t i = 0; i < optionList.size(); i++) {
const SubscribeOptions& opts = optionList[i];
+ ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId);
client->addOrUpdateSubscription(opts);
addClientToPropMapLocked(opts.propId, client);
@@ -102,12 +121,12 @@
if (SubscribeFlags::HAL_EVENT & opts.flags) {
SubscribeOptions updated;
if (updateHalEventSubscriptionLocked(opts, &updated)) {
- updatedSubscriptions.push_back(updated);
+ outUpdatedSubscriptions->push_back(updated);
}
}
}
- return updatedSubscriptions;
+ return StatusCode::OK;
}
std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
@@ -205,6 +224,14 @@
const sp<IVehicleCallback>& callback) {
auto it = mClients.find(callback);
if (it == mClients.end()) {
+ uint64_t cookie = reinterpret_cast<uint64_t>(callback.get());
+ ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie);
+ auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie);
+ if (!res.isOk()) { // Client is already dead?
+ ALOGW("%s failed to link to death, client %p, err: %s",
+ __func__, callback.get(), res.description().c_str());
+ return nullptr;
+ }
IPCThreadState* self = IPCThreadState::self();
pid_t pid = self->getCallingPid();
uid_t uid = self->getCallingUid();
@@ -216,7 +243,7 @@
}
}
-bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
+void SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
int32_t propId) {
MuxGuard g(mLock);
auto propertyClients = getClientsForPropertyLocked(propId);
@@ -243,13 +270,39 @@
}
if (!isClientSubscribedToOtherProps) {
+ auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient);
+ if (!res.isOk()) {
+ ALOGW("%s failed to unlink to death, client: %p, err: %s",
+ __func__, client->getCallback().get(), res.description().c_str());
+ }
mClients.erase(clientIter);
}
}
- return (propertyClients == nullptr || propertyClients->isEmpty())
- ? mHalEventSubscribeOptions.erase(propId) == 1
- : false;
+ if (propertyClients == nullptr || propertyClients->isEmpty()) {
+ mHalEventSubscribeOptions.erase(propId);
+ mOnPropertyUnsubscribed(propId);
+ }
+}
+
+void SubscriptionManager::onCallbackDead(uint64_t cookie) {
+ ALOGI("%s, cookie: 0x%" PRIx64, __func__, cookie);
+ IVehicleCallback* callback = reinterpret_cast<IVehicleCallback*>(cookie);
+
+ std::vector<int32_t> props;
+ {
+ MuxGuard g(mLock);
+ const auto& it = mClients.find(callback);
+ if (it == mClients.end()) {
+ return; // Nothing to do here, client wasn't subscribed to any properties.
+ }
+ const auto& halClient = it->second;
+ props = halClient->getSubscribedProperties();
+ }
+
+ for (int32_t propId : props) {
+ unsubscribe(callback, propId);
+ }
}
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index 3a5e504..8906f6e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -43,8 +43,7 @@
*/
constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
-Return<void> VehicleHalManager::getAllPropConfigs(
- getAllPropConfigs_cb _hidl_cb) {
+Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
ALOGI("getAllPropConfigs called");
hidl_vec<VehiclePropConfig> hidlConfigs;
auto& halConfig = mConfigIndex->getAllConfigs();
@@ -58,9 +57,8 @@
return Void();
}
-Return<void> VehicleHalManager::getPropConfigs(
- const hidl_vec<int32_t> &properties,
- getPropConfigs_cb _hidl_cb) {
+Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties,
+ getPropConfigs_cb _hidl_cb) {
std::vector<VehiclePropConfig> configs;
for (size_t i = 0; i < properties.size(); i++) {
auto prop = properties[i];
@@ -77,8 +75,7 @@
return Void();
}
-Return<void> VehicleHalManager::get(
- const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
+Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
const auto* config = getPropConfigOrNull(requestedPropValue.prop);
if (config == nullptr) {
ALOGE("Failed to get value: config not found, property: 0x%x",
@@ -119,9 +116,8 @@
return Return<StatusCode>(status);
}
-Return<StatusCode> VehicleHalManager::subscribe(
- const sp<IVehicleCallback> &callback,
- const hidl_vec<SubscribeOptions> &options) {
+Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
+ const hidl_vec<SubscribeOptions> &options) {
hidl_vec<SubscribeOptions> verifiedOptions(options);
auto caller = getCaller();
for (size_t i = 0; i < verifiedOptions.size(); i++) {
@@ -135,6 +131,11 @@
return StatusCode::INVALID_ARG;
}
+ if (ops.flags == SubscribeFlags::UNDEFINED) {
+ ALOGE("Failed to subscribe: undefined flag in options provided");
+ return StatusCode::INVALID_ARG;
+ }
+
if (!checkAcl(caller.uid, config->prop, VehiclePropertyAccess::READ)) {
return StatusCode::ACCESS_DENIED;
}
@@ -157,22 +158,24 @@
ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
}
- std::list<SubscribeOptions> updatedOptions =
- mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions);
+ std::list<SubscribeOptions> updatedOptions;
+ auto res = mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions,
+ &updatedOptions);
+ if (StatusCode::OK != res) {
+ ALOGW("%s failed to subscribe, error code: %d", __func__, res);
+ return res;
+ }
for (auto opt : updatedOptions) {
mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
}
- // TODO(pavelm): link to death callback (not implemented yet in HIDL)
return StatusCode::OK;
}
-Return<StatusCode> VehicleHalManager::unsubscribe(
- const sp<IVehicleCallback>& callback, int32_t propId) {
- if (mSubscriptionManager.unsubscribe(callback, propId)) {
- mHal->unsubscribe(propId);
- }
+Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
+ int32_t propId) {
+ mSubscriptionManager.unsubscribe(callback, propId);
return StatusCode::OK;
}
@@ -239,8 +242,7 @@
}
}
-void VehicleHalManager::onBatchHalEvent(
- const std::vector<VehiclePropValuePtr>& values) {
+void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
const auto& clientValues = mSubscriptionManager.distributeValuesToClients(
values, SubscribeFlags::HAL_EVENT);
@@ -257,7 +259,12 @@
for (VehiclePropValue* pValue : cv.values) {
shallowCopy(&(vec)[i++], *pValue);
}
- cv.client->getCallback()->onPropertyEvent(vec);
+ auto status = cv.client->getCallback()->onPropertyEvent(vec);
+ if (!status.isOk()) {
+ ALOGE("Failed to notify client %s, err: %s",
+ toString(cv.client->getCallback()).c_str(),
+ status.description().c_str());
+ }
}
}
@@ -379,6 +386,10 @@
}
}
+void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
+ mHal->unsubscribe(propertyId);
+}
+
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 9591689..596ad85 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -147,6 +147,15 @@
},
{
+ .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
+ .access = VehiclePropertyAccess::READ,
+ // TODO(bryaneyler): Support ON_CHANGE as well.
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 2.0f,
+ },
+
+ {
.prop = toInt(VehicleProperty::NIGHT_MODE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -192,6 +201,14 @@
.prop = toInt(VehicleProperty::IGNITION_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
+ .maxSampleRate = 10, // 10 Hz, every 100 ms
}
};
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
index 7a66c04..2214100 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -118,6 +118,7 @@
val.prop = protoVal.prop();
val.areaId = protoVal.area_id();
+ val.timestamp = elapsedRealtimeNano();
// Copy value data if it is set. This automatically handles complex data types if needed.
if (protoVal.has_string_value()) {
@@ -176,7 +177,7 @@
if (prop != mProps.end()) {
return prop->second.get();
}
- ALOGW("%s: Property not found: propId = 0x%x, areaId = 0x%x", __FUNCTION__, propId, areaId);
+ ALOGW("%s: Property not found: propId = 0x%x, areaId = 0x%x", __func__, propId, areaId);
return nullptr;
}
@@ -202,7 +203,7 @@
doSetProperty(rxMsg, respMsg);
break;
default:
- ALOGW("%s: Unknown message received, type = %d", __FUNCTION__, rxMsg.msg_type());
+ ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
break;
}
@@ -210,7 +211,7 @@
// Send the reply
txMsg(respMsg);
} else {
- ALOGE("%s: ParseFromString() failed. msgSize=%d", __FUNCTION__, static_cast<int>(msg.size()));
+ ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
}
}
@@ -266,7 +267,7 @@
}
break;
default:
- ALOGW("%s: Unknown property type: 0x%x", __FUNCTION__, toInt(getPropType(cfg.prop)));
+ ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
break;
}
@@ -317,7 +318,7 @@
parseRxProtoBuf(msg);
} else {
// This happens when connection is closed
- ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes,
+ ALOGD("%s: numBytes=%d, msgSize=%d", __func__, numBytes,
static_cast<int32_t>(msg.size()));
break;
}
@@ -396,6 +397,9 @@
case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
prop->value.floatValues[0] = 16;
break;
+ case toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE):
+ prop->value.floatValues[0] = 25;
+ break;
case toInt(VehicleProperty::NIGHT_MODE):
prop->value.int32Values[0] = 0;
break;
@@ -408,6 +412,9 @@
case toInt(VehicleProperty::INFO_FUEL_CAPACITY):
prop->value.floatValues[0] = 0.75f;
break;
+ case toInt(VehicleProperty::ENGINE_OIL_TEMP):
+ prop->value.floatValues[0] = 101;
+ break;
case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
prop->value.int32Values[0] = 7;
break;
@@ -415,7 +422,7 @@
prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON);
break;
default:
- ALOGW("%s: propId=0x%x not found", __FUNCTION__, prop->prop);
+ ALOGW("%s: propId=0x%x not found", __func__, prop->prop);
break;
}
}
@@ -434,10 +441,10 @@
}
if (retVal < 0) {
- ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __FUNCTION__, retVal, errno);
+ ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
}
} else {
- ALOGE("%s: SerializeToString failed!", __FUNCTION__);
+ ALOGE("%s: SerializeToString failed!", __func__);
}
}
@@ -453,7 +460,7 @@
VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId);
if (internalPropValue != nullptr) {
internalPropValue->value = propValue.value;
- internalPropValue->timestamp = elapsedRealtimeNano();
+ internalPropValue->timestamp = propValue.timestamp;
status = StatusCode::OK;
}
}
@@ -566,10 +573,8 @@
break;
}
continue;
- break;
- case VehiclePropertyType::MASK:
default:
- ALOGW("%s: propType=0x%x not found", __FUNCTION__, propType);
+ ALOGE("%s: propType=0x%x not found", __func__, propType);
vecSize = 0;
break;
}
@@ -602,6 +607,69 @@
mThread = std::thread(&DefaultVehicleHal::rxThread, this);
}
+void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
+ VehiclePropValuePtr v;
+
+ auto& pool = *getValuePool();
+
+ for (int32_t property : properties) {
+ if (isContinuousProperty(property)) {
+ // In real implementation this value should be read from sensor, random
+ // value used for testing purpose only.
+ std::lock_guard<std::mutex> lock(mPropsMutex);
+
+ VehiclePropValue *internalPropValue = getVehiclePropValueLocked(property);
+ if (internalPropValue != nullptr) {
+ v = pool.obtain(*internalPropValue);
+ }
+ if (VehiclePropertyType::FLOAT == getPropType(property)) {
+ // Just get some randomness to continuous properties to see slightly differnt values
+ // on the other end.
+ v->value.floatValues[0] = v->value.floatValues[0] + std::rand() % 5;
+ }
+ } else {
+ ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
+ }
+
+ if (v.get()) {
+ v->timestamp = elapsedRealtimeNano();
+ doHalEvent(std::move(v));
+ }
+ }
+}
+
+StatusCode DefaultVehicleHal::subscribe(int32_t property, int32_t,
+ float sampleRate) {
+ ALOGI("subscribe called for property: 0x%x, sampleRate: %f", property, sampleRate);
+
+ if (isContinuousProperty(property)) {
+ mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
+ }
+ return StatusCode::OK;
+}
+
+StatusCode DefaultVehicleHal::unsubscribe(int32_t property) {
+ ALOGI("%s propId: 0x%x", __func__, property);
+ if (isContinuousProperty(property)) {
+ mRecurrentTimer.unregisterRecurrentEvent(property);
+ }
+ return StatusCode::OK;
+}
+
+const VehiclePropConfig* DefaultVehicleHal::getPropConfig(int32_t propId) const {
+ auto it = mPropConfigMap.find(propId);
+ return it == mPropConfigMap.end() ? nullptr : it->second;
+}
+
+bool DefaultVehicleHal::isContinuousProperty(int32_t propId) const {
+ const VehiclePropConfig* config = getPropConfig(propId);
+ if (config == nullptr) {
+ ALOGW("Config not found for property: 0x%x", propId);
+ return false;
+ }
+ return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
+}
+
} // impl
} // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
index 1ad8702..98eef27 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
@@ -28,6 +28,7 @@
#include "CommBase.h"
#include "VehicleHalProto.pb.h"
+#include <vhal_v2_0/RecurrentTimer.h>
#include <vhal_v2_0/VehicleHal.h>
#include "DefaultConfig.h"
@@ -43,7 +44,13 @@
class DefaultVehicleHal : public VehicleHal {
public:
- DefaultVehicleHal() : mThread() {}
+ DefaultVehicleHal() : mRecurrentTimer(
+ std::bind(&DefaultVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) {
+ for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
+ mPropConfigMap[kVehicleProperties->prop] = &kVehicleProperties[i];
+ }
+ }
+
~DefaultVehicleHal() override {
// Notify thread to finish and wait for it to terminate
mExit = 1;
@@ -66,16 +73,9 @@
StatusCode set(const VehiclePropValue& propValue) override;
- StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) {
- ALOGD("%s: not implemented: prop=0x%x, areas=0x%x, rate=%f", __FUNCTION__, property,
- areas, sampleRate);
- return StatusCode::OK;
- }
+ StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
- StatusCode unsubscribe(int32_t property) {
- ALOGD("%s: not implemented: prop=0x%x", __FUNCTION__, property);
- return StatusCode::OK;
- }
+ StatusCode unsubscribe(int32_t property) override;
private:
void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
@@ -83,7 +83,9 @@
void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
- VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId);
+ VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId = 0);
+ const VehiclePropConfig* getPropConfig(int32_t propId) const;
+ bool isContinuousProperty(int32_t propId) const;
void parseRxProtoBuf(std::vector<uint8_t>& msg);
void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg);
@@ -94,6 +96,13 @@
void rxThread();
void txMsg(emulator::EmulatorMessage& txMsg);
StatusCode updateProperty(const VehiclePropValue& propValue);
+
+ constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
+ return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
+ }
+
+ void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
+
private:
std::map<
std::pair<int32_t /*VehicleProperty*/, int32_t /*areaId*/>,
@@ -103,6 +112,8 @@
std::mutex mPropsMutex;
std::thread mThread;
std::unique_ptr<CommBase> mComm{nullptr};
+ RecurrentTimer mRecurrentTimer;
+ std::unordered_map<int32_t, const VehiclePropConfig*> mPropConfigMap;
};
} // impl
diff --git a/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
new file mode 100644
index 0000000..9353baa
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 <thread>
+
+#include <gtest/gtest.h>
+
+#include "vhal_v2_0/RecurrentTimer.h"
+
+namespace {
+
+using std::chrono::nanoseconds;
+using std::chrono::milliseconds;
+
+#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \
+ASSERT_LE(val1 - tolerance, val2); \
+ASSERT_GE(val1 + tolerance, val2); \
+
+
+TEST(RecurrentTimerTest, oneInterval) {
+ std::atomic<int64_t> counter { 0L };
+ auto counterRef = std::ref(counter);
+ RecurrentTimer timer([&counterRef](const std::vector<int32_t>& cookies) {
+ ASSERT_EQ(1u, cookies.size());
+ ASSERT_EQ(0xDeadBeef, cookies.front());
+ counterRef.get()++;
+ });
+
+ timer.registerRecurrentEvent(milliseconds(1), 0xDeadBeef);
+ std::this_thread::sleep_for(milliseconds(100));
+ ASSERT_EQ_WITH_TOLERANCE(100, counter.load(), 20);
+}
+
+TEST(RecurrentTimerTest, multipleIntervals) {
+ std::atomic<int64_t> counter1ms { 0L };
+ std::atomic<int64_t> counter5ms { 0L };
+ auto counter1msRef = std::ref(counter1ms);
+ auto counter5msRef = std::ref(counter5ms);
+ RecurrentTimer timer(
+ [&counter1msRef, &counter5msRef](const std::vector<int32_t>& cookies) {
+ for (int32_t cookie : cookies) {
+ if (cookie == 0xdead) {
+ counter1msRef.get()++;
+ } else if (cookie == 0xbeef) {
+ counter5msRef.get()++;
+ } else {
+ FAIL();
+ }
+ }
+ });
+
+ timer.registerRecurrentEvent(milliseconds(1), 0xdead);
+ timer.registerRecurrentEvent(milliseconds(5), 0xbeef);
+
+ std::this_thread::sleep_for(milliseconds(100));
+ ASSERT_EQ_WITH_TOLERANCE(100, counter1ms.load(), 20);
+ ASSERT_EQ_WITH_TOLERANCE(20, counter5ms.load(), 5);
+}
+
+} // anonymous namespace
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
index e13d003..7ec9b79 100644
--- a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include <unordered_map>
+#include <functional>
#include <iostream>
+#include <unordered_map>
#include <gtest/gtest.h>
@@ -35,8 +36,9 @@
class SubscriptionManagerTest : public ::testing::Test {
public:
- SubscriptionManager manager;
+ SubscriptionManagerTest() : manager(([this](int x) { onPropertyUnsubscribed(x); })) {}
+ SubscriptionManager manager;
static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED);
static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
@@ -44,6 +46,10 @@
sp<IVehicleCallback> cb2 = new MockedVehicleCallback();
sp<IVehicleCallback> cb3 = new MockedVehicleCallback();
+ void SetUp() override {
+ lastUnsubscribedProperty = -1;
+ }
+
hidl_vec<SubscribeOptions> subscrToProp1 = {
SubscribeOptions {
.propId = PROP1,
@@ -90,12 +96,31 @@
return manager.getSubscribedClients(PROP2, 0,
SubscribeFlags::DEFAULT);
}
+
+ void onPropertyUnsubscribed(int propertyId) {
+ // Called when there are no clients who subscribed to particular property. This can happen
+ // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected.
+ lastUnsubscribedProperty = propertyId;
+ }
+
+ void assertOnPropertyUnsubscribedNotCalled() {
+ ASSERT_EQ(-1, lastUnsubscribedProperty);
+ }
+
+ void assertLastUnsubscribedProperty(int expectedPropertyId) {
+ ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty);
+ lastUnsubscribedProperty = -1;
+ }
+
+private:
+ int lastUnsubscribedProperty;
};
TEST_F(SubscriptionManagerTest, multipleClients) {
- manager.addOrUpdateSubscription(cb1, subscrToProp1);
- manager.addOrUpdateSubscription(cb2, subscrToProp1);
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp1, &updatedOptions));
auto clients = manager.getSubscribedClients(
PROP1,
@@ -106,7 +131,8 @@
}
TEST_F(SubscriptionManagerTest, negativeCases) {
- manager.addOrUpdateSubscription(cb1, subscrToProp1);
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
// Wrong zone
auto clients = manager.getSubscribedClients(
@@ -131,7 +157,8 @@
}
TEST_F(SubscriptionManagerTest, mulipleSubscriptions) {
- manager.addOrUpdateSubscription(cb1, subscrToProp1);
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
auto clients = manager.getSubscribedClients(
PROP1,
@@ -142,13 +169,13 @@
// Same property, but different zone, to make sure we didn't unsubscribe
// from previous zone.
- manager.addOrUpdateSubscription(cb1, {
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, {
SubscribeOptions {
.propId = PROP1,
.vehicleAreas = toInt(VehicleAreaZone::ROW_2),
.flags = SubscribeFlags::DEFAULT
}
- });
+ }, &updatedOptions));
clients = manager.getSubscribedClients(PROP1,
toInt(VehicleAreaZone::ROW_1_LEFT),
@@ -162,31 +189,38 @@
}
TEST_F(SubscriptionManagerTest, unsubscribe) {
- manager.addOrUpdateSubscription(cb1, subscrToProp1);
- manager.addOrUpdateSubscription(cb2, subscrToProp2);
- manager.addOrUpdateSubscription(cb3, subscrToProp1and2);
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp2, &updatedOptions));
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb3, subscrToProp1and2,
+ &updatedOptions));
ASSERT_ALL_EXISTS({cb1, cb3}, extractCallbacks(clientsToProp1()));
ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
- ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+ manager.unsubscribe(cb1, PROP1);
+ assertOnPropertyUnsubscribedNotCalled();
ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1()));
// Make sure nothing changed in PROP2 so far.
ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
// No one subscribed to PROP1, subscription for PROP2 is not affected.
- ASSERT_TRUE(manager.unsubscribe(cb3, PROP1));
+ manager.unsubscribe(cb3, PROP1);
+ assertLastUnsubscribedProperty(PROP1);
ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
- ASSERT_FALSE(manager.unsubscribe(cb3, PROP2));
+ manager.unsubscribe(cb3, PROP2);
+ assertOnPropertyUnsubscribedNotCalled();
ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2()));
// The last client unsubscribed from this property.
- ASSERT_TRUE(manager.unsubscribe(cb2, PROP2));
+ manager.unsubscribe(cb2, PROP2);
+ assertLastUnsubscribedProperty(PROP2);
- // No one was subscribed, return false.
- ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+ // No one subscribed anymore
+ manager.unsubscribe(cb1, PROP1);
+ assertLastUnsubscribedProperty(PROP1);
}
} // namespace anonymous
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
deleted file mode 100644
index ab0f308..0000000
--- a/benchmarks/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "msgq/1.0",
-]
diff --git a/benchmarks/msgq/1.0/Android.bp b/benchmarks/msgq/1.0/Android.bp
deleted file mode 100644
index 7f8ea99..0000000
--- a/benchmarks/msgq/1.0/Android.bp
+++ /dev/null
@@ -1,59 +0,0 @@
-// This file is autogenerated by hidl-gen. Do not edit manually.
-
-filegroup {
- name: "android.hardware.benchmarks.msgq@1.0_hal",
- srcs: [
- "IBenchmarkMsgQ.hal",
- ],
-}
-
-genrule {
- name: "android.hardware.benchmarks.msgq@1.0_genc++",
- tools: ["hidl-gen"],
- cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.benchmarks.msgq@1.0",
- srcs: [
- ":android.hardware.benchmarks.msgq@1.0_hal",
- ],
- out: [
- "android/hardware/benchmarks/msgq/1.0/BenchmarkMsgQAll.cpp",
- ],
-}
-
-genrule {
- name: "android.hardware.benchmarks.msgq@1.0_genc++_headers",
- tools: ["hidl-gen"],
- cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.benchmarks.msgq@1.0",
- srcs: [
- ":android.hardware.benchmarks.msgq@1.0_hal",
- ],
- out: [
- "android/hardware/benchmarks/msgq/1.0/IBenchmarkMsgQ.h",
- "android/hardware/benchmarks/msgq/1.0/IHwBenchmarkMsgQ.h",
- "android/hardware/benchmarks/msgq/1.0/BnHwBenchmarkMsgQ.h",
- "android/hardware/benchmarks/msgq/1.0/BpHwBenchmarkMsgQ.h",
- "android/hardware/benchmarks/msgq/1.0/BsBenchmarkMsgQ.h",
- ],
-}
-
-cc_library_shared {
- name: "android.hardware.benchmarks.msgq@1.0",
- generated_sources: ["android.hardware.benchmarks.msgq@1.0_genc++"],
- generated_headers: ["android.hardware.benchmarks.msgq@1.0_genc++_headers"],
- export_generated_headers: ["android.hardware.benchmarks.msgq@1.0_genc++_headers"],
- shared_libs: [
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "liblog",
- "libutils",
- "libcutils",
- "android.hidl.base@1.0",
- ],
- export_shared_lib_headers: [
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "libutils",
- "android.hidl.base@1.0",
- ],
-}
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
index 0e5f1fb..4268ddd 100644
--- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -481,6 +481,42 @@
EXPECT_EQ(Result::OK, hidlResult);
}
+/**
+ * Test ITuner::tune failing when channel out of the range is provided.
+ *
+ * Verifies that:
+ * - the method returns INVALID_ARGUMENTS when applicable
+ * - the method recovers and succeeds after passing correct arguments
+ */
+TEST_F(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
+ ASSERT_TRUE(openTuner());
+ ASSERT_TRUE(checkAntenna());
+
+ // get current channel bounds
+ BandConfig halConfig;
+ Result halResult;
+ auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ halConfig = config;
+ });
+ ASSERT_TRUE(configResult.isOk());
+ ASSERT_EQ(Result::OK, halResult);
+
+ // try to tune slightly above the limit and expect to fail
+ auto badChannel = halConfig.upperLimit + halConfig.spacings[0];
+ auto tuneResult = mTuner->tune(badChannel, 0);
+ EXPECT_TRUE(tuneResult.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+ // tuning exactly at the limit should succeed
+ auto goodChannel = halConfig.upperLimit;
+ tuneResult = mTuner->tune(goodChannel, 0);
+ EXPECT_TRUE(tuneResult.isOk());
+ EXPECT_EQ(Result::OK, tuneResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+}
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index c5eea89..40a05e6 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -42,8 +42,6 @@
using ::android::hardware::contexthub::V1_0::TransactionResult;
using ::android::sp;
-#define CONTEXTHUB_SERVICE_NAME "contexthub"
-
#define ASSERT_OK(result) ASSERT_EQ(result, Result::OK)
#define EXPECT_OK(result) EXPECT_EQ(result, Result::OK)
@@ -80,7 +78,7 @@
static std::vector<uint32_t> hubIds;
if (hubIds.size() == 0) {
- sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>(CONTEXTHUB_SERVICE_NAME);
+ sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>();
if (hubApi != nullptr) {
for (ContextHub hub : getHubsSync(hubApi)) {
@@ -98,7 +96,7 @@
class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetBaseTest {
public:
virtual void SetUp() override {
- hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>(CONTEXTHUB_SERVICE_NAME);
+ hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>();
ASSERT_NE(hubApi, nullptr);
// getHubs() must be called at least once for proper initialization of the
diff --git a/media/omx/1.0/IGraphicBufferSource.hal b/media/omx/1.0/IGraphicBufferSource.hal
index 4dbfd32..62073ad 100644
--- a/media/omx/1.0/IGraphicBufferSource.hal
+++ b/media/omx/1.0/IGraphicBufferSource.hal
@@ -29,25 +29,25 @@
*/
interface IGraphicBufferSource {
- configure(IOmxNode omxNode, Dataspace dataspace);
+ configure(IOmxNode omxNode, Dataspace dataspace) generates (Status status);
- setSuspend(bool suspend, int64_t timeUs);
+ setSuspend(bool suspend, int64_t timeUs) generates (Status status);
- setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs);
+ setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) generates (Status status);
- setMaxFps(float maxFps);
+ setMaxFps(float maxFps) generates (Status status);
- setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs);
+ setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) generates (Status status);
- setStartTimeUs(int64_t startTimeUs);
+ setStartTimeUs(int64_t startTimeUs) generates (Status status);
- setStopTimeUs(int64_t stopTimeUs);
+ setStopTimeUs(int64_t stopTimeUs) generates (Status status);
- setColorAspects(ColorAspects aspects);
+ setColorAspects(ColorAspects aspects) generates (Status status);
- setTimeOffsetUs(int64_t timeOffsetUs);
+ setTimeOffsetUs(int64_t timeOffsetUs) generates (Status status);
- signalEndOfInputStream();
+ signalEndOfInputStream() generates (Status status);
};
diff --git a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
index 5b6089d..4aa6d7e 100644
--- a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
+++ b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
@@ -325,18 +325,42 @@
}
/*
+ * PowerCycleAfterClose:
+ * Calls powerCycle() after close()
+ * Checks status
+ */
+TEST_F(NfcHidlTest, PowerCycleAfterClose) {
+ EXPECT_EQ(NfcStatus::OK, nfc_->close());
+ // Wait for CLOSE_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+
+ EXPECT_EQ(NfcStatus::FAILED, nfc_->powerCycle());
+
+ EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+ // Wait for OPEN_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
+/*
* CoreInitialized:
- * Calls coreInitialized()
+ * Calls coreInitialized() with different data
* Waits for NfcEvent.POST_INIT_CPLT
*/
TEST_F(NfcHidlTest, CoreInitialized) {
NfcData data;
data.resize(1);
- data[0] = 0;
- EXPECT_EQ(NfcStatus::OK, nfc_->coreInitialized(data));
- // Wait for NfcEvent.POST_INIT_CPLT
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(NfcEvent::POST_INIT_CPLT, last_event_);
+ for (int i = 0; i <= 6; i++)
+ {
+ data[0] = i;
+ EXPECT_EQ(NfcStatus::OK, nfc_->coreInitialized(data));
+ // Wait for NfcEvent.POST_INIT_CPLT
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::POST_INIT_CPLT, last_event_);
+ }
}
/*
@@ -348,6 +372,27 @@
EXPECT_EQ(NfcStatus::OK, nfc_->controlGranted());
}
+/*
+ * ControlGrantedAfterClose:
+ * Call controlGranted() after close
+ * Checks the return value
+ */
+TEST_F(NfcHidlTest, ControlGrantedAfterClose) {
+ EXPECT_EQ(NfcStatus::OK, nfc_->close());
+ // Wait for CLOSE_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+
+ EXPECT_EQ(NfcStatus::OK, nfc_->controlGranted());
+
+ EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+ // Wait for OPEN_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
/* PreDiscover:
* Calls prediscover()
* Checks the return value
@@ -356,6 +401,59 @@
EXPECT_EQ(NfcStatus::OK, nfc_->prediscover());
}
+/*
+ * PreDiscoverAfterClose:
+ * Call prediscover() after close
+ * Checks the return value
+ */
+TEST_F(NfcHidlTest, PreDiscoverAfterClose) {
+ EXPECT_EQ(NfcStatus::OK, nfc_->close());
+ // Wait for CLOSE_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+
+ EXPECT_EQ(NfcStatus::OK, nfc_->prediscover());
+
+ EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+ // Wait for OPEN_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
+/*
+ * CloseAfterClose:
+ * Calls close() multiple times
+ * Checks status
+ */
+TEST_F(NfcHidlTest, CloseAfterClose) {
+ EXPECT_EQ(NfcStatus::OK, nfc_->close());
+ // Wait for CLOSE_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::CLOSE_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+
+ EXPECT_EQ(NfcStatus::FAILED, nfc_->close());
+
+ EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+ // Wait for OPEN_CPLT event
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(NfcEvent::OPEN_CPLT, last_event_);
+ EXPECT_EQ(NfcStatus::OK, last_status_);
+}
+
+
+/*
+ * OpenAfterOpen:
+ * Calls open() multiple times
+ * Checks status
+ */
+TEST_F(NfcHidlTest, OpenAfterOpen) {
+ EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+ EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
+}
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(new NfcHidlEnvironment);
::testing::InitGoogleTest(&argc, argv);
diff --git a/radio/1.0/IRadio.hal b/radio/1.0/IRadio.hal
index a8c9d93..b3e3e98 100644
--- a/radio/1.0/IRadio.hal
+++ b/radio/1.0/IRadio.hal
@@ -731,20 +731,6 @@
oneway getDataCallList(int32_t serial);
/*
- * Indicates the current state of the screen. When the screen is off, the
- * Radio must notify the baseband to suppress certain notifications (eg,
- * signal strength and changes in LAC/CID or BID/SID/NID/latitude/longitude)
- * in an effort to conserve power. These notifications must resume when the
- * screen is on.
- *
- * @param serial Serial number of request.
- * @param enable true = screen on, false = screen off.
- *
- * Response function is IRadioResponse.sendScreenStateResponse()
- */
- oneway sendScreenState(int32_t serial, bool enable);
-
- /*
* Enables/disables supplementary service related notifications from the network.
* Notifications are reported via unsolSuppSvcNotification().
*
diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal
index 11a1d03..cd0899a 100644
--- a/radio/1.0/IRadioResponse.hal
+++ b/radio/1.0/IRadioResponse.hal
@@ -928,17 +928,6 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INVALID_ARGUMENTS
- * RadioError:GENERIC_FAILURE
- */
- oneway sendScreenStateResponse(RadioResponseInfo info);
-
- /*
- * @param info Response info struct containing response type, serial no. and error
- *
- * Valid errors returned:
- * RadioError:NONE
- * RadioError:RADIO_NOT_AVAILABLE
- * RadioError:INVALID_ARGUMENTS
* RadioError:SIM_BUSY
* RadioError:NO_MEMORY
* RadioError:SYSTEM_ERR
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_utils.h b/radio/1.0/vts/functional/radio_hidl_hal_utils.h
index 0429226..1c58a97 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_utils.h
+++ b/radio/1.0/vts/functional/radio_hidl_hal_utils.h
@@ -234,8 +234,6 @@
Return<void> sendOemRilRequestStringsResponse(const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
- Return<void> sendScreenStateResponse(const RadioResponseInfo& info);
-
Return<void> setSuppServiceNotificationsResponse(
const RadioResponseInfo& info);
diff --git a/radio/1.0/vts/functional/radio_response.cpp b/radio/1.0/vts/functional/radio_response.cpp
index 2b4f10f..64b09c9 100644
--- a/radio/1.0/vts/functional/radio_response.cpp
+++ b/radio/1.0/vts/functional/radio_response.cpp
@@ -314,11 +314,6 @@
return Void();
}
-Return<void> RadioResponse::sendScreenStateResponse(
- const RadioResponseInfo& /*info*/) {
- return Void();
-}
-
Return<void> RadioResponse::setSuppServiceNotificationsResponse(
const RadioResponseInfo& /*info*/) {
return Void();
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
index 4e0d01d..8aa9285 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -20,6 +20,7 @@
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
#include <hidl/Status.h>
+#include <stdatomic.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <system/sound_trigger.h>
diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
index 41e7e69..273ee14 100644
--- a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
+++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -15,6 +15,12 @@
*/
#define LOG_TAG "SoundTriggerHidlHalTest"
+#include <stdlib.h>
+#include <time.h>
+
+#include <condition_variable>
+#include <mutex>
+
#include <android/log.h>
#include <cutils/native_handle.h>
@@ -24,6 +30,8 @@
#include <VtsHalHidlTargetBaseTest.h>
+#define SHORT_TIMEOUT_PERIOD (1)
+
using ::android::hardware::audio::common::V2_0::AudioDevice;
using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
using ::android::hardware::soundtrigger::V2_0::SoundModelType;
@@ -36,43 +44,101 @@
using ::android::hardware::Void;
using ::android::sp;
+/**
+ * Test code uses this class to wait for notification from callback.
+ */
+class Monitor {
+ public:
+ Monitor() : mCount(0) {}
+
+ /**
+ * Adds 1 to the internal counter and unblocks one of the waiting threads.
+ */
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMtx);
+ mCount++;
+ mCv.notify_one();
+ }
+
+ /**
+ * Blocks until the internal counter becomes greater than 0.
+ *
+ * If notified, this method decreases the counter by 1 and returns true.
+ * If timeout, returns false.
+ */
+ bool wait(int timeoutSeconds) {
+ std::unique_lock<std::mutex> lock(mMtx);
+ auto deadline = std::chrono::system_clock::now() +
+ std::chrono::seconds(timeoutSeconds);
+ while (mCount == 0) {
+ if (mCv.wait_until(lock, deadline) == std::cv_status::timeout) {
+ return false;
+ }
+ }
+ mCount--;
+ return true;
+ }
+
+ private:
+ std::mutex mMtx;
+ std::condition_variable mCv;
+ int mCount;
+};
+
// The main test class for Sound Trigger HIDL HAL.
class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
public:
virtual void SetUp() override {
mSoundTriggerHal = ::testing::VtsHalHidlTargetBaseTest::getService<ISoundTriggerHw>("sound_trigger.primary");
ASSERT_NE(nullptr, mSoundTriggerHal.get());
- mCallback = new MyCallback();
+ mCallback = new SoundTriggerHwCallback(*this);
ASSERT_NE(nullptr, mCallback.get());
}
- class MyCallback : public ISoundTriggerHwCallback {
- virtual Return<void> recognitionCallback(
- const ISoundTriggerHwCallback::RecognitionEvent& event __unused,
- int32_t cookie __unused) {
- ALOGI("%s", __FUNCTION__);
- return Void();
- }
+ static void SetUpTestCase() {
+ srand(time(nullptr));
+ }
- virtual Return<void> phraseRecognitionCallback(
- const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
- int32_t cookie __unused) {
- ALOGI("%s", __FUNCTION__);
- return Void();
- }
+ class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
+ private:
+ SoundTriggerHidlTest& mParent;
- virtual Return<void> soundModelCallback(
- const ISoundTriggerHwCallback::ModelEvent& event __unused,
- int32_t cookie __unused) {
- ALOGI("%s", __FUNCTION__);
- return Void();
- }
+ public:
+ SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
+
+ virtual Return<void> recognitionCallback(
+ const ISoundTriggerHwCallback::RecognitionEvent& event __unused,
+ int32_t cookie __unused) {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ virtual Return<void> phraseRecognitionCallback(
+ const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+ int32_t cookie __unused) {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ virtual Return<void> soundModelCallback(
+ const ISoundTriggerHwCallback::ModelEvent& event,
+ int32_t cookie __unused) {
+ ALOGI("%s", __FUNCTION__);
+ mParent.lastModelEvent = event;
+ mParent.monitor.notify();
+ return Void();
+ }
};
virtual void TearDown() override {}
+ Monitor monitor;
+ // updated by soundModelCallback()
+ ISoundTriggerHwCallback::ModelEvent lastModelEvent;
+
+ protected:
sp<ISoundTriggerHw> mSoundTriggerHal;
- sp<MyCallback> mCallback;
+ sp<SoundTriggerHwCallback> mCallback;
};
// A class for test environment setup (kept since this file is a template).
@@ -137,6 +203,36 @@
EXPECT_TRUE(hidlReturn.isOk());
EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+ int ret = -ENODEV;
+ ISoundTriggerHw::SoundModel model;
+ SoundModelHandle handle = 0;
+
+ model.type = SoundModelType::GENERIC;
+ model.data.resize(100);
+ for (auto& d : model.data) {
+ d = rand();
+ }
+
+ Return<void> loadReturn = mSoundTriggerHal->loadSoundModel(
+ model,
+ mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(loadReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
}
/**
diff --git a/tests/msgq/1.0/Android.bp b/tests/msgq/1.0/Android.bp
index d17efe4..2d42699 100644
--- a/tests/msgq/1.0/Android.bp
+++ b/tests/msgq/1.0/Android.bp
@@ -3,6 +3,7 @@
filegroup {
name: "android.hardware.tests.msgq@1.0_hal",
srcs: [
+ "IBenchmarkMsgQ.hal",
"ITestMsgQ.hal",
],
}
@@ -15,6 +16,7 @@
":android.hardware.tests.msgq@1.0_hal",
],
out: [
+ "android/hardware/tests/msgq/1.0/BenchmarkMsgQAll.cpp",
"android/hardware/tests/msgq/1.0/TestMsgQAll.cpp",
],
}
@@ -27,6 +29,11 @@
":android.hardware.tests.msgq@1.0_hal",
],
out: [
+ "android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h",
+ "android/hardware/tests/msgq/1.0/IHwBenchmarkMsgQ.h",
+ "android/hardware/tests/msgq/1.0/BnHwBenchmarkMsgQ.h",
+ "android/hardware/tests/msgq/1.0/BpHwBenchmarkMsgQ.h",
+ "android/hardware/tests/msgq/1.0/BsBenchmarkMsgQ.h",
"android/hardware/tests/msgq/1.0/ITestMsgQ.h",
"android/hardware/tests/msgq/1.0/IHwTestMsgQ.h",
"android/hardware/tests/msgq/1.0/BnHwTestMsgQ.h",
diff --git a/benchmarks/msgq/1.0/IBenchmarkMsgQ.hal b/tests/msgq/1.0/IBenchmarkMsgQ.hal
similarity index 98%
rename from benchmarks/msgq/1.0/IBenchmarkMsgQ.hal
rename to tests/msgq/1.0/IBenchmarkMsgQ.hal
index c4b9d95..81754a4 100644
--- a/benchmarks/msgq/1.0/IBenchmarkMsgQ.hal
+++ b/tests/msgq/1.0/IBenchmarkMsgQ.hal
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.benchmarks.msgq@1.0;
+package android.hardware.tests.msgq@1.0;
interface IBenchmarkMsgQ {
/*
diff --git a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
index c0ae4d4..696b1f9 100644
--- a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
@@ -1,4 +1,4 @@
service wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
class hal
user wifi
- group wifi
+ group wifi gps
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 9042075..e0c92fe 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -36,11 +36,12 @@
using ::android::hardware::hidl_vec;
void stopFramework() {
- ASSERT_EQ(std::system("svc wifi disable"), 0);
+ ASSERT_EQ(std::system("stop"), 0);
+ stopWifi();
sleep(5);
}
-void startFramework() { ASSERT_EQ(std::system("svc wifi enable"), 0); }
+void startFramework() { ASSERT_EQ(std::system("start"), 0); }
sp<IWifi> getWifi() {
sp<IWifi> wifi = ::testing::VtsHalHidlTargetBaseTest::getService<IWifi>();
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index eb482c9..95c0e5d 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -17,24 +17,427 @@
#include <android-base/logging.h>
#include <android/hardware/wifi/1.0/IWifiNanIface.h>
+#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
#include <VtsHalHidlTargetBaseTest.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
-using ::android::hardware::wifi::V1_0::IWifiNanIface;
+using namespace ::android::hardware::wifi::V1_0;
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
using ::android::sp;
+#define TIMEOUT_PERIOD 10
+
/**
* Fixture to use for all NAN Iface HIDL interface tests.
*/
class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
- public:
- virtual void SetUp() override {}
+ public:
+ virtual void SetUp() override {
+ iwifiNanIface = getWifiNanIface();
+ ASSERT_NE(nullptr, iwifiNanIface.get());
+ ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback,
+ new WifiNanIfaceEventCallback(*this)).code);
+ }
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override {
+ stopWifi();
+ }
- protected:
+ /* Used as a mechanism to inform the test about data/event callback */
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ count_++;
+ cv_.notify_one();
+ }
+
+ enum CallbackType {
+ INVALID = -2,
+ ANY_CALLBACK = -1,
+
+ NOTIFY_CAPABILITIES_RESPONSE = 0,
+ NOTIFY_ENABLE_RESPONSE,
+ NOTIFY_CONFIG_RESPONSE,
+ NOTIFY_DISABLE_RESPONSE,
+ NOTIFY_START_PUBLISH_RESPONSE,
+ NOTIFY_STOP_PUBLISH_RESPONSE,
+ NOTIFY_START_SUBSCRIBE_RESPONSE,
+ NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+ NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+ NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+ NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+ NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+ NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+ NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+
+ EVENT_CLUSTER_EVENT,
+ EVENT_DISABLED,
+ EVENT_PUBLISH_TERMINATED,
+ EVENT_SUBSCRIBE_TERMINATED,
+ EVENT_MATCH,
+ EVENT_MATCH_EXPIRED,
+ EVENT_FOLLOWUP_RECEIVED,
+ EVENT_TRANSMIT_FOLLOWUP,
+ EVENT_DATA_PATH_REQUEST,
+ EVENT_DATA_PATH_CONFIRM,
+ EVENT_DATA_PATH_TERMINATED
+ };
+
+ /* Test code calls this function to wait for data/event callback */
+ inline std::cv_status wait(CallbackType waitForCallbackType) {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a non-void-returning method
+
+ callbackType = INVALID;
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count_ == 0) {
+ status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) return status;
+ if (waitForCallbackType != ANY_CALLBACK && callbackType != INVALID
+ && callbackType != waitForCallbackType) {
+ count_--;
+ }
+ }
+ count_--;
+ return status;
+ }
+
+ class WifiNanIfaceEventCallback: public IWifiNanIfaceEventCallback {
+ WifiNanIfaceHidlTest& parent_;
+
+ public:
+ WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent) : parent_(parent) {};
+
+ virtual ~WifiNanIfaceEventCallback() = default;
+
+ Return<void> notifyCapabilitiesResponse(
+ uint16_t id,
+ const WifiNanStatus& status,
+ const NanCapabilities& capabilities) override {
+ parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.capabilities = capabilities;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyEnableResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_ENABLE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyConfigResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_CONFIG_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyDisableResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_DISABLE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStartPublishResponse(
+ uint16_t id,
+ const WifiNanStatus& status,
+ uint8_t sessionId) override {
+ parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.sessionId = sessionId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStopPublishResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStartSubscribeResponse(
+ uint16_t id,
+ const WifiNanStatus& status,
+ uint8_t sessionId) override {
+ parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.sessionId = sessionId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStopSubscribeResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyTransmitFollowupResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyCreateDataInterfaceResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyDeleteDataInterfaceResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyInitiateDataPathResponse(
+ uint16_t id,
+ const WifiNanStatus& status,
+ uint32_t ndpInstanceId) override {
+ parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.ndpInstanceId = ndpInstanceId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyRespondToDataPathIndicationResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyTerminateDataPathResponse(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventClusterEvent(
+ const NanClusterEventInd& event) override {
+ parent_.callbackType = EVENT_CLUSTER_EVENT;
+
+ parent_.nanClusterEventInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDisabled(
+ const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_DISABLED;
+
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventPublishTerminated(
+ uint8_t sessionId,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_PUBLISH_TERMINATED;
+
+ parent_.sessionId = sessionId;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventSubscribeTerminated(
+ uint8_t sessionId,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED;
+
+ parent_.sessionId = sessionId;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventMatch(
+ const NanMatchInd& event) override {
+ parent_.callbackType = EVENT_MATCH;
+
+ parent_.nanMatchInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventMatchExpired(
+ uint8_t discoverySessionId,
+ uint32_t peerId) override {
+ parent_.callbackType = EVENT_MATCH_EXPIRED;
+
+ parent_.sessionId = discoverySessionId;
+ parent_.peerId = peerId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventFollowupReceived(
+ const NanFollowupReceivedInd& event) override {
+ parent_.callbackType = EVENT_FOLLOWUP_RECEIVED;
+
+ parent_.nanFollowupReceivedInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventTransmitFollowup(
+ uint16_t id,
+ const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathRequest(
+ const NanDataPathRequestInd& event) override {
+ parent_.callbackType = EVENT_DATA_PATH_REQUEST;
+
+ parent_.nanDataPathRequestInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathConfirm(
+ const NanDataPathConfirmInd& event) override {
+ parent_.callbackType = EVENT_DATA_PATH_CONFIRM;
+
+ parent_.nanDataPathConfirmInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathTerminated(
+ uint32_t ndpInstanceId) override {
+ parent_.callbackType = EVENT_DATA_PATH_TERMINATED;
+
+ parent_.ndpInstanceId = ndpInstanceId;
+
+ parent_.notify();
+ return Void();
+ }
+ };
+
+ private:
+ // synchronization objects
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_;
+
+ protected:
+ android::sp<IWifiNanIface> iwifiNanIface;
+
+ // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of all
+ // arguments to all callbacks. They are set by the callback (notifications or
+ // events) and can be retrieved by tests.
+ CallbackType callbackType;
+ uint16_t id;
+ WifiNanStatus status;
+ NanCapabilities capabilities;
+ uint8_t sessionId;
+ uint32_t ndpInstanceId;
+ NanClusterEventInd nanClusterEventInd;
+ NanMatchInd nanMatchInd;
+ uint32_t peerId;
+ NanFollowupReceivedInd nanFollowupReceivedInd;
+ NanDataPathRequestInd nanDataPathRequestInd;
+ NanDataPathConfirmInd nanDataPathConfirmInd;
};
/*
@@ -43,6 +446,49 @@
* successfully created.
*/
TEST(WifiNanIfaceHidlTestNoFixture, Create) {
- EXPECT_NE(nullptr, getWifiNanIface().get());
- stopWifi();
+ ASSERT_NE(nullptr, getWifiNanIface().get());
+ stopWifi();
+}
+
+/*
+ * Fail: use past destruction
+ * Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi
+ * is disabled.
+ */
+TEST(WifiNanIfaceHidlTestNoFixture, FailOnIfaceInvalid) {
+ android::sp<IWifiNanIface> iwifiNanIface = getWifiNanIface();
+ ASSERT_NE(nullptr, iwifiNanIface.get());
+ stopWifi();
+ sleep(5); // make sure that all chips/interfaces are invalidated
+ ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
+}
+
+/*
+ * getCapabilitiesRequest: validate that returns capabilities.
+ */
+TEST_F(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
+ uint16_t inputCmdId = 10;
+ ASSERT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code);
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
+ ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+
+ // check for reasonable capability values
+ EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int) 0);
+ EXPECT_GT(capabilities.maxPublishes, (unsigned int) 0);
+ EXPECT_GT(capabilities.maxSubscribes, (unsigned int) 0);
+ EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int) 255);
+ EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int) 255);
+ EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int) 255);
+ EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int) 255);
+ EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int) 255);
+ EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int) 0);
+ EXPECT_GT(capabilities.maxNdpSessions, (unsigned int) 0);
+ EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int) 0);
+ EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int) 0);
+ EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int) 0);
+ EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int) 0);
}