1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.uwb; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.os.Binder; 22 import android.os.BugreportManager; 23 import android.os.BugreportParams; 24 import android.util.Log; 25 26 /** 27 * A class to trigger bugreport and other logs for UWB related failures 28 */ 29 public class UwbDiagnostics { 30 private static final String TAG = "UwbDiagnostics"; 31 private final Context mContext; 32 private final SystemBuildProperties mSystemBuildProperties; 33 private final UwbInjector mUwbInjector; 34 private long mLastBugReportTimeMs; UwbDiagnostics( Context context, UwbInjector uwbInjector, SystemBuildProperties systemBuildProperties)35 public UwbDiagnostics( 36 Context context, UwbInjector uwbInjector, SystemBuildProperties systemBuildProperties) { 37 mContext = context; 38 mSystemBuildProperties = systemBuildProperties; 39 mUwbInjector = uwbInjector; 40 } 41 42 /** 43 * Take a bug report if it is in user debug build and there is no recent bug report 44 */ takeBugReport(String bugTitle)45 public void takeBugReport(String bugTitle) { 46 if (!mSystemBuildProperties.isUserdebugBuild()) { 47 Log.d(TAG, "Skip bugreport because it can be triggered only in userDebug build"); 48 return; 49 } 50 long currentTimeMs = mUwbInjector.getElapsedSinceBootMillis(); 51 long timeSinceLastUploadMs = currentTimeMs - mLastBugReportTimeMs; 52 if (timeSinceLastUploadMs 53 < mUwbInjector.getDeviceConfigFacade().getBugReportMinIntervalMs() 54 && mLastBugReportTimeMs > 0) { 55 Log.d(TAG, "Bugreport was filed recently, Skip " + bugTitle); 56 return; 57 } 58 59 if (!takeBugreportThroughBetterBug(bugTitle)) { 60 takeBugreportThroughBugreportManager(bugTitle); 61 } 62 } 63 takeBugreportThroughBetterBug(String bugTitle)64 private boolean takeBugreportThroughBetterBug(String bugTitle) { 65 Intent launchBetterBugIntent = 66 new BetterBugIntentBuilder() 67 .setIssueTitle(bugTitle) 68 .setHappenedTimestamp(System.currentTimeMillis()) 69 .build(); 70 boolean isIntentUnSafe = mContext 71 .getPackageManager().queryIntentActivities(launchBetterBugIntent, 0) 72 .isEmpty(); 73 if (isIntentUnSafe) { 74 Log.d(TAG, "intent is unsafe and skip bugreport from betterBug: " + bugTitle); 75 return false; 76 } 77 78 long identity = Binder.clearCallingIdentity(); 79 try { 80 launchBetterBugIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 81 mContext.startActivity(launchBetterBugIntent); 82 Log.d(TAG, "Taking the bugreport through betterBug: " + bugTitle); 83 mLastBugReportTimeMs = mUwbInjector.getElapsedSinceBootMillis(); 84 return true; 85 } catch (RuntimeException e) { 86 Log.e(TAG, "Error taking bugreport: " + e); 87 return false; 88 } finally { 89 Binder.restoreCallingIdentity(identity); 90 } 91 } 92 takeBugreportThroughBugreportManager(String bugTitle)93 private boolean takeBugreportThroughBugreportManager(String bugTitle) { 94 BugreportManager bugreportManager = mContext.getSystemService(BugreportManager.class); 95 BugreportParams params = new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL); 96 try { 97 bugreportManager.requestBugreport(params, bugTitle, bugTitle); 98 Log.d(TAG, "Taking the bugreport through bugreportManager: " + bugTitle); 99 mLastBugReportTimeMs = mUwbInjector.getElapsedSinceBootMillis(); 100 return true; 101 } catch (RuntimeException e) { 102 Log.e(TAG, "Error taking bugreport: " + e); 103 return false; 104 } 105 } 106 107 /** 108 * @return the last time when the bug report is taken 109 */ getLastBugReportTimeMs()110 long getLastBugReportTimeMs() { 111 return mLastBugReportTimeMs; 112 } 113 114 /** 115 * Builder for communicating with the betterbug. 116 */ 117 private class BetterBugIntentBuilder { 118 119 private static final String ACTION_FILE_BUG_DEEPLINK = 120 "com.google.android.apps.betterbug.intent.FILE_BUG_DEEPLINK"; 121 private static final boolean DEFAULT_AUTO_UPLOAD_ENABLED = false; 122 private static final boolean DEFAULT_BUGREPORT_REQUIRED = true; 123 private static final String DEFAULT_BUG_ASSIGNEE = "android-uwb-team@google.com"; 124 private static final long DEFAULT_COMPONENT_ID = 1042770L; 125 126 private static final String EXTRA_DEEPLINK = "EXTRA_DEEPLINK"; 127 private static final String EXTRA_ISSUE_TITLE = "EXTRA_ISSUE_TITLE"; 128 private static final String EXTRA_DEEPLINK_SILENT = "EXTRA_DEEPLINK_SILENT"; 129 private static final String EXTRA_ADDITIONAL_COMMENT = "EXTRA_ADDITIONAL_COMMENT"; 130 private static final String EXTRA_TARGET_PACKAGE = "EXTRA_TARGET_PACKAGE"; 131 private static final String EXTRA_REQUIRE_BUGREPORT = "EXTRA_REQUIRE_BUGREPORT"; 132 private static final String EXTRA_HAPPENED_TIME = "EXTRA_HAPPENED_TIME"; 133 private static final String EXTRA_BUG_ASSIGNEE = "EXTRA_BUG_ASSIGNEE"; 134 private static final String EXTRA_COMPONENT_ID = "EXTRA_COMPONENT_ID"; 135 136 private final Intent mBetterBugIntent; 137 BetterBugIntentBuilder()138 BetterBugIntentBuilder() { 139 mBetterBugIntent = new Intent().setAction(ACTION_FILE_BUG_DEEPLINK) 140 .putExtra(EXTRA_DEEPLINK, true); 141 setAutoUpload(DEFAULT_AUTO_UPLOAD_ENABLED); 142 setBugreportRequired(DEFAULT_BUGREPORT_REQUIRED); 143 setBugAssignee(DEFAULT_BUG_ASSIGNEE); 144 setComponentId(DEFAULT_COMPONENT_ID); 145 } 146 setIssueTitle(String title)147 public BetterBugIntentBuilder setIssueTitle(String title) { 148 mBetterBugIntent.putExtra(EXTRA_ISSUE_TITLE, title); 149 return this; 150 } 151 setAutoUpload(boolean autoUploadEnabled)152 public BetterBugIntentBuilder setAutoUpload(boolean autoUploadEnabled) { 153 mBetterBugIntent.putExtra(EXTRA_DEEPLINK_SILENT, autoUploadEnabled); 154 return this; 155 } 156 setTargetPackage(String targetPackage)157 public BetterBugIntentBuilder setTargetPackage(String targetPackage) { 158 mBetterBugIntent.putExtra(EXTRA_TARGET_PACKAGE, targetPackage); 159 return this; 160 } 161 setComponentId(long componentId)162 public BetterBugIntentBuilder setComponentId(long componentId) { 163 mBetterBugIntent.putExtra(EXTRA_COMPONENT_ID, componentId); 164 return this; 165 } 166 setBugreportRequired(boolean isBugreportRequired)167 public BetterBugIntentBuilder setBugreportRequired(boolean isBugreportRequired) { 168 mBetterBugIntent.putExtra(EXTRA_REQUIRE_BUGREPORT, isBugreportRequired); 169 return this; 170 } 171 setHappenedTimestamp(long happenedTimeSinceEpochMs)172 public BetterBugIntentBuilder setHappenedTimestamp(long happenedTimeSinceEpochMs) { 173 mBetterBugIntent.putExtra(EXTRA_HAPPENED_TIME, happenedTimeSinceEpochMs); 174 return this; 175 } 176 setAdditionalComment(String additionalComment)177 public BetterBugIntentBuilder setAdditionalComment(String additionalComment) { 178 mBetterBugIntent.putExtra(EXTRA_ADDITIONAL_COMMENT, additionalComment); 179 return this; 180 } 181 setBugAssignee(String assignee)182 public BetterBugIntentBuilder setBugAssignee(String assignee) { 183 mBetterBugIntent.putExtra(EXTRA_BUG_ASSIGNEE, assignee); 184 return this; 185 } 186 build()187 public Intent build() { 188 return mBetterBugIntent; 189 } 190 } 191 } 192