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 17 package com.android.server.usage; 18 19 import android.util.AtomicFile; 20 import android.util.Slog; 21 import android.util.Xml; 22 import com.android.internal.util.FastXmlSerializer; 23 import com.android.internal.util.XmlUtils; 24 import org.xmlpull.v1.XmlPullParser; 25 import org.xmlpull.v1.XmlPullParserException; 26 27 import java.io.*; 28 29 public class UsageStatsXml { 30 private static final String TAG = "UsageStatsXml"; 31 private static final int CURRENT_VERSION = 1; 32 private static final String USAGESTATS_TAG = "usagestats"; 33 private static final String VERSION_ATTR = "version"; 34 static final String CHECKED_IN_SUFFIX = "-c"; 35 parseBeginTime(AtomicFile file)36 public static long parseBeginTime(AtomicFile file) throws IOException { 37 return parseBeginTime(file.getBaseFile()); 38 } 39 parseBeginTime(File file)40 public static long parseBeginTime(File file) throws IOException { 41 String name = file.getName(); 42 43 // Eat as many occurrences of -c as possible. This is due to a bug where -c 44 // would be appended more than once to a checked-in file, causing a crash 45 // on boot when indexing files since Long.parseLong() will puke on anything but 46 // a number. 47 while (name.endsWith(CHECKED_IN_SUFFIX)) { 48 name = name.substring(0, name.length() - CHECKED_IN_SUFFIX.length()); 49 } 50 51 try { 52 return Long.parseLong(name); 53 } catch (NumberFormatException e) { 54 throw new IOException(e); 55 } 56 } 57 read(AtomicFile file, IntervalStats statsOut)58 public static void read(AtomicFile file, IntervalStats statsOut) throws IOException { 59 try { 60 FileInputStream in = file.openRead(); 61 try { 62 statsOut.beginTime = parseBeginTime(file); 63 read(in, statsOut); 64 statsOut.lastTimeSaved = file.getLastModifiedTime(); 65 } finally { 66 try { 67 in.close(); 68 } catch (IOException e) { 69 // Empty 70 } 71 } 72 } catch (FileNotFoundException e) { 73 Slog.e(TAG, "UsageStats Xml", e); 74 throw e; 75 } 76 } 77 write(AtomicFile file, IntervalStats stats)78 public static void write(AtomicFile file, IntervalStats stats) throws IOException { 79 FileOutputStream fos = file.startWrite(); 80 try { 81 write(fos, stats); 82 file.finishWrite(fos); 83 fos = null; 84 } finally { 85 // When fos is null (successful write), this will no-op 86 file.failWrite(fos); 87 } 88 } 89 read(InputStream in, IntervalStats statsOut)90 static void read(InputStream in, IntervalStats statsOut) throws IOException { 91 XmlPullParser parser = Xml.newPullParser(); 92 try { 93 parser.setInput(in, "utf-8"); 94 XmlUtils.beginDocument(parser, USAGESTATS_TAG); 95 String versionStr = parser.getAttributeValue(null, VERSION_ATTR); 96 try { 97 switch (Integer.parseInt(versionStr)) { 98 case 1: 99 UsageStatsXmlV1.read(parser, statsOut); 100 break; 101 102 default: 103 Slog.e(TAG, "Unrecognized version " + versionStr); 104 throw new IOException("Unrecognized version " + versionStr); 105 } 106 } catch (NumberFormatException e) { 107 Slog.e(TAG, "Bad version"); 108 throw new IOException(e); 109 } 110 } catch (XmlPullParserException e) { 111 Slog.e(TAG, "Failed to parse Xml", e); 112 throw new IOException(e); 113 } 114 } 115 write(OutputStream out, IntervalStats stats)116 static void write(OutputStream out, IntervalStats stats) throws IOException { 117 FastXmlSerializer xml = new FastXmlSerializer(); 118 xml.setOutput(out, "utf-8"); 119 xml.startDocument("utf-8", true); 120 xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 121 xml.startTag(null, USAGESTATS_TAG); 122 xml.attribute(null, VERSION_ATTR, Integer.toString(CURRENT_VERSION)); 123 124 UsageStatsXmlV1.write(xml, stats); 125 126 xml.endTag(null, USAGESTATS_TAG); 127 xml.endDocument(); 128 } 129 }