1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker *
4*4d7e907cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker *
8*4d7e907cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker *
10*4d7e907cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker */
16*4d7e907cSAndroid Build Coastguard Worker
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "[email protected]"
18*4d7e907cSAndroid Build Coastguard Worker
19*4d7e907cSAndroid Build Coastguard Worker #include "PowerStats.h"
20*4d7e907cSAndroid Build Coastguard Worker #include <android-base/file.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <android-base/properties.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <android-base/strings.h>
25*4d7e907cSAndroid Build Coastguard Worker #include <inttypes.h>
26*4d7e907cSAndroid Build Coastguard Worker #include <stdlib.h>
27*4d7e907cSAndroid Build Coastguard Worker #include <algorithm>
28*4d7e907cSAndroid Build Coastguard Worker #include <exception>
29*4d7e907cSAndroid Build Coastguard Worker #include <thread>
30*4d7e907cSAndroid Build Coastguard Worker
31*4d7e907cSAndroid Build Coastguard Worker namespace android {
32*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
33*4d7e907cSAndroid Build Coastguard Worker namespace power {
34*4d7e907cSAndroid Build Coastguard Worker namespace stats {
35*4d7e907cSAndroid Build Coastguard Worker namespace V1_0 {
36*4d7e907cSAndroid Build Coastguard Worker namespace implementation {
37*4d7e907cSAndroid Build Coastguard Worker
38*4d7e907cSAndroid Build Coastguard Worker #define MAX_FILE_PATH_LEN 128
39*4d7e907cSAndroid Build Coastguard Worker #define MAX_DEVICE_NAME_LEN 64
40*4d7e907cSAndroid Build Coastguard Worker #define MAX_QUEUE_SIZE 8192
41*4d7e907cSAndroid Build Coastguard Worker
42*4d7e907cSAndroid Build Coastguard Worker constexpr char kIioDirRoot[] = "/sys/bus/iio/devices/";
43*4d7e907cSAndroid Build Coastguard Worker constexpr char kDeviceName[] = "pm_device_name";
44*4d7e907cSAndroid Build Coastguard Worker constexpr char kDeviceType[] = "iio:device";
45*4d7e907cSAndroid Build Coastguard Worker constexpr uint32_t MAX_SAMPLING_RATE = 10;
46*4d7e907cSAndroid Build Coastguard Worker constexpr uint64_t WRITE_TIMEOUT_NS = 1000000000;
47*4d7e907cSAndroid Build Coastguard Worker
findIioPowerMonitorNodes()48*4d7e907cSAndroid Build Coastguard Worker void PowerStats::findIioPowerMonitorNodes() {
49*4d7e907cSAndroid Build Coastguard Worker struct dirent* ent;
50*4d7e907cSAndroid Build Coastguard Worker int fd;
51*4d7e907cSAndroid Build Coastguard Worker char devName[MAX_DEVICE_NAME_LEN];
52*4d7e907cSAndroid Build Coastguard Worker char filePath[MAX_FILE_PATH_LEN];
53*4d7e907cSAndroid Build Coastguard Worker DIR* iioDir = opendir(kIioDirRoot);
54*4d7e907cSAndroid Build Coastguard Worker if (!iioDir) {
55*4d7e907cSAndroid Build Coastguard Worker ALOGE("Error opening directory: %s", kIioDirRoot);
56*4d7e907cSAndroid Build Coastguard Worker return;
57*4d7e907cSAndroid Build Coastguard Worker }
58*4d7e907cSAndroid Build Coastguard Worker while (ent = readdir(iioDir), ent) {
59*4d7e907cSAndroid Build Coastguard Worker if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0 &&
60*4d7e907cSAndroid Build Coastguard Worker strlen(ent->d_name) > strlen(kDeviceType) &&
61*4d7e907cSAndroid Build Coastguard Worker strncmp(ent->d_name, kDeviceType, strlen(kDeviceType)) == 0) {
62*4d7e907cSAndroid Build Coastguard Worker snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", ent->d_name, "name");
63*4d7e907cSAndroid Build Coastguard Worker fd = openat(dirfd(iioDir), filePath, O_RDONLY);
64*4d7e907cSAndroid Build Coastguard Worker if (fd < 0) {
65*4d7e907cSAndroid Build Coastguard Worker ALOGW("Failed to open directory: %s", filePath);
66*4d7e907cSAndroid Build Coastguard Worker continue;
67*4d7e907cSAndroid Build Coastguard Worker }
68*4d7e907cSAndroid Build Coastguard Worker if (read(fd, devName, MAX_DEVICE_NAME_LEN) < 0) {
69*4d7e907cSAndroid Build Coastguard Worker ALOGW("Failed to read device name from file: %s(%d)", filePath, fd);
70*4d7e907cSAndroid Build Coastguard Worker close(fd);
71*4d7e907cSAndroid Build Coastguard Worker continue;
72*4d7e907cSAndroid Build Coastguard Worker }
73*4d7e907cSAndroid Build Coastguard Worker
74*4d7e907cSAndroid Build Coastguard Worker if (strncmp(devName, kDeviceName, strlen(kDeviceName)) == 0) {
75*4d7e907cSAndroid Build Coastguard Worker snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", kIioDirRoot, ent->d_name);
76*4d7e907cSAndroid Build Coastguard Worker mPm.devicePaths.push_back(filePath);
77*4d7e907cSAndroid Build Coastguard Worker }
78*4d7e907cSAndroid Build Coastguard Worker close(fd);
79*4d7e907cSAndroid Build Coastguard Worker }
80*4d7e907cSAndroid Build Coastguard Worker }
81*4d7e907cSAndroid Build Coastguard Worker closedir(iioDir);
82*4d7e907cSAndroid Build Coastguard Worker return;
83*4d7e907cSAndroid Build Coastguard Worker }
84*4d7e907cSAndroid Build Coastguard Worker
parsePowerRails()85*4d7e907cSAndroid Build Coastguard Worker size_t PowerStats::parsePowerRails() {
86*4d7e907cSAndroid Build Coastguard Worker std::string data;
87*4d7e907cSAndroid Build Coastguard Worker std::string railFileName;
88*4d7e907cSAndroid Build Coastguard Worker std::string spsFileName;
89*4d7e907cSAndroid Build Coastguard Worker uint32_t index = 0;
90*4d7e907cSAndroid Build Coastguard Worker unsigned long samplingRate;
91*4d7e907cSAndroid Build Coastguard Worker for (const auto& path : mPm.devicePaths) {
92*4d7e907cSAndroid Build Coastguard Worker railFileName = path + "/enabled_rails";
93*4d7e907cSAndroid Build Coastguard Worker spsFileName = path + "/sampling_rate";
94*4d7e907cSAndroid Build Coastguard Worker if (!android::base::ReadFileToString(spsFileName, &data)) {
95*4d7e907cSAndroid Build Coastguard Worker ALOGW("Error reading file: %s", spsFileName.c_str());
96*4d7e907cSAndroid Build Coastguard Worker continue;
97*4d7e907cSAndroid Build Coastguard Worker }
98*4d7e907cSAndroid Build Coastguard Worker samplingRate = strtoul(data.c_str(), NULL, 10);
99*4d7e907cSAndroid Build Coastguard Worker if (!samplingRate || samplingRate == ULONG_MAX) {
100*4d7e907cSAndroid Build Coastguard Worker ALOGE("Error parsing: %s", spsFileName.c_str());
101*4d7e907cSAndroid Build Coastguard Worker break;
102*4d7e907cSAndroid Build Coastguard Worker }
103*4d7e907cSAndroid Build Coastguard Worker if (!android::base::ReadFileToString(railFileName, &data)) {
104*4d7e907cSAndroid Build Coastguard Worker ALOGW("Error reading file: %s", railFileName.c_str());
105*4d7e907cSAndroid Build Coastguard Worker continue;
106*4d7e907cSAndroid Build Coastguard Worker }
107*4d7e907cSAndroid Build Coastguard Worker std::istringstream railNames(data);
108*4d7e907cSAndroid Build Coastguard Worker std::string line;
109*4d7e907cSAndroid Build Coastguard Worker while (std::getline(railNames, line)) {
110*4d7e907cSAndroid Build Coastguard Worker std::vector<std::string> words = android::base::Split(line, ":");
111*4d7e907cSAndroid Build Coastguard Worker if (words.size() == 2) {
112*4d7e907cSAndroid Build Coastguard Worker mPm.railsInfo.emplace(
113*4d7e907cSAndroid Build Coastguard Worker words[0], RailData{.devicePath = path,
114*4d7e907cSAndroid Build Coastguard Worker .index = index,
115*4d7e907cSAndroid Build Coastguard Worker .subsysName = words[1],
116*4d7e907cSAndroid Build Coastguard Worker .samplingRate = static_cast<uint32_t>(samplingRate)});
117*4d7e907cSAndroid Build Coastguard Worker index++;
118*4d7e907cSAndroid Build Coastguard Worker } else {
119*4d7e907cSAndroid Build Coastguard Worker ALOGW("Unexpected format in file: %s", railFileName.c_str());
120*4d7e907cSAndroid Build Coastguard Worker }
121*4d7e907cSAndroid Build Coastguard Worker }
122*4d7e907cSAndroid Build Coastguard Worker }
123*4d7e907cSAndroid Build Coastguard Worker return index;
124*4d7e907cSAndroid Build Coastguard Worker }
125*4d7e907cSAndroid Build Coastguard Worker
parseIioEnergyNode(std::string devName)126*4d7e907cSAndroid Build Coastguard Worker int PowerStats::parseIioEnergyNode(std::string devName) {
127*4d7e907cSAndroid Build Coastguard Worker int ret = 0;
128*4d7e907cSAndroid Build Coastguard Worker std::string data;
129*4d7e907cSAndroid Build Coastguard Worker std::string fileName = devName + "/energy_value";
130*4d7e907cSAndroid Build Coastguard Worker if (!android::base::ReadFileToString(fileName, &data)) {
131*4d7e907cSAndroid Build Coastguard Worker ALOGE("Error reading file: %s", fileName.c_str());
132*4d7e907cSAndroid Build Coastguard Worker return -1;
133*4d7e907cSAndroid Build Coastguard Worker }
134*4d7e907cSAndroid Build Coastguard Worker
135*4d7e907cSAndroid Build Coastguard Worker std::istringstream energyData(data);
136*4d7e907cSAndroid Build Coastguard Worker std::string line;
137*4d7e907cSAndroid Build Coastguard Worker uint64_t timestamp = 0;
138*4d7e907cSAndroid Build Coastguard Worker bool timestampRead = false;
139*4d7e907cSAndroid Build Coastguard Worker while (std::getline(energyData, line)) {
140*4d7e907cSAndroid Build Coastguard Worker std::vector<std::string> words = android::base::Split(line, ",");
141*4d7e907cSAndroid Build Coastguard Worker if (timestampRead == false) {
142*4d7e907cSAndroid Build Coastguard Worker if (words.size() == 1) {
143*4d7e907cSAndroid Build Coastguard Worker timestamp = strtoull(words[0].c_str(), NULL, 10);
144*4d7e907cSAndroid Build Coastguard Worker if (timestamp == 0 || timestamp == ULLONG_MAX) {
145*4d7e907cSAndroid Build Coastguard Worker ALOGW("Potentially wrong timestamp: %" PRIu64, timestamp);
146*4d7e907cSAndroid Build Coastguard Worker }
147*4d7e907cSAndroid Build Coastguard Worker timestampRead = true;
148*4d7e907cSAndroid Build Coastguard Worker }
149*4d7e907cSAndroid Build Coastguard Worker } else if (words.size() == 2) {
150*4d7e907cSAndroid Build Coastguard Worker std::string railName = words[0];
151*4d7e907cSAndroid Build Coastguard Worker if (mPm.railsInfo.count(railName) != 0) {
152*4d7e907cSAndroid Build Coastguard Worker size_t index = mPm.railsInfo[railName].index;
153*4d7e907cSAndroid Build Coastguard Worker mPm.reading[index].index = index;
154*4d7e907cSAndroid Build Coastguard Worker mPm.reading[index].timestamp = timestamp;
155*4d7e907cSAndroid Build Coastguard Worker mPm.reading[index].energy = strtoull(words[1].c_str(), NULL, 10);
156*4d7e907cSAndroid Build Coastguard Worker if (mPm.reading[index].energy == ULLONG_MAX) {
157*4d7e907cSAndroid Build Coastguard Worker ALOGW("Potentially wrong energy value: %" PRIu64, mPm.reading[index].energy);
158*4d7e907cSAndroid Build Coastguard Worker }
159*4d7e907cSAndroid Build Coastguard Worker }
160*4d7e907cSAndroid Build Coastguard Worker } else {
161*4d7e907cSAndroid Build Coastguard Worker ALOGW("Unexpected format in file: %s", fileName.c_str());
162*4d7e907cSAndroid Build Coastguard Worker ret = -1;
163*4d7e907cSAndroid Build Coastguard Worker break;
164*4d7e907cSAndroid Build Coastguard Worker }
165*4d7e907cSAndroid Build Coastguard Worker }
166*4d7e907cSAndroid Build Coastguard Worker return ret;
167*4d7e907cSAndroid Build Coastguard Worker }
168*4d7e907cSAndroid Build Coastguard Worker
parseIioEnergyNodes()169*4d7e907cSAndroid Build Coastguard Worker Status PowerStats::parseIioEnergyNodes() {
170*4d7e907cSAndroid Build Coastguard Worker Status ret = Status::SUCCESS;
171*4d7e907cSAndroid Build Coastguard Worker if (mPm.hwEnabled == false) {
172*4d7e907cSAndroid Build Coastguard Worker return Status::NOT_SUPPORTED;
173*4d7e907cSAndroid Build Coastguard Worker }
174*4d7e907cSAndroid Build Coastguard Worker
175*4d7e907cSAndroid Build Coastguard Worker for (const auto& devicePath : mPm.devicePaths) {
176*4d7e907cSAndroid Build Coastguard Worker if (parseIioEnergyNode(devicePath) < 0) {
177*4d7e907cSAndroid Build Coastguard Worker ALOGE("Error in parsing power stats");
178*4d7e907cSAndroid Build Coastguard Worker ret = Status::FILESYSTEM_ERROR;
179*4d7e907cSAndroid Build Coastguard Worker break;
180*4d7e907cSAndroid Build Coastguard Worker }
181*4d7e907cSAndroid Build Coastguard Worker }
182*4d7e907cSAndroid Build Coastguard Worker return ret;
183*4d7e907cSAndroid Build Coastguard Worker }
184*4d7e907cSAndroid Build Coastguard Worker
PowerStats()185*4d7e907cSAndroid Build Coastguard Worker PowerStats::PowerStats() {
186*4d7e907cSAndroid Build Coastguard Worker findIioPowerMonitorNodes();
187*4d7e907cSAndroid Build Coastguard Worker size_t numRails = parsePowerRails();
188*4d7e907cSAndroid Build Coastguard Worker if (mPm.devicePaths.empty() || numRails == 0) {
189*4d7e907cSAndroid Build Coastguard Worker mPm.hwEnabled = false;
190*4d7e907cSAndroid Build Coastguard Worker } else {
191*4d7e907cSAndroid Build Coastguard Worker mPm.hwEnabled = true;
192*4d7e907cSAndroid Build Coastguard Worker mPm.reading.resize(numRails);
193*4d7e907cSAndroid Build Coastguard Worker }
194*4d7e907cSAndroid Build Coastguard Worker }
195*4d7e907cSAndroid Build Coastguard Worker
getRailInfo(getRailInfo_cb _hidl_cb)196*4d7e907cSAndroid Build Coastguard Worker Return<void> PowerStats::getRailInfo(getRailInfo_cb _hidl_cb) {
197*4d7e907cSAndroid Build Coastguard Worker hidl_vec<RailInfo> rInfo;
198*4d7e907cSAndroid Build Coastguard Worker Status ret = Status::SUCCESS;
199*4d7e907cSAndroid Build Coastguard Worker size_t index;
200*4d7e907cSAndroid Build Coastguard Worker std::lock_guard<std::mutex> _lock(mPm.mLock);
201*4d7e907cSAndroid Build Coastguard Worker if (mPm.hwEnabled == false) {
202*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(rInfo, Status::NOT_SUPPORTED);
203*4d7e907cSAndroid Build Coastguard Worker return Void();
204*4d7e907cSAndroid Build Coastguard Worker }
205*4d7e907cSAndroid Build Coastguard Worker rInfo.resize(mPm.railsInfo.size());
206*4d7e907cSAndroid Build Coastguard Worker for (const auto& railData : mPm.railsInfo) {
207*4d7e907cSAndroid Build Coastguard Worker index = railData.second.index;
208*4d7e907cSAndroid Build Coastguard Worker rInfo[index].railName = railData.first;
209*4d7e907cSAndroid Build Coastguard Worker rInfo[index].subsysName = railData.second.subsysName;
210*4d7e907cSAndroid Build Coastguard Worker rInfo[index].index = index;
211*4d7e907cSAndroid Build Coastguard Worker rInfo[index].samplingRate = railData.second.samplingRate;
212*4d7e907cSAndroid Build Coastguard Worker }
213*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(rInfo, ret);
214*4d7e907cSAndroid Build Coastguard Worker return Void();
215*4d7e907cSAndroid Build Coastguard Worker }
216*4d7e907cSAndroid Build Coastguard Worker
getEnergyData(const hidl_vec<uint32_t> & railIndices,getEnergyData_cb _hidl_cb)217*4d7e907cSAndroid Build Coastguard Worker Return<void> PowerStats::getEnergyData(const hidl_vec<uint32_t>& railIndices,
218*4d7e907cSAndroid Build Coastguard Worker getEnergyData_cb _hidl_cb) {
219*4d7e907cSAndroid Build Coastguard Worker hidl_vec<EnergyData> eVal;
220*4d7e907cSAndroid Build Coastguard Worker std::lock_guard<std::mutex> _lock(mPm.mLock);
221*4d7e907cSAndroid Build Coastguard Worker Status ret = parseIioEnergyNodes();
222*4d7e907cSAndroid Build Coastguard Worker
223*4d7e907cSAndroid Build Coastguard Worker if (ret != Status::SUCCESS) {
224*4d7e907cSAndroid Build Coastguard Worker ALOGE("Failed to getEnergyData");
225*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(eVal, ret);
226*4d7e907cSAndroid Build Coastguard Worker return Void();
227*4d7e907cSAndroid Build Coastguard Worker }
228*4d7e907cSAndroid Build Coastguard Worker
229*4d7e907cSAndroid Build Coastguard Worker if (railIndices.size() == 0) {
230*4d7e907cSAndroid Build Coastguard Worker eVal.resize(mPm.railsInfo.size());
231*4d7e907cSAndroid Build Coastguard Worker memcpy(&eVal[0], &mPm.reading[0], mPm.reading.size() * sizeof(EnergyData));
232*4d7e907cSAndroid Build Coastguard Worker } else {
233*4d7e907cSAndroid Build Coastguard Worker eVal.resize(railIndices.size());
234*4d7e907cSAndroid Build Coastguard Worker int i = 0;
235*4d7e907cSAndroid Build Coastguard Worker for (const auto& railIndex : railIndices) {
236*4d7e907cSAndroid Build Coastguard Worker if (railIndex >= mPm.reading.size()) {
237*4d7e907cSAndroid Build Coastguard Worker ret = Status::INVALID_INPUT;
238*4d7e907cSAndroid Build Coastguard Worker eVal.resize(0);
239*4d7e907cSAndroid Build Coastguard Worker break;
240*4d7e907cSAndroid Build Coastguard Worker }
241*4d7e907cSAndroid Build Coastguard Worker memcpy(&eVal[i], &mPm.reading[railIndex], sizeof(EnergyData));
242*4d7e907cSAndroid Build Coastguard Worker i++;
243*4d7e907cSAndroid Build Coastguard Worker }
244*4d7e907cSAndroid Build Coastguard Worker }
245*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(eVal, ret);
246*4d7e907cSAndroid Build Coastguard Worker return Void();
247*4d7e907cSAndroid Build Coastguard Worker }
248*4d7e907cSAndroid Build Coastguard Worker
streamEnergyData(uint32_t timeMs,uint32_t samplingRate,streamEnergyData_cb _hidl_cb)249*4d7e907cSAndroid Build Coastguard Worker Return<void> PowerStats::streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
250*4d7e907cSAndroid Build Coastguard Worker streamEnergyData_cb _hidl_cb) {
251*4d7e907cSAndroid Build Coastguard Worker std::lock_guard<std::mutex> _lock(mPm.mLock);
252*4d7e907cSAndroid Build Coastguard Worker if (mPm.fmqSynchronized != nullptr) {
253*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(MessageQueueSync::Descriptor(), 0, 0, Status::INSUFFICIENT_RESOURCES);
254*4d7e907cSAndroid Build Coastguard Worker return Void();
255*4d7e907cSAndroid Build Coastguard Worker }
256*4d7e907cSAndroid Build Coastguard Worker uint32_t sps = std::min(samplingRate, MAX_SAMPLING_RATE);
257*4d7e907cSAndroid Build Coastguard Worker uint32_t numSamples = timeMs * sps / 1000;
258*4d7e907cSAndroid Build Coastguard Worker mPm.fmqSynchronized.reset(new (std::nothrow) MessageQueueSync(MAX_QUEUE_SIZE, true));
259*4d7e907cSAndroid Build Coastguard Worker if (mPm.fmqSynchronized == nullptr || mPm.fmqSynchronized->isValid() == false) {
260*4d7e907cSAndroid Build Coastguard Worker mPm.fmqSynchronized = nullptr;
261*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(MessageQueueSync::Descriptor(), 0, 0, Status::INSUFFICIENT_RESOURCES);
262*4d7e907cSAndroid Build Coastguard Worker return Void();
263*4d7e907cSAndroid Build Coastguard Worker }
264*4d7e907cSAndroid Build Coastguard Worker std::thread pollThread = std::thread([this, sps, numSamples]() {
265*4d7e907cSAndroid Build Coastguard Worker uint64_t sleepTimeUs = 1000000 / sps;
266*4d7e907cSAndroid Build Coastguard Worker uint32_t currSamples = 0;
267*4d7e907cSAndroid Build Coastguard Worker while (currSamples < numSamples) {
268*4d7e907cSAndroid Build Coastguard Worker mPm.mLock.lock();
269*4d7e907cSAndroid Build Coastguard Worker if (parseIioEnergyNodes() == Status::SUCCESS) {
270*4d7e907cSAndroid Build Coastguard Worker mPm.fmqSynchronized->writeBlocking(&mPm.reading[0], mPm.reading.size(),
271*4d7e907cSAndroid Build Coastguard Worker WRITE_TIMEOUT_NS);
272*4d7e907cSAndroid Build Coastguard Worker mPm.mLock.unlock();
273*4d7e907cSAndroid Build Coastguard Worker currSamples++;
274*4d7e907cSAndroid Build Coastguard Worker if (usleep(sleepTimeUs) < 0) {
275*4d7e907cSAndroid Build Coastguard Worker ALOGW("Sleep interrupted");
276*4d7e907cSAndroid Build Coastguard Worker break;
277*4d7e907cSAndroid Build Coastguard Worker }
278*4d7e907cSAndroid Build Coastguard Worker } else {
279*4d7e907cSAndroid Build Coastguard Worker mPm.mLock.unlock();
280*4d7e907cSAndroid Build Coastguard Worker break;
281*4d7e907cSAndroid Build Coastguard Worker }
282*4d7e907cSAndroid Build Coastguard Worker }
283*4d7e907cSAndroid Build Coastguard Worker mPm.mLock.lock();
284*4d7e907cSAndroid Build Coastguard Worker mPm.fmqSynchronized = nullptr;
285*4d7e907cSAndroid Build Coastguard Worker mPm.mLock.unlock();
286*4d7e907cSAndroid Build Coastguard Worker return;
287*4d7e907cSAndroid Build Coastguard Worker });
288*4d7e907cSAndroid Build Coastguard Worker pollThread.detach();
289*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(*(mPm.fmqSynchronized)->getDesc(), numSamples, mPm.reading.size(), Status::SUCCESS);
290*4d7e907cSAndroid Build Coastguard Worker return Void();
291*4d7e907cSAndroid Build Coastguard Worker }
292*4d7e907cSAndroid Build Coastguard Worker
addPowerEntity(const std::string & name,PowerEntityType type)293*4d7e907cSAndroid Build Coastguard Worker uint32_t PowerStats::addPowerEntity(const std::string& name, PowerEntityType type) {
294*4d7e907cSAndroid Build Coastguard Worker uint32_t id = mPowerEntityInfos.size();
295*4d7e907cSAndroid Build Coastguard Worker mPowerEntityInfos.push_back({id, name, type});
296*4d7e907cSAndroid Build Coastguard Worker return id;
297*4d7e907cSAndroid Build Coastguard Worker }
298*4d7e907cSAndroid Build Coastguard Worker
addStateResidencyDataProvider(std::shared_ptr<IStateResidencyDataProvider> p)299*4d7e907cSAndroid Build Coastguard Worker void PowerStats::addStateResidencyDataProvider(std::shared_ptr<IStateResidencyDataProvider> p) {
300*4d7e907cSAndroid Build Coastguard Worker std::vector<PowerEntityStateSpace> stateSpaces = p->getStateSpaces();
301*4d7e907cSAndroid Build Coastguard Worker for (auto stateSpace : stateSpaces) {
302*4d7e907cSAndroid Build Coastguard Worker mPowerEntityStateSpaces.emplace(stateSpace.powerEntityId, stateSpace);
303*4d7e907cSAndroid Build Coastguard Worker mStateResidencyDataProviders.emplace(stateSpace.powerEntityId, p);
304*4d7e907cSAndroid Build Coastguard Worker }
305*4d7e907cSAndroid Build Coastguard Worker }
306*4d7e907cSAndroid Build Coastguard Worker
getPowerEntityInfo(getPowerEntityInfo_cb _hidl_cb)307*4d7e907cSAndroid Build Coastguard Worker Return<void> PowerStats::getPowerEntityInfo(getPowerEntityInfo_cb _hidl_cb) {
308*4d7e907cSAndroid Build Coastguard Worker // If not configured, return NOT_SUPPORTED
309*4d7e907cSAndroid Build Coastguard Worker if (mPowerEntityInfos.empty()) {
310*4d7e907cSAndroid Build Coastguard Worker _hidl_cb({}, Status::NOT_SUPPORTED);
311*4d7e907cSAndroid Build Coastguard Worker return Void();
312*4d7e907cSAndroid Build Coastguard Worker }
313*4d7e907cSAndroid Build Coastguard Worker
314*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(mPowerEntityInfos, Status::SUCCESS);
315*4d7e907cSAndroid Build Coastguard Worker return Void();
316*4d7e907cSAndroid Build Coastguard Worker }
317*4d7e907cSAndroid Build Coastguard Worker
getPowerEntityStateInfo(const hidl_vec<uint32_t> & powerEntityIds,getPowerEntityStateInfo_cb _hidl_cb)318*4d7e907cSAndroid Build Coastguard Worker Return<void> PowerStats::getPowerEntityStateInfo(const hidl_vec<uint32_t>& powerEntityIds,
319*4d7e907cSAndroid Build Coastguard Worker getPowerEntityStateInfo_cb _hidl_cb) {
320*4d7e907cSAndroid Build Coastguard Worker // If not configured, return NOT_SUPPORTED
321*4d7e907cSAndroid Build Coastguard Worker if (mPowerEntityStateSpaces.empty()) {
322*4d7e907cSAndroid Build Coastguard Worker _hidl_cb({}, Status::NOT_SUPPORTED);
323*4d7e907cSAndroid Build Coastguard Worker return Void();
324*4d7e907cSAndroid Build Coastguard Worker }
325*4d7e907cSAndroid Build Coastguard Worker
326*4d7e907cSAndroid Build Coastguard Worker std::vector<PowerEntityStateSpace> stateSpaces;
327*4d7e907cSAndroid Build Coastguard Worker
328*4d7e907cSAndroid Build Coastguard Worker // If powerEntityIds is empty then return state space info for all entities
329*4d7e907cSAndroid Build Coastguard Worker if (powerEntityIds.size() == 0) {
330*4d7e907cSAndroid Build Coastguard Worker stateSpaces.reserve(mPowerEntityStateSpaces.size());
331*4d7e907cSAndroid Build Coastguard Worker for (auto i : mPowerEntityStateSpaces) {
332*4d7e907cSAndroid Build Coastguard Worker stateSpaces.emplace_back(i.second);
333*4d7e907cSAndroid Build Coastguard Worker }
334*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(stateSpaces, Status::SUCCESS);
335*4d7e907cSAndroid Build Coastguard Worker return Void();
336*4d7e907cSAndroid Build Coastguard Worker }
337*4d7e907cSAndroid Build Coastguard Worker
338*4d7e907cSAndroid Build Coastguard Worker // Return state space information only for valid ids
339*4d7e907cSAndroid Build Coastguard Worker auto ret = Status::SUCCESS;
340*4d7e907cSAndroid Build Coastguard Worker stateSpaces.reserve(powerEntityIds.size());
341*4d7e907cSAndroid Build Coastguard Worker for (const uint32_t id : powerEntityIds) {
342*4d7e907cSAndroid Build Coastguard Worker auto stateSpace = mPowerEntityStateSpaces.find(id);
343*4d7e907cSAndroid Build Coastguard Worker if (stateSpace != mPowerEntityStateSpaces.end()) {
344*4d7e907cSAndroid Build Coastguard Worker stateSpaces.emplace_back(stateSpace->second);
345*4d7e907cSAndroid Build Coastguard Worker } else {
346*4d7e907cSAndroid Build Coastguard Worker ret = Status::INVALID_INPUT;
347*4d7e907cSAndroid Build Coastguard Worker }
348*4d7e907cSAndroid Build Coastguard Worker }
349*4d7e907cSAndroid Build Coastguard Worker
350*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(stateSpaces, ret);
351*4d7e907cSAndroid Build Coastguard Worker return Void();
352*4d7e907cSAndroid Build Coastguard Worker }
353*4d7e907cSAndroid Build Coastguard Worker
getPowerEntityStateResidencyData(const hidl_vec<uint32_t> & powerEntityIds,getPowerEntityStateResidencyData_cb _hidl_cb)354*4d7e907cSAndroid Build Coastguard Worker Return<void> PowerStats::getPowerEntityStateResidencyData(
355*4d7e907cSAndroid Build Coastguard Worker const hidl_vec<uint32_t>& powerEntityIds, getPowerEntityStateResidencyData_cb _hidl_cb) {
356*4d7e907cSAndroid Build Coastguard Worker // If not configured, return NOT_SUPPORTED
357*4d7e907cSAndroid Build Coastguard Worker if (mStateResidencyDataProviders.empty() || mPowerEntityStateSpaces.empty()) {
358*4d7e907cSAndroid Build Coastguard Worker _hidl_cb({}, Status::NOT_SUPPORTED);
359*4d7e907cSAndroid Build Coastguard Worker return Void();
360*4d7e907cSAndroid Build Coastguard Worker }
361*4d7e907cSAndroid Build Coastguard Worker
362*4d7e907cSAndroid Build Coastguard Worker // If powerEntityIds is empty then return data for all supported entities
363*4d7e907cSAndroid Build Coastguard Worker if (powerEntityIds.size() == 0) {
364*4d7e907cSAndroid Build Coastguard Worker std::vector<uint32_t> ids;
365*4d7e907cSAndroid Build Coastguard Worker for (auto stateSpace : mPowerEntityStateSpaces) {
366*4d7e907cSAndroid Build Coastguard Worker ids.emplace_back(stateSpace.first);
367*4d7e907cSAndroid Build Coastguard Worker }
368*4d7e907cSAndroid Build Coastguard Worker return getPowerEntityStateResidencyData(ids, _hidl_cb);
369*4d7e907cSAndroid Build Coastguard Worker }
370*4d7e907cSAndroid Build Coastguard Worker
371*4d7e907cSAndroid Build Coastguard Worker std::unordered_map<uint32_t, PowerEntityStateResidencyResult> stateResidencies;
372*4d7e907cSAndroid Build Coastguard Worker std::vector<PowerEntityStateResidencyResult> results;
373*4d7e907cSAndroid Build Coastguard Worker results.reserve(powerEntityIds.size());
374*4d7e907cSAndroid Build Coastguard Worker
375*4d7e907cSAndroid Build Coastguard Worker // return results for only the given powerEntityIds
376*4d7e907cSAndroid Build Coastguard Worker bool invalidInput = false;
377*4d7e907cSAndroid Build Coastguard Worker bool filesystemError = false;
378*4d7e907cSAndroid Build Coastguard Worker for (auto id : powerEntityIds) {
379*4d7e907cSAndroid Build Coastguard Worker auto dataProvider = mStateResidencyDataProviders.find(id);
380*4d7e907cSAndroid Build Coastguard Worker // skip if the given powerEntityId does not have an associated StateResidencyDataProvider
381*4d7e907cSAndroid Build Coastguard Worker if (dataProvider == mStateResidencyDataProviders.end()) {
382*4d7e907cSAndroid Build Coastguard Worker invalidInput = true;
383*4d7e907cSAndroid Build Coastguard Worker continue;
384*4d7e907cSAndroid Build Coastguard Worker }
385*4d7e907cSAndroid Build Coastguard Worker
386*4d7e907cSAndroid Build Coastguard Worker // get the results if we have not already done so.
387*4d7e907cSAndroid Build Coastguard Worker if (stateResidencies.find(id) == stateResidencies.end()) {
388*4d7e907cSAndroid Build Coastguard Worker if (!dataProvider->second->getResults(stateResidencies)) {
389*4d7e907cSAndroid Build Coastguard Worker filesystemError = true;
390*4d7e907cSAndroid Build Coastguard Worker }
391*4d7e907cSAndroid Build Coastguard Worker }
392*4d7e907cSAndroid Build Coastguard Worker
393*4d7e907cSAndroid Build Coastguard Worker // append results
394*4d7e907cSAndroid Build Coastguard Worker auto stateResidency = stateResidencies.find(id);
395*4d7e907cSAndroid Build Coastguard Worker if (stateResidency != stateResidencies.end()) {
396*4d7e907cSAndroid Build Coastguard Worker results.emplace_back(stateResidency->second);
397*4d7e907cSAndroid Build Coastguard Worker }
398*4d7e907cSAndroid Build Coastguard Worker }
399*4d7e907cSAndroid Build Coastguard Worker
400*4d7e907cSAndroid Build Coastguard Worker auto ret = Status::SUCCESS;
401*4d7e907cSAndroid Build Coastguard Worker if (filesystemError) {
402*4d7e907cSAndroid Build Coastguard Worker ret = Status::FILESYSTEM_ERROR;
403*4d7e907cSAndroid Build Coastguard Worker } else if (invalidInput) {
404*4d7e907cSAndroid Build Coastguard Worker ret = Status::INVALID_INPUT;
405*4d7e907cSAndroid Build Coastguard Worker }
406*4d7e907cSAndroid Build Coastguard Worker
407*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(results, ret);
408*4d7e907cSAndroid Build Coastguard Worker return Void();
409*4d7e907cSAndroid Build Coastguard Worker }
410*4d7e907cSAndroid Build Coastguard Worker
DumpResidencyDataToFd(const hidl_vec<PowerEntityInfo> & infos,const hidl_vec<PowerEntityStateSpace> & stateSpaces,const hidl_vec<PowerEntityStateResidencyResult> & results,int fd)411*4d7e907cSAndroid Build Coastguard Worker bool DumpResidencyDataToFd(const hidl_vec<PowerEntityInfo>& infos,
412*4d7e907cSAndroid Build Coastguard Worker const hidl_vec<PowerEntityStateSpace>& stateSpaces,
413*4d7e907cSAndroid Build Coastguard Worker const hidl_vec<PowerEntityStateResidencyResult>& results, int fd) {
414*4d7e907cSAndroid Build Coastguard Worker // construct lookup table of powerEntityId to name
415*4d7e907cSAndroid Build Coastguard Worker std::unordered_map<uint32_t, std::string> entityNames;
416*4d7e907cSAndroid Build Coastguard Worker for (auto info : infos) {
417*4d7e907cSAndroid Build Coastguard Worker entityNames.emplace(info.powerEntityId, info.powerEntityName);
418*4d7e907cSAndroid Build Coastguard Worker }
419*4d7e907cSAndroid Build Coastguard Worker
420*4d7e907cSAndroid Build Coastguard Worker // construct lookup table of powerEntityId, powerEntityStateId to state name
421*4d7e907cSAndroid Build Coastguard Worker std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> stateNames;
422*4d7e907cSAndroid Build Coastguard Worker for (auto stateSpace : stateSpaces) {
423*4d7e907cSAndroid Build Coastguard Worker stateNames.emplace(stateSpace.powerEntityId, std::unordered_map<uint32_t, std::string>());
424*4d7e907cSAndroid Build Coastguard Worker for (auto state : stateSpace.states) {
425*4d7e907cSAndroid Build Coastguard Worker stateNames.at(stateSpace.powerEntityId)
426*4d7e907cSAndroid Build Coastguard Worker .emplace(state.powerEntityStateId, state.powerEntityStateName);
427*4d7e907cSAndroid Build Coastguard Worker }
428*4d7e907cSAndroid Build Coastguard Worker }
429*4d7e907cSAndroid Build Coastguard Worker
430*4d7e907cSAndroid Build Coastguard Worker std::ostringstream dumpStats;
431*4d7e907cSAndroid Build Coastguard Worker dumpStats << "\n========== PowerStats HAL 1.0 state residencies ==========\n";
432*4d7e907cSAndroid Build Coastguard Worker
433*4d7e907cSAndroid Build Coastguard Worker const char* headerFormat = " %14s %14s %16s %15s %16s\n";
434*4d7e907cSAndroid Build Coastguard Worker const char* dataFormat =
435*4d7e907cSAndroid Build Coastguard Worker " %14s %14s %13" PRIu64 " ms %15" PRIu64 " %13" PRIu64 " ms\n";
436*4d7e907cSAndroid Build Coastguard Worker dumpStats << android::base::StringPrintf(headerFormat, "Entity", "State", "Total time",
437*4d7e907cSAndroid Build Coastguard Worker "Total entries", "Last entry timestamp");
438*4d7e907cSAndroid Build Coastguard Worker
439*4d7e907cSAndroid Build Coastguard Worker for (auto result : results) {
440*4d7e907cSAndroid Build Coastguard Worker for (auto stateResidency : result.stateResidencyData) {
441*4d7e907cSAndroid Build Coastguard Worker dumpStats << android::base::StringPrintf(
442*4d7e907cSAndroid Build Coastguard Worker dataFormat, entityNames.at(result.powerEntityId).c_str(),
443*4d7e907cSAndroid Build Coastguard Worker stateNames.at(result.powerEntityId)
444*4d7e907cSAndroid Build Coastguard Worker .at(stateResidency.powerEntityStateId)
445*4d7e907cSAndroid Build Coastguard Worker .c_str(),
446*4d7e907cSAndroid Build Coastguard Worker stateResidency.totalTimeInStateMs, stateResidency.totalStateEntryCount,
447*4d7e907cSAndroid Build Coastguard Worker stateResidency.lastEntryTimestampMs);
448*4d7e907cSAndroid Build Coastguard Worker }
449*4d7e907cSAndroid Build Coastguard Worker }
450*4d7e907cSAndroid Build Coastguard Worker
451*4d7e907cSAndroid Build Coastguard Worker dumpStats << "========== End of PowerStats HAL 1.0 state residencies ==========\n";
452*4d7e907cSAndroid Build Coastguard Worker
453*4d7e907cSAndroid Build Coastguard Worker return android::base::WriteStringToFd(dumpStats.str(), fd);
454*4d7e907cSAndroid Build Coastguard Worker }
455*4d7e907cSAndroid Build Coastguard Worker
debug(const hidl_handle & handle,const hidl_vec<hidl_string> &)456*4d7e907cSAndroid Build Coastguard Worker Return<void> PowerStats::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
457*4d7e907cSAndroid Build Coastguard Worker if (handle == nullptr || handle->numFds < 1) {
458*4d7e907cSAndroid Build Coastguard Worker return Void();
459*4d7e907cSAndroid Build Coastguard Worker }
460*4d7e907cSAndroid Build Coastguard Worker
461*4d7e907cSAndroid Build Coastguard Worker int fd = handle->data[0];
462*4d7e907cSAndroid Build Coastguard Worker Status status;
463*4d7e907cSAndroid Build Coastguard Worker hidl_vec<PowerEntityInfo> infos;
464*4d7e907cSAndroid Build Coastguard Worker
465*4d7e907cSAndroid Build Coastguard Worker // Get power entity information
466*4d7e907cSAndroid Build Coastguard Worker getPowerEntityInfo([&status, &infos](auto rInfos, auto rStatus) {
467*4d7e907cSAndroid Build Coastguard Worker status = rStatus;
468*4d7e907cSAndroid Build Coastguard Worker infos = rInfos;
469*4d7e907cSAndroid Build Coastguard Worker });
470*4d7e907cSAndroid Build Coastguard Worker if (status != Status::SUCCESS) {
471*4d7e907cSAndroid Build Coastguard Worker LOG(ERROR) << "Error getting power entity info";
472*4d7e907cSAndroid Build Coastguard Worker return Void();
473*4d7e907cSAndroid Build Coastguard Worker }
474*4d7e907cSAndroid Build Coastguard Worker
475*4d7e907cSAndroid Build Coastguard Worker // Get power entity state information
476*4d7e907cSAndroid Build Coastguard Worker hidl_vec<PowerEntityStateSpace> stateSpaces;
477*4d7e907cSAndroid Build Coastguard Worker getPowerEntityStateInfo({}, [&status, &stateSpaces](auto rStateSpaces, auto rStatus) {
478*4d7e907cSAndroid Build Coastguard Worker status = rStatus;
479*4d7e907cSAndroid Build Coastguard Worker stateSpaces = rStateSpaces;
480*4d7e907cSAndroid Build Coastguard Worker });
481*4d7e907cSAndroid Build Coastguard Worker if (status != Status::SUCCESS) {
482*4d7e907cSAndroid Build Coastguard Worker LOG(ERROR) << "Error getting state info";
483*4d7e907cSAndroid Build Coastguard Worker return Void();
484*4d7e907cSAndroid Build Coastguard Worker }
485*4d7e907cSAndroid Build Coastguard Worker
486*4d7e907cSAndroid Build Coastguard Worker // Get power entity state residency data
487*4d7e907cSAndroid Build Coastguard Worker hidl_vec<PowerEntityStateResidencyResult> results;
488*4d7e907cSAndroid Build Coastguard Worker getPowerEntityStateResidencyData({}, [&status, &results](auto rResults, auto rStatus) {
489*4d7e907cSAndroid Build Coastguard Worker status = rStatus;
490*4d7e907cSAndroid Build Coastguard Worker results = rResults;
491*4d7e907cSAndroid Build Coastguard Worker });
492*4d7e907cSAndroid Build Coastguard Worker
493*4d7e907cSAndroid Build Coastguard Worker // This implementation of getPowerEntityStateResidencyData supports the
494*4d7e907cSAndroid Build Coastguard Worker // return of partial results if status == FILESYSTEM_ERROR.
495*4d7e907cSAndroid Build Coastguard Worker if (status != Status::SUCCESS) {
496*4d7e907cSAndroid Build Coastguard Worker LOG(ERROR) << "Error getting residency data -- Some results missing";
497*4d7e907cSAndroid Build Coastguard Worker }
498*4d7e907cSAndroid Build Coastguard Worker
499*4d7e907cSAndroid Build Coastguard Worker if (!DumpResidencyDataToFd(infos, stateSpaces, results, fd)) {
500*4d7e907cSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to dump residency data to fd";
501*4d7e907cSAndroid Build Coastguard Worker }
502*4d7e907cSAndroid Build Coastguard Worker
503*4d7e907cSAndroid Build Coastguard Worker fsync(fd);
504*4d7e907cSAndroid Build Coastguard Worker
505*4d7e907cSAndroid Build Coastguard Worker return Void();
506*4d7e907cSAndroid Build Coastguard Worker }
507*4d7e907cSAndroid Build Coastguard Worker
508*4d7e907cSAndroid Build Coastguard Worker } // namespace implementation
509*4d7e907cSAndroid Build Coastguard Worker } // namespace V1_0
510*4d7e907cSAndroid Build Coastguard Worker } // namespace stats
511*4d7e907cSAndroid Build Coastguard Worker } // namespace power
512*4d7e907cSAndroid Build Coastguard Worker } // namespace hardware
513*4d7e907cSAndroid Build Coastguard Worker } // namespace android
514