• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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