Home | History | Annotate | Download | only in preload
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy 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,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.preload;
     18 
     19 import org.xml.sax.Attributes;
     20 import org.xml.sax.InputSource;
     21 import org.xml.sax.SAXException;
     22 import org.xml.sax.XMLReader;
     23 import org.xml.sax.helpers.DefaultHandler;
     24 
     25 import java.io.File;
     26 import java.io.FileReader;
     27 import java.text.DateFormat;
     28 import java.util.Collection;
     29 import java.util.Date;
     30 import java.util.HashMap;
     31 import java.util.LinkedList;
     32 import java.util.Map;
     33 
     34 import javax.xml.parsers.SAXParser;
     35 import javax.xml.parsers.SAXParserFactory;
     36 
     37 /**
     38  * Helper class for serialization and deserialization of a collection of DumpData objects to XML.
     39  */
     40 public class DumpDataIO {
     41 
     42   /**
     43    * Serialize the given collection to an XML document. Returns the produced string.
     44    */
     45   public static String serialize(Collection<DumpData> data) {
     46       // We'll do this by hand, constructing a DOM or similar is too complicated for our simple
     47       // use case.
     48 
     49       StringBuilder sb = new StringBuilder();
     50       sb.append("<preloaded-classes-data>\n");
     51 
     52       for (DumpData d : data) {
     53           serialize(d, sb);
     54       }
     55 
     56       sb.append("</preloaded-classes-data>\n");
     57       return sb.toString();
     58   }
     59 
     60   private static void serialize(DumpData d, StringBuilder sb) {
     61       sb.append("<data package=\"" + d.packageName + "\" date=\"" +
     62               DateFormat.getDateTimeInstance().format(d.date) +"\">\n");
     63 
     64       for (Map.Entry<String, String> e : d.dumpData.entrySet()) {
     65           sb.append("<class name=\"" + e.getKey() + "\" classloader=\"" + e.getValue() + "\"/>\n");
     66       }
     67 
     68       sb.append("</data>\n");
     69   }
     70 
     71   /**
     72    * Load a collection of DumpData objects from the given file.
     73    */
     74   public static Collection<DumpData> deserialize(File f) throws Exception {
     75       // Use SAX parsing. Our format is very simple. Don't do any schema validation or such.
     76 
     77       SAXParserFactory spf = SAXParserFactory.newInstance();
     78       spf.setNamespaceAware(false);
     79       SAXParser saxParser = spf.newSAXParser();
     80 
     81       XMLReader xmlReader = saxParser.getXMLReader();
     82       DumpDataContentHandler ddch = new DumpDataContentHandler();
     83       xmlReader.setContentHandler(ddch);
     84       xmlReader.parse(new InputSource(new FileReader(f)));
     85 
     86       return ddch.data;
     87   }
     88 
     89   private static class DumpDataContentHandler extends DefaultHandler {
     90       Collection<DumpData> data = new LinkedList<DumpData>();
     91       DumpData openData = null;
     92 
     93       @Override
     94       public void startElement(String uri, String localName, String qName, Attributes attributes)
     95               throws SAXException {
     96           if (qName.equals("data")) {
     97               if (openData != null) {
     98                   throw new IllegalStateException();
     99               }
    100               String pkg = attributes.getValue("package");
    101               String dateString = attributes.getValue("date");
    102 
    103               if (pkg == null || dateString == null) {
    104                   throw new IllegalArgumentException();
    105               }
    106 
    107               try {
    108                   Date date = DateFormat.getDateTimeInstance().parse(dateString);
    109                   openData = new DumpData(pkg, new HashMap<String, String>(), date);
    110               } catch (Exception e) {
    111                   throw new RuntimeException(e);
    112               }
    113           } else if (qName.equals("class")) {
    114               if (openData == null) {
    115                   throw new IllegalStateException();
    116               }
    117               String className = attributes.getValue("name");
    118               String classLoader = attributes.getValue("classloader");
    119 
    120               if (className == null || classLoader == null) {
    121                   throw new IllegalArgumentException();
    122               }
    123 
    124               openData.dumpData.put(className, classLoader.equals("null") ? null : classLoader);
    125           }
    126       }
    127 
    128       @Override
    129       public void endElement(String uri, String localName, String qName) throws SAXException {
    130           if (qName.equals("data")) {
    131               if (openData == null) {
    132                   throw new IllegalStateException();
    133               }
    134               openData.countBootClassPath();
    135 
    136               data.add(openData);
    137               openData = null;
    138           }
    139       }
    140   }
    141 }
    142