From c36ef092adfdc87bb4a9e5080591d011801ea78a Mon Sep 17 00:00:00 2001 From: Max Dashouk Date: Wed, 11 Nov 2020 21:59:29 -0800 Subject: [PATCH] Adds a flag to allow collection of Looper and Binder stats even when charging. This is done for automotive form factor. Notion of battery is not as significant as it is in phones. Test: atest FrameworksCoreTests:LooperStatsTest & atest FrameworksCoreTests:BinderCallStatsTest Change-Id: I05c92bccda39fb4fbc9cf770b179edabe01e8f11 --- .../android/internal/os/BinderCallsStats.java | 36 ++++++++++++++++--- .../com/android/internal/os/LooperStats.java | 18 ++++++++-- .../internal/os/BinderCallsStatsTest.java | 14 +++++++- .../android/internal/os/LooperStatsTest.java | 17 +++++++++ .../server/BinderCallsStatsService.java | 4 +++ .../android/server/LooperStatsService.java | 13 +++++++ 6 files changed, 95 insertions(+), 7 deletions(-) diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 70b1ad49d8b84..aa42979ed53cf 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -56,6 +56,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 1000; public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true; + public static final boolean DEFAULT_IGNORE_BATTERY_STATUS = false; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 1500; private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; @@ -95,6 +96,7 @@ public class BinderCallsStats implements BinderInternal.Observer { private boolean mAddDebugEntries = false; private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID; private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE; + private boolean mIgnoreBatteryStatus = DEFAULT_IGNORE_BATTERY_STATUS; private CachedDeviceState.Readonly mDeviceState; private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch; @@ -185,8 +187,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public CallSession callStarted(Binder binder, int code, int workSourceUid) { noteNativeThreadId(); - if (!mRecordingAllTransactionsForUid - && (mDeviceState == null || mDeviceState.isCharging())) { + if (!canCollect()) { return null; } @@ -255,8 +256,7 @@ public class BinderCallsStats implements BinderInternal.Observer { synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. - if (!mRecordingAllTransactionsForUid - && (mDeviceState == null || mDeviceState.isCharging())) { + if (!canCollect()) { return; } @@ -372,6 +372,22 @@ public class BinderCallsStats implements BinderInternal.Observer { mCallStatsObserver.noteBinderThreadNativeIds(getNativeTids()); } + private boolean canCollect() { + if (mRecordingAllTransactionsForUid) { + return true; + } + if (mIgnoreBatteryStatus) { + return true; + } + if (mDeviceState == null) { + return false; + } + if (mDeviceState.isCharging()) { + return false; + } + return true; + } + /** * This method is expensive to call. */ @@ -671,6 +687,18 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** + * Whether to ignore battery status when collecting stats + */ + public void setIgnoreBatteryStatus(boolean ignored) { + synchronized (mLock) { + if (ignored != mIgnoreBatteryStatus) { + mIgnoreBatteryStatus = ignored; + reset(); + } + } + } + /** * Marks the specified work source UID for total binder call tracking: detailed information * will be recorded for all calls from this source ID. diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java index 932ff572219f6..2805dccffe506 100644 --- a/core/java/com/android/internal/os/LooperStats.java +++ b/core/java/com/android/internal/os/LooperStats.java @@ -40,6 +40,7 @@ public class LooperStats implements Looper.Observer { public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; private static final int SESSION_POOL_SIZE = 50; private static final boolean DISABLED_SCREEN_STATE_TRACKING_VALUE = false; + public static final boolean DEFAULT_IGNORE_BATTERY_STATUS = false; @GuardedBy("mLock") private final SparseArray mEntries = new SparseArray<>(512); @@ -56,6 +57,7 @@ public class LooperStats implements Looper.Observer { private long mStartElapsedTime = SystemClock.elapsedRealtime(); private boolean mAddDebugEntries = false; private boolean mTrackScreenInteractive = false; + private boolean mIgnoreBatteryStatus = DEFAULT_IGNORE_BATTERY_STATUS; public LooperStats(int samplingInterval, int entriesSizeCap) { this.mSamplingInterval = samplingInterval; @@ -139,8 +141,16 @@ public class LooperStats implements Looper.Observer { } private boolean deviceStateAllowsCollection() { - // Do not collect data if on charger or the state is not set. - return mDeviceState != null && !mDeviceState.isCharging(); + if (mIgnoreBatteryStatus) { + return true; + } + if (mDeviceState == null) { + return false; + } + if (mDeviceState.isCharging()) { + return false; + } + return true; } /** Returns an array of {@link ExportedEntry entries} with the aggregated statistics. */ @@ -225,6 +235,10 @@ public class LooperStats implements Looper.Observer { mTrackScreenInteractive = enabled; } + public void setIgnoreBatteryStatus(boolean ignore) { + mIgnoreBatteryStatus = ignore; + } + @Nullable private Entry findEntry(Message msg, boolean allowCreateNew) { final boolean isInteractive = mTrackScreenInteractive diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index 3117935fb3edc..561c549676da8 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -46,7 +46,6 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Random; @@ -427,6 +426,19 @@ public class BinderCallsStatsTest { assertEquals(0, bcs.getUidEntries().size()); } + @Test + public void testIgnoreBatteryStatusFlag() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + mDeviceState.setCharging(true); + bcs.setIgnoreBatteryStatus(true); + + Binder binder = new Binder(); + CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + assertEquals(1, bcs.getExportedCallStats().size()); + } + @Test public void testScreenOff() { TestBinderCallsStats bcs = new TestBinderCallsStats(); diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java index 7917a06cb9b7b..fdfc7ac5587cc 100644 --- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java @@ -321,6 +321,23 @@ public final class LooperStatsTest { assertThat(entries).hasSize(0); } + @Test + public void testDataCollectedIfIgnoreBatteryStatusFlagSet() { + TestableLooperStats looperStats = new TestableLooperStats(1, 100); + mDeviceState.setCharging(true); + looperStats.setIgnoreBatteryStatus(true); + + Object token1 = looperStats.messageDispatchStarting(); + looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000)); + Object token2 = looperStats.messageDispatchStarting(); + looperStats.dispatchingThrewException(token2, mHandlerFirst.obtainMessage(1000), + new IllegalArgumentException()); + + List entries = looperStats.getEntries(); + assertThat(entries).hasSize(1); + + } + @Test public void testScreenStateCollected() { TestableLooperStats looperStats = new TestableLooperStats(1, 100); diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index 66ac889ff2ca2..fdda239e7fde1 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -131,6 +131,7 @@ public class BinderCallsStatsService extends Binder { private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; + private static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status"; private boolean mEnabled; private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS); @@ -184,6 +185,9 @@ public class BinderCallsStatsService extends Binder { mBinderCallsStats.setTrackDirectCallerUid( mParser.getBoolean(SETTINGS_TRACK_DIRECT_CALLING_UID_KEY, BinderCallsStats.DEFAULT_TRACK_DIRECT_CALLING_UID)); + mBinderCallsStats.setIgnoreBatteryStatus( + mParser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY, + BinderCallsStats.DEFAULT_IGNORE_BATTERY_STATUS)); final boolean enabled = diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java index 965b64bd98536..de40b5207a6ea 100644 --- a/services/core/java/com/android/server/LooperStatsService.java +++ b/services/core/java/com/android/server/LooperStatsService.java @@ -52,6 +52,7 @@ public class LooperStatsService extends Binder { private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; + private static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status"; private static final String DEBUG_SYS_LOOPER_STATS_ENABLED = "debug.sys.looper_stats_enabled"; private static final int DEFAULT_SAMPLING_INTERVAL = 1000; @@ -64,6 +65,7 @@ public class LooperStatsService extends Binder { // Default should be false so that the first call to #setEnabled installed the looper observer. private boolean mEnabled = false; private boolean mTrackScreenInteractive = false; + private boolean mIgnoreBatteryStatus = LooperStats.DEFAULT_IGNORE_BATTERY_STATUS; private LooperStatsService(Context context, LooperStats stats) { this.mContext = context; @@ -85,6 +87,9 @@ public class LooperStatsService extends Binder { setTrackScreenInteractive( parser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY, DEFAULT_TRACK_SCREEN_INTERACTIVE)); + setIgnoreBatteryStatus( + parser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY, + LooperStats.DEFAULT_IGNORE_BATTERY_STATUS)); // Manually specified value takes precedence over Settings. setEnabled(SystemProperties.getBoolean( DEBUG_SYS_LOOPER_STATS_ENABLED, @@ -168,6 +173,14 @@ public class LooperStatsService extends Binder { } } + private void setIgnoreBatteryStatus(boolean ignore) { + if (mIgnoreBatteryStatus != ignore) { + mStats.setIgnoreBatteryStatus(ignore); + mIgnoreBatteryStatus = ignore; + mStats.reset(); + } + } + private void setSamplingInterval(int samplingInterval) { if (samplingInterval > 0) { mStats.setSamplingInterval(samplingInterval);