• 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 static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assert.fail;
22 
23 import android.content.Context;
24 import android.hardware.power.stats.Channel;
25 import android.hardware.power.stats.EnergyConsumer;
26 import android.hardware.power.stats.EnergyConsumerAttribution;
27 import android.hardware.power.stats.EnergyConsumerResult;
28 import android.hardware.power.stats.EnergyMeasurement;
29 import android.hardware.power.stats.PowerEntity;
30 import android.hardware.power.stats.State;
31 import android.hardware.power.stats.StateResidency;
32 import android.hardware.power.stats.StateResidencyResult;
33 
34 import androidx.test.InstrumentationRegistry;
35 
36 import com.android.server.SystemService;
37 import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
38 import com.android.server.powerstats.ProtoStreamUtils.ChannelUtils;
39 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerUtils;
40 import com.android.server.powerstats.ProtoStreamUtils.PowerEntityUtils;
41 import com.android.server.powerstats.nano.PowerEntityProto;
42 import com.android.server.powerstats.nano.PowerStatsServiceMeterProto;
43 import com.android.server.powerstats.nano.PowerStatsServiceModelProto;
44 import com.android.server.powerstats.nano.PowerStatsServiceResidencyProto;
45 import com.android.server.powerstats.nano.StateProto;
46 import com.android.server.powerstats.nano.StateResidencyProto;
47 import com.android.server.powerstats.nano.StateResidencyResultProto;
48 
49 import org.junit.Before;
50 import org.junit.Test;
51 
52 import java.io.ByteArrayOutputStream;
53 import java.io.File;
54 import java.io.FileInputStream;
55 import java.io.FileOutputStream;
56 import java.io.IOException;
57 import java.nio.ByteBuffer;
58 import java.nio.file.Files;
59 import java.util.Arrays;
60 import java.util.Random;
61 
62 /**
63  * Tests for {@link com.android.server.powerstats.PowerStatsService}.
64  *
65  * Build/Install/Run:
66  *  atest FrameworksServicesTests:PowerStatsServiceTest
67  */
68 public class PowerStatsServiceTest {
69     private static final String TAG = PowerStatsServiceTest.class.getSimpleName();
70     private static final String DATA_STORAGE_SUBDIR = "powerstatstest";
71     private static final String METER_FILENAME = "log.powerstats.metertest.0";
72     private static final String MODEL_FILENAME = "log.powerstats.modeltest.0";
73     private static final String RESIDENCY_FILENAME = "log.powerstats.residencytest.0";
74     private static final String PROTO_OUTPUT_FILENAME = "powerstats.proto";
75     private static final String CHANNEL_NAME = "channelname";
76     private static final String CHANNEL_SUBSYSTEM = "channelsubsystem";
77     private static final String POWER_ENTITY_NAME = "powerentityinfo";
78     private static final String STATE_NAME = "stateinfo";
79     private static final String ENERGY_CONSUMER_NAME = "energyconsumer";
80     private static final String METER_CACHE_FILENAME = "meterCacheTest";
81     private static final String MODEL_CACHE_FILENAME = "modelCacheTest";
82     private static final String RESIDENCY_CACHE_FILENAME = "residencyCacheTest";
83     private static final int ENERGY_METER_COUNT = 8;
84     private static final int ENERGY_CONSUMER_COUNT = 2;
85     private static final int ENERGY_CONSUMER_ATTRIBUTION_COUNT = 5;
86     private static final int POWER_ENTITY_COUNT = 3;
87     private static final int STATE_INFO_COUNT = 5;
88     private static final int STATE_RESIDENCY_COUNT = 4;
89 
90     private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
91     private PowerStatsService mService;
92     private File mDataStorageDir;
93     private TimerTrigger mTimerTrigger;
94     private BatteryTrigger mBatteryTrigger;
95     private PowerStatsLogger mPowerStatsLogger;
96 
97     private final PowerStatsService.Injector mInjector = new PowerStatsService.Injector() {
98         private TestPowerStatsHALWrapper mTestPowerStatsHALWrapper = new TestPowerStatsHALWrapper();
99         @Override
100         File createDataStoragePath() {
101             if (mDataStorageDir == null) {
102                 try {
103                     mDataStorageDir = Files.createTempDirectory(DATA_STORAGE_SUBDIR).toFile();
104                 } catch (IOException e) {
105                     fail("Could not create temp directory.");
106                 }
107             }
108 
109             return mDataStorageDir;
110         }
111 
112         @Override
113         String createMeterFilename() {
114             return METER_FILENAME;
115         }
116 
117         @Override
118         String createModelFilename() {
119             return MODEL_FILENAME;
120         }
121 
122         @Override
123         String createResidencyFilename() {
124             return RESIDENCY_FILENAME;
125         }
126 
127         @Override
128         String createMeterCacheFilename() {
129             return METER_CACHE_FILENAME;
130         }
131 
132         @Override
133         String createModelCacheFilename() {
134             return MODEL_CACHE_FILENAME;
135         }
136 
137         @Override
138         String createResidencyCacheFilename() {
139             return RESIDENCY_CACHE_FILENAME;
140         }
141 
142         @Override
143         IPowerStatsHALWrapper getPowerStatsHALWrapperImpl() {
144             return mTestPowerStatsHALWrapper;
145         }
146 
147         @Override
148         PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
149                 String meterFilename, String meterCacheFilename,
150                 String modelFilename, String modelCacheFilename,
151                 String residencyFilename, String residencyCacheFilename,
152                 IPowerStatsHALWrapper powerStatsHALWrapper) {
153             mPowerStatsLogger = new PowerStatsLogger(context, dataStoragePath,
154                 meterFilename, meterCacheFilename,
155                 modelFilename, modelCacheFilename,
156                 residencyFilename, residencyCacheFilename,
157                 powerStatsHALWrapper);
158             return mPowerStatsLogger;
159         }
160 
161         @Override
162         BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) {
163             mBatteryTrigger = new BatteryTrigger(context, powerStatsLogger,
164                 false /* trigger enabled */);
165             return mBatteryTrigger;
166         }
167 
168         @Override
169         TimerTrigger createTimerTrigger(Context context, PowerStatsLogger powerStatsLogger) {
170             mTimerTrigger = new TimerTrigger(context, powerStatsLogger,
171                 false /* trigger enabled */);
172             return mTimerTrigger;
173         }
174     };
175 
176     public static final class TestPowerStatsHALWrapper implements IPowerStatsHALWrapper {
177         @Override
getPowerEntityInfo()178         public PowerEntity[] getPowerEntityInfo() {
179             PowerEntity[] powerEntityList = new PowerEntity[POWER_ENTITY_COUNT];
180             for (int i = 0; i < powerEntityList.length; i++) {
181                 powerEntityList[i] = new PowerEntity();
182                 powerEntityList[i].id = i;
183                 powerEntityList[i].name = new String(POWER_ENTITY_NAME + i);
184                 powerEntityList[i].states = new State[STATE_INFO_COUNT];
185                 for (int j = 0; j < powerEntityList[i].states.length; j++) {
186                     powerEntityList[i].states[j] = new State();
187                     powerEntityList[i].states[j].id = j;
188                     powerEntityList[i].states[j].name = new String(STATE_NAME + j);
189                 }
190             }
191             return powerEntityList;
192         }
193 
194         @Override
getStateResidency(int[] powerEntityIds)195         public StateResidencyResult[] getStateResidency(int[] powerEntityIds) {
196             StateResidencyResult[] stateResidencyResultList =
197                 new StateResidencyResult[POWER_ENTITY_COUNT];
198             for (int i = 0; i < stateResidencyResultList.length; i++) {
199                 stateResidencyResultList[i] = new StateResidencyResult();
200                 stateResidencyResultList[i].id = i;
201                 stateResidencyResultList[i].stateResidencyData =
202                     new StateResidency[STATE_RESIDENCY_COUNT];
203                 for (int j = 0; j < stateResidencyResultList[i].stateResidencyData.length; j++) {
204                     stateResidencyResultList[i].stateResidencyData[j] = new StateResidency();
205                     stateResidencyResultList[i].stateResidencyData[j].id = j;
206                     stateResidencyResultList[i].stateResidencyData[j].totalTimeInStateMs = j;
207                     stateResidencyResultList[i].stateResidencyData[j].totalStateEntryCount = j;
208                     stateResidencyResultList[i].stateResidencyData[j].lastEntryTimestampMs = j;
209                 }
210             }
211 
212             return stateResidencyResultList;
213         }
214 
215         @Override
getEnergyConsumerInfo()216         public EnergyConsumer[] getEnergyConsumerInfo() {
217             EnergyConsumer[] energyConsumerList = new EnergyConsumer[ENERGY_CONSUMER_COUNT];
218             for (int i = 0; i < energyConsumerList.length; i++) {
219                 energyConsumerList[i] = new EnergyConsumer();
220                 energyConsumerList[i].id = i;
221                 energyConsumerList[i].ordinal = i;
222                 energyConsumerList[i].type = (byte) i;
223                 energyConsumerList[i].name = new String(ENERGY_CONSUMER_NAME + i);
224             }
225             return energyConsumerList;
226         }
227 
228         @Override
getEnergyConsumed(int[] energyConsumerIds)229         public EnergyConsumerResult[] getEnergyConsumed(int[] energyConsumerIds) {
230             EnergyConsumerResult[] energyConsumedList =
231                 new EnergyConsumerResult[ENERGY_CONSUMER_COUNT];
232             for (int i = 0; i < energyConsumedList.length; i++) {
233                 energyConsumedList[i] = new EnergyConsumerResult();
234                 energyConsumedList[i].id = i;
235                 energyConsumedList[i].timestampMs = i;
236                 energyConsumedList[i].energyUWs = i;
237                 energyConsumedList[i].attribution =
238                     new EnergyConsumerAttribution[ENERGY_CONSUMER_ATTRIBUTION_COUNT];
239                 for (int j = 0; j < energyConsumedList[i].attribution.length; j++) {
240                     energyConsumedList[i].attribution[j] = new EnergyConsumerAttribution();
241                     energyConsumedList[i].attribution[j].uid = j;
242                     energyConsumedList[i].attribution[j].energyUWs = j;
243                 }
244             }
245             return energyConsumedList;
246         }
247 
248         @Override
getEnergyMeterInfo()249         public Channel[] getEnergyMeterInfo() {
250             Channel[] energyMeterList = new Channel[ENERGY_METER_COUNT];
251             for (int i = 0; i < energyMeterList.length; i++) {
252                 energyMeterList[i] = new Channel();
253                 energyMeterList[i].id = i;
254                 energyMeterList[i].name = new String(CHANNEL_NAME + i);
255                 energyMeterList[i].subsystem = new String(CHANNEL_SUBSYSTEM + i);
256             }
257             return energyMeterList;
258         }
259 
260         @Override
readEnergyMeter(int[] channelIds)261         public EnergyMeasurement[] readEnergyMeter(int[] channelIds) {
262             EnergyMeasurement[] energyMeasurementList = new EnergyMeasurement[ENERGY_METER_COUNT];
263             for (int i = 0; i < energyMeasurementList.length; i++) {
264                 energyMeasurementList[i] = new EnergyMeasurement();
265                 energyMeasurementList[i].id = i;
266                 energyMeasurementList[i].timestampMs = i;
267                 energyMeasurementList[i].durationMs = i;
268                 energyMeasurementList[i].energyUWs = i;
269             }
270             return energyMeasurementList;
271         }
272 
273         @Override
isInitialized()274         public boolean isInitialized() {
275             return true;
276         }
277     }
278 
279     @Before
setUp()280     public void setUp() {
281         mService = new PowerStatsService(mContext, mInjector);
282     }
283 
284     @Test
testWrittenMeterDataMatchesReadIncidentReportData()285     public void testWrittenMeterDataMatchesReadIncidentReportData()
286             throws InterruptedException, IOException {
287         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
288 
289         // Write data to on-device storage.
290         mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY);
291 
292         // The above call puts a message on a handler.  Wait for
293         // it to be processed.
294         Thread.sleep(100);
295 
296         // Write on-device storage to an incident report.
297         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
298         FileOutputStream fos = new FileOutputStream(incidentReport);
299         mPowerStatsLogger.writeMeterDataToFile(fos.getFD());
300 
301         // Read the incident report in to a byte array.
302         FileInputStream fis = new FileInputStream(incidentReport);
303         byte[] fileContent = new byte[(int) incidentReport.length()];
304         fis.read(fileContent);
305 
306         // Parse the incident data into a PowerStatsServiceMeterProto object.
307         PowerStatsServiceMeterProto pssProto = PowerStatsServiceMeterProto.parseFrom(fileContent);
308 
309         // Validate the channel array matches what was written to on-device storage.
310         assertTrue(pssProto.channel.length == ENERGY_METER_COUNT);
311         for (int i = 0; i < pssProto.channel.length; i++) {
312             assertTrue(pssProto.channel[i].id == i);
313             assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i));
314             assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i));
315         }
316 
317         // Validate the energyMeasurement array matches what was written to on-device storage.
318         assertTrue(pssProto.energyMeasurement.length == ENERGY_METER_COUNT);
319         for (int i = 0; i < pssProto.energyMeasurement.length; i++) {
320             assertTrue(pssProto.energyMeasurement[i].id == i);
321             assertTrue(pssProto.energyMeasurement[i].timestampMs ==
322                     i + mPowerStatsLogger.getStartWallTime());
323             assertTrue(pssProto.energyMeasurement[i].durationMs == i);
324             assertTrue(pssProto.energyMeasurement[i].energyUws == i);
325         }
326     }
327 
328     @Test
testWrittenModelDataMatchesReadIncidentReportData()329     public void testWrittenModelDataMatchesReadIncidentReportData()
330             throws InterruptedException, IOException {
331         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
332 
333         // Write data to on-device storage.
334         mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY);
335 
336         // The above call puts a message on a handler.  Wait for
337         // it to be processed.
338         Thread.sleep(100);
339 
340         // Write on-device storage to an incident report.
341         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
342         FileOutputStream fos = new FileOutputStream(incidentReport);
343         mPowerStatsLogger.writeModelDataToFile(fos.getFD());
344 
345         // Read the incident report in to a byte array.
346         FileInputStream fis = new FileInputStream(incidentReport);
347         byte[] fileContent = new byte[(int) incidentReport.length()];
348         fis.read(fileContent);
349 
350         // Parse the incident data into a PowerStatsServiceModelProto object.
351         PowerStatsServiceModelProto pssProto = PowerStatsServiceModelProto.parseFrom(fileContent);
352 
353         // Validate the energyConsumer array matches what was written to on-device storage.
354         assertTrue(pssProto.energyConsumer.length == ENERGY_CONSUMER_COUNT);
355         for (int i = 0; i < pssProto.energyConsumer.length; i++) {
356             assertTrue(pssProto.energyConsumer[i].id == i);
357         }
358 
359         // Validate the energyConsumerResult array matches what was written to on-device storage.
360         assertTrue(pssProto.energyConsumerResult.length == ENERGY_CONSUMER_COUNT);
361         for (int i = 0; i < pssProto.energyConsumerResult.length; i++) {
362             assertTrue(pssProto.energyConsumerResult[i].id == i);
363             assertTrue(pssProto.energyConsumerResult[i].timestampMs ==
364                     i + mPowerStatsLogger.getStartWallTime());
365             assertTrue(pssProto.energyConsumerResult[i].energyUws == i);
366             assertTrue(pssProto.energyConsumerResult[i].attribution.length
367                     == ENERGY_CONSUMER_ATTRIBUTION_COUNT);
368             for (int j = 0; j < pssProto.energyConsumerResult[i].attribution.length; j++) {
369                 assertTrue(pssProto.energyConsumerResult[i].attribution[j].uid == j);
370                 assertTrue(pssProto.energyConsumerResult[i].attribution[j].energyUws  == j);
371             }
372         }
373     }
374 
375     @Test
testWrittenResidencyDataMatchesReadIncidentReportData()376     public void testWrittenResidencyDataMatchesReadIncidentReportData()
377             throws InterruptedException, IOException {
378         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
379 
380         // Write data to on-device storage.
381         mBatteryTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP);
382 
383         // The above call puts a message on a handler.  Wait for
384         // it to be processed.
385         Thread.sleep(100);
386 
387         // Write on-device storage to an incident report.
388         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
389         FileOutputStream fos = new FileOutputStream(incidentReport);
390         mPowerStatsLogger.writeResidencyDataToFile(fos.getFD());
391 
392         // Read the incident report in to a byte array.
393         FileInputStream fis = new FileInputStream(incidentReport);
394         byte[] fileContent = new byte[(int) incidentReport.length()];
395         fis.read(fileContent);
396 
397         // Parse the incident data into a PowerStatsServiceResidencyProto object.
398         PowerStatsServiceResidencyProto pssProto =
399                 PowerStatsServiceResidencyProto.parseFrom(fileContent);
400 
401         // Validate the powerEntity array matches what was written to on-device storage.
402         assertTrue(pssProto.powerEntity.length == POWER_ENTITY_COUNT);
403         for (int i = 0; i < pssProto.powerEntity.length; i++) {
404             PowerEntityProto powerEntity = pssProto.powerEntity[i];
405             assertTrue(powerEntity.id == i);
406             assertTrue(powerEntity.name.equals(POWER_ENTITY_NAME + i));
407             for (int j = 0; j < powerEntity.states.length; j++) {
408                 StateProto state = powerEntity.states[j];
409                 assertTrue(state.id == j);
410                 assertTrue(state.name.equals(STATE_NAME + j));
411             }
412         }
413 
414         // Validate the stateResidencyResult array matches what was written to on-device storage.
415         assertTrue(pssProto.stateResidencyResult.length == POWER_ENTITY_COUNT);
416         for (int i = 0; i < pssProto.stateResidencyResult.length; i++) {
417             StateResidencyResultProto stateResidencyResult = pssProto.stateResidencyResult[i];
418             assertTrue(stateResidencyResult.id == i);
419             assertTrue(stateResidencyResult.stateResidencyData.length == STATE_RESIDENCY_COUNT);
420             for (int j = 0; j < stateResidencyResult.stateResidencyData.length; j++) {
421                 StateResidencyProto stateResidency = stateResidencyResult.stateResidencyData[j];
422                 assertTrue(stateResidency.id == j);
423                 assertTrue(stateResidency.totalTimeInStateMs == j);
424                 assertTrue(stateResidency.totalStateEntryCount == j);
425                 assertTrue(stateResidency.lastEntryTimestampMs ==
426                         j + mPowerStatsLogger.getStartWallTime());
427             }
428         }
429     }
430 
431     @Test
testCorruptOnDeviceMeterStorage()432     public void testCorruptOnDeviceMeterStorage() throws IOException {
433         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
434 
435         // Generate random array of bytes to emulate corrupt data.
436         Random rd = new Random();
437         byte[] bytes = new byte[100];
438         rd.nextBytes(bytes);
439 
440         // Store corrupt data in on-device storage.  Add fake timestamp to filename
441         // to match format expected by FileRotator.
442         File onDeviceStorageFile = new File(mDataStorageDir, METER_FILENAME + ".1234-2234");
443         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
444         onDeviceStorageFos.write(bytes);
445         onDeviceStorageFos.close();
446 
447         // Write on-device storage to an incident report.
448         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
449         FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
450         mPowerStatsLogger.writeMeterDataToFile(incidentReportFos.getFD());
451 
452         // Read the incident report in to a byte array.
453         FileInputStream fis = new FileInputStream(incidentReport);
454         byte[] fileContent = new byte[(int) incidentReport.length()];
455         fis.read(fileContent);
456 
457         // Parse the incident data into a PowerStatsServiceMeterProto object.
458         PowerStatsServiceMeterProto pssProto = PowerStatsServiceMeterProto.parseFrom(fileContent);
459 
460         // Valid channel data is written to the incident report in the call to
461         // mPowerStatsLogger.writeMeterDataToFile().
462         assertTrue(pssProto.channel.length == ENERGY_METER_COUNT);
463         for (int i = 0; i < pssProto.channel.length; i++) {
464             assertTrue(pssProto.channel[i].id == i);
465             assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i));
466             assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i));
467         }
468 
469         // No energyMeasurements should be written to the incident report since it
470         // is all corrupt (random bytes generated above).
471         assertTrue(pssProto.energyMeasurement.length == 0);
472     }
473 
474     @Test
testCorruptOnDeviceModelStorage()475     public void testCorruptOnDeviceModelStorage() throws IOException {
476         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
477 
478         // Generate random array of bytes to emulate corrupt data.
479         Random rd = new Random();
480         byte[] bytes = new byte[100];
481         rd.nextBytes(bytes);
482 
483         // Store corrupt data in on-device storage.  Add fake timestamp to filename
484         // to match format expected by FileRotator.
485         File onDeviceStorageFile = new File(mDataStorageDir, MODEL_FILENAME + ".1234-2234");
486         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
487         onDeviceStorageFos.write(bytes);
488         onDeviceStorageFos.close();
489 
490         // Write on-device storage to an incident report.
491         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
492         FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
493         mPowerStatsLogger.writeModelDataToFile(incidentReportFos.getFD());
494 
495         // Read the incident report in to a byte array.
496         FileInputStream fis = new FileInputStream(incidentReport);
497         byte[] fileContent = new byte[(int) incidentReport.length()];
498         fis.read(fileContent);
499 
500         // Parse the incident data into a PowerStatsServiceModelProto object.
501         PowerStatsServiceModelProto pssProto = PowerStatsServiceModelProto.parseFrom(fileContent);
502 
503         // Valid energyConsumer data is written to the incident report in the call to
504         // mPowerStatsLogger.writeModelDataToFile().
505         assertTrue(pssProto.energyConsumer.length == ENERGY_CONSUMER_COUNT);
506         for (int i = 0; i < pssProto.energyConsumer.length; i++) {
507             assertTrue(pssProto.energyConsumer[i].id == i);
508         }
509 
510         // No energyConsumerResults should be written to the incident report since it
511         // is all corrupt (random bytes generated above).
512         assertTrue(pssProto.energyConsumerResult.length == 0);
513     }
514 
515     @Test
testCorruptOnDeviceResidencyStorage()516     public void testCorruptOnDeviceResidencyStorage() throws IOException {
517         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
518 
519         // Generate random array of bytes to emulate corrupt data.
520         Random rd = new Random();
521         byte[] bytes = new byte[100];
522         rd.nextBytes(bytes);
523 
524         // Store corrupt data in on-device storage.  Add fake timestamp to filename
525         // to match format expected by FileRotator.
526         File onDeviceStorageFile = new File(mDataStorageDir, RESIDENCY_FILENAME + ".1234-2234");
527         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
528         onDeviceStorageFos.write(bytes);
529         onDeviceStorageFos.close();
530 
531         // Write on-device storage to an incident report.
532         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
533         FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
534         mPowerStatsLogger.writeResidencyDataToFile(incidentReportFos.getFD());
535 
536         // Read the incident report in to a byte array.
537         FileInputStream fis = new FileInputStream(incidentReport);
538         byte[] fileContent = new byte[(int) incidentReport.length()];
539         fis.read(fileContent);
540 
541         // Parse the incident data into a PowerStatsServiceResidencyProto object.
542         PowerStatsServiceResidencyProto pssProto =
543                 PowerStatsServiceResidencyProto.parseFrom(fileContent);
544 
545         // Valid powerEntity data is written to the incident report in the call to
546         // mPowerStatsLogger.writeResidencyDataToFile().
547         assertTrue(pssProto.powerEntity.length == POWER_ENTITY_COUNT);
548         for (int i = 0; i < pssProto.powerEntity.length; i++) {
549             PowerEntityProto powerEntity = pssProto.powerEntity[i];
550             assertTrue(powerEntity.id == i);
551             assertTrue(powerEntity.name.equals(POWER_ENTITY_NAME + i));
552             for (int j = 0; j < powerEntity.states.length; j++) {
553                 StateProto state = powerEntity.states[j];
554                 assertTrue(state.id == j);
555                 assertTrue(state.name.equals(STATE_NAME + j));
556             }
557         }
558 
559         // No stateResidencyResults should be written to the incident report since it
560         // is all corrupt (random bytes generated above).
561         assertTrue(pssProto.stateResidencyResult.length == 0);
562     }
563 
564     @Test
testNotEnoughBytesAfterMeterLengthField()565     public void testNotEnoughBytesAfterMeterLengthField() throws IOException {
566         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
567 
568         // Create corrupt data.
569         // Length field is correct, but there is no data following the length.
570         ByteArrayOutputStream data = new ByteArrayOutputStream();
571         data.write(ByteBuffer.allocate(4).putInt(50).array());
572         byte[] test = data.toByteArray();
573 
574         // Store corrupt data in on-device storage.  Add fake timestamp to filename
575         // to match format expected by FileRotator.
576         File onDeviceStorageFile = new File(mDataStorageDir, METER_FILENAME + ".1234-2234");
577         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
578         onDeviceStorageFos.write(data.toByteArray());
579         onDeviceStorageFos.close();
580 
581         // Write on-device storage to an incident report.
582         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
583         FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
584         mPowerStatsLogger.writeMeterDataToFile(incidentReportFos.getFD());
585 
586         // Read the incident report in to a byte array.
587         FileInputStream fis = new FileInputStream(incidentReport);
588         byte[] fileContent = new byte[(int) incidentReport.length()];
589         fis.read(fileContent);
590 
591         // Parse the incident data into a PowerStatsServiceMeterProto object.
592         PowerStatsServiceMeterProto pssProto = PowerStatsServiceMeterProto.parseFrom(fileContent);
593 
594         // Valid channel data is written to the incident report in the call to
595         // mPowerStatsLogger.writeMeterDataToFile().
596         assertTrue(pssProto.channel.length == ENERGY_METER_COUNT);
597         for (int i = 0; i < pssProto.channel.length; i++) {
598             assertTrue(pssProto.channel[i].id == i);
599             assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i));
600             assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i));
601         }
602 
603         // No energyMeasurements should be written to the incident report since the
604         // input buffer had only length and no data.
605         assertTrue(pssProto.energyMeasurement.length == 0);
606     }
607 
608     @Test
testNotEnoughBytesAfterModelLengthField()609     public void testNotEnoughBytesAfterModelLengthField() throws IOException {
610         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
611 
612         // Create corrupt data.
613         // Length field is correct, but there is no data following the length.
614         ByteArrayOutputStream data = new ByteArrayOutputStream();
615         data.write(ByteBuffer.allocate(4).putInt(50).array());
616         byte[] test = data.toByteArray();
617 
618         // Store corrupt data in on-device storage.  Add fake timestamp to filename
619         // to match format expected by FileRotator.
620         File onDeviceStorageFile = new File(mDataStorageDir, MODEL_FILENAME + ".1234-2234");
621         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
622         onDeviceStorageFos.write(data.toByteArray());
623         onDeviceStorageFos.close();
624 
625         // Write on-device storage to an incident report.
626         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
627         FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
628         mPowerStatsLogger.writeModelDataToFile(incidentReportFos.getFD());
629 
630         // Read the incident report in to a byte array.
631         FileInputStream fis = new FileInputStream(incidentReport);
632         byte[] fileContent = new byte[(int) incidentReport.length()];
633         fis.read(fileContent);
634 
635         // Parse the incident data into a PowerStatsServiceModelProto object.
636         PowerStatsServiceModelProto pssProto = PowerStatsServiceModelProto.parseFrom(fileContent);
637 
638         // Valid energyConsumer data is written to the incident report in the call to
639         // mPowerStatsLogger.writeModelDataToFile().
640         assertTrue(pssProto.energyConsumer.length == ENERGY_CONSUMER_COUNT);
641         for (int i = 0; i < pssProto.energyConsumer.length; i++) {
642             assertTrue(pssProto.energyConsumer[i].id == i);
643         }
644 
645         // No energyConsumerResults should be written to the incident report since the
646         // input buffer had only length and no data.
647         assertTrue(pssProto.energyConsumerResult.length == 0);
648     }
649 
650     @Test
testNotEnoughBytesAfterResidencyLengthField()651     public void testNotEnoughBytesAfterResidencyLengthField() throws IOException {
652         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
653 
654         // Create corrupt data.
655         // Length field is correct, but there is no data following the length.
656         ByteArrayOutputStream data = new ByteArrayOutputStream();
657         data.write(ByteBuffer.allocate(4).putInt(50).array());
658         byte[] test = data.toByteArray();
659 
660         // Store corrupt data in on-device storage.  Add fake timestamp to filename
661         // to match format expected by FileRotator.
662         File onDeviceStorageFile = new File(mDataStorageDir, RESIDENCY_FILENAME + ".1234-2234");
663         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
664         onDeviceStorageFos.write(data.toByteArray());
665         onDeviceStorageFos.close();
666 
667         // Write on-device storage to an incident report.
668         File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
669         FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
670         mPowerStatsLogger.writeResidencyDataToFile(incidentReportFos.getFD());
671 
672         // Read the incident report in to a byte array.
673         FileInputStream fis = new FileInputStream(incidentReport);
674         byte[] fileContent = new byte[(int) incidentReport.length()];
675         fis.read(fileContent);
676 
677         // Parse the incident data into a PowerStatsServiceResidencyProto object.
678         PowerStatsServiceResidencyProto pssProto =
679                 PowerStatsServiceResidencyProto.parseFrom(fileContent);
680 
681         // Valid powerEntity data is written to the incident report in the call to
682         // mPowerStatsLogger.writeResidencyDataToFile().
683         assertTrue(pssProto.powerEntity.length == POWER_ENTITY_COUNT);
684         for (int i = 0; i < pssProto.powerEntity.length; i++) {
685             PowerEntityProto powerEntity = pssProto.powerEntity[i];
686             assertTrue(powerEntity.id == i);
687             assertTrue(powerEntity.name.equals(POWER_ENTITY_NAME + i));
688             for (int j = 0; j < powerEntity.states.length; j++) {
689                 StateProto state = powerEntity.states[j];
690                 assertTrue(state.id == j);
691                 assertTrue(state.name.equals(STATE_NAME + j));
692             }
693         }
694 
695         // No stateResidencyResults should be written to the incident report since the
696         // input buffer had only length and no data.
697         assertTrue(pssProto.stateResidencyResult.length == 0);
698     }
699 
700     @Test
testDataStorageDeletedMeterMismatch()701     public void testDataStorageDeletedMeterMismatch() throws IOException {
702         // Create the directory where cached data will be stored.
703         mInjector.createDataStoragePath();
704 
705         // In order to create cached data that will match the current data read by the
706         // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is
707         // returned from the Injector.
708         IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl();
709 
710         // Generate random array of bytes to emulate cached meter data.  Store to file.
711         Random rd = new Random();
712         byte[] bytes = new byte[100];
713         rd.nextBytes(bytes);
714         File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename());
715         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
716         onDeviceStorageFos.write(bytes);
717         onDeviceStorageFos.close();
718 
719         // Create cached energy consumer data and write to file.
720         EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo();
721         bytes = EnergyConsumerUtils.getProtoBytes(energyConsumers);
722         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename());
723         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
724         onDeviceStorageFos.write(bytes);
725         onDeviceStorageFos.close();
726 
727         // Create cached power entity info data and write to file.
728         PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo();
729         bytes = PowerEntityUtils.getProtoBytes(powerEntityInfo);
730         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename());
731         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
732         onDeviceStorageFos.write(bytes);
733         onDeviceStorageFos.close();
734 
735         // Create log files.
736         File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename());
737         File modelFile = new File(mDataStorageDir, mInjector.createModelFilename());
738         File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename());
739         meterFile.createNewFile();
740         modelFile.createNewFile();
741         residencyFile.createNewFile();
742 
743         // Verify log files exist.
744         assertTrue(meterFile.exists());
745         assertTrue(modelFile.exists());
746         assertTrue(residencyFile.exists());
747 
748         // Boot device after creating old cached data.
749         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
750 
751         // Since cached meter data is just random bytes it won't match the data read from the HAL.
752         // This mismatch of cached and current HAL data should force a delete.
753         assertTrue(mService.getDeleteMeterDataOnBoot());
754         assertFalse(mService.getDeleteModelDataOnBoot());
755         assertFalse(mService.getDeleteResidencyDataOnBoot());
756 
757         // Verify log files were deleted.
758         assertFalse(meterFile.exists());
759         assertTrue(modelFile.exists());
760         assertTrue(residencyFile.exists());
761 
762         // Verify cached meter data was updated to new HAL output.
763         Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo();
764         byte[] bytesExpected = ChannelUtils.getProtoBytes(channels);
765         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename());
766         byte[] bytesActual = new byte[(int) onDeviceStorageFile.length()];
767         FileInputStream onDeviceStorageFis = new FileInputStream(onDeviceStorageFile);
768         onDeviceStorageFis.read(bytesActual);
769         assertTrue(Arrays.equals(bytesExpected, bytesActual));
770     }
771 
772     @Test
testDataStorageDeletedModelMismatch()773     public void testDataStorageDeletedModelMismatch() throws IOException {
774         // Create the directory where cached data will be stored.
775         mInjector.createDataStoragePath();
776 
777         // In order to create cached data that will match the current data read by the
778         // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is
779         // returned from the Injector.
780         IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl();
781 
782         // Create cached channel data and write to file.
783         Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo();
784         byte[] bytes = ChannelUtils.getProtoBytes(channels);
785         File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename());
786         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
787         onDeviceStorageFos.write(bytes);
788         onDeviceStorageFos.close();
789 
790         // Generate random array of bytes to emulate cached energy consumer data.  Store to file.
791         Random rd = new Random();
792         bytes = new byte[100];
793         rd.nextBytes(bytes);
794         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename());
795         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
796         onDeviceStorageFos.write(bytes);
797         onDeviceStorageFos.close();
798 
799         // Create cached power entity info data and write to file.
800         PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo();
801         bytes = PowerEntityUtils.getProtoBytes(powerEntityInfo);
802         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename());
803         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
804         onDeviceStorageFos.write(bytes);
805         onDeviceStorageFos.close();
806 
807         // Create log files.
808         File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename());
809         File modelFile = new File(mDataStorageDir, mInjector.createModelFilename());
810         File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename());
811         meterFile.createNewFile();
812         modelFile.createNewFile();
813         residencyFile.createNewFile();
814 
815         // Verify log files exist.
816         assertTrue(meterFile.exists());
817         assertTrue(modelFile.exists());
818         assertTrue(residencyFile.exists());
819 
820         // Boot device after creating old cached data.
821         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
822 
823         // Since cached energy consumer data is just random bytes it won't match the data read from
824         // the HAL.  This mismatch of cached and current HAL data should force a delete.
825         assertFalse(mService.getDeleteMeterDataOnBoot());
826         assertTrue(mService.getDeleteModelDataOnBoot());
827         assertFalse(mService.getDeleteResidencyDataOnBoot());
828 
829         // Verify log files were deleted.
830         assertTrue(meterFile.exists());
831         assertFalse(modelFile.exists());
832         assertTrue(residencyFile.exists());
833 
834         // Verify cached energy consumer data was updated to new HAL output.
835         EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo();
836         byte[] bytesExpected = EnergyConsumerUtils.getProtoBytes(energyConsumers);
837         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename());
838         byte[] bytesActual = new byte[(int) onDeviceStorageFile.length()];
839         FileInputStream onDeviceStorageFis = new FileInputStream(onDeviceStorageFile);
840         onDeviceStorageFis.read(bytesActual);
841         assertTrue(Arrays.equals(bytesExpected, bytesActual));
842     }
843 
844     @Test
testDataStorageDeletedResidencyMismatch()845     public void testDataStorageDeletedResidencyMismatch() throws IOException {
846         // Create the directory where cached data will be stored.
847         mInjector.createDataStoragePath();
848 
849         // In order to create cached data that will match the current data read by the
850         // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is
851         // returned from the Injector.
852         IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl();
853 
854         // Create cached channel data and write to file.
855         Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo();
856         byte[] bytes = ChannelUtils.getProtoBytes(channels);
857         File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename());
858         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
859         onDeviceStorageFos.write(bytes);
860         onDeviceStorageFos.close();
861 
862         // Create cached energy consumer data and write to file.
863         EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo();
864         bytes = EnergyConsumerUtils.getProtoBytes(energyConsumers);
865         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename());
866         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
867         onDeviceStorageFos.write(bytes);
868         onDeviceStorageFos.close();
869 
870         // Generate random array of bytes to emulate cached power entity info data.  Store to file.
871         Random rd = new Random();
872         bytes = new byte[100];
873         rd.nextBytes(bytes);
874         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename());
875         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
876         onDeviceStorageFos.write(bytes);
877         onDeviceStorageFos.close();
878 
879         // Create log files.
880         File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename());
881         File modelFile = new File(mDataStorageDir, mInjector.createModelFilename());
882         File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename());
883         meterFile.createNewFile();
884         modelFile.createNewFile();
885         residencyFile.createNewFile();
886 
887         // Verify log files exist.
888         assertTrue(meterFile.exists());
889         assertTrue(modelFile.exists());
890         assertTrue(residencyFile.exists());
891 
892         // Boot device after creating old cached data.
893         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
894 
895         // Since cached power entity info data is just random bytes it won't match the data read
896         // from the HAL.  This mismatch of cached and current HAL data should force a delete.
897         assertFalse(mService.getDeleteMeterDataOnBoot());
898         assertFalse(mService.getDeleteModelDataOnBoot());
899         assertTrue(mService.getDeleteResidencyDataOnBoot());
900 
901         // Verify log files were deleted.
902         assertTrue(meterFile.exists());
903         assertTrue(modelFile.exists());
904         assertFalse(residencyFile.exists());
905 
906         // Verify cached power entity data was updated to new HAL output.
907         PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo();
908         byte[] bytesExpected = PowerEntityUtils.getProtoBytes(powerEntityInfo);
909         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename());
910         byte[] bytesActual = new byte[(int) onDeviceStorageFile.length()];
911         FileInputStream onDeviceStorageFis = new FileInputStream(onDeviceStorageFile);
912         onDeviceStorageFis.read(bytesActual);
913         assertTrue(Arrays.equals(bytesExpected, bytesActual));
914     }
915 
916     @Test
testDataStorageNotDeletedNoCachedData()917     public void testDataStorageNotDeletedNoCachedData() throws IOException {
918         // Create the directory where log files will be stored.
919         mInjector.createDataStoragePath();
920 
921         // Create log files.
922         File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename());
923         File modelFile = new File(mDataStorageDir, mInjector.createModelFilename());
924         File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename());
925         meterFile.createNewFile();
926         modelFile.createNewFile();
927         residencyFile.createNewFile();
928 
929         // Verify log files exist.
930         assertTrue(meterFile.exists());
931         assertTrue(modelFile.exists());
932         assertTrue(residencyFile.exists());
933 
934         // This test mimics the device's first boot where there is no cached data.
935         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
936 
937         // Since there is no cached data on the first boot any log files that happen to exist
938         // should be deleted.
939         assertTrue(mService.getDeleteMeterDataOnBoot());
940         assertTrue(mService.getDeleteModelDataOnBoot());
941         assertTrue(mService.getDeleteResidencyDataOnBoot());
942 
943         // Verify log files were deleted.
944         assertFalse(meterFile.exists());
945         assertFalse(modelFile.exists());
946         assertFalse(residencyFile.exists());
947     }
948 
949     @Test
testDataStorageNotDeletedAllDataMatches()950     public void testDataStorageNotDeletedAllDataMatches() throws IOException {
951         // Create the directory where cached data will be stored.
952         mInjector.createDataStoragePath();
953 
954         // In order to create cached data that will match the current data read by the
955         // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is
956         // returned from the Injector.
957         IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl();
958 
959         // Create cached channel data and write to file.
960         Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo();
961         byte[] bytes = ChannelUtils.getProtoBytes(channels);
962         File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename());
963         FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
964         onDeviceStorageFos.write(bytes);
965         onDeviceStorageFos.close();
966 
967         // Create cached energy consumer data and write to file.
968         EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo();
969         bytes = EnergyConsumerUtils.getProtoBytes(energyConsumers);
970         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename());
971         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
972         onDeviceStorageFos.write(bytes);
973         onDeviceStorageFos.close();
974 
975         // Create cached power entity info data and write to file.
976         PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo();
977         bytes = PowerEntityUtils.getProtoBytes(powerEntityInfo);
978         onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename());
979         onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
980         onDeviceStorageFos.write(bytes);
981         onDeviceStorageFos.close();
982 
983         // Create log files.
984         File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename());
985         File modelFile = new File(mDataStorageDir, mInjector.createModelFilename());
986         File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename());
987         meterFile.createNewFile();
988         modelFile.createNewFile();
989         residencyFile.createNewFile();
990 
991         // Verify log files exist.
992         assertTrue(meterFile.exists());
993         assertTrue(modelFile.exists());
994         assertTrue(residencyFile.exists());
995 
996         // Boot device after creating old cached data.
997         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
998 
999         // All cached data created above should match current data read in PowerStatsService so we
1000         // expect the data not to be deleted.
1001         assertFalse(mService.getDeleteMeterDataOnBoot());
1002         assertFalse(mService.getDeleteModelDataOnBoot());
1003         assertFalse(mService.getDeleteResidencyDataOnBoot());
1004 
1005         // Verify log files were not deleted.
1006         assertTrue(meterFile.exists());
1007         assertTrue(modelFile.exists());
1008         assertTrue(residencyFile.exists());
1009     }
1010 }
1011