Add a version of SettingsObserver to BinderCallsStats and make it public so it could be

used to collect binder latency data from bluetooth and telephony.

Test: latency collection is unit tested, this is just an alternative settings configuration
Bug: 180584913
Change-Id: Ide51afb7eb26a96c7692bceb0a22585a74f08aa7
This commit is contained in:
Siim Sammul
2021-04-19 16:24:33 +01:00
parent 909042e9a4
commit 58f933471d
5 changed files with 168 additions and 61 deletions

View File

@@ -16,18 +16,25 @@
package com.android.internal.os;
import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.KeyValueListParser;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -157,15 +164,20 @@ public class BinderCallsStats implements BinderInternal.Observer {
return new Handler(Looper.getMainLooper());
}
public BinderLatencyObserver getLatencyObserver() {
return new BinderLatencyObserver(new BinderLatencyObserver.Injector());
/** Create a latency observer for the specified process. */
public BinderLatencyObserver getLatencyObserver(int processSource) {
return new BinderLatencyObserver(new BinderLatencyObserver.Injector(), processSource);
}
}
public BinderCallsStats(Injector injector) {
this(injector, SYSTEM_SERVER);
}
public BinderCallsStats(Injector injector, int processSource) {
this.mRandom = injector.getRandomGenerator();
this.mCallStatsObserverHandler = injector.getHandler();
this.mLatencyObserver = injector.getLatencyObserver();
this.mLatencyObserver = injector.getLatencyObserver(processSource);
}
public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) {
@@ -1074,4 +1086,120 @@ public class BinderCallsStats implements BinderInternal.Observer {
? result
: Integer.compare(a.transactionCode, b.transactionCode);
}
/**
* Settings observer for other processes (not system_server).
*
* We do not want to collect cpu data from other processes so only latency collection should be
* possible to enable.
*/
public static class SettingsObserver extends ContentObserver {
// Settings for BinderCallsStats.
public static final String SETTINGS_ENABLED_KEY = "enabled";
public static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking";
public static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data";
public static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
public static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state";
public static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid";
public static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count";
public static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status";
// Settings for BinderLatencyObserver.
public static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data";
public static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY =
"latency_observer_sampling_interval";
public static final String SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY =
"latency_observer_push_interval_minutes";
public static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY =
"latency_histogram_bucket_count";
public static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY =
"latency_histogram_first_bucket_size";
public static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY =
"latency_histogram_bucket_scale_factor";
private boolean mEnabled;
private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS);
private final Context mContext;
private final KeyValueListParser mParser = new KeyValueListParser(',');
private final BinderCallsStats mBinderCallsStats;
private final int mProcessSource;
public SettingsObserver(Context context, BinderCallsStats binderCallsStats,
int processSource, int userHandle) {
super(BackgroundThread.getHandler());
mContext = context;
context.getContentResolver().registerContentObserver(mUri, false, this,
userHandle);
mBinderCallsStats = binderCallsStats;
mProcessSource = processSource;
// Always kick once to ensure that we match current state
onChange();
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
if (mUri.equals(uri)) {
onChange();
}
}
void onChange() {
try {
mParser.setString(Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.BINDER_CALLS_STATS));
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Bad binder call stats settings", e);
}
// Cpu data collection should always be disabled for other processes.
mBinderCallsStats.setDetailedTracking(false);
mBinderCallsStats.setTrackScreenInteractive(false);
mBinderCallsStats.setTrackDirectCallerUid(false);
mBinderCallsStats.setIgnoreBatteryStatus(
mParser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY,
BinderCallsStats.DEFAULT_IGNORE_BATTERY_STATUS));
mBinderCallsStats.setCollectLatencyData(
mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY,
BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA));
// Binder latency observer settings.
configureLatencyObserver(mParser, mBinderCallsStats.getLatencyObserver());
final boolean enabled =
mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);
if (mEnabled != enabled) {
if (enabled) {
Binder.setObserver(mBinderCallsStats);
} else {
Binder.setObserver(null);
}
mEnabled = enabled;
mBinderCallsStats.reset();
mBinderCallsStats.setAddDebugEntries(enabled);
mBinderCallsStats.getLatencyObserver().reset();
}
}
/** Configures the binder latency observer related settings. */
public static void configureLatencyObserver(
KeyValueListParser mParser, BinderLatencyObserver binderLatencyObserver) {
binderLatencyObserver.setSamplingInterval(mParser.getInt(
SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY,
BinderLatencyObserver.PERIODIC_SAMPLING_INTERVAL_DEFAULT));
binderLatencyObserver.setHistogramBucketsParams(
mParser.getInt(
SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY,
BinderLatencyObserver.BUCKET_COUNT_DEFAULT),
mParser.getInt(
SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY,
BinderLatencyObserver.FIRST_BUCKET_SIZE_DEFAULT),
mParser.getFloat(
SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY,
BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT));
binderLatencyObserver.setPushInterval(mParser.getInt(
SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY,
BinderLatencyObserver.STATSD_PUSH_INTERVAL_MINUTES_DEFAULT));
}
}
}

View File

@@ -16,8 +16,6 @@
package com.android.internal.os;
import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
import android.annotation.Nullable;
import android.os.Binder;
import android.os.Handler;
@@ -68,9 +66,10 @@ public class BinderLatencyObserver {
private int mStatsdPushIntervalMinutes = STATSD_PUSH_INTERVAL_MINUTES_DEFAULT;
private final Random mRandom;
private BinderLatencyBuckets mLatencyBuckets;
private final Handler mLatencyObserverHandler;
private final int mProcessSource;
private BinderLatencyBuckets mLatencyBuckets;
private Runnable mLatencyObserverRunnable = new Runnable() {
@Override
@@ -134,7 +133,7 @@ public class BinderLatencyObserver {
// Write the dims.
long dimsToken = proto.start(ApiStats.DIMS);
proto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
proto.write(Dims.PROCESS_SOURCE, mProcessSource);
proto.write(Dims.SERVICE_CLASS_NAME, dims.getBinderClass().getName());
proto.write(Dims.SERVICE_METHOD_NAME, transactionName);
proto.end(dimsToken);
@@ -180,11 +179,12 @@ public class BinderLatencyObserver {
}
}
public BinderLatencyObserver(Injector injector) {
public BinderLatencyObserver(Injector injector, int processSource) {
mRandom = injector.getRandomGenerator();
mLatencyObserverHandler = injector.getHandler();
mLatencyBuckets = new BinderLatencyBuckets(
mBucketCount, mFirstBucketSize, mBucketScaleFactor);
mProcessSource = processSource;
noteLatencyDelayed();
}

View File

@@ -984,8 +984,9 @@ public class BinderCallsStatsTest {
return mHandler;
}
public BinderLatencyObserver getLatencyObserver() {
return new BinderLatencyObserverTest.TestBinderLatencyObserver();
@Override
public BinderLatencyObserver getLatencyObserver(int processSource) {
return new BinderLatencyObserverTest.TestBinderLatencyObserver(processSource);
}
});
setSamplingInterval(1);

View File

@@ -245,18 +245,24 @@ public class BinderLatencyObserverTest {
private ArrayList<String> mWrittenAtoms;
TestBinderLatencyObserver() {
// Make random generator not random.
super(new Injector() {
public Random getRandomGenerator() {
return new Random() {
int mCallCount = 0;
this(SYSTEM_SERVER);
}
public int nextInt() {
return mCallCount++;
TestBinderLatencyObserver(int processSource) {
// Make random generator not random.
super(
new Injector() {
public Random getRandomGenerator() {
return new Random() {
int mCallCount = 0;
public int nextInt() {
return mCallCount++;
}
};
}
};
}
});
},
processSource);
setSamplingInterval(1);
mWrittenAtoms = new ArrayList<>();
}

View File

@@ -19,6 +19,15 @@ package com.android.server;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_COLLECT_LATENCY_DATA_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_DETAILED_TRACKING_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_ENABLED_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_IGNORE_BATTERY_STATUS_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_MAX_CALL_STATS_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_SAMPLING_INTERVAL_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_DIRECT_CALLING_UID_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY;
import android.app.ActivityThread;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -43,7 +52,6 @@ import com.android.internal.os.AppIdToPackageMap;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BinderCallsStats;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.BinderLatencyObserver;
import com.android.internal.os.CachedDeviceState;
import com.android.internal.util.DumpUtils;
@@ -125,28 +133,6 @@ public class BinderCallsStatsService extends Binder {
/** Listens for flag changes. */
private static class SettingsObserver extends ContentObserver {
// Settings for BinderCallsStats.
private static final String SETTINGS_ENABLED_KEY = "enabled";
private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking";
private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data";
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_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";
// Settings for BinderLatencyObserver.
private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data";
private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY =
"latency_observer_sampling_interval";
private static final String SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY =
"latency_observer_push_interval_minutes";
private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY =
"latency_histogram_bucket_count";
private static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY =
"latency_histogram_first_bucket_size";
private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY =
"latency_histogram_bucket_scale_factor";
private boolean mEnabled;
private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS);
private final Context mContext;
@@ -206,23 +192,9 @@ public class BinderCallsStatsService extends Binder {
mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY,
BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA));
// Binder latency observer settings.
BinderLatencyObserver binderLatencyObserver = mBinderCallsStats.getLatencyObserver();
binderLatencyObserver.setSamplingInterval(mParser.getInt(
SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY,
BinderLatencyObserver.PERIODIC_SAMPLING_INTERVAL_DEFAULT));
binderLatencyObserver.setHistogramBucketsParams(
mParser.getInt(
SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY,
BinderLatencyObserver.BUCKET_COUNT_DEFAULT),
mParser.getInt(
SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY,
BinderLatencyObserver.FIRST_BUCKET_SIZE_DEFAULT),
mParser.getFloat(
SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY,
BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT));
binderLatencyObserver.setPushInterval(mParser.getInt(
SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY,
BinderLatencyObserver.STATSD_PUSH_INTERVAL_MINUTES_DEFAULT));
BinderCallsStats.SettingsObserver.configureLatencyObserver(
mParser,
mBinderCallsStats.getLatencyObserver());
final boolean enabled =
mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);