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
17 #define LOG_TAG "AudioToken"
18 #include <android-base/logging.h>
19 #include <utils/Log.h>
20 #include "AudioToken.h"
21 #include <psh_utils/AudioPowerManager.h>
22
23 namespace android::media::psh_utils {
24
25 /* static */
26 constinit std::atomic<size_t> AudioClientToken::sIdCounter{};
27
AudioClientToken(std::shared_ptr<PowerClientStats> powerClientStats,pid_t pid,uid_t uid,const std::string & additional)28 AudioClientToken::AudioClientToken(
29 std::shared_ptr<PowerClientStats> powerClientStats, pid_t pid, uid_t uid,
30 const std::string& additional)
31 : mPowerClientStats(std::move(powerClientStats))
32 , mPid(pid)
33 , mAdditional(additional)
34 , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
35 (void)uid;
36 }
37
~AudioClientToken()38 AudioClientToken::~AudioClientToken() {
39 auto& apm = AudioPowerManager::getAudioPowerManager();
40
41 // APM has a back pointer to AudioToken, which is accessible on toString().
42 // We first remove ourselves to prevent use after free.
43 apm.clear_token_ptr(this);
44
45 // The client token is released when it is no longer registered with AudioFlinger.
46 // However, it is possible that AudioTrackTokens are still active when the client is released
47 // after crashing and some of its tracks are draining. Those track tokens also
48 // maintain a pointer to the PowerClientStats keeping that consistent.
49
50 // Stopping the client moves its PowerClientStats from active to historical
51 // if it is the last pid associated with the client uid.
52 apm.stopClient(mPid);
53 }
54
toString() const55 std::string AudioClientToken::toString() const {
56 std::string result("Client-");
57 result.append(std::to_string(mId)).append(": ")
58 .append(" pid: ").append(std::to_string(mPid));
59 if (!mAdditional.empty()) {
60 result.append(" ").append(mAdditional);
61 }
62 return result;
63 }
64
createAudioClientToken(pid_t pid,uid_t uid,const std::string & additional)65 std::unique_ptr<Token> createAudioClientToken(pid_t pid, uid_t uid,
66 const std::string& additional) {
67 return AudioPowerManager::getAudioPowerManager().startClient(pid, uid, additional);
68 }
69
70 /* static */
71 constinit std::atomic<size_t> AudioThreadToken::sIdCounter{};
72
AudioThreadToken(pid_t tid,const std::string & wakeLockName,WakeFlag wakeFlag,const std::string & additional)73 AudioThreadToken::AudioThreadToken(
74 pid_t tid, const std::string& wakeLockName,
75 WakeFlag wakeFlag, const std::string& additional)
76 : mTid(tid)
77 , mWakeLockName(wakeLockName)
78 , mWakeFlag(wakeFlag)
79 , mAdditional(additional)
80 , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
81 }
82
~AudioThreadToken()83 AudioThreadToken::~AudioThreadToken() {
84 auto& apm = AudioPowerManager::getAudioPowerManager();
85
86 // APM has a back pointer to AudioToken, which is accessible on toString().
87 // We first remove ourselves to prevent use after free.
88 apm.clear_token_ptr(this);
89 }
90
toString() const91 std::string AudioThreadToken::toString() const {
92 std::string result("Thread-");
93 result.append(std::to_string(mId)).append(": ")
94 .append(" ThreadBase-tid: ").append(std::to_string(mTid))
95 .append(" wakeLockName: ").append(mWakeLockName)
96 .append(" wakeFlag: ").append(::android::media::psh_utils::toString(mWakeFlag));
97 if (!mAdditional.empty()) {
98 result.append(" ").append(mAdditional);
99 }
100 return result;
101 }
102
createAudioThreadToken(pid_t pid,const std::string & wakeLockName,WakeFlag wakeFlag,const std::string & additional)103 std::unique_ptr<Token> createAudioThreadToken(
104 pid_t pid, const std::string& wakeLockName,
105 WakeFlag wakeFlag, const std::string& additional) {
106 return AudioPowerManager::getAudioPowerManager().startThread(
107 pid, wakeLockName, wakeFlag, additional);
108 }
109
110 /* static */
111 constinit std::atomic<size_t> AudioTrackToken::sIdCounter{};
112
AudioTrackToken(std::shared_ptr<PowerClientStats> powerClientStats,const std::string & additional)113 AudioTrackToken::AudioTrackToken(
114 std::shared_ptr<PowerClientStats> powerClientStats, const std::string& additional)
115 : mPowerClientStats(std::move(powerClientStats))
116 , mAdditional(additional)
117 , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
118 if (mPowerClientStats){
119 mPowerClientStats->getCommandThread().add(
120 "start",
121 [pas = mPowerClientStats, actualNs = systemTime(SYSTEM_TIME_BOOTTIME)]() {
122 pas->start(actualNs);
123 });
124 }
125 }
126
~AudioTrackToken()127 AudioTrackToken::~AudioTrackToken() {
128 // APM has a back pointer to AudioToken, which is accessible on toString().
129 // We first remove ourselves to prevent use after free.
130 AudioPowerManager::getAudioPowerManager().clear_token_ptr(this);
131 if (mPowerClientStats) {
132 mPowerClientStats->getCommandThread().add(
133 "stop",
134 [pas = mPowerClientStats, actualNs = systemTime(SYSTEM_TIME_BOOTTIME)]() {
135 pas->stop(actualNs);
136 });
137 }
138 }
139
toString() const140 std::string AudioTrackToken::toString() const {
141 std::string result("Track-");
142 result.append(std::to_string(mId)).append(": ")
143 .append(mPowerClientStats ? mPowerClientStats->toString() : std::string("null"));
144 if (!mAdditional.empty()) {
145 result.append(" ").append(mAdditional);
146 }
147 return result;
148 }
149
createAudioTrackToken(uid_t uid,const std::string & additional)150 std::unique_ptr<Token> createAudioTrackToken(uid_t uid, const std::string& additional) {
151 return AudioPowerManager::getAudioPowerManager().startTrack(uid, additional);
152 }
153
154
155 } // namespace android::media::psh_utils
156