Loading automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h +3 −21 Original line number Diff line number Diff line Loading @@ -99,13 +99,10 @@ class GetSetValuesClient final : public ConnectedClient { std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback; }; // A class to represent a client that calls {@code IVehicle.subscribe}. class SubscriptionClient final : public ConnectedClient { class SubscriptionClient { public: SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback); // Gets the callback to be called when the request for this client has finished. std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback(); using CallbackType = std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>; // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent} // callback. Loading @@ -119,21 +116,6 @@ class SubscriptionClient final : public ConnectedClient { CallbackType callback, std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&& vehiclePropErrors); protected: // Gets the callback to be called when the request for this client has timeout. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override; private: // The following members are only initialized during construction. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback; std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback; std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback; static void onGetValueResults( const void* clientId, CallbackType callback, std::shared_ptr<PendingRequestPool> requestPool, std::vector<aidl::android::hardware::automotive::vehicle::GetValueResult> results); }; } // namespace vehicle Loading automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h +2 −35 Original line number Diff line number Diff line Loading @@ -90,39 +90,6 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult, aidl::android::hardware::automotive::vehicle::SetValueResults>; // A thread safe class to maintain an increasing request ID for each subscribe client. This // class is safe to pass to async callbacks. class SubscribeIdByClient { public: int64_t getId(const CallbackType& callback); private: std::mutex mLock; std::unordered_map<const AIBinder*, int64_t> mIds GUARDED_BY(mLock); }; // A thread safe class to store all subscribe clients. This class is safe to pass to async // callbacks. class SubscriptionClients { public: SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {} std::shared_ptr<SubscriptionClient> maybeAddClient(const CallbackType& callback); std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback); void removeClient(const AIBinder* clientId); size_t countClients(); private: std::mutex mLock; std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>> mClients GUARDED_BY(mLock); // PendingRequestPool is thread-safe. std::shared_ptr<PendingRequestPool> mPendingRequestPool; }; // A wrapper for binder lifecycle operations to enable stubbing for test. class BinderLifecycleInterface { public: Loading Loading @@ -185,8 +152,6 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi GUARDED_BY(mLock); std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>> mSetValuesClients GUARDED_BY(mLock); // SubscriptionClients is thread-safe. std::shared_ptr<SubscriptionClients> mSubscriptionClients; // mBinderLifecycleHandler is only going to be changed in test. std::unique_ptr<BinderLifecycleInterface> mBinderLifecycleHandler; Loading Loading @@ -242,6 +207,8 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi // mBinderEvents. void onBinderDiedUnlinkedHandler(); size_t countSubscribeClients(); // Gets or creates a {@code T} object for the client to or from {@code clients}. template <class T> static std::shared_ptr<T> getOrCreateClient( Loading automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h +3 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ class SubscriptionManager final { std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>> getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents); // Returns the number of subscribed clients. size_t countClients(); // Checks whether the sample rate is valid. static bool checkSampleRateHz(float sampleRateHz); Loading automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp +0 −67 Original line number Diff line number Diff line Loading @@ -250,36 +250,6 @@ void GetSetValuesClient<ResultType, ResultsType>::sendResultsSeparately( template class GetSetValuesClient<GetValueResult, GetValueResults>; template class GetSetValuesClient<SetValueResult, SetValueResults>; SubscriptionClient::SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback) : ConnectedClient(requestPool, callback) { mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>( [](std::unordered_set<int64_t> timeoutIds) { for (int64_t id : timeoutIds) { ALOGW("subscribe: requests with IDs: %" PRId64 " has timed-out, not client informed, " "possibly one of recurrent requests for this subscription failed", id); } }); auto requestPoolCopy = mRequestPool; const void* clientId = reinterpret_cast<const void*>(this); mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>( [clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) { onGetValueResults(clientId, callback, requestPoolCopy, results); }); } std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> SubscriptionClient::getResultCallback() { return mResultCallback; } std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> SubscriptionClient::getTimeoutCallback() { return mTimeoutCallback; } void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback, std::vector<VehiclePropValue>&& updatedValues) { if (updatedValues.empty()) { Loading Loading @@ -336,43 +306,6 @@ void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> } } void SubscriptionClient::onGetValueResults(const void* clientId, std::shared_ptr<IVehicleCallback> callback, std::shared_ptr<PendingRequestPool> requestPool, std::vector<GetValueResult> results) { std::unordered_set<int64_t> requestIds; for (const auto& result : results) { requestIds.insert(result.requestId); } auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds); std::vector<VehiclePropValue> propValues; for (auto& result : results) { int64_t requestId = result.requestId; if (finishedRequests.find(requestId) == finishedRequests.end()) { ALOGE("subscribe[%" PRId64 "]: no pending request for the result from hardware, " "possibly already time-out", requestId); continue; } if (result.status != StatusCode::OK) { ALOGE("subscribe[%" PRId64 "]: hardware returns non-ok status for getValues, status: " "%d", requestId, toInt(result.status)); continue; } if (!result.prop.has_value()) { ALOGE("subscribe[%" PRId64 "]: no prop value in getValues result", requestId); continue; } propValues.push_back(std::move(result.prop.value())); } sendUpdatedValues(callback, std::move(propValues)); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +5 −46 Original line number Diff line number Diff line Loading @@ -92,39 +92,6 @@ float getDefaultSampleRateHz(float sampleRateHz, float minSampleRateHz, float ma } // namespace std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::maybeAddClient( const CallbackType& callback) { std::scoped_lock<std::mutex> lockGuard(mLock); return getOrCreateClient(&mClients, callback, mPendingRequestPool); } std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient( const CallbackType& callback) { std::scoped_lock<std::mutex> lockGuard(mLock); const AIBinder* clientId = callback->asBinder().get(); if (mClients.find(clientId) == mClients.end()) { return nullptr; } return mClients[clientId]; } int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) { std::scoped_lock<std::mutex> lockGuard(mLock); // This would be initialized to 0 if callback does not exist in the map. int64_t subscribeId = (mIds[callback->asBinder().get()])++; return subscribeId; } void DefaultVehicleHal::SubscriptionClients::removeClient(const AIBinder* clientId) { std::scoped_lock<std::mutex> lockGuard(mLock); mClients.erase(clientId); } size_t DefaultVehicleHal::SubscriptionClients::countClients() { std::scoped_lock<std::mutex> lockGuard(mLock); return mClients.size(); } DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware) : mVehicleHardware(std::move(vehicleHardware)), mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) { Loading @@ -132,9 +99,6 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHa return; } mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool); auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>(); IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get(); mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr); Loading Loading @@ -262,7 +226,6 @@ void DefaultVehicleHal::onBinderDiedWithContext(const AIBinder* clientId) { ALOGD("binder died, client ID: %p", clientId); mSetValuesClients.erase(clientId); mGetValuesClients.erase(clientId); mSubscriptionClients->removeClient(clientId); mSubscriptionManager->unsubscribe(clientId); } Loading Loading @@ -301,10 +264,6 @@ template std::shared_ptr<DefaultVehicleHal::SetValuesClient> DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>( std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>>* clients, const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool); template std::shared_ptr<SubscriptionClient> DefaultVehicleHal::getOrCreateClient<SubscriptionClient>( std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>>* clients, const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool); void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) { mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano); Loading Loading @@ -708,9 +667,6 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback, "client died"); } // Create a new SubscriptionClient if there isn't an existing one. mSubscriptionClients->maybeAddClient(callback); if (!onChangeSubscriptions.empty()) { auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions, /*isContinuousProperty=*/false); Loading Loading @@ -842,12 +798,15 @@ binder_status_t DefaultVehicleHal::dump(int fd, const char** args, uint32_t numA dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size()); dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size()); dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size()); dprintf(fd, "Currently have %zu subscription clients\n", mSubscriptionClients->countClients()); dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients()); } return STATUS_OK; } size_t DefaultVehicleHal::countSubscribeClients() { return mSubscriptionManager->countClients(); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading Loading
automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h +3 −21 Original line number Diff line number Diff line Loading @@ -99,13 +99,10 @@ class GetSetValuesClient final : public ConnectedClient { std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback; }; // A class to represent a client that calls {@code IVehicle.subscribe}. class SubscriptionClient final : public ConnectedClient { class SubscriptionClient { public: SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback); // Gets the callback to be called when the request for this client has finished. std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback(); using CallbackType = std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>; // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent} // callback. Loading @@ -119,21 +116,6 @@ class SubscriptionClient final : public ConnectedClient { CallbackType callback, std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&& vehiclePropErrors); protected: // Gets the callback to be called when the request for this client has timeout. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override; private: // The following members are only initialized during construction. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback; std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback; std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback; static void onGetValueResults( const void* clientId, CallbackType callback, std::shared_ptr<PendingRequestPool> requestPool, std::vector<aidl::android::hardware::automotive::vehicle::GetValueResult> results); }; } // namespace vehicle Loading
automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h +2 −35 Original line number Diff line number Diff line Loading @@ -90,39 +90,6 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult, aidl::android::hardware::automotive::vehicle::SetValueResults>; // A thread safe class to maintain an increasing request ID for each subscribe client. This // class is safe to pass to async callbacks. class SubscribeIdByClient { public: int64_t getId(const CallbackType& callback); private: std::mutex mLock; std::unordered_map<const AIBinder*, int64_t> mIds GUARDED_BY(mLock); }; // A thread safe class to store all subscribe clients. This class is safe to pass to async // callbacks. class SubscriptionClients { public: SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {} std::shared_ptr<SubscriptionClient> maybeAddClient(const CallbackType& callback); std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback); void removeClient(const AIBinder* clientId); size_t countClients(); private: std::mutex mLock; std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>> mClients GUARDED_BY(mLock); // PendingRequestPool is thread-safe. std::shared_ptr<PendingRequestPool> mPendingRequestPool; }; // A wrapper for binder lifecycle operations to enable stubbing for test. class BinderLifecycleInterface { public: Loading Loading @@ -185,8 +152,6 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi GUARDED_BY(mLock); std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>> mSetValuesClients GUARDED_BY(mLock); // SubscriptionClients is thread-safe. std::shared_ptr<SubscriptionClients> mSubscriptionClients; // mBinderLifecycleHandler is only going to be changed in test. std::unique_ptr<BinderLifecycleInterface> mBinderLifecycleHandler; Loading Loading @@ -242,6 +207,8 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi // mBinderEvents. void onBinderDiedUnlinkedHandler(); size_t countSubscribeClients(); // Gets or creates a {@code T} object for the client to or from {@code clients}. template <class T> static std::shared_ptr<T> getOrCreateClient( Loading
automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h +3 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ class SubscriptionManager final { std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>> getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents); // Returns the number of subscribed clients. size_t countClients(); // Checks whether the sample rate is valid. static bool checkSampleRateHz(float sampleRateHz); Loading
automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp +0 −67 Original line number Diff line number Diff line Loading @@ -250,36 +250,6 @@ void GetSetValuesClient<ResultType, ResultsType>::sendResultsSeparately( template class GetSetValuesClient<GetValueResult, GetValueResults>; template class GetSetValuesClient<SetValueResult, SetValueResults>; SubscriptionClient::SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback) : ConnectedClient(requestPool, callback) { mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>( [](std::unordered_set<int64_t> timeoutIds) { for (int64_t id : timeoutIds) { ALOGW("subscribe: requests with IDs: %" PRId64 " has timed-out, not client informed, " "possibly one of recurrent requests for this subscription failed", id); } }); auto requestPoolCopy = mRequestPool; const void* clientId = reinterpret_cast<const void*>(this); mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>( [clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) { onGetValueResults(clientId, callback, requestPoolCopy, results); }); } std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> SubscriptionClient::getResultCallback() { return mResultCallback; } std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> SubscriptionClient::getTimeoutCallback() { return mTimeoutCallback; } void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback, std::vector<VehiclePropValue>&& updatedValues) { if (updatedValues.empty()) { Loading Loading @@ -336,43 +306,6 @@ void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> } } void SubscriptionClient::onGetValueResults(const void* clientId, std::shared_ptr<IVehicleCallback> callback, std::shared_ptr<PendingRequestPool> requestPool, std::vector<GetValueResult> results) { std::unordered_set<int64_t> requestIds; for (const auto& result : results) { requestIds.insert(result.requestId); } auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds); std::vector<VehiclePropValue> propValues; for (auto& result : results) { int64_t requestId = result.requestId; if (finishedRequests.find(requestId) == finishedRequests.end()) { ALOGE("subscribe[%" PRId64 "]: no pending request for the result from hardware, " "possibly already time-out", requestId); continue; } if (result.status != StatusCode::OK) { ALOGE("subscribe[%" PRId64 "]: hardware returns non-ok status for getValues, status: " "%d", requestId, toInt(result.status)); continue; } if (!result.prop.has_value()) { ALOGE("subscribe[%" PRId64 "]: no prop value in getValues result", requestId); continue; } propValues.push_back(std::move(result.prop.value())); } sendUpdatedValues(callback, std::move(propValues)); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading
automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +5 −46 Original line number Diff line number Diff line Loading @@ -92,39 +92,6 @@ float getDefaultSampleRateHz(float sampleRateHz, float minSampleRateHz, float ma } // namespace std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::maybeAddClient( const CallbackType& callback) { std::scoped_lock<std::mutex> lockGuard(mLock); return getOrCreateClient(&mClients, callback, mPendingRequestPool); } std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient( const CallbackType& callback) { std::scoped_lock<std::mutex> lockGuard(mLock); const AIBinder* clientId = callback->asBinder().get(); if (mClients.find(clientId) == mClients.end()) { return nullptr; } return mClients[clientId]; } int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) { std::scoped_lock<std::mutex> lockGuard(mLock); // This would be initialized to 0 if callback does not exist in the map. int64_t subscribeId = (mIds[callback->asBinder().get()])++; return subscribeId; } void DefaultVehicleHal::SubscriptionClients::removeClient(const AIBinder* clientId) { std::scoped_lock<std::mutex> lockGuard(mLock); mClients.erase(clientId); } size_t DefaultVehicleHal::SubscriptionClients::countClients() { std::scoped_lock<std::mutex> lockGuard(mLock); return mClients.size(); } DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware) : mVehicleHardware(std::move(vehicleHardware)), mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) { Loading @@ -132,9 +99,6 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHa return; } mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool); auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>(); IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get(); mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr); Loading Loading @@ -262,7 +226,6 @@ void DefaultVehicleHal::onBinderDiedWithContext(const AIBinder* clientId) { ALOGD("binder died, client ID: %p", clientId); mSetValuesClients.erase(clientId); mGetValuesClients.erase(clientId); mSubscriptionClients->removeClient(clientId); mSubscriptionManager->unsubscribe(clientId); } Loading Loading @@ -301,10 +264,6 @@ template std::shared_ptr<DefaultVehicleHal::SetValuesClient> DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>( std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>>* clients, const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool); template std::shared_ptr<SubscriptionClient> DefaultVehicleHal::getOrCreateClient<SubscriptionClient>( std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>>* clients, const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool); void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) { mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano); Loading Loading @@ -708,9 +667,6 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback, "client died"); } // Create a new SubscriptionClient if there isn't an existing one. mSubscriptionClients->maybeAddClient(callback); if (!onChangeSubscriptions.empty()) { auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions, /*isContinuousProperty=*/false); Loading Loading @@ -842,12 +798,15 @@ binder_status_t DefaultVehicleHal::dump(int fd, const char** args, uint32_t numA dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size()); dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size()); dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size()); dprintf(fd, "Currently have %zu subscription clients\n", mSubscriptionClients->countClients()); dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients()); } return STATUS_OK; } size_t DefaultVehicleHal::countSubscribeClients() { return mSubscriptionManager->countClients(); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading