CSD: fix issue with timestamp after reboot
The CSD record timestamps use CLOCK_MONOTONIC which is counting from
boot time. In order to have a consistent timestamp between reboots we
need to convert between global system time to boot time.
Test: audio and media.audio_flinger dumpsys after reboot
Bug: 266915998
Change-Id: I49111f002d95c27c039e1bd719c39ab5ae5e29d3
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 748c4ce5..4e8e704 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -108,6 +108,8 @@
private static final String PERSIST_CSD_RECORD_SEPARATOR_CHAR = "|";
private static final String PERSIST_CSD_RECORD_SEPARATOR = "\\|";
+ private static final long GLOBAL_TIME_OFFSET_UNINITIALIZED = -1;
+
private final EventLogger mLogger = new EventLogger(AudioService.LOG_NB_EVENTS_SOUND_DOSE,
"CSD updates");
@@ -168,6 +170,11 @@
@GuardedBy("mCsdStateLock")
private final List<SoundDoseRecord> mDoseRecords = new ArrayList<>();
+ // time in seconds reported by System.currentTimeInMillis used as an offset to convert between
+ // boot time and global time
+ @GuardedBy("mCsdStateLock")
+ private long mGlobalTimeOffsetInSecs = GLOBAL_TIME_OFFSET_UNINITIALIZED;
+
private final Context mContext;
private final ISoundDoseCallback.Stub mSoundDoseCallback = new ISoundDoseCallback.Stub() {
@@ -590,16 +597,24 @@
Log.v(TAG, "Initializing sound dose");
synchronized (mCsdStateLock) {
+ if (mGlobalTimeOffsetInSecs == GLOBAL_TIME_OFFSET_UNINITIALIZED) {
+ mGlobalTimeOffsetInSecs = System.currentTimeMillis() / 1000L;
+ }
+
+ float prevCsd = mCurrentCsd;
// Restore persisted values
mCurrentCsd = parseGlobalSettingFloat(
Settings.Global.AUDIO_SAFE_CSD_CURRENT_VALUE, /* defaultValue= */0.f);
- mNextCsdWarning = parseGlobalSettingFloat(
- Settings.Global.AUDIO_SAFE_CSD_NEXT_WARNING, /* defaultValue= */1.f);
- final List<SoundDoseRecord> records = persistedStringToRecordList(
- mSettings.getGlobalString(mAudioService.getContentResolver(),
- Settings.Global.AUDIO_SAFE_CSD_DOSE_RECORDS));
- if (records != null) {
- mDoseRecords.addAll(records);
+ if (mCurrentCsd != prevCsd) {
+ mNextCsdWarning = parseGlobalSettingFloat(
+ Settings.Global.AUDIO_SAFE_CSD_NEXT_WARNING, /* defaultValue= */1.f);
+ final List<SoundDoseRecord> records = persistedStringToRecordList(
+ mSettings.getGlobalString(mAudioService.getContentResolver(),
+ Settings.Global.AUDIO_SAFE_CSD_DOSE_RECORDS),
+ mGlobalTimeOffsetInSecs);
+ if (records != null) {
+ mDoseRecords.addAll(records);
+ }
}
}
@@ -774,8 +789,13 @@
mLogger.enqueue(SoundDoseEvent.getDoseUpdateEvent(currentCsd, totalDuration));
}
+ @SuppressWarnings("GuardedBy") // avoid limitation with intra-procedural analysis of lambdas
private void onPersistSoundDoseRecords() {
synchronized (mCsdStateLock) {
+ if (mGlobalTimeOffsetInSecs == GLOBAL_TIME_OFFSET_UNINITIALIZED) {
+ mGlobalTimeOffsetInSecs = System.currentTimeMillis() / 1000L;
+ }
+
mSettings.putGlobalString(mAudioService.getContentResolver(),
Settings.Global.AUDIO_SAFE_CSD_CURRENT_VALUE,
Float.toString(mCurrentCsd));
@@ -785,28 +805,41 @@
mSettings.putGlobalString(mAudioService.getContentResolver(),
Settings.Global.AUDIO_SAFE_CSD_DOSE_RECORDS,
mDoseRecords.stream().map(
- SoundDoseHelper::recordToPersistedString).collect(
+ record -> SoundDoseHelper.recordToPersistedString(record,
+ mGlobalTimeOffsetInSecs)).collect(
Collectors.joining(PERSIST_CSD_RECORD_SEPARATOR_CHAR)));
}
}
- private static String recordToPersistedString(SoundDoseRecord record) {
- return record.timestamp
+ private static String recordToPersistedString(SoundDoseRecord record,
+ long globalTimeOffsetInSecs) {
+ return convertToGlobalTime(record.timestamp, globalTimeOffsetInSecs)
+ PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.duration
+ PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.value
+ PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.averageMel;
}
- private static List<SoundDoseRecord> persistedStringToRecordList(String records) {
+ private static long convertToGlobalTime(long bootTimeInSecs, long globalTimeOffsetInSecs) {
+ return bootTimeInSecs + globalTimeOffsetInSecs;
+ }
+
+ private static long convertToBootTime(long globalTimeInSecs, long globalTimeOffsetInSecs) {
+ return globalTimeInSecs - globalTimeOffsetInSecs;
+ }
+
+ private static List<SoundDoseRecord> persistedStringToRecordList(String records,
+ long globalTimeOffsetInSecs) {
if (records == null || records.isEmpty()) {
return null;
}
return Arrays.stream(TextUtils.split(records, PERSIST_CSD_RECORD_SEPARATOR)).map(
- SoundDoseHelper::persistedStringToRecord).filter(Objects::nonNull).collect(
+ record -> SoundDoseHelper.persistedStringToRecord(record,
+ globalTimeOffsetInSecs)).filter(Objects::nonNull).collect(
Collectors.toList());
}
- private static SoundDoseRecord persistedStringToRecord(String record) {
+ private static SoundDoseRecord persistedStringToRecord(String record,
+ long globalTimeOffsetInSecs) {
if (record == null || record.isEmpty()) {
return null;
}
@@ -818,7 +851,8 @@
final SoundDoseRecord sdRecord = new SoundDoseRecord();
try {
- sdRecord.timestamp = Long.parseLong(fields[0]);
+ sdRecord.timestamp = convertToBootTime(Long.parseLong(fields[0]),
+ globalTimeOffsetInSecs);
sdRecord.duration = Integer.parseInt(fields[1]);
sdRecord.value = Float.parseFloat(fields[2]);
sdRecord.averageMel = Float.parseFloat(fields[3]);