/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "PowerStatsProvider.h" #include namespace android::media::psh_utils { PowerStatsCollector::PowerStatsCollector() { addProvider(std::make_unique()); addProvider(std::make_unique()); addProvider(std::make_unique()); } /* static */ PowerStatsCollector& PowerStatsCollector::getCollector() { [[clang::no_destroy]] static PowerStatsCollector psc; return psc; } std::shared_ptr PowerStatsCollector::getStats(int64_t toleranceNs) { // Check if there is a cached PowerStats result available. // As toleranceNs may be different between callers, it may be that some callers // are blocked on mMutexExclusiveFill for a new stats result, while other callers // may find the current cached result acceptable (within toleranceNs). if (toleranceNs > 0) { auto result = checkLastStats(toleranceNs); if (result) return result; } // Take the mMutexExclusiveFill to ensure only one thread is filling. std::lock_guard lg1(mMutexExclusiveFill); // As obtaining a new PowerStats snapshot might take some time, // check again to see if another waiting thread filled the cached result for us. if (toleranceNs > 0) { auto result = checkLastStats(toleranceNs); if (result) return result; } auto result = std::make_shared(); (void)fill(result.get()); std::lock_guard lg2(mMutex); mLastFetchNs = systemTime(SYSTEM_TIME_BOOTTIME); mLastFetchStats = result; return result; } std::shared_ptr PowerStatsCollector::checkLastStats(int64_t toleranceNs) const { if (toleranceNs > 0) { // see if we can return an old result. std::lock_guard lg(mMutex); if (mLastFetchStats && systemTime(SYSTEM_TIME_BOOTTIME) - mLastFetchNs < toleranceNs) { return mLastFetchStats; } } return {}; } void PowerStatsCollector::addProvider(std::unique_ptr&& powerStatsProvider) { mPowerStatsProviders.emplace_back(std::move(powerStatsProvider)); } int PowerStatsCollector::fill(PowerStats* stats) const { if (!stats) { LOG(ERROR) << __func__ << ": bad args; stat is null"; return 1; } for (const auto& provider : mPowerStatsProviders) { (void) provider->fill(stats); // on error, we continue to proceed. } // boot time follows wall clock time, but starts from boot. stats->metadata.start_time_since_boot_ms = systemTime(SYSTEM_TIME_BOOTTIME) / 1'000'000; // wall clock time stats->metadata.start_time_epoch_ms = systemTime(SYSTEM_TIME_REALTIME) / 1'000'000; // monotonic time follows boot time, but does not include any time suspended. stats->metadata.start_time_monotonic_ms = systemTime() / 1'000'000; return 0; } } // namespace android::media::psh_utils