Home | History | Annotate | Download | only in usage
      1 /**
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy
      6  * of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations
     14  * under the License.
     15  */
     16 package com.android.server.usage;
     17 
     18 import com.android.internal.util.XmlUtils;
     19 
     20 import org.xmlpull.v1.XmlPullParser;
     21 import org.xmlpull.v1.XmlPullParserException;
     22 import org.xmlpull.v1.XmlSerializer;
     23 
     24 import android.app.usage.ConfigurationStats;
     25 import android.app.usage.TimeSparseArray;
     26 import android.app.usage.UsageEvents;
     27 import android.app.usage.UsageStats;
     28 import android.content.res.Configuration;
     29 
     30 import java.io.IOException;
     31 import java.net.ProtocolException;
     32 
     33 /**
     34  * UsageStats reader/writer for version 1 of the XML format.
     35  */
     36 final class UsageStatsXmlV1 {
     37     private static final String PACKAGES_TAG = "packages";
     38     private static final String PACKAGE_TAG = "package";
     39 
     40     private static final String CONFIGURATIONS_TAG = "configurations";
     41     private static final String CONFIG_TAG = "config";
     42 
     43     private static final String EVENT_LOG_TAG = "event-log";
     44     private static final String EVENT_TAG = "event";
     45 
     46     // Attributes
     47     private static final String PACKAGE_ATTR = "package";
     48     private static final String CLASS_ATTR = "class";
     49     private static final String TOTAL_TIME_ACTIVE_ATTR = "timeActive";
     50     private static final String COUNT_ATTR = "count";
     51     private static final String ACTIVE_ATTR = "active";
     52     private static final String LAST_EVENT_ATTR = "lastEvent";
     53     private static final String TYPE_ATTR = "type";
     54 
     55     // Time attributes stored as an offset of the beginTime.
     56     private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
     57     private static final String END_TIME_ATTR = "endTime";
     58     private static final String TIME_ATTR = "time";
     59 
     60     private static void loadUsageStats(XmlPullParser parser, IntervalStats statsOut)
     61             throws XmlPullParserException, IOException {
     62         final String pkg = parser.getAttributeValue(null, PACKAGE_ATTR);
     63         if (pkg == null) {
     64             throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
     65         }
     66 
     67         final UsageStats stats = statsOut.getOrCreateUsageStats(pkg);
     68 
     69         // Apply the offset to the beginTime to find the absolute time.
     70         stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
     71                 parser, LAST_TIME_ACTIVE_ATTR);
     72 
     73         stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
     74         stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
     75     }
     76 
     77     private static void loadConfigStats(XmlPullParser parser, IntervalStats statsOut)
     78             throws XmlPullParserException, IOException {
     79         final Configuration config = new Configuration();
     80         Configuration.readXmlAttrs(parser, config);
     81 
     82         final ConfigurationStats configStats = statsOut.getOrCreateConfigurationStats(config);
     83 
     84         // Apply the offset to the beginTime to find the absolute time.
     85         configStats.mLastTimeActive = statsOut.beginTime + XmlUtils.readLongAttribute(
     86                 parser, LAST_TIME_ACTIVE_ATTR);
     87 
     88         configStats.mTotalTimeActive = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
     89         configStats.mActivationCount = XmlUtils.readIntAttribute(parser, COUNT_ATTR);
     90         if (XmlUtils.readBooleanAttribute(parser, ACTIVE_ATTR)) {
     91             statsOut.activeConfiguration = configStats.mConfiguration;
     92         }
     93     }
     94 
     95     private static void loadEvent(XmlPullParser parser, IntervalStats statsOut)
     96             throws XmlPullParserException, IOException {
     97         final String packageName = XmlUtils.readStringAttribute(parser, PACKAGE_ATTR);
     98         if (packageName == null) {
     99             throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
    100         }
    101 
    102         final String className = XmlUtils.readStringAttribute(parser, CLASS_ATTR);
    103 
    104         final UsageEvents.Event event = statsOut.buildEvent(packageName, className);
    105 
    106         // Apply the offset to the beginTime to find the absolute time of this event.
    107         event.mTimeStamp = statsOut.beginTime + XmlUtils.readLongAttribute(parser, TIME_ATTR);
    108 
    109         event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR);
    110         if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) {
    111             event.mConfiguration = new Configuration();
    112             Configuration.readXmlAttrs(parser, event.mConfiguration);
    113         }
    114 
    115         if (statsOut.events == null) {
    116             statsOut.events = new TimeSparseArray<>();
    117         }
    118         statsOut.events.put(event.mTimeStamp, event);
    119     }
    120 
    121     private static void writeUsageStats(XmlSerializer xml, final IntervalStats stats,
    122             final UsageStats usageStats) throws IOException {
    123         xml.startTag(null, PACKAGE_TAG);
    124 
    125         // Write the time offset.
    126         XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
    127                 usageStats.mLastTimeUsed - stats.beginTime);
    128 
    129         XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
    130         XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
    131         XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent);
    132 
    133         xml.endTag(null, PACKAGE_TAG);
    134     }
    135 
    136     private static void writeConfigStats(XmlSerializer xml, final IntervalStats stats,
    137             final ConfigurationStats configStats, boolean isActive) throws IOException {
    138         xml.startTag(null, CONFIG_TAG);
    139 
    140         // Write the time offset.
    141         XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
    142                 configStats.mLastTimeActive - stats.beginTime);
    143 
    144         XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, configStats.mTotalTimeActive);
    145         XmlUtils.writeIntAttribute(xml, COUNT_ATTR, configStats.mActivationCount);
    146         if (isActive) {
    147             XmlUtils.writeBooleanAttribute(xml, ACTIVE_ATTR, true);
    148         }
    149 
    150         // Now write the attributes representing the configuration object.
    151         Configuration.writeXmlAttrs(xml, configStats.mConfiguration);
    152 
    153         xml.endTag(null, CONFIG_TAG);
    154     }
    155 
    156     private static void writeEvent(XmlSerializer xml, final IntervalStats stats,
    157             final UsageEvents.Event event) throws IOException {
    158         xml.startTag(null, EVENT_TAG);
    159 
    160         // Store the time offset.
    161         XmlUtils.writeLongAttribute(xml, TIME_ATTR, event.mTimeStamp - stats.beginTime);
    162 
    163         XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, event.mPackage);
    164         if (event.mClass != null) {
    165             XmlUtils.writeStringAttribute(xml, CLASS_ATTR, event.mClass);
    166         }
    167         XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType);
    168 
    169         if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE
    170                 && event.mConfiguration != null) {
    171             Configuration.writeXmlAttrs(xml, event.mConfiguration);
    172         }
    173 
    174         xml.endTag(null, EVENT_TAG);
    175     }
    176 
    177     /**
    178      * Reads from the {@link XmlPullParser}, assuming that it is already on the
    179      * <code><usagestats></code> tag.
    180      *
    181      * @param parser The parser from which to read events.
    182      * @param statsOut The stats object to populate with the data from the XML file.
    183      */
    184     public static void read(XmlPullParser parser, IntervalStats statsOut)
    185             throws XmlPullParserException, IOException {
    186         statsOut.packageStats.clear();
    187         statsOut.configurations.clear();
    188         statsOut.activeConfiguration = null;
    189 
    190         if (statsOut.events != null) {
    191             statsOut.events.clear();
    192         }
    193 
    194         statsOut.endTime = XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
    195 
    196         int eventCode;
    197         int outerDepth = parser.getDepth();
    198         while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT
    199                 && (eventCode != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    200             if (eventCode != XmlPullParser.START_TAG) {
    201                 continue;
    202             }
    203 
    204             final String tag = parser.getName();
    205             switch (tag) {
    206                 case PACKAGE_TAG:
    207                     loadUsageStats(parser, statsOut);
    208                     break;
    209 
    210                 case CONFIG_TAG:
    211                     loadConfigStats(parser, statsOut);
    212                     break;
    213 
    214                 case EVENT_TAG:
    215                     loadEvent(parser, statsOut);
    216                     break;
    217             }
    218         }
    219     }
    220 
    221     /**
    222      * Writes the stats object to an XML file. The {@link XmlSerializer}
    223      * has already written the <code><usagestats></code> tag, but attributes may still
    224      * be added.
    225      *
    226      * @param xml The serializer to which to write the packageStats data.
    227      * @param stats The stats object to write to the XML file.
    228      */
    229     public static void write(XmlSerializer xml, IntervalStats stats) throws IOException {
    230         XmlUtils.writeLongAttribute(xml, END_TIME_ATTR, stats.endTime - stats.beginTime);
    231 
    232         xml.startTag(null, PACKAGES_TAG);
    233         final int statsCount = stats.packageStats.size();
    234         for (int i = 0; i < statsCount; i++) {
    235             writeUsageStats(xml, stats, stats.packageStats.valueAt(i));
    236         }
    237         xml.endTag(null, PACKAGES_TAG);
    238 
    239 
    240         xml.startTag(null, CONFIGURATIONS_TAG);
    241         final int configCount = stats.configurations.size();
    242         for (int i = 0; i < configCount; i++) {
    243             boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i));
    244             writeConfigStats(xml, stats, stats.configurations.valueAt(i), active);
    245         }
    246         xml.endTag(null, CONFIGURATIONS_TAG);
    247 
    248         xml.startTag(null, EVENT_LOG_TAG);
    249         final int eventCount = stats.events != null ? stats.events.size() : 0;
    250         for (int i = 0; i < eventCount; i++) {
    251             writeEvent(xml, stats, stats.events.valueAt(i));
    252         }
    253         xml.endTag(null, EVENT_LOG_TAG);
    254     }
    255 
    256     private UsageStatsXmlV1() {
    257     }
    258 }
    259