xref: /aosp_15_r20/hardware/interfaces/power/stats/1.0/default/PowerStats.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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