1 /*
2  * Copyright (C) 2020 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_NDEBUG 0
18 #define LOG_TAG "AudioPowerUsage"
19 #include <utils/Log.h>
20 
21 #include "AudioAnalytics.h"
22 #include "MediaMetricsService.h"
23 #include "StringUtils.h"
24 #include <map>
25 #include <sstream>
26 #include <string>
27 #include <audio_utils/clock.h>
28 #include <cutils/properties.h>
29 #include <stats_media_metrics.h>
30 #include <sys/timerfd.h>
31 #include <system/audio.h>
32 
33 // property to disable audio power use metrics feature, default is enabled
34 #define PROP_AUDIO_METRICS_DISABLED "persist.media.audio_metrics.power_usage_disabled"
35 #define AUDIO_METRICS_DISABLED_DEFAULT (false)
36 
37 // property to set how long to send audio power use metrics data to statsd, default is 24hrs
38 #define PROP_AUDIO_METRICS_INTERVAL_HR "persist.media.audio_metrics.interval_hr"
39 #define INTERVAL_HR_DEFAULT (24)
40 
41 // for Audio Power Usage Metrics
42 #define AUDIO_POWER_USAGE_KEY_AUDIO_USAGE     "audio.power.usage"
43 
44 #define AUDIO_POWER_USAGE_PROP_DEVICE         "device"     // int32
45 #define AUDIO_POWER_USAGE_PROP_DURATION_NS    "durationNs" // int64
46 #define AUDIO_POWER_USAGE_PROP_TYPE           "type"       // int32
47 #define AUDIO_POWER_USAGE_PROP_VOLUME         "volume"     // double
48 #define AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS "minVolumeDurationNs" // int64
49 #define AUDIO_POWER_USAGE_PROP_MIN_VOLUME             "minVolume"           // double
50 #define AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS "maxVolumeDurationNs" // int64
51 #define AUDIO_POWER_USAGE_PROP_MAX_VOLUME             "maxVolume"           // double
52 
53 namespace android::mediametrics {
54 
55 /* static */
typeFromString(const std::string & type_string,int32_t & type)56 bool AudioPowerUsage::typeFromString(const std::string& type_string, int32_t& type) {
57     static std::map<std::string, int32_t> typeTable = {
58         { "AUDIO_STREAM_VOICE_CALL",          VOIP_CALL_TYPE },
59         { "AUDIO_STREAM_SYSTEM",              MEDIA_TYPE },
60         { "AUDIO_STREAM_RING",                RINGTONE_NOTIFICATION_TYPE },
61         { "AUDIO_STREAM_MUSIC",               MEDIA_TYPE },
62         { "AUDIO_STREAM_ALARM",               ALARM_TYPE },
63         { "AUDIO_STREAM_NOTIFICATION",        RINGTONE_NOTIFICATION_TYPE },
64 
65         { "AUDIO_CONTENT_TYPE_SPEECH",        VOIP_CALL_TYPE },
66         { "AUDIO_CONTENT_TYPE_MUSIC",         MEDIA_TYPE },
67         { "AUDIO_CONTENT_TYPE_MOVIE",         MEDIA_TYPE },
68         { "AUDIO_CONTENT_TYPE_SONIFICATION",  RINGTONE_NOTIFICATION_TYPE },
69 
70         { "AUDIO_USAGE_MEDIA",                MEDIA_TYPE },
71         { "AUDIO_USAGE_VOICE_COMMUNICATION",  VOIP_CALL_TYPE },
72         { "AUDIO_USAGE_ALARM",                ALARM_TYPE },
73         { "AUDIO_USAGE_NOTIFICATION",         RINGTONE_NOTIFICATION_TYPE },
74 
75         { "AUDIO_SOURCE_CAMCORDER",           CAMCORDER_TYPE },
76         { "AUDIO_SOURCE_VOICE_COMMUNICATION", VOIP_CALL_TYPE },
77         { "AUDIO_SOURCE_DEFAULT",             RECORD_TYPE },
78         { "AUDIO_SOURCE_MIC",                 RECORD_TYPE },
79         { "AUDIO_SOURCE_UNPROCESSED",         RECORD_TYPE },
80         { "AUDIO_SOURCE_VOICE_RECOGNITION",   RECORD_TYPE },
81     };
82 
83     auto it = typeTable.find(type_string);
84     if (it == typeTable.end()) {
85         type = UNKNOWN_TYPE;
86         return false;
87     }
88 
89     type = it->second;
90     return true;
91 }
92 
93 /* static */
deviceFromString(const std::string & device_string,int32_t & device)94 bool AudioPowerUsage::deviceFromString(const std::string& device_string, int32_t& device) {
95     static std::map<std::string, int32_t> deviceTable = {
96         { "AUDIO_DEVICE_OUT_EARPIECE",                  OUTPUT_EARPIECE },
97         { "AUDIO_DEVICE_OUT_SPEAKER_SAFE",              OUTPUT_SPEAKER_SAFE },
98         { "AUDIO_DEVICE_OUT_SPEAKER",                   OUTPUT_SPEAKER },
99         { "AUDIO_DEVICE_OUT_WIRED_HEADSET",             OUTPUT_WIRED_HEADSET },
100         { "AUDIO_DEVICE_OUT_WIRED_HEADPHONE",           OUTPUT_WIRED_HEADSET },
101         { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO",             OUTPUT_BLUETOOTH_SCO },
102         { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET",     OUTPUT_BLUETOOTH_SCO },
103         { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP",            OUTPUT_BLUETOOTH_A2DP },
104         { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES", OUTPUT_BLUETOOTH_A2DP },
105         { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER",    OUTPUT_BLUETOOTH_A2DP },
106         { "AUDIO_DEVICE_OUT_BLE_HEADSET",               OUTPUT_BLUETOOTH_BLE },
107         { "AUDIO_DEVICE_OUT_BLE_SPEAKER",               OUTPUT_BLUETOOTH_BLE },
108         { "AUDIO_DEVICE_OUT_BLE_BROADCAST",             OUTPUT_BLUETOOTH_BLE },
109         { "AUDIO_DEVICE_OUT_USB_HEADSET",               OUTPUT_USB_HEADSET },
110         { "AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET",         OUTPUT_DOCK },
111         { "AUDIO_DEVICE_OUT_HDMI",                      OUTPUT_HDMI },
112 
113         { "AUDIO_DEVICE_IN_BUILTIN_MIC",           INPUT_BUILTIN_MIC },
114         { "AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET", INPUT_BLUETOOTH_SCO },
115         { "AUDIO_DEVICE_IN_BLUETOOTH_BLE",         INPUT_BLUETOOTH_BLE },
116         { "AUDIO_DEVICE_IN_BLE_HEADSET",           INPUT_BLUETOOTH_BLE },
117         { "AUDIO_DEVICE_IN_WIRED_HEADSET",         INPUT_WIRED_HEADSET_MIC },
118         { "AUDIO_DEVICE_IN_USB_DEVICE",            INPUT_USB_HEADSET_MIC },
119         { "AUDIO_DEVICE_IN_BACK_MIC",              INPUT_BUILTIN_BACK_MIC },
120     };
121 
122     auto it = deviceTable.find(device_string);
123     if (it == deviceTable.end()) {
124         device = 0;
125         return false;
126     }
127 
128     device = it->second;
129     return true;
130 }
131 
deviceFromStringPairs(const std::string & device_strings)132 int32_t AudioPowerUsage::deviceFromStringPairs(const std::string& device_strings) {
133     int32_t deviceMask = 0;
134     const auto devaddrvec = stringutils::getDeviceAddressPairs(device_strings);
135     for (const auto &[device, addr] : devaddrvec) {
136         int32_t combo_device = 0;
137         deviceFromString(device, combo_device);
138         deviceMask |= combo_device;
139     }
140     return deviceMask;
141 }
142 
sendItem(const std::shared_ptr<const mediametrics::Item> & item) const143 void AudioPowerUsage::sendItem(const std::shared_ptr<const mediametrics::Item>& item) const
144 {
145     int32_t type;
146     if (!item->getInt32(AUDIO_POWER_USAGE_PROP_TYPE, &type)) return;
147 
148     int32_t audio_device;
149     if (!item->getInt32(AUDIO_POWER_USAGE_PROP_DEVICE, &audio_device)) return;
150 
151     int64_t duration_ns;
152     if (!item->getInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, &duration_ns)) return;
153 
154     double volume;
155     if (!item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &volume)) return;
156 
157     int64_t min_volume_duration_ns;
158     if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, &min_volume_duration_ns)) {
159         return;
160     }
161 
162     double min_volume;
163     if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &min_volume)) return;
164 
165     int64_t max_volume_duration_ns;
166     if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, &max_volume_duration_ns)) {
167         return;
168     }
169 
170     double max_volume;
171     if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &max_volume)) return;
172 
173     const int32_t duration_secs = (int32_t)(duration_ns / NANOS_PER_SECOND);
174     const int32_t min_volume_duration_secs = (int32_t)(min_volume_duration_ns / NANOS_PER_SECOND);
175     const int32_t max_volume_duration_secs = (int32_t)(max_volume_duration_ns / NANOS_PER_SECOND);
176     const int result = stats::media_metrics::stats_write(stats::media_metrics::AUDIO_POWER_USAGE_DATA_REPORTED,
177                                          audio_device,
178                                          duration_secs,
179                                          (float)volume,
180                                          type,
181                                          min_volume_duration_secs,
182                                          (float)min_volume,
183                                          max_volume_duration_secs,
184                                          (float)max_volume);
185 
186     std::stringstream log;
187     log << "result:" << result << " {"
188             << " mediametrics_audio_power_usage_data_reported:"
189             << stats::media_metrics::AUDIO_POWER_USAGE_DATA_REPORTED
190             << " audio_device:" << audio_device
191             << " duration_secs:" << duration_secs
192             << " average_volume:" << (float)volume
193             << " type:" << type
194             << " min_volume_duration_secs:" << min_volume_duration_secs
195             << " min_volume:" << (float)min_volume
196             << " max_volume_duration_secs:" << max_volume_duration_secs
197             << " max_volume:" << (float)max_volume
198             << " }";
199     mStatsdLog->log(stats::media_metrics::AUDIO_POWER_USAGE_DATA_REPORTED, log.str());
200 }
201 
updateMinMaxVolumeAndDuration(const int64_t cur_max_volume_duration_ns,const double cur_max_volume,const int64_t cur_min_volume_duration_ns,const double cur_min_volume,int64_t & f_max_volume_duration_ns,double & f_max_volume,int64_t & f_min_volume_duration_ns,double & f_min_volume)202 void AudioPowerUsage::updateMinMaxVolumeAndDuration(
203             const int64_t cur_max_volume_duration_ns, const double cur_max_volume,
204             const int64_t cur_min_volume_duration_ns, const double cur_min_volume,
205             int64_t& f_max_volume_duration_ns, double& f_max_volume,
206             int64_t& f_min_volume_duration_ns, double& f_min_volume)
207 {
208     if (f_min_volume > cur_min_volume) {
209         f_min_volume = cur_min_volume;
210         f_min_volume_duration_ns = cur_min_volume_duration_ns;
211     } else if (f_min_volume == cur_min_volume) {
212         f_min_volume_duration_ns += cur_min_volume_duration_ns;
213     }
214     if (f_max_volume < cur_max_volume) {
215         f_max_volume = cur_max_volume;
216         f_max_volume_duration_ns = cur_max_volume_duration_ns;
217     } else if (f_max_volume == cur_max_volume) {
218         f_max_volume_duration_ns += cur_max_volume_duration_ns;
219     }
220 }
221 
saveAsItem_l(int32_t device,int64_t duration_ns,int32_t type,double average_vol,int64_t max_volume_duration_ns,double max_volume,int64_t min_volume_duration_ns,double min_volume)222 bool AudioPowerUsage::saveAsItem_l(
223         int32_t device, int64_t duration_ns, int32_t type, double average_vol,
224         int64_t max_volume_duration_ns, double max_volume,
225         int64_t min_volume_duration_ns, double min_volume)
226 {
227     ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
228                                    (long long)duration_ns, average_vol);
229     if (duration_ns == 0) {
230         return true; // skip duration 0 usage
231     }
232     if (device == 0) {
233         return true; //ignore unknown device
234     }
235 
236     for (const auto& item : mItems) {
237         int32_t item_type = 0, item_device = 0;
238         double item_volume = 0.;
239         int64_t item_duration_ns = 0;
240         item->getInt32(AUDIO_POWER_USAGE_PROP_DEVICE, &item_device);
241         item->getInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, &item_duration_ns);
242         item->getInt32(AUDIO_POWER_USAGE_PROP_TYPE, &item_type);
243         item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &item_volume);
244 
245         // aggregate by device and type
246         if (item_device == device && item_type == type) {
247             int64_t final_duration_ns = item_duration_ns + duration_ns;
248             double final_volume = (device & INPUT_DEVICE_BIT) ? 1.0:
249                             ((item_volume * (double)item_duration_ns +
250                             average_vol * (double)duration_ns) / (double)final_duration_ns);
251 
252             item->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, final_duration_ns);
253             item->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, final_volume);
254             item->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
255 
256             // Update the max/min volume and duration
257             int64_t final_min_volume_duration_ns;
258             int64_t final_max_volume_duration_ns;
259             double final_min_volume;
260             double final_max_volume;
261 
262             item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
263                            &final_min_volume_duration_ns);
264             item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &final_min_volume);
265             item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
266                            &final_max_volume_duration_ns);
267             item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &final_max_volume);
268             updateMinMaxVolumeAndDuration(max_volume_duration_ns, max_volume,
269                                           min_volume_duration_ns, min_volume,
270                                           final_max_volume_duration_ns, final_max_volume,
271                                           final_min_volume_duration_ns, final_min_volume);
272             item->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
273                            final_min_volume_duration_ns);
274             item->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, final_min_volume);
275             item->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
276                            final_max_volume_duration_ns);
277             item->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, final_max_volume);
278 
279             ALOGV("%s: update (%#x, %d, %lld, %f) --> (%lld, %f) min(%lld, %f) max(%lld, %f)",
280                   __func__,
281                   device, type,
282                   (long long)item_duration_ns, item_volume,
283                   (long long)final_duration_ns, final_volume,
284                   (long long)final_min_volume_duration_ns, final_min_volume,
285                   (long long)final_max_volume_duration_ns, final_max_volume);
286 
287             return true;
288         }
289     }
290 
291     auto sitem = std::make_shared<mediametrics::Item>(AUDIO_POWER_USAGE_KEY_AUDIO_USAGE);
292     sitem->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
293     sitem->setInt32(AUDIO_POWER_USAGE_PROP_DEVICE, device);
294     sitem->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, duration_ns);
295     sitem->setInt32(AUDIO_POWER_USAGE_PROP_TYPE, type);
296     sitem->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, average_vol);
297     sitem->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, min_volume_duration_ns);
298     sitem->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, min_volume);
299     sitem->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, max_volume_duration_ns);
300     sitem->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, max_volume);
301     mItems.emplace_back(sitem);
302     return true;
303 }
304 
saveAsItems_l(int32_t device,int64_t duration_ns,int32_t type,double average_vol,int64_t max_volume_duration,double max_volume,int64_t min_volume_duration,double min_volume)305 bool AudioPowerUsage::saveAsItems_l(
306         int32_t device, int64_t duration_ns, int32_t type, double average_vol,
307         int64_t max_volume_duration, double max_volume,
308         int64_t min_volume_duration, double min_volume)
309 {
310     ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
311                                    (long long)duration_ns, average_vol );
312     if (duration_ns == 0) {
313         return true; // skip duration 0 usage
314     }
315     if (device == 0) {
316         return true; //ignore unknown device
317     }
318 
319     bool ret = false;
320     const int32_t input_bit = device & INPUT_DEVICE_BIT;
321     int32_t device_bits = device ^ input_bit;
322 
323     while (device_bits != 0) {
324         int32_t tmp_device = device_bits & -device_bits; // get lowest bit
325         device_bits ^= tmp_device;  // clear lowest bit
326         tmp_device |= input_bit;    // restore input bit
327         ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol,
328                            max_volume_duration, max_volume,
329                            min_volume_duration, min_volume);
330 
331         ALOGV("%s: device %#x recorded, remaining device_bits = %#x", __func__,
332             tmp_device, device_bits);
333     }
334     return ret;
335 }
336 
checkTrackRecord(const std::shared_ptr<const mediametrics::Item> & item,bool isTrack)337 void AudioPowerUsage::checkTrackRecord(
338         const std::shared_ptr<const mediametrics::Item>& item, bool isTrack)
339 {
340     const std::string key = item->getKey();
341 
342     int64_t deviceTimeNs = 0;
343     if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs)) {
344         return;
345     }
346     double deviceVolume = 1.;
347     int64_t maxVolumeDurationNs = 0;
348     double maxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
349     int64_t minVolumeDurationNs = 0;
350     double minVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
351     if (isTrack) {
352         if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume)) {
353             return;
354         }
355         if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, &maxVolumeDurationNs)) {
356             return;
357         }
358         if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, &maxVolume)) {
359             return;
360         }
361         if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, &minVolumeDurationNs)) {
362             return;
363         }
364         if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, &minVolume)) {
365             return;
366         }
367     }
368 
369     int32_t type = 0;
370     std::string type_string;
371     if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
372                key, AMEDIAMETRICS_PROP_STREAMTYPE, &type_string) == OK) ||
373         (!isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
374                key, AMEDIAMETRICS_PROP_SOURCE, &type_string) == OK)) {
375         typeFromString(type_string, type);
376 
377         if (isTrack && type == UNKNOWN_TYPE &&
378                    mAudioAnalytics->mAnalyticsState->timeMachine().get(
379                    key, AMEDIAMETRICS_PROP_USAGE, &type_string) == OK) {
380             typeFromString(type_string, type);
381         }
382         if (isTrack && type == UNKNOWN_TYPE &&
383                    mAudioAnalytics->mAnalyticsState->timeMachine().get(
384                    key, AMEDIAMETRICS_PROP_CONTENTTYPE, &type_string) == OK) {
385             typeFromString(type_string, type);
386         }
387         ALOGV("type = %s => %d", type_string.c_str(), type);
388     }
389 
390     int32_t device = 0;
391     std::string device_strings;
392     if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
393          key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &device_strings) == OK) ||
394         (!isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
395          key, AMEDIAMETRICS_PROP_INPUTDEVICES, &device_strings) == OK)) {
396 
397         device = deviceFromStringPairs(device_strings);
398         ALOGV("device = %s => %d", device_strings.c_str(), device);
399     }
400     std::lock_guard l(mLock);
401     saveAsItems_l(device, deviceTimeNs, type, deviceVolume,
402                   maxVolumeDurationNs, maxVolume, minVolumeDurationNs, minVolume);
403 }
404 
checkMode(const std::shared_ptr<const mediametrics::Item> & item)405 void AudioPowerUsage::checkMode(const std::shared_ptr<const mediametrics::Item>& item)
406 {
407     std::string mode;
408     if (!item->getString(AMEDIAMETRICS_PROP_AUDIOMODE, &mode)) return;
409 
410     std::lock_guard l(mLock);
411     if (mode == mMode) return;  // no change in mode.
412 
413     if (mMode == "AUDIO_MODE_IN_CALL") { // leaving call mode
414         const int64_t endCallNs = item->getTimestamp();
415         const int64_t durationNs = endCallNs - mDeviceTimeNs;
416         const int64_t volumeDurationNs = endCallNs - mVolumeTimeNs;
417         if (durationNs > 0) {
418             mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
419                     mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
420             updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
421                           volumeDurationNs, mVoiceVolume,
422                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
423                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
424             saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
425                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
426                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
427         }
428     } else if (mode == "AUDIO_MODE_IN_CALL") { // entering call mode
429         mStartCallNs = item->getTimestamp(); // advisory only
430 
431         mDeviceVolume = 0;
432         mVolumeTimeNs = mStartCallNs;
433         mDeviceTimeNs = mStartCallNs;
434     }
435     ALOGV("%s: new mode:%s  old mode:%s", __func__, mode.c_str(), mMode.c_str());
436     mMode = mode;
437 }
438 
checkVoiceVolume(const std::shared_ptr<const mediametrics::Item> & item)439 void AudioPowerUsage::checkVoiceVolume(const std::shared_ptr<const mediametrics::Item>& item)
440 {
441     double voiceVolume = 0.;
442     if (!item->getDouble(AMEDIAMETRICS_PROP_VOICEVOLUME, &voiceVolume)) return;
443 
444     std::lock_guard l(mLock);
445     if (voiceVolume == mVoiceVolume) return;  // no change in volume
446 
447     // we only track average device volume when we are in-call
448     if (mMode == "AUDIO_MODE_IN_CALL") {
449         const int64_t timeNs = item->getTimestamp();
450         const int64_t durationNs = timeNs - mDeviceTimeNs;
451         const int64_t volumeDurationNs = timeNs - mVolumeTimeNs;
452         if (durationNs > 0) {
453             mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
454                     mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
455             mVolumeTimeNs = timeNs;
456             updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
457                           volumeDurationNs, mVoiceVolume,
458                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
459                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
460         }
461     }
462     ALOGV("%s: new voice volume:%lf  old voice volume:%lf", __func__, voiceVolume, mVoiceVolume);
463     mVoiceVolume = voiceVolume;
464 }
465 
checkCreatePatch(const std::shared_ptr<const mediametrics::Item> & item)466 void AudioPowerUsage::checkCreatePatch(const std::shared_ptr<const mediametrics::Item>& item)
467 {
468     std::string outputDevices;
469     if (!item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices)) return;
470 
471     const std::string& key = item->getKey();
472     std::string flags;
473     if (mAudioAnalytics->mAnalyticsState->timeMachine().get(
474          key, AMEDIAMETRICS_PROP_FLAGS, &flags) != OK) return;
475 
476     if (flags.find("AUDIO_OUTPUT_FLAG_PRIMARY") == std::string::npos) return;
477 
478     const int32_t device = deviceFromStringPairs(outputDevices);
479 
480     std::lock_guard l(mLock);
481     if (mPrimaryDevice == device) return;
482 
483     if (mMode == "AUDIO_MODE_IN_CALL") {
484         // Save statistics
485         const int64_t endDeviceNs = item->getTimestamp();
486         const int64_t durationNs = endDeviceNs - mDeviceTimeNs;
487         const int64_t volumeDurationNs = endDeviceNs - mVolumeTimeNs;
488         if (durationNs > 0) {
489             mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
490                     mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
491             updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
492                           volumeDurationNs, mVoiceVolume,
493                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
494                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
495             saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
496                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
497                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
498         }
499         // reset statistics
500         mDeviceVolume = 0;
501         mDeviceTimeNs = endDeviceNs;
502         mVolumeTimeNs = endDeviceNs;
503         mMaxVoiceVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
504         mMinVoiceVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
505         mMaxVoiceVolumeDurationNs = 0;
506         mMinVoiceVolumeDurationNs = 0;
507     }
508     ALOGV("%s: new primary device:%#x  old primary device:%#x", __func__, device, mPrimaryDevice);
509     mPrimaryDevice = device;
510 }
511 
AudioPowerUsage(AudioAnalytics * audioAnalytics,const std::shared_ptr<StatsdLog> & statsdLog)512 AudioPowerUsage::AudioPowerUsage(
513         AudioAnalytics *audioAnalytics, const std::shared_ptr<StatsdLog>& statsdLog)
514     : mAudioAnalytics(audioAnalytics)
515     , mStatsdLog(statsdLog)
516     , mDisabled(property_get_bool(PROP_AUDIO_METRICS_DISABLED, AUDIO_METRICS_DISABLED_DEFAULT))
517     , mIntervalHours(property_get_int32(PROP_AUDIO_METRICS_INTERVAL_HR, INTERVAL_HR_DEFAULT))
518 {
519     ALOGD("%s", __func__);
520     ALOGI_IF(mDisabled, "AudioPowerUsage is disabled.");
521     collect(); // send items
522 }
523 
~AudioPowerUsage()524 AudioPowerUsage::~AudioPowerUsage()
525 {
526     ALOGD("%s", __func__);
527 }
528 
clear()529 void AudioPowerUsage::clear()
530 {
531     std::lock_guard _l(mLock);
532     mItems.clear();
533 }
534 
collect()535 void AudioPowerUsage::collect()
536 {
537     std::lock_guard _l(mLock);
538     for (const auto &item : mItems) {
539         sendItem(item);
540     }
541     mItems.clear();
542     mAudioAnalytics->mTimedAction.postIn(
543         mIntervalHours <= 0 ? std::chrono::seconds(5) : std::chrono::hours(mIntervalHours),
544         [this](){ collect(); });
545 }
546 
dump(int limit) const547 std::pair<std::string, int32_t> AudioPowerUsage::dump(int limit) const {
548     if (limit <= 2) {
549         return {{}, 0};
550     }
551     std::lock_guard _l(mLock);
552     if (mDisabled) {
553         return {"AudioPowerUsage disabled\n", 1};
554     }
555     if (mItems.empty()) {
556         return {"AudioPowerUsage empty\n", 1};
557     }
558 
559     int slot = 1;
560     std::stringstream ss;
561     ss << "AudioPowerUsage interval " << mIntervalHours << " hours:\n";
562     for (const auto &item : mItems) {
563         if (slot >= limit - 1) {
564             ss << "-- AudioPowerUsage may be truncated!\n";
565             ++slot;
566             break;
567         }
568         ss << " " << slot << " " << item->toString() << "\n";
569         slot++;
570     }
571     return { ss.str(), slot };
572 }
573 
574 } // namespace android::mediametrics
575