| /* |
| * 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 "AudioToken.h" |
| #define LOG_TAG "AudioPowerManager" |
| #include <com_android_media_audioserver.h> |
| #include <cutils/properties.h> |
| #include <utils/Log.h> |
| #include <psh_utils/AudioPowerManager.h> |
| |
| namespace android::media::psh_utils { |
| |
| /* static */ |
| AudioPowerManager& AudioPowerManager::getAudioPowerManager() { |
| [[clang::no_destroy]] static AudioPowerManager apm; |
| return apm; |
| } |
| |
| std::unique_ptr<Token> AudioPowerManager::startClient(pid_t pid, uid_t uid, |
| const std::string& additional) { |
| std::shared_ptr<PowerClientStats> powerClientStats; |
| std::lock_guard l(mMutex); |
| if (mPowerClientStats.count(uid) == 0) { |
| const auto it = mHistoricalClients.find(uid); |
| if (it == mHistoricalClients.end()) { |
| powerClientStats = std::make_shared<PowerClientStats>(uid, additional); |
| } else { |
| powerClientStats = it->second; |
| mHistoricalClients.erase(it); |
| } |
| mPowerClientStats[uid] = powerClientStats; |
| } else { |
| powerClientStats = mPowerClientStats[uid]; |
| } |
| powerClientStats->addPid(pid); |
| mPidToUid[pid] = uid; |
| std::unique_ptr<Token> token = |
| std::make_unique<AudioClientToken>(powerClientStats, pid, uid, additional); |
| mOutstandingTokens.emplace(token.get()); |
| return token; |
| } |
| |
| std::unique_ptr<Token> AudioPowerManager::startTrack(uid_t uid, const std::string& additional) { |
| std::lock_guard l(mMutex); |
| if (mPowerClientStats.count(uid) == 0) { |
| ALOGW("%s: Cannot find uid: %d", __func__, uid); |
| return {}; |
| } |
| auto powerClientStats = mPowerClientStats[uid]; |
| std::unique_ptr<Token> token = |
| std::make_unique<AudioTrackToken>(powerClientStats, additional); |
| mOutstandingTokens.emplace(token.get()); |
| return token; |
| } |
| |
| std::unique_ptr<Token> AudioPowerManager::startThread( |
| pid_t pid, const std::string& wakeLockName, |
| WakeFlag wakeFlag, const std::string& additional) { |
| std::lock_guard l(mMutex); |
| std::unique_ptr<Token> token = |
| std::make_unique<AudioThreadToken>(pid, wakeLockName, wakeFlag, additional); |
| mOutstandingTokens.emplace(token.get()); |
| return token; |
| } |
| |
| std::string AudioPowerManager::toString() const { |
| const std::string prefix(" "); |
| std::string result; |
| std::lock_guard l(mMutex); |
| result.append("Power Tokens:\n"); |
| std::vector<std::string> tokenInfo; |
| for (const auto& token: mOutstandingTokens) { |
| tokenInfo.emplace_back(token->toString()); |
| } |
| std::sort(tokenInfo.begin(), tokenInfo.end()); |
| for (const auto& info: tokenInfo) { |
| result.append(prefix).append(info).append("\n"); |
| } |
| result.append("Power Clients:\n"); |
| for (const auto& [uid, powerClientStats]: mPowerClientStats) { |
| result.append(powerClientStats->toString(true, prefix)); |
| } |
| result.append("Power Client History:\n"); |
| for (const auto& [power, powerClientStats]: mHistoricalClients) { |
| result.append(powerClientStats->toString(true, prefix)); |
| } |
| return result; |
| } |
| |
| void AudioPowerManager::stopClient(pid_t pid) { |
| std::lock_guard l(mMutex); |
| const auto pidit = mPidToUid.find(pid); |
| if (pidit == mPidToUid.end()) return; |
| const uid_t uid = pidit->second; |
| const auto it = mPowerClientStats.find(uid); |
| if (it == mPowerClientStats.end()) return; |
| |
| auto powerClientStats = it->second; |
| size_t count = powerClientStats->removePid(pid); |
| if (count == 0) { |
| mHistoricalClients[uid] = powerClientStats; |
| mPowerClientStats.erase(it); |
| if (mHistoricalClients.size() > kHistory) { |
| mHistoricalClients.erase(mHistoricalClients.begin()); // remove oldest. |
| } |
| } |
| mPidToUid.erase(pid); |
| } |
| |
| void AudioPowerManager::clear_token_ptr(Token* token) { |
| if (token != nullptr) { |
| std::lock_guard l(mMutex); |
| (void)mOutstandingTokens.erase(token); |
| } |
| } |
| |
| /* static */ |
| bool AudioPowerManager::enabled() { |
| static const bool enabled = com::android::media::audioserver::power_stats() |
| && property_get_bool("persist.audio.power_stats.enabled", false); |
| return enabled; |
| } |
| |
| } // namespace android::media::psh_utils |