1 /*
2 * Copyright (C) 2024 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 #include <android-base/logging.h>
17 #include <psh_utils/PowerStatsCollector.h>
18 #include "PowerStatsProvider.h"
19 #include <utils/Timers.h>
20
21 namespace android::media::psh_utils {
22
PowerStatsCollector()23 PowerStatsCollector::PowerStatsCollector() {
24 addProvider(std::make_unique<PowerEntityResidencyDataProvider>());
25 addProvider(std::make_unique<RailEnergyDataProvider>());
26 addProvider(std::make_unique<HealthStatsDataProvider>());
27 }
28
29 /* static */
getCollector()30 PowerStatsCollector& PowerStatsCollector::getCollector() {
31 [[clang::no_destroy]] static PowerStatsCollector psc;
32 return psc;
33 }
34
getStats(int64_t toleranceNs)35 std::shared_ptr<const PowerStats> PowerStatsCollector::getStats(int64_t toleranceNs) {
36 // Check if there is a cached PowerStats result available.
37 // As toleranceNs may be different between callers, it may be that some callers
38 // are blocked on mMutexExclusiveFill for a new stats result, while other callers
39 // may find the current cached result acceptable (within toleranceNs).
40 if (toleranceNs > 0) {
41 auto result = checkLastStats(toleranceNs);
42 if (result) return result;
43 }
44
45 // Take the mMutexExclusiveFill to ensure only one thread is filling.
46 std::lock_guard lg1(mMutexExclusiveFill);
47 // As obtaining a new PowerStats snapshot might take some time,
48 // check again to see if another waiting thread filled the cached result for us.
49 if (toleranceNs > 0) {
50 auto result = checkLastStats(toleranceNs);
51 if (result) return result;
52 }
53 auto result = std::make_shared<PowerStats>();
54 (void)fill(result.get());
55 std::lock_guard lg2(mMutex);
56 mLastFetchNs = systemTime(SYSTEM_TIME_BOOTTIME);
57 mLastFetchStats = result;
58 return result;
59 }
60
checkLastStats(int64_t toleranceNs) const61 std::shared_ptr<const PowerStats> PowerStatsCollector::checkLastStats(int64_t toleranceNs) const {
62 if (toleranceNs > 0) {
63 // see if we can return an old result.
64 std::lock_guard lg(mMutex);
65 if (mLastFetchStats && systemTime(SYSTEM_TIME_BOOTTIME) - mLastFetchNs < toleranceNs) {
66 return mLastFetchStats;
67 }
68 }
69 return {};
70 }
71
addProvider(std::unique_ptr<PowerStatsProvider> && powerStatsProvider)72 void PowerStatsCollector::addProvider(std::unique_ptr<PowerStatsProvider>&& powerStatsProvider) {
73 mPowerStatsProviders.emplace_back(std::move(powerStatsProvider));
74 }
75
fill(PowerStats * stats) const76 int PowerStatsCollector::fill(PowerStats* stats) const {
77 if (!stats) {
78 LOG(ERROR) << __func__ << ": bad args; stat is null";
79 return 1;
80 }
81
82 for (const auto& provider : mPowerStatsProviders) {
83 (void) provider->fill(stats); // on error, we continue to proceed.
84 }
85
86 // boot time follows wall clock time, but starts from boot.
87 stats->metadata.start_time_since_boot_ms = systemTime(SYSTEM_TIME_BOOTTIME) / 1'000'000;
88
89 // wall clock time
90 stats->metadata.start_time_epoch_ms = systemTime(SYSTEM_TIME_REALTIME) / 1'000'000;
91
92 // monotonic time follows boot time, but does not include any time suspended.
93 stats->metadata.start_time_monotonic_ms = systemTime() / 1'000'000;
94 return 0;
95 }
96
97 } // namespace android::media::psh_utils
98