UsageStatsXmlV1.java revision 3516800b611a79339a3c188332d13a26e9086b09
13516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/**
23516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Copyright (C) 2014 The Android Open Source Project
33516800b611a79339a3c188332d13a26e9086b09Adam Lesinski *
43516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not
53516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * use this file except in compliance with the License. You may obtain a copy
63516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * of the License at
73516800b611a79339a3c188332d13a26e9086b09Adam Lesinski *
83516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0
93516800b611a79339a3c188332d13a26e9086b09Adam Lesinski *
103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Unless required by applicable law or agreed to in writing, software
113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * License for the specific language governing permissions and limitations
143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * under the License.
153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */
163516800b611a79339a3c188332d13a26e9086b09Adam Lesinskipackage com.android.server.usage;
173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
183516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport com.android.internal.util.FastXmlSerializer;
193516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport com.android.internal.util.XmlUtils;
203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
213516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.xmlpull.v1.XmlPullParser;
223516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.xmlpull.v1.XmlPullParserException;
233516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
243516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.TimeSparseArray;
253516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageEvents;
263516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageStats;
273516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.content.ComponentName;
283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
293516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.io.IOException;
303516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.net.ProtocolException;
313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/**
333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * UsageStats reader/writer for version 1 of the XML format.
343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */
353516800b611a79339a3c188332d13a26e9086b09Adam Lesinskifinal class UsageStatsXmlV1 {
363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String BEGIN_TIME_ATTR = "beginTime";
373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String END_TIME_ATTR = "endTime";
383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String PACKAGE_TAG = "package";
393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String NAME_ATTR = "name";
403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TOTAL_TIME_ACTIVE_ATTR = "totalTimeActive";
413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
423516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String LAST_EVENT_ATTR = "lastEvent";
433516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String EVENT_LOG_TAG = "event-log";
443516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TYPE_ATTR = "type";
453516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TIME_ATTR = "time";
463516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
473516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static UsageStats readNextUsageStats(XmlPullParser parser)
483516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (parser.getEventType() != XmlPullParser.START_TAG) {
503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            XmlUtils.nextElement(parser);
513516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
523516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (parser.getEventType() != XmlPullParser.START_TAG ||
543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                !parser.getName().equals(PACKAGE_TAG)) {
553516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            return null;
563516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
573516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        final String name = parser.getAttributeValue(null, NAME_ATTR);
593516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (name == null) {
603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throw new ProtocolException("no " + NAME_ATTR + " attribute present");
613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        UsageStats stats = new UsageStats();
643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mPackageName = name;
653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
663516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mLastTimeUsed = XmlUtils.readLongAttribute(parser, LAST_TIME_ACTIVE_ATTR);
673516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
683516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        XmlUtils.skipCurrentTag(parser);
693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        return stats;
703516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static UsageEvents.Event readNextEvent(XmlPullParser parser, IntervalStats statsOut)
733516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
743516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (parser.getEventType() != XmlPullParser.START_TAG) {
753516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            XmlUtils.nextElement(parser);
763516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
773516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
783516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (parser.getEventType() != XmlPullParser.START_TAG ||
793516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                !parser.getName().equals(EVENT_LOG_TAG)) {
803516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            return null;
813516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        final String componentName = XmlUtils.readStringAttribute(parser, NAME_ATTR);
843516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (componentName == null) {
853516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throw new ProtocolException("no " + NAME_ATTR + " attribute present");
863516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
873516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
883516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        ComponentName component = statsOut.getCachedComponentName(componentName);
893516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (component == null) {
903516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throw new ProtocolException("ComponentName " + componentName + " is invalid");
913516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
923516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
933516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        UsageEvents.Event event = new UsageEvents.Event();
943516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        event.mComponent = component;
953516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR);
963516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        event.mTimeStamp = XmlUtils.readLongAttribute(parser, TIME_ATTR);
973516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        XmlUtils.skipCurrentTag(parser);
983516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        return event;
993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1003516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1013516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static void writeUsageStats(FastXmlSerializer serializer, UsageStats stats)
1023516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws IOException {
1033516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.startTag(null, PACKAGE_TAG);
1043516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, NAME_ATTR, stats.mPackageName);
1053516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, TOTAL_TIME_ACTIVE_ATTR,
1063516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                Long.toString(stats.mTotalTimeInForeground));
1073516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, LAST_TIME_ACTIVE_ATTR, Long.toString(stats.mLastTimeUsed));
1083516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, LAST_EVENT_ATTR, Integer.toString(stats.mLastEvent));
1093516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.endTag(null, PACKAGE_TAG);
1103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static void writeEvent(FastXmlSerializer serializer, UsageEvents.Event event)
1133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws IOException {
1143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.startTag(null, EVENT_LOG_TAG);
1153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, NAME_ATTR, event.getComponent().flattenToString());
1163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, TYPE_ATTR, Integer.toString(event.getEventType()));
1173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, TIME_ATTR, Long.toString(event.getTimeStamp()));
1183516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.endTag(null, EVENT_LOG_TAG);
1193516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    /**
1223516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * Reads from the {@link XmlPullParser}, assuming that it is already on the
1233516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * <code><usagestats></code> tag.
1243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     *
1253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param parser The parser from which to read events.
1263516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param statsOut The stats object to populate with the data from the XML file.
1273516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     */
1283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    public static void read(XmlPullParser parser, IntervalStats statsOut)
1293516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
1303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        statsOut.stats.clear();
1313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (statsOut.events != null) {
1333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            statsOut.events.clear();
1343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1353516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        statsOut.beginTime = XmlUtils.readLongAttribute(parser, BEGIN_TIME_ATTR);
1373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        statsOut.endTime = XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
1383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        XmlUtils.nextElement(parser);
1393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        UsageStats pkgStats;
1413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        while ((pkgStats = readNextUsageStats(parser)) != null) {
1423516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            pkgStats.mBeginTimeStamp = statsOut.beginTime;
1433516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            pkgStats.mEndTimeStamp = statsOut.endTime;
1443516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            statsOut.stats.put(pkgStats.mPackageName, pkgStats);
1453516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1463516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1473516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        UsageEvents.Event event;
1483516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        while ((event = readNextEvent(parser, statsOut)) != null) {
1493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            if (statsOut.events == null) {
1503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                statsOut.events = new TimeSparseArray<>();
1513516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            }
1523516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            statsOut.events.put(event.getTimeStamp(), event);
1533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1553516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1563516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    /**
1573516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * Writes the stats object to an XML file. The {@link FastXmlSerializer}
1583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * has already written the <code><usagestats></code> tag, but attributes may still
1593516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * be added.
1603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     *
1613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param serializer The serializer to which to write the stats data.
1623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param stats The stats object to write to the XML file.
1633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     */
1643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    public static void write(FastXmlSerializer serializer, IntervalStats stats) throws IOException {
1653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, BEGIN_TIME_ATTR, Long.toString(stats.beginTime));
1663516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, END_TIME_ATTR, Long.toString(stats.endTime));
1673516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1683516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        final int statsCount = stats.stats.size();
1693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        for (int i = 0; i < statsCount; i++) {
1703516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            writeUsageStats(serializer, stats.stats.valueAt(i));
1713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1733516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (stats.events != null) {
1743516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            final int eventCount = stats.events.size();
1753516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            for (int i = 0; i < eventCount; i++) {
1763516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                writeEvent(serializer, stats.events.valueAt(i));
1773516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            }
1783516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1793516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1803516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1813516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private UsageStatsXmlV1() {
1823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski}
184