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