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