diff options
Diffstat (limited to 'src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParser.java')
-rw-r--r-- | src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParser.java | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParser.java b/src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParser.java new file mode 100644 index 0000000..d5177e3 --- /dev/null +++ b/src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParser.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2015 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.loganalysis.parser; + +import com.android.loganalysis.item.BatteryDischargeItem; +import com.android.loganalysis.item.BatteryDischargeItem.BatteryDischargeInfoItem; +import com.android.loganalysis.item.BatteryStatsSummaryInfoItem; +import com.android.loganalysis.util.NumberFormattingUtil; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A {@link IParser} to parse batterystats summary + */ +public class BatteryStatsSummaryInfoParser implements IParser{ + + /** + * Matches: 0 (15) RESET:TIME: 2015-01-18-12-56-57 + */ + private static final Pattern RESET_TIME_PATTERN = Pattern.compile("^\\s*" + + "\\d\\s*\\(\\d+\\)\\s*RESET:TIME:\\s*(\\d+)-(\\d+)-(\\d+)-(\\d+)-(\\d+)-(\\d+)$"); + + /** + * Matches: +1d01h03m37s246ms (1) 028 c10400010 -running -wake_lock + */ + private static final Pattern BATTERY_DISCHARGE_PATTERN = Pattern.compile( + "^\\s*\\+(?:(\\d+)d)?(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?(?:(\\d+)ms)? \\(\\d+\\) " + + "(\\d+) \\w+ .*"); + + private BatteryDischargeItem mBatteryDischarge = new BatteryDischargeItem(); + private BatteryStatsSummaryInfoItem mItem = new BatteryStatsSummaryInfoItem(); + private long mBatteryDischargeRateAvg = 0; + private int mBatteryDischargeSamples = 0; + private Calendar mResetTime; + private static final int BATTERY_GROUP_LIMIT = 10; + + /** + * {@inheritDoc} + * + * @return The {@link BatteryStatsSummaryInfoItem}. + */ + @Override + public BatteryStatsSummaryInfoItem parse(List<String> lines) { + Matcher resetTimeMatcher = null; + Matcher dischargeMatcher = null; + + long previousDischargeElapsedTime= 0; + int previousBatteryLevel = 0; + boolean batteryDischargedFully = false; + for (String line : lines) { + resetTimeMatcher = RESET_TIME_PATTERN.matcher(line); + dischargeMatcher = BATTERY_DISCHARGE_PATTERN.matcher(line); + if (resetTimeMatcher.matches()) { + mResetTime = new GregorianCalendar(); + final int year = Integer.parseInt(resetTimeMatcher.group(1)); + final int month = Integer.parseInt(resetTimeMatcher.group(2)); + final int day = Integer.parseInt(resetTimeMatcher.group(3)); + final int hour = Integer.parseInt(resetTimeMatcher.group(4)); + final int minute = Integer.parseInt(resetTimeMatcher.group(5)); + final int second = Integer.parseInt(resetTimeMatcher.group(6)); + // Calendar month is zero indexed but the parsed date is 1-12 + mResetTime.set(year, (month - 1), day, hour, minute, second); + } else if (dischargeMatcher.matches()) { + final int days = NumberFormattingUtil.parseIntOrZero(dischargeMatcher.group(1)); + final int hours = NumberFormattingUtil.parseIntOrZero(dischargeMatcher.group(2)); + final int mins = NumberFormattingUtil.parseIntOrZero(dischargeMatcher.group(3)); + final int secs = NumberFormattingUtil.parseIntOrZero(dischargeMatcher.group(4)); + final int msecs = NumberFormattingUtil.parseIntOrZero(dischargeMatcher.group(5)); + final int batteryLevel = Integer.parseInt(dischargeMatcher.group(6)); + if (batteryLevel == 0) { + // Ignore the subsequent battery drop readings + batteryDischargedFully = true; + continue; + } else if (previousBatteryLevel == 0) { + // Ignore the first drop + previousBatteryLevel = batteryLevel; + continue; + } else if (!batteryDischargedFully && previousBatteryLevel != batteryLevel) { + long elapsedTime = NumberFormattingUtil.getMs(days, hours, mins, secs, msecs); + mBatteryDischargeRateAvg += (elapsedTime - previousDischargeElapsedTime); + mBatteryDischargeSamples++; + mBatteryDischarge.addBatteryDischargeInfo( + getDischargeClockTime(days, hours, mins, secs), + (elapsedTime - previousDischargeElapsedTime), batteryLevel); + previousDischargeElapsedTime = elapsedTime; + previousBatteryLevel = batteryLevel; + } + } + } + mItem.setBatteryDischargeRate(getAverageDischargeRate()); + mItem.setPeakDischargeTime(getPeakDischargeTime()); + return mItem; + } + + private Calendar getDischargeClockTime(int days, int hours, int mins, int secs) { + Calendar dischargeClockTime = new GregorianCalendar(); + + dischargeClockTime.setTime(mResetTime.getTime()); + dischargeClockTime.add(Calendar.DATE, days); + dischargeClockTime.add(Calendar.HOUR, hours); + dischargeClockTime.add(Calendar.MINUTE, mins); + dischargeClockTime.add(Calendar.SECOND, secs); + return dischargeClockTime; + } + + private String getAverageDischargeRate() { + if (mBatteryDischargeSamples == 0) { + return "The battery did not discharge"; + } + + final long minsPerLevel = mBatteryDischargeRateAvg / (mBatteryDischargeSamples * 60 * 1000); + return String.format("The battery dropped a level %d mins on average", minsPerLevel); + } + + private String getPeakDischargeTime() { + + int peakDischargeStartBatteryLevel = 0, peakDischargeStopBatteryLevel = 0; + long minDischargeDuration = 0; + Calendar peakDischargeStartTime= null, peakDischargeStopTime = null; + Queue <BatteryDischargeInfoItem> batteryDischargeWindow = + new LinkedList <BatteryDischargeInfoItem>(); + long sumDischargeDuration = 0; + for (BatteryDischargeInfoItem dischargeSteps : mBatteryDischarge.getDischargeStepsInfo()) { + batteryDischargeWindow.add(dischargeSteps); + sumDischargeDuration += dischargeSteps.getElapsedTime(); + if (batteryDischargeWindow.size() >= BATTERY_GROUP_LIMIT) { + final long averageDischargeDuration = sumDischargeDuration/BATTERY_GROUP_LIMIT; + final BatteryDischargeInfoItem startNode = batteryDischargeWindow.remove(); + sumDischargeDuration -= startNode.getElapsedTime(); + + if (minDischargeDuration == 0 || averageDischargeDuration < minDischargeDuration) { + minDischargeDuration = averageDischargeDuration; + peakDischargeStartBatteryLevel = startNode.getBatteryLevel(); + peakDischargeStopBatteryLevel = dischargeSteps.getBatteryLevel(); + peakDischargeStartTime = startNode.getClockTime(); + peakDischargeStopTime = dischargeSteps.getClockTime(); + } + } + } + if (peakDischargeStartTime != null && peakDischargeStopTime != null && + peakDischargeStartBatteryLevel > 0 && peakDischargeStopBatteryLevel > 0) { + return String.format( + "The peak discharge time was during %s to %s where battery dropped from %d to " + + "%d", peakDischargeStartTime.getTime().toString(), + peakDischargeStopTime.getTime().toString(), peakDischargeStartBatteryLevel, + peakDischargeStopBatteryLevel); + + } else { + return "The battery did not discharge"; + } + } + + /** + * Get the {@link BatteryStatsSummaryInfoItem}. + * <p> + * Exposed for unit testing. + * </p> + */ + BatteryStatsSummaryInfoItem getItem() { + return mItem; + } +} |