1 /*
2 * Copyright (C) 2021 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 <dataproviders/PixelStateResidencyDataProvider.h>
18
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 #include <android/binder_status.h>
22
23 namespace aidl {
24 namespace android {
25 namespace hardware {
26 namespace power {
27 namespace stats {
28
PixelStateResidencyDataProvider()29 PixelStateResidencyDataProvider::PixelStateResidencyDataProvider()
30 : mProviderService(ndk::SharedRefBase::make<ProviderService>(this)) {}
31
addEntity(std::string name,std::vector<State> states)32 void PixelStateResidencyDataProvider::addEntity(std::string name, std::vector<State> states) {
33 std::lock_guard<std::mutex> lock(mLock);
34
35 mEntries.emplace_back(name, states);
36 }
37
start()38 void PixelStateResidencyDataProvider::start() {
39 binder_status_t status =
40 AServiceManager_addService(mProviderService->asBinder().get(), kInstance.c_str());
41 if (status != STATUS_OK) {
42 LOG(ERROR) << "Failed to start " << kInstance;
43 }
44 }
45
getStateResidenciesTimed(const Entry & entry,std::vector<StateResidency> * residency)46 ::ndk::ScopedAStatus PixelStateResidencyDataProvider::getStateResidenciesTimed(
47 const Entry &entry, std::vector<StateResidency> *residency) {
48 const uint64_t MAX_LATENCY_US = 2000;
49
50 if (!entry.mCallback) {
51 LOG(ERROR) << "callback for " << entry.mName << " is not registered";
52 return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
53 }
54
55 struct timespec then;
56 struct timespec now;
57
58 clock_gettime(CLOCK_BOOTTIME, &then);
59 ::ndk::ScopedAStatus status = entry.mCallback->getStateResidency(residency);
60 clock_gettime(CLOCK_BOOTTIME, &now);
61
62 uint64_t timeElapsedUs =
63 ((now.tv_sec - then.tv_sec) * 1000000) + ((now.tv_nsec - then.tv_nsec) / 1000);
64 if (timeElapsedUs > MAX_LATENCY_US) {
65 LOG(WARNING) << "getStateResidency latency for " << entry.mName
66 << " exceeded time allowed: " << timeElapsedUs << "us";
67 }
68
69 return status;
70 }
71
getStateResidencies(std::unordered_map<std::string,std::vector<StateResidency>> * residencies)72 bool PixelStateResidencyDataProvider::getStateResidencies(
73 std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
74 std::lock_guard<std::mutex> lock(mLock);
75
76 size_t numResultsFound = 0;
77 size_t numResults = mEntries.size();
78 for (auto &entry : mEntries) {
79 std::vector<StateResidency> residency;
80 ::ndk::ScopedAStatus status = getStateResidenciesTimed(entry, &residency);
81
82 if (!status.isOk()) {
83 LOG(ERROR) << "getStateResidency for " << entry.mName << " failed";
84
85 if (status.getStatus() == STATUS_DEAD_OBJECT) {
86 LOG(ERROR) << "Unregistering dead callback for " << entry.mName;
87 entry.mCallback = nullptr;
88 }
89 }
90 if (!residency.empty()) {
91 residencies->emplace(entry.mName, residency);
92 numResultsFound++;
93 }
94 }
95
96 return (numResultsFound == numResults);
97 }
98
getInfo()99 std::unordered_map<std::string, std::vector<State>> PixelStateResidencyDataProvider::getInfo() {
100 std::lock_guard<std::mutex> lock(mLock);
101
102 std::unordered_map<std::string, std::vector<State>> ret;
103 for (const auto &entry : mEntries) {
104 ret.emplace(entry.mName, entry.mStates);
105 }
106
107 return ret;
108 }
109
registerStatesUpdateCallback(std::function<void (const std::string &,const std::vector<State> & in_states)> statesUpdateCallback)110 void PixelStateResidencyDataProvider::registerStatesUpdateCallback(
111 std::function<void(const std::string &, const std::vector<State> &in_states)>
112 statesUpdateCallback) {
113 mStatesUpdateCallback = statesUpdateCallback;
114 }
115
registerCallbackByStates(const std::string & in_entityName,const std::shared_ptr<IPixelStateResidencyCallback> & in_cb,const std::vector<State> & in_states)116 ::ndk::ScopedAStatus PixelStateResidencyDataProvider::registerCallbackByStates(
117 const std::string &in_entityName,
118 const std::shared_ptr<IPixelStateResidencyCallback> &in_cb,
119 const std::vector<State> &in_states) {
120 std::lock_guard<std::mutex> lock(mLock);
121
122 if (!in_cb) {
123 return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
124 }
125
126 auto toRegister =
127 std::find_if(mEntries.begin(), mEntries.end(),
128 [&in_entityName](const auto &it) { return it.mName == in_entityName; });
129
130 if (toRegister == mEntries.end()) {
131 LOG(ERROR) << __func__ << " Invalid entityName: " << in_entityName;
132 return ::ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
133 }
134
135 toRegister->mCallback = in_cb;
136
137 if (!in_states.empty()) {
138 toRegister->mStates = in_states;
139 mStatesUpdateCallback(in_entityName, in_states);
140 }
141
142 LOG(INFO) << __func__ << ": Registered " << in_entityName;
143 return ::ndk::ScopedAStatus::ok();
144 }
145
registerCallback(const std::string & in_entityName,const std::shared_ptr<IPixelStateResidencyCallback> & in_cb)146 ::ndk::ScopedAStatus PixelStateResidencyDataProvider::registerCallback(
147 const std::string &in_entityName,
148 const std::shared_ptr<IPixelStateResidencyCallback> &in_cb) {
149 return registerCallbackByStates(in_entityName, in_cb, {});
150 }
151
unregisterCallback(const std::shared_ptr<IPixelStateResidencyCallback> & in_cb)152 ::ndk::ScopedAStatus PixelStateResidencyDataProvider::unregisterCallback(
153 const std::shared_ptr<IPixelStateResidencyCallback> &in_cb) {
154 std::lock_guard<std::mutex> lock(mLock);
155
156 if (!in_cb) {
157 return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
158 }
159
160 auto toRemove = std::find_if(mEntries.begin(), mEntries.end(), [&in_cb](const auto &it) {
161 if (!it.mCallback) {
162 return false;
163 }
164 return it.mCallback->asBinder().get() == in_cb->asBinder().get();
165 });
166
167 if (toRemove == mEntries.end()) {
168 return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
169 }
170
171 toRemove->mCallback = nullptr;
172
173 return ::ndk::ScopedAStatus::ok();
174 }
175
176 } // namespace stats
177 } // namespace power
178 } // namespace hardware
179 } // namespace android
180 } // namespace aidl
181