1 /* 2 * Copyright (C) 2022 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 AIDL_CALLBACK_UTIL_H_ 18 #define AIDL_CALLBACK_UTIL_H_ 19 20 #include <android-base/logging.h> 21 22 #include <mutex> 23 #include <set> 24 #include <unordered_map> 25 26 namespace { 27 std::unordered_map<void* /* callback */, void* /* handler */> callback_handler_map_; 28 std::mutex callback_handler_lock_; 29 int32_t min_callback_version_ = INT_MAX; 30 } 31 32 namespace aidl { 33 namespace android { 34 namespace hardware { 35 namespace wifi { 36 namespace aidl_callback_util { 37 38 // Provides a class to manage callbacks for the various AIDL interfaces and 39 // handle the death of the process hosting each callback. 40 template <typename CallbackType> 41 class AidlCallbackHandler { 42 public: AidlCallbackHandler()43 AidlCallbackHandler() { 44 death_handler_ = AIBinder_DeathRecipient_new(AidlCallbackHandler::onCallbackDeath); 45 } ~AidlCallbackHandler()46 ~AidlCallbackHandler() { invalidate(); } 47 addCallback(const std::shared_ptr<CallbackType> & cb)48 bool addCallback(const std::shared_ptr<CallbackType>& cb) { 49 if (cb == nullptr) { 50 LOG(ERROR) << "Unable to register a null callback"; 51 return false; 52 } 53 54 // Callback interface version indicates which methods are available 55 int callbackVersion = getCallbackInterfaceVersion(cb); 56 if (callbackVersion < min_callback_version_) { 57 LOG(INFO) << "Setting min callback version to " << callbackVersion; 58 min_callback_version_ = callbackVersion; 59 } 60 61 std::unique_lock<std::mutex> lk(callback_handler_lock_); 62 void* cbPtr = reinterpret_cast<void*>(cb->asBinder().get()); 63 const auto& cbPosition = findCbInSet(cbPtr); 64 if (cbPosition != cb_set_.end()) { 65 LOG(WARNING) << "Duplicate death notification registration"; 66 return true; 67 } 68 69 if (AIBinder_linkToDeath(cb->asBinder().get(), death_handler_, cbPtr /* cookie */) != 70 STATUS_OK) { 71 LOG(ERROR) << "Failed to register death notification"; 72 return false; 73 } 74 75 callback_handler_map_[cbPtr] = reinterpret_cast<void*>(this); 76 cb_set_.insert(cb); 77 // unique_lock unlocked here 78 return true; 79 } 80 getCallbacks()81 const std::set<std::shared_ptr<CallbackType>>& getCallbacks() { 82 std::unique_lock<std::mutex> lk(callback_handler_lock_); 83 // unique_lock unlocked here 84 return cb_set_; 85 } 86 invalidate()87 void invalidate() { 88 std::unique_lock<std::mutex> lk(callback_handler_lock_); 89 for (auto cb : cb_set_) { 90 void* cookie = reinterpret_cast<void*>(cb->asBinder().get()); 91 if (AIBinder_unlinkToDeath(cb->asBinder().get(), death_handler_, cookie) != STATUS_OK) { 92 LOG(ERROR) << "Failed to deregister death notification"; 93 } 94 if (!removeCbFromHandlerMap(cookie)) { 95 LOG(ERROR) << "Failed to remove callback from handler map"; 96 } 97 } 98 cb_set_.clear(); 99 // unique_lock unlocked here 100 } 101 102 // Entry point for the death handling logic. AIBinder_DeathRecipient 103 // can only call a static function, so use the cookie to find the 104 // proper handler and route the request there. onCallbackDeath(void * cookie)105 static void onCallbackDeath(void* cookie) { 106 std::unique_lock<std::mutex> lk(callback_handler_lock_); 107 auto cbQuery = callback_handler_map_.find(cookie); 108 if (cbQuery == callback_handler_map_.end()) { 109 LOG(ERROR) << "Invalid death cookie received"; 110 return; 111 } 112 113 AidlCallbackHandler* cbHandler = reinterpret_cast<AidlCallbackHandler*>(cbQuery->second); 114 if (cbHandler == nullptr) { 115 LOG(ERROR) << "Handler mapping contained an invalid handler"; 116 return; 117 } 118 cbHandler->handleCallbackDeath(cbQuery->first); 119 // unique_lock unlocked here 120 } 121 getMinCallbackVersion()122 int32_t getMinCallbackVersion() { return min_callback_version_; } 123 124 private: 125 std::set<std::shared_ptr<CallbackType>> cb_set_; 126 AIBinder_DeathRecipient* death_handler_; 127 findCbInSet(void * cbPtr)128 typename std::set<std::shared_ptr<CallbackType>>::iterator findCbInSet(void* cbPtr) { 129 const auto& cbPosition = std::find_if( 130 cb_set_.begin(), cb_set_.end(), [cbPtr](const std::shared_ptr<CallbackType>& p) { 131 return cbPtr == reinterpret_cast<void*>(p->asBinder().get()); 132 }); 133 return cbPosition; 134 } 135 removeCbFromHandlerMap(void * cbPtr)136 bool removeCbFromHandlerMap(void* cbPtr) { 137 auto cbQuery = callback_handler_map_.find(cbPtr); 138 if (cbQuery != callback_handler_map_.end()) { 139 callback_handler_map_.erase(cbQuery); 140 return true; 141 } 142 return false; 143 } 144 handleCallbackDeath(void * cbPtr)145 void handleCallbackDeath(void* cbPtr) { 146 const auto& cbPosition = findCbInSet(cbPtr); 147 if (cbPosition == cb_set_.end()) { 148 LOG(ERROR) << "Unknown callback death notification received"; 149 return; 150 } 151 cb_set_.erase(cbPosition); 152 153 if (!removeCbFromHandlerMap(cbPtr)) { 154 LOG(ERROR) << "Callback was not in callback handler map"; 155 } 156 } 157 getCallbackInterfaceVersion(std::shared_ptr<CallbackType> callback)158 static int32_t getCallbackInterfaceVersion(std::shared_ptr<CallbackType> callback) { 159 int32_t callbackVersion; 160 if (!callback->getInterfaceVersion(&callbackVersion).isOk()) { 161 LOG(ERROR) << "Unable to check the callback version"; 162 return INT_MAX; 163 } 164 return callbackVersion; 165 } 166 167 DISALLOW_COPY_AND_ASSIGN(AidlCallbackHandler); 168 }; 169 170 } // namespace aidl_callback_util 171 } // namespace wifi 172 } // namespace hardware 173 } // namespace android 174 } // namespace aidl 175 176 #endif // AIDL_CALLBACK_UTIL_H_ 177