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