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 constexpr int32_t kMaxConnectionAttempt = 5;
52
53 } // namespace
54
hasComponent(const std::vector<PowerComponent> & components,PowerComponent component)55 bool hasComponent(const std::vector<PowerComponent>& components, PowerComponent component) {
56 std::vector<PowerComponent>::const_iterator it =
57 std::find(components.cbegin(), components.cend(), component);
58 return it != components.cend();
59 }
60
PowerPolicyClientBase()61 PowerPolicyClientBase::PowerPolicyClientBase() :
62 mDeathRecipient(AIBinder_DeathRecipient_new(PowerPolicyClientBase::onBinderDied)) {}
63
~PowerPolicyClientBase()64 PowerPolicyClientBase::~PowerPolicyClientBase() {
65 if (mPolicyServer != nullptr) {
66 auto status =
67 ScopedAStatus::fromStatus(AIBinder_unlinkToDeath(mPolicyServer->asBinder().get(),
68 mDeathRecipient.get(), nullptr));
69 if (!status.isOk()) {
70 LOG(WARNING) << "Unlinking from death recipient failed";
71 }
72 }
73 }
74
onBinderDied(void * cookie)75 void PowerPolicyClientBase::onBinderDied(void* cookie) {
76 PowerPolicyClientBase* client = static_cast<PowerPolicyClientBase*>(cookie);
77 client->handleBinderDeath();
78 }
79
init()80 void PowerPolicyClientBase::init() {
81 mConnectionThread = std::thread([this]() {
82 Result<void> ret;
83 int attemptCount = 1;
84 while (attemptCount <= kMaxConnectionAttempt) {
85 ret = connectToDaemon();
86 if (ret.ok()) {
87 return;
88 }
89 LOG(WARNING) << "Connection attempt #" << attemptCount << " failed: " << ret.error();
90 attemptCount++;
91 }
92 onInitFailed();
93 });
94 }
95
handleBinderDeath()96 void PowerPolicyClientBase::handleBinderDeath() {
97 LOG(INFO) << "Power policy daemon died. Reconnecting...";
98 {
99 std::unique_lock writeLock(mRWMutex);
100 mPolicyServer = nullptr;
101 }
102 init();
103 }
104
connectToDaemon()105 Result<void> PowerPolicyClientBase::connectToDaemon() {
106 {
107 std::shared_lock readLock(mRWMutex);
108 if (mPolicyServer.get() != nullptr) {
109 LOG(INFO) << "Power policy daemon is already connected";
110 return {};
111 }
112 }
113 int64_t currentUptime = uptimeMillis();
114 SpAIBinder binder(AServiceManager_getService(kPowerPolicyServerInterface));
115 if (binder.get() == nullptr) {
116 return Error() << "Failed to get car power policy daemon";
117 }
118 int64_t elapsedTime = uptimeMillis() - currentUptime;
119 if (elapsedTime > kPowerPolicyDaemomFindMarginalTimeMs.count()) {
120 LOG(WARNING) << "Finding power policy daemon took too long(" << elapsedTime << " ms)";
121 }
122 std::shared_ptr<ICarPowerPolicyServer> server = ICarPowerPolicyServer::fromBinder(binder);
123 if (server == nullptr) {
124 return Error() << "Failed to connect to car power policy daemon";
125 }
126 binder = this->asBinder();
127 if (binder.get() == nullptr) {
128 return Error() << "Failed to get car power policy client binder object";
129 }
130 auto status = ScopedAStatus::fromStatus(
131 AIBinder_linkToDeath(server->asBinder().get(), mDeathRecipient.get(), this));
132 if (!status.isOk()) {
133 return Error() << "Linking to death recipient failed";
134 }
135
136 std::shared_ptr<ICarPowerPolicyChangeCallback> client =
137 ICarPowerPolicyChangeCallback::fromBinder(binder);
138 const auto& components = getComponentsOfInterest();
139 CarPowerPolicyFilter filter;
140 filter.components = components;
141 status = server->registerPowerPolicyChangeCallback(client, filter);
142 if (!status.isOk()) {
143 status = ScopedAStatus::fromStatus(AIBinder_unlinkToDeath(server->asBinder().get(),
144 mDeathRecipient.get(), nullptr));
145 if (!status.isOk()) {
146 LOG(WARNING) << "Unlinking from death recipient failed";
147 }
148 return Error() << "Register power policy change challback failed";
149 }
150
151 {
152 std::unique_lock writeLock(mRWMutex);
153 mPolicyServer = server;
154 }
155
156 LOG(INFO) << "Connected to power policy daemon";
157 return {};
158 }
159
160 } // namespace powerpolicy
161 } // namespace automotive
162 } // namespace frameworks
163 } // namespace android
164