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
registerCallback(const std::string & in_entityName,const std::shared_ptr<IPixelStateResidencyCallback> & in_cb)110 ::ndk::ScopedAStatus PixelStateResidencyDataProvider::registerCallback(
111 const std::string &in_entityName,
112 const std::shared_ptr<IPixelStateResidencyCallback> &in_cb) {
113 std::lock_guard<std::mutex> lock(mLock);
114
115 if (!in_cb) {
116 return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
117 }
118
119 auto toRegister =
120 std::find_if(mEntries.begin(), mEntries.end(),
121 [&in_entityName](const auto &it) { return it.mName == in_entityName; });
122
123 if (toRegister == mEntries.end()) {
124 LOG(ERROR) << __func__ << " Invalid entityName: " << in_entityName;
125 return ::ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
126 }
127
128 toRegister->mCallback = in_cb;
129
130 LOG(INFO) << __func__ << ": Registered " << in_entityName;
131 return ::ndk::ScopedAStatus::ok();
132 }
133
unregisterCallback(const std::shared_ptr<IPixelStateResidencyCallback> & in_cb)134 ::ndk::ScopedAStatus PixelStateResidencyDataProvider::unregisterCallback(
135 const std::shared_ptr<IPixelStateResidencyCallback> &in_cb) {
136 std::lock_guard<std::mutex> lock(mLock);
137
138 if (!in_cb) {
139 return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL);
140 }
141
142 auto toRemove = std::find_if(mEntries.begin(), mEntries.end(), [&in_cb](const auto &it) {
143 return it.mCallback->asBinder().get() == in_cb->asBinder().get();
144 });
145
146 if (toRemove == mEntries.end()) {
147 return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
148 }
149
150 toRemove->mCallback = nullptr;
151
152 return ::ndk::ScopedAStatus::ok();
153 }
154
155 } // namespace stats
156 } // namespace power
157 } // namespace hardware
158 } // namespace android
159 } // namespace aidl
160