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