xref: /aosp_15_r20/hardware/interfaces/wifi/aidl/default/aidl_callback_util.h (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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