1554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe/* 2554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Copyright (C) 2015 The Android Open Source Project 3554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * 4554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License"); 5554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * you may not use this file except in compliance with the License. 6554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * You may obtain a copy of the License at 7554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * 8554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * http://www.apache.org/licenses/LICENSE-2.0 9554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * 10554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Unless required by applicable law or agreed to in writing, software 11554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS, 12554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * See the License for the specific language governing permissions and 14554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * limitations under the License. 15554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 16554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 17554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampepackage com.android.preload; 18554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 19554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport org.xml.sax.Attributes; 20554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport org.xml.sax.InputSource; 21554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport org.xml.sax.SAXException; 22554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport org.xml.sax.XMLReader; 23554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport org.xml.sax.helpers.DefaultHandler; 24554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 25554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.io.File; 26554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.io.FileReader; 27554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.text.DateFormat; 28554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.Collection; 29554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.Date; 30554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.HashMap; 31554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.LinkedList; 32554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.Map; 33554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 34554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport javax.xml.parsers.SAXParser; 35554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport javax.xml.parsers.SAXParserFactory; 36554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 37554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe/** 38554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Helper class for serialization and deserialization of a collection of DumpData objects to XML. 39554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 40554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampepublic class DumpDataIO { 41554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 42554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 43554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Serialize the given collection to an XML document. Returns the produced string. 44554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 45554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static String serialize(Collection<DumpData> data) { 46554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // We'll do this by hand, constructing a DOM or similar is too complicated for our simple 47554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // use case. 48554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 49554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe StringBuilder sb = new StringBuilder(); 50554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe sb.append("<preloaded-classes-data>\n"); 51554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 52554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe for (DumpData d : data) { 53554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe serialize(d, sb); 54554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 55554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 56554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe sb.append("</preloaded-classes-data>\n"); 57554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return sb.toString(); 58554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 59554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 60554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private static void serialize(DumpData d, StringBuilder sb) { 61554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe sb.append("<data package=\"" + d.packageName + "\" date=\"" + 62554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe DateFormat.getDateTimeInstance().format(d.date) +"\">\n"); 63554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 64554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe for (Map.Entry<String, String> e : d.dumpData.entrySet()) { 65554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe sb.append("<class name=\"" + e.getKey() + "\" classloader=\"" + e.getValue() + "\"/>\n"); 66554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 67554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 68554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe sb.append("</data>\n"); 69554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 70554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 71554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 72554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Load a collection of DumpData objects from the given file. 73554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 74554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static Collection<DumpData> deserialize(File f) throws Exception { 75554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Use SAX parsing. Our format is very simple. Don't do any schema validation or such. 76554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 77554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe SAXParserFactory spf = SAXParserFactory.newInstance(); 78554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe spf.setNamespaceAware(false); 79554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe SAXParser saxParser = spf.newSAXParser(); 80554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 81554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe XMLReader xmlReader = saxParser.getXMLReader(); 82554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe DumpDataContentHandler ddch = new DumpDataContentHandler(); 83554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe xmlReader.setContentHandler(ddch); 84554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe xmlReader.parse(new InputSource(new FileReader(f))); 85554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 86554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return ddch.data; 87554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 88554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 89554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private static class DumpDataContentHandler extends DefaultHandler { 90554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe Collection<DumpData> data = new LinkedList<DumpData>(); 91554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe DumpData openData = null; 92554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 93554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 94554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void startElement(String uri, String localName, String qName, Attributes attributes) 95554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe throws SAXException { 96554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (qName.equals("data")) { 97554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (openData != null) { 98554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe throw new IllegalStateException(); 99554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 100554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe String pkg = attributes.getValue("package"); 101554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe String dateString = attributes.getValue("date"); 102554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 103554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (pkg == null || dateString == null) { 104554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe throw new IllegalArgumentException(); 105554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 106554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 107554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe try { 108554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe Date date = DateFormat.getDateTimeInstance().parse(dateString); 109554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe openData = new DumpData(pkg, new HashMap<String, String>(), date); 110554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } catch (Exception e) { 111554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe throw new RuntimeException(e); 112554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 113554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } else if (qName.equals("class")) { 114554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (openData == null) { 115554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe throw new IllegalStateException(); 116554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 117554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe String className = attributes.getValue("name"); 118554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe String classLoader = attributes.getValue("classloader"); 119554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 120554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (className == null || classLoader == null) { 121554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe throw new IllegalArgumentException(); 122554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 123554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 124554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe openData.dumpData.put(className, classLoader.equals("null") ? null : classLoader); 125554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 126554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 127554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 128554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 129554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void endElement(String uri, String localName, String qName) throws SAXException { 130554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (qName.equals("data")) { 131554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (openData == null) { 132554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe throw new IllegalStateException(); 133554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 134554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe openData.countBootClassPath(); 135554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 136554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe data.add(openData); 137554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe openData = null; 138554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 139554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 140554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 141554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe} 142