1 /*
2  * Copyright (C) 2019 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 #include <health2impl/BinderHealth.h>
18 
19 #include <android-base/logging.h>
20 #include <hidl/HidlTransportSupport.h>
21 #include <hwbinder/IPCThreadState.h>
22 
23 #include <health2impl/Callback.h>
24 #include <health2impl/Health.h>
25 
26 using android::hardware::handleTransportPoll;
27 using android::hardware::IPCThreadState;
28 using android::hardware::setupTransportPolling;
29 
30 using android::hardware::health::V2_0::Result;
31 
32 namespace android {
33 namespace hardware {
34 namespace health {
35 namespace V2_1 {
36 namespace implementation {
37 
IsDeadObject(const Return<void> & ret)38 bool IsDeadObject(const Return<void>& ret) {
39     if (ret.isOk()) return false;
40     if (ret.isDeadObject()) return true;
41     return false;
42 }
43 
BinderHealth(const std::string & name,const sp<IHealth> & impl)44 BinderHealth::BinderHealth(const std::string& name, const sp<IHealth>& impl)
45     : HalHealthLoop(name, impl) {
46     CHECK_NE(this, impl.get());
47     CHECK(!impl->isRemote());
48 }
49 
50 //
51 // Methods that handle callbacks.
52 //
53 
registerCallback(const sp<V2_0::IHealthInfoCallback> & callback)54 Return<Result> BinderHealth::registerCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
55     if (callback == nullptr) {
56         return Result::SUCCESS;
57     }
58 
59     Callback* wrapped = nullptr;
60     {
61         std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
62         wrapped = callbacks_.emplace_back(Wrap(callback)).get();
63         // unlock
64     }
65 
66     auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
67     if (!linkRet.withDefault(false)) {
68         LOG(WARNING) << __func__ << "Cannot link to death: "
69                      << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
70         // ignore the error
71     }
72 
73     getHealthInfo_2_1([&](auto res, const auto& health_info) {
74         if (res != Result::SUCCESS) {
75             LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
76             return;
77         }
78         auto ret = wrapped->Notify(health_info);
79         if (IsDeadObject(ret)) {
80             // Remove callback reference.
81             std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
82             auto it = std::find_if(callbacks_.begin(), callbacks_.end(),
83                                    [wrapped](const auto& cb) { return cb.get() == wrapped; });
84             if (it != callbacks_.end()) {
85                 callbacks_.erase(it);
86             }
87             // unlock
88         }
89     });
90 
91     return Result::SUCCESS;
92 }
93 
unregisterCallbackInternal(const sp<IBase> & callback)94 bool BinderHealth::unregisterCallbackInternal(const sp<IBase>& callback) {
95     if (callback == nullptr) {
96         return false;
97     }
98 
99     bool removed = false;
100     std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
101     for (auto it = callbacks_.begin(); it != callbacks_.end();) {
102         if (interfacesEqual((*it)->Get(), callback)) {
103             it = callbacks_.erase(it);
104             removed = true;
105         } else {
106             ++it;
107         }
108     }
109     (void)callback->unlinkToDeath(this).isOk();  // ignore errors
110     return removed;
111 }
112 
update()113 Return<Result> BinderHealth::update() {
114     Result result = service()->update();
115     if (result != Result::SUCCESS) return result;
116     getHealthInfo_2_1([&](auto res, const auto& health_info) {
117         if (res != Result::SUCCESS) {
118             result = res;
119             return;
120         }
121         OnHealthInfoChanged(health_info);
122     });
123     return result;
124 }
125 
unregisterCallback(const sp<V2_0::IHealthInfoCallback> & callback)126 Return<Result> BinderHealth::unregisterCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
127     return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
128 }
129 
OnHealthInfoChanged(const HealthInfo & health_info)130 void BinderHealth::OnHealthInfoChanged(const HealthInfo& health_info) {
131     // Notify all callbacks
132     std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
133     for (auto it = callbacks_.begin(); it != callbacks_.end();) {
134         auto ret = (*it)->Notify(health_info);
135         if (IsDeadObject(ret)) {
136             it = callbacks_.erase(it);
137         } else {
138             ++it;
139         }
140     }
141     lock.unlock();
142 
143     // adjusts uevent / wakealarm periods
144     HalHealthLoop::OnHealthInfoChanged(health_info);
145 }
146 
serviceDied(uint64_t,const wp<IBase> & who)147 void BinderHealth::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
148     (void)unregisterCallbackInternal(who.promote());
149 }
150 
BinderEvent(uint32_t)151 void BinderHealth::BinderEvent(uint32_t /*epevents*/) {
152     if (binder_fd_ >= 0) {
153         handleTransportPoll(binder_fd_);
154     }
155 }
156 
Init(struct healthd_config * config)157 void BinderHealth::Init(struct healthd_config* config) {
158     // Set up epoll and get uevent / wake alarm periods
159     HalHealthLoop::Init(config);
160 
161     LOG(INFO) << instance_name() << " instance initializing with healthd_config...";
162 
163     binder_fd_ = setupTransportPolling();
164 
165     if (binder_fd_ >= 0) {
166         auto binder_event = [](auto* health_loop, uint32_t epevents) {
167             static_cast<BinderHealth*>(health_loop)->BinderEvent(epevents);
168         };
169         if (RegisterEvent(binder_fd_, binder_event, EVENT_NO_WAKEUP_FD) != 0) {
170             PLOG(ERROR) << instance_name() << " instance: Register for binder events failed";
171         }
172     }
173 
174     CHECK_EQ(registerAsService(instance_name()), android::OK)
175             << instance_name() << ": Failed to register HAL";
176 
177     LOG(INFO) << instance_name() << ": Hal init done";
178 }
179 
PrepareToWait(void)180 int BinderHealth::PrepareToWait(void) {
181     IPCThreadState::self()->flushCommands();
182     return HalHealthLoop::PrepareToWait();
183 }
184 
185 }  // namespace implementation
186 }  // namespace V2_1
187 }  // namespace health
188 }  // namespace hardware
189 }  // namespace android
190