1 /*
2  * Copyright (C) 2022 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 "AocTimedStateResidencyDataProvider.h"
18 
19 #include <android-base/logging.h>
20 #include <chrono>
21 
22 namespace aidl {
23 namespace android {
24 namespace hardware {
25 namespace power {
26 namespace stats {
27 
AocTimedStateResidencyDataProvider(std::vector<std::pair<std::string,std::string>> ids,std::vector<std::pair<std::string,std::string>> states,const uint64_t timeoutMillis,const uint64_t aocClock)28 AocTimedStateResidencyDataProvider::AocTimedStateResidencyDataProvider(
29     std::vector<std::pair<std::string, std::string>> ids,
30     std::vector<std::pair<std::string, std::string>> states,
31     const uint64_t timeoutMillis,
32     const uint64_t aocClock)
33     : AocStateResidencyDataProvider(ids, states, aocClock) {
34   static const uint64_t DEFAULT_MAX_TIME_PER_STATE_MILLIS = 120;
35 
36   mTimeoutMillis =
37       timeoutMillis == 0 ? DEFAULT_MAX_TIME_PER_STATE_MILLIS * states.size() : timeoutMillis;
38 
39   mAsyncThread = std::thread(&AocTimedStateResidencyDataProvider::getStateResidenciesAsync, this);
40 }
41 
getStateResidencies(std::unordered_map<std::string,std::vector<StateResidency>> * residencies)42 bool AocTimedStateResidencyDataProvider::getStateResidencies(
43     std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
44   bool ret = true;
45   std::unique_lock<std::mutex> statusLock(mStatusMutex);
46 
47   if (mAsyncStatus != COMPLETED) {
48     LOG(ERROR) << "The async thread is not ready: " << mAsyncStatus;
49     return false;
50   }
51 
52   mStateResidencies.clear();
53 
54   mAsyncStatus = RUN;
55   mRunCond.notify_one();
56 
57   auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(mTimeoutMillis);
58   auto isCompleted =
59       mCompletedCond.wait_until(statusLock, timeout, [this]{ return mAsyncStatus == COMPLETED; });
60 
61   if (isCompleted) {
62     for (const auto &residency : mStateResidencies) {
63       residencies->emplace(residency.first, residency.second);
64     }
65   } else {
66     LOG(ERROR) << __func__ << " for AoC timed out: " << mTimeoutMillis << " ms";
67     ret = false;
68   }
69 
70   return ret;
71 }
72 
getStateResidenciesAsync()73 void AocTimedStateResidencyDataProvider::getStateResidenciesAsync() {
74   std::unique_lock<std::mutex> statusLock(mStatusMutex);
75 
76   mAsyncStatus = COMPLETED;
77 
78   while (1) {
79     mRunCond.wait(statusLock, [this]{ return mAsyncStatus == RUN; });
80 
81     mAsyncStatus = RUNNING;
82     statusLock.unlock();
83 
84     // States from the same power entity are merged.
85     for (const auto &providerList : mProviders) {
86       int32_t stateId = 0;
87       std::string curEntity = providerList.first;
88       std::vector<StateResidency> stateResidencies;
89 
90       // Iterate over each provider in the providerList, appending each of the states
91       for (const auto &provider : providerList.second) {
92         std::unordered_map<std::string, std::vector<StateResidency>> residency;
93         provider->getStateResidencies(&residency);
94 
95         // Each provider should only return data for curEntity but checking anyway
96         if (residency.find(curEntity) != residency.end()) {
97           for (auto &r : residency.at(curEntity)) {
98             /*
99              * Modifying stateId here because we are stitching together infos from
100              * multiple GenericStateResidencyDataProviders. stateId must be modified
101              * to maintain uniqueness for a given entity
102              */
103             r.id = stateId++;
104             stateResidencies.push_back(r);
105           }
106         }
107       }
108       mStateResidencies.emplace(curEntity, stateResidencies);
109     }
110 
111     statusLock.lock();
112     mAsyncStatus = COMPLETED;
113     mCompletedCond.notify_one();
114   } // while loop
115 }
116 
117 }  // namespace stats
118 }  // namespace power
119 }  // namespace hardware
120 }  // namespace android
121 }  // namespace aidl
122