Loading automotive/vehicle/2.0/default/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES := \ LOCAL_SRC_FILES:= \ tests/AccessControlConfigParser_test.cpp \ tests/RecurrentTimer_test.cpp \ tests/SubscriptionManager_test.cpp \ tests/VehicleHalManager_test.cpp \ tests/VehicleObjectPool_test.cpp \ Loading automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * 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 automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h +59 −25 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -50,10 +51,8 @@ public: } 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; Loading Loading @@ -85,15 +84,29 @@ struct HalClientValues { 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 Loading @@ -103,30 +116,48 @@ public: 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>; Loading @@ -136,6 +167,9 @@ private: 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; }; Loading automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h +5 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,9 @@ struct Caller { class VehicleHalManager : public IVehicle { public: VehicleHalManager(VehicleHal* vehicleHal) : mHal(vehicleHal) { : mHal(vehicleHal), mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed, this, std::placeholders::_1)) { init(); } Loading Loading @@ -105,6 +107,8 @@ private: int32_t propertyId, VehiclePropertyAccess requiredAccess) const; void onAllClientsUnsubscribed(int32_t propertyId); static bool isSubscribable(const VehiclePropConfig& config, SubscribeFlags flags); static bool isSampleRateFixed(VehiclePropertyChangeMode mode); Loading automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp +62 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "SubscriptionManager.h" #include <cmath> #include <inttypes.h> #include <android/log.h> Loading Loading @@ -58,6 +59,8 @@ bool mergeSubscribeOptions(const SubscribeOptions &oldOpts, } 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); Loading @@ -84,17 +87,33 @@ bool HalClient::isSubscribed(int32_t propId, 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); Loading @@ -102,12 +121,12 @@ std::list<SubscribeOptions> SubscriptionManager::addOrUpdateSubscription( 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( Loading Loading @@ -205,6 +224,14 @@ sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked( 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(); Loading @@ -216,7 +243,7 @@ sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked( } } bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback, void SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback, int32_t propId) { MuxGuard g(mLock); auto propertyClients = getClientsForPropertyLocked(propId); Loading @@ -243,13 +270,39 @@ bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback, } 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); } } Loading Loading
automotive/vehicle/2.0/default/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES := \ LOCAL_SRC_FILES:= \ tests/AccessControlConfigParser_test.cpp \ tests/RecurrentTimer_test.cpp \ tests/SubscriptionManager_test.cpp \ tests/VehicleHalManager_test.cpp \ tests/VehicleObjectPool_test.cpp \ Loading
automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * 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
automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h +59 −25 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -50,10 +51,8 @@ public: } 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; Loading Loading @@ -85,15 +84,29 @@ struct HalClientValues { 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 Loading @@ -103,30 +116,48 @@ public: 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>; Loading @@ -136,6 +167,9 @@ private: 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; }; Loading
automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h +5 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,9 @@ struct Caller { class VehicleHalManager : public IVehicle { public: VehicleHalManager(VehicleHal* vehicleHal) : mHal(vehicleHal) { : mHal(vehicleHal), mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed, this, std::placeholders::_1)) { init(); } Loading Loading @@ -105,6 +107,8 @@ private: int32_t propertyId, VehiclePropertyAccess requiredAccess) const; void onAllClientsUnsubscribed(int32_t propertyId); static bool isSubscribable(const VehiclePropConfig& config, SubscribeFlags flags); static bool isSampleRateFixed(VehiclePropertyChangeMode mode); Loading
automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp +62 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "SubscriptionManager.h" #include <cmath> #include <inttypes.h> #include <android/log.h> Loading Loading @@ -58,6 +59,8 @@ bool mergeSubscribeOptions(const SubscribeOptions &oldOpts, } 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); Loading @@ -84,17 +87,33 @@ bool HalClient::isSubscribed(int32_t propId, 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); Loading @@ -102,12 +121,12 @@ std::list<SubscribeOptions> SubscriptionManager::addOrUpdateSubscription( 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( Loading Loading @@ -205,6 +224,14 @@ sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked( 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(); Loading @@ -216,7 +243,7 @@ sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked( } } bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback, void SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback, int32_t propId) { MuxGuard g(mLock); auto propertyClients = getClientsForPropertyLocked(propId); Loading @@ -243,13 +270,39 @@ bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback, } 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); } } Loading