• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.preload;
18 
19 import com.android.ddmlib.Client;
20 import com.android.ddmlib.IDevice;
21 import com.android.preload.actions.ClearTableAction;
22 import com.android.preload.actions.ComputeThresholdAction;
23 import com.android.preload.actions.ComputeThresholdXAction;
24 import com.android.preload.actions.DeviceSpecific;
25 import com.android.preload.actions.ExportAction;
26 import com.android.preload.actions.ImportAction;
27 import com.android.preload.actions.ReloadListAction;
28 import com.android.preload.actions.RunMonkeyAction;
29 import com.android.preload.actions.ScanAllPackagesAction;
30 import com.android.preload.actions.ScanPackageAction;
31 import com.android.preload.actions.ShowDataAction;
32 import com.android.preload.actions.WritePreloadedClassesAction;
33 import com.android.preload.classdataretrieval.ClassDataRetriever;
34 import com.android.preload.classdataretrieval.hprof.Hprof;
35 import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
36 import com.android.preload.ui.IUI;
37 import com.android.preload.ui.SequenceUI;
38 import com.android.preload.ui.SwingUI;
39 
40 import java.io.File;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.NoSuchElementException;
48 
49 import javax.swing.Action;
50 import javax.swing.DefaultListModel;
51 
52 public 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 
76     private IUI ui;
77 
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 
95     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";
100     public final static String WRITE_CMD = "write";
101 
102     /**
103      * @param args
104      */
main(String[] args)105     public static void main(String[] args) {
106         Main m;
107         if (args.length > 0 && args[0].equals("--seq")) {
108             m = createSequencedMain(args);
109         } else {
110             m = new Main(new SwingUI());
111         }
112 
113         top = m;
114         m.startUp();
115     }
116 
Main(IUI ui)117     public Main(IUI ui) {
118         this.ui = ui;
119 
120         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));
137         actions.add(new WritePreloadedClassesAction(clientUtils, null, dataTableModel));
138         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 
149         ui.prepare(clientListModel, dataTableModel, actions);
150     }
151 
152     /**
153      * @param args
154      * @return
155      */
createSequencedMain(String[] args)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
162         // Setup
163         ui.choice("#" + it.next());  // Device.
164         ui.confirmNo();              // Prepare: no.
165         // 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()));
206                 // 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()));
211                 }
212             }
213         } catch (NoSuchElementException e) {
214             System.out.println("Failed to parse action sequence correctly.");
215             throw e;
216         }
217 
218         return main;
219     }
220 
getUI()221     public static IUI getUI() {
222         return top.ui;
223     }
224 
getClassDataRetriever()225     public static ClassDataRetriever getClassDataRetriever() {
226         if (useJdwpClassDataRetriever) {
227             return new JDWPClassDataRetriever();
228         } else {
229             return new Hprof(HPROF_TIMEOUT_MILLIS);
230         }
231     }
232 
getDevice()233     public IDevice getDevice() {
234         return device;
235     }
236 
setDevice(IDevice device)237     public void setDevice(IDevice device) {
238         this.device = device;
239         for (DeviceSpecific ds : deviceSpecificActions) {
240             ds.setDevice(device);
241         }
242     }
243 
getClientListModel()244     public DefaultListModel<Client> getClientListModel() {
245         return clientListModel;
246     }
247 
248     static class DeviceWrapper {
249         IDevice device;
250 
DeviceWrapper(IDevice d)251         public DeviceWrapper(IDevice d) {
252             device = d;
253         }
254 
255         @Override
toString()256         public String toString() {
257             return device.getName() + " (#" + device.getSerialNumber() + ")";
258         }
259     }
260 
startUp()261     private void startUp() {
262         getUI().showWaitDialog();
263         initDevice();
264 
265         // Load clients.
266         new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
267 
268         getUI().hideWaitDialog();
269         getUI().ready();
270     }
271 
initDevice()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.");
316             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                 }
326             }
327         }
328     }
329 
findAndGetClassData(IDevice device, String packageName)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 }
342