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