blob: b8552fe1ce22a43704b7e8bd6741d7406c0d22cf [file] [log] [blame]
Richard Uhlerb730b782015-07-15 16:01:58 -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.ahat;
18
Richard Uhlercda4f2e2016-09-09 09:56:20 +010019import com.android.ahat.heapdump.AhatSnapshot;
Richard Uhlerf629cfd2016-12-12 13:11:26 +000020import com.android.ahat.heapdump.Diff;
Richard Uhlerec78c782016-05-13 14:19:37 -070021import com.android.tools.perflib.heap.ProguardMap;
Richard Uhlerb730b782015-07-15 16:01:58 -070022import com.sun.net.httpserver.HttpServer;
23import java.io.File;
24import java.io.IOException;
25import java.io.PrintStream;
26import java.net.InetAddress;
27import java.net.InetSocketAddress;
Richard Uhlerec78c782016-05-13 14:19:37 -070028import java.text.ParseException;
Richard Uhlerb730b782015-07-15 16:01:58 -070029import java.util.concurrent.Executors;
30
31public class Main {
32
33 public static void help(PrintStream out) {
Richard Uhlerf629cfd2016-12-12 13:11:26 +000034 out.println("java -jar ahat.jar [OPTIONS] FILE");
35 out.println(" Launch an http server for viewing the given Android heap dump FILE.");
Richard Uhlerb730b782015-07-15 16:01:58 -070036 out.println("");
Richard Uhlerf629cfd2016-12-12 13:11:26 +000037 out.println("OPTIONS:");
Richard Uhlerb730b782015-07-15 16:01:58 -070038 out.println(" -p <port>");
39 out.println(" Serve pages on the given port. Defaults to 7100.");
Richard Uhlerec78c782016-05-13 14:19:37 -070040 out.println(" --proguard-map FILE");
41 out.println(" Use the proguard map FILE to deobfuscate the heap dump.");
Richard Uhlerf629cfd2016-12-12 13:11:26 +000042 out.println(" --baseline FILE");
43 out.println(" Diff the heap dump against the given baseline heap dump FILE.");
44 out.println(" --baseline-proguard-map FILE");
45 out.println(" Use the proguard map FILE to deobfuscate the baseline heap dump.");
Richard Uhlerb730b782015-07-15 16:01:58 -070046 out.println("");
47 }
48
49 public static void main(String[] args) throws IOException {
50 int port = 7100;
51 for (String arg : args) {
52 if (arg.equals("--help")) {
53 help(System.out);
54 return;
55 }
56 }
57
58 File hprof = null;
Richard Uhlerf629cfd2016-12-12 13:11:26 +000059 File hprofbase = null;
Richard Uhlerec78c782016-05-13 14:19:37 -070060 ProguardMap map = new ProguardMap();
Richard Uhlerf629cfd2016-12-12 13:11:26 +000061 ProguardMap mapbase = new ProguardMap();
Richard Uhlerb730b782015-07-15 16:01:58 -070062 for (int i = 0; i < args.length; i++) {
63 if ("-p".equals(args[i]) && i + 1 < args.length) {
64 i++;
65 port = Integer.parseInt(args[i]);
Richard Uhlerec78c782016-05-13 14:19:37 -070066 } else if ("--proguard-map".equals(args[i]) && i + 1 < args.length) {
67 i++;
68 try {
69 map.readFromFile(new File(args[i]));
70 } catch (IOException|ParseException ex) {
71 System.out.println("Unable to read proguard map: " + ex);
72 System.out.println("The proguard map will not be used.");
73 }
Richard Uhlerf629cfd2016-12-12 13:11:26 +000074 } else if ("--baseline-proguard-map".equals(args[i]) && i + 1 < args.length) {
75 i++;
76 try {
77 mapbase.readFromFile(new File(args[i]));
78 } catch (IOException|ParseException ex) {
79 System.out.println("Unable to read baselline proguard map: " + ex);
80 System.out.println("The proguard map will not be used.");
81 }
82 } else if ("--baseline".equals(args[i]) && i + 1 < args.length) {
83 i++;
84 if (hprofbase != null) {
85 System.err.println("multiple baseline heap dumps.");
86 help(System.err);
87 return;
88 }
89 hprofbase = new File(args[i]);
Richard Uhlerb730b782015-07-15 16:01:58 -070090 } else {
91 if (hprof != null) {
92 System.err.println("multiple input files.");
93 help(System.err);
94 return;
95 }
96 hprof = new File(args[i]);
97 }
98 }
99
100 if (hprof == null) {
101 System.err.println("no input file.");
102 help(System.err);
103 return;
104 }
105
Richard Uhler46e476b2016-07-21 13:52:48 -0700106 // Launch the server before parsing the hprof file so we get
107 // BindExceptions quickly.
Richard Uhlerb730b782015-07-15 16:01:58 -0700108 InetAddress loopback = InetAddress.getLoopbackAddress();
109 InetSocketAddress addr = new InetSocketAddress(loopback, port);
110 HttpServer server = HttpServer.create(addr, 0);
Richard Uhler46e476b2016-07-21 13:52:48 -0700111
112 System.out.println("Processing hprof file...");
Richard Uhlerec78c782016-05-13 14:19:37 -0700113 AhatSnapshot ahat = AhatSnapshot.fromHprof(hprof, map);
Richard Uhlerf629cfd2016-12-12 13:11:26 +0000114
115 if (hprofbase != null) {
116 System.out.println("Processing baseline hprof file...");
117 AhatSnapshot base = AhatSnapshot.fromHprof(hprofbase, mapbase);
118
119 System.out.println("Diffing hprof files...");
120 Diff.snapshots(ahat, base);
121 }
122
123 server.createContext("/", new AhatHttpHandler(new OverviewHandler(ahat, hprof, hprofbase)));
Richard Uhler7a16adb2015-11-11 09:13:23 -0800124 server.createContext("/rooted", new AhatHttpHandler(new RootedHandler(ahat)));
Richard Uhler1af86f12015-10-29 14:55:00 -0700125 server.createContext("/object", new AhatHttpHandler(new ObjectHandler(ahat)));
126 server.createContext("/objects", new AhatHttpHandler(new ObjectsHandler(ahat)));
127 server.createContext("/site", new AhatHttpHandler(new SiteHandler(ahat)));
Richard Uhlerb730b782015-07-15 16:01:58 -0700128 server.createContext("/bitmap", new BitmapHandler(ahat));
Richard Uhlerb730b782015-07-15 16:01:58 -0700129 server.createContext("/style.css", new StaticHandler("style.css", "text/css"));
130 server.setExecutor(Executors.newFixedThreadPool(1));
131 System.out.println("Server started on localhost:" + port);
Richard Uhlercda4f2e2016-09-09 09:56:20 +0100132
Richard Uhlerb730b782015-07-15 16:01:58 -0700133 server.start();
134 }
135}
136