• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 kPowerPolicyDaemonFindMarginalTimeMs = 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     // This will unlink all linked binders.
74     AIBinder_DeathRecipient_delete(mDeathRecipient.release());
75 
76     // Need to wait until for each linkToDeath call, one onBinderUnlinked is called.
77     // In release, the connection thread already ends so we are sure mSelfRefCounter does not
78     // increase. We are sure mSelfRefCounter will not change once it is set to 0.
79     {
80         std::unique_lock lk(mLock);
81         mDeathRecipientLinkedCv.wait(lk, [this] { return mSelfRefCounter == 0; });
82     }
83 }
84 
onDeathRecipientUnlinked(void * cookie)85 void PowerPolicyClientBase::onDeathRecipientUnlinked(void* cookie) {
86     PowerPolicyClientBase* client = static_cast<PowerPolicyClientBase*>(cookie);
87     client->handleDeathRecipientUnlinked();
88 }
89 
onBinderDied(void * cookie)90 void PowerPolicyClientBase::onBinderDied(void* cookie) {
91     PowerPolicyClientBase* client = static_cast<PowerPolicyClientBase*>(cookie);
92     client->handleBinderDeath();
93 }
94 
release()95 void PowerPolicyClientBase::release() {
96     SpAIBinder binder;
97     std::shared_ptr<ICarPowerPolicyServer> policyServer;
98     std::shared_ptr<ICarPowerPolicyChangeCallback> policyChangeCallback;
99     {
100         std::lock_guard<std::mutex> lk(mLock);
101 
102         if (std::this_thread::get_id() == mConnectionThread.get_id()) {
103             LOG(ERROR) << "Cannot release from callback, deadlock would happen";
104             return;
105         }
106 
107         // wait for existing connection thread to finish
108         mConnecting = false;
109         if (mConnectionThread.joinable()) {
110             mConnectionThread.join();
111         }
112 
113         if (mPolicyServer == nullptr || mDisconnecting == true) {
114             return;
115         }
116 
117         mDisconnecting = true;
118         binder = mPolicyServer->asBinder();
119         policyServer = mPolicyServer;
120         policyChangeCallback = mPolicyChangeCallback;
121     }
122 
123     if (binder.get() != nullptr && AIBinder_isAlive(binder.get())) {
124         auto status = policyServer->unregisterPowerPolicyChangeCallback(policyChangeCallback);
125         if (!status.isOk()) {
126             LOG(ERROR) << "Unregister power policy change callback failed";
127         }
128     }
129 
130     {
131         std::lock_guard<std::mutex> lk(mLock);
132         mPolicyServer = nullptr;
133         mPolicyChangeCallback = nullptr;
134         mDisconnecting = false;
135     }
136 }
137 
init()138 void PowerPolicyClientBase::init() {
139     std::lock_guard<std::mutex> lk(mLock);
140 
141     if (mConnecting) {
142         LOG(WARNING) << "Connecting in progress";
143         return;
144     }
145 
146     if (mPolicyServer != nullptr) {
147         LOG(WARNING) << "Already connected";
148         return;
149     }
150 
151     mConnecting = true;
152     // ensure already finished old connection thread is cleaned up before creating new one
153     if (mConnectionThread.joinable()) {
154         mConnectionThread.join();
155     }
156     mConnectionThread = std::thread([this]() {
157         Result<void> ret = connectToDaemon();
158         mConnecting = false;
159         if (!ret.ok()) {
160             LOG(WARNING) << "Connecting to car power policy daemon failed: " << ret.error();
161             onInitFailed();
162         }
163     });
164 }
165 
handleBinderDeath()166 void PowerPolicyClientBase::handleBinderDeath() {
167     LOG(INFO) << "Power policy daemon died. Reconnecting...";
168     release();
169     init();
170 }
171 
handleDeathRecipientUnlinked()172 void PowerPolicyClientBase::handleDeathRecipientUnlinked() {
173     LOG(INFO) << "Power policy death recipient unlinked";
174     mSelfRefCounter--;
175     mDeathRecipientLinkedCv.notify_all();
176 }
177 
connectToDaemon()178 Result<void> PowerPolicyClientBase::connectToDaemon() {
179     int64_t currentUptime = uptimeMillis();
180     SpAIBinder binder(AServiceManager_waitForService(kPowerPolicyServerInterface));
181     if (binder.get() == nullptr) {
182         return Error() << "Failed to get car power policy daemon";
183     }
184     int64_t elapsedTime = uptimeMillis() - currentUptime;
185     if (elapsedTime > kPowerPolicyDaemonFindMarginalTimeMs.count()) {
186         LOG(WARNING) << "Finding power policy daemon took too long(" << elapsedTime << " ms)";
187     }
188     std::shared_ptr<ICarPowerPolicyServer> server = ICarPowerPolicyServer::fromBinder(binder);
189     if (server == nullptr) {
190         return Error() << "Failed to connect to car power policy daemon";
191     }
192     binder = this->asBinder();
193     if (binder.get() == nullptr) {
194         return Error() << "Failed to get car power policy client binder object";
195     }
196     // We pass 'this' as cookie to DeathRecipient so we need to increase ref counter to make
197     // sure we do not delete 'this' before the cookie is never used again.
198     mSelfRefCounter++;
199     auto status = ScopedAStatus::fromStatus(
200             AIBinder_linkToDeath(server->asBinder().get(), mDeathRecipient.get(), this));
201     if (!status.isOk()) {
202         return Error() << "Linking to death recipient failed";
203     }
204 
205     std::shared_ptr<ICarPowerPolicyChangeCallback> client =
206             ICarPowerPolicyChangeCallback::fromBinder(binder);
207     const auto& components = getComponentsOfInterest();
208     const auto& customComponents = getCustomComponentsOfInterest();
209     CarPowerPolicyFilter filter;
210     filter.components = components;
211     filter.customComponents = customComponents;
212     status = server->registerPowerPolicyChangeCallback(client, filter);
213     if (!status.isOk()) {
214         status = ScopedAStatus::fromStatus(
215                 AIBinder_unlinkToDeath(server->asBinder().get(), mDeathRecipient.get(), this));
216         if (!status.isOk()) {
217             LOG(WARNING) << "Unlinking from death recipient failed";
218         }
219         return Error() << "Register power policy change challback failed";
220     }
221 
222     mPolicyServer = server;
223     mPolicyChangeCallback = client;
224 
225     LOG(INFO) << "Connected to power policy daemon";
226     return {};
227 }
228 
229 }  // namespace powerpolicy
230 }  // namespace automotive
231 }  // namespace frameworks
232 }  // namespace android
233