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