1 /* 2 * Copyright (C) 2021 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 package com.android.car.bugreport; 17 18 import android.content.Context; 19 import android.os.Build; 20 import android.os.SystemProperties; 21 import android.provider.DeviceConfig; 22 import android.util.Log; 23 24 import androidx.annotation.GuardedBy; 25 import androidx.annotation.NonNull; 26 27 import com.google.common.collect.ImmutableSet; 28 29 import java.io.PrintWriter; 30 31 /** 32 * Contains config for BugReport App. 33 * 34 * <p>The config is kept synchronized with {@code car} namespace. It's not defined in 35 * {@link DeviceConfig}. 36 * 37 * <ul>To get/set the flags via adb: 38 * <li>{@code adb shell device_config get car bugreport_upload_destination} 39 * <li>{@code adb shell device_config put car bugreport_upload_destination gcs} 40 * <li>{@code adb shell device_config delete car bugreport_upload_destination} 41 * </ul> 42 */ 43 final class Config { 44 private static final String TAG = Config.class.getSimpleName(); 45 46 /** 47 * Namespace for all Android Automotive related features. 48 * 49 * <p>In the future it will move to {@code DeviceConfig#NAMESPACE_CAR}. 50 */ 51 private static final String NAMESPACE_CAR = "car"; 52 53 /** 54 * A string flag, can be one of {@code null} or {@link #UPLOAD_DESTINATION_GCS}. 55 */ 56 private static final String KEY_BUGREPORT_UPLOAD_DESTINATION = "bugreport_upload_destination"; 57 58 /** 59 * A value for {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}. 60 * 61 * Upload bugreports to GCS. Only works in {@code userdebug} or {@code eng} builds. 62 */ 63 private static final String UPLOAD_DESTINATION_GCS = "gcs"; 64 65 /** 66 * A system property to force enable the app bypassing the {@code userdebug/eng} build check. 67 */ 68 private static final String PROP_FORCE_ENABLE = "android.car.bugreport.force_enable"; 69 70 /** 71 * A system property to override GCS bucket name that is defined in {@code configs.xml}. 72 */ 73 private static final String PROP_GCS_BUCKET = "android.car.bugreport.gcs_bucket"; 74 75 /* 76 * Enable uploading new bugreports to GCS for these devices. If the device is not in this list, 77 * {@link #KEY_UPLOAD_DESTINATION} flag will be used instead. 78 */ 79 private static final ImmutableSet<String> ENABLE_FORCE_UPLOAD_TO_GCS_FOR_DEVICES = 80 ImmutableSet.of("hawk", "seahawk"); 81 82 private final Object mLock = new Object(); 83 84 @GuardedBy("mLock") 85 private String mUploadDestination = null; 86 create(@onNull Context context)87 static Config create(@NonNull Context context) { 88 Config config = new Config(); 89 config.start(context); 90 return config; 91 } 92 Config()93 private Config() {} 94 start(@onNull Context context)95 private void start(@NonNull Context context) { 96 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CAR, 97 context.getMainExecutor(), this::onPropertiesChanged); 98 updateConstants(); 99 } 100 onPropertiesChanged(DeviceConfig.Properties properties)101 private void onPropertiesChanged(DeviceConfig.Properties properties) { 102 if (properties.getKeyset().contains(KEY_BUGREPORT_UPLOAD_DESTINATION)) { 103 updateConstants(); 104 } 105 } 106 107 /** Returns true if the device build is debuggable.*/ isDebuggable()108 static boolean isDebuggable() { 109 return "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE); 110 } 111 112 /** Returns true if bugreport app is enabled for this device. */ isBugReportEnabled()113 static boolean isBugReportEnabled() { 114 return isDebuggable() 115 || SystemProperties.getBoolean(PROP_FORCE_ENABLE, false); 116 } 117 118 /** Returns GCS bucket system property. */ getPropGcsBucket()119 static String getPropGcsBucket() { 120 return SystemProperties.get(PROP_GCS_BUCKET, ""); 121 } 122 123 /** If new bugreports should be scheduled for uploading. */ isAutoUpload()124 boolean isAutoUpload() { 125 // TODO(b/144851443): Enable auto-upload only if upload destination is Gcs until 126 // we create a way to allow implementing OEMs custom upload logic. 127 return isUploadDestinationGcs(); 128 } 129 130 /** 131 * Returns {@link true} if bugreport upload destination is GCS. 132 */ isUploadDestinationGcs()133 private boolean isUploadDestinationGcs() { 134 if (isTempForceAutoUploadGcsEnabled()) { 135 Log.d(TAG, "Setting upload dest to GCS ENABLE_AUTO_UPLOAD is true"); 136 return true; 137 } 138 // NOTE: enable it only for userdebug/eng builds. 139 return UPLOAD_DESTINATION_GCS.equals(getUploadDestination()) && isDebuggable(); 140 } 141 isTempForceAutoUploadGcsEnabled()142 private static boolean isTempForceAutoUploadGcsEnabled() { 143 return ENABLE_FORCE_UPLOAD_TO_GCS_FOR_DEVICES.contains(Build.DEVICE); 144 } 145 146 /** 147 * Returns value of a flag {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}. 148 */ getUploadDestination()149 private String getUploadDestination() { 150 synchronized (mLock) { 151 return mUploadDestination; 152 } 153 } 154 updateConstants()155 private void updateConstants() { 156 synchronized (mLock) { 157 mUploadDestination = DeviceConfig.getString(NAMESPACE_CAR, 158 KEY_BUGREPORT_UPLOAD_DESTINATION, /* defaultValue= */ null); 159 } 160 } 161 dump(String prefix, PrintWriter pw)162 void dump(String prefix, PrintWriter pw) { 163 pw.println(prefix + "car.bugreport.Config:"); 164 165 pw.print(prefix + " "); 166 pw.print("getAutoUpload"); 167 pw.print("="); 168 pw.println(isAutoUpload() ? "true" : "false"); 169 170 pw.print(prefix + " "); 171 pw.print("getUploadDestination"); 172 pw.print("="); 173 pw.println(getUploadDestination()); 174 175 pw.print(prefix + " "); 176 pw.print("isUploadDestinationGcs"); 177 pw.print("="); 178 pw.println(isUploadDestinationGcs()); 179 } 180 } 181