Loading services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java +29 −10 Original line number Diff line number Diff line Loading @@ -47,7 +47,8 @@ public class PowerStatsDataStorage { private static final long DELETE_AGE_MILLIS = 48 * MILLISECONDS_PER_HOUR; private final ReentrantLock mLock = new ReentrantLock(); private File mDataStorageDir; private final File mDataStorageDir; private final String mDataStorageFilename; private final FileRotator mFileRotator; private static class DataElement { Loading Loading @@ -168,6 +169,7 @@ public class PowerStatsDataStorage { public PowerStatsDataStorage(Context context, File dataStoragePath, String dataStorageFilename) { mDataStorageDir = dataStoragePath; mDataStorageFilename = dataStorageFilename; if (!mDataStorageDir.exists() && !mDataStorageDir.mkdirs()) { Slog.wtf(TAG, "mDataStorageDir does not exist: " + mDataStorageDir.getPath()); Loading @@ -177,33 +179,35 @@ public class PowerStatsDataStorage { // filename, so any files that don't match the current version number can be deleted. File[] files = mDataStorageDir.listFiles(); for (int i = 0; i < files.length; i++) { // Meter and model files are stored in the same directory. // Meter, model, and residency files are stored in the same directory. // // The format of filenames on disk is: // log.powerstats.meter.version.timestamp // log.powerstats.model.version.timestamp // log.powerstats.residency.version.timestamp // // The format of dataStorageFilenames is: // log.powerstats.meter.version // log.powerstats.model.version // log.powerstats.residency.version // // A PowerStatsDataStorage object is created for meter and model data. Strip off // the version and check that the current file we're checking starts with the stem // (log.powerstats.meter or log.powerstats.model). If the stem matches and the // version number is different, delete the old file. int versionDot = dataStorageFilename.lastIndexOf('.'); String beforeVersionDot = dataStorageFilename.substring(0, versionDot); // A PowerStatsDataStorage object is created for meter, model, and residency data. // Strip off the version and check that the current file we're checking starts with // the stem (log.powerstats.meter, log.powerstats.model, log.powerstats.residency). // If the stem matches and the version number is different, delete the old file. int versionDot = mDataStorageFilename.lastIndexOf('.'); String beforeVersionDot = mDataStorageFilename.substring(0, versionDot); // Check that the stems match. if (files[i].getName().startsWith(beforeVersionDot)) { // Check that the version number matches. If not, delete the old file. if (!files[i].getName().startsWith(dataStorageFilename)) { if (!files[i].getName().startsWith(mDataStorageFilename)) { files[i].delete(); } } } mFileRotator = new FileRotator(mDataStorageDir, dataStorageFilename, mDataStorageFilename, ROTATE_AGE_MILLIS, DELETE_AGE_MILLIS); } Loading Loading @@ -242,4 +246,19 @@ public class PowerStatsDataStorage { public void read(DataElementReadCallback callback) throws IOException { mFileRotator.readMatching(new DataReader(callback), Long.MIN_VALUE, Long.MAX_VALUE); } /** * Deletes all stored log data. */ public void deleteLogs() { File[] files = mDataStorageDir.listFiles(); for (int i = 0; i < files.length; i++) { int versionDot = mDataStorageFilename.lastIndexOf('.'); String beforeVersionDot = mDataStorageFilename.substring(0, versionDot); // Check that the stems before the version match. if (files[i].getName().startsWith(beforeVersionDot)) { files[i].delete(); } } } } services/core/java/com/android/server/powerstats/PowerStatsLogger.java +101 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.hardware.power.stats.StateResidencyResult; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.AtomicFile; import android.util.Slog; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; Loading @@ -41,14 +42,17 @@ import com.android.server.powerstats.ProtoStreamUtils.StateResidencyResultUtils; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; /** * PowerStatsLogger is responsible for logging model and meter energy data to on-device storage. * Messages are sent to its message handler to request that energy data be logged, at which time it * queries the PowerStats HAL and logs the data to on-device storage. The on-device storage is * dumped to file by calling writeModelDataToFile, writeMeterDataToFile, or writeResidencyDataToFile * with a file descriptor that points to the output file. * PowerStatsLogger is responsible for logging model, meter, and residency data to on-device * storage. Messages are sent to its message handler to request that energy data be logged, at * which time it queries the PowerStats HAL and logs the data to on-device storage. The on-device * storage is dumped to file by calling writeModelDataToFile, writeMeterDataToFile, or * writeResidencyDataToFile with a file descriptor that points to the output file. */ public final class PowerStatsLogger extends Handler { private static final String TAG = PowerStatsLogger.class.getSimpleName(); Loading @@ -61,6 +65,10 @@ public final class PowerStatsLogger extends Handler { private final PowerStatsDataStorage mPowerStatsModelStorage; private final PowerStatsDataStorage mPowerStatsResidencyStorage; private final IPowerStatsHALWrapper mPowerStatsHALWrapper; private File mDataStoragePath; private boolean mDeleteMeterDataOnBoot; private boolean mDeleteModelDataOnBoot; private boolean mDeleteResidencyDataOnBoot; @Override public void handleMessage(Message msg) { Loading Loading @@ -230,16 +238,99 @@ public final class PowerStatsLogger extends Handler { pos.flush(); } public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, String residencyFilename, private boolean dataChanged(String cachedFilename, byte[] dataCurrent) { boolean dataChanged = false; if (mDataStoragePath.exists() || mDataStoragePath.mkdirs()) { final File cachedFile = new File(mDataStoragePath, cachedFilename); if (cachedFile.exists()) { // Get the byte array for the cached data. final byte[] dataCached = new byte[(int) cachedFile.length()]; // Get the cached data from file. try { final FileInputStream fis = new FileInputStream(cachedFile.getPath()); fis.read(dataCached); } catch (IOException e) { Slog.e(TAG, "Failed to read cached data from file"); } // If the cached and current data are different, delete the data store. dataChanged = !Arrays.equals(dataCached, dataCurrent); } else { // Either the cached file was somehow deleted, or this is the first // boot of the device and we're creating the file for the first time. // In either case, delete the log files. dataChanged = true; } } return dataChanged; } private void updateCacheFile(String cacheFilename, byte[] data) { try { final AtomicFile atomicCachedFile = new AtomicFile(new File(mDataStoragePath, cacheFilename)); final FileOutputStream fos = atomicCachedFile.startWrite(); fos.write(data); atomicCachedFile.finishWrite(fos); } catch (IOException e) { Slog.e(TAG, "Failed to write current data to cached file"); } } public boolean getDeleteMeterDataOnBoot() { return mDeleteMeterDataOnBoot; } public boolean getDeleteModelDataOnBoot() { return mDeleteModelDataOnBoot; } public boolean getDeleteResidencyDataOnBoot() { return mDeleteResidencyDataOnBoot; } public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String meterCacheFilename, String modelFilename, String modelCacheFilename, String residencyFilename, String residencyCacheFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { super(Looper.getMainLooper()); mPowerStatsHALWrapper = powerStatsHALWrapper; mPowerStatsMeterStorage = new PowerStatsDataStorage(context, dataStoragePath, mDataStoragePath = dataStoragePath; mPowerStatsMeterStorage = new PowerStatsDataStorage(context, mDataStoragePath, meterFilename); mPowerStatsModelStorage = new PowerStatsDataStorage(context, dataStoragePath, mPowerStatsModelStorage = new PowerStatsDataStorage(context, mDataStoragePath, modelFilename); mPowerStatsResidencyStorage = new PowerStatsDataStorage(context, dataStoragePath, mPowerStatsResidencyStorage = new PowerStatsDataStorage(context, mDataStoragePath, residencyFilename); final Channel[] channels = mPowerStatsHALWrapper.getEnergyMeterInfo(); final byte[] channelBytes = ChannelUtils.getProtoBytes(channels); mDeleteMeterDataOnBoot = dataChanged(meterCacheFilename, channelBytes); if (mDeleteMeterDataOnBoot) { mPowerStatsMeterStorage.deleteLogs(); updateCacheFile(meterCacheFilename, channelBytes); } final EnergyConsumer[] energyConsumers = mPowerStatsHALWrapper.getEnergyConsumerInfo(); final byte[] energyConsumerBytes = EnergyConsumerUtils.getProtoBytes(energyConsumers); mDeleteModelDataOnBoot = dataChanged(modelCacheFilename, energyConsumerBytes); if (mDeleteModelDataOnBoot) { mPowerStatsModelStorage.deleteLogs(); updateCacheFile(modelCacheFilename, energyConsumerBytes); } final PowerEntity[] powerEntities = mPowerStatsHALWrapper.getPowerEntityInfo(); final byte[] powerEntityBytes = PowerEntityUtils.getProtoBytes(powerEntities); mDeleteResidencyDataOnBoot = dataChanged(residencyCacheFilename, powerEntityBytes); if (mDeleteResidencyDataOnBoot) { mPowerStatsResidencyStorage.deleteLogs(); updateCacheFile(residencyCacheFilename, powerEntityBytes); } } } services/core/java/com/android/server/powerstats/PowerStatsService.java +44 −6 Original line number Diff line number Diff line Loading @@ -61,8 +61,12 @@ public class PowerStatsService extends SystemService { private static final String MODEL_FILENAME = "log.powerstats.model." + DATA_STORAGE_VERSION; private static final String RESIDENCY_FILENAME = "log.powerstats.residency." + DATA_STORAGE_VERSION; private static final String METER_CACHE_FILENAME = "meterCache"; private static final String MODEL_CACHE_FILENAME = "modelCache"; private static final String RESIDENCY_CACHE_FILENAME = "residencyCache"; private final Injector mInjector; private File mDataStoragePath; private Context mContext; @Nullable Loading Loading @@ -98,6 +102,18 @@ public class PowerStatsService extends SystemService { return RESIDENCY_FILENAME; } String createMeterCacheFilename() { return METER_CACHE_FILENAME; } String createModelCacheFilename() { return MODEL_CACHE_FILENAME; } String createResidencyCacheFilename() { return RESIDENCY_CACHE_FILENAME; } IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() { return PowerStatsHALWrapper.getPowerStatsHalImpl(); } Loading @@ -112,10 +128,15 @@ public class PowerStatsService extends SystemService { } PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, String residencyFilename, String meterFilename, String meterCacheFilename, String modelFilename, String modelCacheFilename, String residencyFilename, String residencyCacheFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { return new PowerStatsLogger(context, dataStoragePath, meterFilename, modelFilename, residencyFilename, powerStatsHALWrapper); return new PowerStatsLogger(context, dataStoragePath, meterFilename, meterCacheFilename, modelFilename, modelCacheFilename, residencyFilename, residencyCacheFilename, powerStatsHALWrapper); } BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) { Loading Loading @@ -187,14 +208,31 @@ public class PowerStatsService extends SystemService { mPullAtomCallback = mInjector.createStatsPullerImpl(mContext, mPowerStatsInternal); } @VisibleForTesting public boolean getDeleteMeterDataOnBoot() { return mPowerStatsLogger.getDeleteMeterDataOnBoot(); } @VisibleForTesting public boolean getDeleteModelDataOnBoot() { return mPowerStatsLogger.getDeleteModelDataOnBoot(); } @VisibleForTesting public boolean getDeleteResidencyDataOnBoot() { return mPowerStatsLogger.getDeleteResidencyDataOnBoot(); } private void onBootCompleted() { if (getPowerStatsHal().isInitialized()) { if (DEBUG) Slog.d(TAG, "Starting PowerStatsService loggers"); mDataStoragePath = mInjector.createDataStoragePath(); // Only start logger and triggers if initialization is successful. mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mInjector.createDataStoragePath(), mInjector.createMeterFilename(), mInjector.createModelFilename(), mInjector.createResidencyFilename(), mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mDataStoragePath, mInjector.createMeterFilename(), mInjector.createMeterCacheFilename(), mInjector.createModelFilename(), mInjector.createModelCacheFilename(), mInjector.createResidencyFilename(), mInjector.createResidencyCacheFilename(), getPowerStatsHal()); mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger); mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger); Loading services/core/java/com/android/server/powerstats/ProtoStreamUtils.java +84 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,12 @@ public class ProtoStreamUtils { private static final String TAG = ProtoStreamUtils.class.getSimpleName(); static class PowerEntityUtils { public static byte[] getProtoBytes(PowerEntity[] powerEntity) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(powerEntity, pos); return pos.getBytes(); } public static void packProtoMessage(PowerEntity[] powerEntity, ProtoOutputStream pos) { if (powerEntity == null) return; Loading Loading @@ -260,6 +266,12 @@ public class ProtoStreamUtils { } static class ChannelUtils { public static byte[] getProtoBytes(Channel[] channel) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(channel, pos); return pos.getBytes(); } public static void packProtoMessage(Channel[] channel, ProtoOutputStream pos) { if (channel == null) return; Loading Loading @@ -396,6 +408,12 @@ public class ProtoStreamUtils { } static class EnergyConsumerUtils { public static byte[] getProtoBytes(EnergyConsumer[] energyConsumer) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(energyConsumer, pos); return pos.getBytes(); } public static void packProtoMessage(EnergyConsumer[] energyConsumer, ProtoOutputStream pos) { if (energyConsumer == null) return; Loading @@ -410,6 +428,72 @@ public class ProtoStreamUtils { } } public static EnergyConsumer[] unpackProtoMessage(byte[] data) throws IOException { final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data)); List<EnergyConsumer> energyConsumerList = new ArrayList<EnergyConsumer>(); while (true) { try { int nextField = pis.nextField(); EnergyConsumer energyConsumer = new EnergyConsumer(); if (nextField == (int) PowerStatsServiceModelProto.ENERGY_CONSUMER) { long token = pis.start(PowerStatsServiceModelProto.ENERGY_CONSUMER); energyConsumerList.add(unpackEnergyConsumerProto(pis)); pis.end(token); } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) { return energyConsumerList.toArray( new EnergyConsumer[energyConsumerList.size()]); } else { Slog.e(TAG, "Unhandled field in proto: " + ProtoUtils.currentFieldToString(pis)); } } catch (WireTypeMismatchException wtme) { Slog.e(TAG, "Wire Type mismatch in proto: " + ProtoUtils.currentFieldToString(pis)); } } } private static EnergyConsumer unpackEnergyConsumerProto(ProtoInputStream pis) throws IOException { final EnergyConsumer energyConsumer = new EnergyConsumer(); while (true) { try { switch (pis.nextField()) { case (int) EnergyConsumerProto.ID: energyConsumer.id = pis.readInt(EnergyConsumerProto.ID); break; case (int) EnergyConsumerProto.ORDINAL: energyConsumer.ordinal = pis.readInt(EnergyConsumerProto.ORDINAL); break; case (int) EnergyConsumerProto.TYPE: energyConsumer.type = (byte) pis.readInt(EnergyConsumerProto.TYPE); break; case (int) EnergyConsumerProto.NAME: energyConsumer.name = pis.readString(EnergyConsumerProto.NAME); break; case ProtoInputStream.NO_MORE_FIELDS: return energyConsumer; default: Slog.e(TAG, "Unhandled field in EnergyConsumerProto: " + ProtoUtils.currentFieldToString(pis)); break; } } catch (WireTypeMismatchException wtme) { Slog.e(TAG, "Wire Type mismatch in EnergyConsumerProto: " + ProtoUtils.currentFieldToString(pis)); } } } public static void print(EnergyConsumer[] energyConsumer) { if (energyConsumer == null) return; Loading services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java +351 −12 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java +29 −10 Original line number Diff line number Diff line Loading @@ -47,7 +47,8 @@ public class PowerStatsDataStorage { private static final long DELETE_AGE_MILLIS = 48 * MILLISECONDS_PER_HOUR; private final ReentrantLock mLock = new ReentrantLock(); private File mDataStorageDir; private final File mDataStorageDir; private final String mDataStorageFilename; private final FileRotator mFileRotator; private static class DataElement { Loading Loading @@ -168,6 +169,7 @@ public class PowerStatsDataStorage { public PowerStatsDataStorage(Context context, File dataStoragePath, String dataStorageFilename) { mDataStorageDir = dataStoragePath; mDataStorageFilename = dataStorageFilename; if (!mDataStorageDir.exists() && !mDataStorageDir.mkdirs()) { Slog.wtf(TAG, "mDataStorageDir does not exist: " + mDataStorageDir.getPath()); Loading @@ -177,33 +179,35 @@ public class PowerStatsDataStorage { // filename, so any files that don't match the current version number can be deleted. File[] files = mDataStorageDir.listFiles(); for (int i = 0; i < files.length; i++) { // Meter and model files are stored in the same directory. // Meter, model, and residency files are stored in the same directory. // // The format of filenames on disk is: // log.powerstats.meter.version.timestamp // log.powerstats.model.version.timestamp // log.powerstats.residency.version.timestamp // // The format of dataStorageFilenames is: // log.powerstats.meter.version // log.powerstats.model.version // log.powerstats.residency.version // // A PowerStatsDataStorage object is created for meter and model data. Strip off // the version and check that the current file we're checking starts with the stem // (log.powerstats.meter or log.powerstats.model). If the stem matches and the // version number is different, delete the old file. int versionDot = dataStorageFilename.lastIndexOf('.'); String beforeVersionDot = dataStorageFilename.substring(0, versionDot); // A PowerStatsDataStorage object is created for meter, model, and residency data. // Strip off the version and check that the current file we're checking starts with // the stem (log.powerstats.meter, log.powerstats.model, log.powerstats.residency). // If the stem matches and the version number is different, delete the old file. int versionDot = mDataStorageFilename.lastIndexOf('.'); String beforeVersionDot = mDataStorageFilename.substring(0, versionDot); // Check that the stems match. if (files[i].getName().startsWith(beforeVersionDot)) { // Check that the version number matches. If not, delete the old file. if (!files[i].getName().startsWith(dataStorageFilename)) { if (!files[i].getName().startsWith(mDataStorageFilename)) { files[i].delete(); } } } mFileRotator = new FileRotator(mDataStorageDir, dataStorageFilename, mDataStorageFilename, ROTATE_AGE_MILLIS, DELETE_AGE_MILLIS); } Loading Loading @@ -242,4 +246,19 @@ public class PowerStatsDataStorage { public void read(DataElementReadCallback callback) throws IOException { mFileRotator.readMatching(new DataReader(callback), Long.MIN_VALUE, Long.MAX_VALUE); } /** * Deletes all stored log data. */ public void deleteLogs() { File[] files = mDataStorageDir.listFiles(); for (int i = 0; i < files.length; i++) { int versionDot = mDataStorageFilename.lastIndexOf('.'); String beforeVersionDot = mDataStorageFilename.substring(0, versionDot); // Check that the stems before the version match. if (files[i].getName().startsWith(beforeVersionDot)) { files[i].delete(); } } } }
services/core/java/com/android/server/powerstats/PowerStatsLogger.java +101 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.hardware.power.stats.StateResidencyResult; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.AtomicFile; import android.util.Slog; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; Loading @@ -41,14 +42,17 @@ import com.android.server.powerstats.ProtoStreamUtils.StateResidencyResultUtils; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; /** * PowerStatsLogger is responsible for logging model and meter energy data to on-device storage. * Messages are sent to its message handler to request that energy data be logged, at which time it * queries the PowerStats HAL and logs the data to on-device storage. The on-device storage is * dumped to file by calling writeModelDataToFile, writeMeterDataToFile, or writeResidencyDataToFile * with a file descriptor that points to the output file. * PowerStatsLogger is responsible for logging model, meter, and residency data to on-device * storage. Messages are sent to its message handler to request that energy data be logged, at * which time it queries the PowerStats HAL and logs the data to on-device storage. The on-device * storage is dumped to file by calling writeModelDataToFile, writeMeterDataToFile, or * writeResidencyDataToFile with a file descriptor that points to the output file. */ public final class PowerStatsLogger extends Handler { private static final String TAG = PowerStatsLogger.class.getSimpleName(); Loading @@ -61,6 +65,10 @@ public final class PowerStatsLogger extends Handler { private final PowerStatsDataStorage mPowerStatsModelStorage; private final PowerStatsDataStorage mPowerStatsResidencyStorage; private final IPowerStatsHALWrapper mPowerStatsHALWrapper; private File mDataStoragePath; private boolean mDeleteMeterDataOnBoot; private boolean mDeleteModelDataOnBoot; private boolean mDeleteResidencyDataOnBoot; @Override public void handleMessage(Message msg) { Loading Loading @@ -230,16 +238,99 @@ public final class PowerStatsLogger extends Handler { pos.flush(); } public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, String residencyFilename, private boolean dataChanged(String cachedFilename, byte[] dataCurrent) { boolean dataChanged = false; if (mDataStoragePath.exists() || mDataStoragePath.mkdirs()) { final File cachedFile = new File(mDataStoragePath, cachedFilename); if (cachedFile.exists()) { // Get the byte array for the cached data. final byte[] dataCached = new byte[(int) cachedFile.length()]; // Get the cached data from file. try { final FileInputStream fis = new FileInputStream(cachedFile.getPath()); fis.read(dataCached); } catch (IOException e) { Slog.e(TAG, "Failed to read cached data from file"); } // If the cached and current data are different, delete the data store. dataChanged = !Arrays.equals(dataCached, dataCurrent); } else { // Either the cached file was somehow deleted, or this is the first // boot of the device and we're creating the file for the first time. // In either case, delete the log files. dataChanged = true; } } return dataChanged; } private void updateCacheFile(String cacheFilename, byte[] data) { try { final AtomicFile atomicCachedFile = new AtomicFile(new File(mDataStoragePath, cacheFilename)); final FileOutputStream fos = atomicCachedFile.startWrite(); fos.write(data); atomicCachedFile.finishWrite(fos); } catch (IOException e) { Slog.e(TAG, "Failed to write current data to cached file"); } } public boolean getDeleteMeterDataOnBoot() { return mDeleteMeterDataOnBoot; } public boolean getDeleteModelDataOnBoot() { return mDeleteModelDataOnBoot; } public boolean getDeleteResidencyDataOnBoot() { return mDeleteResidencyDataOnBoot; } public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String meterCacheFilename, String modelFilename, String modelCacheFilename, String residencyFilename, String residencyCacheFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { super(Looper.getMainLooper()); mPowerStatsHALWrapper = powerStatsHALWrapper; mPowerStatsMeterStorage = new PowerStatsDataStorage(context, dataStoragePath, mDataStoragePath = dataStoragePath; mPowerStatsMeterStorage = new PowerStatsDataStorage(context, mDataStoragePath, meterFilename); mPowerStatsModelStorage = new PowerStatsDataStorage(context, dataStoragePath, mPowerStatsModelStorage = new PowerStatsDataStorage(context, mDataStoragePath, modelFilename); mPowerStatsResidencyStorage = new PowerStatsDataStorage(context, dataStoragePath, mPowerStatsResidencyStorage = new PowerStatsDataStorage(context, mDataStoragePath, residencyFilename); final Channel[] channels = mPowerStatsHALWrapper.getEnergyMeterInfo(); final byte[] channelBytes = ChannelUtils.getProtoBytes(channels); mDeleteMeterDataOnBoot = dataChanged(meterCacheFilename, channelBytes); if (mDeleteMeterDataOnBoot) { mPowerStatsMeterStorage.deleteLogs(); updateCacheFile(meterCacheFilename, channelBytes); } final EnergyConsumer[] energyConsumers = mPowerStatsHALWrapper.getEnergyConsumerInfo(); final byte[] energyConsumerBytes = EnergyConsumerUtils.getProtoBytes(energyConsumers); mDeleteModelDataOnBoot = dataChanged(modelCacheFilename, energyConsumerBytes); if (mDeleteModelDataOnBoot) { mPowerStatsModelStorage.deleteLogs(); updateCacheFile(modelCacheFilename, energyConsumerBytes); } final PowerEntity[] powerEntities = mPowerStatsHALWrapper.getPowerEntityInfo(); final byte[] powerEntityBytes = PowerEntityUtils.getProtoBytes(powerEntities); mDeleteResidencyDataOnBoot = dataChanged(residencyCacheFilename, powerEntityBytes); if (mDeleteResidencyDataOnBoot) { mPowerStatsResidencyStorage.deleteLogs(); updateCacheFile(residencyCacheFilename, powerEntityBytes); } } }
services/core/java/com/android/server/powerstats/PowerStatsService.java +44 −6 Original line number Diff line number Diff line Loading @@ -61,8 +61,12 @@ public class PowerStatsService extends SystemService { private static final String MODEL_FILENAME = "log.powerstats.model." + DATA_STORAGE_VERSION; private static final String RESIDENCY_FILENAME = "log.powerstats.residency." + DATA_STORAGE_VERSION; private static final String METER_CACHE_FILENAME = "meterCache"; private static final String MODEL_CACHE_FILENAME = "modelCache"; private static final String RESIDENCY_CACHE_FILENAME = "residencyCache"; private final Injector mInjector; private File mDataStoragePath; private Context mContext; @Nullable Loading Loading @@ -98,6 +102,18 @@ public class PowerStatsService extends SystemService { return RESIDENCY_FILENAME; } String createMeterCacheFilename() { return METER_CACHE_FILENAME; } String createModelCacheFilename() { return MODEL_CACHE_FILENAME; } String createResidencyCacheFilename() { return RESIDENCY_CACHE_FILENAME; } IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() { return PowerStatsHALWrapper.getPowerStatsHalImpl(); } Loading @@ -112,10 +128,15 @@ public class PowerStatsService extends SystemService { } PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String modelFilename, String residencyFilename, String meterFilename, String meterCacheFilename, String modelFilename, String modelCacheFilename, String residencyFilename, String residencyCacheFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { return new PowerStatsLogger(context, dataStoragePath, meterFilename, modelFilename, residencyFilename, powerStatsHALWrapper); return new PowerStatsLogger(context, dataStoragePath, meterFilename, meterCacheFilename, modelFilename, modelCacheFilename, residencyFilename, residencyCacheFilename, powerStatsHALWrapper); } BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) { Loading Loading @@ -187,14 +208,31 @@ public class PowerStatsService extends SystemService { mPullAtomCallback = mInjector.createStatsPullerImpl(mContext, mPowerStatsInternal); } @VisibleForTesting public boolean getDeleteMeterDataOnBoot() { return mPowerStatsLogger.getDeleteMeterDataOnBoot(); } @VisibleForTesting public boolean getDeleteModelDataOnBoot() { return mPowerStatsLogger.getDeleteModelDataOnBoot(); } @VisibleForTesting public boolean getDeleteResidencyDataOnBoot() { return mPowerStatsLogger.getDeleteResidencyDataOnBoot(); } private void onBootCompleted() { if (getPowerStatsHal().isInitialized()) { if (DEBUG) Slog.d(TAG, "Starting PowerStatsService loggers"); mDataStoragePath = mInjector.createDataStoragePath(); // Only start logger and triggers if initialization is successful. mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mInjector.createDataStoragePath(), mInjector.createMeterFilename(), mInjector.createModelFilename(), mInjector.createResidencyFilename(), mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mDataStoragePath, mInjector.createMeterFilename(), mInjector.createMeterCacheFilename(), mInjector.createModelFilename(), mInjector.createModelCacheFilename(), mInjector.createResidencyFilename(), mInjector.createResidencyCacheFilename(), getPowerStatsHal()); mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger); mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger); Loading
services/core/java/com/android/server/powerstats/ProtoStreamUtils.java +84 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,12 @@ public class ProtoStreamUtils { private static final String TAG = ProtoStreamUtils.class.getSimpleName(); static class PowerEntityUtils { public static byte[] getProtoBytes(PowerEntity[] powerEntity) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(powerEntity, pos); return pos.getBytes(); } public static void packProtoMessage(PowerEntity[] powerEntity, ProtoOutputStream pos) { if (powerEntity == null) return; Loading Loading @@ -260,6 +266,12 @@ public class ProtoStreamUtils { } static class ChannelUtils { public static byte[] getProtoBytes(Channel[] channel) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(channel, pos); return pos.getBytes(); } public static void packProtoMessage(Channel[] channel, ProtoOutputStream pos) { if (channel == null) return; Loading Loading @@ -396,6 +408,12 @@ public class ProtoStreamUtils { } static class EnergyConsumerUtils { public static byte[] getProtoBytes(EnergyConsumer[] energyConsumer) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(energyConsumer, pos); return pos.getBytes(); } public static void packProtoMessage(EnergyConsumer[] energyConsumer, ProtoOutputStream pos) { if (energyConsumer == null) return; Loading @@ -410,6 +428,72 @@ public class ProtoStreamUtils { } } public static EnergyConsumer[] unpackProtoMessage(byte[] data) throws IOException { final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data)); List<EnergyConsumer> energyConsumerList = new ArrayList<EnergyConsumer>(); while (true) { try { int nextField = pis.nextField(); EnergyConsumer energyConsumer = new EnergyConsumer(); if (nextField == (int) PowerStatsServiceModelProto.ENERGY_CONSUMER) { long token = pis.start(PowerStatsServiceModelProto.ENERGY_CONSUMER); energyConsumerList.add(unpackEnergyConsumerProto(pis)); pis.end(token); } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) { return energyConsumerList.toArray( new EnergyConsumer[energyConsumerList.size()]); } else { Slog.e(TAG, "Unhandled field in proto: " + ProtoUtils.currentFieldToString(pis)); } } catch (WireTypeMismatchException wtme) { Slog.e(TAG, "Wire Type mismatch in proto: " + ProtoUtils.currentFieldToString(pis)); } } } private static EnergyConsumer unpackEnergyConsumerProto(ProtoInputStream pis) throws IOException { final EnergyConsumer energyConsumer = new EnergyConsumer(); while (true) { try { switch (pis.nextField()) { case (int) EnergyConsumerProto.ID: energyConsumer.id = pis.readInt(EnergyConsumerProto.ID); break; case (int) EnergyConsumerProto.ORDINAL: energyConsumer.ordinal = pis.readInt(EnergyConsumerProto.ORDINAL); break; case (int) EnergyConsumerProto.TYPE: energyConsumer.type = (byte) pis.readInt(EnergyConsumerProto.TYPE); break; case (int) EnergyConsumerProto.NAME: energyConsumer.name = pis.readString(EnergyConsumerProto.NAME); break; case ProtoInputStream.NO_MORE_FIELDS: return energyConsumer; default: Slog.e(TAG, "Unhandled field in EnergyConsumerProto: " + ProtoUtils.currentFieldToString(pis)); break; } } catch (WireTypeMismatchException wtme) { Slog.e(TAG, "Wire Type mismatch in EnergyConsumerProto: " + ProtoUtils.currentFieldToString(pis)); } } } public static void print(EnergyConsumer[] energyConsumer) { if (energyConsumer == null) return; Loading
services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java +351 −12 File changed.Preview size limit exceeded, changes collapsed. Show changes