1 /* 2 * Copyright (C) 2020 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.powerstats; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.hardware.power.stats.Channel; 22 import android.hardware.power.stats.EnergyConsumer; 23 import android.hardware.power.stats.EnergyConsumerResult; 24 import android.hardware.power.stats.EnergyMeasurement; 25 import android.hardware.power.stats.PowerEntity; 26 import android.hardware.power.stats.StateResidencyResult; 27 import android.os.Binder; 28 import android.os.Environment; 29 import android.os.Handler; 30 import android.os.HandlerThread; 31 import android.os.UserHandle; 32 import android.power.PowerStatsInternal; 33 import android.util.Slog; 34 35 import com.android.internal.annotations.GuardedBy; 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.internal.util.DumpUtils; 38 import com.android.internal.util.function.pooled.PooledLambda; 39 import com.android.server.SystemService; 40 import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper; 41 import com.android.server.powerstats.ProtoStreamUtils.ChannelUtils; 42 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerUtils; 43 import com.android.server.powerstats.ProtoStreamUtils.PowerEntityUtils; 44 45 import java.io.File; 46 import java.io.FileDescriptor; 47 import java.io.PrintWriter; 48 import java.util.concurrent.CompletableFuture; 49 50 /** 51 * This class provides a system service that estimates system power usage 52 * per subsystem (modem, wifi, gps, display, etc) and provides those power 53 * estimates to subscribers. 54 */ 55 public class PowerStatsService extends SystemService { 56 private static final String TAG = PowerStatsService.class.getSimpleName(); 57 private static final boolean DEBUG = false; 58 private static final String DATA_STORAGE_SUBDIR = "powerstats"; 59 private static final int DATA_STORAGE_VERSION = 0; 60 private static final String METER_FILENAME = "log.powerstats.meter." + DATA_STORAGE_VERSION; 61 private static final String MODEL_FILENAME = "log.powerstats.model." + DATA_STORAGE_VERSION; 62 private static final String RESIDENCY_FILENAME = 63 "log.powerstats.residency." + DATA_STORAGE_VERSION; 64 private static final String METER_CACHE_FILENAME = "meterCache"; 65 private static final String MODEL_CACHE_FILENAME = "modelCache"; 66 private static final String RESIDENCY_CACHE_FILENAME = "residencyCache"; 67 68 private final Injector mInjector; 69 private File mDataStoragePath; 70 71 private Context mContext; 72 @Nullable 73 private PowerStatsLogger mPowerStatsLogger; 74 @Nullable 75 private BatteryTrigger mBatteryTrigger; 76 @Nullable 77 private TimerTrigger mTimerTrigger; 78 @Nullable 79 private StatsPullAtomCallbackImpl mPullAtomCallback; 80 @Nullable 81 private PowerStatsInternal mPowerStatsInternal; 82 83 @VisibleForTesting 84 static class Injector { 85 @GuardedBy("this") 86 private IPowerStatsHALWrapper mPowerStatsHALWrapper; 87 createDataStoragePath()88 File createDataStoragePath() { 89 return new File(Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), 90 DATA_STORAGE_SUBDIR); 91 } 92 createMeterFilename()93 String createMeterFilename() { 94 return METER_FILENAME; 95 } 96 createModelFilename()97 String createModelFilename() { 98 return MODEL_FILENAME; 99 } 100 createResidencyFilename()101 String createResidencyFilename() { 102 return RESIDENCY_FILENAME; 103 } 104 createMeterCacheFilename()105 String createMeterCacheFilename() { 106 return METER_CACHE_FILENAME; 107 } 108 createModelCacheFilename()109 String createModelCacheFilename() { 110 return MODEL_CACHE_FILENAME; 111 } 112 createResidencyCacheFilename()113 String createResidencyCacheFilename() { 114 return RESIDENCY_CACHE_FILENAME; 115 } 116 createPowerStatsHALWrapperImpl()117 IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() { 118 return PowerStatsHALWrapper.getPowerStatsHalImpl(); 119 } 120 getPowerStatsHALWrapperImpl()121 IPowerStatsHALWrapper getPowerStatsHALWrapperImpl() { 122 synchronized (this) { 123 if (mPowerStatsHALWrapper == null) { 124 mPowerStatsHALWrapper = PowerStatsHALWrapper.getPowerStatsHalImpl(); 125 } 126 return mPowerStatsHALWrapper; 127 } 128 } 129 createPowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String meterCacheFilename, String modelFilename, String modelCacheFilename, String residencyFilename, String residencyCacheFilename, IPowerStatsHALWrapper powerStatsHALWrapper)130 PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath, 131 String meterFilename, String meterCacheFilename, 132 String modelFilename, String modelCacheFilename, 133 String residencyFilename, String residencyCacheFilename, 134 IPowerStatsHALWrapper powerStatsHALWrapper) { 135 return new PowerStatsLogger(context, dataStoragePath, 136 meterFilename, meterCacheFilename, 137 modelFilename, modelCacheFilename, 138 residencyFilename, residencyCacheFilename, 139 powerStatsHALWrapper); 140 } 141 createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger)142 BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) { 143 return new BatteryTrigger(context, powerStatsLogger, true /* trigger enabled */); 144 } 145 createTimerTrigger(Context context, PowerStatsLogger powerStatsLogger)146 TimerTrigger createTimerTrigger(Context context, PowerStatsLogger powerStatsLogger) { 147 return new TimerTrigger(context, powerStatsLogger, true /* trigger enabled */); 148 } 149 createStatsPullerImpl(Context context, PowerStatsInternal powerStatsInternal)150 StatsPullAtomCallbackImpl createStatsPullerImpl(Context context, 151 PowerStatsInternal powerStatsInternal) { 152 return new StatsPullAtomCallbackImpl(context, powerStatsInternal); 153 } 154 } 155 156 private final class BinderService extends Binder { 157 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)158 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 159 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 160 161 if (mPowerStatsLogger == null) { 162 Slog.e(TAG, "PowerStats HAL is not initialized. No data available."); 163 } else { 164 if (args.length > 0 && "--proto".equals(args[0])) { 165 if ("model".equals(args[1])) { 166 mPowerStatsLogger.writeModelDataToFile(fd); 167 } else if ("meter".equals(args[1])) { 168 mPowerStatsLogger.writeMeterDataToFile(fd); 169 } else if ("residency".equals(args[1])) { 170 mPowerStatsLogger.writeResidencyDataToFile(fd); 171 } 172 } else if (args.length == 0) { 173 pw.println("PowerStatsService dumpsys: available PowerEntities"); 174 PowerEntity[] powerEntity = getPowerStatsHal().getPowerEntityInfo(); 175 PowerEntityUtils.dumpsys(powerEntity, pw); 176 177 pw.println("PowerStatsService dumpsys: available Channels"); 178 Channel[] channel = getPowerStatsHal().getEnergyMeterInfo(); 179 ChannelUtils.dumpsys(channel, pw); 180 181 pw.println("PowerStatsService dumpsys: available EnergyConsumers"); 182 EnergyConsumer[] energyConsumer = getPowerStatsHal().getEnergyConsumerInfo(); 183 EnergyConsumerUtils.dumpsys(energyConsumer, pw); 184 } 185 } 186 } 187 } 188 189 @Override onBootPhase(int phase)190 public void onBootPhase(int phase) { 191 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 192 onSystemServicesReady(); 193 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { 194 onBootCompleted(); 195 } 196 } 197 198 @Override onStart()199 public void onStart() { 200 if (getPowerStatsHal().isInitialized()) { 201 mPowerStatsInternal = new LocalService(); 202 publishLocalService(PowerStatsInternal.class, mPowerStatsInternal); 203 } 204 publishBinderService(Context.POWER_STATS_SERVICE, new BinderService()); 205 } 206 onSystemServicesReady()207 private void onSystemServicesReady() { 208 mPullAtomCallback = mInjector.createStatsPullerImpl(mContext, mPowerStatsInternal); 209 } 210 211 @VisibleForTesting getDeleteMeterDataOnBoot()212 public boolean getDeleteMeterDataOnBoot() { 213 return mPowerStatsLogger.getDeleteMeterDataOnBoot(); 214 } 215 216 @VisibleForTesting getDeleteModelDataOnBoot()217 public boolean getDeleteModelDataOnBoot() { 218 return mPowerStatsLogger.getDeleteModelDataOnBoot(); 219 } 220 221 @VisibleForTesting getDeleteResidencyDataOnBoot()222 public boolean getDeleteResidencyDataOnBoot() { 223 return mPowerStatsLogger.getDeleteResidencyDataOnBoot(); 224 } 225 onBootCompleted()226 private void onBootCompleted() { 227 if (getPowerStatsHal().isInitialized()) { 228 if (DEBUG) Slog.d(TAG, "Starting PowerStatsService loggers"); 229 mDataStoragePath = mInjector.createDataStoragePath(); 230 231 // Only start logger and triggers if initialization is successful. 232 mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mDataStoragePath, 233 mInjector.createMeterFilename(), mInjector.createMeterCacheFilename(), 234 mInjector.createModelFilename(), mInjector.createModelCacheFilename(), 235 mInjector.createResidencyFilename(), mInjector.createResidencyCacheFilename(), 236 getPowerStatsHal()); 237 mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger); 238 mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger); 239 } else { 240 Slog.e(TAG, "Failed to start PowerStatsService loggers"); 241 } 242 } 243 getPowerStatsHal()244 private IPowerStatsHALWrapper getPowerStatsHal() { 245 return mInjector.getPowerStatsHALWrapperImpl(); 246 } 247 PowerStatsService(Context context)248 public PowerStatsService(Context context) { 249 this(context, new Injector()); 250 } 251 252 @VisibleForTesting PowerStatsService(Context context, Injector injector)253 public PowerStatsService(Context context, Injector injector) { 254 super(context); 255 mContext = context; 256 mInjector = injector; 257 } 258 259 private final class LocalService extends PowerStatsInternal { 260 private final Handler mHandler; 261 LocalService()262 LocalService() { 263 HandlerThread thread = new HandlerThread(TAG); 264 thread.start(); 265 mHandler = new Handler(thread.getLooper()); 266 } 267 268 269 @Override getEnergyConsumerInfo()270 public EnergyConsumer[] getEnergyConsumerInfo() { 271 return getPowerStatsHal().getEnergyConsumerInfo(); 272 } 273 274 @Override getEnergyConsumedAsync( int[] energyConsumerIds)275 public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync( 276 int[] energyConsumerIds) { 277 final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture<>(); 278 mHandler.sendMessage( 279 PooledLambda.obtainMessage(PowerStatsService.this::getEnergyConsumedAsync, 280 future, energyConsumerIds)); 281 return future; 282 } 283 284 @Override getPowerEntityInfo()285 public PowerEntity[] getPowerEntityInfo() { 286 return getPowerStatsHal().getPowerEntityInfo(); 287 } 288 289 @Override getStateResidencyAsync( int[] powerEntityIds)290 public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync( 291 int[] powerEntityIds) { 292 final CompletableFuture<StateResidencyResult[]> future = new CompletableFuture<>(); 293 mHandler.sendMessage( 294 PooledLambda.obtainMessage(PowerStatsService.this::getStateResidencyAsync, 295 future, powerEntityIds)); 296 return future; 297 } 298 299 @Override getEnergyMeterInfo()300 public Channel[] getEnergyMeterInfo() { 301 return getPowerStatsHal().getEnergyMeterInfo(); 302 } 303 304 @Override readEnergyMeterAsync( int[] channelIds)305 public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync( 306 int[] channelIds) { 307 final CompletableFuture<EnergyMeasurement[]> future = new CompletableFuture<>(); 308 mHandler.sendMessage( 309 PooledLambda.obtainMessage(PowerStatsService.this::readEnergyMeterAsync, 310 future, channelIds)); 311 return future; 312 } 313 } 314 getEnergyConsumedAsync(CompletableFuture<EnergyConsumerResult[]> future, int[] energyConsumerIds)315 private void getEnergyConsumedAsync(CompletableFuture<EnergyConsumerResult[]> future, 316 int[] energyConsumerIds) { 317 future.complete(getPowerStatsHal().getEnergyConsumed(energyConsumerIds)); 318 } 319 getStateResidencyAsync(CompletableFuture<StateResidencyResult[]> future, int[] powerEntityIds)320 private void getStateResidencyAsync(CompletableFuture<StateResidencyResult[]> future, 321 int[] powerEntityIds) { 322 future.complete(getPowerStatsHal().getStateResidency(powerEntityIds)); 323 } 324 readEnergyMeterAsync(CompletableFuture<EnergyMeasurement[]> future, int[] channelIds)325 private void readEnergyMeterAsync(CompletableFuture<EnergyMeasurement[]> future, 326 int[] channelIds) { 327 future.complete(getPowerStatsHal().readEnergyMeter(channelIds)); 328 } 329 } 330