diff options
author | Kai Shi <kaishi@google.com> | 2022-04-19 16:48:01 -0700 |
---|---|---|
committer | Kai Shi <kaishi@google.com> | 2022-04-20 08:35:30 -0700 |
commit | f00004edfd816101f7c20be91e27b92b0ff1c3c6 (patch) | |
tree | b29112df9f3ce8facef677dee97459f5f0a8762d | |
parent | a68572f0f423a830e2557b0ff1b6cc817f90b16e (diff) | |
download | Uwb-f00004edfd816101f7c20be91e27b92b0ff1c3c6.tar.gz |
Trigger bugreport for device error
Add an option to trigger bugreport for device initialization error or
device status error.
Test: atest com.android.server.uwb
Bug: 229789022
Change-Id: I83a0184452081607297c53464b147d651282df02
8 files changed, 232 insertions, 2 deletions
diff --git a/service/java/com/android/server/uwb/DeviceConfigFacade.java b/service/java/com/android/server/uwb/DeviceConfigFacade.java index 29554ee1..cd841960 100644 --- a/service/java/com/android/server/uwb/DeviceConfigFacade.java +++ b/service/java/com/android/server/uwb/DeviceConfigFacade.java @@ -24,11 +24,14 @@ import android.provider.DeviceConfig; */ public class DeviceConfigFacade { public static final int DEFAULT_RANGING_RESULT_LOG_INTERVAL_MS = 5_000; + public static final int DEFAULT_BUG_REPORT_MIN_INTERVAL_MS = 24 * 3_600_000; private final UwbInjector mUwbInjector; // Cached values of fields updated via updateDeviceConfigFlags() private int mRangingResultLogIntervalMs; + private boolean mDeviceErrorBugreportEnabled; + private int mBugReportMinIntervalMs; public DeviceConfigFacade(Handler handler, UwbInjector uwbInjector) { mUwbInjector = uwbInjector; @@ -45,6 +48,10 @@ public class DeviceConfigFacade { private void updateDeviceConfigFlags() { mRangingResultLogIntervalMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_UWB, "ranging_result_log_interval_ms", DEFAULT_RANGING_RESULT_LOG_INTERVAL_MS); + mDeviceErrorBugreportEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_UWB, + "device_error_bugreport_enabled", false); + mBugReportMinIntervalMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_UWB, + "bug_report_min_interval_ms", DEFAULT_BUG_REPORT_MIN_INTERVAL_MS); } /** @@ -53,4 +60,18 @@ public class DeviceConfigFacade { public int getRangingResultLogIntervalMs() { return mRangingResultLogIntervalMs; } + + /** + * Gets the feature flag for reporting device error + */ + public boolean isDeviceErrorBugreportEnabled() { + return mDeviceErrorBugreportEnabled; + } + + /** + * Gets minimum wait time between two bug report captures + */ + public int getBugReportMinIntervalMs() { + return mBugReportMinIntervalMs; + } } diff --git a/service/java/com/android/server/uwb/SystemBuildProperties.java b/service/java/com/android/server/uwb/SystemBuildProperties.java new file mode 100644 index 00000000..4090978d --- /dev/null +++ b/service/java/com/android/server/uwb/SystemBuildProperties.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 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.uwb; + +import android.os.Build; + +class SystemBuildProperties { + /** @return if it is an eng build. */ + public boolean isEngBuild() { + return Build.TYPE.equals("eng"); + } + + /** @return if it is an userdebug build. */ + public boolean isUserdebugBuild() { + return Build.TYPE.equals("userdebug"); + } + + /** @return if it is a normal user build. */ + public boolean isUserBuild() { + return Build.TYPE.equals("user"); + } +} diff --git a/service/java/com/android/server/uwb/UwbDiagnostics.java b/service/java/com/android/server/uwb/UwbDiagnostics.java new file mode 100644 index 00000000..173f9ebc --- /dev/null +++ b/service/java/com/android/server/uwb/UwbDiagnostics.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 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.uwb; + +import android.content.Context; +import android.os.BugreportManager; +import android.os.BugreportParams; +import android.util.Log; + +/** + * A class to trigger bugreport and other logs for UWB related failures + */ +public class UwbDiagnostics { + private static final String TAG = "UwbDiagnostics"; + private final Context mContext; + private final SystemBuildProperties mSystemBuildProperties; + private final UwbInjector mUwbInjector; + private long mLastBugReportTimeMs; + public UwbDiagnostics( + Context context, UwbInjector uwbInjector, SystemBuildProperties systemBuildProperties) { + mContext = context; + mSystemBuildProperties = systemBuildProperties; + mUwbInjector = uwbInjector; + } + + /** + * Take a bug report if it is not in user build and there is no recent bug report + */ + public void takeBugReport(String bugTitle) { + if (mSystemBuildProperties.isUserBuild()) { + return; + } + long currentTimeMs = mUwbInjector.getElapsedSinceBootMillis(); + if ((currentTimeMs - mLastBugReportTimeMs) + < mUwbInjector.getDeviceConfigFacade().getBugReportMinIntervalMs() + && mLastBugReportTimeMs > 0) { + return; + } + mLastBugReportTimeMs = currentTimeMs; + BugreportManager bugreportManager = mContext.getSystemService(BugreportManager.class); + BugreportParams params = new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL); + try { + bugreportManager.requestBugreport(params, bugTitle, bugTitle); + } catch (RuntimeException e) { + Log.e(TAG, "Error taking bugreport: " + e); + } + } +} diff --git a/service/java/com/android/server/uwb/UwbInjector.java b/service/java/com/android/server/uwb/UwbInjector.java index ace37f80..70d32b9b 100644 --- a/service/java/com/android/server/uwb/UwbInjector.java +++ b/service/java/com/android/server/uwb/UwbInjector.java @@ -74,6 +74,8 @@ public class UwbInjector { private final UwbMetrics mUwbMetrics; private final DeviceConfigFacade mDeviceConfigFacade; private final UwbMultichipData mUwbMultichipData; + private final SystemBuildProperties mSystemBuildProperties; + private final UwbDiagnostics mUwbDiagnostics; public UwbInjector(@NonNull UwbContext context) { // Create UWB service thread. @@ -103,6 +105,8 @@ public class UwbInjector { mContext.getSystemService(AlarmManager.class), mLooper); mUwbService = new UwbServiceCore(mContext, mNativeUwbManager, mUwbMetrics, mUwbCountryCode, uwbSessionManager, uwbConfigurationManager, this, mLooper); + mSystemBuildProperties = new SystemBuildProperties(); + mUwbDiagnostics = new UwbDiagnostics(mContext, this, mSystemBuildProperties); } public UwbSettingsStore getUwbSettingsStore() { @@ -133,6 +137,10 @@ public class UwbInjector { return mUwbService; } + public UwbDiagnostics getUwbDiagnostics() { + return mUwbDiagnostics; + } + /** * Create a UwbShellCommand instance. */ diff --git a/service/java/com/android/server/uwb/UwbServiceCore.java b/service/java/com/android/server/uwb/UwbServiceCore.java index d97ccf80..54abc54b 100644 --- a/service/java/com/android/server/uwb/UwbServiceCore.java +++ b/service/java/com/android/server/uwb/UwbServiceCore.java @@ -179,6 +179,7 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, if ((byte) deviceState == UwbUciConstants.DEVICE_STATE_ERROR) { Log.e(TAG, "Error device status received. Disabling..."); mUwbMetrics.incrementDeviceStatusErrorCount(); + takBugReportAfterDeviceError("UWB is disabled due to device status error"); setEnabled(false); return; } @@ -521,6 +522,7 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, if (!mNativeUwbManager.doInitialize()) { Log.e(TAG, "Error enabling UWB"); mUwbMetrics.incrementDeviceInitFailureCount(); + takBugReportAfterDeviceError("Error enabling UWB"); updateState(AdapterStateCallback.STATE_DISABLED, StateChangeReason.SYSTEM_POLICY); } else { @@ -633,6 +635,12 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, } } + private void takBugReportAfterDeviceError(String bugTitle) { + if (mUwbInjector.getDeviceConfigFacade().isDeviceErrorBugreportEnabled()) { + mUwbInjector.getUwbDiagnostics().takeBugReport(bugTitle); + } + } + /** * Dump the UWB service status */ diff --git a/service/tests/src/com/android/server/uwb/DeviceConfigFacadeTest.java b/service/tests/src/com/android/server/uwb/DeviceConfigFacadeTest.java index a75da48f..59025a51 100644 --- a/service/tests/src/com/android/server/uwb/DeviceConfigFacadeTest.java +++ b/service/tests/src/com/android/server/uwb/DeviceConfigFacadeTest.java @@ -45,8 +45,7 @@ import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; public class DeviceConfigFacadeTest { - @Mock - UwbInjector mUwbInjector; + @Mock UwbInjector mUwbInjector; final ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener> mOnPropertiesChangedListenerCaptor = @@ -114,6 +113,9 @@ public class DeviceConfigFacadeTest { public void testDefaultValue() throws Exception { assertEquals(DeviceConfigFacade.DEFAULT_RANGING_RESULT_LOG_INTERVAL_MS, mDeviceConfigFacade.getRangingResultLogIntervalMs()); + assertEquals(false, mDeviceConfigFacade.isDeviceErrorBugreportEnabled()); + assertEquals(DeviceConfigFacade.DEFAULT_BUG_REPORT_MIN_INTERVAL_MS, + mDeviceConfigFacade.getBugReportMinIntervalMs()); } /** @@ -124,10 +126,16 @@ public class DeviceConfigFacadeTest { // Simulate updating the fields when(DeviceConfig.getInt(anyString(), eq("ranging_result_log_interval_ms"), anyInt())).thenReturn(4000); + when(DeviceConfig.getBoolean(anyString(), eq("device_error_bugreport_enabled"), + anyBoolean())).thenReturn(true); + when(DeviceConfig.getInt(anyString(), eq("bug_report_min_interval_ms"), + anyInt())).thenReturn(10 * 3600_000); mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); // Verifying fields are updated to the new values assertEquals(4000, mDeviceConfigFacade.getRangingResultLogIntervalMs()); + assertEquals(true, mDeviceConfigFacade.isDeviceErrorBugreportEnabled()); + assertEquals(10 * 3600_000, mDeviceConfigFacade.getBugReportMinIntervalMs()); } } diff --git a/service/tests/src/com/android/server/uwb/UwbDiagnosticsTest.java b/service/tests/src/com/android/server/uwb/UwbDiagnosticsTest.java new file mode 100644 index 00000000..51f785f7 --- /dev/null +++ b/service/tests/src/com/android/server/uwb/UwbDiagnosticsTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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.uwb; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.BugreportManager; +import android.platform.test.annotations.Presubmit; +import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit tests for {@link com.android.server.uwb.UwbDiagnostics}. + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class UwbDiagnosticsTest { + @Mock SystemBuildProperties mBuildProperties; + @Mock Context mContext; + @Mock UwbInjector mUwbInjector; + @Mock DeviceConfigFacade mDeviceConfigFacade; + @Mock BugreportManager mBugreportManager; + UwbDiagnostics mUwbDiagnostics; + + private static final int BUG_REPORT_MIN_INTERVAL_MS = 3600_000; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mUwbInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); + when(mDeviceConfigFacade.getBugReportMinIntervalMs()) + .thenReturn(BUG_REPORT_MIN_INTERVAL_MS); + when(mBuildProperties.isUserBuild()).thenReturn(false); + when(mContext.getSystemService(BugreportManager.class)).thenReturn(mBugreportManager); + mUwbDiagnostics = new UwbDiagnostics(mContext, mUwbInjector, mBuildProperties); + } + + @Test + public void takeBugReportDoesNothingOnUserBuild() throws Exception { + when(mBuildProperties.isUserBuild()).thenReturn(true); + mUwbDiagnostics.takeBugReport(""); + verify(mBugreportManager, never()).requestBugreport(any(), any(), any()); + } + + @Test + public void takeBugReportTwiceWithInsufficientTimeGapSkipSecondRequest() throws Exception { + // 1st attempt should succeed + when(mUwbInjector.getElapsedSinceBootMillis()).thenReturn(10L); + mUwbDiagnostics.takeBugReport(""); + verify(mBugreportManager, times(1)).requestBugreport(any(), any(), any()); + // 2nd attempt should fail + when(mUwbInjector.getWallClockMillis()).thenReturn(BUG_REPORT_MIN_INTERVAL_MS - 20L); + mUwbDiagnostics.takeBugReport(""); + verify(mBugreportManager, times(1)).requestBugreport(any(), any(), any()); + } +} diff --git a/service/tests/src/com/android/server/uwb/UwbServiceCoreTest.java b/service/tests/src/com/android/server/uwb/UwbServiceCoreTest.java index 0b5ff02a..5c22ae83 100644 --- a/service/tests/src/com/android/server/uwb/UwbServiceCoreTest.java +++ b/service/tests/src/com/android/server/uwb/UwbServiceCoreTest.java @@ -152,6 +152,7 @@ public class UwbServiceCoreTest { @Mock private UwbSessionManager mUwbSessionManager; @Mock private UwbConfigurationManager mUwbConfigurationManager; @Mock private UwbInjector mUwbInjector; + @Mock DeviceConfigFacade mDeviceConfigFacade; private TestLooper mTestLooper; private MockitoSession mMockitoSession; @@ -167,6 +168,9 @@ public class UwbServiceCoreTest { when(mContext.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mUwbInjector.isSystemApp(TEST_UID, TEST_PACKAGE_NAME)).thenReturn(true); when(mUwbInjector.isForegroundAppOrService(TEST_UID, TEST_PACKAGE_NAME)).thenReturn(true); + when(mUwbInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); + when(mDeviceConfigFacade.getBugReportMinIntervalMs()) + .thenReturn(DeviceConfigFacade.DEFAULT_BUG_REPORT_MIN_INTERVAL_MS); mUwbServiceCore = new UwbServiceCore(mContext, mNativeUwbManager, mUwbMetrics, mUwbCountryCode, mUwbSessionManager, mUwbConfigurationManager, mUwbInjector, mTestLooper.getLooper()); |