1 /*
2  * Copyright (C) 2020 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 "PowerPolicyClientBase.h"
18 
19 #include <android-base/chrono_utils.h>
20 #include <android-base/logging.h>
21 #include <android/binder_manager.h>
22 #include <utils/SystemClock.h>
23 
24 #include <algorithm>
25 #include <memory>
26 
27 namespace android {
28 namespace frameworks {
29 namespace automotive {
30 namespace powerpolicy {
31 
32 namespace aafap = ::aidl::android::frameworks::automotive::powerpolicy;
33 
34 using aafap::CarPowerPolicy;
35 using aafap::CarPowerPolicyFilter;
36 using aafap::ICarPowerPolicyChangeCallback;
37 using aafap::ICarPowerPolicyServer;
38 using aafap::PowerComponent;
39 using android::uptimeMillis;
40 using android::base::Error;
41 using android::base::Result;
42 using ::ndk::ScopedAStatus;
43 using ::ndk::SpAIBinder;
44 
45 namespace {
46 
47 constexpr const char* kPowerPolicyServerInterface =
48         "android.frameworks.automotive.powerpolicy.ICarPowerPolicyServer/default";
49 
50 constexpr std::chrono::milliseconds kPowerPolicyDaemomFindMarginalTimeMs = 500ms;
51 
52 }  // namespace
53 
hasComponent(const std::vector<PowerComponent> & components,PowerComponent component)54 bool hasComponent(const std::vector<PowerComponent>& components, PowerComponent component) {
55     std::vector<PowerComponent>::const_iterator it =
56             std::find(components.cbegin(), components.cend(), component);
57     return it != components.cend();
58 }
59 
PowerPolicyClientBase()60 PowerPolicyClientBase::PowerPolicyClientBase() :
61       mPolicyServer(nullptr),
62       mPolicyChangeCallback(nullptr),
63       mDeathRecipient(AIBinder_DeathRecipient_new(PowerPolicyClientBase::onBinderDied)),
64       mConnecting(false),
65       mDisconnecting(false) {
66     AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(),
67                                           &PowerPolicyClientBase::onDeathRecipientUnlinked);
68 }
69 
~PowerPolicyClientBase()70 PowerPolicyClientBase::~PowerPolicyClientBase() {
71     release();
72 }
73 
onDeathRecipientUnlinked(void * cookie)74 void PowerPolicyClientBase::onDeathRecipientUnlinked(void* cookie) {
75     PowerPolicyClientBase* client = static_cast<PowerPolicyClientBase*>(cookie);
76     client->handleDeathRecipientUnlinked();
77 }
78 
onBinderDied(void * cookie)79 void PowerPolicyClientBase::onBinderDied(void* cookie) {
80     PowerPolicyClientBase* client = static_cast<PowerPolicyClientBase*>(cookie);
81     client->handleBinderDeath();
82 }
83 
release()84 void PowerPolicyClientBase::release() {
85     SpAIBinder binder;
86     std::shared_ptr<ICarPowerPolicyServer> policyServer;
87     std::shared_ptr<ICarPowerPolicyChangeCallback> policyChangeCallback;
88     {
89         std::lock_guard<std::mutex> lk(mLock);
90 
91         if (std::this_thread::get_id() == mConnectionThread.get_id()) {
92             LOG(ERROR) << "Cannot release from callback, deadlock would happen";
93             return;
94         }
95 
96         // wait for existing connection thread to finish
97         mConnecting = false;
98         if (mConnectionThread.joinable()) {
99             mConnectionThread.join();
100         }
101 
102         if (mPolicyServer == nullptr || mDisconnecting == true) {
103             return;
104         }
105 
106         mDisconnecting = true;
107         binder = mPolicyServer->asBinder();
108         policyServer = mPolicyServer;
109         policyChangeCallback = mPolicyChangeCallback;
110     }
111 
112     if (binder.get() != nullptr && AIBinder_isAlive(binder.get())) {
113         auto status = policyServer->unregisterPowerPolicyChangeCallback(policyChangeCallback);
114         if (!status.isOk()) {
115             LOG(ERROR) << "Unregister power policy change callback failed";
116         }
117 
118         status = ScopedAStatus::fromStatus(
119                 AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), this));
120         if (!status.isOk()) {
121             LOG(WARNING) << "Unlinking from death recipient failed";
122         }
123 
124         // Need to wait until onUnlinked to be called.
125         {
126             std::unique_lock lk(mLock);
127             mDeathRecipientLinkedCv.wait(lk, [this] { return !mDeathRecipientLinked; });
128         }
129     }
130 
131     {
132         std::lock_guard<std::mutex> lk(mLock);
133         mPolicyServer = nullptr;
134         mPolicyChangeCallback = nullptr;
135         mDisconnecting = false;
136     }
137 }
138 
init()139 void PowerPolicyClientBase::init() {
140     std::lock_guard<std::mutex> lk(mLock);
141 
142     if (mConnecting) {
143         LOG(WARNING) << "Connecting in progress";
144         return;
145     }
146 
147     if (mPolicyServer != nullptr) {
148         LOG(WARNING) << "Already connected";
149         return;
150     }
151 
152     mConnecting = true;
153     // ensure already finished old connection thread is cleaned up before creating new one
154     if (mConnectionThread.joinable()) {
155         mConnectionThread.join();
156     }
157     mConnectionThread = std::thread([this]() {
158         Result<void> ret = connectToDaemon();
159         mConnecting = false;
160         if (!ret.ok()) {
161             LOG(WARNING) << "Connecting to car power policy daemon failed: " << ret.error();
162             onInitFailed();
163         }
164     });
165 }
166 
handleBinderDeath()167 void PowerPolicyClientBase::handleBinderDeath() {
168     LOG(INFO) << "Power policy daemon died. Reconnecting...";
169     release();
170     init();
171 }
172 
handleDeathRecipientUnlinked()173 void PowerPolicyClientBase::handleDeathRecipientUnlinked() {
174     LOG(INFO) << "Power policy death recipient unlinked";
175     {
176         std::lock_guard<std::mutex> lk(mLock);
177         mDeathRecipientLinked = false;
178     }
179     mDeathRecipientLinkedCv.notify_all();
180 }
181 
connectToDaemon()182 Result<void> PowerPolicyClientBase::connectToDaemon() {
183     int64_t currentUptime = uptimeMillis();
184     SpAIBinder binder(AServiceManager_waitForService(kPowerPolicyServerInterface));
185     if (binder.get() == nullptr) {
186         return Error() << "Failed to get car power policy daemon";
187     }
188     int64_t elapsedTime = uptimeMillis() - currentUptime;
189     if (elapsedTime > kPowerPolicyDaemomFindMarginalTimeMs.count()) {
190         LOG(WARNING) << "Finding power policy daemon took too long(" << elapsedTime << " ms)";
191     }
192     std::shared_ptr<ICarPowerPolicyServer> server = ICarPowerPolicyServer::fromBinder(binder);
193     if (server == nullptr) {
194         return Error() << "Failed to connect to car power policy daemon";
195     }
196     binder = this->asBinder();
197     if (binder.get() == nullptr) {
198         return Error() << "Failed to get car power policy client binder object";
199     }
200     mDeathRecipientLinked = true;
201     auto status = ScopedAStatus::fromStatus(
202             AIBinder_linkToDeath(server->asBinder().get(), mDeathRecipient.get(), this));
203     if (!status.isOk()) {
204         return Error() << "Linking to death recipient failed";
205     }
206 
207     std::shared_ptr<ICarPowerPolicyChangeCallback> client =
208             ICarPowerPolicyChangeCallback::fromBinder(binder);
209     const auto& components = getComponentsOfInterest();
210     const auto& customComponents = getCustomComponentsOfInterest();
211     CarPowerPolicyFilter filter;
212     filter.components = components;
213     filter.customComponents = customComponents;
214     status = server->registerPowerPolicyChangeCallback(client, filter);
215     if (!status.isOk()) {
216         status = ScopedAStatus::fromStatus(
217                 AIBinder_unlinkToDeath(server->asBinder().get(), mDeathRecipient.get(), this));
218         if (!status.isOk()) {
219             LOG(WARNING) << "Unlinking from death recipient failed";
220         }
221         return Error() << "Register power policy change challback failed";
222     }
223 
224     mPolicyServer = server;
225     mPolicyChangeCallback = client;
226 
227     LOG(INFO) << "Connected to power policy daemon";
228     return {};
229 }
230 
231 }  // namespace powerpolicy
232 }  // namespace automotive
233 }  // namespace frameworks
234 }  // namespace android
235