| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.powerstats; |
| |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import android.content.Context; |
| import android.hardware.power.stats.Channel; |
| import android.hardware.power.stats.EnergyConsumer; |
| import android.hardware.power.stats.EnergyConsumerAttribution; |
| import android.hardware.power.stats.EnergyConsumerResult; |
| import android.hardware.power.stats.EnergyMeasurement; |
| import android.hardware.power.stats.PowerEntity; |
| import android.hardware.power.stats.State; |
| import android.hardware.power.stats.StateResidency; |
| import android.hardware.power.stats.StateResidencyResult; |
| import android.os.Looper; |
| |
| import androidx.test.InstrumentationRegistry; |
| |
| import com.android.server.SystemService; |
| import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper; |
| import com.android.server.powerstats.ProtoStreamUtils.ChannelUtils; |
| import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerUtils; |
| import com.android.server.powerstats.ProtoStreamUtils.PowerEntityUtils; |
| import com.android.server.powerstats.nano.PowerEntityProto; |
| import com.android.server.powerstats.nano.PowerStatsServiceMeterProto; |
| import com.android.server.powerstats.nano.PowerStatsServiceModelProto; |
| import com.android.server.powerstats.nano.PowerStatsServiceResidencyProto; |
| import com.android.server.powerstats.nano.StateProto; |
| import com.android.server.powerstats.nano.StateResidencyProto; |
| import com.android.server.powerstats.nano.StateResidencyResultProto; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.nio.file.Files; |
| import java.util.Arrays; |
| import java.util.Random; |
| |
| /** |
| * Tests for {@link com.android.server.powerstats.PowerStatsService}. |
| * |
| * Build/Install/Run: |
| * atest FrameworksServicesTests:PowerStatsServiceTest |
| */ |
| public class PowerStatsServiceTest { |
| private static final String TAG = PowerStatsServiceTest.class.getSimpleName(); |
| private static final String DATA_STORAGE_SUBDIR = "powerstatstest"; |
| private static final String METER_FILENAME = "log.powerstats.metertest.0"; |
| private static final String MODEL_FILENAME = "log.powerstats.modeltest.0"; |
| private static final String RESIDENCY_FILENAME = "log.powerstats.residencytest.0"; |
| private static final String PROTO_OUTPUT_FILENAME = "powerstats.proto"; |
| private static final String CHANNEL_NAME = "channelname"; |
| private static final String CHANNEL_SUBSYSTEM = "channelsubsystem"; |
| private static final String POWER_ENTITY_NAME = "powerentityinfo"; |
| private static final String STATE_NAME = "stateinfo"; |
| private static final String ENERGY_CONSUMER_NAME = "energyconsumer"; |
| private static final String METER_CACHE_FILENAME = "meterCacheTest"; |
| private static final String MODEL_CACHE_FILENAME = "modelCacheTest"; |
| private static final String RESIDENCY_CACHE_FILENAME = "residencyCacheTest"; |
| private static final int ENERGY_METER_COUNT = 8; |
| private static final int ENERGY_CONSUMER_COUNT = 2; |
| private static final int ENERGY_CONSUMER_ATTRIBUTION_COUNT = 5; |
| private static final int POWER_ENTITY_COUNT = 3; |
| private static final int STATE_INFO_COUNT = 5; |
| private static final int STATE_RESIDENCY_COUNT = 4; |
| |
| private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); |
| private PowerStatsService mService; |
| private File mDataStorageDir; |
| private TimerTrigger mTimerTrigger; |
| private BatteryTrigger mBatteryTrigger; |
| private PowerStatsLogger mPowerStatsLogger; |
| |
| private final PowerStatsService.Injector mInjector = new PowerStatsService.Injector() { |
| private TestPowerStatsHALWrapper mTestPowerStatsHALWrapper = new TestPowerStatsHALWrapper(); |
| @Override |
| File createDataStoragePath() { |
| if (mDataStorageDir == null) { |
| try { |
| mDataStorageDir = Files.createTempDirectory(DATA_STORAGE_SUBDIR).toFile(); |
| } catch (IOException e) { |
| fail("Could not create temp directory."); |
| } |
| } |
| |
| return mDataStorageDir; |
| } |
| |
| @Override |
| String createMeterFilename() { |
| return METER_FILENAME; |
| } |
| |
| @Override |
| String createModelFilename() { |
| return MODEL_FILENAME; |
| } |
| |
| @Override |
| String createResidencyFilename() { |
| return RESIDENCY_FILENAME; |
| } |
| |
| @Override |
| String createMeterCacheFilename() { |
| return METER_CACHE_FILENAME; |
| } |
| |
| @Override |
| String createModelCacheFilename() { |
| return MODEL_CACHE_FILENAME; |
| } |
| |
| @Override |
| String createResidencyCacheFilename() { |
| return RESIDENCY_CACHE_FILENAME; |
| } |
| |
| @Override |
| IPowerStatsHALWrapper getPowerStatsHALWrapperImpl() { |
| return mTestPowerStatsHALWrapper; |
| } |
| |
| @Override |
| PowerStatsLogger createPowerStatsLogger(Context context, Looper looper, |
| File dataStoragePath, String meterFilename, String meterCacheFilename, |
| String modelFilename, String modelCacheFilename, |
| String residencyFilename, String residencyCacheFilename, |
| IPowerStatsHALWrapper powerStatsHALWrapper) { |
| mPowerStatsLogger = new PowerStatsLogger(context, looper, dataStoragePath, |
| meterFilename, meterCacheFilename, |
| modelFilename, modelCacheFilename, |
| residencyFilename, residencyCacheFilename, |
| powerStatsHALWrapper); |
| return mPowerStatsLogger; |
| } |
| |
| @Override |
| BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) { |
| mBatteryTrigger = new BatteryTrigger(context, powerStatsLogger, |
| false /* trigger enabled */); |
| return mBatteryTrigger; |
| } |
| |
| @Override |
| TimerTrigger createTimerTrigger(Context context, PowerStatsLogger powerStatsLogger) { |
| mTimerTrigger = new TimerTrigger(context, powerStatsLogger, |
| false /* trigger enabled */); |
| return mTimerTrigger; |
| } |
| }; |
| |
| public static final class TestPowerStatsHALWrapper implements IPowerStatsHALWrapper { |
| @Override |
| public PowerEntity[] getPowerEntityInfo() { |
| PowerEntity[] powerEntityList = new PowerEntity[POWER_ENTITY_COUNT]; |
| for (int i = 0; i < powerEntityList.length; i++) { |
| powerEntityList[i] = new PowerEntity(); |
| powerEntityList[i].id = i; |
| powerEntityList[i].name = new String(POWER_ENTITY_NAME + i); |
| powerEntityList[i].states = new State[STATE_INFO_COUNT]; |
| for (int j = 0; j < powerEntityList[i].states.length; j++) { |
| powerEntityList[i].states[j] = new State(); |
| powerEntityList[i].states[j].id = j; |
| powerEntityList[i].states[j].name = new String(STATE_NAME + j); |
| } |
| } |
| return powerEntityList; |
| } |
| |
| @Override |
| public StateResidencyResult[] getStateResidency(int[] powerEntityIds) { |
| StateResidencyResult[] stateResidencyResultList = |
| new StateResidencyResult[POWER_ENTITY_COUNT]; |
| for (int i = 0; i < stateResidencyResultList.length; i++) { |
| stateResidencyResultList[i] = new StateResidencyResult(); |
| stateResidencyResultList[i].id = i; |
| stateResidencyResultList[i].stateResidencyData = |
| new StateResidency[STATE_RESIDENCY_COUNT]; |
| for (int j = 0; j < stateResidencyResultList[i].stateResidencyData.length; j++) { |
| stateResidencyResultList[i].stateResidencyData[j] = new StateResidency(); |
| stateResidencyResultList[i].stateResidencyData[j].id = j; |
| stateResidencyResultList[i].stateResidencyData[j].totalTimeInStateMs = j; |
| stateResidencyResultList[i].stateResidencyData[j].totalStateEntryCount = j; |
| stateResidencyResultList[i].stateResidencyData[j].lastEntryTimestampMs = j; |
| } |
| } |
| |
| return stateResidencyResultList; |
| } |
| |
| @Override |
| public EnergyConsumer[] getEnergyConsumerInfo() { |
| EnergyConsumer[] energyConsumerList = new EnergyConsumer[ENERGY_CONSUMER_COUNT]; |
| for (int i = 0; i < energyConsumerList.length; i++) { |
| energyConsumerList[i] = new EnergyConsumer(); |
| energyConsumerList[i].id = i; |
| energyConsumerList[i].ordinal = i; |
| energyConsumerList[i].type = (byte) i; |
| energyConsumerList[i].name = new String(ENERGY_CONSUMER_NAME + i); |
| } |
| return energyConsumerList; |
| } |
| |
| @Override |
| public EnergyConsumerResult[] getEnergyConsumed(int[] energyConsumerIds) { |
| EnergyConsumerResult[] energyConsumedList = |
| new EnergyConsumerResult[ENERGY_CONSUMER_COUNT]; |
| for (int i = 0; i < energyConsumedList.length; i++) { |
| energyConsumedList[i] = new EnergyConsumerResult(); |
| energyConsumedList[i].id = i; |
| energyConsumedList[i].timestampMs = i; |
| energyConsumedList[i].energyUWs = i; |
| energyConsumedList[i].attribution = |
| new EnergyConsumerAttribution[ENERGY_CONSUMER_ATTRIBUTION_COUNT]; |
| for (int j = 0; j < energyConsumedList[i].attribution.length; j++) { |
| energyConsumedList[i].attribution[j] = new EnergyConsumerAttribution(); |
| energyConsumedList[i].attribution[j].uid = j; |
| energyConsumedList[i].attribution[j].energyUWs = j; |
| } |
| } |
| return energyConsumedList; |
| } |
| |
| @Override |
| public Channel[] getEnergyMeterInfo() { |
| Channel[] energyMeterList = new Channel[ENERGY_METER_COUNT]; |
| for (int i = 0; i < energyMeterList.length; i++) { |
| energyMeterList[i] = new Channel(); |
| energyMeterList[i].id = i; |
| energyMeterList[i].name = new String(CHANNEL_NAME + i); |
| energyMeterList[i].subsystem = new String(CHANNEL_SUBSYSTEM + i); |
| } |
| return energyMeterList; |
| } |
| |
| @Override |
| public EnergyMeasurement[] readEnergyMeter(int[] channelIds) { |
| EnergyMeasurement[] energyMeasurementList = new EnergyMeasurement[ENERGY_METER_COUNT]; |
| for (int i = 0; i < energyMeasurementList.length; i++) { |
| energyMeasurementList[i] = new EnergyMeasurement(); |
| energyMeasurementList[i].id = i; |
| energyMeasurementList[i].timestampMs = i; |
| energyMeasurementList[i].durationMs = i; |
| energyMeasurementList[i].energyUWs = i; |
| } |
| return energyMeasurementList; |
| } |
| |
| @Override |
| public boolean isInitialized() { |
| return true; |
| } |
| } |
| |
| @Before |
| public void setUp() { |
| mService = new PowerStatsService(mContext, mInjector); |
| } |
| |
| @Test |
| public void testWrittenMeterDataMatchesReadIncidentReportData() |
| throws InterruptedException, IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Write data to on-device storage. |
| mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY); |
| |
| // The above call puts a message on a handler. Wait for |
| // it to be processed. |
| Thread.sleep(100); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream fos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeMeterDataToFile(fos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceMeterProto object. |
| PowerStatsServiceMeterProto pssProto = PowerStatsServiceMeterProto.parseFrom(fileContent); |
| |
| // Validate the channel array matches what was written to on-device storage. |
| assertTrue(pssProto.channel.length == ENERGY_METER_COUNT); |
| for (int i = 0; i < pssProto.channel.length; i++) { |
| assertTrue(pssProto.channel[i].id == i); |
| assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i)); |
| assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i)); |
| } |
| |
| // Validate the energyMeasurement array matches what was written to on-device storage. |
| assertTrue(pssProto.energyMeasurement.length == ENERGY_METER_COUNT); |
| for (int i = 0; i < pssProto.energyMeasurement.length; i++) { |
| assertTrue(pssProto.energyMeasurement[i].id == i); |
| assertTrue(pssProto.energyMeasurement[i].timestampMs == |
| i + mPowerStatsLogger.getStartWallTime()); |
| assertTrue(pssProto.energyMeasurement[i].durationMs == i); |
| assertTrue(pssProto.energyMeasurement[i].energyUws == i); |
| } |
| } |
| |
| @Test |
| public void testWrittenModelDataMatchesReadIncidentReportData() |
| throws InterruptedException, IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Write data to on-device storage. |
| mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY); |
| |
| // The above call puts a message on a handler. Wait for |
| // it to be processed. |
| Thread.sleep(100); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream fos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeModelDataToFile(fos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceModelProto object. |
| PowerStatsServiceModelProto pssProto = PowerStatsServiceModelProto.parseFrom(fileContent); |
| |
| // Validate the energyConsumer array matches what was written to on-device storage. |
| assertTrue(pssProto.energyConsumer.length == ENERGY_CONSUMER_COUNT); |
| for (int i = 0; i < pssProto.energyConsumer.length; i++) { |
| assertTrue(pssProto.energyConsumer[i].id == i); |
| } |
| |
| // Validate the energyConsumerResult array matches what was written to on-device storage. |
| assertTrue(pssProto.energyConsumerResult.length == ENERGY_CONSUMER_COUNT); |
| for (int i = 0; i < pssProto.energyConsumerResult.length; i++) { |
| assertTrue(pssProto.energyConsumerResult[i].id == i); |
| assertTrue(pssProto.energyConsumerResult[i].timestampMs == |
| i + mPowerStatsLogger.getStartWallTime()); |
| assertTrue(pssProto.energyConsumerResult[i].energyUws == i); |
| assertTrue(pssProto.energyConsumerResult[i].attribution.length |
| == ENERGY_CONSUMER_ATTRIBUTION_COUNT); |
| for (int j = 0; j < pssProto.energyConsumerResult[i].attribution.length; j++) { |
| assertTrue(pssProto.energyConsumerResult[i].attribution[j].uid == j); |
| assertTrue(pssProto.energyConsumerResult[i].attribution[j].energyUws == j); |
| } |
| } |
| } |
| |
| @Test |
| public void testWrittenResidencyDataMatchesReadIncidentReportData() |
| throws InterruptedException, IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Write data to on-device storage. |
| mBatteryTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP); |
| |
| // The above call puts a message on a handler. Wait for |
| // it to be processed. |
| Thread.sleep(100); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream fos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeResidencyDataToFile(fos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceResidencyProto object. |
| PowerStatsServiceResidencyProto pssProto = |
| PowerStatsServiceResidencyProto.parseFrom(fileContent); |
| |
| // Validate the powerEntity array matches what was written to on-device storage. |
| assertTrue(pssProto.powerEntity.length == POWER_ENTITY_COUNT); |
| for (int i = 0; i < pssProto.powerEntity.length; i++) { |
| PowerEntityProto powerEntity = pssProto.powerEntity[i]; |
| assertTrue(powerEntity.id == i); |
| assertTrue(powerEntity.name.equals(POWER_ENTITY_NAME + i)); |
| for (int j = 0; j < powerEntity.states.length; j++) { |
| StateProto state = powerEntity.states[j]; |
| assertTrue(state.id == j); |
| assertTrue(state.name.equals(STATE_NAME + j)); |
| } |
| } |
| |
| // Validate the stateResidencyResult array matches what was written to on-device storage. |
| assertTrue(pssProto.stateResidencyResult.length == POWER_ENTITY_COUNT); |
| for (int i = 0; i < pssProto.stateResidencyResult.length; i++) { |
| StateResidencyResultProto stateResidencyResult = pssProto.stateResidencyResult[i]; |
| assertTrue(stateResidencyResult.id == i); |
| assertTrue(stateResidencyResult.stateResidencyData.length == STATE_RESIDENCY_COUNT); |
| for (int j = 0; j < stateResidencyResult.stateResidencyData.length; j++) { |
| StateResidencyProto stateResidency = stateResidencyResult.stateResidencyData[j]; |
| assertTrue(stateResidency.id == j); |
| assertTrue(stateResidency.totalTimeInStateMs == j); |
| assertTrue(stateResidency.totalStateEntryCount == j); |
| assertTrue(stateResidency.lastEntryTimestampMs == |
| j + mPowerStatsLogger.getStartWallTime()); |
| } |
| } |
| } |
| |
| @Test |
| public void testCorruptOnDeviceMeterStorage() throws IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Generate random array of bytes to emulate corrupt data. |
| Random rd = new Random(); |
| byte[] bytes = new byte[100]; |
| rd.nextBytes(bytes); |
| |
| // Store corrupt data in on-device storage. Add fake timestamp to filename |
| // to match format expected by FileRotator. |
| File onDeviceStorageFile = new File(mDataStorageDir, METER_FILENAME + ".1234-2234"); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream incidentReportFos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeMeterDataToFile(incidentReportFos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceMeterProto object. |
| PowerStatsServiceMeterProto pssProto = PowerStatsServiceMeterProto.parseFrom(fileContent); |
| |
| // Valid channel data is written to the incident report in the call to |
| // mPowerStatsLogger.writeMeterDataToFile(). |
| assertTrue(pssProto.channel.length == ENERGY_METER_COUNT); |
| for (int i = 0; i < pssProto.channel.length; i++) { |
| assertTrue(pssProto.channel[i].id == i); |
| assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i)); |
| assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i)); |
| } |
| |
| // No energyMeasurements should be written to the incident report since it |
| // is all corrupt (random bytes generated above). |
| assertTrue(pssProto.energyMeasurement.length == 0); |
| } |
| |
| @Test |
| public void testCorruptOnDeviceModelStorage() throws IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Generate random array of bytes to emulate corrupt data. |
| Random rd = new Random(); |
| byte[] bytes = new byte[100]; |
| rd.nextBytes(bytes); |
| |
| // Store corrupt data in on-device storage. Add fake timestamp to filename |
| // to match format expected by FileRotator. |
| File onDeviceStorageFile = new File(mDataStorageDir, MODEL_FILENAME + ".1234-2234"); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream incidentReportFos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeModelDataToFile(incidentReportFos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceModelProto object. |
| PowerStatsServiceModelProto pssProto = PowerStatsServiceModelProto.parseFrom(fileContent); |
| |
| // Valid energyConsumer data is written to the incident report in the call to |
| // mPowerStatsLogger.writeModelDataToFile(). |
| assertTrue(pssProto.energyConsumer.length == ENERGY_CONSUMER_COUNT); |
| for (int i = 0; i < pssProto.energyConsumer.length; i++) { |
| assertTrue(pssProto.energyConsumer[i].id == i); |
| } |
| |
| // No energyConsumerResults should be written to the incident report since it |
| // is all corrupt (random bytes generated above). |
| assertTrue(pssProto.energyConsumerResult.length == 0); |
| } |
| |
| @Test |
| public void testCorruptOnDeviceResidencyStorage() throws IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Generate random array of bytes to emulate corrupt data. |
| Random rd = new Random(); |
| byte[] bytes = new byte[100]; |
| rd.nextBytes(bytes); |
| |
| // Store corrupt data in on-device storage. Add fake timestamp to filename |
| // to match format expected by FileRotator. |
| File onDeviceStorageFile = new File(mDataStorageDir, RESIDENCY_FILENAME + ".1234-2234"); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream incidentReportFos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeResidencyDataToFile(incidentReportFos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceResidencyProto object. |
| PowerStatsServiceResidencyProto pssProto = |
| PowerStatsServiceResidencyProto.parseFrom(fileContent); |
| |
| // Valid powerEntity data is written to the incident report in the call to |
| // mPowerStatsLogger.writeResidencyDataToFile(). |
| assertTrue(pssProto.powerEntity.length == POWER_ENTITY_COUNT); |
| for (int i = 0; i < pssProto.powerEntity.length; i++) { |
| PowerEntityProto powerEntity = pssProto.powerEntity[i]; |
| assertTrue(powerEntity.id == i); |
| assertTrue(powerEntity.name.equals(POWER_ENTITY_NAME + i)); |
| for (int j = 0; j < powerEntity.states.length; j++) { |
| StateProto state = powerEntity.states[j]; |
| assertTrue(state.id == j); |
| assertTrue(state.name.equals(STATE_NAME + j)); |
| } |
| } |
| |
| // No stateResidencyResults should be written to the incident report since it |
| // is all corrupt (random bytes generated above). |
| assertTrue(pssProto.stateResidencyResult.length == 0); |
| } |
| |
| @Test |
| public void testNotEnoughBytesAfterMeterLengthField() throws IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Create corrupt data. |
| // Length field is correct, but there is no data following the length. |
| ByteArrayOutputStream data = new ByteArrayOutputStream(); |
| data.write(ByteBuffer.allocate(4).putInt(50).array()); |
| byte[] test = data.toByteArray(); |
| |
| // Store corrupt data in on-device storage. Add fake timestamp to filename |
| // to match format expected by FileRotator. |
| File onDeviceStorageFile = new File(mDataStorageDir, METER_FILENAME + ".1234-2234"); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(data.toByteArray()); |
| onDeviceStorageFos.close(); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream incidentReportFos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeMeterDataToFile(incidentReportFos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceMeterProto object. |
| PowerStatsServiceMeterProto pssProto = PowerStatsServiceMeterProto.parseFrom(fileContent); |
| |
| // Valid channel data is written to the incident report in the call to |
| // mPowerStatsLogger.writeMeterDataToFile(). |
| assertTrue(pssProto.channel.length == ENERGY_METER_COUNT); |
| for (int i = 0; i < pssProto.channel.length; i++) { |
| assertTrue(pssProto.channel[i].id == i); |
| assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i)); |
| assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i)); |
| } |
| |
| // No energyMeasurements should be written to the incident report since the |
| // input buffer had only length and no data. |
| assertTrue(pssProto.energyMeasurement.length == 0); |
| } |
| |
| @Test |
| public void testNotEnoughBytesAfterModelLengthField() throws IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Create corrupt data. |
| // Length field is correct, but there is no data following the length. |
| ByteArrayOutputStream data = new ByteArrayOutputStream(); |
| data.write(ByteBuffer.allocate(4).putInt(50).array()); |
| byte[] test = data.toByteArray(); |
| |
| // Store corrupt data in on-device storage. Add fake timestamp to filename |
| // to match format expected by FileRotator. |
| File onDeviceStorageFile = new File(mDataStorageDir, MODEL_FILENAME + ".1234-2234"); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(data.toByteArray()); |
| onDeviceStorageFos.close(); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream incidentReportFos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeModelDataToFile(incidentReportFos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceModelProto object. |
| PowerStatsServiceModelProto pssProto = PowerStatsServiceModelProto.parseFrom(fileContent); |
| |
| // Valid energyConsumer data is written to the incident report in the call to |
| // mPowerStatsLogger.writeModelDataToFile(). |
| assertTrue(pssProto.energyConsumer.length == ENERGY_CONSUMER_COUNT); |
| for (int i = 0; i < pssProto.energyConsumer.length; i++) { |
| assertTrue(pssProto.energyConsumer[i].id == i); |
| } |
| |
| // No energyConsumerResults should be written to the incident report since the |
| // input buffer had only length and no data. |
| assertTrue(pssProto.energyConsumerResult.length == 0); |
| } |
| |
| @Test |
| public void testNotEnoughBytesAfterResidencyLengthField() throws IOException { |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Create corrupt data. |
| // Length field is correct, but there is no data following the length. |
| ByteArrayOutputStream data = new ByteArrayOutputStream(); |
| data.write(ByteBuffer.allocate(4).putInt(50).array()); |
| byte[] test = data.toByteArray(); |
| |
| // Store corrupt data in on-device storage. Add fake timestamp to filename |
| // to match format expected by FileRotator. |
| File onDeviceStorageFile = new File(mDataStorageDir, RESIDENCY_FILENAME + ".1234-2234"); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(data.toByteArray()); |
| onDeviceStorageFos.close(); |
| |
| // Write on-device storage to an incident report. |
| File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME); |
| FileOutputStream incidentReportFos = new FileOutputStream(incidentReport); |
| mPowerStatsLogger.writeResidencyDataToFile(incidentReportFos.getFD()); |
| |
| // Read the incident report in to a byte array. |
| FileInputStream fis = new FileInputStream(incidentReport); |
| byte[] fileContent = new byte[(int) incidentReport.length()]; |
| fis.read(fileContent); |
| |
| // Parse the incident data into a PowerStatsServiceResidencyProto object. |
| PowerStatsServiceResidencyProto pssProto = |
| PowerStatsServiceResidencyProto.parseFrom(fileContent); |
| |
| // Valid powerEntity data is written to the incident report in the call to |
| // mPowerStatsLogger.writeResidencyDataToFile(). |
| assertTrue(pssProto.powerEntity.length == POWER_ENTITY_COUNT); |
| for (int i = 0; i < pssProto.powerEntity.length; i++) { |
| PowerEntityProto powerEntity = pssProto.powerEntity[i]; |
| assertTrue(powerEntity.id == i); |
| assertTrue(powerEntity.name.equals(POWER_ENTITY_NAME + i)); |
| for (int j = 0; j < powerEntity.states.length; j++) { |
| StateProto state = powerEntity.states[j]; |
| assertTrue(state.id == j); |
| assertTrue(state.name.equals(STATE_NAME + j)); |
| } |
| } |
| |
| // No stateResidencyResults should be written to the incident report since the |
| // input buffer had only length and no data. |
| assertTrue(pssProto.stateResidencyResult.length == 0); |
| } |
| |
| @Test |
| public void testDataStorageDeletedMeterMismatch() throws IOException { |
| // Create the directory where cached data will be stored. |
| mInjector.createDataStoragePath(); |
| |
| // In order to create cached data that will match the current data read by the |
| // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is |
| // returned from the Injector. |
| IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl(); |
| |
| // Generate random array of bytes to emulate cached meter data. Store to file. |
| Random rd = new Random(); |
| byte[] bytes = new byte[100]; |
| rd.nextBytes(bytes); |
| File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename()); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create cached energy consumer data and write to file. |
| EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo(); |
| bytes = EnergyConsumerUtils.getProtoBytes(energyConsumers); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create cached power entity info data and write to file. |
| PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo(); |
| bytes = PowerEntityUtils.getProtoBytes(powerEntityInfo); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create log files. |
| File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename()); |
| File modelFile = new File(mDataStorageDir, mInjector.createModelFilename()); |
| File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename()); |
| meterFile.createNewFile(); |
| modelFile.createNewFile(); |
| residencyFile.createNewFile(); |
| |
| // Verify log files exist. |
| assertTrue(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| |
| // Boot device after creating old cached data. |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Since cached meter data is just random bytes it won't match the data read from the HAL. |
| // This mismatch of cached and current HAL data should force a delete. |
| assertTrue(mService.getDeleteMeterDataOnBoot()); |
| assertFalse(mService.getDeleteModelDataOnBoot()); |
| assertFalse(mService.getDeleteResidencyDataOnBoot()); |
| |
| // Verify log files were deleted. |
| assertFalse(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| |
| // Verify cached meter data was updated to new HAL output. |
| Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo(); |
| byte[] bytesExpected = ChannelUtils.getProtoBytes(channels); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename()); |
| byte[] bytesActual = new byte[(int) onDeviceStorageFile.length()]; |
| FileInputStream onDeviceStorageFis = new FileInputStream(onDeviceStorageFile); |
| onDeviceStorageFis.read(bytesActual); |
| assertTrue(Arrays.equals(bytesExpected, bytesActual)); |
| } |
| |
| @Test |
| public void testDataStorageDeletedModelMismatch() throws IOException { |
| // Create the directory where cached data will be stored. |
| mInjector.createDataStoragePath(); |
| |
| // In order to create cached data that will match the current data read by the |
| // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is |
| // returned from the Injector. |
| IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl(); |
| |
| // Create cached channel data and write to file. |
| Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo(); |
| byte[] bytes = ChannelUtils.getProtoBytes(channels); |
| File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename()); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Generate random array of bytes to emulate cached energy consumer data. Store to file. |
| Random rd = new Random(); |
| bytes = new byte[100]; |
| rd.nextBytes(bytes); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create cached power entity info data and write to file. |
| PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo(); |
| bytes = PowerEntityUtils.getProtoBytes(powerEntityInfo); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create log files. |
| File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename()); |
| File modelFile = new File(mDataStorageDir, mInjector.createModelFilename()); |
| File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename()); |
| meterFile.createNewFile(); |
| modelFile.createNewFile(); |
| residencyFile.createNewFile(); |
| |
| // Verify log files exist. |
| assertTrue(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| |
| // Boot device after creating old cached data. |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Since cached energy consumer data is just random bytes it won't match the data read from |
| // the HAL. This mismatch of cached and current HAL data should force a delete. |
| assertFalse(mService.getDeleteMeterDataOnBoot()); |
| assertTrue(mService.getDeleteModelDataOnBoot()); |
| assertFalse(mService.getDeleteResidencyDataOnBoot()); |
| |
| // Verify log files were deleted. |
| assertTrue(meterFile.exists()); |
| assertFalse(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| |
| // Verify cached energy consumer data was updated to new HAL output. |
| EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo(); |
| byte[] bytesExpected = EnergyConsumerUtils.getProtoBytes(energyConsumers); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename()); |
| byte[] bytesActual = new byte[(int) onDeviceStorageFile.length()]; |
| FileInputStream onDeviceStorageFis = new FileInputStream(onDeviceStorageFile); |
| onDeviceStorageFis.read(bytesActual); |
| assertTrue(Arrays.equals(bytesExpected, bytesActual)); |
| } |
| |
| @Test |
| public void testDataStorageDeletedResidencyMismatch() throws IOException { |
| // Create the directory where cached data will be stored. |
| mInjector.createDataStoragePath(); |
| |
| // In order to create cached data that will match the current data read by the |
| // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is |
| // returned from the Injector. |
| IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl(); |
| |
| // Create cached channel data and write to file. |
| Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo(); |
| byte[] bytes = ChannelUtils.getProtoBytes(channels); |
| File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename()); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create cached energy consumer data and write to file. |
| EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo(); |
| bytes = EnergyConsumerUtils.getProtoBytes(energyConsumers); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Generate random array of bytes to emulate cached power entity info data. Store to file. |
| Random rd = new Random(); |
| bytes = new byte[100]; |
| rd.nextBytes(bytes); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create log files. |
| File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename()); |
| File modelFile = new File(mDataStorageDir, mInjector.createModelFilename()); |
| File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename()); |
| meterFile.createNewFile(); |
| modelFile.createNewFile(); |
| residencyFile.createNewFile(); |
| |
| // Verify log files exist. |
| assertTrue(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| |
| // Boot device after creating old cached data. |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Since cached power entity info data is just random bytes it won't match the data read |
| // from the HAL. This mismatch of cached and current HAL data should force a delete. |
| assertFalse(mService.getDeleteMeterDataOnBoot()); |
| assertFalse(mService.getDeleteModelDataOnBoot()); |
| assertTrue(mService.getDeleteResidencyDataOnBoot()); |
| |
| // Verify log files were deleted. |
| assertTrue(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertFalse(residencyFile.exists()); |
| |
| // Verify cached power entity data was updated to new HAL output. |
| PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo(); |
| byte[] bytesExpected = PowerEntityUtils.getProtoBytes(powerEntityInfo); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename()); |
| byte[] bytesActual = new byte[(int) onDeviceStorageFile.length()]; |
| FileInputStream onDeviceStorageFis = new FileInputStream(onDeviceStorageFile); |
| onDeviceStorageFis.read(bytesActual); |
| assertTrue(Arrays.equals(bytesExpected, bytesActual)); |
| } |
| |
| @Test |
| public void testDataStorageNotDeletedNoCachedData() throws IOException { |
| // Create the directory where log files will be stored. |
| mInjector.createDataStoragePath(); |
| |
| // Create log files. |
| File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename()); |
| File modelFile = new File(mDataStorageDir, mInjector.createModelFilename()); |
| File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename()); |
| meterFile.createNewFile(); |
| modelFile.createNewFile(); |
| residencyFile.createNewFile(); |
| |
| // Verify log files exist. |
| assertTrue(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| |
| // This test mimics the device's first boot where there is no cached data. |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // Since there is no cached data on the first boot any log files that happen to exist |
| // should be deleted. |
| assertTrue(mService.getDeleteMeterDataOnBoot()); |
| assertTrue(mService.getDeleteModelDataOnBoot()); |
| assertTrue(mService.getDeleteResidencyDataOnBoot()); |
| |
| // Verify log files were deleted. |
| assertFalse(meterFile.exists()); |
| assertFalse(modelFile.exists()); |
| assertFalse(residencyFile.exists()); |
| } |
| |
| @Test |
| public void testDataStorageNotDeletedAllDataMatches() throws IOException { |
| // Create the directory where cached data will be stored. |
| mInjector.createDataStoragePath(); |
| |
| // In order to create cached data that will match the current data read by the |
| // PowerStatsService we need to write valid data from the TestPowerStatsHALWrapper that is |
| // returned from the Injector. |
| IPowerStatsHALWrapper powerStatsHALWrapper = mInjector.getPowerStatsHALWrapperImpl(); |
| |
| // Create cached channel data and write to file. |
| Channel[] channels = powerStatsHALWrapper.getEnergyMeterInfo(); |
| byte[] bytes = ChannelUtils.getProtoBytes(channels); |
| File onDeviceStorageFile = new File(mDataStorageDir, mInjector.createMeterCacheFilename()); |
| FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create cached energy consumer data and write to file. |
| EnergyConsumer[] energyConsumers = powerStatsHALWrapper.getEnergyConsumerInfo(); |
| bytes = EnergyConsumerUtils.getProtoBytes(energyConsumers); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createModelCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create cached power entity info data and write to file. |
| PowerEntity[] powerEntityInfo = powerStatsHALWrapper.getPowerEntityInfo(); |
| bytes = PowerEntityUtils.getProtoBytes(powerEntityInfo); |
| onDeviceStorageFile = new File(mDataStorageDir, mInjector.createResidencyCacheFilename()); |
| onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile); |
| onDeviceStorageFos.write(bytes); |
| onDeviceStorageFos.close(); |
| |
| // Create log files. |
| File meterFile = new File(mDataStorageDir, mInjector.createMeterFilename()); |
| File modelFile = new File(mDataStorageDir, mInjector.createModelFilename()); |
| File residencyFile = new File(mDataStorageDir, mInjector.createResidencyFilename()); |
| meterFile.createNewFile(); |
| modelFile.createNewFile(); |
| residencyFile.createNewFile(); |
| |
| // Verify log files exist. |
| assertTrue(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| |
| // Boot device after creating old cached data. |
| mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| |
| // All cached data created above should match current data read in PowerStatsService so we |
| // expect the data not to be deleted. |
| assertFalse(mService.getDeleteMeterDataOnBoot()); |
| assertFalse(mService.getDeleteModelDataOnBoot()); |
| assertFalse(mService.getDeleteResidencyDataOnBoot()); |
| |
| // Verify log files were not deleted. |
| assertTrue(meterFile.exists()); |
| assertTrue(modelFile.exists()); |
| assertTrue(residencyFile.exists()); |
| } |
| } |