diff options
author | Joe Onorato <joeo@google.com> | 2018-11-16 16:26:13 -0800 |
---|---|---|
committer | Joe Onorato <joeo@google.com> | 2018-11-29 10:48:26 -0800 |
commit | 6e6208769903f2fd466250033abf7084fbef550e (patch) | |
tree | 2d115e1e0fab4fcc4e5964bb5769216d69c25256 /tools/powermodel/src | |
parent | a3f265fa2e28a2ea1f4fc0e7eeea64bbb1423028 (diff) |
Add the concept of apps to the battery stats parser.
AttributionKey is how we identify an app. It contains either
a set of package names, read from the uid records from batterystats
(or later UidMap from statsd), or one of the hard coded SpecialApps.
Test: atest frameworks/base/tools/powermodel --host
Change-Id: If2dee6bffd2d3dafccfeff5c92bafc651b356b15
Diffstat (limited to 'tools/powermodel/src')
3 files changed, 264 insertions, 0 deletions
diff --git a/tools/powermodel/src/com/android/powermodel/AttributionKey.java b/tools/powermodel/src/com/android/powermodel/AttributionKey.java new file mode 100644 index 000000000000..f19e0b7373c7 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/AttributionKey.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.util.Set; +import java.util.HashSet; + +import com.google.common.collect.ImmutableSet; + +public class AttributionKey { + private final int mUid; + private final ImmutableSet<String> mPackages; + private final SpecialApp mSpecialApp; + + public AttributionKey(SpecialApp specialApp) { + mUid = -1; + mPackages = ImmutableSet.of(); + mSpecialApp = specialApp; + } + + public AttributionKey(int uid, Set<String> packages) { + mUid = uid; + mPackages = ImmutableSet.copyOf(packages); + mSpecialApp = null; + } + + public ImmutableSet<String> getPackages() { + return mPackages; + } + + public boolean hasPackage(String pkg) { + return mPackages.contains(pkg); + } + + public SpecialApp getSpecialApp() { + return mSpecialApp; + } + + public boolean isSpecialApp() { + return mSpecialApp != null; + } + + /** + * Returns the uid for this attribution, or -1 if there isn't one + * (e.g. if it is a special app). + */ + public int getUid() { + return mUid; + } + @Override + public int hashCode() { + int hash = 7; + hash = (31 * hash) + (mUid); + hash = (31 * hash) + (mPackages == null ? 0 : mPackages.hashCode()); + hash = (31 * hash) + (mSpecialApp == null ? 0 : mSpecialApp.hashCode()); + return hash; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null) { + return false; + } + if (this.getClass() != o.getClass()) { + return false; + } + final AttributionKey that = (AttributionKey)o; + return (this.mUid == that.mUid) + && this.mPackages != null && this.mPackages.equals(that.mPackages) + && this.mSpecialApp != null && this.mSpecialApp.equals(that.mSpecialApp); + } + + @Override + public String toString() { + final StringBuilder str = new StringBuilder("AttributionKey("); + if (mUid >= 0) { + str.append(" uid="); + str.append(mUid); + } + if (mPackages.size() > 0) { + str.append(" packages=["); + for (String pkg: mPackages) { + str.append(' '); + str.append(pkg); + } + str.append(" ]"); + } + if (mSpecialApp != null) { + str.append(" specialApp="); + str.append(mSpecialApp.name()); + } + str.append(" )"); + return str.toString(); + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/RawBatteryStats.java b/tools/powermodel/src/com/android/powermodel/RawBatteryStats.java index 28004f50ee8d..d0c1790f4774 100644 --- a/tools/powermodel/src/com/android/powermodel/RawBatteryStats.java +++ b/tools/powermodel/src/com/android/powermodel/RawBatteryStats.java @@ -57,6 +57,15 @@ public class RawBatteryStats { private ImmutableMap<String,ImmutableList<Record>> mRecordsByType; /** + * The attribution keys for which we have data (corresponding to UIDs we've seen). + * <p> + * Does not include the synthetic apps. + * <p> + * Don't use this before {@link #indexRecords()} has been called. + */ + private ImmutableSet<AttributionKey> mApps; + + /** * The warnings that have been issued during parsing. */ private ArrayList<Warning> mWarnings = new ArrayList<Warning>(); @@ -687,6 +696,13 @@ public class RawBatteryStats { } /** + * Get the UIDs that are covered by this batterystats dump. + */ + public Set<AttributionKey> getApps() { + return mApps; + } + + /** * No public constructor. Use {@link #parse}. */ private RawBatteryStats() { @@ -721,6 +737,9 @@ public class RawBatteryStats { // Gather the records by class name for the getSingle() and getMultiple() functions. indexRecords(); + + // Gather the uids from all the places UIDs come from, for getApps(). + indexApps(); } /** @@ -832,6 +851,53 @@ public class RawBatteryStats { } /** + * Collect the UIDs from the csv. + * + * They come from two places. + * <ul> + * <li>The uid to package name map entries ({@link #Uid}) at the beginning. + * <li>The uid fields of the rest of the entries, some of which might not + * have package names associated with them. + * </ul> + * + * TODO: Is this where we should also do the logic about the special UIDs? + */ + private void indexApps() { + final HashMap<Integer,HashSet<String>> uids = new HashMap<Integer,HashSet<String>>(); + + // The Uid rows, from which we get package names + for (Uid record: getMultiple(Uid.class)) { + HashSet<String> list = uids.get(record.uidKey); + if (list == null) { + list = new HashSet<String>(); + uids.put(record.uidKey, list); + } + list.add(record.pkg); + } + + // The uid fields of everything + for (Record record: mRecords) { + // The 0 in the INFO records isn't really root, it's just unfilled data. + // The root uid (0) will show up practically in every record, but don't force it. + if (record.category != Category.INFO) { + if (uids.get(record.uid) == null) { + // There is no other data about this UID, but it does exist! + uids.put(record.uid, new HashSet<String>()); + } + } + } + + // Turn our temporary lists of package names into AttributionKeys. + final HashSet<AttributionKey> result = new HashSet<AttributionKey>(); + for (HashMap.Entry<Integer,HashSet<String>> entry: uids.entrySet()) { + result.add(new AttributionKey(entry.getKey(), entry.getValue())); + } + + // Initialize here so uninitialized access will result in NPE. + mApps = ImmutableSet.copyOf(result); + } + + /** * Init the factory classes. */ static { diff --git a/tools/powermodel/src/com/android/powermodel/SpecialApp.java b/tools/powermodel/src/com/android/powermodel/SpecialApp.java new file mode 100644 index 000000000000..df1e1fbda5f6 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/SpecialApp.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 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.powermodel; + +/** + * Identifiers for well-known apps that have unique characteristics. + * + * @more + * This includes three categories: + * <ul> + * <li><b>Built-in system components</b> – These have predefined UIDs that are + * always the same. For example, the system UID is always 1000.</li> + * <li><b>Well known apps with shared UIDs</b> – These do not have predefined + * UIDs (i.e. are different on each device), but since they have shared UIDs + * with varying sets of package names (GmsCore is the canonical example), we + * have special logic to capture these into a single entity with a well defined + * key. These have the {@link #uid uid} field set to + * {@link Uid#UID_VARIES Uid.UID_VARIES}.</li> + * <li><b>Synthetic remainder app</b> – The {@link #REMAINDER REMAINDER} app doesn't + * represent a real app. It contains accounting for usage which is not attributed + * to any UID. This app has the {@link #uid uid} field set to + * {@link Uid#UID_SYNTHETIC Uid.UID_SYNTHETIC}.</li> + * </ul> + */ +public enum SpecialApp { + + /** + * Synthetic app that accounts for the remaining amount of resources used + * that is unaccounted for by apps, or overcounted because of inaccuracies + * in the model. + */ + REMAINDER(Uid.UID_SYNTHETIC), + + /** + * Synthetic app that holds system-wide numbers, for example the total amount + * of various resources used, device-wide. + */ + GLOBAL(Uid.UID_SYNTHETIC), + + SYSTEM(1000), + + GOOGLE_SERVICES(Uid.UID_VARIES); + + /** + * Constants for SpecialApps where the uid is not actually a UID. + */ + public static class Uid { + /** + * Constant to indicate that this special app does not have a fixed UID. + */ + public static final int UID_VARIES = -1; + + /** + * Constant to indicate that this special app is not actually an app with a UID. + * + * @see SpecialApp#REMAINDER + * @see SpecialApp#GLOBAL + */ + public static final int UID_SYNTHETIC = -2; + } + + /** + * The fixed UID value of this special app, or {@link #UID_VARIES} if there + * isn't one. + */ + public final int uid; + + private SpecialApp(int uid) { + this.uid = uid; + } +} |