blob: 21b7a04e07dc592d719c974d94a0270ea0ba519d [file] [log] [blame]
Andreas Gampe554d7ee2015-09-15 08:57:12 -07001/*
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
17package com.android.preload.classdataretrieval.hprof;
18
19import com.android.ddmlib.Client;
20import com.android.ddmlib.ClientData;
21import com.android.ddmlib.ClientData.IHprofDumpHandler;
22import com.android.preload.classdataretrieval.ClassDataRetriever;
23import com.android.preload.ui.NullProgressMonitor;
24import com.android.tools.perflib.captures.MemoryMappedFileBuffer;
25import com.android.tools.perflib.heap.ClassObj;
26import com.android.tools.perflib.heap.Queries;
27import com.android.tools.perflib.heap.Snapshot;
28
29import java.io.BufferedOutputStream;
30import java.io.File;
31import java.io.FileOutputStream;
32import java.util.HashMap;
33import java.util.Map;
34import java.util.Set;
35
36public class Hprof implements ClassDataRetriever {
37
38 private static GeneralHprofDumpHandler hprofHandler;
39
40 public static void init() {
41 synchronized(Hprof.class) {
42 if (hprofHandler == null) {
43 ClientData.setHprofDumpHandler(hprofHandler = new GeneralHprofDumpHandler());
44 }
45 }
46 }
47
48 public static File doHprof(Client client, int timeout) {
49 GetHprof gh = new GetHprof(client, timeout);
50 return gh.get();
51 }
52
53 /**
54 * Return a map of class names to class-loader names derived from the hprof dump.
55 *
56 * @param hprofLocalFile
57 */
58 public static Map<String, String> analyzeHprof(File hprofLocalFile) throws Exception {
59 Snapshot snapshot = Snapshot.createSnapshot(new MemoryMappedFileBuffer(hprofLocalFile));
60
61 Map<String, Set<ClassObj>> classes = Queries.classes(snapshot, null);
62 Map<String, String> retValue = new HashMap<String, String>();
63 for (Map.Entry<String, Set<ClassObj>> e : classes.entrySet()) {
64 for (ClassObj c : e.getValue()) {
65 String cl = c.getClassLoader() == null ? null : c.getClassLoader().toString();
66 String cName = c.getClassName();
67 int aDepth = 0;
68 while (cName.endsWith("[]")) {
69 cName = cName.substring(0, cName.length()-2);
70 aDepth++;
71 }
72 String newName = transformPrimitiveClass(cName);
73 if (aDepth > 0) {
74 // Need to use kind-a descriptor syntax. If it was transformed, it is primitive.
75 if (newName.equals(cName)) {
76 newName = "L" + newName + ";";
77 }
78 for (int i = 0; i < aDepth; i++) {
79 newName = "[" + newName;
80 }
81 }
82 retValue.put(newName, cl);
83 }
84 }
85
86 // Free up memory.
87 snapshot.dispose();
88
89 return retValue;
90 }
91
92 private static Map<String, String> primitiveMapping;
93
94 static {
95 primitiveMapping = new HashMap<>();
96 primitiveMapping.put("boolean", "Z");
97 primitiveMapping.put("byte", "B");
98 primitiveMapping.put("char", "C");
99 primitiveMapping.put("double", "D");
100 primitiveMapping.put("float", "F");
101 primitiveMapping.put("int", "I");
102 primitiveMapping.put("long", "J");
103 primitiveMapping.put("short", "S");
104 primitiveMapping.put("void", "V");
105 }
106
107 private static String transformPrimitiveClass(String name) {
108 String rep = primitiveMapping.get(name);
109 if (rep != null) {
110 return rep;
111 }
112 return name;
113 }
114
115 private static class GetHprof implements IHprofDumpHandler {
116
117 private File target;
118 private long timeout;
119 private Client client;
120
121 public GetHprof(Client client, long timeout) {
122 this.client = client;
123 this.timeout = timeout;
124 }
125
126 public File get() {
127 synchronized (this) {
128 hprofHandler.addHandler(this);
129 client.dumpHprof();
130 if (target == null) {
131 try {
132 wait(timeout);
133 } catch (Exception e) {
134 System.out.println(e);
135 }
136 }
137 }
138
139 hprofHandler.removeHandler(this);
140 return target;
141 }
142
143 private void wakeUp() {
144 synchronized (this) {
145 notifyAll();
146 }
147 }
148
149 @Override
150 public void onEndFailure(Client arg0, String arg1) {
151 System.out.println("GetHprof.onEndFailure");
152 if (client == arg0) {
153 wakeUp();
154 }
155 }
156
157 private static File createTargetFile() {
158 try {
159 return File.createTempFile("ddms", ".hprof");
160 } catch (Exception e) {
161 throw new RuntimeException(e);
162 }
163 }
164
165 @Override
166 public void onSuccess(String arg0, Client arg1) {
167 System.out.println("GetHprof.onSuccess");
168 if (client == arg1) {
169 try {
170 target = createTargetFile();
171 arg1.getDevice().getSyncService().pullFile(arg0,
172 target.getAbsoluteFile().toString(), new NullProgressMonitor());
173 } catch (Exception e) {
174 e.printStackTrace();
175 target = null;
176 }
177 wakeUp();
178 }
179 }
180
181 @Override
182 public void onSuccess(byte[] arg0, Client arg1) {
183 System.out.println("GetHprof.onSuccess");
184 if (client == arg1) {
185 try {
186 target = createTargetFile();
187 BufferedOutputStream out =
188 new BufferedOutputStream(new FileOutputStream(target));
189 out.write(arg0);
190 out.close();
191 } catch (Exception e) {
192 e.printStackTrace();
193 target = null;
194 }
195 wakeUp();
196 }
197 }
198 }
199
200 private int timeout;
201
202 public Hprof(int timeout) {
203 this.timeout = timeout;
204 }
205
206 @Override
207 public Map<String, String> getClassData(Client client) {
208 File hprofLocalFile = Hprof.doHprof(client, timeout);
209 if (hprofLocalFile == null) {
210 throw new RuntimeException("Failed getting dump...");
211 }
212 System.out.println("Dump file is " + hprofLocalFile);
213
214 try {
215 return analyzeHprof(hprofLocalFile);
216 } catch (Exception e) {
217 throw new RuntimeException(e);
218 }
219 }
220}