KernelWakelockReader: provide class level lock when updates staleStats

As the wakelock version number is defined as static to provide
consistent versioning across objects, class level static lock should be
implemented to prevent racing conditions.

To trigger the racing condition, update statsd's stats pulling logic
locally to repeatably requesting wakelock stats then wakeup the phone
to trigger BatteryStats update routine. The racing condition is 100%
reproducible under the setup. The patch has been verified with the
setup, and the racing is no longer seen. See more reproduce details in
the linked bug.

Bug: 173539101
Test: manual
Change-Id: I386afa2f2ecd8678e71ece978da4a9950b21ca4d
This commit is contained in:
Michael Sun
2020-12-21 07:29:39 +00:00
parent 2cbc87a9bf
commit 5886ede607

View File

@@ -78,13 +78,16 @@ public class KernelWakelockReader {
boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
if (useSystemSuspend) {
// Get both kernel and native wakelock stats from SystemSuspend
updateVersion(staleStats);
if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
return null;
// static read/write lock protection for sKernelWakelockUpdateVersion
synchronized (KernelWakelockReader.class) {
// Get both kernel and native wakelock stats from SystemSuspend
updateVersion(staleStats);
if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
return null;
}
return removeOldStats(staleStats);
}
return removeOldStats(staleStats);
} else {
Arrays.fill(mKernelWakelockBuffer, (byte) 0);
int len = 0;
@@ -141,14 +144,17 @@ public class KernelWakelockReader {
}
}
updateVersion(staleStats);
// Get native wakelock stats from SystemSuspend
if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
// static read/write lock protection for sKernelWakelockUpdateVersion
synchronized (KernelWakelockReader.class) {
updateVersion(staleStats);
// Get native wakelock stats from SystemSuspend
if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
}
// Get kernel wakelock stats
parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats);
return removeOldStats(staleStats);
}
// Get kernel wakelock stats
parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats);
return removeOldStats(staleStats);
}
}