xref: /aosp_15_r20/hardware/interfaces/health/utils/libhealth2impl/BinderHealth.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #include <health2impl/BinderHealth.h>
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*4d7e907cSAndroid Build Coastguard Worker #include <hidl/HidlTransportSupport.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <hwbinder/IPCThreadState.h>
22*4d7e907cSAndroid Build Coastguard Worker 
23*4d7e907cSAndroid Build Coastguard Worker #include <health2impl/Callback.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <health2impl/Health.h>
25*4d7e907cSAndroid Build Coastguard Worker 
26*4d7e907cSAndroid Build Coastguard Worker using android::hardware::handleTransportPoll;
27*4d7e907cSAndroid Build Coastguard Worker using android::hardware::IPCThreadState;
28*4d7e907cSAndroid Build Coastguard Worker using android::hardware::setupTransportPolling;
29*4d7e907cSAndroid Build Coastguard Worker 
30*4d7e907cSAndroid Build Coastguard Worker using android::hardware::health::V2_0::Result;
31*4d7e907cSAndroid Build Coastguard Worker 
32*4d7e907cSAndroid Build Coastguard Worker namespace android {
33*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
34*4d7e907cSAndroid Build Coastguard Worker namespace health {
35*4d7e907cSAndroid Build Coastguard Worker namespace V2_1 {
36*4d7e907cSAndroid Build Coastguard Worker namespace implementation {
37*4d7e907cSAndroid Build Coastguard Worker 
IsDeadObject(const Return<void> & ret)38*4d7e907cSAndroid Build Coastguard Worker bool IsDeadObject(const Return<void>& ret) {
39*4d7e907cSAndroid Build Coastguard Worker     if (ret.isOk()) return false;
40*4d7e907cSAndroid Build Coastguard Worker     if (ret.isDeadObject()) return true;
41*4d7e907cSAndroid Build Coastguard Worker     return false;
42*4d7e907cSAndroid Build Coastguard Worker }
43*4d7e907cSAndroid Build Coastguard Worker 
BinderHealth(const std::string & name,const sp<IHealth> & impl)44*4d7e907cSAndroid Build Coastguard Worker BinderHealth::BinderHealth(const std::string& name, const sp<IHealth>& impl)
45*4d7e907cSAndroid Build Coastguard Worker     : HalHealthLoop(name, impl) {
46*4d7e907cSAndroid Build Coastguard Worker     CHECK_NE(this, impl.get());
47*4d7e907cSAndroid Build Coastguard Worker     CHECK(!impl->isRemote());
48*4d7e907cSAndroid Build Coastguard Worker }
49*4d7e907cSAndroid Build Coastguard Worker 
50*4d7e907cSAndroid Build Coastguard Worker //
51*4d7e907cSAndroid Build Coastguard Worker // Methods that handle callbacks.
52*4d7e907cSAndroid Build Coastguard Worker //
53*4d7e907cSAndroid Build Coastguard Worker 
registerCallback(const sp<V2_0::IHealthInfoCallback> & callback)54*4d7e907cSAndroid Build Coastguard Worker Return<Result> BinderHealth::registerCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
55*4d7e907cSAndroid Build Coastguard Worker     if (callback == nullptr) {
56*4d7e907cSAndroid Build Coastguard Worker         return Result::SUCCESS;
57*4d7e907cSAndroid Build Coastguard Worker     }
58*4d7e907cSAndroid Build Coastguard Worker 
59*4d7e907cSAndroid Build Coastguard Worker     Callback* wrapped = nullptr;
60*4d7e907cSAndroid Build Coastguard Worker     {
61*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
62*4d7e907cSAndroid Build Coastguard Worker         wrapped = callbacks_.emplace_back(Wrap(callback)).get();
63*4d7e907cSAndroid Build Coastguard Worker         // unlock
64*4d7e907cSAndroid Build Coastguard Worker     }
65*4d7e907cSAndroid Build Coastguard Worker 
66*4d7e907cSAndroid Build Coastguard Worker     auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
67*4d7e907cSAndroid Build Coastguard Worker     if (!linkRet.withDefault(false)) {
68*4d7e907cSAndroid Build Coastguard Worker         LOG(WARNING) << __func__ << "Cannot link to death: "
69*4d7e907cSAndroid Build Coastguard Worker                      << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
70*4d7e907cSAndroid Build Coastguard Worker         // ignore the error
71*4d7e907cSAndroid Build Coastguard Worker     }
72*4d7e907cSAndroid Build Coastguard Worker 
73*4d7e907cSAndroid Build Coastguard Worker     getHealthInfo_2_1([&](auto res, const auto& health_info) {
74*4d7e907cSAndroid Build Coastguard Worker         if (res != Result::SUCCESS) {
75*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
76*4d7e907cSAndroid Build Coastguard Worker             return;
77*4d7e907cSAndroid Build Coastguard Worker         }
78*4d7e907cSAndroid Build Coastguard Worker         auto ret = wrapped->Notify(health_info);
79*4d7e907cSAndroid Build Coastguard Worker         if (IsDeadObject(ret)) {
80*4d7e907cSAndroid Build Coastguard Worker             // Remove callback reference.
81*4d7e907cSAndroid Build Coastguard Worker             std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
82*4d7e907cSAndroid Build Coastguard Worker             auto it = std::find_if(callbacks_.begin(), callbacks_.end(),
83*4d7e907cSAndroid Build Coastguard Worker                                    [wrapped](const auto& cb) { return cb.get() == wrapped; });
84*4d7e907cSAndroid Build Coastguard Worker             if (it != callbacks_.end()) {
85*4d7e907cSAndroid Build Coastguard Worker                 callbacks_.erase(it);
86*4d7e907cSAndroid Build Coastguard Worker             }
87*4d7e907cSAndroid Build Coastguard Worker             // unlock
88*4d7e907cSAndroid Build Coastguard Worker         }
89*4d7e907cSAndroid Build Coastguard Worker     });
90*4d7e907cSAndroid Build Coastguard Worker 
91*4d7e907cSAndroid Build Coastguard Worker     return Result::SUCCESS;
92*4d7e907cSAndroid Build Coastguard Worker }
93*4d7e907cSAndroid Build Coastguard Worker 
unregisterCallbackInternal(const sp<IBase> & callback)94*4d7e907cSAndroid Build Coastguard Worker bool BinderHealth::unregisterCallbackInternal(const sp<IBase>& callback) {
95*4d7e907cSAndroid Build Coastguard Worker     if (callback == nullptr) {
96*4d7e907cSAndroid Build Coastguard Worker         return false;
97*4d7e907cSAndroid Build Coastguard Worker     }
98*4d7e907cSAndroid Build Coastguard Worker 
99*4d7e907cSAndroid Build Coastguard Worker     bool removed = false;
100*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
101*4d7e907cSAndroid Build Coastguard Worker     for (auto it = callbacks_.begin(); it != callbacks_.end();) {
102*4d7e907cSAndroid Build Coastguard Worker         if (interfacesEqual((*it)->Get(), callback)) {
103*4d7e907cSAndroid Build Coastguard Worker             it = callbacks_.erase(it);
104*4d7e907cSAndroid Build Coastguard Worker             removed = true;
105*4d7e907cSAndroid Build Coastguard Worker         } else {
106*4d7e907cSAndroid Build Coastguard Worker             ++it;
107*4d7e907cSAndroid Build Coastguard Worker         }
108*4d7e907cSAndroid Build Coastguard Worker     }
109*4d7e907cSAndroid Build Coastguard Worker     (void)callback->unlinkToDeath(this).isOk();  // ignore errors
110*4d7e907cSAndroid Build Coastguard Worker     return removed;
111*4d7e907cSAndroid Build Coastguard Worker }
112*4d7e907cSAndroid Build Coastguard Worker 
update()113*4d7e907cSAndroid Build Coastguard Worker Return<Result> BinderHealth::update() {
114*4d7e907cSAndroid Build Coastguard Worker     Result result = service()->update();
115*4d7e907cSAndroid Build Coastguard Worker     if (result != Result::SUCCESS) return result;
116*4d7e907cSAndroid Build Coastguard Worker     getHealthInfo_2_1([&](auto res, const auto& health_info) {
117*4d7e907cSAndroid Build Coastguard Worker         if (res != Result::SUCCESS) {
118*4d7e907cSAndroid Build Coastguard Worker             result = res;
119*4d7e907cSAndroid Build Coastguard Worker             return;
120*4d7e907cSAndroid Build Coastguard Worker         }
121*4d7e907cSAndroid Build Coastguard Worker         OnHealthInfoChanged(health_info);
122*4d7e907cSAndroid Build Coastguard Worker     });
123*4d7e907cSAndroid Build Coastguard Worker     return result;
124*4d7e907cSAndroid Build Coastguard Worker }
125*4d7e907cSAndroid Build Coastguard Worker 
unregisterCallback(const sp<V2_0::IHealthInfoCallback> & callback)126*4d7e907cSAndroid Build Coastguard Worker Return<Result> BinderHealth::unregisterCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
127*4d7e907cSAndroid Build Coastguard Worker     return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
128*4d7e907cSAndroid Build Coastguard Worker }
129*4d7e907cSAndroid Build Coastguard Worker 
OnHealthInfoChanged(const HealthInfo & health_info)130*4d7e907cSAndroid Build Coastguard Worker void BinderHealth::OnHealthInfoChanged(const HealthInfo& health_info) {
131*4d7e907cSAndroid Build Coastguard Worker     // Notify all callbacks
132*4d7e907cSAndroid Build Coastguard Worker     std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
133*4d7e907cSAndroid Build Coastguard Worker     for (auto it = callbacks_.begin(); it != callbacks_.end();) {
134*4d7e907cSAndroid Build Coastguard Worker         auto ret = (*it)->Notify(health_info);
135*4d7e907cSAndroid Build Coastguard Worker         if (IsDeadObject(ret)) {
136*4d7e907cSAndroid Build Coastguard Worker             it = callbacks_.erase(it);
137*4d7e907cSAndroid Build Coastguard Worker         } else {
138*4d7e907cSAndroid Build Coastguard Worker             ++it;
139*4d7e907cSAndroid Build Coastguard Worker         }
140*4d7e907cSAndroid Build Coastguard Worker     }
141*4d7e907cSAndroid Build Coastguard Worker     lock.unlock();
142*4d7e907cSAndroid Build Coastguard Worker 
143*4d7e907cSAndroid Build Coastguard Worker     // adjusts uevent / wakealarm periods
144*4d7e907cSAndroid Build Coastguard Worker     HalHealthLoop::OnHealthInfoChanged(health_info);
145*4d7e907cSAndroid Build Coastguard Worker }
146*4d7e907cSAndroid Build Coastguard Worker 
serviceDied(uint64_t,const wp<IBase> & who)147*4d7e907cSAndroid Build Coastguard Worker void BinderHealth::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
148*4d7e907cSAndroid Build Coastguard Worker     (void)unregisterCallbackInternal(who.promote());
149*4d7e907cSAndroid Build Coastguard Worker }
150*4d7e907cSAndroid Build Coastguard Worker 
BinderEvent(uint32_t)151*4d7e907cSAndroid Build Coastguard Worker void BinderHealth::BinderEvent(uint32_t /*epevents*/) {
152*4d7e907cSAndroid Build Coastguard Worker     if (binder_fd_ >= 0) {
153*4d7e907cSAndroid Build Coastguard Worker         handleTransportPoll(binder_fd_);
154*4d7e907cSAndroid Build Coastguard Worker     }
155*4d7e907cSAndroid Build Coastguard Worker }
156*4d7e907cSAndroid Build Coastguard Worker 
Init(struct healthd_config * config)157*4d7e907cSAndroid Build Coastguard Worker void BinderHealth::Init(struct healthd_config* config) {
158*4d7e907cSAndroid Build Coastguard Worker     // Set up epoll and get uevent / wake alarm periods
159*4d7e907cSAndroid Build Coastguard Worker     HalHealthLoop::Init(config);
160*4d7e907cSAndroid Build Coastguard Worker 
161*4d7e907cSAndroid Build Coastguard Worker     LOG(INFO) << instance_name() << " instance initializing with healthd_config...";
162*4d7e907cSAndroid Build Coastguard Worker 
163*4d7e907cSAndroid Build Coastguard Worker     binder_fd_ = setupTransportPolling();
164*4d7e907cSAndroid Build Coastguard Worker 
165*4d7e907cSAndroid Build Coastguard Worker     if (binder_fd_ >= 0) {
166*4d7e907cSAndroid Build Coastguard Worker         auto binder_event = [](auto* health_loop, uint32_t epevents) {
167*4d7e907cSAndroid Build Coastguard Worker             static_cast<BinderHealth*>(health_loop)->BinderEvent(epevents);
168*4d7e907cSAndroid Build Coastguard Worker         };
169*4d7e907cSAndroid Build Coastguard Worker         if (RegisterEvent(binder_fd_, binder_event, EVENT_NO_WAKEUP_FD) != 0) {
170*4d7e907cSAndroid Build Coastguard Worker             PLOG(ERROR) << instance_name() << " instance: Register for binder events failed";
171*4d7e907cSAndroid Build Coastguard Worker         }
172*4d7e907cSAndroid Build Coastguard Worker     }
173*4d7e907cSAndroid Build Coastguard Worker 
174*4d7e907cSAndroid Build Coastguard Worker     CHECK_EQ(registerAsService(instance_name()), android::OK)
175*4d7e907cSAndroid Build Coastguard Worker             << instance_name() << ": Failed to register HAL";
176*4d7e907cSAndroid Build Coastguard Worker 
177*4d7e907cSAndroid Build Coastguard Worker     LOG(INFO) << instance_name() << ": Hal init done";
178*4d7e907cSAndroid Build Coastguard Worker }
179*4d7e907cSAndroid Build Coastguard Worker 
PrepareToWait(void)180*4d7e907cSAndroid Build Coastguard Worker int BinderHealth::PrepareToWait(void) {
181*4d7e907cSAndroid Build Coastguard Worker     IPCThreadState::self()->flushCommands();
182*4d7e907cSAndroid Build Coastguard Worker     return HalHealthLoop::PrepareToWait();
183*4d7e907cSAndroid Build Coastguard Worker }
184*4d7e907cSAndroid Build Coastguard Worker 
185*4d7e907cSAndroid Build Coastguard Worker }  // namespace implementation
186*4d7e907cSAndroid Build Coastguard Worker }  // namespace V2_1
187*4d7e907cSAndroid Build Coastguard Worker }  // namespace health
188*4d7e907cSAndroid Build Coastguard Worker }  // namespace hardware
189*4d7e907cSAndroid Build Coastguard Worker }  // namespace android
190