diff options
author | avellore <avellore@google.com> | 2015-05-19 12:21:25 -0700 |
---|---|---|
committer | avellore <avellore@google.com> | 2015-05-19 17:22:23 -0700 |
commit | c62fad09df43054df2d755ef7e43d6085656c04b (patch) | |
tree | dc972167eb160cf4580c806c52d32b87e0e358fe | |
parent | 45eae46848a8ce314029a718ff5e5bded76fe3ce (diff) | |
download | loganalysis-c62fad09df43054df2d755ef7e43d6085656c04b.tar.gz |
Parse the battery usage statistics
Change-Id: I5000e4352ded2eaa004bc486242c241bcdf4dada
6 files changed, 344 insertions, 4 deletions
diff --git a/src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java b/src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java index a1ac0b0..6a06f4e 100644 --- a/src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java +++ b/src/com/android/loganalysis/item/BatteryStatsDetailedInfoItem.java @@ -28,6 +28,8 @@ public class BatteryStatsDetailedInfoItem implements IItem { /** Constant for JSON output */ public static final String SCREEN_ON_TIME = "SCREEN_ON_TIME"; /** Constant for JSON output */ + public static final String BATTERY_USAGE = "BATTERY_USAGE"; + /** Constant for JSON output */ public static final String WAKELOCKS = "WAKELOCKS"; /** Constant for JSON output */ public static final String INTERRUPTS = "INTERRUPTS"; @@ -36,6 +38,7 @@ public class BatteryStatsDetailedInfoItem implements IItem { private long mTimeOnBattery = 0; private long mScreenOnTime = 0; + private BatteryUsageItem mBatteryUsageItem = null; private WakelockItem mWakelockItem = null; private InterruptItem mInterruptItem = null; private ProcessUsageItem mprocessUsageItem = null; @@ -76,6 +79,13 @@ public class BatteryStatsDetailedInfoItem implements IItem { } /** + * Set the process usage {@link BatteryUsageItem} + */ + public void setBatteryUsageItem(BatteryUsageItem batteryUsageItem) { + mBatteryUsageItem = batteryUsageItem; + } + + /** * Get the time on battery */ public long getTimeOnBattery() { @@ -111,6 +121,13 @@ public class BatteryStatsDetailedInfoItem implements IItem { } /** + * Get the battery usage summary {@link BatteryUsageItem} + */ + public BatteryUsageItem getBatteryUsageItem() { + return mBatteryUsageItem; + } + + /** * {@inheritDoc} */ @Override @@ -139,6 +156,9 @@ public class BatteryStatsDetailedInfoItem implements IItem { if (mScreenOnTime > 0) { batteryStatsComponent.put(SCREEN_ON_TIME, getScreenOnTime()); } + if (mBatteryUsageItem != null) { + batteryStatsComponent.put(BATTERY_USAGE, mBatteryUsageItem.toJson()); + } if (mWakelockItem != null) { batteryStatsComponent.put(WAKELOCKS, mWakelockItem.toJson()); } diff --git a/src/com/android/loganalysis/item/BatteryUsageItem.java b/src/com/android/loganalysis/item/BatteryUsageItem.java new file mode 100644 index 0000000..07bbef3 --- /dev/null +++ b/src/com/android/loganalysis/item/BatteryUsageItem.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.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 battery usage stats + */ +public class BatteryUsageItem implements IItem { + + /** Constant for JSON output */ + public static final String BATTERY_USAGE = "BATTERY_USAGE"; + /** Constant for JSON output */ + public static final String BATTERY_CAPACITY = "BATTERY_CAPACITY"; + + private Collection<BatteryUsageInfoItem> mBatteryUsage = new LinkedList<BatteryUsageInfoItem>(); + + private int mBatteryCapacity = 0; + + public static class BatteryUsageInfoItem extends GenericItem { + /** Constant for JSON output */ + public static final String NAME = "NAME"; + /** Constant for JSON output */ + public static final String USAGE = "USAGE"; + + private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList( + NAME, USAGE)); + + /** + * The constructor for {@link BatteryUsageItem} + * + * @param name The name of the wake lock + * @param usage Usage in mAh + */ + public BatteryUsageInfoItem(String name, double usage) { + super(ATTRIBUTES); + setAttribute(NAME, name); + setAttribute(USAGE, usage); + } + + /** + * Get the name of the wake lock. + */ + public String getName() { + return (String) getAttribute(NAME); + } + + /** + * Get the battery usage + */ + public double getUsage() { + return (double) getAttribute(USAGE); + } + } + + /** + * Add a battery usage from the battery stats section. + * + * @param name The name of the process + * @param usage The usage in mAh + */ + public void addBatteryUsage(String name, double usage) { + mBatteryUsage.add(new BatteryUsageInfoItem(name, usage)); + } + + public int getBatteryCapacity() { + return mBatteryCapacity; + } + + public List<BatteryUsageInfoItem> getBatteryUsage() { + return (List<BatteryUsageInfoItem>)mBatteryUsage; + } + + public void setBatteryCapacity(int capacity) { + mBatteryCapacity = capacity; + } + + /** + * {@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 (mBatteryUsage != null) { + try { + object.put(BATTERY_CAPACITY, mBatteryCapacity); + JSONArray usageInfo = new JSONArray(); + for (BatteryUsageInfoItem usage : mBatteryUsage) { + usageInfo.put(usage.toJson()); + } + object.put(BATTERY_USAGE, usageInfo); + } catch (JSONException e) { + // Ignore + } + } + return object; + } +} diff --git a/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java b/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java index f1bbed0..b800371 100644 --- a/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java +++ b/src/com/android/loganalysis/parser/BatteryStatsDetailedInfoParser.java @@ -17,6 +17,7 @@ package com.android.loganalysis.parser; import com.android.loganalysis.item.BatteryStatsDetailedInfoItem; +import com.android.loganalysis.item.BatteryUsageItem; import com.android.loganalysis.item.InterruptItem; import com.android.loganalysis.item.ProcessUsageItem; import com.android.loganalysis.item.WakelockItem; @@ -32,6 +33,7 @@ import java.util.regex.Pattern; */ public class BatteryStatsDetailedInfoParser extends AbstractSectionParser { + private static final String BATTERY_USAGE_SECTION_REGEX = "^\\s*Estimated power use \\(mAh\\):$"; 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:$"; @@ -49,6 +51,7 @@ public class BatteryStatsDetailedInfoParser extends AbstractSectionParser { + "screen off: (?:(\\d+)d)?\\s?(?:(\\d+)h)?\\s?(?:(\\d+)m)?\\s?(?:(\\d+)s)?\\s?" + "(?:(\\d+)ms).*"); + private BatteryUsageParser mBatteryUsageParser = new BatteryUsageParser(); private WakelockParser mWakelockParser = new WakelockParser(); private InterruptParser mInterruptParser = new InterruptParser(); private ProcessUsageParser mProcessUsageParser = new ProcessUsageParser(); @@ -123,6 +126,7 @@ public class BatteryStatsDetailedInfoParser extends AbstractSectionParser { */ protected void setup() { setParser(mBatteryTimeParser); + addSectionParser(mBatteryUsageParser, BATTERY_USAGE_SECTION_REGEX); addSectionParser(mWakelockParser, WAKELOCK_SECTION_REGEX); addSectionParser(mInterruptParser, INTERRUPT_SECTION_REGEX); addSectionParser(mProcessUsageParser, PROCESS_USAGE_SECTION_REGEX); @@ -149,17 +153,19 @@ public class BatteryStatsDetailedInfoParser extends AbstractSectionParser { super.commit(); if (mParsedInput) { if (mBatteryStatsDetailedInfoItem == null) { - mBatteryStatsDetailedInfoItem = new BatteryStatsDetailedInfoItem(); + mBatteryStatsDetailedInfoItem = new BatteryStatsDetailedInfoItem(); } } if (mBatteryStatsDetailedInfoItem != null) { + mBatteryStatsDetailedInfoItem.setBatteryUsageItem( + (BatteryUsageItem) getSection(mBatteryUsageParser)); mBatteryStatsDetailedInfoItem.setWakelockItem( - (WakelockItem) getSection(mWakelockParser)); + (WakelockItem) getSection(mWakelockParser)); mBatteryStatsDetailedInfoItem.setInterruptItem( - (InterruptItem) getSection(mInterruptParser)); + (InterruptItem) getSection(mInterruptParser)); mBatteryStatsDetailedInfoItem.setProcessUsageItem( - (ProcessUsageItem) getSection(mProcessUsageParser)); + (ProcessUsageItem) getSection(mProcessUsageParser)); } } } diff --git a/src/com/android/loganalysis/parser/BatteryUsageParser.java b/src/com/android/loganalysis/parser/BatteryUsageParser.java new file mode 100644 index 0000000..92cb5d2 --- /dev/null +++ b/src/com/android/loganalysis/parser/BatteryUsageParser.java @@ -0,0 +1,68 @@ +/* + * 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.BatteryUsageItem; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A {@link IParser} to parse battery usage statistics + */ +public class BatteryUsageParser implements IParser { + + /** + * Matches: Capacity: 3220, Computed drain: 11.0, actual drain: 0 + */ + private static final Pattern Capacity = Pattern.compile( + "^\\s*Capacity: (\\d+), Computed drain: \\d+.*"); + + private static final Pattern Usage = Pattern.compile("^\\s*(.*): (\\d+(\\.\\d*)?)"); + private BatteryUsageItem mItem = new BatteryUsageItem(); + + /** + * {@inheritDoc} + * + * @return The {@link BatteryUsageItem}. + */ + @Override + public BatteryUsageItem parse(List<String> lines) { + for (String line : lines) { + Matcher m = Capacity.matcher(line); + if(m.matches()) { + mItem.setBatteryCapacity(Integer.parseInt(m.group(1))); + } else { + m = Usage.matcher(line); + if (m.matches()) { + mItem.addBatteryUsage(m.group(1), Double.parseDouble(m.group(2))); + } + } + } + return mItem; + } + + /** + * Get the {@link BatteryUsageItem}. + * <p> + * Exposed for unit testing. + * </p> + */ + BatteryUsageItem getItem() { + return mItem; + } +} diff --git a/tests/src/com/android/loganalysis/item/BatteryUsageItemTest.java b/tests/src/com/android/loganalysis/item/BatteryUsageItemTest.java new file mode 100644 index 0000000..b44a432 --- /dev/null +++ b/tests/src/com/android/loganalysis/item/BatteryUsageItemTest.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.BatteryUsageItem.BatteryUsageInfoItem; + +import junit.framework.TestCase; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Unit test for {@link BatteryUsageItem}. + */ +public class BatteryUsageItemTest extends TestCase { + + /** + * Test that {@link BatteryUsageItem#toJson()} returns correctly. + */ + public void testToJson() throws JSONException { + BatteryUsageItem item = new BatteryUsageItem(); + item.addBatteryUsage("Cell standby", 2925); + item.addBatteryUsage("Uid u0a71", 68.1); + // Convert to JSON string and back again + JSONObject output = new JSONObject(item.toJson().toString()); + + assertTrue(output.has(BatteryUsageItem.BATTERY_CAPACITY)); + assertTrue(output.get(BatteryUsageItem.BATTERY_USAGE) instanceof JSONArray); + + JSONArray usage = output.getJSONArray(BatteryUsageItem.BATTERY_USAGE); + + assertEquals(2, usage.length()); + assertTrue(usage.getJSONObject(0).has(BatteryUsageInfoItem.NAME)); + assertTrue(usage.getJSONObject(0).has(BatteryUsageInfoItem.USAGE)); + + assertTrue(usage.getJSONObject(1).has(BatteryUsageInfoItem.NAME)); + assertTrue(usage.getJSONObject(1).has(BatteryUsageInfoItem.USAGE)); + } +} diff --git a/tests/src/com/android/loganalysis/parser/BatteryUsageParserTest.java b/tests/src/com/android/loganalysis/parser/BatteryUsageParserTest.java new file mode 100644 index 0000000..20a9a2e --- /dev/null +++ b/tests/src/com/android/loganalysis/parser/BatteryUsageParserTest.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.parser; + +import com.android.loganalysis.item.BatteryUsageItem; + +import junit.framework.TestCase; + +import java.util.Arrays; +import java.util.List; + +/** + * Unit tests for {@link BatteryUsageParser} + */ +public class BatteryUsageParserTest extends TestCase { + + private static final double EPSILON = 1e-3; + /** + * Test that normal input is parsed. + */ + public void testBatteryUsageParser() { + List<String> inputBlock = Arrays.asList( + " Capacity: 3220, Computed drain: 11.0, actual drain: 0", + " Screen: 8.93", + " Idle: 1.23", + " Uid 0: 0.281", + " Uid u0a36: 0.200", + " Uid 1000: 0.165", + " Uid 1013: 0.0911", + " Uid u0a16: 0.0441"); + + BatteryUsageItem usage = new BatteryUsageParser().parse(inputBlock); + + assertEquals(3220, usage.getBatteryCapacity()); + assertEquals(7, usage.getBatteryUsage().size()); + + assertEquals("Screen", usage.getBatteryUsage().get(0).getName()); + assertEquals(8.93, usage.getBatteryUsage().get(0).getUsage(), EPSILON); + assertEquals("Uid u0a16", usage.getBatteryUsage().get(6).getName()); + assertEquals(0.0441, usage.getBatteryUsage().get(6).getUsage()); + } +} + |