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.settings.fuelgauge; 18 19 import android.content.Context; 20 import android.content.SharedPreferences; 21 import android.util.Base64; 22 23 import androidx.annotation.VisibleForTesting; 24 25 import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; 26 import com.android.settings.fuelgauge.batteryusage.ConvertUtils; 27 28 import java.io.PrintWriter; 29 import java.util.List; 30 31 /** Writes and reads a historical log of battery related state change events. */ 32 public final class BatteryOptimizeLogUtils { 33 private static final String TAG = "BatteryOptimizeLogUtils"; 34 private static final String BATTERY_OPTIMIZE_FILE_NAME = "battery_optimize_historical_logs"; 35 private static final String LOGS_KEY = "battery_optimize_logs_key"; 36 37 @VisibleForTesting static final int MAX_ENTRIES = 40; 38 BatteryOptimizeLogUtils()39 private BatteryOptimizeLogUtils() {} 40 41 /** Writes a log entry for battery optimization mode. */ writeLog( Context context, Action action, String packageName, String actionDescription)42 static void writeLog( 43 Context context, Action action, String packageName, String actionDescription) { 44 writeLog(getSharedPreferences(context), action, packageName, actionDescription); 45 } 46 writeLog( SharedPreferences sharedPreferences, Action action, String packageName, String actionDescription)47 static void writeLog( 48 SharedPreferences sharedPreferences, 49 Action action, 50 String packageName, 51 String actionDescription) { 52 writeLog( 53 sharedPreferences, 54 BatteryOptimizeHistoricalLogEntry.newBuilder() 55 .setPackageName(packageName) 56 .setAction(action) 57 .setActionDescription(actionDescription) 58 .setTimestamp(System.currentTimeMillis()) 59 .build()); 60 } 61 writeLog( SharedPreferences sharedPreferences, BatteryOptimizeHistoricalLogEntry logEntry)62 private static void writeLog( 63 SharedPreferences sharedPreferences, BatteryOptimizeHistoricalLogEntry logEntry) { 64 BatteryOptimizeHistoricalLog existingLog = 65 parseLogFromString(sharedPreferences.getString(LOGS_KEY, "")); 66 BatteryOptimizeHistoricalLog.Builder newLogBuilder = existingLog.toBuilder(); 67 // Prune old entries to limit the max logging data count. 68 if (existingLog.getLogEntryCount() >= MAX_ENTRIES) { 69 newLogBuilder.removeLogEntry(0); 70 } 71 newLogBuilder.addLogEntry(logEntry); 72 73 String loggingContent = 74 Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT); 75 sharedPreferences.edit().putString(LOGS_KEY, loggingContent).apply(); 76 } 77 parseLogFromString(String storedLogs)78 private static BatteryOptimizeHistoricalLog parseLogFromString(String storedLogs) { 79 return BatteryUtils.parseProtoFromString( 80 storedLogs, BatteryOptimizeHistoricalLog.getDefaultInstance()); 81 } 82 83 /** Prints the historical log that has previously been stored by this utility. */ printBatteryOptimizeHistoricalLog(Context context, PrintWriter writer)84 public static void printBatteryOptimizeHistoricalLog(Context context, PrintWriter writer) { 85 printBatteryOptimizeHistoricalLog(getSharedPreferences(context), writer); 86 } 87 88 /** Prints the historical log that has previously been stored by this utility. */ printBatteryOptimizeHistoricalLog( SharedPreferences sharedPreferences, PrintWriter writer)89 public static void printBatteryOptimizeHistoricalLog( 90 SharedPreferences sharedPreferences, PrintWriter writer) { 91 writer.println("Battery optimize state history:"); 92 BatteryOptimizeHistoricalLog existingLog = 93 parseLogFromString(sharedPreferences.getString(LOGS_KEY, "")); 94 List<BatteryOptimizeHistoricalLogEntry> logEntryList = existingLog.getLogEntryList(); 95 if (logEntryList.isEmpty()) { 96 writer.println("\tnothing to dump"); 97 } else { 98 writer.println("0:UNKNOWN 1:RESTRICTED 2:UNRESTRICTED 3:OPTIMIZED"); 99 logEntryList.forEach(entry -> writer.println(toString(entry))); 100 } 101 } 102 103 /** Gets the unique key for logging. */ getPackageNameWithUserId(String packageName, int userId)104 static String getPackageNameWithUserId(String packageName, int userId) { 105 return packageName + ":" + userId; 106 } 107 toString(BatteryOptimizeHistoricalLogEntry entry)108 private static String toString(BatteryOptimizeHistoricalLogEntry entry) { 109 return String.format( 110 "%s\t%s\taction:%s\tevent:%s", 111 ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()), 112 entry.getPackageName(), 113 entry.getAction(), 114 entry.getActionDescription()); 115 } 116 117 @VisibleForTesting getSharedPreferences(Context context)118 static SharedPreferences getSharedPreferences(Context context) { 119 return context.getApplicationContext() 120 .getSharedPreferences(BATTERY_OPTIMIZE_FILE_NAME, Context.MODE_PRIVATE); 121 } 122 } 123