diff options
Diffstat (limited to 'src/com/android/loganalysis')
8 files changed, 489 insertions, 1 deletions
diff --git a/src/com/android/loganalysis/item/ActivityServiceItem.java b/src/com/android/loganalysis/item/ActivityServiceItem.java new file mode 100644 index 0000000..f149adf --- /dev/null +++ b/src/com/android/loganalysis/item/ActivityServiceItem.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 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 IItem} used to store Activity Service Dumps + */ +public class ActivityServiceItem extends GenericItem { + + /** Constant for JSON output */ + public static final String LOCATION_DUMPS = "LOCATION"; + + private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList( + LOCATION_DUMPS)); + + /** + * The constructor for {@link ActivityServiceItem}. + */ + public ActivityServiceItem() { + super(ATTRIBUTES); + } + + /** + * Get the location dump + */ + public LocationDumpsItem getLocationDumps() { + return (LocationDumpsItem) getAttribute(LOCATION_DUMPS); + } + + /** + * Set the location dump + */ + public void setLocationDumps(LocationDumpsItem location) { + setAttribute(LOCATION_DUMPS, location); + } +} diff --git a/src/com/android/loganalysis/item/BugreportItem.java b/src/com/android/loganalysis/item/BugreportItem.java index 969c90a..e716728 100644 --- a/src/com/android/loganalysis/item/BugreportItem.java +++ b/src/com/android/loganalysis/item/BugreportItem.java @@ -45,10 +45,12 @@ public class BugreportItem extends GenericItem { public static final String SYSTEM_PROPS = "SYSTEM_PROPS"; /** Constant for JSON output */ public static final String DUMPSYS = "DUMPSYS"; + /** Constant for JSON output */ + public static final String ACTIVITY_SERVICE = "ACTIVITY_SERVICE"; private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList( TIME, COMMAND_LINE, MEM_INFO, PROCRANK, TOP, KERNEL_LOG, LAST_KMSG, SYSTEM_LOG, - SYSTEM_PROPS, DUMPSYS)); + SYSTEM_PROPS, DUMPSYS, ACTIVITY_SERVICE)); public static class CommandLineItem extends GenericMapItem<String> { private static final long serialVersionUID = 0L; @@ -200,4 +202,17 @@ public class BugreportItem extends GenericItem { public void setDumpsys(DumpsysItem dumpsys) { setAttribute(DUMPSYS, dumpsys); } + /** + * Get the {@link ActivityServiceItem} of the bugreport. + */ + public ActivityServiceItem getActivityService() { + return (ActivityServiceItem) getAttribute(ACTIVITY_SERVICE); + } + + /** + * Set the {@link ActivityServiceItem} of the bugreport. + */ + public void setActivityService(ActivityServiceItem activityService) { + setAttribute(ACTIVITY_SERVICE, activityService); + } } diff --git a/src/com/android/loganalysis/item/LocationDumpsItem.java b/src/com/android/loganalysis/item/LocationDumpsItem.java new file mode 100644 index 0000000..580145f --- /dev/null +++ b/src/com/android/loganalysis/item/LocationDumpsItem.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2016 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 location dumps. + */ +public class LocationDumpsItem implements IItem { + + /** Constant for JSON output */ + public static final String LOCATION_CLIENTS = "LOCATION_CLIENTS"; + + private Collection<LocationInfoItem> mLocationClients = + new LinkedList<LocationInfoItem>(); + + public static class LocationInfoItem extends GenericItem { + /** Constant for JSON output */ + public static final String PACKAGE = "PACKAGE"; + /** Constant for JSON output */ + public static final String EFFECTIVE_INTERVAL = "EFFECTIVE_INTERVAL"; + /** Constant for JSON output */ + public static final String MIN_INTERVAL = "MIN_INTERVAL"; + /** Constant for JSON output */ + public static final String MAX_INTERVAL = "MAX_INTERVAL"; + /** Constant for JSON output */ + public static final String REQUEST_PRIORITY = "PRIORITY"; + /** Constant for JSON output */ + public static final String LOCATION_DURATION = "LOCATION_DURATION"; + + private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList( + PACKAGE, EFFECTIVE_INTERVAL, MIN_INTERVAL, MAX_INTERVAL, REQUEST_PRIORITY, + LOCATION_DURATION )); + /** + * The constructor for {@link LocationInfoItem} + * + * @param packageName The package that requests location + * @param effective Effective interval of location request + * @param min Min interval of location request + * @param max Max interval of location request + * @param priority The priority of the request + * @param duration Duration of the request + */ + public LocationInfoItem(String packageName, int effective, int min, int max, + String priority, int duration) { + super(ATTRIBUTES); + setAttribute(PACKAGE, packageName); + setAttribute(EFFECTIVE_INTERVAL, effective); + setAttribute(MIN_INTERVAL, min); + setAttribute(MAX_INTERVAL, max); + setAttribute(REQUEST_PRIORITY, priority); + setAttribute(LOCATION_DURATION, duration); + } + + /** + * Get the name of the package + */ + public String getPackage() { + return (String) getAttribute(PACKAGE); + } + + /** + * Get the effective location interval + */ + public int getEffectiveInterval() { + return (int) getAttribute(EFFECTIVE_INTERVAL); + } + + /** + * Get the min location interval + */ + public int getMinInterval() { + return (int) getAttribute(MIN_INTERVAL); + } + + /** + * Get the max location interval + */ + public int getMaxInterval() { + return (int) getAttribute(MAX_INTERVAL); + } + + /** + * Get the priority of location request + */ + public String getPriority() { + return (String) getAttribute(REQUEST_PRIORITY); + } + + /** + * Get the location duration + */ + public int getDuration() { + return (int) getAttribute(LOCATION_DURATION); + } + + } + + /** + * Add a location client {@link LocationDumpsItem}. + * + * @param packageName The package that requests location + * @param effective Effective interval of location request + * @param min Min interval of location request + * @param max Max interval of location request + * @param priority The priority of the request + * @param duration Duration of the request + */ + public void addLocationClient(String packageName, int effective, int min, int max, + String priority, int duration) { + mLocationClients.add(new LocationInfoItem(packageName, effective, min, max, priority, + duration)); + } + + public Collection<LocationInfoItem> getLocationClients() { + return mLocationClients; + } + + /** + * {@inheritDoc} + */ + @Override + public IItem merge(IItem other) throws ConflictingItemException { + throw new ConflictingItemException("Location dumps items cannot be merged"); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isConsistent(IItem other) { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public JSONObject toJson() { + JSONObject object = new JSONObject(); + if (mLocationClients != null) { + try { + JSONArray locationClients = new JSONArray(); + for (LocationInfoItem locationClient : mLocationClients) { + locationClients.put(locationClient.toJson()); + } + object.put(LOCATION_CLIENTS, locationClients); + } catch (JSONException e) { + // Ignore + } + } + + return object; + } +} diff --git a/src/com/android/loganalysis/parser/ActivityServiceParser.java b/src/com/android/loganalysis/parser/ActivityServiceParser.java new file mode 100644 index 0000000..c79d6e5 --- /dev/null +++ b/src/com/android/loganalysis/parser/ActivityServiceParser.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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.LocationDumpsItem; +import com.android.loganalysis.item.ActivityServiceItem; + +import java.util.List; + +/** + * A {@link IParser} to parse the activity service dump section of the bugreport + */ +public class ActivityServiceParser extends AbstractSectionParser { + + private static final String LOCATION_SECTION_REGEX = + "^\\s*SERVICE com.google.android.gms/" + + "com.google.android.location.internal.GoogleLocationManagerService \\w+ pid=\\d+"; + + private static final String NOOP_SECTION_REGEX = "^\\s*SERVICE .*/.*"; + + private LocationServiceParser mLocationParser = new LocationServiceParser(); + + private ActivityServiceItem mActivityServiceItem= null; + private boolean mParsedInput = false; + + /** + * {@inheritDoc} + * + * @return The {@link ActivityServiceItem} + */ + @Override + public ActivityServiceItem parse(List<String> lines) { + setup(); + for (String line : lines) { + if (!mParsedInput && !"".equals(line.trim())) { + mParsedInput = true; + } + parseLine(line); + } + commit(); + return mActivityServiceItem; + } + + /** + * Sets up the parser by adding the section parsers. + */ + protected void setup() { + addSectionParser(mLocationParser, LOCATION_SECTION_REGEX); + addSectionParser(new NoopParser(), NOOP_SECTION_REGEX); + } + + /** + * {@inheritDoc} + */ + @Override + protected void commit() { + // signal EOF + super.commit(); + if (mParsedInput) { + if (mActivityServiceItem == null) { + mActivityServiceItem = new ActivityServiceItem(); + } + } + + if (mActivityServiceItem != null) { + mActivityServiceItem.setLocationDumps( + (LocationDumpsItem) getSection(mLocationParser)); + } + } +} diff --git a/src/com/android/loganalysis/parser/BugreportParser.java b/src/com/android/loganalysis/parser/BugreportParser.java index ece6076..dac1f53 100644 --- a/src/com/android/loganalysis/parser/BugreportParser.java +++ b/src/com/android/loganalysis/parser/BugreportParser.java @@ -15,6 +15,7 @@ */ package com.android.loganalysis.parser; +import com.android.loganalysis.item.ActivityServiceItem; import com.android.loganalysis.item.AnrItem; import com.android.loganalysis.item.BugreportItem; import com.android.loganalysis.item.BugreportItem.CommandLineItem; @@ -55,6 +56,8 @@ public class BugreportParser extends AbstractSectionParser { "------ (SYSTEM|MAIN|MAIN AND SYSTEM) LOG .*"; private static final String ANR_TRACES_SECTION_REGEX = "------ VM TRACES AT LAST ANR .*"; private static final String DUMPSYS_SECTION_REGEX = "------ DUMPSYS .*"; + private static final String ACTIVITY_SERVICE_SECTION_REGEX = + "^------ APP SERVICES \\(dumpsys activity service all\\) ------$"; private static final String NOOP_SECTION_REGEX = "------ .* ------"; private static final String BOOTREASON_PROP = "ro.boot.bootreason"; @@ -112,6 +115,7 @@ public class BugreportParser extends AbstractSectionParser { private KernelLogParser mLastKmsgParser = new KernelLogParser(); private LogcatParser mLogcatParser = new LogcatParser(); private DumpsysParser mDumpsysParser = new DumpsysParser(); + private ActivityServiceParser mActivityServiceParser = new ActivityServiceParser(); private BugreportItem mBugreport = null; private CommandLineItem mCommandLine = new CommandLineItem(); @@ -175,6 +179,7 @@ public class BugreportParser extends AbstractSectionParser { addSectionParser(mKernelLogParser, KERNEL_LOG_SECTION_REGEX); addSectionParser(mLastKmsgParser, LAST_KMSG_SECTION_REGEX); addSectionParser(mDumpsysParser, DUMPSYS_SECTION_REGEX); + addSectionParser(mActivityServiceParser, ACTIVITY_SERVICE_SECTION_REGEX); addSectionParser(new NoopParser(), NOOP_SECTION_REGEX); mKernelLogParser.setAddUnknownBootreason(false); mLastKmsgParser.setAddUnknownBootreason(false); @@ -202,6 +207,7 @@ public class BugreportParser extends AbstractSectionParser { mBugreport.setLastKmsg((KernelLogItem) getSection(mLastKmsgParser)); mBugreport.setSystemProps((SystemPropsItem) getSection(mSystemPropsParser)); mBugreport.setDumpsys((DumpsysItem) getSection(mDumpsysParser)); + mBugreport.setActivityService((ActivityServiceItem) getSection(mActivityServiceParser)); if (mBugreport.getSystemLog() != null && mBugreport.getProcrank() != null) { for (IItem item : mBugreport.getSystemLog().getEvents()) { diff --git a/src/com/android/loganalysis/parser/LocationServiceParser.java b/src/com/android/loganalysis/parser/LocationServiceParser.java new file mode 100644 index 0000000..1f0450f --- /dev/null +++ b/src/com/android/loganalysis/parser/LocationServiceParser.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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.LocationDumpsItem; +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 location request information + */ +public class LocationServiceParser implements IParser { + /** + * Match a valid line such as: + * "Interval effective/min/max 1/0/0[s] Duration: 140[minutes] [com.google.android.gms, + * PRIORITY_NO_POWER, UserLocationProducer] Num requests: 2 Active: true" + */ + private static final Pattern LOCATION_PAT = Pattern.compile( + "^\\s*Interval effective/min/max (\\d+)/(\\d+)/(\\d+)\\[s\\] Duration: (\\d+)" + + "\\[minutes\\]\\s*\\[([\\w.]+), (\\w+)(,.*)?\\] Num requests: \\d+ Active: \\w*"); + + private LocationDumpsItem mItem = new LocationDumpsItem(); + + /** + * {@inheritDoc} + */ + @Override + public LocationDumpsItem parse(List<String> lines) { + Matcher m = null; + for (String line : lines) { + m = LOCATION_PAT.matcher(line); + if (m.matches()) { + mItem.addLocationClient(m.group(5), NumberFormattingUtil.parseIntOrZero(m.group(1)), + NumberFormattingUtil.parseIntOrZero(m.group(2)), + NumberFormattingUtil.parseIntOrZero(m.group(3)), m.group(6), + NumberFormattingUtil.parseIntOrZero(m.group(4))); + continue; + } + } + return mItem; + } + + /** + * Get the {@link LocationDumpsItem}. + * <p> + * Exposed for unit testing. + * </p> + */ + LocationDumpsItem getItem() { + return mItem; + } +} diff --git a/src/com/android/loganalysis/rule/LocationUsageRule.java b/src/com/android/loganalysis/rule/LocationUsageRule.java new file mode 100644 index 0000000..71defa2 --- /dev/null +++ b/src/com/android/loganalysis/rule/LocationUsageRule.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016 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.LocationDumpsItem; +import com.android.loganalysis.item.LocationDumpsItem.LocationInfoItem; + +import java.util.concurrent.TimeUnit; + +import org.json.JSONException; +import org.json.JSONObject; + + +/** + * Rules definition for Process usage + */ +public class LocationUsageRule extends AbstractPowerRule { + + private static final String LOCATION_USAGE_ANALYSIS = "LOCATION_USAGE_ANALYSIS"; + private static final float LOCATION_REQUEST_DURATION_THRESHOLD = 0.1f; // 10% + // GSA requests for location every 285 seconds, anything more frequent is an issue + private static final int LOCATION_INTERVAL_THRESHOLD = 285; + + private StringBuffer mAnalysisBuffer; + + private BugreportItem mBugreportItem = null; + + public LocationUsageRule (BugreportItem bugreportItem) { + super(bugreportItem); + mBugreportItem = bugreportItem; + } + + + @Override + public void applyRule() { + mAnalysisBuffer = new StringBuffer(); + LocationDumpsItem locationDumpsItem = mBugreportItem.getActivityService() + .getLocationDumps(); + final long locationRequestThresholdMs = (long) (getTimeOnBattery() * + LOCATION_REQUEST_DURATION_THRESHOLD); + if (locationDumpsItem != null) { + for (LocationInfoItem locationClient : locationDumpsItem.getLocationClients()) { + final String packageName = locationClient.getPackage(); + final String priority = locationClient.getPriority(); + final int effectiveIntervalSec = locationClient.getEffectiveInterval(); + if (effectiveIntervalSec < LOCATION_INTERVAL_THRESHOLD && + !priority.equals("PRIORITY_NO_POWER") && + (TimeUnit.MINUTES.toMillis(locationClient.getDuration()) > + locationRequestThresholdMs)) { + mAnalysisBuffer.append(String.format("Package %s is requesting for location " + + "updates every %d secs with priority %s", packageName, + effectiveIntervalSec, priority)); + } + } + } + } + + @Override + public JSONObject getAnalysis() { + JSONObject usageAnalysis = new JSONObject(); + try { + usageAnalysis.put(LOCATION_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 index add61e6..57daa19 100644 --- a/src/com/android/loganalysis/rule/RuleEngine.java +++ b/src/com/android/loganalysis/rule/RuleEngine.java @@ -66,5 +66,6 @@ public class RuleEngine { private void addPowerRules() { mRulesList.add(new WakelockRule(mBugreportItem)); mRulesList.add(new ProcessUsageRule(mBugreportItem)); + mRulesList.add(new LocationUsageRule(mBugreportItem)); } } |