summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoravellore <avellore@google.com>2015-04-08 00:02:47 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-08 00:02:48 +0000
commit29a6e07bab66064c455db27394147103919bfdb2 (patch)
tree1aeeae65aaa19fc7e2d5a197837a5649f0c7b95b
parentce2941c2e70b3444824f0cfe2883f4b77ad93542 (diff)
parentf11cbc4985b91b25d9e967cb7438fd8af80faa5c (diff)
downloadloganalysis-marshmallow-dr-dev.tar.gz
Merge "Battery drain investigator"android-wear-n-preview-3android-wear-n-preview-2android-wear-n-preview-1android-wear-7.1.1_r1android-n-preview-5android-n-preview-4android-n-preview-3android-n-preview-2android-n-preview-1android-n-iot-preview-2android-cts-6.0_r9android-cts-6.0_r8android-cts-6.0_r7android-cts-6.0_r6android-cts-6.0_r5android-cts-6.0_r4android-cts-6.0_r32android-cts-6.0_r31android-cts-6.0_r30android-cts-6.0_r3android-cts-6.0_r29android-cts-6.0_r28android-cts-6.0_r27android-cts-6.0_r26android-cts-6.0_r25android-cts-6.0_r24android-cts-6.0_r23android-cts-6.0_r22android-cts-6.0_r21android-cts-6.0_r20android-cts-6.0_r2android-cts-6.0_r19android-cts-6.0_r18android-cts-6.0_r17android-cts-6.0_r16android-cts-6.0_r15android-cts-6.0_r14android-cts-6.0_r13android-cts-6.0_r12android-cts-6.0_r1android-6.0.1_r9android-6.0.1_r81android-6.0.1_r80android-6.0.1_r8android-6.0.1_r79android-6.0.1_r78android-6.0.1_r77android-6.0.1_r74android-6.0.1_r73android-6.0.1_r72android-6.0.1_r70android-6.0.1_r7android-6.0.1_r69android-6.0.1_r68android-6.0.1_r67android-6.0.1_r66android-6.0.1_r65android-6.0.1_r63android-6.0.1_r62android-6.0.1_r61android-6.0.1_r60android-6.0.1_r59android-6.0.1_r58android-6.0.1_r57android-6.0.1_r56android-6.0.1_r55android-6.0.1_r54android-6.0.1_r53android-6.0.1_r52android-6.0.1_r51android-6.0.1_r50android-6.0.1_r5android-6.0.1_r49android-6.0.1_r48android-6.0.1_r47android-6.0.1_r46android-6.0.1_r45android-6.0.1_r43android-6.0.1_r42android-6.0.1_r41android-6.0.1_r40android-6.0.1_r4android-6.0.1_r33android-6.0.1_r32android-6.0.1_r31android-6.0.1_r30android-6.0.1_r3android-6.0.1_r28android-6.0.1_r27android-6.0.1_r26android-6.0.1_r25android-6.0.1_r24android-6.0.1_r22android-6.0.1_r21android-6.0.1_r20android-6.0.1_r18android-6.0.1_r17android-6.0.1_r16android-6.0.1_r13android-6.0.1_r12android-6.0.1_r11android-6.0.1_r10android-6.0.1_r1android-6.0.0_r7android-6.0.0_r6android-6.0.0_r5android-6.0.0_r41android-6.0.0_r4android-6.0.0_r3android-6.0.0_r26android-6.0.0_r25android-6.0.0_r24android-6.0.0_r23android-6.0.0_r2android-6.0.0_r13android-6.0.0_r12android-6.0.0_r11android-6.0.0_r1nougat-mr1-wear-releasen-iot-preview-2marshmallow-releasemarshmallow-mr3-releasemarshmallow-mr2-releasemarshmallow-mr1-releasemarshmallow-mr1-devmarshmallow-dr1.6-releasemarshmallow-dr1.5-releasemarshmallow-dr1.5-devmarshmallow-dr-releasemarshmallow-dr-dragon-releasemarshmallow-dr-devmarshmallow-devmarshmallow-cts-release
-rw-r--r--src/com/android/loganalysis/LogAnalyzer.java91
-rw-r--r--src/com/android/loganalysis/item/BatteryDischargeItem.java137
-rw-r--r--src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java156
-rw-r--r--src/com/android/loganalysis/item/BatteryStatsSummaryInfoItem.java69
-rw-r--r--src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java97
-rw-r--r--src/com/android/loganalysis/item/DumpsysItem.java35
-rw-r--r--src/com/android/loganalysis/item/DumpsysProcStatsItem.java24
-rw-r--r--src/com/android/loganalysis/item/InterruptItem.java162
-rw-r--r--src/com/android/loganalysis/item/ProcessUsageItem.java199
-rw-r--r--src/com/android/loganalysis/item/WakelockItem.java (renamed from src/com/android/loganalysis/item/DumpsysBatteryInfoItem.java)103
-rw-r--r--src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java165
-rw-r--r--src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParser.java181
-rw-r--r--src/com/android/loganalysis/parser/DumpsysBatteryInfoParser.java189
-rw-r--r--src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java89
-rw-r--r--src/com/android/loganalysis/parser/DumpsysParser.java23
-rw-r--r--src/com/android/loganalysis/parser/DumpsysProcStatsParser.java51
-rw-r--r--src/com/android/loganalysis/parser/InterruptParser.java89
-rw-r--r--src/com/android/loganalysis/parser/ProcessUsageParser.java99
-rw-r--r--src/com/android/loganalysis/parser/WakelockParser.java155
-rw-r--r--src/com/android/loganalysis/rule/AbstractPowerRule.java67
-rw-r--r--src/com/android/loganalysis/rule/IRule.java29
-rw-r--r--src/com/android/loganalysis/rule/ProcessUsageRule.java76
-rw-r--r--src/com/android/loganalysis/rule/RuleEngine.java70
-rw-r--r--src/com/android/loganalysis/rule/WakelockRule.java71
-rw-r--r--src/com/android/loganalysis/util/NumberFormattingUtil.java94
-rw-r--r--tests/src/com/android/loganalysis/UnitTests.java18
-rw-r--r--tests/src/com/android/loganalysis/item/BatteryDischargeItemTest.java56
-rw-r--r--tests/src/com/android/loganalysis/item/DumpsysBatteryInfoItemTest.java68
-rw-r--r--tests/src/com/android/loganalysis/item/InterruptItemTest.java53
-rw-r--r--tests/src/com/android/loganalysis/item/WakelockItemTest.java63
-rw-r--r--tests/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParserTest.java131
-rw-r--r--tests/src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParserTest.java101
-rw-r--r--tests/src/com/android/loganalysis/parser/BugreportParserTest.java26
-rw-r--r--tests/src/com/android/loganalysis/parser/DumpsysBatteryInfoParserTest.java188
-rw-r--r--tests/src/com/android/loganalysis/parser/DumpsysBatteryStatsParserTest.java93
-rw-r--r--tests/src/com/android/loganalysis/parser/DumpsysParserTest.java100
-rw-r--r--tests/src/com/android/loganalysis/parser/DumpsysProcStatsParserTest.java48
-rw-r--r--tests/src/com/android/loganalysis/parser/InterruptParserTest.java62
-rw-r--r--tests/src/com/android/loganalysis/parser/ProcessUsageParserTest.java74
-rw-r--r--tests/src/com/android/loganalysis/parser/WakelockParserTest.java75
40 files changed, 3123 insertions, 554 deletions
diff --git a/src/com/android/loganalysis/LogAnalyzer.java b/src/com/android/loganalysis/LogAnalyzer.java
index 787e58a..a0a49a1 100644
--- a/src/com/android/loganalysis/LogAnalyzer.java
+++ b/src/com/android/loganalysis/LogAnalyzer.java
@@ -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)) {
- printJson(bugreport);
+ 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());
}
diff --git a/src/com/android/loganalysis/item/BatteryDischargeItem.java b/src/com/android/loganalysis/item/BatteryDischargeItem.java
new file mode 100644
index 0000000..cdfcbcc
--- /dev/null
+++ b/src/com/android/loganalysis/item/BatteryDischargeItem.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java b/src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java
new file mode 100644
index 0000000..a1ac0b0
--- /dev/null
+++ b/src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java
@@ -0,0 +1,156 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/com/android/loganalysis/item/BatteryStatsSummaryInfoItem.java b/src/com/android/loganalysis/item/BatteryStatsSummaryInfoItem.java
new file mode 100644
index 0000000..6b07905
--- /dev/null
+++ b/src/com/android/loganalysis/item/BatteryStatsSummaryInfoItem.java
@@ -0,0 +1,69 @@
+/*
+ * 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);
+ }
+}
diff --git a/src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java b/src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java
new file mode 100644
index 0000000..1039324
--- /dev/null
+++ b/src/com/android/loganalysis/item/DumpsysBatteryStatsItem.java
@@ -0,0 +1,97 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/com/android/loganalysis/item/DumpsysItem.java b/src/com/android/loganalysis/item/DumpsysItem.java
index 866c56f..5bd82e2 100644
--- a/src/com/android/loganalysis/item/DumpsysItem.java
+++ b/src/com/android/loganalysis/item/DumpsysItem.java
@@ -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);
}
}
diff --git a/src/com/android/loganalysis/item/DumpsysProcStatsItem.java b/src/com/android/loganalysis/item/DumpsysProcStatsItem.java
new file mode 100644
index 0000000..846f70a
--- /dev/null
+++ b/src/com/android/loganalysis/item/DumpsysProcStatsItem.java
@@ -0,0 +1,24 @@
+/*
+ * 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> {
+
+}
diff --git a/src/com/android/loganalysis/item/InterruptItem.java b/src/com/android/loganalysis/item/InterruptItem.java
new file mode 100644
index 0000000..1169004
--- /dev/null
+++ b/src/com/android/loganalysis/item/InterruptItem.java
@@ -0,0 +1,162 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/com/android/loganalysis/item/ProcessUsageItem.java b/src/com/android/loganalysis/item/ProcessUsageItem.java
new file mode 100644
index 0000000..e2feddb
--- /dev/null
+++ b/src/com/android/loganalysis/item/ProcessUsageItem.java
@@ -0,0 +1,199 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/com/android/loganalysis/item/DumpsysBatteryInfoItem.java b/src/com/android/loganalysis/item/WakelockItem.java
index 8525f94..7bfab4b 100644
--- a/src/com/android/loganalysis/item/DumpsysBatteryInfoItem.java
+++ b/src/com/android/loganalysis/item/WakelockItem.java
@@ -1,5 +1,5 @@
/*
- * 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);
}
@@ -178,11 +181,23 @@ public class DumpsysBatteryInfoItem implements IItem {
}
/**
+ * 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,14 +214,16 @@ public class DumpsysBatteryInfoItem implements IItem {
@Override
public JSONObject toJson() {
JSONObject object = new JSONObject();
- try {
- JSONArray wakeLocks = new JSONArray();
- for (WakeLock wakeLock : mWakeLocks) {
- wakeLocks.put(wakeLock.toJson());
+ if (mWakeLocks != null) {
+ try {
+ JSONArray wakeLocks = new JSONArray();
+ for (WakelockInfoItem wakeLock : mWakeLocks) {
+ wakeLocks.put(wakeLock.toJson());
+ }
+ object.put(WAKELOCKS, wakeLocks);
+ } catch (JSONException e) {
+ // Ignore
}
- object.put(WAKELOCKS, wakeLocks);
- } catch (JSONException e) {
- // Ignore
}
return object;
}
diff --git a/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java b/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java
new file mode 100644
index 0000000..f1bbed0
--- /dev/null
+++ b/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java
@@ -0,0 +1,165 @@
+/*
+ * 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));
+ }
+ }
+}
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;
+ }
+}
diff --git a/src/com/android/loganalysis/parser/DumpsysBatteryInfoParser.java b/src/com/android/loganalysis/parser/DumpsysBatteryInfoParser.java
deleted file mode 100644
index afd4359..0000000
--- a/src/com/android/loganalysis/parser/DumpsysBatteryInfoParser.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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);
- }
-}
diff --git a/src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java b/src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java
new file mode 100644
index 0000000..3e8be2c
--- /dev/null
+++ b/src/com/android/loganalysis/parser/DumpsysBatteryStatsParser.java
@@ -0,0 +1,89 @@
+/*
+ * 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));
+ }
+ }
+}
diff --git a/src/com/android/loganalysis/parser/DumpsysParser.java b/src/com/android/loganalysis/parser/DumpsysParser.java
index e950341..d8941e0 100644
--- a/src/com/android/loganalysis/parser/DumpsysParser.java
+++ b/src/com/android/loganalysis/parser/DumpsysParser.java
@@ -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));
}
}
}
diff --git a/src/com/android/loganalysis/parser/DumpsysProcStatsParser.java b/src/com/android/loganalysis/parser/DumpsysProcStatsParser.java
new file mode 100644
index 0000000..010036b
--- /dev/null
+++ b/src/com/android/loganalysis/parser/DumpsysProcStatsParser.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+ }
+
+}
diff --git a/src/com/android/loganalysis/parser/InterruptParser.java b/src/com/android/loganalysis/parser/InterruptParser.java
new file mode 100644
index 0000000..26417c4
--- /dev/null
+++ b/src/com/android/loganalysis/parser/InterruptParser.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+ }
+
+}
diff --git a/src/com/android/loganalysis/parser/ProcessUsageParser.java b/src/com/android/loganalysis/parser/ProcessUsageParser.java
new file mode 100644
index 0000000..9609cd2
--- /dev/null
+++ b/src/com/android/loganalysis/parser/ProcessUsageParser.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/com/android/loganalysis/parser/WakelockParser.java b/src/com/android/loganalysis/parser/WakelockParser.java
new file mode 100644
index 0000000..91652f7
--- /dev/null
+++ b/src/com/android/loganalysis/parser/WakelockParser.java
@@ -0,0 +1,155 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/com/android/loganalysis/rule/AbstractPowerRule.java b/src/com/android/loganalysis/rule/AbstractPowerRule.java
new file mode 100644
index 0000000..cab46a3
--- /dev/null
+++ b/src/com/android/loganalysis/rule/AbstractPowerRule.java
@@ -0,0 +1,67 @@
+/*
+ * 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();
+
+}
diff --git a/src/com/android/loganalysis/rule/IRule.java b/src/com/android/loganalysis/rule/IRule.java
new file mode 100644
index 0000000..416d7f6
--- /dev/null
+++ b/src/com/android/loganalysis/rule/IRule.java
@@ -0,0 +1,29 @@
+/*
+ * 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 org.json.JSONObject;
+
+/**
+ * An interface which defines the rules. Individual rules will apply the filter on the parsed data
+ * and return the high level analysis in JSON Format
+ */
+public interface IRule {
+ // Apply the rules
+ public void applyRule();
+
+ public JSONObject getAnalysis();
+}
diff --git a/src/com/android/loganalysis/rule/ProcessUsageRule.java b/src/com/android/loganalysis/rule/ProcessUsageRule.java
new file mode 100644
index 0000000..4e15aee
--- /dev/null
+++ b/src/com/android/loganalysis/rule/ProcessUsageRule.java
@@ -0,0 +1,76 @@
+/*
+ * 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.BugreportItem;
+import com.android.loganalysis.item.DumpsysProcStatsItem;
+import com.android.loganalysis.item.ProcessUsageItem;
+import com.android.loganalysis.item.ProcessUsageItem.ProcessUsageInfoItem;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+
+/**
+ * Rules definition for Process usage
+ */
+public class ProcessUsageRule extends AbstractPowerRule {
+
+ private static final String PROCESS_USAGE_ANALYSIS = "PROCESS_USAGE_ANALYSIS";
+ private static final long ALARM_THRESHOLD = 60000;
+
+ private StringBuffer mAnalysisBuffer;
+
+ public ProcessUsageRule (BugreportItem bugreportItem) {
+ super(bugreportItem);
+ }
+
+
+ @Override
+ public void applyRule() {
+ mAnalysisBuffer = new StringBuffer();
+ ProcessUsageItem processUsageItem = getDetailedAnalysisItem().getProcessUsageItem();
+ DumpsysProcStatsItem procStatsItem = getProcStatsItem();
+ if (processUsageItem != null && procStatsItem!= null) {
+ for (ProcessUsageInfoItem usage : processUsageItem.getProcessUsage()) {
+ if (usage.getAlarmWakeups() > 0) {
+ final long alarmsPerMs = getTimeOnBattery()/usage.getAlarmWakeups();
+ if (alarmsPerMs < ALARM_THRESHOLD) {
+ final String processName = procStatsItem.get(usage.getProcessUID());
+ if (processName != null) {
+ mAnalysisBuffer.append(processName);
+ } else {
+ mAnalysisBuffer.append(usage.getProcessUID());
+ }
+ mAnalysisBuffer.append(" has requested frequent repeating alarms");
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public JSONObject getAnalysis() {
+ JSONObject usageAnalysis = new JSONObject();
+ try {
+ usageAnalysis.put(PROCESS_USAGE_ANALYSIS, mAnalysisBuffer.toString());
+ } catch (JSONException e) {
+ // do nothing
+ }
+ return usageAnalysis;
+ }
+}
diff --git a/src/com/android/loganalysis/rule/RuleEngine.java b/src/com/android/loganalysis/rule/RuleEngine.java
new file mode 100644
index 0000000..add61e6
--- /dev/null
+++ b/src/com/android/loganalysis/rule/RuleEngine.java
@@ -0,0 +1,70 @@
+/*
+ * 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.BugreportItem;
+
+import org.json.JSONArray;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+
+/**
+ * Applies rules to the parsed bugreport
+ */
+public class RuleEngine {
+
+ public enum RuleType{
+ ALL, POWER;
+ }
+
+ BugreportItem mBugreportItem;
+ private Collection<IRule> mRulesList;
+
+ public RuleEngine(BugreportItem bugreportItem) {
+ mBugreportItem = bugreportItem;
+ mRulesList = new LinkedList<IRule>();
+ }
+
+ public void registerRules(RuleType ruleType) {
+ if (ruleType == RuleType.ALL) {
+ // add all rules
+ addPowerRules();
+ } else if (ruleType == RuleType.POWER) {
+ addPowerRules();
+ }
+ }
+
+ public void executeRules() {
+ for (IRule rule : mRulesList) {
+ rule.applyRule();
+ }
+ }
+
+ public JSONArray getAnalysis() {
+ JSONArray result = new JSONArray();
+ for (IRule rule : mRulesList) {
+ result.put(rule.getAnalysis());
+ }
+ return result;
+ }
+
+ private void addPowerRules() {
+ mRulesList.add(new WakelockRule(mBugreportItem));
+ mRulesList.add(new ProcessUsageRule(mBugreportItem));
+ }
+}
diff --git a/src/com/android/loganalysis/rule/WakelockRule.java b/src/com/android/loganalysis/rule/WakelockRule.java
new file mode 100644
index 0000000..b2db2cd
--- /dev/null
+++ b/src/com/android/loganalysis/rule/WakelockRule.java
@@ -0,0 +1,71 @@
+/*
+ * 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.BugreportItem;
+import com.android.loganalysis.item.WakelockItem;
+import com.android.loganalysis.item.WakelockItem.WakelockInfoItem;
+import com.android.loganalysis.util.NumberFormattingUtil;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Rules definition for wakelock
+ */
+public class WakelockRule extends AbstractPowerRule {
+
+ private static final String WAKELOCK_ANALYSIS = "WAKELOCK_ANALYSIS";
+ private static final float WAKELOCK_HELD_TIME_THRESHOLD_PERCENTAGE = 0.1f; // 10%
+
+ private String mAnalysis = null;
+
+ public WakelockRule (BugreportItem bugreportItem) {
+ super(bugreportItem);
+ }
+
+ @SuppressWarnings("cast")
+ @Override
+ public void applyRule() {
+ WakelockItem wakelockItem = getDetailedAnalysisItem().getWakelockItem();
+ if (wakelockItem != null) {
+ long wakelockThreshold = (long)(getTimeOnBattery()
+ * WAKELOCK_HELD_TIME_THRESHOLD_PERCENTAGE);
+
+ for (WakelockInfoItem wakelocks : wakelockItem.getWakeLocks()) {
+ if (wakelocks.getHeldTime() > wakelockThreshold) {
+ mAnalysis = String.format("%s %s is held for %s", wakelocks.getName(),
+ wakelocks.getCategory(),
+ NumberFormattingUtil.getDuration(wakelocks.getHeldTime()));
+ }
+ }
+ }
+ }
+
+ @Override
+ public JSONObject getAnalysis() {
+ JSONObject wakelockAnalysis = new JSONObject();
+ try {
+ if (mAnalysis != null) {
+ wakelockAnalysis.put(WAKELOCK_ANALYSIS, mAnalysis);
+ }
+ } catch (JSONException e) {
+ // do nothing
+ }
+ return wakelockAnalysis;
+ }
+}
diff --git a/src/com/android/loganalysis/util/NumberFormattingUtil.java b/src/com/android/loganalysis/util/NumberFormattingUtil.java
new file mode 100644
index 0000000..8652c2e
--- /dev/null
+++ b/src/com/android/loganalysis/util/NumberFormattingUtil.java
@@ -0,0 +1,94 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.TimeUnit;
+
+
+
+/**
+ * Utility methods for number formatting
+ */
+public class NumberFormattingUtil {
+
+ private NumberFormattingUtil() {
+ }
+
+ /**
+ * Convert days/hours/mins/secs/msecs into milliseconds.
+ */
+ public static long getMs(long days, long hours, long mins, long secs, long msecs) {
+ return (((24 * days + hours) * 60 + mins) * 60 + secs) * 1000 + msecs;
+ }
+
+ /**
+ * Convert hours/mins/secs/msecs into milliseconds.
+ */
+ public static long getMs(long hours, long mins, long secs, long msecs) {
+ return getMs(0, hours, mins, secs, 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.
+ */
+ public static long parseLongOrZero(String s) throws NumberFormatException {
+ if (s == null) {
+ return 0;
+ }
+ return Long.parseLong(s);
+ }
+
+ /**
+ * Parses a string into a int, or returns 0 if the string is null.
+ *
+ * @param s a {@link String} containing the int representation to be parsed
+ * @return the int 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.
+ */
+ public static int parseIntOrZero(String s) throws NumberFormatException {
+ if (s == null) {
+ return 0;
+ }
+ return Integer.parseInt(s);
+ }
+
+ /**
+ * Converts milliseconds to days/hours/mins/secs
+ *
+ * @param ms elapsed time in ms
+ * @return the duration in days/hours/mins/secs
+ */
+ public static String getDuration(long ms) {
+ if (ms <= 0) {
+ return "Not a valid time";
+ }
+ final long days = TimeUnit.MILLISECONDS.toDays(ms);
+ final long hrs = TimeUnit.MILLISECONDS.toHours(ms - TimeUnit.DAYS.toMillis(days));
+ final long mins = TimeUnit.MILLISECONDS.toMinutes(ms - TimeUnit.DAYS.toMillis(days)
+ - TimeUnit.HOURS.toMillis(hrs));
+ final long secs = TimeUnit.MILLISECONDS.toSeconds(ms - TimeUnit.DAYS.toMillis(days)
+ - TimeUnit.HOURS.toMillis(hrs) - TimeUnit.MINUTES.toMillis(mins));
+
+ return String.format("%dd %dh %dm %ds", days, hrs, mins, secs);
+ }
+}
+
diff --git a/tests/src/com/android/loganalysis/UnitTests.java b/tests/src/com/android/loganalysis/UnitTests.java
index eba92aa..c896d90 100644
--- a/tests/src/com/android/loganalysis/UnitTests.java
+++ b/tests/src/com/android/loganalysis/UnitTests.java
@@ -16,29 +16,32 @@
package com.android.loganalysis;
-import com.android.loganalysis.item.DumpsysBatteryInfoItemTest;
+import com.android.loganalysis.item.BatteryDischargeItemTest;
import com.android.loganalysis.item.GenericItemTest;
+import com.android.loganalysis.item.InterruptItemTest;
import com.android.loganalysis.item.MemInfoItemTest;
import com.android.loganalysis.item.MonkeyLogItemTest;
import com.android.loganalysis.item.ProcrankItemTest;
import com.android.loganalysis.item.SmartMonkeyLogItemTest;
import com.android.loganalysis.item.SystemPropsItemTest;
import com.android.loganalysis.item.TopItemTest;
+import com.android.loganalysis.item.WakelockItemTest;
import com.android.loganalysis.parser.AbstractSectionParserTest;
import com.android.loganalysis.parser.AnrParserTest;
import com.android.loganalysis.parser.BugreportParserTest;
-import com.android.loganalysis.parser.DumpsysBatteryInfoParserTest;
-import com.android.loganalysis.parser.DumpsysParserTest;
+import com.android.loganalysis.parser.InterruptParserTest;
import com.android.loganalysis.parser.JavaCrashParserTest;
import com.android.loganalysis.parser.KernelLogParserTest;
import com.android.loganalysis.parser.LogcatParserTest;
import com.android.loganalysis.parser.MemInfoParserTest;
import com.android.loganalysis.parser.MonkeyLogParserTest;
import com.android.loganalysis.parser.NativeCrashParserTest;
+import com.android.loganalysis.parser.ProcessUsageParserTest;
import com.android.loganalysis.parser.ProcrankParserTest;
import com.android.loganalysis.parser.SystemPropsParserTest;
import com.android.loganalysis.parser.TopParserTest;
import com.android.loganalysis.parser.TracesParserTest;
+import com.android.loganalysis.parser.WakelockParserTest;
import com.android.loganalysis.util.ArrayUtilTest;
import com.android.loganalysis.util.LogPatternUtilTest;
import com.android.loganalysis.util.LogTailUtilTest;
@@ -61,31 +64,34 @@ public class UnitTests extends TestSuite {
super();
// item
- addTestSuite(DumpsysBatteryInfoItemTest.class);
+ addTestSuite(BatteryDischargeItemTest.class);
addTestSuite(GenericItemTest.class);
+ addTestSuite(InterruptItemTest.class);
addTestSuite(MemInfoItemTest.class);
addTestSuite(MonkeyLogItemTest.class);
addTestSuite(ProcrankItemTest.class);
addTestSuite(SmartMonkeyLogItemTest.class);
addTestSuite(SystemPropsItemTest.class);
addTestSuite(TopItemTest.class);
+ addTestSuite(WakelockItemTest.class);
// parser
addTestSuite(AbstractSectionParserTest.class);
addTestSuite(AnrParserTest.class);
addTestSuite(BugreportParserTest.class);
- addTestSuite(DumpsysParserTest.class);
- addTestSuite(DumpsysBatteryInfoParserTest.class);
+ addTestSuite(InterruptParserTest.class);
addTestSuite(JavaCrashParserTest.class);
addTestSuite(KernelLogParserTest.class);
addTestSuite(LogcatParserTest.class);
addTestSuite(MemInfoParserTest.class);
addTestSuite(MonkeyLogParserTest.class);
addTestSuite(NativeCrashParserTest.class);
+ addTestSuite(ProcessUsageParserTest.class);
addTestSuite(ProcrankParserTest.class);
addTestSuite(SystemPropsParserTest.class);
addTestSuite(TopParserTest.class);
addTestSuite(TracesParserTest.class);
+ addTestSuite(WakelockParserTest.class);
// util
addTestSuite(ArrayUtilTest.class);
diff --git a/tests/src/com/android/loganalysis/item/BatteryDischargeItemTest.java b/tests/src/com/android/loganalysis/item/BatteryDischargeItemTest.java
new file mode 100644
index 0000000..5e27eb2
--- /dev/null
+++ b/tests/src/com/android/loganalysis/item/BatteryDischargeItemTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 com.android.loganalysis.item.BatteryDischargeItem.BatteryDischargeInfoItem;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Calendar;
+
+/**
+ * Unit test for {@link BatteryDischargeItem}.
+ */
+public class BatteryDischargeItemTest extends TestCase {
+
+ /**
+ * Test that {@link BatteryDischargeItem#toJson()} returns correctly.
+ */
+ public void testToJson() throws JSONException {
+ BatteryDischargeItem item = new BatteryDischargeItem();
+ item.addBatteryDischargeInfo(Calendar.getInstance(),25, 95);
+
+ // Convert to JSON string and back again
+ JSONObject output = new JSONObject(item.toJson().toString());
+
+ assertTrue(output.has(BatteryDischargeItem.BATTERY_DISCHARGE));
+ assertTrue(output.get(BatteryDischargeItem.BATTERY_DISCHARGE) instanceof JSONArray);
+
+ JSONArray dischargeInfo = output.getJSONArray(BatteryDischargeItem.BATTERY_DISCHARGE);
+
+ assertEquals(1, dischargeInfo.length());
+ assertTrue(dischargeInfo.getJSONObject(0).has(BatteryDischargeInfoItem.BATTERY_LEVEL));
+ assertTrue(dischargeInfo.getJSONObject(0).has(
+ BatteryDischargeInfoItem.DISCHARGE_ELAPSED_TIME));
+ assertTrue(dischargeInfo.getJSONObject(0).has(
+ BatteryDischargeInfoItem.CLOCK_TIME_OF_DISCHARGE));
+
+ }
+}
diff --git a/tests/src/com/android/loganalysis/item/DumpsysBatteryInfoItemTest.java b/tests/src/com/android/loganalysis/item/DumpsysBatteryInfoItemTest.java
deleted file mode 100644
index bb48da7..0000000
--- a/tests/src/com/android/loganalysis/item/DumpsysBatteryInfoItemTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.item;
-
-import com.android.loganalysis.item.DumpsysBatteryInfoItem.WakeLockCategory;
-
-import junit.framework.TestCase;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Unit test for {@link DumpsysBatteryInfoItem}.
- */
-public class DumpsysBatteryInfoItemTest extends TestCase {
- private static final String WAKELOCKS = "WAKELOCKS";
- private static final String LAST_CHARGE_KERNEL_WAKELOCKS = "LAST_CHARGE_KERNEL_WAKELOCKS";
- private static final String LAST_UNPLUGGED_WAKELOCKS = "LAST_UNPLUGGED_WAKELOCKS";
- private static final String LAST_UNPLUGGED_KERNEL_WAKELOCKS = "LAST_UNPLUGGED_KERNEL_WAKELOCKS";
- /**
- * Test that {@link DumpsysBatteryInfoItem#toJson()} returns correctly.
- */
- public void testToJson() throws JSONException {
- DumpsysBatteryInfoItem item = new DumpsysBatteryInfoItem();
- item.addWakeLock("a", 0, 1, WakeLockCategory.LAST_UNPLUGGED_KERNEL_WAKELOCK);
- item.addWakeLock("b", 2, 3, WakeLockCategory.LAST_UNPLUGGED_KERNEL_WAKELOCK);
- item.addWakeLock("c", 4, 5, 6, WakeLockCategory.LAST_UNPLUGGED_WAKELOCK);
- item.addWakeLock("d", 7, 8, 9, WakeLockCategory.LAST_UNPLUGGED_WAKELOCK);
- item.addWakeLock("e", 10, 11, 12, WakeLockCategory.LAST_UNPLUGGED_WAKELOCK);
- item.addWakeLock("w", 0, 1, WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK);
- item.addWakeLock("v", 2, 3, WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK);
- item.addWakeLock("x", 4, 5, 6, WakeLockCategory.LAST_CHARGE_WAKELOCK);
- item.addWakeLock("y", 7, 8, 9, WakeLockCategory.LAST_CHARGE_WAKELOCK);
- item.addWakeLock("z", 10, 11, 12, WakeLockCategory.LAST_CHARGE_WAKELOCK);
-
- // Convert to JSON string and back again
- JSONObject output = new JSONObject(item.toJson().toString());
-
- assertTrue(output.has(WAKELOCKS));
- assertTrue(output.get(WAKELOCKS) instanceof JSONArray);
-
- JSONArray wakeLocks = output.getJSONArray(WAKELOCKS);
- assertEquals(10, wakeLocks.length());
- assertTrue(wakeLocks.get(0) instanceof JSONObject);
-
- JSONObject wakeLock = wakeLocks.getJSONObject(0);
- assertEquals("a", wakeLock.get(DumpsysBatteryInfoItem.WakeLock.NAME));
- assertFalse(wakeLock.has(DumpsysBatteryInfoItem.WakeLock.NUMBER));
- assertEquals(0, wakeLock.get(DumpsysBatteryInfoItem.WakeLock.HELD_TIME));
- assertEquals(1, wakeLock.get(DumpsysBatteryInfoItem.WakeLock.LOCKED_COUNT));
- assertEquals(WakeLockCategory.LAST_UNPLUGGED_KERNEL_WAKELOCK.toString(),
- wakeLock.get(DumpsysBatteryInfoItem.WakeLock.CATEGORY));
- }
-}
diff --git a/tests/src/com/android/loganalysis/item/InterruptItemTest.java b/tests/src/com/android/loganalysis/item/InterruptItemTest.java
new file mode 100644
index 0000000..9e9df61
--- /dev/null
+++ b/tests/src/com/android/loganalysis/item/InterruptItemTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 com.android.loganalysis.item.InterruptItem.InterruptInfoItem;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Unit test for {@link InterruptItem}.
+ */
+public class InterruptItemTest extends TestCase {
+
+ /**
+ * Test that {@link InterruptItem#toJson()} returns correctly.
+ */
+ public void testToJson() throws JSONException {
+ InterruptItem item = new InterruptItem();
+ item.addInterrupt("smd-modem",25, InterruptItem.InterruptCategory.ALARM_INTERRUPT);
+
+ // Convert to JSON string and back again
+ JSONObject output = new JSONObject(item.toJson().toString());
+
+ assertTrue(output.has(InterruptItem.INTERRUPTS));
+ assertTrue(output.get(InterruptItem.INTERRUPTS) instanceof JSONArray);
+
+ JSONArray interruptsInfo = output.getJSONArray(InterruptItem.INTERRUPTS);
+
+ assertEquals(1, interruptsInfo.length());
+ assertTrue(interruptsInfo.getJSONObject(0).has(InterruptInfoItem.NAME));
+ assertTrue(interruptsInfo.getJSONObject(0).has(InterruptInfoItem.CATEGORY));
+ assertTrue(interruptsInfo.getJSONObject(0).has(InterruptInfoItem.INTERRUPT_COUNT));
+
+ }
+}
diff --git a/tests/src/com/android/loganalysis/item/WakelockItemTest.java b/tests/src/com/android/loganalysis/item/WakelockItemTest.java
new file mode 100644
index 0000000..f570a7b
--- /dev/null
+++ b/tests/src/com/android/loganalysis/item/WakelockItemTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 com.android.loganalysis.item.WakelockItem.WakelockInfoItem;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Unit test for {@link WakelockItem}.
+ */
+public class WakelockItemTest extends TestCase {
+
+ /**
+ * Test that {@link WakelockItem#toJson()} returns correctly.
+ */
+ public void testToJson() throws JSONException {
+ WakelockItem item = new WakelockItem();
+ item.addWakeLock("screen","u100", 150000, 25,
+ WakelockItem.WakeLockCategory.PARTIAL_WAKELOCK);
+ item.addWakeLock("wlan_rx", 150000, 25,
+ WakelockItem.WakeLockCategory.KERNEL_WAKELOCK);
+
+ // Convert to JSON string and back again
+ JSONObject output = new JSONObject(item.toJson().toString());
+
+ assertTrue(output.has(WakelockItem.WAKELOCKS));
+ assertTrue(output.get(WakelockItem.WAKELOCKS) instanceof JSONArray);
+
+ JSONArray wakelockInfo = output.getJSONArray(WakelockItem.WAKELOCKS);
+
+ assertEquals(2, wakelockInfo.length());
+ assertTrue(wakelockInfo.getJSONObject(0).has(WakelockInfoItem.NAME));
+ assertTrue(wakelockInfo.getJSONObject(0).has(WakelockInfoItem.PROCESS_UID));
+ assertTrue(wakelockInfo.getJSONObject(0).has(WakelockInfoItem.HELD_TIME));
+ assertTrue(wakelockInfo.getJSONObject(0).has(WakelockInfoItem.LOCKED_COUNT));
+ assertTrue(wakelockInfo.getJSONObject(0).has(WakelockInfoItem.CATEGORY));
+
+ assertTrue(wakelockInfo.getJSONObject(1).has(WakelockInfoItem.NAME));
+ assertFalse(wakelockInfo.getJSONObject(1).has(WakelockInfoItem.PROCESS_UID));
+ assertTrue(wakelockInfo.getJSONObject(1).has(WakelockInfoItem.HELD_TIME));
+ assertTrue(wakelockInfo.getJSONObject(1).has(WakelockInfoItem.LOCKED_COUNT));
+ assertTrue(wakelockInfo.getJSONObject(1).has(WakelockInfoItem.CATEGORY));
+
+ }
+}
diff --git a/tests/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParserTest.java b/tests/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParserTest.java
new file mode 100644
index 0000000..b176fa2
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParserTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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 junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link BatteryStatsDetailedInfoParser}
+ */
+public class BatteryStatsDetailedInfoParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed.
+ */
+ public void testBatteryStatsDetailedInfoParser() {
+ List<String> inputBlock = Arrays.asList(
+ " Time on battery: 2h 21m 5s 622ms (12.0%) realtime, 7m 54s 146ms (0.7%) uptime",
+ " Time on battery screen off: 2h 5m 55s 3ms (1%) realtime, 7m 4s 5ms (7%) uptime",
+ " Total run time: 19h 38m 43s 650ms realtime, 17h 25m 32s 175ms uptime",
+ " All kernel wake locks:",
+ " Kernel Wake lock PowerManagerService.WakeLocks: 1h 3m 50s 5ms (8 times) realtime",
+ " Kernel Wake lock event0-2656 : 3m 49s 268ms (2399 times) realtime",
+ " Kernel Wake lock wlan_wd_wake: 3m 34s 639ms (1751 times) realtime",
+ " Kernel Wake lock wlan_rx_wake: 3m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock wlan_tx_wake: 2m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock tx_wake: 1m 19s 887ms (225 times) realtime",
+ " ",
+ " All partial wake locks:",
+ " Wake lock u0a7 NlpWakeLock: 8m 13s 203ms (1479 times) realtime",
+ " Wake lock u0a7 NlpCollectorWakeLock: 6m 29s 18ms (238 times) realtime",
+ " Wake lock u0a7 GCM_CONN_ALARM: 6m 8s 587ms (239 times) realtime",
+ " Wake lock 1000 *alarm*: 5m 11s 316ms (1469 times) realtime",
+ " Wake lock u10 xxx: 4m 11s 316ms (1469 times) realtime",
+ " Wake lock u30 cst: 2m 11s 316ms (1469 times) realtime",
+ " ",
+ " All wakeup reasons:",
+ " Wakeup reason 200:qcom,smd-rpm:222:fc4: 11m 49s 332ms (0 times) realtime",
+ " Wakeup reason 200:qcom,smd-rpm: 48s 45ms (0 times) realtime",
+ " Wakeup reason 2:qcom,smd-rpm:2:f0.qm,mm:22:fc4mi: 3s 417ms (0 times) realtime",
+ " Wakeup reason 188:qcom,smd-adsp:200:qcom,smd-rpm: 1s 656ms (0 times) realtime",
+ " Wakeup reason 58:qcom,smsm-modem:2:qcom,smd-rpm: 6m 16s 1ms (5 times) realtime",
+ " Wakeup reason 57:qcom,smd-modem:200:qcom,smd-rpm: 40s 995ms (0 times) realtime",
+ " Wakeup reason unknown: 8s 455ms (0 times) realtime",
+ " Wakeup reason 9:bcmsdh_sdmmc:2:qcomd-rpm:240:mso: 8m 5s 9ms (0 times) realtime",
+ " ",
+ " 0:",
+ " User activity: 2 other",
+ " Wake lock SCREEN_FROZEN realtime",
+ " Sensor 0: 9s 908ms realtime (1 times)",
+ " Sensor 1: 9s 997ms realtime (1 times)",
+ " Foreground for: 2h 21m 5s 622ms",
+ " Apk android:",
+ " 24 wakeup alarms",
+ " u0a9:",
+ " Mobile network: 8.1KB received, 1.6KB sent (packets 291 received, 342 sent)",
+ " Mobile radio active: 3m 43s 890ms (34.2%) 39x @ 354 mspp",
+ " Sensor 2: 12m 13s 15ms realtime (5 times)",
+ " Sensor 32: (not used)",
+ " Sensor 35: (not used)");
+
+ BatteryStatsDetailedInfoItem stats = new BatteryStatsDetailedInfoParser().parse(inputBlock);
+
+ assertEquals(8465622, stats.getTimeOnBattery());
+ assertEquals(910619, stats.getScreenOnTime());
+ assertNotNull(stats.getWakelockItem());
+ assertNotNull(stats.getInterruptItem());
+ assertNotNull(stats.getProcessUsageItem());
+ }
+
+ /**
+ * Test with missing wakelock section
+ */
+ public void testMissingWakelockSection() {
+ List<String> inputBlock = Arrays.asList(
+ " Time on battery: 2h 21m 5s 622ms (12.0%) realtime, 7m 54s 146ms (0.7%) uptime",
+ " Time on battery screen off: 2h 5m 55s 3ms (1%) realtime, 7m 4s 5ms (7%) uptime",
+ " Total run time: 19h 38m 43s 650ms realtime, 17h 25m 32s 175ms uptime",
+ " All wakeup reasons:",
+ " Wakeup reason 200:qcom,smd-rpm:222:fc4: 11m 49s 332ms (0 times) realtime",
+ " Wakeup reason 200:qcom,smd-rpm: 48s 45ms (0 times) realtime",
+ " Wakeup reason 2:qcom,smd-rpm:2:f0.qm,mm:22:fc4mi: 3s 417ms (0 times) realtime",
+ " Wakeup reason 188:qcom,smd-adsp:200:qcom,smd-rpm: 1s 656ms (0 times) realtime",
+ " Wakeup reason 58:qcom,smsm-modem:2:qcom,smd-rpm: 6m 16s 1ms (5 times) realtime",
+ " Wakeup reason 57:qcom,smd-modem:200:qcom,smd-rpm: 40s 995ms (0 times) realtime",
+ " Wakeup reason unknown: 8s 455ms (0 times) realtime",
+ " Wakeup reason 9:bcmsdh_sdmmc:2:qcomd-rpm:240:mso: 8m 5s 9ms (0 times) realtime",
+ " ",
+ " 0:",
+ " User activity: 2 other",
+ " Wake lock SCREEN_FROZEN realtime",
+ " Sensor 0: 9s 908ms realtime (1 times)",
+ " Sensor 1: 9s 997ms realtime (1 times)",
+ " Foreground for: 2h 21m 5s 622ms",
+ " Apk android:",
+ " 24 wakeup alarms",
+ " u0a9:",
+ " Mobile network: 8.1KB received, 1.6KB sent (packets 291 received, 342 sent)",
+ " Mobile radio active: 3m 43s 890ms (34.2%) 39x @ 354 mspp",
+ " Sensor 2: 12m 13s 15ms realtime (5 times)",
+ " Sensor 32: (not used)",
+ " Sensor 35: (not used)");
+ BatteryStatsDetailedInfoItem stats = new BatteryStatsDetailedInfoParser().parse(inputBlock);
+
+ assertEquals(8465622, stats.getTimeOnBattery());
+ assertEquals(910619, stats.getScreenOnTime());
+
+ assertNull(stats.getWakelockItem());
+
+ assertNotNull(stats.getInterruptItem());
+ assertNotNull(stats.getProcessUsageItem());
+ }
+}
+
diff --git a/tests/src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParserTest.java b/tests/src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParserTest.java
new file mode 100644
index 0000000..ad0c999
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/BatteryStatsSummaryInfoParserTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.BatteryStatsSummaryInfoItem;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link BatteryStatsSummaryInfoParser}
+ */
+public class BatteryStatsSummaryInfoParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed.
+ */
+ public void testBatteryStatsSummaryInfoParser() {
+ List<String> inputBlock = Arrays.asList(
+ "Battery History (37% used, 95KB used of 256KB, 166 strings using 15KB):",
+ " 0 (9) RESET:TIME: 2014-12-09-11-33-29",
+ " +1s067ms (1) 100 c0500020 -wifi_full_lock -wifi_scan",
+ " +3s297ms (2) 100 80400020 -wake_lock -screen",
+ " +30m02s075ms (1) 100 c0500020 wifi_signal_strength=4 wifi_suppl=completed",
+ " +30m03s012ms (2) 099 c0500020 temp=306 volt=4217",
+ " +33m48s967ms (1) 099 f8400020 +wifi_scan",
+ " +33m49s335ms (2) 098 f0400020 temp=324 -wifi_scan",
+ " +1h07m27s735ms (1) 098 80400020 -wake_lock",
+ " +1h07m27s950ms (2) 097 c0400020",
+ " +1h07m29s000ms (2) 097 c0400020 -sync=u0a41:\"gmail-ls/com.google/a@g",
+ " +1h25m34s877ms (2) 097 00400020 -running wake_reason=0:200:qcom,smd-rpm",
+ " +1h25m41s948ms (2) 096 80400020 wifi_suppl=associated",
+ " +2h13m40s055ms (1) 096 00400018 -running",
+ " +2h13m40s570ms (2) 095 c0400008 temp=304 volt=4167",
+ " +2h56m50s792ms (1) 095 80400020 -wake_lock",
+ " +2h56m50s967ms (2) 094 00400020 temp=317 -running",
+ " +3h38m57s986ms (2) 094 80400020 +running wake_reason=0:289:bcmsdh_sdmmc",
+ " +3h38m58s241ms (2) 093 00400020 temp=327 -running",
+ " +3h56m33s329ms (1) 093 00400020 -running -wake_lock",
+ " +3h56m43s245ms (2) 092 00400020 -running",
+ " +4h13m00s551ms (1) 092 00400020 -running -wake_lock",
+ " +4h13m24s250ms (2) 091 00400020 -running",
+ " +4h34m52s233ms (2) 091 80400020 +running wake_reason=0:289:bcmsdh_sdmmc",
+ " +4h34m52s485ms (3) 090 00400020 -running wake_reason=0:200:qcom,smd-rpm",
+ " +4h57m20s644ms (1) 090 00400020 -running",
+ " +4h57m38s484ms (2) 089 00400020 -running",
+ " +5h20m58s226ms (1) 089 80400020 +running wifi_suppl=associated",
+ " +5h21m03s909ms (1) 088 80400020 -wake_lock -wifi_full_lock",
+ " +5h40m38s169ms (2) 088 c0500020 +top=u0a19:com.google.android.googlequick",
+ " +5h40m38s479ms (2) 087 c0500020 volt=4036",
+ " +6h16m45s248ms (2) 087 d0440020 -sync=u0a41:gmail-ls/com.google/avellore@go",
+ " +6h16m45s589ms (2) 086 d0440020 volt=4096",
+ " +6h52m43s316ms (1) 086 80400020 -wake_lock",
+ " +6h53m18s952ms (2) 085 c0400020",
+ " +7h24m02s415ms (1) 085 80400020 -wake_lock",
+ " +7h24m02s904ms (3) 084 c0400020 volt=4105 +wake_lock=u0a7:NlpWakeLock",
+ " +7h29m10s379ms (1) 084 00400020 -running -wake_lock",
+ " +7h29m11s841ms (2) 083 00400020 temp=317 volt=4047 -running",
+ " +7h41m08s963ms (1) 083 00400020 -running",
+ " +7h41m20s494ms (2) 082 00400020 temp=300 -running",
+ " +7h54m57s288ms (1) 082 52441420 -running",
+ " +7h55m00s801ms (1) 081 52441420 -running",
+ " +8h02m18s594ms (1) 081 50440020 -running",
+ " +8h02m23s493ms (2) 080 50440020 temp=313 -running");
+
+ BatteryStatsSummaryInfoItem summary = new BatteryStatsSummaryInfoParser().parse(inputBlock);
+
+ assertEquals("The battery dropped a level 24 mins on average",
+ summary.getBatteryDischargeRate());
+
+ assertEquals("The peak discharge time was during Tue Dec 09 16:31:07 PST 2014 to "
+ + "Tue Dec 09 19:35:52 PST 2014 where battery dropped from 89 to 80",
+ summary.getPeakDischargeTime());
+ }
+
+ public void testNoBatteryDischarge() {
+ List<String> inputBlock = Arrays.asList(
+ "Battery History (37% used, 95KB used of 256KB, 166 strings using 15KB):",
+ " 0 (9) RESET:TIME: 2014-12-09-11-33-29");
+ BatteryStatsSummaryInfoItem summary = new BatteryStatsSummaryInfoParser().parse(inputBlock);
+
+ assertEquals("The battery did not discharge", summary.getBatteryDischargeRate());
+ assertEquals("The battery did not discharge", summary.getPeakDischargeTime());
+ }
+}
+
diff --git a/tests/src/com/android/loganalysis/parser/BugreportParserTest.java b/tests/src/com/android/loganalysis/parser/BugreportParserTest.java
index a17493e..ea7537f 100644
--- a/tests/src/com/android/loganalysis/parser/BugreportParserTest.java
+++ b/tests/src/com/android/loganalysis/parser/BugreportParserTest.java
@@ -118,14 +118,24 @@ public class BugreportParserTest extends TestCase {
"------ SECTION ------",
"",
"------ DUMPSYS (dumpsys) ------",
- "DUMP OF SERVICE batteryinfo:",
- "Statistics since last unplugged:",
- " Kernel Wake lock \"PowerManagerService.WakeLocks\": 5m 10s 61ms (2 times) realtime",
- " Kernel Wake lock \"pm8921_eoc\": 9s 660ms (0 times) realtime",
+ "DUMP OF SERVICE batterystats:",
+ "Battery History (0% used, 1636 used of 256KB, 15 strings using 794):",
+ " 0 (15) RESET:TIME: 1970-01-10-06-23-28",
+ " +45s702ms (2) 001 80080000 volt=4187",
+ " +1m15s525ms (2) 001 80080000 temp=299 volt=4155",
+ "Statistics since last charged:",
+ " Time on battery: 1h 5m 2s 4ms (9%) realtime, 1h 5m 2s 4ms (9%) uptime",
+ " Time on battery screen off: 1h 4m 5s 8ms (9%) realtime, 1h 4m 5s 8ms (9%) uptime",
+ " All kernel wake locks:",
+ " Kernel Wake lock PowerManagerService.WakeLocks: 5m 10s 6ms (2 times) realtime",
+ " Kernel Wake lock msm_serial_hs_rx: 2m 13s 612ms (258 times) realtime",
"",
" All partial wake locks:",
- " Wake lock #0 partialWakelock: 5m 9s 260ms (1 times) realtime",
- " Wake lock #1000 AlarmManager: 422ms (7 times) realtime",
+ " Wake lock 1001 ProxyController: 1h 4m 47s 565ms (4 times) realtime",
+ " Wake lock 1013 AudioMix: 1s 979ms (3 times) realtime",
+ " All wakeup reasons:",
+ " Wakeup reason 2:bcmsdh_sdmmc:2:qcom,smd:2:msmgio: 1m 5s 4ms (2 times) realtime",
+ " Wakeup reason 2:qcom,smd-rpm:2:fc4c.qcom,spmi: 7m 1s 914ms (7 times) realtime",
"");
BugreportItem bugreport = new BugreportParser().parse(lines);
@@ -158,7 +168,7 @@ public class BugreportParserTest extends TestCase {
assertEquals(4, bugreport.getSystemProps().size());
assertNotNull(bugreport.getDumpsys());
- assertNotNull(bugreport.getDumpsys().getBatteryInfo());
+ assertNotNull(bugreport.getDumpsys().getBatteryStats());
}
/**
@@ -440,7 +450,7 @@ public class BugreportParserTest extends TestCase {
bugreport = new BugreportParser().parse(lines);
assertNotNull(bugreport);
- assertNull(bugreport.getDumpsys());
+ assertNotNull(bugreport.getDumpsys());
assertNull(bugreport.getKernelLog());
assertNull(bugreport.getLastKmsg());
assertNull(bugreport.getMemInfo());
diff --git a/tests/src/com/android/loganalysis/parser/DumpsysBatteryInfoParserTest.java b/tests/src/com/android/loganalysis/parser/DumpsysBatteryInfoParserTest.java
deleted file mode 100644
index 66c7796..0000000
--- a/tests/src/com/android/loganalysis/parser/DumpsysBatteryInfoParserTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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.WakeLock;
-import com.android.loganalysis.item.DumpsysBatteryInfoItem.WakeLockCategory;
-
-import junit.framework.TestCase;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Unit tests for {@link DumpsysBatteryInfoParser}
- */
-public class DumpsysBatteryInfoParserTest extends TestCase {
-
- /**
- * Test that complete battery info dumpsys is parsed.
- */
- public void testParse() {
- List<String> inputBlock = Arrays.asList(
- "Battery History:",
- " -15m07s754ms START",
- " -15m05s119ms 088 20080000 status=charging health=good plug=usb temp=269 volt=4358 +plugged +sensor",
- "",
- "Per-PID Stats:",
- " PID 4242 wake time: +5m10s24ms",
- " PID 543 wake time: +3s585ms",
- "",
- "Statistics since last charge:",
- " System starts: 2, currently on battery: false",
- " Time on battery: 8m 20s 142ms (55.1%) realtime, 5m 17s 5ms (34.9%) uptime",
- " Kernel Wake lock \"PowerManagerService.WakeLocks\": 5m 10s 61ms (2 times) realtime",
- " Kernel Wake lock \"pm8921_eoc\": 9s 660ms (0 times) realtime",
- " ",
- " All partial wake locks:",
- " Wake lock #0 partialWakelock: 5m 9s 260ms (1 times) realtime",
- " Wake lock #1000 AlarmManager: 422ms (7 times) realtime",
- "",
- "Statistics since last unplugged:",
- " Time on battery: 8m 20s 142ms (92.6%) realtime, 5m 17s 5ms (58.7%) uptime",
- " Total run time: 8m 59s 968ms realtime, 5m 56s 831ms uptime, ",
- " Screen on: 0ms (0.0%), Input events: 0, Active phone call: 0ms (0.0%)",
- " Screen brightnesses: No activity",
- " Kernel Wake lock \"PowerManagerService.WakeLocks\": 5m 10s 61ms (2 times) realtime",
- " Kernel Wake lock \"pm8921_eoc\": 9s 660ms (0 times) realtime",
- " Kernel Wake lock \"main\": 7s 323ms (0 times) realtime",
- " Total received: 0B, Total sent: 0B",
- " Total full wakelock time: 0ms , Total partial wakelock time: 5m 10s 60ms ",
- " Signal levels: No activity",
- " Signal scanning time: 0ms ",
- " Radio types: none 8m 20s 142ms (100.0%) 0x",
- " Radio data uptime when unplugged: 0 ms",
- " Wifi on: 0ms (0.0%), Wifi running: 0ms (0.0%), Bluetooth on: 0ms (0.0%)",
- " ",
- " Device is currently plugged into power",
- " Last discharge cycle start level: 87",
- " Last discharge cycle end level: 87",
- " Amount discharged while screen on: 0",
- " Amount discharged while screen off: 0",
- " ",
- " All partial wake locks:",
- " Wake lock #0 partialWakelock: 5m 9s 260ms (1 times) realtime",
- " Wake lock #1000 AlarmManager: 422ms (7 times) realtime",
- " Wake lock #1000 show keyguard: 277ms (1 times) realtime",
- " Wake lock #1000 ActivityManager-Sleep: 72ms (1 times) realtime",
- " Wake lock #10015 AlarmManager: 16ms (1 times) realtime",
- "",
- " #0:",
- " Wake lock partialWakelock: 5m 9s 260ms partial (1 times) realtime",
- " Proc /init:",
- " CPU: 10ms usr + 0ms krn",
- " Proc flush-179:0:",
- " CPU: 0ms usr + 10ms krn",
- " Proc vold:",
- " CPU: 20ms usr + 10ms krn",
- " #1000:",
- " User activity: 3 other, 1 button",
- " Wake lock show keyguard: 277ms partial (1 times) realtime",
- " Wake lock AlarmManager: 422ms partial (7 times) realtime");
-
- DumpsysBatteryInfoParser parser = new DumpsysBatteryInfoParser();
- DumpsysBatteryInfoItem item = parser.parse(inputBlock);
-
- assertEquals(2, item.getWakeLocks(WakeLockCategory.LAST_CHARGE_WAKELOCK).size());
- assertEquals(2, item.getWakeLocks(WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK).size());
- assertEquals(5, item.getWakeLocks(WakeLockCategory.LAST_UNPLUGGED_WAKELOCK).size());
- assertEquals(3, item.getWakeLocks(WakeLockCategory.LAST_UNPLUGGED_KERNEL_WAKELOCK).size());
-
- assertEquals("partialWakelock",
- item.getWakeLocks(WakeLockCategory.LAST_CHARGE_WAKELOCK).get(0).getName());
- assertEquals("PowerManagerService.WakeLocks",
- item.getWakeLocks(WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK).get(0).getName());
- assertEquals("partialWakelock",
- item.getWakeLocks(WakeLockCategory.LAST_UNPLUGGED_WAKELOCK).get(0).getName());
- assertEquals("PowerManagerService.WakeLocks",
- item.getWakeLocks(WakeLockCategory.LAST_UNPLUGGED_KERNEL_WAKELOCK).get(0).getName());
- }
-
- /**
- * Test that kernel wakelocks are parsed.
- */
- public void testParseKernelWakeLock() {
- String inputLine = " Kernel Wake lock \"Process\": 1d 2h 3m 4s 5ms (6 times) realtime";
-
- DumpsysBatteryInfoParser parser = new DumpsysBatteryInfoParser();
- parser.parseKernelWakeLock(inputLine, WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK);
- DumpsysBatteryInfoItem item = parser.getItem();
-
- assertEquals(1, item.getWakeLocks(WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK).size());
- WakeLock wakeLock = item.getWakeLocks(WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK).get(0);
- assertEquals("Process", wakeLock.getName());
- assertNull(wakeLock.getNumber());
- assertEquals(DumpsysBatteryInfoParser.getMs(1, 2, 3, 4, 5), wakeLock.getHeldTime());
- assertEquals(6, wakeLock.getLockedCount());
-
- inputLine = " Kernel Wake lock \"Process\": 5m 7ms (2 times) realtime";
-
- parser = new DumpsysBatteryInfoParser();
- parser.parseKernelWakeLock(inputLine, WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK);
- item = parser.getItem();
-
- assertEquals(1, item.getWakeLocks(WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK).size());
- wakeLock = item.getWakeLocks(WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK).get(0);
- assertEquals("Process", wakeLock.getName());
- assertNull(wakeLock.getNumber());
- assertEquals(5 * 60 * 1000 + 7, wakeLock.getHeldTime());
- assertEquals(2, wakeLock.getLockedCount());
- }
-
- /**
- * Test that wake locks are parsed.
- */
- public void testParseWakeLock() {
- String inputLine = " Wake lock #1234 Process: 1d 2h 3m 4s 5ms (6 times) realtime";
-
- DumpsysBatteryInfoParser parser = new DumpsysBatteryInfoParser();
- parser.parseWakeLock(inputLine, WakeLockCategory.LAST_CHARGE_WAKELOCK);
- DumpsysBatteryInfoItem item = parser.getItem();
-
- assertEquals(1, item.getWakeLocks(WakeLockCategory.LAST_CHARGE_WAKELOCK).size());
- WakeLock wakeLock = item.getWakeLocks(WakeLockCategory.LAST_CHARGE_WAKELOCK).get(0);
- assertEquals("Process", wakeLock.getName());
- assertEquals((Integer) 1234, wakeLock.getNumber());
- assertEquals(DumpsysBatteryInfoParser.getMs(1, 2, 3, 4, 5), wakeLock.getHeldTime());
- assertEquals(6, wakeLock.getLockedCount());
-
- inputLine = " Wake lock #1234 Process:with:colons: 5m 7ms (2 times) realtime";
-
- parser = new DumpsysBatteryInfoParser();
- parser.parseWakeLock(inputLine, WakeLockCategory.LAST_CHARGE_WAKELOCK);
- item = parser.getItem();
-
- assertEquals(1, item.getWakeLocks(WakeLockCategory.LAST_CHARGE_WAKELOCK).size());
- wakeLock = item.getWakeLocks(WakeLockCategory.LAST_CHARGE_WAKELOCK).get(0);
- assertEquals("Process:with:colons", wakeLock.getName());
- assertEquals((Integer) 1234, wakeLock.getNumber());
- assertEquals(5 * 60 * 1000 + 7, wakeLock.getHeldTime());
- assertEquals(2, wakeLock.getLockedCount());
- }
-
- /**
- * Test the helper function to covert time to ms.
- */
- public void testGetMs() {
- assertEquals(1, DumpsysBatteryInfoParser.getMs(0, 0, 0, 0, 1));
- assertEquals(1000, DumpsysBatteryInfoParser.getMs(0, 0, 0, 1, 0));
- assertEquals(60 * 1000, DumpsysBatteryInfoParser.getMs(0, 0, 1, 0, 0));
- assertEquals(60 * 60 * 1000, DumpsysBatteryInfoParser.getMs(0, 1, 0, 0, 0));
- assertEquals(24 * 60 * 60 * 1000, DumpsysBatteryInfoParser.getMs(1, 0, 0, 0, 0));
- }
-}
-
diff --git a/tests/src/com/android/loganalysis/parser/DumpsysBatteryStatsParserTest.java b/tests/src/com/android/loganalysis/parser/DumpsysBatteryStatsParserTest.java
new file mode 100644
index 0000000..8799a9b
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/DumpsysBatteryStatsParserTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.DumpsysBatteryStatsItem;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link DumpsysBatteryStatsParser}
+ */
+public class DumpsysBatteryStatsParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed.
+ */
+ public void testBatteryStatsParser() {
+ List<String> inputBlock = Arrays.asList(
+ "Battery History (37% used, 95KB used of 256KB, 166 strings using 15KB):",
+ " 0 (9) RESET:TIME: 2014-12-09-11-33-29",
+ " +1s067ms (1) 100 c0500020 -wifi_full_lock -wifi_scan",
+ " +3s297ms (2) 100 80400020 -wake_lock -screen",
+ " +30m02s075ms (1) 100 c0500020 wifi_signal_strength=4 wifi_suppl=completed",
+ " +30m03s012ms (2) 099 c0500020 temp=306 volt=4217",
+ " +33m48s967ms (1) 099 f8400020 +wifi_scan",
+ " +33m49s335ms (2) 098 f0400020 temp=324 -wifi_scan",
+ "Statistics since last charge:",
+ " Time on battery: 2h 21m 5s 622ms (12.0%) realtime, 7m 54s 146ms (0.7%) uptime",
+ " Time on battery screen off: 2h 5m 55s 3ms (1%) realtime, 7m 4s 5ms (7%) uptime",
+ " Total run time: 19h 38m 43s 650ms realtime, 17h 25m 32s 175ms uptime",
+ " All kernel wake locks:",
+ " Kernel Wake lock PowerManagerService.WakeLocks: 1h 3m 50s 5ms (8 times) realtime",
+ " Kernel Wake lock event0-2656 : 3m 49s 268ms (2399 times) realtime",
+ " Kernel Wake lock wlan_wd_wake: 3m 34s 639ms (1751 times) realtime",
+ " Kernel Wake lock wlan_rx_wake: 3m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock wlan_tx_wake: 2m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock tx_wake: 1m 19s 887ms (225 times) realtime",
+ " ",
+ " All partial wake locks:",
+ " Wake lock u0a7 NlpWakeLock: 8m 13s 203ms (1479 times) realtime",
+ " Wake lock u0a7 NlpCollectorWakeLock: 6m 29s 18ms (238 times) realtime",
+ " Wake lock u0a7 GCM_CONN_ALARM: 6m 8s 587ms (239 times) realtime",
+ " Wake lock 1000 *alarm*: 5m 11s 316ms (1469 times) realtime",
+ " Wake lock u10 xxx: 4m 11s 316ms (1469 times) realtime",
+ " Wake lock u30 cst: 2m 11s 316ms (1469 times) realtime",
+ " ",
+ " All wakeup reasons:",
+ " Wakeup reason 200:qcom,smd-rpm:222:fc4: 11m 49s 332ms (0 times) realtime",
+ " Wakeup reason 200:qcom,smd-rpm: 48s 45ms (0 times) realtime",
+ " Wakeup reason 2:qcom,smd-rpm:2:f0.qm,mm:22:fc4mi: 3s 417ms (0 times) realtime",
+ " Wakeup reason 188:qcom,smd-adsp:200:qcom,smd-rpm: 1s 656ms (0 times) realtime",
+ " Wakeup reason 58:qcom,smsm-modem:2:qcom,smd-rpm: 6m 16s 1ms (5 times) realtime",
+ " Wakeup reason 57:qcom,smd-modem:200:qcom,smd-rpm: 40s 995ms (0 times) realtime",
+ " Wakeup reason unknown: 8s 455ms (0 times) realtime",
+ " Wakeup reason 9:bcmsdh_sdmmc:2:qcomd-rpm:240:mso: 8m 5s 9ms (0 times) realtime",
+ " ",
+ " 0:",
+ " User activity: 2 other",
+ " Wake lock SCREEN_FROZEN realtime",
+ " Sensor 0: 9s 908ms realtime (1 times)",
+ " Sensor 1: 9s 997ms realtime (1 times)",
+ " Foreground for: 2h 21m 5s 622ms",
+ " Apk android:",
+ " 24 wakeup alarms",
+ " u0a9:",
+ " Mobile network: 8.1KB received, 1.6KB sent (packets 291 received, 342 sent)",
+ " Mobile radio active: 3m 43s 890ms (34.2%) 39x @ 354 mspp",
+ " Sensor 2: 12m 13s 15ms realtime (5 times)",
+ " Sensor 32: (not used)",
+ " Sensor 35: (not used)");
+
+ DumpsysBatteryStatsItem batteryStats = new DumpsysBatteryStatsParser().parse(inputBlock);
+ assertNotNull(batteryStats.getBatteryStatsSummaryItem());
+ assertNotNull(batteryStats.getDetailedBatteryStatsItem());
+ }
+}
+
diff --git a/tests/src/com/android/loganalysis/parser/DumpsysParserTest.java b/tests/src/com/android/loganalysis/parser/DumpsysParserTest.java
index 423ec06..7dff3a1 100644
--- a/tests/src/com/android/loganalysis/parser/DumpsysParserTest.java
+++ b/tests/src/com/android/loganalysis/parser/DumpsysParserTest.java
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -15,7 +15,6 @@
*/
package com.android.loganalysis.parser;
-import com.android.loganalysis.item.DumpsysBatteryInfoItem.WakeLockCategory;
import com.android.loganalysis.item.DumpsysItem;
import junit.framework.TestCase;
@@ -29,40 +28,75 @@ import java.util.List;
public class DumpsysParserTest extends TestCase {
/**
- * Test that the dumpsys section of the bugreport is parsed.
+ * Test that normal input is parsed.
*/
- public void testParse() {
+ public void testDumpsysParser() {
List<String> inputBlock = Arrays.asList(
- "-------------------------------------------------------------------------------",
- "DUMP OF SERVICE process1:",
- "-------------------------------------------------------------------------------",
- "DUMP OF SERVICE batteryinfo:",
+ "DUMP OF SERVICE batterystats:",
+ "Battery History (37% used, 95KB used of 256KB, 166 strings using 15KB):",
+ " 0 (9) RESET:TIME: 2014-12-09-11-33-29",
+ " +1s067ms (1) 100 c0500020 -wifi_full_lock -wifi_scan",
+ " +3s297ms (2) 100 80400020 -wake_lock -screen",
+ " +30m02s075ms (1) 100 c0500020 wifi_signal_strength=4 wifi_suppl=completed",
+ " +30m03s012ms (2) 099 c0500020 temp=306 volt=4217",
+ " +33m48s967ms (1) 099 f8400020 +wifi_scan",
+ " +33m49s335ms (2) 098 f0400020 temp=324 -wifi_scan",
"Statistics since last charge:",
- " Kernel Wake lock \"PowerManagerService.WakeLocks\": 5m 10s 61ms (2 times) realtime",
- " Kernel Wake lock \"pm8921_eoc\": 9s 660ms (0 times) realtime",
- "",
- " All partial wake locks:",
- " Wake lock #0 partialWakelock: 5m 9s 260ms (1 times) realtime",
- " Wake lock #1000 AlarmManager: 422ms (7 times) realtime",
- "",
- "-------------------------------------------------------------------------------",
- "DUMP OF SERVICE process2:",
- "-------------------------------------------------------------------------------");
+ " Time on battery: 2h 21m 5s 622ms (12.0%) realtime, 7m 54s 146ms (0.7%) uptime",
+ " Time on battery screen off: 2h 5m 55s 3ms (1%) realtime, 7m 4s 5ms (7%) uptime",
+ " Total run time: 19h 38m 43s 650ms realtime, 17h 25m 32s 175ms uptime",
+ " All kernel wake locks:",
+ " Kernel Wake lock PowerManagerService.WakeLocks: 1h 3m 50s 5ms (8 times) realtime",
+ " Kernel Wake lock event0-2656 : 3m 49s 268ms (2399 times) realtime",
+ " Kernel Wake lock wlan_wd_wake: 3m 34s 639ms (1751 times) realtime",
+ " Kernel Wake lock wlan_rx_wake: 3m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock wlan_tx_wake: 2m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock tx_wake: 1m 19s 887ms (225 times) realtime",
+ " ",
+ " All partial wake locks:",
+ " Wake lock u0a7 NlpWakeLock: 8m 13s 203ms (1479 times) realtime",
+ " Wake lock u0a7 NlpCollectorWakeLock: 6m 29s 18ms (238 times) realtime",
+ " Wake lock u0a7 GCM_CONN_ALARM: 6m 8s 587ms (239 times) realtime",
+ " Wake lock 1000 *alarm*: 5m 11s 316ms (1469 times) realtime",
+ " Wake lock u10 xxx: 4m 11s 316ms (1469 times) realtime",
+ " Wake lock u30 cst: 2m 11s 316ms (1469 times) realtime",
+ " ",
+ " All wakeup reasons:",
+ " Wakeup reason 200:qcom,smd-rpm:222:fc4: 11m 49s 332ms (0 times) realtime",
+ " Wakeup reason 200:qcom,smd-rpm: 48s 45ms (0 times) realtime",
+ " Wakeup reason 2:qcom,smd-rpm:2:f0.qm,mm:22:fc4mi: 3s 417ms (0 times) realtime",
+ " Wakeup reason 188:qcom,smd-adsp:200:qcom,smd-rpm: 1s 656ms (0 times) realtime",
+ " Wakeup reason 58:qcom,smsm-modem:2:qcom,smd-rpm: 6m 16s 1ms (5 times) realtime",
+ " Wakeup reason 57:qcom,smd-modem:200:qcom,smd-rpm: 40s 995ms (0 times) realtime",
+ " Wakeup reason unknown: 8s 455ms (0 times) realtime",
+ " Wakeup reason 9:bcmsdh_sdmmc:2:qcomd-rpm:240:mso: 8m 5s 9ms (0 times) realtime",
+ " ",
+ " 0:",
+ " User activity: 2 other",
+ " Wake lock SCREEN_FROZEN realtime",
+ " Sensor 0: 9s 908ms realtime (1 times)",
+ " Sensor 1: 9s 997ms realtime (1 times)",
+ " Foreground for: 2h 21m 5s 622ms",
+ " Apk android:",
+ " 24 wakeup alarms",
+ " u0a9:",
+ " Mobile network: 8.1KB received, 1.6KB sent (packets 291 received, 342 sent)",
+ " Mobile radio active: 3m 43s 890ms (34.2%) 39x @ 354 mspp",
+ " Sensor 2: 12m 13s 15ms realtime (5 times)",
+ " Sensor 32: (not used)",
+ " Sensor 35: (not used)",
+ "DUMP OF SERVICE procstats:",
+ "COMMITTED STATS FROM 2015-03-20-02-01-02 (checked in):",
+ " * com.android.systemui / u0a22 / v22:",
+ " TOTAL: 100% (159MB-160MB-161MB/153MB-153MB-154MB over 13)",
+ " Persistent: 100% (159MB-160MB-161MB/153MB-153MB-154MB over 13)",
+ " * com.google.process.gapps / u0a9 / v22:",
+ " TOTAL: 100% (22MB-24MB-25MB/18MB-19MB-20MB over 13)",
+ " Imp Fg: 100% (22MB-24MB-25MB/18MB-19MB-20MB over 13)");
- DumpsysItem item = new DumpsysParser().parse(inputBlock);
-
- assertNotNull(item.getBatteryInfo());
- assertEquals(2, item.getBatteryInfo().getWakeLocks(
- WakeLockCategory.LAST_CHARGE_WAKELOCK).size());
- assertEquals(2, item.getBatteryInfo().getWakeLocks(
- WakeLockCategory.LAST_CHARGE_KERNEL_WAKELOCK).size());
- }
-
- /**
- * Test that an empty input returns {@code null}.
- */
- public void testEmptyInput() {
- DumpsysItem item = new DumpsysParser().parse(Arrays.asList(""));
- assertNull(item);
+ DumpsysItem dumpsys = new DumpsysParser().parse(inputBlock);
+ assertNotNull(dumpsys.getBatteryStats());
+ assertNotNull(dumpsys.getProcStats());
}
}
+
diff --git a/tests/src/com/android/loganalysis/parser/DumpsysProcStatsParserTest.java b/tests/src/com/android/loganalysis/parser/DumpsysProcStatsParserTest.java
new file mode 100644
index 0000000..27bb7a4
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/DumpsysProcStatsParserTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.DumpsysProcStatsItem;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link DumpsysProcStatsParser}
+ */
+public class DumpsysProcStatsParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed.
+ */
+ public void testDumpsysProcStatsParser() {
+ List<String> inputBlock = Arrays.asList(
+ "COMMITTED STATS FROM 2015-03-20-02-01-02 (checked in):",
+ " * com.android.systemui / u0a22 / v22:",
+ " TOTAL: 100% (159MB-160MB-161MB/153MB-153MB-154MB over 13)",
+ " Persistent: 100% (159MB-160MB-161MB/153MB-153MB-154MB over 13)",
+ " * com.google.process.gapps / u0a9 / v22:",
+ " TOTAL: 100% (22MB-24MB-25MB/18MB-19MB-20MB over 13)",
+ " Imp Fg: 100% (22MB-24MB-25MB/18MB-19MB-20MB over 13)");
+
+ DumpsysProcStatsItem procstats = new DumpsysProcStatsParser().parse(inputBlock);
+ assertEquals("com.android.systemui", procstats.get("u0a22"));
+ assertEquals("com.google.process.gapps", procstats.get("u0a9"));
+ }
+}
+
diff --git a/tests/src/com/android/loganalysis/parser/InterruptParserTest.java b/tests/src/com/android/loganalysis/parser/InterruptParserTest.java
new file mode 100644
index 0000000..d45f3af
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/InterruptParserTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link InterruptParser}
+ */
+public class InterruptParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed.
+ */
+ public void testInterruptParser() {
+ List<String> inputBlock = Arrays.asList(
+ " Wakeup reason 200:qcom,smd-rpm:222:fc4: 11m 49s 332ms (0 times) realtime",
+ " Wakeup reason 200:qcom,smd-rpm: 48s 45ms (0 times) realtime",
+ " Wakeup reason 2:qcom,smd-rpm:2:f0.qm,mm:22:fc4mi: 3s 417ms (0 times) realtime",
+ " Wakeup reason 188:qcom,smd-adsp:200:qcom,smd-rpm: 1s 656ms (0 times) realtime",
+ " Wakeup reason 58:qcom,smsm-modem:2:qcom,smd-rpm: 6m 16s 1ms (5 times) realtime",
+ " Wakeup reason 57:qcom,smd-modem:200:qcom,smd-rpm: 40s 995ms (0 times) realtime",
+ " Wakeup reason unknown: 8s 455ms (0 times) realtime",
+ " Wakeup reason 9:bcmsdh_sdmmc:2:qcomd-rpm:240:mso: 8m 5s 9ms (0 times) realtime");
+
+ InterruptItem interrupt = new InterruptParser().parse(inputBlock);
+
+ assertEquals(1, interrupt.getInterrupts(
+ InterruptItem.InterruptCategory.WIFI_INTERRUPT).size());
+
+ assertEquals("9:bcmsdh_sdmmc:2:qcomd-rpm:240:mso", interrupt.getInterrupts(
+ InterruptItem.InterruptCategory.WIFI_INTERRUPT).get(0).getName());
+
+ assertEquals(2, interrupt.getInterrupts(
+ InterruptItem.InterruptCategory.MODEM_INTERRUPT).size());
+
+ assertEquals(5, interrupt.getInterrupts(InterruptItem.InterruptCategory.MODEM_INTERRUPT).
+ get(0).getInterruptCount());
+
+ }
+}
+
diff --git a/tests/src/com/android/loganalysis/parser/ProcessUsageParserTest.java b/tests/src/com/android/loganalysis/parser/ProcessUsageParserTest.java
new file mode 100644
index 0000000..e87b4a1
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/ProcessUsageParserTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.ProcessUsageInfoItem;
+import com.android.loganalysis.item.ProcessUsageItem.SensorInfoItem;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link ProcessUsageParser}
+ */
+public class ProcessUsageParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed.
+ */
+ public void testProcessUsageParser() {
+ List<String> inputBlock = Arrays.asList(
+ " 0:",
+ " Mobile network: 173.70KB received, 102.55KB sent (packets 129)",
+ " Mobile radio active: 6m 5s 80ms (14.9%) 80x @ 139 mspp",
+ " 1000:",
+ " Mobile network: 16.43KB received, 26.26KB sent",
+ " Mobile radio active: 1m 17s 489ms (3.2%) 61x @ 179 mspp",
+ " Sensor 44: 27m 18s 207ms realtime (22 times)",
+ " Sensor 36: 6s 483ms realtime (3 times)",
+ " Proc servicemanager:",
+ " CPU: 2s 20ms usr + 4s 60ms krn ; 0ms fg",
+ " Apk android:",
+ " 266 wakeup alarms",
+ " u0a2:",
+ " Mobile network: 16.43KB received, 26.26KB sent",
+ " Mobile radio active: 1m 17s 489ms (3.2%) 61x @ 179 mspp",
+ " Sensor 0: 5s 207ms realtime (2 times)",
+ " Proc servicemanager:",
+ " CPU: 2s 20ms usr + 4s 60ms krn ; 0ms fg",
+ " Apk android:",
+ " 2 wakeup alarms");
+
+ ProcessUsageItem processUsage = new ProcessUsageParser().parse(inputBlock);
+
+ assertEquals(2, processUsage.getProcessUsage().size());
+
+ LinkedList<ProcessUsageInfoItem> processUsageInfo =
+ (LinkedList<ProcessUsageInfoItem>)processUsage.getProcessUsage();
+
+ assertEquals("1000", processUsageInfo.get(1).getProcessUID());
+ assertEquals(266, processUsageInfo.get(1).getAlarmWakeups());
+
+ LinkedList<SensorInfoItem> sensor = processUsageInfo.get(1).getSensorUsage();
+ assertEquals("44", sensor.get(0).getSensorName());
+ assertEquals("36", sensor.get(1).getSensorName());
+ }
+}
+
diff --git a/tests/src/com/android/loganalysis/parser/WakelockParserTest.java b/tests/src/com/android/loganalysis/parser/WakelockParserTest.java
new file mode 100644
index 0000000..bed831b
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/WakelockParserTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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 junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link WakelockParser}
+ */
+public class WakelockParserTest extends TestCase {
+
+ /**
+ * Test that normal input is parsed.
+ */
+ public void testWakelockParser() {
+ List<String> inputBlock = Arrays.asList(
+ " All kernel wake locks:",
+ " Kernel Wake lock PowerManagerService.WakeLocks: 1h 3m 50s 5ms (8 times) realtime",
+ " Kernel Wake lock event0-2656 : 3m 49s 268ms (2399 times) realtime",
+ " Kernel Wake lock wlan_wd_wake: 3m 34s 639ms (1751 times) realtime",
+ " Kernel Wake lock wlan_rx_wake: 3m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock wlan_tx_wake: 2m 19s 887ms (225 times) realtime",
+ " Kernel Wake lock tx_wake: 1m 19s 887ms (225 times) realtime",
+ " ",
+ " All partial wake locks:",
+ " Wake lock u0a7 NlpWakeLock: 8m 13s 203ms (1479 times) realtime",
+ " Wake lock u0a7 NlpCollectorWakeLock: 6m 29s 18ms (238 times) realtime",
+ " Wake lock u0a7 GCM_CONN_ALARM: 6m 8s 587ms (239 times) realtime",
+ " Wake lock 1000 *alarm*: 5m 11s 316ms (1469 times) realtime",
+ " Wake lock u10 xxx: 4m 11s 316ms (1469 times) realtime",
+ " Wake lock u30 cst: 2m 11s 316ms (1469 times) realtime");
+
+ WakelockItem wakelock = new WakelockParser().parse(inputBlock);
+
+ assertEquals(WakelockParser.TOP_WAKELOCK_COUNT,
+ wakelock.getWakeLocks(WakeLockCategory.KERNEL_WAKELOCK).size());
+ assertEquals("event0-2656 ",
+ wakelock.getWakeLocks(WakeLockCategory.KERNEL_WAKELOCK).get(0).getName());
+ assertEquals(229268, wakelock.getWakeLocks(WakeLockCategory.KERNEL_WAKELOCK).
+ get(0).getHeldTime());
+ assertEquals(2399, wakelock.getWakeLocks(WakeLockCategory.KERNEL_WAKELOCK).
+ get(0).getLockedCount());
+
+ assertEquals(WakelockParser.TOP_WAKELOCK_COUNT,
+ wakelock.getWakeLocks(WakeLockCategory.PARTIAL_WAKELOCK).size());
+ assertEquals("NlpWakeLock", wakelock.getWakeLocks(WakeLockCategory.PARTIAL_WAKELOCK).
+ get(0).getName());
+ assertEquals("u0a7", wakelock.getWakeLocks(WakeLockCategory.PARTIAL_WAKELOCK).
+ get(0).getProcessUID());
+ assertEquals(493203, wakelock.getWakeLocks(WakeLockCategory.PARTIAL_WAKELOCK).
+ get(0).getHeldTime());
+ assertEquals(1479, wakelock.getWakeLocks(WakeLockCategory.PARTIAL_WAKELOCK).
+ get(0).getLockedCount());
+ }
+}
+