Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d960752 authored by Adam Lesinski's avatar Adam Lesinski
Browse files

Split up ComponentName in UsageEvents.Event

Some events in the future may not have originated
from a class, so we shouldn't be using ComponentName.

Bug:17259858
Change-Id: Id7fe3245b91596cf27ae4ec51655602f01665622
parent 4e9c07c0
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -5715,8 +5715,9 @@ package android.app.usage {
  public static final class UsageEvents.Event {
    ctor public UsageEvents.Event();
    method public android.content.ComponentName getComponent();
    method public java.lang.String getClassName();
    method public int getEventType();
    method public java.lang.String getPackageName();
    method public long getTimeStamp();
    field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
    field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
+64 −15
Original line number Diff line number Diff line
@@ -65,7 +65,12 @@ public final class UsageEvents implements Parcelable {
        /**
         * {@hide}
         */
        public ComponentName mComponent;
        public String mPackage;

        /**
         * {@hide}
         */
        public String mClass;

        /**
         * {@hide}
@@ -78,10 +83,26 @@ public final class UsageEvents implements Parcelable {
        public int mEventType;

        /**
         * The component this event represents.
         * TODO(adamlesinski): Removed before release.
         * {@hide}
         */
        public ComponentName getComponent() {
            return mComponent;
            return new ComponentName(mPackage, mClass);
        }

        /**
         * The package name of the source of this event.
         */
        public String getPackageName() {
            return mPackage;
        }

        /**
         * The class name of the source of this event. This may be null for
         * certain events.
         */
        public String getClassName() {
            return mClass;
        }

        /**
@@ -115,7 +136,7 @@ public final class UsageEvents implements Parcelable {
     * In order to save space, since ComponentNames will be duplicated everywhere,
     * we use a map and index into it.
     */
    private ComponentName[] mComponentNameTable;
    private String[] mStringPool;

    /**
     * Construct the iterator from a parcel.
@@ -125,7 +146,7 @@ public final class UsageEvents implements Parcelable {
        mEventCount = in.readInt();
        mIndex = in.readInt();
        if (mEventCount > 0) {
            mComponentNameTable = in.createTypedArray(ComponentName.CREATOR);
            mStringPool = in.createStringArray();

            final int listByteLength = in.readInt();
            final int positionInParcel = in.readInt();
@@ -149,8 +170,8 @@ public final class UsageEvents implements Parcelable {
     * Construct the iterator in preparation for writing it to a parcel.
     * {@hide}
     */
    public UsageEvents(List<Event> events, ComponentName[] nameTable) {
        mComponentNameTable = nameTable;
    public UsageEvents(List<Event> events, String[] stringPool) {
        mStringPool = stringPool;
        mEventCount = events.size();
        mEventsToWrite = events;
    }
@@ -178,8 +199,19 @@ public final class UsageEvents implements Parcelable {
            return false;
        }

        final int index = mParcel.readInt();
        eventOut.mComponent = mComponentNameTable[index];
        final int packageIndex = mParcel.readInt();
        if (packageIndex >= 0) {
            eventOut.mPackage = mStringPool[packageIndex];
        } else {
            eventOut.mPackage = null;
        }

        final int classIndex = mParcel.readInt();
        if (classIndex >= 0) {
            eventOut.mClass = mStringPool[classIndex];
        } else {
            eventOut.mClass = null;
        }
        eventOut.mEventType = mParcel.readInt();
        eventOut.mTimeStamp = mParcel.readLong();
        mIndex++;
@@ -206,12 +238,20 @@ public final class UsageEvents implements Parcelable {
        return 0;
    }

    private int findStringIndex(String str) {
        final int index = Arrays.binarySearch(mStringPool, str);
        if (index < 0) {
            throw new IllegalStateException("String '" + str + "' is not in the string pool");
        }
        return index;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mEventCount);
        dest.writeInt(mIndex);
        if (mEventCount > 0) {
            dest.writeTypedArray(mComponentNameTable, flags);
            dest.writeStringArray(mStringPool);

            if (mEventsToWrite != null) {
                // Write out the events
@@ -221,12 +261,21 @@ public final class UsageEvents implements Parcelable {
                    for (int i = 0; i < mEventCount; i++) {
                        final Event event = mEventsToWrite.get(i);

                        int index = Arrays.binarySearch(mComponentNameTable, event.getComponent());
                        if (index < 0) {
                            throw new IllegalStateException(event.getComponent().toShortString() +
                                    " is not in the component name table");
                        final int packageIndex;
                        if (event.mPackage != null) {
                            packageIndex = findStringIndex(event.mPackage);
                        } else {
                            packageIndex = -1;
                        }

                        final int classIndex;
                        if (event.mClass != null) {
                            classIndex = findStringIndex(event.mClass);
                        } else {
                            classIndex = -1;
                        }
                        p.writeInt(index);
                        p.writeInt(packageIndex);
                        p.writeInt(classIndex);
                        p.writeInt(event.getEventType());
                        p.writeLong(event.getTimeStamp());
                    }
+21 −18
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ package com.android.server.usage;
import android.app.usage.TimeSparseArray;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.content.ComponentName;
import android.util.ArrayMap;
import android.util.ArraySet;

class IntervalStats {
    public long beginTime;
@@ -28,10 +28,11 @@ class IntervalStats {
    public final ArrayMap<String, UsageStats> stats = new ArrayMap<>();
    public TimeSparseArray<UsageEvents.Event> events;

    // Maps flattened string representations of component names to ComponentName.
    // This helps save memory from using many duplicate ComponentNames and
    // parse time when reading XML.
    private final ArrayMap<String, ComponentName> mComponentNames = new ArrayMap<>();
    // A string cache. This is important as when we're parsing XML files, we don't want to
    // keep hundreds of strings that have the same contents. We will read the string
    // and only keep it if it's not in the cache. The GC will take care of the
    // strings that had identical copies in the cache.
    private final ArraySet<String> mStringCache = new ArraySet<>();

    UsageStats getOrCreateUsageStats(String packageName) {
        UsageStats usageStats = stats.get(packageName);
@@ -63,19 +64,21 @@ class IntervalStats {
        endTime = timeStamp;
    }

    /**
     * Return a ComponentName for the given string representation. This will use a cached
     * copy of the ComponentName if possible, otherwise it will parse and add it to the
     * internal cache.
     */
    ComponentName getCachedComponentName(String str) {
        ComponentName name = mComponentNames.get(str);
        if (name == null) {
            name = ComponentName.unflattenFromString(str);
            if (name != null) {
                mComponentNames.put(str, name);
    private String getCachedStringRef(String str) {
        final int index = mStringCache.indexOf(str);
        if (index < 0) {
            mStringCache.add(str);
            return str;
        }
        return mStringCache.valueAt(index);
    }

    UsageEvents.Event buildEvent(String packageName, String className) {
        UsageEvents.Event event = new UsageEvents.Event();
        event.mPackage = getCachedStringRef(packageName);
        if (className != null) {
            event.mClass = getCachedStringRef(className);
        }
        return name;
        return event;
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -354,7 +354,8 @@ public class UsageStatsService extends SystemService implements
            }

            UsageEvents.Event event = new UsageEvents.Event();
            event.mComponent = component;
            event.mPackage = component.getPackageName();
            event.mClass = component.getClassName();
            event.mTimeStamp = timeStamp;
            event.mEventType = eventType;
            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
+24 −10
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ final class UsageStatsXmlV1 {
    private static final String END_TIME_ATTR = "endTime";
    private static final String PACKAGE_TAG = "package";
    private static final String NAME_ATTR = "name";
    private static final String PACKAGE_ATTR = "package";
    private static final String CLASS_ATTR = "class";
    private static final String TOTAL_TIME_ACTIVE_ATTR = "totalTimeActive";
    private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
    private static final String LAST_EVENT_ATTR = "lastEvent";
@@ -80,18 +82,27 @@ final class UsageStatsXmlV1 {
            return null;
        }

        String packageName = XmlUtils.readStringAttribute(parser, PACKAGE_ATTR);
        String className;
        if (packageName == null) {
            // Try getting the component name if it exists.
            final String componentName = XmlUtils.readStringAttribute(parser, NAME_ATTR);
            if (componentName == null) {
            throw new ProtocolException("no " + NAME_ATTR + " attribute present");
                throw new ProtocolException("no " + NAME_ATTR + " or " + PACKAGE_ATTR +
                        " attribute present");
            }

        ComponentName component = statsOut.getCachedComponentName(componentName);
            ComponentName component = ComponentName.unflattenFromString(componentName);
            if (component == null) {
                throw new ProtocolException("ComponentName " + componentName + " is invalid");
            }

        UsageEvents.Event event = new UsageEvents.Event();
        event.mComponent = component;
            packageName = component.getPackageName();
            className = component.getClassName();
        } else {
            className = XmlUtils.readStringAttribute(parser, CLASS_ATTR);
        }

        UsageEvents.Event event = statsOut.buildEvent(packageName, className);
        event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR);
        event.mTimeStamp = XmlUtils.readLongAttribute(parser, TIME_ATTR);
        XmlUtils.skipCurrentTag(parser);
@@ -112,7 +123,10 @@ final class UsageStatsXmlV1 {
    private static void writeEvent(FastXmlSerializer serializer, UsageEvents.Event event)
            throws IOException {
        serializer.startTag(null, EVENT_LOG_TAG);
        serializer.attribute(null, NAME_ATTR, event.getComponent().flattenToString());
        serializer.attribute(null, PACKAGE_ATTR, event.mPackage);
        if (event.mClass != null) {
            serializer.attribute(null, CLASS_ATTR, event.mClass);
        }
        serializer.attribute(null, TYPE_ATTR, Integer.toString(event.getEventType()));
        serializer.attribute(null, TIME_ATTR, Long.toString(event.getTimeStamp()));
        serializer.endTag(null, EVENT_LOG_TAG);
Loading