From 8945c2a640c3227e4e5efe5dbffbaacd579eeec5 Mon Sep 17 00:00:00 2001 From: xshu Date: Tue, 21 May 2019 17:34:56 -0700 Subject: Detect+trigger bugreport for abnormal connections This is an effort investigate why certain connections take really long to finish. Users running user-debug builds will be shown an notification, which they may tap on to file a bugreport. Added DeviceConfig flags (that is disabled by default) which may be configured on the server side to enable this feature for a select group of users. Also added a flag to fine tune the threshold at which bugreports get triggered. Bug: 132648941 Test: Unit tests Test: Tested turning on the bugreport trigger with "adb shell device_config put wifi abnormal_connection_bugreport_enabled true" Test: Ran "adb shell device_config put wifi abnormal_connection_duration_ms 30" and verified that bugreport is taken Change-Id: Ic4ea7c1850677781838a645b989f81db858546f4 --- .../com/android/server/wifi/ClientModeImpl.java | 3 + .../android/server/wifi/DeviceConfigFacade.java | 57 +++++++++++++++ .../java/com/android/server/wifi/WifiInjector.java | 7 +- .../server/wifi/WifiLastResortWatchdog.java | 83 +++++++++++++++++++++- 4 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 service/java/com/android/server/wifi/DeviceConfigFacade.java (limited to 'service') diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index a18760c17..292e902bc 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -959,6 +959,8 @@ public class ClientModeImpl extends StateMachine { mWifiMetrics.getHandler()); mWifiMonitor.registerHandler(mInterfaceName, CMD_TARGET_BSSID, mWifiMetrics.getHandler()); + mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT, + mWifiInjector.getWifiLastResortWatchdog().getHandler()); } private void setMulticastFilter(boolean enabled) { @@ -4292,6 +4294,7 @@ public class ClientModeImpl extends StateMachine { } if (mWifiNative.connectToNetwork(mInterfaceName, config)) { + mWifiInjector.getWifiLastResortWatchdog().noteStartConnectTime(); mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config); mLastConnectAttemptTimestamp = mClock.getWallClockMillis(); mTargetWifiConfiguration = config; diff --git a/service/java/com/android/server/wifi/DeviceConfigFacade.java b/service/java/com/android/server/wifi/DeviceConfigFacade.java new file mode 100644 index 000000000..c64cd5259 --- /dev/null +++ b/service/java/com/android/server/wifi/DeviceConfigFacade.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.provider.DeviceConfig; + +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +/** + * This class allows getting all configurable flags from DeviceConfig. + */ +public class DeviceConfigFacade { + private static final int DEFAULT_ABNORMAL_CONNECTION_DURATION_MS = + (int) TimeUnit.SECONDS.toMillis(30); + private static final String NAMESPACE = "wifi"; + + /** + * Gets the feature flag for reporting abnormally long connections. + */ + public boolean isAbnormalConnectionBugreportEnabled() { + return DeviceConfig.getBoolean(NAMESPACE, "abnormal_connection_bugreport_enabled", false); + } + + /** + * Gets the threshold for classifying abnormally long connections. + */ + public int getAbnormalConnectionDurationMs() { + return DeviceConfig.getInt(NAMESPACE, "abnormal_connection_duration_ms", + DEFAULT_ABNORMAL_CONNECTION_DURATION_MS); + } + + /** + * Adds a listener that will be run on the specified executor. + * @param executor + * @param onPropertiesChangedListener + */ + public void addOnPropertiesChangedListener(Executor executor, + DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) { + DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor, + onPropertiesChangedListener); + } +} diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index f33c7cf93..ade295c63 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -82,6 +82,7 @@ public class WifiInjector { private final Context mContext; private final FrameworkFacade mFrameworkFacade = new FrameworkFacade(); + private final DeviceConfigFacade mDeviceConfigFacade; private final HandlerThread mWifiServiceHandlerThread; private final HandlerThread mWifiCoreHandlerThread; private final HandlerThread mWifiP2pServiceHandlerThread; @@ -168,6 +169,7 @@ public class WifiInjector { sWifiInjector = this; mContext = context; + mDeviceConfigFacade = new DeviceConfigFacade(); mWifiScoreCard = new WifiScoreCard(mClock, Secure.getString(mContext.getContentResolver(), Secure.ANDROID_ID)); mSettingsStore = new WifiSettingsStore(mContext); @@ -605,8 +607,9 @@ public class WifiInjector { mWifiCoreHandlerThread.getLooper(), mFrameworkFacade, mClock, mWifiMetrics, mWifiConfigManager, mWifiConfigStore, clientModeImpl, new ConnectToNetworkNotificationBuilder(mContext, mFrameworkFacade)); - mWifiLastResortWatchdog = new WifiLastResortWatchdog(this, mClock, - mWifiMetrics, clientModeImpl, clientModeImpl.getHandler().getLooper()); + mWifiLastResortWatchdog = new WifiLastResortWatchdog(this, mContext, mClock, + mWifiMetrics, clientModeImpl, clientModeImpl.getHandler().getLooper(), + mDeviceConfigFacade); return new WifiConnectivityManager(mContext, getScoringParams(), clientModeImpl, this, mWifiConfigManager, clientModeImpl.getWifiInfo(), diff --git a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java index 6889b5016..e8a06881b 100644 --- a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java +++ b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java @@ -16,10 +16,12 @@ package com.android.server.wifi; +import android.content.Context; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.os.Handler; import android.os.Looper; +import android.os.Message; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; @@ -75,6 +77,10 @@ public class WifiLastResortWatchdog { @VisibleForTesting public static final long LAST_TRIGGER_TIMEOUT_MILLIS = 2 * 3600 * 1000; // 2 hours + private int mAbnormalConnectionDurationMs; + private boolean mAbnormalConnectionBugreportEnabled; + + /** * Cached WifiConfigurations of available networks seen within MAX_BSSID_AGE scan results * Key:BSSID, Value:Counters of failure types @@ -102,22 +108,95 @@ public class WifiLastResortWatchdog { private Looper mClientModeImplLooper; private double mBugReportProbability = PROB_TAKE_BUGREPORT_DEFAULT; private Clock mClock; + private Context mContext; + private DeviceConfigFacade mDeviceConfigFacade; // If any connection failure happened after watchdog triggering restart then assume watchdog // did not fix the problem private boolean mWatchdogFixedWifi = true; + private long mLastStartConnectTime = 0; + private Handler mHandler; /** * Local log used for debugging any WifiLastResortWatchdog issues. */ private final LocalLog mLocalLog = new LocalLog(100); - WifiLastResortWatchdog(WifiInjector wifiInjector, Clock clock, WifiMetrics wifiMetrics, - ClientModeImpl clientModeImpl, Looper clientModeImplLooper) { + WifiLastResortWatchdog(WifiInjector wifiInjector, Context context, Clock clock, + WifiMetrics wifiMetrics, ClientModeImpl clientModeImpl, Looper clientModeImplLooper, + DeviceConfigFacade deviceConfigFacade) { mWifiInjector = wifiInjector; mClock = clock; mWifiMetrics = wifiMetrics; mClientModeImpl = clientModeImpl; mClientModeImplLooper = clientModeImplLooper; + mContext = context; + mDeviceConfigFacade = deviceConfigFacade; + updateDeviceConfigFlags(); + mHandler = new Handler(clientModeImplLooper) { + public void handleMessage(Message msg) { + processMessage(msg); + } + }; + + mDeviceConfigFacade.addOnPropertiesChangedListener( + command -> mHandler.post(command), + properties -> { + updateDeviceConfigFlags(); + }); + } + + private void updateDeviceConfigFlags() { + mAbnormalConnectionBugreportEnabled = + mDeviceConfigFacade.isAbnormalConnectionBugreportEnabled(); + mAbnormalConnectionDurationMs = + mDeviceConfigFacade.getAbnormalConnectionDurationMs(); + logv("updateDeviceConfigFlags: mAbnormalConnectionDurationMs = " + + mAbnormalConnectionDurationMs + + ", mAbnormalConnectionBugreportEnabled = " + + mAbnormalConnectionBugreportEnabled); + } + + /** + * Returns handler for L2 events from supplicant. + * @return Handler + */ + public Handler getHandler() { + return mHandler; + } + + /** + * Refreshes when the last CMD_START_CONNECT is triggered. + */ + public void noteStartConnectTime() { + mHandler.post(() -> { + mLastStartConnectTime = mClock.getElapsedSinceBootMillis(); + }); + } + + private void processMessage(Message msg) { + switch (msg.what) { + case WifiMonitor.NETWORK_CONNECTION_EVENT: + // Trigger bugreport for successful connections that take abnormally long + if (mAbnormalConnectionBugreportEnabled && mLastStartConnectTime > 0) { + long durationMs = mClock.getElapsedSinceBootMillis() - mLastStartConnectTime; + if (durationMs > mAbnormalConnectionDurationMs) { + final String bugTitle = "Wi-Fi Bugreport: Abnormal connection time"; + final String bugDetail = "Expected connection to take less than " + + mAbnormalConnectionDurationMs + " milliseconds. " + + "Actually took " + durationMs + " milliseconds."; + logv("Triggering bug report for abnormal connection time."); + mWifiInjector.getClientModeImplHandler().post(() -> { + mClientModeImpl.takeBugReport(bugTitle, bugDetail); + }); + } + } + // Should reset last connection time after each connection regardless if bugreport + // is enabled or not. + mLastStartConnectTime = 0; + break; + default: + return; + } } /** -- cgit v1.2.3