• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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