19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.Serializable; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.Writer; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedWriter; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStreamWriter; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileInputStream; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.ObjectInputStream; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedInputStream; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.ObjectOutputStream; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedOutputStream; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Set; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.TreeSet; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.nio.charset.Charset; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Root of our data model. 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Root implements Serializable { 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final long serialVersionUID = 0; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** pid -> Proc */ 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Map<Integer, Proc> processes = new HashMap<Integer, Proc>(); 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Class name -> LoadedClass */ 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Map<String, LoadedClass> loadedClasses 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project = new HashMap<String, LoadedClass>(); 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 499d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee MemoryUsage baseline = MemoryUsage.baseline(); 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Records class loads and initializations. 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void indexClassOperation(Record record) { 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Proc process = processes.get(record.pid); 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Ignore dexopt output. It loads applications classes through the 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // system class loader and messes us up. 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (record.processName.equals("dexopt")) { 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String name = record.className; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LoadedClass loadedClass = loadedClasses.get(name); 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Operation o = null; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (record.type) { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case START_LOAD: 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case START_INIT: 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (loadedClass == null) { 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project loadedClass = new LoadedClass( 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name, record.classLoader == 0); 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (loadedClass.systemClass) { 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Only measure memory for classes in the boot 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // classpath. 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project loadedClass.measureMemoryUsage(); 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project loadedClasses.put(name, loadedClass); 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case END_LOAD: 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case END_INIT: 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project o = process.endOperation(record.tid, record.className, 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project loadedClass, record.time); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (o == null) { 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (record.type) { 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case START_LOAD: 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project process.startOperation(record.tid, loadedClass, record.time, 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Operation.Type.LOAD); 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case START_INIT: 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project process.startOperation(record.tid, loadedClass, record.time, 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Operation.Type.INIT); 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case END_LOAD: 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project loadedClass.loads.add(o); 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case END_INIT: 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project loadedClass.initializations.add(o); 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Indexes information about the process from the given record. 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void indexProcess(Record record) { 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Proc proc = processes.get(record.pid); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (proc == null) { 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Create a new process object. 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Proc parent = processes.get(record.ppid); 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proc = new Proc(parent, record.pid); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processes.put(proc.id, proc); 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (parent != null) { 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parent.children.add(proc); 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project proc.setName(record.processName); 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Writes this graph to a file. 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void toFile(String fileName) throws IOException { 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileOutputStream out = new FileOutputStream(fileName); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ObjectOutputStream oout = new ObjectOutputStream( 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new BufferedOutputStream(out)); 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.err.println("Writing object model..."); 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oout.writeObject(this); 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oout.close(); 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.err.println("Done!"); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Reads Root from a file. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Root fromFile(String fileName) 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException, ClassNotFoundException { 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileInputStream fin = new FileInputStream(fileName); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ObjectInputStream oin = new ObjectInputStream( 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new BufferedInputStream(fin)); 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Root root = (Root) oin.readObject(); 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oin.close(); 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return root; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 164