1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_ 18 #define android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_ 19 20 #include <IVehicleHardware.h> 21 #include <VehicleHalTypes.h> 22 #include <VehicleUtils.h> 23 24 #include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h> 25 #include <android-base/result.h> 26 #include <android-base/thread_annotations.h> 27 28 #include <cmath> 29 #include <limits> 30 #include <mutex> 31 #include <optional> 32 #include <unordered_map> 33 #include <unordered_set> 34 #include <vector> 35 36 namespace android { 37 namespace hardware { 38 namespace automotive { 39 namespace vehicle { 40 41 // A structure to represent subscription config for one subscription client. 42 struct SubConfig { 43 float sampleRateHz; 44 float resolution; 45 bool enableVur; 46 }; 47 48 // A class to represent all the subscription configs for a continuous [propId, areaId]. 49 class ContSubConfigs final { 50 public: 51 using ClientIdType = const AIBinder*; 52 53 void addClient(const ClientIdType& clientId, const SubConfig& subConfig); 54 void removeClient(const ClientIdType& clientId); 55 float getMaxSampleRateHz() const; 56 float getMinRequiredResolution() const; 57 bool isVurEnabled() const; 58 bool isVurEnabledForClient(const ClientIdType& clientId) const; 59 float getResolutionForClient(const ClientIdType& clientId) const; 60 61 private: 62 float mMaxSampleRateHz = 0.; 63 // Baseline for resolution is maximum possible float. We want to sanitize to the highest 64 // requested resolution, which is the smallest float value for resolution. 65 float mMinRequiredResolution = std::numeric_limits<float>::max(); 66 bool mEnableVur; 67 std::unordered_map<ClientIdType, SubConfig> mConfigByClient; 68 69 void refreshCombinedConfig(); 70 }; 71 72 // A thread-safe subscription manager that manages all VHAL subscriptions. 73 class SubscriptionManager final { 74 public: 75 using ClientIdType = const AIBinder*; 76 using CallbackType = 77 std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>; 78 using VehiclePropValue = aidl::android::hardware::automotive::vehicle::VehiclePropValue; 79 80 explicit SubscriptionManager(IVehicleHardware* vehicleHardware); 81 ~SubscriptionManager(); 82 83 // Subscribes to properties according to {@code SubscribeOptions}. Note that all option must 84 // contain non-empty areaIds field, which contains all area IDs to subscribe. As a result, 85 // the options here is different from the options passed from VHAL client. 86 // Returns error if any of the subscribe options is not valid or one of the properties failed 87 // to subscribe. Part of the properties maybe be subscribed successfully if this function 88 // returns error. Caller is safe to retry since subscribing to an already subscribed property 89 // is okay. 90 // Returns ok if all the options are parsed correctly and all the properties are subscribed. 91 VhalResult<void> subscribe( 92 const CallbackType& callback, 93 const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>& 94 options, 95 bool isContinuousProperty); 96 97 // Unsubscribes from the properties for the client. 98 // Returns error if the client was not subscribed before, or one of the given property was not 99 // subscribed, or one of the property failed to unsubscribe. Caller is safe to retry since 100 // unsubscribing to an already unsubscribed property is okay (it would be ignored). 101 // Returns ok if all the requested properties for the client are unsubscribed. 102 VhalResult<void> unsubscribe(ClientIdType client, const std::vector<int32_t>& propIds); 103 104 // Unsubscribes from all the properties for the client. 105 // Returns error if the client was not subscribed before or one of the subscribed properties 106 // for the client failed to unsubscribe. Caller is safe to retry. 107 // Returns ok if all the properties for the client are unsubscribed. 108 VhalResult<void> unsubscribe(ClientIdType client); 109 110 // For a list of updated properties, returns a map that maps clients subscribing to 111 // the updated properties to a list of updated values. This would only return on-change property 112 // clients that should be informed for the given updated values. 113 std::unordered_map<CallbackType, std::vector<VehiclePropValue>> getSubscribedClients( 114 std::vector<VehiclePropValue>&& updatedValues); 115 116 // For a list of set property error events, returns a map that maps clients subscribing to the 117 // properties to a list of errors for each client. 118 std::unordered_map<CallbackType, 119 std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>> 120 getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents); 121 122 // Returns the number of subscribed clients. 123 size_t countClients(); 124 125 // Checks whether the sample rate is valid. 126 static bool checkSampleRateHz(float sampleRateHz); 127 128 // Checks whether the resolution is valid. 129 static bool checkResolution(float resolution); 130 131 private: 132 // Friend class for testing. 133 friend class DefaultVehicleHalTest; 134 135 IVehicleHardware* mVehicleHardware; 136 137 struct VehiclePropValueHashPropIdAreaId { operatorVehiclePropValueHashPropIdAreaId138 inline size_t operator()(const VehiclePropValue& vehiclePropValue) const { 139 size_t res = 0; 140 hashCombine(res, vehiclePropValue.prop); 141 hashCombine(res, vehiclePropValue.areaId); 142 return res; 143 } 144 }; 145 146 struct VehiclePropValueEqualPropIdAreaId { operatorVehiclePropValueEqualPropIdAreaId147 inline bool operator()(const VehiclePropValue& left, const VehiclePropValue& right) const { 148 return left.prop == right.prop && left.areaId == right.areaId; 149 } 150 }; 151 152 mutable std::mutex mLock; 153 std::unordered_map<PropIdAreaId, std::unordered_map<ClientIdType, CallbackType>, 154 PropIdAreaIdHash> 155 mClientsByPropIdAreaId GUARDED_BY(mLock); 156 std::unordered_map<ClientIdType, std::unordered_set<PropIdAreaId, PropIdAreaIdHash>> 157 mSubscribedPropsByClient GUARDED_BY(mLock); 158 std::unordered_map<PropIdAreaId, ContSubConfigs, PropIdAreaIdHash> mContSubConfigsByPropIdArea 159 GUARDED_BY(mLock); 160 std::unordered_map<CallbackType, 161 std::unordered_set<VehiclePropValue, VehiclePropValueHashPropIdAreaId, 162 VehiclePropValueEqualPropIdAreaId>> 163 mContSubValuesByCallback GUARDED_BY(mLock); 164 165 VhalResult<void> addContinuousSubscriberLocked(const ClientIdType& clientId, 166 const PropIdAreaId& propIdAreaId, 167 float sampleRateHz, float resolution, 168 bool enableVur) REQUIRES(mLock); 169 VhalResult<void> addOnChangeSubscriberLocked(const PropIdAreaId& propIdAreaId) REQUIRES(mLock); 170 // Removes the subscription client for the continuous [propId, areaId]. 171 VhalResult<void> removeContinuousSubscriberLocked(const ClientIdType& clientId, 172 const PropIdAreaId& propIdAreaId) 173 REQUIRES(mLock); 174 // Removes one subscription client for the on-change [propId, areaId]. 175 VhalResult<void> removeOnChangeSubscriberLocked(const PropIdAreaId& propIdAreaId) 176 REQUIRES(mLock); 177 178 VhalResult<void> updateContSubConfigsLocked(const PropIdAreaId& PropIdAreaId, 179 const ContSubConfigs& newConfig) REQUIRES(mLock); 180 181 VhalResult<void> unsubscribePropIdAreaIdLocked(SubscriptionManager::ClientIdType clientId, 182 const PropIdAreaId& propIdAreaId) 183 REQUIRES(mLock); 184 185 // Checks whether the manager is empty. For testing purpose. 186 bool isEmpty(); 187 188 bool isValueUpdatedLocked(const CallbackType& callback, const VehiclePropValue& value) 189 REQUIRES(mLock); 190 191 // Get the interval in nanoseconds accroding to sample rate. 192 static android::base::Result<int64_t> getIntervalNanos(float sampleRateHz); 193 }; 194 195 } // namespace vehicle 196 } // namespace automotive 197 } // namespace hardware 198 } // namespace android 199 200 #endif // android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_ 201