1 /* 2 * Copyright (C) 2023 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.backup.utils; 18 19 import android.app.backup.BackupAnnotations; 20 import android.app.backup.BackupManagerMonitor; 21 import android.app.backup.BackupRestoreEventLogger; 22 import android.os.Bundle; 23 import android.os.Environment; 24 import android.util.Slog; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 import com.android.internal.util.FastPrintWriter; 28 29 import java.io.BufferedReader; 30 import java.io.File; 31 import java.io.FileInputStream; 32 import java.io.FileOutputStream; 33 import java.io.FileWriter; 34 import java.io.IOException; 35 import java.io.InputStreamReader; 36 import java.io.PrintWriter; 37 import java.text.SimpleDateFormat; 38 import java.util.ArrayList; 39 import java.util.Date; 40 import java.util.Map; 41 import java.util.concurrent.TimeUnit; 42 43 44 /* 45 * Util class to parse a BMM event and write it to a text file, to be the printed in 46 * the backup dumpsys 47 * 48 * Note: this class is note thread safe 49 */ 50 public class BackupManagerMonitorDumpsysUtils { 51 52 private static final String TAG = "BackupManagerMonitorDumpsysUtils"; 53 // Name of the subdirectory where the text file containing the BMM events will be stored. 54 // Same as {@link UserBackupManagerFiles} 55 private static final String BACKUP_PERSISTENT_DIR = "backup"; 56 private static final String INITIAL_SETUP_TIMESTAMP_KEY = "initialSetupTimestamp"; 57 // Retention period of 60 days (in millisec) for the BMM Events. 58 // After tha time has passed the text file containing the BMM events will be emptied 59 private static final long LOGS_RETENTION_PERIOD_MILLISEC = 60 * TimeUnit.DAYS.toMillis(1); 60 // Size limit for the text file containing the BMM events 61 private static final long BMM_FILE_SIZE_LIMIT_BYTES = 25 * 1024 * 1000; // 2.5 MB 62 63 // We cache the value of IsAfterRetentionPeriod() to avoid unnecessary disk I/O 64 // mIsAfterRetentionPeriodCached tracks if we have cached the value of IsAfterRetentionPeriod() 65 private boolean mIsAfterRetentionPeriodCached = false; 66 // The cached value of IsAfterRetentionPeriod() 67 private boolean mIsAfterRetentionPeriod; 68 // If isFileLargerThanSizeLimit(bmmEvents) returns true we cache the value to avoid 69 // unnecessary disk I/O 70 private boolean mIsFileLargerThanSizeLimit = false; 71 72 /** 73 * Parses the BackupManagerMonitor bundle for a RESTORE event in a series of strings that 74 * will be persisted in a text file and printed in the dumpsys. 75 * 76 * If the eventBundle passed is not a RESTORE event, return early 77 * 78 * Key information related to the event: 79 * - Timestamp (HAS TO ALWAYS BE THE FIRST LINE OF EACH EVENT) 80 * - Event ID 81 * - Event Category 82 * - Operation type 83 * - Package name (can be null) 84 * - Agent logs (if available) 85 * 86 * Example of formatting: 87 * [2023-09-21 14:43:33.824] - Agent logging results 88 * Package: com.android.wallpaperbackup 89 * Agent Logs: 90 * Data Type: wlp_img_system 91 * Item restored: 0/1 92 * Agent Error - Category: no_wallpaper, Count: 1 93 * Data Type: wlp_img_lock 94 * Item restored: 0/1 95 * Agent Error - Category: no_wallpaper, Count: 1 96 */ parseBackupManagerMonitorRestoreEventForDumpsys(Bundle eventBundle)97 public void parseBackupManagerMonitorRestoreEventForDumpsys(Bundle eventBundle) { 98 if (isAfterRetentionPeriod()) { 99 // We only log data for the first 60 days since setup 100 return; 101 } 102 103 if (eventBundle == null) { 104 return; 105 } 106 107 if (!isOpTypeRestore(eventBundle)) { 108 //We only log Restore events 109 return; 110 } 111 112 if (!eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_ID) 113 || !eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY)) { 114 Slog.w(TAG, "Event id and category are not optional fields."); 115 return; 116 } 117 File bmmEvents = getBMMEventsFile(); 118 119 if (bmmEvents.length() == 0) { 120 // We are parsing the first restore event. 121 // Time to also record the setup timestamp of the device 122 recordSetUpTimestamp(); 123 } 124 125 if(isFileLargerThanSizeLimit(bmmEvents)){ 126 // Do not write more events if the file is over size limit 127 return; 128 } 129 130 try (FileOutputStream out = new FileOutputStream(bmmEvents, /*append*/ true); 131 PrintWriter pw = new FastPrintWriter(out);) { 132 133 int eventCategory = eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY); 134 int eventId = eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID); 135 136 if (eventId == BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS && 137 !hasAgentLogging(eventBundle)) { 138 // Do not record an empty agent logging event 139 return; 140 } 141 142 pw.println("[" + timestamp() + "] - " + getId(eventId)); 143 144 if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME)) { 145 pw.println("\tPackage: " 146 + eventBundle.getString(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME)); 147 } 148 149 // TODO(b/296818666): add extras to the events 150 addAgentLogsIfAvailable(eventBundle, pw); 151 addExtrasIfAvailable(eventBundle, pw); 152 } catch (java.io.IOException e) { 153 Slog.e(TAG, "IO Exception when writing BMM events to file: " + e); 154 } 155 156 } 157 hasAgentLogging(Bundle eventBundle)158 private boolean hasAgentLogging(Bundle eventBundle) { 159 if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS)) { 160 ArrayList<BackupRestoreEventLogger.DataTypeResult> agentLogs = 161 eventBundle.getParcelableArrayList( 162 BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS); 163 164 return !agentLogs.isEmpty(); 165 } 166 return false; 167 } 168 169 /** 170 * Extracts agent logs from the BackupManagerMonitor event. These logs detail: 171 * - the data type for the agent 172 * - the count of successfully restored items 173 * - the count of items that failed to restore 174 * - the metadata associated with this datatype 175 * - any errors 176 */ addAgentLogsIfAvailable(Bundle eventBundle, PrintWriter pw)177 private void addAgentLogsIfAvailable(Bundle eventBundle, PrintWriter pw) { 178 if (hasAgentLogging(eventBundle)) { 179 pw.println("\tAgent Logs:"); 180 ArrayList<BackupRestoreEventLogger.DataTypeResult> agentLogs = 181 eventBundle.getParcelableArrayList( 182 BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS); 183 for (BackupRestoreEventLogger.DataTypeResult result : agentLogs) { 184 int totalItems = result.getFailCount() + result.getSuccessCount(); 185 pw.println("\t\tData Type: " + result.getDataType()); 186 pw.println("\t\t\tItem restored: " + result.getSuccessCount() + "/" + 187 totalItems); 188 for (Map.Entry<String, Integer> entry : result.getErrors().entrySet()) { 189 pw.println("\t\t\tAgent Error - Category: " + 190 entry.getKey() + ", Count: " + entry.getValue()); 191 } 192 } 193 } 194 } 195 196 /** 197 * Extracts some extras (defined in BackupManagerMonitor as EXTRA_LOG_<description>) 198 * from the BackupManagerMonitor event. Not all extras have the same importance. For now only 199 * focus on extras relating to version mismatches between packages on the source and target. 200 * 201 * When an event with ID LOG_EVENT_ID_RESTORE_VERSION_HIGHER (trying to restore from higher to 202 * lower version of a package) parse: 203 * EXTRA_LOG_RESTORE_VERSION [int]: the version of the package on the source 204 * EXTRA_LOG_RESTORE_ANYWAY [bool]: if the package allows restore any version 205 * EXTRA_LOG_RESTORE_VERSION_TARGET [int]: an extra to record the package version on the target 206 */ addExtrasIfAvailable(Bundle eventBundle, PrintWriter pw)207 private void addExtrasIfAvailable(Bundle eventBundle, PrintWriter pw) { 208 if (eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID) == 209 BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER) { 210 if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY)) { 211 pw.println("\t\tPackage supports RestoreAnyVersion: " 212 + eventBundle.getBoolean(BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY)); 213 } 214 if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION)) { 215 pw.println("\t\tPackage version on source: " 216 + eventBundle.getLong(BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION)); 217 } 218 if (eventBundle.containsKey( 219 BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)) { 220 pw.println("\t\tPackage version on target: " 221 + eventBundle.getLong( 222 BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)); 223 } 224 } 225 } 226 227 /* 228 * Get the path of the text files which stores the BMM events 229 */ getBMMEventsFile()230 public File getBMMEventsFile() { 231 File dataDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR); 232 File fname = new File(dataDir, "bmmevents.txt"); 233 return fname; 234 } 235 isFileLargerThanSizeLimit(File events)236 public boolean isFileLargerThanSizeLimit(File events){ 237 if (!mIsFileLargerThanSizeLimit) { 238 mIsFileLargerThanSizeLimit = events.length() > getBMMEventsFileSizeLimit(); 239 } 240 return mIsFileLargerThanSizeLimit; 241 } 242 timestamp()243 private String timestamp() { 244 long currentTime = System.currentTimeMillis(); 245 Date date = new Date(currentTime); 246 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 247 return dateFormat.format(date); 248 } 249 getCategory(int code)250 private String getCategory(int code) { 251 String category = switch (code) { 252 case BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT -> "Transport"; 253 case BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT -> "Agent"; 254 case BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY -> 255 "Backup Manager Policy"; 256 default -> "Unknown category code: " + code; 257 }; 258 return category; 259 } 260 getId(int code)261 private String getId(int code) { 262 String id = switch (code) { 263 case BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL -> "Full backup cancel"; 264 case BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY -> "Illegal key"; 265 case BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND -> "No data to send"; 266 case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE -> "Package ineligible"; 267 case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT -> 268 "Package key-value participant"; 269 case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED -> "Package stopped"; 270 case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND -> "Package not found"; 271 case BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED -> "Backup disabled"; 272 case BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED -> 273 "Device not provisioned"; 274 case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT -> 275 "Package transport not present"; 276 case BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT -> "Error preflight"; 277 case BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT -> "Quota hit preflight"; 278 case BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP -> "Exception full backup"; 279 case BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL -> 280 "Key-value backup cancel"; 281 case BackupManagerMonitor.LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE -> 282 "No restore metadata available"; 283 case BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED -> 284 "No PM metadata received"; 285 case BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA -> 286 "PM agent has no metadata"; 287 case BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT -> "Lost transport"; 288 case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_PRESENT -> "Package not present"; 289 case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER -> 290 "Restore version higher"; 291 case BackupManagerMonitor.LOG_EVENT_ID_APP_HAS_NO_AGENT -> "App has no agent"; 292 case BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH -> "Signature mismatch"; 293 case BackupManagerMonitor.LOG_EVENT_ID_CANT_FIND_AGENT -> "Can't find agent"; 294 case BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT -> 295 "Key-value restore timeout"; 296 case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION -> "Restore any version"; 297 case BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH -> "Versions match"; 298 case BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER -> 299 "Version of backup older"; 300 case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH -> 301 "Full restore signature mismatch"; 302 case BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT -> "System app no agent"; 303 case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE -> 304 "Full restore allow backup false"; 305 case BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED -> "APK not installed"; 306 case BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK -> 307 "Cannot restore without APK"; 308 case BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE -> "Missing signature"; 309 case BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE -> 310 "Expected different package"; 311 case BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION -> "Unknown version"; 312 case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_TIMEOUT -> "Full restore timeout"; 313 case BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST -> "Corrupt manifest"; 314 case BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH -> 315 "Widget metadata mismatch"; 316 case BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION -> 317 "Widget unknown version"; 318 case BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES -> "No packages"; 319 case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL -> "Transport is null"; 320 case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED -> 321 "Transport non-incremental backup required"; 322 case BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS -> "Agent logging results"; 323 case BackupManagerMonitor.LOG_EVENT_ID_START_SYSTEM_RESTORE -> "Start system restore"; 324 case BackupManagerMonitor.LOG_EVENT_ID_START_RESTORE_AT_INSTALL -> 325 "Start restore at install"; 326 case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_DURING_START_RESTORE -> 327 "Transport error during start restore"; 328 case BackupManagerMonitor.LOG_EVENT_ID_CANNOT_GET_NEXT_PKG_NAME -> 329 "Cannot get next package name"; 330 case BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_RESTORE_TYPE -> "Unknown restore type"; 331 case BackupManagerMonitor.LOG_EVENT_ID_KV_RESTORE -> "KV restore"; 332 case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE -> "Full restore"; 333 case BackupManagerMonitor.LOG_EVENT_ID_NO_NEXT_RESTORE_TARGET -> 334 "No next restore target"; 335 case BackupManagerMonitor.LOG_EVENT_ID_KV_AGENT_ERROR -> "KV agent error"; 336 case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_RESTORE_FINISHED -> 337 "Package restore finished"; 338 case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_KV_RESTORE -> 339 "Transport error KV restore"; 340 case BackupManagerMonitor.LOG_EVENT_ID_NO_FEEDER_THREAD -> "No feeder thread"; 341 case BackupManagerMonitor.LOG_EVENT_ID_FULL_AGENT_ERROR -> "Full agent error"; 342 case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_FULL_RESTORE -> 343 "Transport error full restore"; 344 case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_COMPLETE -> "Restore complete"; 345 case BackupManagerMonitor.LOG_EVENT_ID_START_PACKAGE_RESTORE -> 346 "Start package restore"; 347 case BackupManagerMonitor.LOG_EVENT_ID_AGENT_FAILURE -> 348 "Agent failure"; 349 default -> "Unknown log event ID: " + code; 350 }; 351 return id; 352 } 353 isOpTypeRestore(Bundle eventBundle)354 private boolean isOpTypeRestore(Bundle eventBundle) { 355 return switch (eventBundle.getInt( 356 BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE, -1)) { 357 case BackupAnnotations.OperationType.RESTORE -> true; 358 default -> false; 359 }; 360 } 361 362 /** 363 * Store the timestamp when the device was set up (date when the first BMM event is parsed) 364 * in a text file. 365 */ 366 @VisibleForTesting recordSetUpTimestamp()367 void recordSetUpTimestamp() { 368 File setupDateFile = getSetUpDateFile(); 369 // record setup timestamp only once 370 if (setupDateFile.length() == 0) { 371 try (FileOutputStream out = new FileOutputStream(setupDateFile, /*append*/ true); 372 PrintWriter pw = new FastPrintWriter(out);) { 373 long currentDate = System.currentTimeMillis(); 374 pw.println(currentDate); 375 } catch (IOException e) { 376 Slog.w(TAG, "An error occurred while recording the setup date: " 377 + e.getMessage()); 378 } 379 } 380 381 } 382 383 @VisibleForTesting getSetUpDate()384 String getSetUpDate() { 385 File fname = getSetUpDateFile(); 386 try (FileInputStream inputStream = new FileInputStream(fname); 387 InputStreamReader reader = new InputStreamReader(inputStream); 388 BufferedReader bufferedReader = new BufferedReader(reader);) { 389 return bufferedReader.readLine(); 390 } catch (Exception e) { 391 Slog.w(TAG, "An error occurred while reading the date: " + e.getMessage()); 392 return "Could not retrieve setup date"; 393 } 394 } 395 396 @VisibleForTesting isDateAfterNMillisec(long startTimeStamp, long endTimeStamp, long millisec)397 static boolean isDateAfterNMillisec(long startTimeStamp, long endTimeStamp, long millisec) { 398 if (startTimeStamp > endTimeStamp) { 399 // Something has gone wrong, timeStamp1 should always precede timeStamp2. 400 // Out of caution return true: we would delete the logs rather than 401 // risking them being kept for longer than the retention period 402 return true; 403 } 404 long timeDifferenceMillis = endTimeStamp - startTimeStamp; 405 return (timeDifferenceMillis >= millisec); 406 } 407 408 /** 409 * Check if current date is after retention period 410 */ 411 @VisibleForTesting isAfterRetentionPeriod()412 boolean isAfterRetentionPeriod() { 413 if (mIsAfterRetentionPeriodCached) { 414 return mIsAfterRetentionPeriod; 415 } else { 416 File setUpDateFile = getSetUpDateFile(); 417 if (setUpDateFile.length() == 0) { 418 // We are yet to record a setup date. This means we haven't parsed the first event. 419 mIsAfterRetentionPeriod = false; 420 mIsAfterRetentionPeriodCached = true; 421 return false; 422 } 423 try { 424 long setupTimestamp = Long.parseLong(getSetUpDate()); 425 long currentTimestamp = System.currentTimeMillis(); 426 mIsAfterRetentionPeriod = isDateAfterNMillisec(setupTimestamp, currentTimestamp, 427 getRetentionPeriodInMillisec()); 428 mIsAfterRetentionPeriodCached = true; 429 return mIsAfterRetentionPeriod; 430 } catch (NumberFormatException e) { 431 // An error occurred when parsing the setup timestamp. 432 // Out of caution return true: we would delete the logs rather than 433 // risking them being kept for longer than the retention period 434 mIsAfterRetentionPeriod = true; 435 mIsAfterRetentionPeriodCached = true; 436 return true; 437 } 438 } 439 } 440 441 @VisibleForTesting getSetUpDateFile()442 File getSetUpDateFile() { 443 File dataDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR); 444 File setupDateFile = new File(dataDir, INITIAL_SETUP_TIMESTAMP_KEY + ".txt"); 445 return setupDateFile; 446 } 447 448 @VisibleForTesting getRetentionPeriodInMillisec()449 long getRetentionPeriodInMillisec() { 450 return LOGS_RETENTION_PERIOD_MILLISEC; 451 } 452 453 @VisibleForTesting getBMMEventsFileSizeLimit()454 long getBMMEventsFileSizeLimit(){ 455 return BMM_FILE_SIZE_LIMIT_BYTES; 456 } 457 458 /** 459 * Delete the BMM Events file after the retention period has passed. 460 * 461 * @return true if the retention period has passed false otherwise. 462 * we want to return true even if we were unable to delete the file, as this will prevent 463 * expired BMM events from being printed to the dumpsys 464 */ deleteExpiredBMMEvents()465 public boolean deleteExpiredBMMEvents() { 466 try { 467 if (isAfterRetentionPeriod()) { 468 File bmmEvents = getBMMEventsFile(); 469 if (bmmEvents.exists()) { 470 if (bmmEvents.delete()) { 471 Slog.i(TAG, "Deleted expired BMM Events"); 472 } else { 473 Slog.e(TAG, "Unable to delete expired BMM Events"); 474 } 475 } 476 return true; 477 } 478 return false; 479 } catch (Exception e) { 480 // Handle any unexpected exceptions 481 // To be safe we return true as we want to avoid exposing expired BMMEvents 482 return true; 483 } 484 } 485 } 486