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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
p.writeInt(index);
|
||||
|
||||
final int classIndex;
|
||||
if (event.mClass != null) {
|
||||
classIndex = findStringIndex(event.mClass);
|
||||
} else {
|
||||
classIndex = -1;
|
||||
}
|
||||
p.writeInt(packageIndex);
|
||||
p.writeInt(classIndex);
|
||||
p.writeInt(event.getEventType());
|
||||
p.writeLong(event.getTimeStamp());
|
||||
}
|
||||
|
||||
@@ -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 name;
|
||||
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 event;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
final String componentName = XmlUtils.readStringAttribute(parser, NAME_ATTR);
|
||||
if (componentName == null) {
|
||||
throw new ProtocolException("no " + NAME_ATTR + " attribute present");
|
||||
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 + " or " + PACKAGE_ATTR +
|
||||
" attribute present");
|
||||
}
|
||||
ComponentName component = ComponentName.unflattenFromString(componentName);
|
||||
if (component == null) {
|
||||
throw new ProtocolException("ComponentName " + componentName + " is invalid");
|
||||
}
|
||||
|
||||
packageName = component.getPackageName();
|
||||
className = component.getClassName();
|
||||
} else {
|
||||
className = XmlUtils.readStringAttribute(parser, CLASS_ATTR);
|
||||
}
|
||||
|
||||
ComponentName component = statsOut.getCachedComponentName(componentName);
|
||||
if (component == null) {
|
||||
throw new ProtocolException("ComponentName " + componentName + " is invalid");
|
||||
}
|
||||
|
||||
UsageEvents.Event event = new UsageEvents.Event();
|
||||
event.mComponent = component;
|
||||
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);
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.app.usage.TimeSparseArray;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.app.usage.UsageStats;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.ComponentName;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -114,7 +113,7 @@ class UserUsageStatsService {
|
||||
|
||||
void reportEvent(UsageEvents.Event event) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, mLogPrefix + "Got usage event for " + event.getComponent().getPackageName()
|
||||
Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage
|
||||
+ "[" + event.getTimeStamp() + "]: "
|
||||
+ eventToString(event.getEventType()));
|
||||
}
|
||||
@@ -130,7 +129,7 @@ class UserUsageStatsService {
|
||||
mCurrentStats[UsageStatsManager.INTERVAL_DAILY].events.put(event.getTimeStamp(), event);
|
||||
|
||||
for (IntervalStats stats : mCurrentStats) {
|
||||
stats.update(event.getComponent().getPackageName(), event.getTimeStamp(),
|
||||
stats.update(event.mPackage, event.getTimeStamp(),
|
||||
event.getEventType());
|
||||
}
|
||||
|
||||
@@ -203,17 +202,21 @@ class UserUsageStatsService {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArraySet<ComponentName> names = new ArraySet<>();
|
||||
ArraySet<String> names = new ArraySet<>();
|
||||
ArrayList<UsageEvents.Event> results = new ArrayList<>();
|
||||
final int size = events.size();
|
||||
for (int i = startIndex; i < size; i++) {
|
||||
if (events.keyAt(i) >= endTime) {
|
||||
break;
|
||||
}
|
||||
names.add(events.valueAt(i).getComponent());
|
||||
results.add(events.valueAt(i));
|
||||
final UsageEvents.Event event = events.valueAt(i);
|
||||
names.add(event.mPackage);
|
||||
if (event.mClass != null) {
|
||||
names.add(event.mClass);
|
||||
}
|
||||
results.add(event);
|
||||
}
|
||||
ComponentName[] table = names.toArray(new ComponentName[names.size()]);
|
||||
String[] table = names.toArray(new String[names.size()]);
|
||||
Arrays.sort(table);
|
||||
return new UsageEvents(results, table);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class UsageLogActivity extends ListActivity implements Runnable {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
holder.packageName.setText(mEvents.get(position).getComponent().toShortString());
|
||||
holder.packageName.setText(mEvents.get(position).getPackageName());
|
||||
String state;
|
||||
switch (mEvents.get(position).getEventType()) {
|
||||
case UsageEvents.Event.MOVE_TO_FOREGROUND:
|
||||
|
||||
Reference in New Issue
Block a user