/* * 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.content.Intent; import android.os.Binder; 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 in user debug build and there is no recent bug report */ public void takeBugReport(String bugTitle) { if (!mSystemBuildProperties.isUserdebugBuild()) { Log.d(TAG, "Skip bugreport because it can be triggered only in userDebug build"); return; } long currentTimeMs = mUwbInjector.getElapsedSinceBootMillis(); long timeSinceLastUploadMs = currentTimeMs - mLastBugReportTimeMs; if (timeSinceLastUploadMs < mUwbInjector.getDeviceConfigFacade().getBugReportMinIntervalMs() && mLastBugReportTimeMs > 0) { Log.d(TAG, "Bugreport was filed recently, Skip " + bugTitle); return; } if (!takeBugreportThroughBetterBug(bugTitle)) { takeBugreportThroughBugreportManager(bugTitle); } } private boolean takeBugreportThroughBetterBug(String bugTitle) { Intent launchBetterBugIntent = new BetterBugIntentBuilder() .setIssueTitle(bugTitle) .setHappenedTimestamp(System.currentTimeMillis()) .build(); boolean isIntentUnSafe = mContext .getPackageManager().queryIntentActivities(launchBetterBugIntent, 0) .isEmpty(); if (isIntentUnSafe) { Log.d(TAG, "intent is unsafe and skip bugreport from betterBug: " + bugTitle); return false; } long identity = Binder.clearCallingIdentity(); try { launchBetterBugIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mContext.startActivity(launchBetterBugIntent); Log.d(TAG, "Taking the bugreport through betterBug: " + bugTitle); mLastBugReportTimeMs = mUwbInjector.getElapsedSinceBootMillis(); return true; } catch (RuntimeException e) { Log.e(TAG, "Error taking bugreport: " + e); return false; } finally { Binder.restoreCallingIdentity(identity); } } private boolean takeBugreportThroughBugreportManager(String bugTitle) { BugreportManager bugreportManager = mContext.getSystemService(BugreportManager.class); BugreportParams params = new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL); try { bugreportManager.requestBugreport(params, bugTitle, bugTitle); Log.d(TAG, "Taking the bugreport through bugreportManager: " + bugTitle); mLastBugReportTimeMs = mUwbInjector.getElapsedSinceBootMillis(); return true; } catch (RuntimeException e) { Log.e(TAG, "Error taking bugreport: " + e); return false; } } /** * @return the last time when the bug report is taken */ long getLastBugReportTimeMs() { return mLastBugReportTimeMs; } /** * Builder for communicating with the betterbug. */ private class BetterBugIntentBuilder { private static final String ACTION_FILE_BUG_DEEPLINK = "com.google.android.apps.betterbug.intent.FILE_BUG_DEEPLINK"; private static final boolean DEFAULT_AUTO_UPLOAD_ENABLED = false; private static final boolean DEFAULT_BUGREPORT_REQUIRED = true; private static final String DEFAULT_BUG_ASSIGNEE = "android-uwb-team@google.com"; private static final long DEFAULT_COMPONENT_ID = 1042770L; private static final String EXTRA_DEEPLINK = "EXTRA_DEEPLINK"; private static final String EXTRA_ISSUE_TITLE = "EXTRA_ISSUE_TITLE"; private static final String EXTRA_DEEPLINK_SILENT = "EXTRA_DEEPLINK_SILENT"; private static final String EXTRA_ADDITIONAL_COMMENT = "EXTRA_ADDITIONAL_COMMENT"; private static final String EXTRA_TARGET_PACKAGE = "EXTRA_TARGET_PACKAGE"; private static final String EXTRA_REQUIRE_BUGREPORT = "EXTRA_REQUIRE_BUGREPORT"; private static final String EXTRA_HAPPENED_TIME = "EXTRA_HAPPENED_TIME"; private static final String EXTRA_BUG_ASSIGNEE = "EXTRA_BUG_ASSIGNEE"; private static final String EXTRA_COMPONENT_ID = "EXTRA_COMPONENT_ID"; private final Intent mBetterBugIntent; BetterBugIntentBuilder() { mBetterBugIntent = new Intent().setAction(ACTION_FILE_BUG_DEEPLINK) .putExtra(EXTRA_DEEPLINK, true); setAutoUpload(DEFAULT_AUTO_UPLOAD_ENABLED); setBugreportRequired(DEFAULT_BUGREPORT_REQUIRED); setBugAssignee(DEFAULT_BUG_ASSIGNEE); setComponentId(DEFAULT_COMPONENT_ID); } public BetterBugIntentBuilder setIssueTitle(String title) { mBetterBugIntent.putExtra(EXTRA_ISSUE_TITLE, title); return this; } public BetterBugIntentBuilder setAutoUpload(boolean autoUploadEnabled) { mBetterBugIntent.putExtra(EXTRA_DEEPLINK_SILENT, autoUploadEnabled); return this; } public BetterBugIntentBuilder setTargetPackage(String targetPackage) { mBetterBugIntent.putExtra(EXTRA_TARGET_PACKAGE, targetPackage); return this; } public BetterBugIntentBuilder setComponentId(long componentId) { mBetterBugIntent.putExtra(EXTRA_COMPONENT_ID, componentId); return this; } public BetterBugIntentBuilder setBugreportRequired(boolean isBugreportRequired) { mBetterBugIntent.putExtra(EXTRA_REQUIRE_BUGREPORT, isBugreportRequired); return this; } public BetterBugIntentBuilder setHappenedTimestamp(long happenedTimeSinceEpochMs) { mBetterBugIntent.putExtra(EXTRA_HAPPENED_TIME, happenedTimeSinceEpochMs); return this; } public BetterBugIntentBuilder setAdditionalComment(String additionalComment) { mBetterBugIntent.putExtra(EXTRA_ADDITIONAL_COMMENT, additionalComment); return this; } public BetterBugIntentBuilder setBugAssignee(String assignee) { mBetterBugIntent.putExtra(EXTRA_BUG_ASSIGNEE, assignee); return this; } public Intent build() { return mBetterBugIntent; } } }