blob: 2265e9557c4bbfd3b6acba750008c22fac1bd901 [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;
18
19import com.android.ddmlib.Client;
20import com.android.ddmlib.IDevice;
21import com.android.preload.actions.ClearTableAction;
22import com.android.preload.actions.ComputeThresholdAction;
23import com.android.preload.actions.ComputeThresholdXAction;
24import com.android.preload.actions.DeviceSpecific;
25import com.android.preload.actions.ExportAction;
26import com.android.preload.actions.ImportAction;
27import com.android.preload.actions.ReloadListAction;
28import com.android.preload.actions.RunMonkeyAction;
29import com.android.preload.actions.ScanAllPackagesAction;
30import com.android.preload.actions.ScanPackageAction;
31import com.android.preload.actions.ShowDataAction;
Michael Rosenfeld286839e2017-02-14 17:52:23 -080032import com.android.preload.actions.WritePreloadedClassesAction;
Andreas Gampe554d7ee2015-09-15 08:57:12 -070033import com.android.preload.classdataretrieval.ClassDataRetriever;
34import com.android.preload.classdataretrieval.hprof.Hprof;
35import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
Andreas Gampe5cb89982016-11-28 13:15:10 -080036import com.android.preload.ui.IUI;
Andreas Gampe43747492016-11-28 15:07:39 -080037import com.android.preload.ui.SequenceUI;
Andreas Gampe5cb89982016-11-28 13:15:10 -080038import com.android.preload.ui.SwingUI;
Michael Rosenfeldc37b0a42016-11-28 18:08:00 -080039
Andreas Gampe43747492016-11-28 15:07:39 -080040import java.io.File;
Andreas Gampe554d7ee2015-09-15 08:57:12 -070041import java.util.ArrayList;
Andreas Gampe43747492016-11-28 15:07:39 -080042import java.util.Arrays;
Andreas Gampe554d7ee2015-09-15 08:57:12 -070043import java.util.Collection;
Andreas Gampe43747492016-11-28 15:07:39 -080044import java.util.Iterator;
Andreas Gampe554d7ee2015-09-15 08:57:12 -070045import java.util.List;
46import java.util.Map;
Michael Rosenfeldc37b0a42016-11-28 18:08:00 -080047import java.util.NoSuchElementException;
Andreas Gampe554d7ee2015-09-15 08:57:12 -070048
49import javax.swing.Action;
50import javax.swing.DefaultListModel;
51
52public class Main {
53
54 /**
55 * Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is
56 * off for now.
57 */
58 public final static boolean ENABLE_TRACING = false;
59
60 /**
61 * Ten-second timeout.
62 */
63 public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000;
64
65 /**
66 * Hprof timeout. Two minutes.
67 */
68 public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000;
69
70 private IDevice device;
71 private static ClientUtils clientUtils;
72
73 private DumpTableModel dataTableModel;
74 private DefaultListModel<Client> clientListModel;
75
Andreas Gampe5cb89982016-11-28 13:15:10 -080076 private IUI ui;
Andreas Gampe554d7ee2015-09-15 08:57:12 -070077
78 // Actions that need to be updated once a device is selected.
79 private Collection<DeviceSpecific> deviceSpecificActions;
80
81 // Current main instance.
82 private static Main top;
83 private static boolean useJdwpClassDataRetriever = false;
84
85 public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|"
86 + "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|"
87 + "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" +
88
89
90 // Threads
91 "android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|"
92 + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
93 + "(.*\\$NoPreloadHolder$)";
94
Michael Rosenfeldc37b0a42016-11-28 18:08:00 -080095 public final static String SCAN_ALL_CMD = "scan-all";
96 public final static String SCAN_PACKAGE_CMD = "scan";
97 public final static String COMPUTE_FILE_CMD = "comp";
98 public final static String EXPORT_CMD = "export";
99 public final static String IMPORT_CMD = "import";
Michael Rosenfeld286839e2017-02-14 17:52:23 -0800100 public final static String WRITE_CMD = "write";
Michael Rosenfeldc37b0a42016-11-28 18:08:00 -0800101
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700102 /**
103 * @param args
104 */
105 public static void main(String[] args) {
Andreas Gampe43747492016-11-28 15:07:39 -0800106 Main m;
107 if (args.length > 0 && args[0].equals("--seq")) {
108 m = createSequencedMain(args);
109 } else {
110 m = new Main(new SwingUI());
111 }
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700112
Andreas Gampe43747492016-11-28 15:07:39 -0800113 top = m;
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700114 m.startUp();
115 }
116
Andreas Gampe5cb89982016-11-28 13:15:10 -0800117 public Main(IUI ui) {
118 this.ui = ui;
119
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700120 clientListModel = new DefaultListModel<Client>();
121 dataTableModel = new DumpTableModel();
122
123 clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS); // Client utils with 10s timeout.
124
125 List<Action> actions = new ArrayList<Action>();
126 actions.add(new ReloadListAction(clientUtils, null, clientListModel));
127 actions.add(new ClearTableAction(dataTableModel));
128 actions.add(new RunMonkeyAction(null, dataTableModel));
129 actions.add(new ScanPackageAction(clientUtils, null, dataTableModel));
130 actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel));
131 actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2,
132 CLASS_PRELOAD_BLACKLIST));
133 actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1,
134 null));
135 actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
136 CLASS_PRELOAD_BLACKLIST));
Michael Rosenfeld286839e2017-02-14 17:52:23 -0800137 actions.add(new WritePreloadedClassesAction(clientUtils, null, dataTableModel));
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700138 actions.add(new ShowDataAction(dataTableModel));
139 actions.add(new ImportAction(dataTableModel));
140 actions.add(new ExportAction(dataTableModel));
141
142 deviceSpecificActions = new ArrayList<DeviceSpecific>();
143 for (Action a : actions) {
144 if (a instanceof DeviceSpecific) {
145 deviceSpecificActions.add((DeviceSpecific)a);
146 }
147 }
148
Andreas Gampe5cb89982016-11-28 13:15:10 -0800149 ui.prepare(clientListModel, dataTableModel, actions);
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700150 }
151
Andreas Gampe43747492016-11-28 15:07:39 -0800152 /**
153 * @param args
154 * @return
155 */
156 private static Main createSequencedMain(String[] args) {
157 SequenceUI ui = new SequenceUI();
158 Main main = new Main(ui);
159
160 Iterator<String> it = Arrays.asList(args).iterator();
161 it.next(); // --seq
Michael Rosenfeldc37b0a42016-11-28 18:08:00 -0800162 // Setup
Andreas Gampe43747492016-11-28 15:07:39 -0800163 ui.choice("#" + it.next()); // Device.
164 ui.confirmNo(); // Prepare: no.
Michael Rosenfeldc37b0a42016-11-28 18:08:00 -0800165 // Actions
166 try {
167 while (it.hasNext()) {
168 String op = it.next();
169 // Operation: Scan a single package
170 if (SCAN_PACKAGE_CMD.equals(op)) {
171 System.out.println("Scanning package.");
172 ui.action(ScanPackageAction.class);
173 ui.client(it.next());
174 // Operation: Scan all packages
175 } else if (SCAN_ALL_CMD.equals(op)) {
176 System.out.println("Scanning all packages.");
177 ui.action(ScanAllPackagesAction.class);
178 // Operation: Export the output to a file
179 } else if (EXPORT_CMD.equals(op)) {
180 System.out.println("Exporting data.");
181 ui.action(ExportAction.class);
182 ui.output(new File(it.next()));
183 // Operation: Import the input from a file or directory
184 } else if (IMPORT_CMD.equals(op)) {
185 System.out.println("Importing data.");
186 File file = new File(it.next());
187 if (!file.exists()) {
188 throw new RuntimeException(
189 String.format("File does not exist, %s.", file.getAbsolutePath()));
190 } else if (file.isFile()) {
191 ui.action(ImportAction.class);
192 ui.input(file);
193 } else if (file.isDirectory()) {
194 for (File content : file.listFiles()) {
195 ui.action(ImportAction.class);
196 ui.input(content);
197 }
198 }
199 // Operation: Compute preloaded classes with specific threshold
200 } else if (COMPUTE_FILE_CMD.equals(op)) {
201 System.out.println("Compute preloaded classes.");
202 ui.action(ComputeThresholdXAction.class);
203 ui.input(it.next());
204 ui.confirmYes();
205 ui.output(new File(it.next()));
Michael Rosenfeld286839e2017-02-14 17:52:23 -0800206 // Operation: Write preloaded classes from a specific file
207 } else if (WRITE_CMD.equals(op)) {
208 System.out.println("Writing preloaded classes.");
209 ui.action(WritePreloadedClassesAction.class);
210 ui.input(new File(it.next()));
Michael Rosenfeldc37b0a42016-11-28 18:08:00 -0800211 }
212 }
213 } catch (NoSuchElementException e) {
214 System.out.println("Failed to parse action sequence correctly.");
215 throw e;
216 }
Andreas Gampe43747492016-11-28 15:07:39 -0800217
218 return main;
219 }
220
Andreas Gampe5cb89982016-11-28 13:15:10 -0800221 public static IUI getUI() {
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700222 return top.ui;
223 }
224
225 public static ClassDataRetriever getClassDataRetriever() {
226 if (useJdwpClassDataRetriever) {
227 return new JDWPClassDataRetriever();
228 } else {
229 return new Hprof(HPROF_TIMEOUT_MILLIS);
230 }
231 }
232
233 public IDevice getDevice() {
234 return device;
235 }
236
237 public void setDevice(IDevice device) {
238 this.device = device;
239 for (DeviceSpecific ds : deviceSpecificActions) {
240 ds.setDevice(device);
241 }
242 }
243
244 public DefaultListModel<Client> getClientListModel() {
245 return clientListModel;
246 }
247
248 static class DeviceWrapper {
249 IDevice device;
250
251 public DeviceWrapper(IDevice d) {
252 device = d;
253 }
254
255 @Override
256 public String toString() {
257 return device.getName() + " (#" + device.getSerialNumber() + ")";
258 }
259 }
260
261 private void startUp() {
262 getUI().showWaitDialog();
263 initDevice();
264
265 // Load clients.
266 new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
267
268 getUI().hideWaitDialog();
Andreas Gampe5cb89982016-11-28 13:15:10 -0800269 getUI().ready();
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700270 }
271
272 private void initDevice() {
273 DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS);
274
275 IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS);
276 if (devices == null || devices.length == 0) {
277 throw new RuntimeException("Could not find any devices...");
278 }
279
280 getUI().hideWaitDialog();
281
282 DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length];
283 for (int i = 0; i < devices.length; i++) {
284 deviceWrappers[i] = new DeviceWrapper(devices[i]);
285 }
286
287 DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device",
288 deviceWrappers);
289 if (ret != null) {
290 setDevice(ret.device);
291 } else {
292 System.exit(0);
293 }
294
295 boolean prepare = Main.getUI().showConfirmDialog("Prepare device?",
296 "Do you want to prepare the device? This is highly recommended.");
297 if (prepare) {
298 String buildType = DeviceUtils.getBuildType(device);
299 if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) {
300 Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType
301 + ")");
302 return;
303 }
304 if (DeviceUtils.hasPrebuiltBootImage(device)) {
305 Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot "
306 + "image!");
307 return;
308 }
309
310 if (ENABLE_TRACING) {
311 DeviceUtils.enableTracing(device);
312 }
313
314 Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
315 + "long time. Please be patient.");
Michael Rosenfeld286839e2017-02-14 17:52:23 -0800316 boolean success = false;
317 try {
318 success = DeviceUtils.overwritePreloaded(device, null, 15 * 60);
319 } catch (Exception e) {
320 System.err.println(e);
321 } finally {
322 if (!success) {
323 Main.getUI().showMessageDialog(
324 "Removing preloaded-classes failed unexpectedly!");
325 }
Andreas Gampe554d7ee2015-09-15 08:57:12 -0700326 }
327 }
328 }
329
330 public static Map<String, String> findAndGetClassData(IDevice device, String packageName)
331 throws Exception {
332 Client client = clientUtils.findClient(device, packageName, -1);
333 if (client == null) {
334 throw new RuntimeException("Could not find client...");
335 }
336 System.out.println("Found client: " + client);
337
338 return getClassDataRetriever().getClassData(client);
339 }
340
341}