1/* 2 * Copyright (C) 2008 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 17import java.io.Serializable; 18import java.io.IOException; 19import java.io.Writer; 20import java.io.BufferedWriter; 21import java.io.OutputStreamWriter; 22import java.io.FileOutputStream; 23import java.io.FileInputStream; 24import java.io.ObjectInputStream; 25import java.io.BufferedInputStream; 26import java.io.ObjectOutputStream; 27import java.io.BufferedOutputStream; 28import java.util.Map; 29import java.util.HashMap; 30import java.util.Set; 31import java.util.TreeSet; 32import java.util.Arrays; 33import java.nio.charset.Charset; 34 35/** 36 * Root of our data model. 37 */ 38public class Root implements Serializable { 39 40 private static final long serialVersionUID = 0; 41 42 /** pid -> Proc */ 43 final Map<Integer, Proc> processes = new HashMap<Integer, Proc>(); 44 45 /** Class name -> LoadedClass */ 46 final Map<String, LoadedClass> loadedClasses 47 = new HashMap<String, LoadedClass>(); 48 49 MemoryUsage baseline = MemoryUsage.baseline(); 50 51 /** 52 * Records class loads and initializations. 53 */ 54 void indexClassOperation(Record record) { 55 Proc process = processes.get(record.pid); 56 57 // Ignore dexopt output. It loads applications classes through the 58 // system class loader and messes us up. 59 if (record.processName.equals("dexopt")) { 60 return; 61 } 62 63 String name = record.className; 64 LoadedClass loadedClass = loadedClasses.get(name); 65 Operation o = null; 66 67 switch (record.type) { 68 case START_LOAD: 69 case START_INIT: 70 if (loadedClass == null) { 71 loadedClass = new LoadedClass( 72 name, record.classLoader == 0); 73 if (loadedClass.systemClass) { 74 // Only measure memory for classes in the boot 75 // classpath. 76 loadedClass.measureMemoryUsage(); 77 } 78 loadedClasses.put(name, loadedClass); 79 } 80 break; 81 82 case END_LOAD: 83 case END_INIT: 84 o = process.endOperation(record.tid, record.className, 85 loadedClass, record.time); 86 if (o == null) { 87 return; 88 } 89 } 90 91 switch (record.type) { 92 case START_LOAD: 93 process.startOperation(record.tid, loadedClass, record.time, 94 Operation.Type.LOAD); 95 break; 96 97 case START_INIT: 98 process.startOperation(record.tid, loadedClass, record.time, 99 Operation.Type.INIT); 100 break; 101 102 case END_LOAD: 103 loadedClass.loads.add(o); 104 break; 105 106 case END_INIT: 107 loadedClass.initializations.add(o); 108 break; 109 } 110 } 111 112 /** 113 * Indexes information about the process from the given record. 114 */ 115 void indexProcess(Record record) { 116 Proc proc = processes.get(record.pid); 117 118 if (proc == null) { 119 // Create a new process object. 120 Proc parent = processes.get(record.ppid); 121 proc = new Proc(parent, record.pid); 122 processes.put(proc.id, proc); 123 if (parent != null) { 124 parent.children.add(proc); 125 } 126 } 127 128 proc.setName(record.processName); 129 } 130 131 /** 132 * Writes this graph to a file. 133 */ 134 void toFile(String fileName) throws IOException { 135 FileOutputStream out = new FileOutputStream(fileName); 136 ObjectOutputStream oout = new ObjectOutputStream( 137 new BufferedOutputStream(out)); 138 139 System.err.println("Writing object model..."); 140 141 oout.writeObject(this); 142 143 oout.close(); 144 145 System.err.println("Done!"); 146 } 147 148 /** 149 * Reads Root from a file. 150 */ 151 static Root fromFile(String fileName) 152 throws IOException, ClassNotFoundException { 153 FileInputStream fin = new FileInputStream(fileName); 154 ObjectInputStream oin = new ObjectInputStream( 155 new BufferedInputStream(fin)); 156 157 Root root = (Root) oin.readObject(); 158 159 oin.close(); 160 161 return root; 162 } 163} 164