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 
17 import java.io.Serializable;
18 import java.io.IOException;
19 import java.io.Writer;
20 import java.io.BufferedWriter;
21 import java.io.OutputStreamWriter;
22 import java.io.FileOutputStream;
23 import java.io.FileInputStream;
24 import java.io.ObjectInputStream;
25 import java.io.BufferedInputStream;
26 import java.io.ObjectOutputStream;
27 import java.io.BufferedOutputStream;
28 import java.util.Map;
29 import java.util.HashMap;
30 import java.util.Set;
31 import java.util.TreeSet;
32 import java.util.Arrays;
33 import java.nio.charset.Charset;
34 
35 /**
36  * Root of our data model.
37  */
38 public 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      */
indexClassOperation(Record record)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      */
indexProcess(Record record)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      */
toFile(String fileName)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      */
fromFile(String fileName)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