Skip to content
Snippets Groups Projects
Commit f11cbc49 authored by avellore's avatar avellore
Browse files

Battery drain investigator

Initial version of the battery drain investigator. It parses the bugreport
for power specific sections and returns the analysis in JSON format

Change-Id: I56c1e010666892b1296272942cc5edcc5072c731
parent 3c61512f
No related branches found
No related tags found
No related merge requests found
Showing
with 1930 additions and 251 deletions
......@@ -26,10 +26,14 @@ import com.android.loganalysis.parser.KernelLogParser;
import com.android.loganalysis.parser.LogcatParser;
import com.android.loganalysis.parser.MemoryHealthParser;
import com.android.loganalysis.parser.MonkeyLogParser;
import com.android.loganalysis.rule.RuleEngine;
import com.android.loganalysis.rule.RuleEngine.RuleType;
import com.android.loganalysis.util.config.ArgsOptionParser;
import com.android.loganalysis.util.config.ConfigurationException;
import com.android.loganalysis.util.config.Option;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
......@@ -39,6 +43,9 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* A command line tool to parse a bugreport, logcat, or kernel log file and return the output.
*/
......@@ -49,6 +56,10 @@ public class LogAnalyzer {
JSON;
}
private enum ResultType {
RAW, ANALYSIS;
}
@Option(name="bugreport", description="The path to the bugreport")
private String mBugreportPath = null;
......@@ -67,6 +78,17 @@ public class LogAnalyzer {
@Option(name="output", description="The output format, currently only JSON")
private OutputFormat mOutputFormat = OutputFormat.JSON;
@Option(name="rule-type", description="The type of rules to be applied")
private RuleType mRuleType = RuleType.ALL;
@Option(name="print", description="Print the result type")
private List<ResultType> mResultType = new ArrayList<ResultType>();
/** Constant for JSON output */
private static final String RAW_DATA = "RAW";
/** Constant for JSON output */
private static final String ANALYSIS_DATA = "ANALYSIS";
/**
* Run the command line tool
*/
......@@ -140,9 +162,61 @@ public class LogAnalyzer {
*/
private void printBugreport(BugreportItem bugreport) {
if (OutputFormat.JSON.equals(mOutputFormat)) {
if (mResultType.size() == 0) {
printJson(bugreport);
} else if (mResultType.size() == 1) {
switch (mResultType.get(0)) {
case RAW:
printJson(bugreport);
break;
case ANALYSIS:
printBugreportAnalysis(getBugreportAnalysis(bugreport));
break;
default:
// should not get here
return;
}
} else {
JSONObject result = new JSONObject();
try {
for (ResultType resultType : mResultType) {
switch (resultType) {
case RAW:
result.put(RAW_DATA, bugreport.toJson());
break;
case ANALYSIS:
result.put(ANALYSIS_DATA, getBugreportAnalysis(bugreport));
break;
default:
// should not get here
break;
}
}
} catch (JSONException e) {
// Ignore
}
printJson(result);
}
}
}
private JSONArray getBugreportAnalysis(BugreportItem bugreport) {
RuleEngine ruleEngine = new RuleEngine(bugreport);
ruleEngine.registerRules(mRuleType);
ruleEngine.executeRules();
if (ruleEngine.getAnalysis() != null) {
return ruleEngine.getAnalysis();
} else {
return new JSONArray();
}
}
private void printBugreportAnalysis(JSONArray analysis) {
if (analysis != null && analysis.length() > 0) {
System.out.println(analysis.toString());
} else {
System.out.println(new JSONObject().toString());
}
// TODO: Print bugreport in human readable form.
}
/**
......@@ -180,7 +254,18 @@ public class LogAnalyzer {
*/
private void printJson(IItem item) {
if (item != null && item.toJson() != null) {
System.out.println(item.toJson().toString());
printJson(item.toJson());
} else {
printJson(new JSONObject());
}
}
/**
* Print an {@link JSONObject} to stdout
*/
private void printJson(JSONObject json) {
if (json != null) {
System.out.println(json.toString());
} else {
System.out.println(new JSONObject().toString());
}
......
/*
* 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.item;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
/**
* An {@link IItem} used to store information related to Battery discharge
*/
public class BatteryDischargeItem implements IItem {
/** Constant for JSON output */
public static final String BATTERY_DISCHARGE = "BATTERY_DISCHARGE";
private Collection<BatteryDischargeInfoItem> mBatteryDischargeInfo =
new LinkedList<BatteryDischargeInfoItem>();
public static class BatteryDischargeInfoItem extends GenericItem {
/** Constant for JSON output */
public static final String CLOCK_TIME_OF_DISCHARGE = "CLOCK_TIME_OF_DISCHARGE";
/** Constant for JSON output */
public static final String DISCHARGE_ELAPSED_TIME = "DISCHARGE_ELAPSED_TIME";
/** Constant for JSON output */
public static final String BATTERY_LEVEL = "BATTERY_LEVEL";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
CLOCK_TIME_OF_DISCHARGE, DISCHARGE_ELAPSED_TIME, BATTERY_LEVEL));
/**
* The constructor for {@link BatteryDischargeInfoItem}
*
* @param clockTime Clock time when the battery discharge happened
* @param elapsedTime Time it took to discharge to the current battery level
* @param batteryLevel Current battery level
*/
public BatteryDischargeInfoItem(Calendar clockTime, long elapsedTime, int batteryLevel) {
super(ATTRIBUTES);
setAttribute(CLOCK_TIME_OF_DISCHARGE, clockTime);
setAttribute(DISCHARGE_ELAPSED_TIME, elapsedTime);
setAttribute(BATTERY_LEVEL, batteryLevel);
}
/**
* Get the clock time when the battery level dropped
*/
public Calendar getClockTime() {
return (Calendar) getAttribute(CLOCK_TIME_OF_DISCHARGE);
}
/**
* Get the time elapsed to discharge to the current battery level
*/
public long getElapsedTime() {
return (long) getAttribute(DISCHARGE_ELAPSED_TIME);
}
/**
* Get the current battery level
*/
public int getBatteryLevel() {
return (int) getAttribute(BATTERY_LEVEL);
}
}
/**
* Add a battery discharge step from battery stats
*
* @param clockTime Clock time when the battery discharge happened
* @param elapsedTime Time it took to discharge to the current battery level
* @param batteryLevel Current battery level
*/
public void addBatteryDischargeInfo(Calendar clockTime, long elapsedTime, int batteryLevel) {
mBatteryDischargeInfo.add(new BatteryDischargeInfoItem(clockTime,
elapsedTime, batteryLevel));
}
public Collection<BatteryDischargeInfoItem> getDischargeStepsInfo() {
return mBatteryDischargeInfo;
}
/**
* {@inheritDoc}
*/
@Override
public IItem merge(IItem other) throws ConflictingItemException {
throw new ConflictingItemException("Wakelock items cannot be merged");
}
/**
* {@inheritDoc}
*/
@Override
public boolean isConsistent(IItem other) {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public JSONObject toJson() {
JSONObject object = new JSONObject();
try {
JSONArray batteryDischargeSteps = new JSONArray();
for (BatteryDischargeInfoItem batteryDischargeStep : mBatteryDischargeInfo) {
batteryDischargeSteps.put(batteryDischargeStep.toJson());
}
object.put(BATTERY_DISCHARGE, batteryDischargeSteps);
} catch (JSONException e) {
// Ignore
}
return object;
}
}
/*
* 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.item;
import org.json.JSONException;
import org.json.JSONObject;
/**
* An {@link IItem} used to store BatteryStats Info
*/
public class BatteryStatsDetailedInfoItem implements IItem {
/** Constant for JSON output */
public static final String TIME_ON_BATTERY = "TIME_ON_BATTERY";
/** Constant for JSON output */
public static final String SCREEN_ON_TIME = "SCREEN_ON_TIME";
/** Constant for JSON output */
public static final String WAKELOCKS = "WAKELOCKS";
/** Constant for JSON output */
public static final String INTERRUPTS = "INTERRUPTS";
/** Constant for JSON output */
public static final String PROCESS_USAGE = "PROCESS_USAGE";
private long mTimeOnBattery = 0;
private long mScreenOnTime = 0;
private WakelockItem mWakelockItem = null;
private InterruptItem mInterruptItem = null;
private ProcessUsageItem mprocessUsageItem = null;
/**
* Set the time on battery
*/
public void setTimeOnBattery(long timeOnBattery) {
mTimeOnBattery = timeOnBattery;
}
/**
* Set the time on battery
*/
public void setScreenOnTime(long screenOnTime) {
mScreenOnTime = screenOnTime;
}
/**
* Set the wakelock summary {@link WakelockItem}
*/
public void setWakelockItem(WakelockItem wakelockItem) {
mWakelockItem = wakelockItem;
}
/**
* Set the interrupt summary {@link InterruptItem}
*/
public void setInterruptItem(InterruptItem interruptItem) {
mInterruptItem = interruptItem;
}
/**
* Set the process usage {@link ProcessUsageItem}
*/
public void setProcessUsageItem(ProcessUsageItem processUsageItem) {
mprocessUsageItem = processUsageItem;
}
/**
* Get the time on battery
*/
public long getTimeOnBattery() {
return mTimeOnBattery;
}
/**
* Get the screen on time
*/
public long getScreenOnTime() {
return mScreenOnTime;
}
/**
* Get the wakelock summary {@link WakelockItem}
*/
public WakelockItem getWakelockItem() {
return mWakelockItem;
}
/**
* Get the interrupt summary {@link InterruptItem}
*/
public InterruptItem getInterruptItem() {
return mInterruptItem;
}
/**
* Get the process usage summary {@link ProcessUsageItem}
*/
public ProcessUsageItem getProcessUsageItem() {
return mprocessUsageItem;
}
/**
* {@inheritDoc}
*/
@Override
public IItem merge(IItem other) throws ConflictingItemException {
throw new ConflictingItemException("Dumpsys battery info items cannot be merged");
}
/**
* {@inheritDoc}
*/
@Override
public boolean isConsistent(IItem other) {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public JSONObject toJson() {
JSONObject batteryStatsComponent = new JSONObject();
try {
if (mTimeOnBattery > 0) {
batteryStatsComponent.put(TIME_ON_BATTERY, getTimeOnBattery());
}
if (mScreenOnTime > 0) {
batteryStatsComponent.put(SCREEN_ON_TIME, getScreenOnTime());
}
if (mWakelockItem != null) {
batteryStatsComponent.put(WAKELOCKS, mWakelockItem.toJson());
}
if (mInterruptItem != null) {
batteryStatsComponent.put(INTERRUPTS, mInterruptItem.toJson());
}
if (mprocessUsageItem != null) {
batteryStatsComponent.put(PROCESS_USAGE, mprocessUsageItem.toJson());
}
} catch (JSONException e) {
// ignore
}
return batteryStatsComponent;
}
}
/*
* 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.item;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* An {@link GenericItem} used to store the power analysis summary
*/
public class BatteryStatsSummaryInfoItem extends GenericItem {
/** Constant for JSON output */
public static final String DISCHARGE_RATE = "DISCHARGE_RATE";
/** Constant for JSON output */
public static final String PEAK_DISCHARGE_TIME = "PEAK_DISCHARGE_TIME";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
DISCHARGE_RATE, PEAK_DISCHARGE_TIME));
/**
* The constructor for {@link BatteryStatsSummaryInfoItem}.
*/
public BatteryStatsSummaryInfoItem() {
super(ATTRIBUTES);
}
/**
* Get the battery discharge rate
*/
public String getBatteryDischargeRate() {
return (String) getAttribute(DISCHARGE_RATE);
}
/**
* Set the battery discharge rate
*/
public void setBatteryDischargeRate(String dischargeRate) {
setAttribute(DISCHARGE_RATE, dischargeRate);
}
/**
* Get the peak discharge time
*/
public String getPeakDischargeTime() {
return (String) getAttribute(PEAK_DISCHARGE_TIME);
}
/**
* Set the peak discharge time
*/
public void setPeakDischargeTime(String peakDischargeTime) {
setAttribute(PEAK_DISCHARGE_TIME, peakDischargeTime);
}
}
/*
* 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.item;
import org.json.JSONException;
import org.json.JSONObject;
/**
* An {@link IItem} used to store BatteryStats Info
*/
public class DumpsysBatteryStatsItem implements IItem {
/** Constant for JSON output */
public static final String SUMMARY = "SUMMARY";
/** Constant for JSON output */
public static final String DETAILED_STATS = "DETAILED_STATS";
private BatteryStatsSummaryInfoItem mBatteryStatsSummaryItem;
private BatteryStatsDetailedInfoItem mDetailedBatteryStatsItem;
/**
* Set the battery stats summary {@link BatteryStatsSummaryInfoItem}
*/
public void setBatteryStatsSummarytem(BatteryStatsSummaryInfoItem summaryItem) {
mBatteryStatsSummaryItem = summaryItem;
}
/**
* Set the detailed battery stats item {@link BatteryStatsDetailedInfoItem}
*/
public void setDetailedBatteryStatsItem(BatteryStatsDetailedInfoItem detailedItem) {
mDetailedBatteryStatsItem = detailedItem;
}
/**
* Get the battery stats summary {@link BatteryStatsSummaryInfoItem}
*/
public BatteryStatsSummaryInfoItem getBatteryStatsSummaryItem() {
return mBatteryStatsSummaryItem;
}
/**
* Get the detailed battery stats item {@link BatteryStatsDetailedInfoItem}
*/
public BatteryStatsDetailedInfoItem getDetailedBatteryStatsItem() {
return mDetailedBatteryStatsItem;
}
/**
* {@inheritDoc}
*/
@Override
public IItem merge(IItem other) throws ConflictingItemException {
throw new ConflictingItemException("Dumpsys battery info items cannot be merged");
}
/**
* {@inheritDoc}
*/
@Override
public boolean isConsistent(IItem other) {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public JSONObject toJson() {
JSONObject batteryStatsComponent = new JSONObject();
try {
if (mBatteryStatsSummaryItem != null) {
batteryStatsComponent.put(SUMMARY, mBatteryStatsSummaryItem.toJson());
}
if (mDetailedBatteryStatsItem != null) {
batteryStatsComponent.put(DETAILED_STATS, mDetailedBatteryStatsItem.toJson());
}
} catch (JSONException e) {
// ignore
}
return batteryStatsComponent;
}
}
......@@ -25,28 +25,45 @@ import java.util.Set;
public class DumpsysItem extends GenericItem {
/** Constant for JSON output */
private static final String BATTERY_INFO = "BATTERY_INFO";
private static final String BATTERY_STATS = "BATTERY_STATS";
/** Constant for JSON output */
private static final String PROC_STATS = "PROC_STATS";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(BATTERY_INFO));
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
BATTERY_STATS, PROC_STATS));
/**
* The constructor for {@link BugreportItem}.
* The constructor for {@link DumpsysItem}.
*/
public DumpsysItem() {
super(ATTRIBUTES);
}
/**
* Get the battery info section of the dumpsys.
* Set the {@link DumpsysBatteryStatsItem} of the bugreport.
*/
public void setBatteryInfo(DumpsysBatteryStatsItem batteryStats) {
setAttribute(BATTERY_STATS, batteryStats);
}
/**
* Set the {@link DumpsysProcStatsItem} of the bugreport.
*/
public void setProcStats(DumpsysProcStatsItem procStats) {
setAttribute(PROC_STATS, procStats);
}
/**
* Get the {@link DumpsysBatteryStatsItem} of the bugreport.
*/
public DumpsysBatteryInfoItem getBatteryInfo() {
return (DumpsysBatteryInfoItem) getAttribute(BATTERY_INFO);
public DumpsysBatteryStatsItem getBatteryStats() {
return (DumpsysBatteryStatsItem) getAttribute(BATTERY_STATS);
}
/**
* Set the battery info section of the dumpsys.
* Get the {@link DumpsysProcStatsItem} of the bugreport.
*/
public void setBatteryInfo(DumpsysBatteryInfoItem batteryInfo) {
setAttribute(BATTERY_INFO, batteryInfo);
public DumpsysProcStatsItem getProcStats() {
return (DumpsysProcStatsItem) getAttribute(PROC_STATS);
}
}
/*
* 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.item;
/**
* An {@link IItem} used to store uid and processname map. It is going to be
* used a helper item and not going to be marshalled to JSON
*/
public class DumpsysProcStatsItem extends GenericMapItem<String> {
}
/*
* 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.item;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* An {@link IItem} used to store information related to interrupts
*/
public class InterruptItem implements IItem {
/** Constant for JSON output */
public static final String INTERRUPTS = "INTERRUPT_INFO";
private Collection<InterruptInfoItem> mInterrupts = new LinkedList<InterruptInfoItem>();
/**
* Enum for describing the type of interrupt
*/
public enum InterruptCategory {
WIFI_INTERRUPT,
MODEM_INTERRUPT,
ALARM_INTERRUPT,
ADSP_INTERRUPT,
UNKNOWN_INTERRUPT,
}
public static class InterruptInfoItem extends GenericItem {
/** Constant for JSON output */
public static final String NAME = "NAME";
/** Constant for JSON output */
public static final String CATEGORY = "CATEGORY";
/** Constant for JSON output */
public static final String INTERRUPT_COUNT = "INTERRUPT_COUNT";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
NAME, INTERRUPT_COUNT, CATEGORY));
/**
* The constructor for {@link InterruptItem}
*
* @param name The name of the wake lock
* @param interruptCount The number of times the interrupt woke up the AP
* @param category The {@link InterruptCategory} of the interrupt
*/
public InterruptInfoItem(String name, int interruptCount,
InterruptCategory category) {
super(ATTRIBUTES);
setAttribute(NAME, name);
setAttribute(INTERRUPT_COUNT, interruptCount);
setAttribute(CATEGORY, category);
}
/**
* Get the name of the interrupt
*/
public String getName() {
return (String) getAttribute(NAME);
}
/**
* Get the interrupt count.
*/
public int getInterruptCount() {
return (Integer) getAttribute(INTERRUPT_COUNT);
}
/**
* Get the {@link InterruptCategory} of the wake lock.
*/
public InterruptCategory getCategory() {
return (InterruptCategory) getAttribute(CATEGORY);
}
}
/**
* Add an interrupt from the battery info section.
*
* @param name The name of the interrupt
* @param interruptCount Number of interrupts
* @param category The {@link InterruptCategory} of the interrupt.
*/
public void addInterrupt(String name, int interruptCount,
InterruptCategory category) {
mInterrupts.add(new InterruptInfoItem(name, interruptCount, category));
}
/**
* Get a list of {@link InterruptInfoItem} objects matching a given {@link InterruptCategory}.
*/
public List<InterruptInfoItem> getInterrupts(InterruptCategory category) {
LinkedList<InterruptInfoItem> interrupts = new LinkedList<InterruptInfoItem>();
if (category == null) {
return interrupts;
}
for (InterruptInfoItem interrupt : mInterrupts) {
if (category.equals(interrupt.getCategory())) {
interrupts.add(interrupt);
}
}
return interrupts;
}
/**
* {@inheritDoc}
*/
@Override
public IItem merge(IItem other) throws ConflictingItemException {
throw new ConflictingItemException("Wakelock items cannot be merged");
}
/**
* {@inheritDoc}
*/
@Override
public boolean isConsistent(IItem other) {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public JSONObject toJson() {
JSONObject object = new JSONObject();
if (mInterrupts != null) {
try {
JSONArray interrupts = new JSONArray();
for (InterruptInfoItem interrupt : mInterrupts) {
interrupts.put(interrupt.toJson());
}
object.put(INTERRUPTS, interrupts);
} catch (JSONException e) {
// Ignore
}
}
return object;
}
}
/*
* 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.item;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
/**
* An {@link IItem} used to store information related to network bandwidth, sensor usage,
* alarm usage by each processes
*/
public class ProcessUsageItem implements IItem {
/** Constant for JSON output */
public static final String PROCESS_USAGE = "PROCESS_USAGE";
private Collection<ProcessUsageInfoItem> mProcessUsage =
new LinkedList<ProcessUsageInfoItem>();
public static class SensorInfoItem extends GenericItem {
/** Constant for JSON output */
public static final String SENSOR_NAME = "SENSOR_NAME";
/** Constant for JSON output */
public static final String USAGE_DURATION = "USAGE_DURATION";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
SENSOR_NAME, USAGE_DURATION));
/**
* The constructor for {@link SensorInfoItem}
*
* @param name The name of the sensor
* @param usageDuration Duration of the usage
*/
public SensorInfoItem(String name, long usageDuration) {
super(ATTRIBUTES);
setAttribute(SENSOR_NAME, name);
setAttribute(USAGE_DURATION, usageDuration);
}
/**
* Get the sensor name
*/
public String getSensorName() {
return (String) getAttribute(SENSOR_NAME);
}
/**
* Get the sensor usage duration in milliseconds
*/
public long getUsageDurationMs() {
return (long) getAttribute(USAGE_DURATION);
}
}
public static class ProcessUsageInfoItem extends GenericItem {
/** Constant for JSON output */
public static final String ALARM_WAKEUPS = "ALARM_WAKEUPS";
/** Constant for JSON output */
public static final String SENSOR_USAGE = "SENSOR_USAGE";
/** Constant for JSON output */
public static final String PROCESS_UID = "PROCESS_UID";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
ALARM_WAKEUPS, SENSOR_USAGE, PROCESS_UID));
/**
* The constructor for {@link ProcessUsageItem}
*
* @param uid The name of the process
* @param alarmWakeups Number of alarm wakeups
* @param sensorUsage Different sensors used by the process
*/
public ProcessUsageInfoItem(String uid, int alarmWakeups,
LinkedList<SensorInfoItem> sensorUsage) {
super(ATTRIBUTES);
setAttribute(PROCESS_UID, uid);
setAttribute(ALARM_WAKEUPS, alarmWakeups);
setAttribute(SENSOR_USAGE, sensorUsage);
}
/**
* Get the number of Alarm wakeups
*/
public int getAlarmWakeups() {
return (int) getAttribute(ALARM_WAKEUPS);
}
/**
* Get the Sensor usage of the process
*/
@SuppressWarnings("unchecked")
public LinkedList<SensorInfoItem> getSensorUsage() {
return (LinkedList<SensorInfoItem>) getAttribute(SENSOR_USAGE);
}
/**
* Get the process name
*/
public String getProcessUID() {
return (String) getAttribute(PROCESS_UID);
}
/**
* {@inheritDoc}
*/
@Override
public JSONObject toJson() {
JSONObject object = new JSONObject();
try {
object.put(PROCESS_UID, getProcessUID());
JSONArray sensorUsage = new JSONArray();
for (SensorInfoItem usage : getSensorUsage()) {
sensorUsage.put(usage.toJson());
}
object.put(SENSOR_USAGE, sensorUsage);
object.put(ALARM_WAKEUPS, getAlarmWakeups());
} catch (JSONException e) {
// Ignore
}
return object;
}
}
/**
* Add individual process usage from the battery stats section.
*
* @param processUID The name of the process
* @param alarmWakeups The number of alarm wakeups
* @param sensorUsage Sensor usage of the process
*/
public void addProcessUsage(String processUID, int alarmWakeups,
LinkedList<SensorInfoItem> sensorUsage) {
mProcessUsage.add(new ProcessUsageInfoItem(processUID, alarmWakeups, sensorUsage));
}
/**
* {@inheritDoc}
*/
@Override
public IItem merge(IItem other) throws ConflictingItemException {
throw new ConflictingItemException("Wakelock items cannot be merged");
}
/**
* {@inheritDoc}
*/
@Override
public boolean isConsistent(IItem other) {
return false;
}
public Collection<ProcessUsageInfoItem> getProcessUsage() {
return mProcessUsage;
}
/**
* {@inheritDoc}
*/
@Override
public JSONObject toJson() {
JSONObject object = new JSONObject();
if (mProcessUsage != null) {
try {
JSONArray processUsage = new JSONArray();
for (ProcessUsageInfoItem usage : mProcessUsage) {
processUsage.put(usage.toJson());
}
object.put(PROCESS_USAGE, processUsage);
} catch (JSONException e) {
// Ignore
}
}
return object;
}
}
/*
* Copyright (C) 2013 The Android Open Source Project
* 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.
......@@ -27,32 +27,30 @@ import java.util.List;
import java.util.Set;
/**
* An {@link IItem} used to store the battery info part of the dumpsys output.
* An {@link IItem} used to store information related to wake locks and kernel wake locks
*/
public class DumpsysBatteryInfoItem implements IItem {
public class WakelockItem implements IItem {
/** Constant for JSON output */
public static final String WAKELOCKS = "WAKELOCKS";
public static final String WAKELOCKS = "WAKELOCKS_INFO";
private Collection<WakelockInfoItem> mWakeLocks = new LinkedList<WakelockInfoItem>();
/**
* Enum for describing the type of wakelock
*/
public enum WakeLockCategory {
LAST_CHARGE_WAKELOCK,
LAST_CHARGE_KERNEL_WAKELOCK,
LAST_UNPLUGGED_WAKELOCK,
LAST_UNPLUGGED_KERNEL_WAKELOCK;
KERNEL_WAKELOCK,
PARTIAL_WAKELOCK,
}
/**
* A class designed to store information related to wake locks and kernel wake locks.
*/
public static class WakeLock extends GenericItem {
public static class WakelockInfoItem extends GenericItem {
/** Constant for JSON output */
public static final String NAME = "NAME";
/** Constant for JSON output */
public static final String NUMBER = "NUMBER";
public static final String PROCESS_UID = "PROCESS_UID";
/** Constant for JSON output */
public static final String PROCESS_NAME = "PROCESS_NAME";
/** Constant for JSON output */
public static final String HELD_TIME = "HELD_TIME";
/** Constant for JSON output */
......@@ -61,35 +59,35 @@ public class DumpsysBatteryInfoItem implements IItem {
public static final String CATEGORY = "CATEGORY";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
NAME, NUMBER, HELD_TIME, LOCKED_COUNT, CATEGORY));
NAME, PROCESS_UID, PROCESS_NAME, HELD_TIME, LOCKED_COUNT, CATEGORY));
/**
* The constructor for {@link WakeLock}
* The constructor for {@link WakelockItem}
*
* @param name The name of the wake lock
* @param heldTime The amount of time held in milliseconds
* @param lockedCount The number of times the wake lock was locked
* @param category The {@link WakeLockCategory} of the wake lock
*/
public WakeLock(String name, long heldTime, int lockedCount, WakeLockCategory category) {
public WakelockInfoItem(String name, long heldTime, int lockedCount, WakeLockCategory category) {
this(name, null, heldTime, lockedCount, category);
}
/**
* The constructor for {@link WakeLock}
* The constructor for {@link WakelockItem}
*
* @param name The name of the wake lock
* @param number The number of the wake lock
* @param processUID The number of the wake lock
* @param heldTime The amount of time held in milliseconds
* @param lockedCount The number of times the wake lock was locked
* @param category The {@link WakeLockCategory} of the wake lock
*/
public WakeLock(String name, Integer number, long heldTime, int lockedCount,
public WakelockInfoItem(String name, String processUID, long heldTime, int lockedCount,
WakeLockCategory category) {
super(ATTRIBUTES);
setAttribute(NAME, name);
setAttribute(NUMBER, number);
setAttribute(PROCESS_UID, processUID);
setAttribute(HELD_TIME, heldTime);
setAttribute(LOCKED_COUNT, lockedCount);
setAttribute(CATEGORY, category);
......@@ -103,10 +101,10 @@ public class DumpsysBatteryInfoItem implements IItem {
}
/**
* Get the number of the wake lock.
* Get the process UID holding the wake lock.
*/
public Integer getNumber() {
return (Integer) getAttribute(NUMBER);
public String getProcessUID() {
return (String) getAttribute(PROCESS_UID);
}
/**
......@@ -129,26 +127,31 @@ public class DumpsysBatteryInfoItem implements IItem {
public WakeLockCategory getCategory() {
return (WakeLockCategory) getAttribute(CATEGORY);
}
}
private Collection<WakeLock> mWakeLocks = new LinkedList<WakeLock>();
/**
* Set the process name holding the wake lock
*/
public void setWakelockProcessName(String processName) {
setAttribute(PROCESS_NAME, processName);
}
}
/**
* Add a wakelock from the battery info section.
* Add a wakelock from the battery stats section.
*
* @param name The name of the wake lock.
* @param number The number of the wake lock.
* @param processUID The number of the wake lock.
* @param heldTime The held time of the wake lock.
* @param timesCalled The number of times the wake lock has been called.
* @param category The {@link WakeLockCategory} of the wake lock.
*/
public void addWakeLock(String name, Integer number, long heldTime, int timesCalled,
public void addWakeLock(String name, String processUID, long heldTime, int timesCalled,
WakeLockCategory category) {
mWakeLocks.add(new WakeLock(name, number, heldTime, timesCalled, category));
mWakeLocks.add(new WakelockInfoItem(name, processUID, heldTime, timesCalled, category));
}
/**
* Add a wakelock from the battery info section.
* Add a wakelock from the battery stats section.
*
* @param name The name of the wake lock.
* @param heldTime The held time of the wake lock.
......@@ -161,15 +164,15 @@ public class DumpsysBatteryInfoItem implements IItem {
}
/**
* Get a list of {@link WakeLock} objects matching a given {@link WakeLockCategory}.
* Get a list of {@link WakelockInfoItem} objects matching a given {@link WakeLockCategory}.
*/
public List<WakeLock> getWakeLocks(WakeLockCategory category) {
LinkedList<WakeLock> wakeLocks = new LinkedList<WakeLock>();
public List<WakelockInfoItem> getWakeLocks(WakeLockCategory category) {
LinkedList<WakelockInfoItem> wakeLocks = new LinkedList<WakelockInfoItem>();
if (category == null) {
return wakeLocks;
}
for (WakeLock wakeLock : mWakeLocks) {
for (WakelockInfoItem wakeLock : mWakeLocks) {
if (category.equals(wakeLock.getCategory())) {
wakeLocks.add(wakeLock);
}
......@@ -177,12 +180,24 @@ public class DumpsysBatteryInfoItem implements IItem {
return wakeLocks;
}
/**
* Get a list of {@link WakelockInfoItem} .
*/
public List<WakelockInfoItem> getWakeLocks() {
LinkedList<WakelockInfoItem> wakeLocks = new LinkedList<WakelockInfoItem>();
for (WakelockInfoItem wakeLock : mWakeLocks) {
wakeLocks.add(wakeLock);
}
return wakeLocks;
}
/**
* {@inheritDoc}
*/
@Override
public IItem merge(IItem other) throws ConflictingItemException {
throw new ConflictingItemException("Dumpsys battery info items cannot be merged");
throw new ConflictingItemException("Wakelock items cannot be merged");
}
/**
......@@ -199,15 +214,17 @@ public class DumpsysBatteryInfoItem implements IItem {
@Override
public JSONObject toJson() {
JSONObject object = new JSONObject();
if (mWakeLocks != null) {
try {
JSONArray wakeLocks = new JSONArray();
for (WakeLock wakeLock : mWakeLocks) {
for (WakelockInfoItem wakeLock : mWakeLocks) {
wakeLocks.put(wakeLock.toJson());
}
object.put(WAKELOCKS, wakeLocks);
} catch (JSONException e) {
// Ignore
}
}
return object;
}
}
/*
* 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.BatteryStatsDetailedInfoItem;
import com.android.loganalysis.item.InterruptItem;
import com.android.loganalysis.item.ProcessUsageItem;
import com.android.loganalysis.item.WakelockItem;
import com.android.loganalysis.util.NumberFormattingUtil;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link IParser} to parse the battery stats section of the bugreport
*/
public class BatteryStatsDetailedInfoParser extends AbstractSectionParser {
private static final String WAKELOCK_SECTION_REGEX = "^\\s*All kernel wake locks:$";
private static final String INTERRUPT_SECTION_REGEX = "^\\s*All wakeup reasons:$";
private static final String PROCESS_USAGE_SECTION_REGEX = "^\\s*0:$";
/**
* Matches: Time on battery: 7h 45m 54s 332ms (98.3%) realtime, 4h 40m 51s 315ms (59.3%) uptime
*/
private static final Pattern TIME_ON_BATTERY_PATTERN = Pattern.compile(
"^\\s*Time on battery: (?:(\\d+)d)?\\s?(?:(\\d+)h)?\\s?(?:(\\d+)m)?\\s?(?:(\\d+)s)?" +
"\\s?(?:(\\d+)ms)?.*");
/**
* Matches:Time on battery screen off: 1d 4h 6m 16s 46ms (99.1%) realtime, 6h 37m 49s 201ms
*/
private static final Pattern SCREEN_OFF_TIME_PATTERN = Pattern.compile("^\\s*Time on battery "
+ "screen off: (?:(\\d+)d)?\\s?(?:(\\d+)h)?\\s?(?:(\\d+)m)?\\s?(?:(\\d+)s)?\\s?"
+ "(?:(\\d+)ms).*");
private WakelockParser mWakelockParser = new WakelockParser();
private InterruptParser mInterruptParser = new InterruptParser();
private ProcessUsageParser mProcessUsageParser = new ProcessUsageParser();
private IParser mBatteryTimeParser = new IParser() {
@Override
public BatteryStatsDetailedInfoItem parse(List<String> lines) {
BatteryStatsDetailedInfoItem detailedInfo = null;
long timeOnBattery = 0, screenOffTime = 0;
Matcher m = null;
for (String line : lines) {
if (detailedInfo == null && !"".equals(line.trim())) {
detailedInfo = new BatteryStatsDetailedInfoItem();
}
m = TIME_ON_BATTERY_PATTERN.matcher(line);
if (m.matches()) {
timeOnBattery = NumberFormattingUtil.getMs(
NumberFormattingUtil.parseIntOrZero(m.group(1)),
NumberFormattingUtil.parseIntOrZero(m.group(2)),
NumberFormattingUtil.parseIntOrZero(m.group(3)),
NumberFormattingUtil.parseIntOrZero(m.group(4)),
NumberFormattingUtil.parseIntOrZero(m.group(5)));
detailedInfo.setTimeOnBattery(timeOnBattery);
} else {
m = SCREEN_OFF_TIME_PATTERN.matcher(line);
if (m.matches()) {
screenOffTime = NumberFormattingUtil.getMs(
NumberFormattingUtil.parseIntOrZero(m.group(1)),
NumberFormattingUtil.parseIntOrZero(m.group(2)),
NumberFormattingUtil.parseIntOrZero(m.group(3)),
NumberFormattingUtil.parseIntOrZero(m.group(4)),
NumberFormattingUtil.parseIntOrZero(m.group(5)));
detailedInfo.setScreenOnTime(getScreenOnTime(timeOnBattery, screenOffTime));
return detailedInfo;
}
}
}
return detailedInfo;
}
private long getScreenOnTime(long timeOnBattery, long screenOffTime) {
if (timeOnBattery > screenOffTime) {
return (timeOnBattery - screenOffTime);
}
return 0;
}
};
private BatteryStatsDetailedInfoItem mBatteryStatsDetailedInfoItem = null;
private boolean mParsedInput = false;
/**
* {@inheritDoc}
*
* @return The {@link BatteryStatsDetailedInfoItem}
*/
@Override
public BatteryStatsDetailedInfoItem parse(List<String> lines) {
setup();
for (String line : lines) {
if (!mParsedInput && !"".equals(line.trim())) {
mParsedInput = true;
}
parseLine(line);
}
commit();
return mBatteryStatsDetailedInfoItem;
}
/**
* Sets up the parser by adding the section parsers.
*/
protected void setup() {
setParser(mBatteryTimeParser);
addSectionParser(mWakelockParser, WAKELOCK_SECTION_REGEX);
addSectionParser(mInterruptParser, INTERRUPT_SECTION_REGEX);
addSectionParser(mProcessUsageParser, PROCESS_USAGE_SECTION_REGEX);
}
/**
* Set the {@link BatteryStatsDetailedInfoItem}
*
*/
@Override
protected void onSwitchParser() {
if (mBatteryStatsDetailedInfoItem == null) {
mBatteryStatsDetailedInfoItem = (BatteryStatsDetailedInfoItem)
getSection(mBatteryTimeParser);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void commit() {
// signal EOF
super.commit();
if (mParsedInput) {
if (mBatteryStatsDetailedInfoItem == null) {
mBatteryStatsDetailedInfoItem = new BatteryStatsDetailedInfoItem();
}
}
if (mBatteryStatsDetailedInfoItem != null) {
mBatteryStatsDetailedInfoItem.setWakelockItem(
(WakelockItem) getSection(mWakelockParser));
mBatteryStatsDetailedInfoItem.setInterruptItem(
(InterruptItem) getSection(mInterruptParser));
mBatteryStatsDetailedInfoItem.setProcessUsageItem(
(ProcessUsageItem) getSection(mProcessUsageParser));
}
}
}
/*
* 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;
}
}
/*
* Copyright (C) 2013 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.DumpsysBatteryInfoItem;
import com.android.loganalysis.item.DumpsysBatteryInfoItem.WakeLockCategory;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link IParser} to handle the "dumpsys batteryinfo" command output.
*/
public class DumpsysBatteryInfoParser implements IParser {
private static final Pattern LAST_CHARGED_START_PAT = Pattern.compile(
"^Statistics since last charge:$");
private static final Pattern LAST_UNPLUGGED_START_PAT = Pattern.compile(
"^Statistics since last unplugged:$");
private static final Pattern WAKE_LOCK_START_PAT = Pattern.compile(
"^ All partial wake locks:$");
private static final String WAKE_LOCK_PAT_SUFFIX =
"((\\d+)d )?((\\d+)h )?((\\d+)m )?((\\d+)s )?((\\d+)ms )?\\((\\d+) times\\) realtime";
/**
* Match a valid line such as:
* " Kernel Wake lock \"Process\": 1d 2h 3m 4s 5ms (6 times) realtime";
*/
private static final Pattern KERNEL_WAKE_LOCK_PAT = Pattern.compile(
"^ Kernel Wake lock \"([^\"]+)\": " + WAKE_LOCK_PAT_SUFFIX);
/**
* Match a valid line such as:
* " Wake lock #1234 Process: 1d 2h 3m 4s 5ms (6 times) realtime";
*/
private static final Pattern WAKE_LOCK_PAT = Pattern.compile(
"^ Wake lock #(\\d+) (.+): " + WAKE_LOCK_PAT_SUFFIX);
private DumpsysBatteryInfoItem mItem = new DumpsysBatteryInfoItem();
/**
* {@inheritDoc}
*/
@Override
public DumpsysBatteryInfoItem parse(List<String> lines) {
WakeLockCategory kernelWakeLockCategory = null;
WakeLockCategory wakeLockCategory = null;
boolean inKernelWakeLock = false;
boolean inWakeLock = false;
// Look for the section for last unplugged statistics. Kernel wakelocks are in the lines
// immediately following, until a blank line. Partial wake locks are in their own block,
// until a blank line. Return immediately after since there is nothing left to parse.
for (String line : lines) {
if (kernelWakeLockCategory == null || wakeLockCategory == null) {
Matcher m = LAST_CHARGED_START_PAT.matcher(line);
if (m.matches()) {
kernelWakeLockCategory = WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK;
wakeLockCategory = WakeLockCategory.LAST_CHARGE_WAKELOCK;
inKernelWakeLock = true;
}
m = LAST_UNPLUGGED_START_PAT.matcher(line);
if (m.matches()) {
kernelWakeLockCategory = WakeLockCategory.LAST_UNPLUGGED_KERNEL_WAKELOCK;
wakeLockCategory = WakeLockCategory.LAST_UNPLUGGED_WAKELOCK;
inKernelWakeLock = true;
}
} else {
if (inKernelWakeLock) {
if ("".equals(line.trim())) {
inKernelWakeLock = false;
} else {
parseKernelWakeLock(line, kernelWakeLockCategory);
}
} else if (inWakeLock) {
if ("".equals(line.trim())) {
inWakeLock = false;
kernelWakeLockCategory = null;
wakeLockCategory = null;
} else {
parseWakeLock(line, wakeLockCategory);
}
} else {
Matcher m = WAKE_LOCK_START_PAT.matcher(line);
if (m.matches()) {
inWakeLock = true;
}
}
}
}
return mItem;
}
/**
* Parse a line of output and add it to the last unplugged kernel wake lock section.
* <p>
* Exposed for unit testing.
* </p>
*/
void parseKernelWakeLock(String line, WakeLockCategory category) {
Matcher m = KERNEL_WAKE_LOCK_PAT.matcher(line);
if (!m.matches()) {
return;
}
final String name = m.group(1);
final long days = parseLongOrZero(m.group(3));
final long hours = parseLongOrZero(m.group(5));
final long mins = parseLongOrZero(m.group(7));
final long secs = parseLongOrZero(m.group(9));
final long msecs = parseLongOrZero(m.group(11));
final int timesCalled = Integer.parseInt(m.group(12));
mItem.addWakeLock(name, getMs(days, hours, mins, secs, msecs), timesCalled, category);
}
/**
* Parse a line of output and add it to the last unplugged wake lock section.
* <p>
* Exposed for unit testing.
* </p>
*/
void parseWakeLock(String line, WakeLockCategory category) {
Matcher m = WAKE_LOCK_PAT.matcher(line);
if (!m.matches()) {
return;
}
final int number = Integer.parseInt(m.group(1));
final String name = m.group(2);
final long days = parseLongOrZero(m.group(4));
final long hours = parseLongOrZero(m.group(6));
final long mins = parseLongOrZero(m.group(8));
final long secs = parseLongOrZero(m.group(10));
final long msecs = parseLongOrZero(m.group(12));
final int timesCalled = Integer.parseInt(m.group(13));
mItem.addWakeLock(name, number, getMs(days, hours, mins, secs, msecs), timesCalled,
category);
}
/**
* Get the {@link DumpsysBatteryInfoItem}.
* <p>
* Exposed for unit testing.
* </p>
*/
DumpsysBatteryInfoItem getItem() {
return mItem;
}
/**
* Convert days/hours/mins/secs/msecs into milliseconds.
* <p>
* Exposed for unit testing.
* </p>
*/
static long getMs(long days, long hours, long mins, long secs, long msecs) {
return (((24 * days + hours) * 60 + mins) * 60 + secs) * 1000 + msecs;
}
/**
* Parses a string into a long, or returns 0 if the string is null.
*
* @param s a {@link String} containing the long representation to be parsed
* @return the long represented by the argument in decimal, or 0 if the string is {@code null}.
* @throws NumberFormatException if the string is not {@code null} or does not contain a
* parsable long.
*/
private long parseLongOrZero(String s) {
if (s == null) {
return 0;
}
return Long.parseLong(s);
}
}
/*
* 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.BatteryStatsDetailedInfoItem;
import com.android.loganalysis.item.DumpsysBatteryStatsItem;
import com.android.loganalysis.item.BatteryStatsSummaryInfoItem;
import java.util.List;
/**
* A {@link IParser} to parse the battery stats section of the bugreport
*/
public class DumpsysBatteryStatsParser extends AbstractSectionParser {
private static final String SUMMARY_INFO_SECTION_REGEX =
"Battery History \\(\\d+% used, \\d+KB used of \\d+KB, \\d+ strings using \\d+KB\\):$";
private static final String DETAILED_INFO_SECTION_REGEX = "^Statistics since last charge:$";
private static final String NOOP_SECTION_REGEX = "^Statistics since last unplugged:$";
private BatteryStatsSummaryInfoParser mSummaryParser = new BatteryStatsSummaryInfoParser();
private BatteryStatsDetailedInfoParser mDetailedParser = new BatteryStatsDetailedInfoParser();
private DumpsysBatteryStatsItem mDumpsysBatteryStatsItem = null;
private boolean mParsedInput = false;
/**
* {@inheritDoc}
*
* @return The {@link DumpsysBatteryStatsItem}
*/
@Override
public DumpsysBatteryStatsItem parse(List<String> lines) {
setup();
for (String line : lines) {
if (!mParsedInput && !"".equals(line.trim())) {
mParsedInput = true;
}
parseLine(line);
}
commit();
return mDumpsysBatteryStatsItem;
}
/**
* Sets up the parser by adding the section parsers.
*/
protected void setup() {
addSectionParser(mSummaryParser, SUMMARY_INFO_SECTION_REGEX);
addSectionParser(mDetailedParser, DETAILED_INFO_SECTION_REGEX);
addSectionParser(new NoopParser(), NOOP_SECTION_REGEX);
}
/**
* {@inheritDoc}
*/
@Override
protected void commit() {
// signal EOF
super.commit();
if (mParsedInput) {
if (mDumpsysBatteryStatsItem == null) {
mDumpsysBatteryStatsItem = new DumpsysBatteryStatsItem();
}
}
if (mDumpsysBatteryStatsItem != null) {
mDumpsysBatteryStatsItem.setBatteryStatsSummarytem(
(BatteryStatsSummaryInfoItem) getSection(mSummaryParser));
mDumpsysBatteryStatsItem.setDetailedBatteryStatsItem(
(BatteryStatsDetailedInfoItem) getSection(mDetailedParser));
}
}
}
......@@ -15,8 +15,10 @@
*/
package com.android.loganalysis.parser;
import com.android.loganalysis.item.DumpsysBatteryInfoItem;
import com.android.loganalysis.item.DumpsysBatteryStatsItem;
import com.android.loganalysis.item.DumpsysItem;
import com.android.loganalysis.item.DumpsysProcStatsItem;
import java.util.List;
......@@ -24,10 +26,14 @@ import java.util.List;
* A {@link IParser} to handle the output of the dumpsys section of the bugreport.
*/
public class DumpsysParser extends AbstractSectionParser {
private static final String BATTERY_INFO_SECTION_REGEX = "DUMP OF SERVICE batteryinfo:";
private static final String BATTERY_STATS_SECTION_REGEX = "^DUMP OF SERVICE batterystats:$";
private static final String PROC_STATS_SECTION_REGEX = "^DUMP OF SERVICE procstats:";
private static final String NOOP_SECTION_REGEX = "DUMP OF SERVICE .*";
private DumpsysBatteryInfoParser mBatteryInfoParser = new DumpsysBatteryInfoParser();
private DumpsysBatteryStatsParser mBatteryStatsParser = new DumpsysBatteryStatsParser();
private DumpsysProcStatsParser mProcStatsParser = new DumpsysProcStatsParser();
private DumpsysItem mDumpsys = null;
/**
......@@ -53,7 +59,8 @@ public class DumpsysParser extends AbstractSectionParser {
* Sets up the parser by adding the section parsers.
*/
protected void setup() {
addSectionParser(mBatteryInfoParser, BATTERY_INFO_SECTION_REGEX);
addSectionParser(mBatteryStatsParser, BATTERY_STATS_SECTION_REGEX);
addSectionParser(mProcStatsParser, PROC_STATS_SECTION_REGEX);
addSectionParser(new NoopParser(), NOOP_SECTION_REGEX);
}
......@@ -64,10 +71,12 @@ public class DumpsysParser extends AbstractSectionParser {
protected void commit() {
// signal EOF
super.commit();
if (mDumpsys == null) {
mDumpsys = new DumpsysItem();
}
if (mDumpsys != null) {
mDumpsys.setBatteryInfo(
(DumpsysBatteryInfoItem) getSection(mBatteryInfoParser));
mDumpsys.setBatteryInfo((DumpsysBatteryStatsItem) getSection(mBatteryStatsParser));
mDumpsys.setProcStats((DumpsysProcStatsItem) getSection(mProcStatsParser));
}
}
}
/*
* Copyright (C) 2011 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.DumpsysProcStatsItem;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link IParser} to parse procstats and create a mapping table of process names and UIDs
*/
public class DumpsysProcStatsParser implements IParser {
/**
* Matches: * com.google.android.googlequicksearchbox:search / u0a19 / v300401240: -----
*/
private static final Pattern UID = Pattern.compile("^\\s*\\* (.*):?.*/ (.*)/.*");
/**
* {@inheritDoc}
*
* @return The {@link DumpsysProcStatsItem}.
*/
@Override
public DumpsysProcStatsItem parse(List<String> lines) {
DumpsysProcStatsItem item = new DumpsysProcStatsItem();
for (String line : lines) {
Matcher m = UID.matcher(line);
if(m.matches()) {
item.put(m.group(2).trim(), m.group(1).trim());
}
}
return item;
}
}
/*
* 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.InterruptItem;
import com.android.loganalysis.item.InterruptItem.InterruptCategory;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link IParser} to parse wake up interrupts
*/
public class InterruptParser implements IParser {
/**
* Matches: Wakeup reason 289:bcmsdh_sdmmc:200:qcom,smd-rpm:240:msmgpio:
* 20m 5s 194ms (1485 times) realtime
*/
private static final Pattern Interrupt = Pattern.compile(
"^\\s*Wakeup reason (.*): (?:\\d+h )?(?:\\d+m )?(?:\\d+s )(?:\\d+ms )" +
"\\((\\d+) times\\) realtime");
private InterruptItem mItem = new InterruptItem();
/**
* {@inheritDoc}
*
* @return The {@link InterruptItem}.
*/
@Override
public InterruptItem parse(List<String> lines) {
for (String line : lines) {
Matcher m = Interrupt.matcher(line);
if(m.matches()) {
final String interruptName = m.group(1);
final int interruptCount = Integer.parseInt(m.group(2));
mItem.addInterrupt(interruptName, interruptCount,
getInterruptCategory(interruptName));
} else {
// Done with interrupts
break;
}
}
return mItem;
}
/**
* Get the {@link InterruptItem}.
* <p>
* Exposed for unit testing.
* </p>
*/
InterruptItem getItem() {
return mItem;
}
private InterruptCategory getInterruptCategory(String interruptName) {
if (interruptName.contains("bcmsdh_sdmmc")) {
return InterruptCategory.WIFI_INTERRUPT;
} else if (interruptName.contains("smd-modem") ||
interruptName.contains("smsm-modem")) {
return InterruptCategory.MODEM_INTERRUPT;
} else if (interruptName.contains("smd-adsp")) {
return InterruptCategory.ADSP_INTERRUPT;
} else if (interruptName.contains("max77686-irq") ||
interruptName.contains("cpcap-irq") ||
interruptName.contains("TWL6030-PIH")) {
return InterruptCategory.ALARM_INTERRUPT;
}
return InterruptCategory.UNKNOWN_INTERRUPT;
}
}
/*
* 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.ProcessUsageItem;
import com.android.loganalysis.item.ProcessUsageItem.SensorInfoItem;
import com.android.loganalysis.util.NumberFormattingUtil;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link IParser} to handle the parsing of process usage information
*/
public class ProcessUsageParser implements IParser {
private ProcessUsageItem mItem = new ProcessUsageItem();
private LinkedList<SensorInfoItem> mSensorUsage = new LinkedList<SensorInfoItem>();
/**
* Matches: 1000:
*/
private static final Pattern UID_PATTERN = Pattern.compile("^\\s*(\\w+):$");
/**
* Matches: Sensor 1: 12m 52s 311ms realtime (29 times)
*/
private static final Pattern SENSOR_PATTERN = Pattern.compile(
"^\\s*Sensor (\\d+): (?:(\\d+)d\\s)?"
+ "(?:(\\d+)h\\s)?(?:(\\d+)m\\s)?(?:(\\d+)s\\s)?(\\d+)ms "
+ "realtime \\((\\d+) times\\)$");
/**
* Matches: 507 wakeup alarms
*/
private static final Pattern ALARM_PATTERN = Pattern.compile("^\\s*(\\d+) wakeup alarms$");
/**
* {@inheritDoc}
*/
@Override
public ProcessUsageItem parse(List<String> lines) {
String processUid = null;
int alarmWakeups = 0;
for (String line : lines) {
Matcher m = UID_PATTERN.matcher(line);
if (m.matches()) {
if (processUid != null) {
// Save the process usage info for the previous process
mItem.addProcessUsage(processUid, alarmWakeups, mSensorUsage);
}
processUid = m.group(1);
mSensorUsage = new LinkedList<SensorInfoItem>();
continue;
}
m = SENSOR_PATTERN.matcher(line);
if (m.matches()) {
final long duration = NumberFormattingUtil.getMs(
NumberFormattingUtil.parseIntOrZero(m.group(2)),
NumberFormattingUtil.parseIntOrZero(m.group(3)),
NumberFormattingUtil.parseIntOrZero(m.group(4)),
NumberFormattingUtil.parseIntOrZero(m.group(5)),
NumberFormattingUtil.parseIntOrZero(m.group(6)));
mSensorUsage.add(new SensorInfoItem(m.group(1), duration));
continue;
}
m = ALARM_PATTERN.matcher(line);
if (m.matches()) {
alarmWakeups = Integer.parseInt(m.group(1));
}
}
return mItem;
}
/**
* Get the {@link ProcessUsageItem}.
* <p>
* Exposed for unit testing.
* </p>
*/
ProcessUsageItem getItem() {
return mItem;
}
}
/*
* 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.WakelockItem;
import com.android.loganalysis.item.WakelockItem.WakeLockCategory;
import com.android.loganalysis.util.NumberFormattingUtil;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link IParser} to handle the parsing of wakelock information
*/
public class WakelockParser implements IParser {
private static final Pattern PARTIAL_WAKE_LOCK_START_PAT = Pattern.compile(
"^\\s*All partial wake locks:$");
private static final String WAKE_LOCK_PAT_SUFFIX =
"(?:(\\d+)d)?\\s?(?:(\\d+)h)?\\s?(?:(\\d+)m)?\\s?(?:(\\d+)s)?\\s?(?:(\\d+)ms)?"
+ "\\s?\\((\\d+) times\\) realtime";
/**
* Match a valid line such as:
* " Kernel Wake lock PowerManagerService.WakeLocks: 1h 13m 50s 950ms (2858 times) realtime"
*/
private static final Pattern KERNEL_WAKE_LOCK_PAT = Pattern.compile(
"^\\s*Kernel Wake lock (.+): " + WAKE_LOCK_PAT_SUFFIX);
/**
* Match a valid line such as:
* " Wake lock u0a7 NlpWakeLock: 8m 13s 203ms (1479 times) realtime";
*/
private static final Pattern PARTIAL_WAKE_LOCK_PAT = Pattern.compile(
"^\\s*Wake lock (.*)\\s(.+): " + WAKE_LOCK_PAT_SUFFIX);
private WakelockItem mItem = new WakelockItem();
public static final int TOP_WAKELOCK_COUNT = 5;
/**
* {@inheritDoc}
*/
@Override
public WakelockItem parse(List<String> lines) {
boolean inPartialWakeLock = false;
Matcher m = null;
int wakelockCounter = 0;
for (String line : lines) {
if ("".equals(line.trim())) {
if (inPartialWakeLock) {
// Done with parsing wakelock sections
break;
} else {
// Done with parsing kernel wakelocks and continue with
// partial wakelock
wakelockCounter = 0;
continue;
}
}
m = KERNEL_WAKE_LOCK_PAT.matcher(line);
if (m.matches()) {
if (wakelockCounter < TOP_WAKELOCK_COUNT &&
!line.contains("PowerManagerService.WakeLocks")) {
parseKernelWakeLock(line, WakeLockCategory.KERNEL_WAKELOCK);
wakelockCounter++;
}
continue;
}
m = PARTIAL_WAKE_LOCK_START_PAT.matcher(line);
if (m.matches()) {
inPartialWakeLock = true;
continue;
}
m = PARTIAL_WAKE_LOCK_PAT.matcher(line);
if (m.matches() && wakelockCounter < TOP_WAKELOCK_COUNT) {
parsePartialWakeLock(line, WakeLockCategory.PARTIAL_WAKELOCK);
wakelockCounter++;
}
}
return mItem;
}
/**
* Parse a line of output and add it to wakelock section
* <p>
* Exposed for unit testing.
* </p>
*/
void parseKernelWakeLock(String line, WakeLockCategory category) {
Matcher m = KERNEL_WAKE_LOCK_PAT.matcher(line);
if (!m.matches()) {
return;
}
final String name = m.group(1);
final long wakelockTime = NumberFormattingUtil.getMs(
NumberFormattingUtil.parseIntOrZero(m.group(2)),
NumberFormattingUtil.parseIntOrZero(m.group(3)),
NumberFormattingUtil.parseIntOrZero(m.group(4)),
NumberFormattingUtil.parseIntOrZero(m.group(5)),
NumberFormattingUtil.parseIntOrZero(m.group(6)));
final int timesCalled = Integer.parseInt(m.group(7));
mItem.addWakeLock(name, wakelockTime, timesCalled, category);
}
/**
* Parse a line of output and add it to wake lock section.
* <p>
* Exposed for unit testing.
* </p>
*/
void parsePartialWakeLock(String line, WakeLockCategory category) {
Matcher m = PARTIAL_WAKE_LOCK_PAT.matcher(line);
if (!m.matches()) {
return;
}
final String processUID = m.group(1);
final String name = m.group(2);
final long wakelockTime = NumberFormattingUtil.getMs(
NumberFormattingUtil.parseIntOrZero(m.group(3)),
NumberFormattingUtil.parseIntOrZero(m.group(4)),
NumberFormattingUtil.parseIntOrZero(m.group(5)),
NumberFormattingUtil.parseIntOrZero(m.group(6)),
NumberFormattingUtil.parseIntOrZero(m.group(7)));
final int timesCalled = Integer.parseInt(m.group(8));
mItem.addWakeLock(name, processUID, wakelockTime, timesCalled, category);
}
/**
* Get the {@link WakelockItem}.
* <p>
* Exposed for unit testing.
* </p>
*/
WakelockItem getItem() {
return mItem;
}
}
/*
* 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.rule;
import com.android.loganalysis.item.BatteryStatsDetailedInfoItem;
import com.android.loganalysis.item.BugreportItem;
import com.android.loganalysis.item.BatteryStatsSummaryInfoItem;
import com.android.loganalysis.item.DumpsysProcStatsItem;
import org.json.JSONObject;
/**
* Base class for all power rules
*/
public abstract class AbstractPowerRule implements IRule {
private BugreportItem mBugreportItem;
private BatteryStatsSummaryInfoItem mPowerSummaryAnalysisItem;
private BatteryStatsDetailedInfoItem mPowerDetailedAnalysisItem;
private DumpsysProcStatsItem mProcStatsItem;
public AbstractPowerRule(BugreportItem bugreportItem) {
mBugreportItem = bugreportItem;
mPowerSummaryAnalysisItem = mBugreportItem.getDumpsys().getBatteryStats().
getBatteryStatsSummaryItem();
mPowerDetailedAnalysisItem = mBugreportItem.getDumpsys().getBatteryStats().
getDetailedBatteryStatsItem();
mProcStatsItem = mBugreportItem.getDumpsys().getProcStats();
}
protected long getTimeOnBattery() {
return mPowerDetailedAnalysisItem.getTimeOnBattery();
}
protected BatteryStatsSummaryInfoItem getSummaryItem() {
return mPowerSummaryAnalysisItem;
}
protected BatteryStatsDetailedInfoItem getDetailedAnalysisItem() {
return mPowerDetailedAnalysisItem;
}
protected DumpsysProcStatsItem getProcStatsItem() {
return mProcStatsItem;
}
@Override
public abstract void applyRule();
@Override
public abstract JSONObject getAnalysis();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment