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.classdataretrieval.ClassDataRetriever;
33 import com.android.preload.classdataretrieval.hprof.Hprof;
34 import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
35 import com.android.preload.ui.UI;
36 
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.List;
40 import java.util.Map;
41 
42 import javax.swing.Action;
43 import javax.swing.DefaultListModel;
44 
45 public class Main {
46 
47     /**
48      * Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is
49      * off for now.
50      */
51     public final static boolean ENABLE_TRACING = false;
52 
53     /**
54      * Ten-second timeout.
55      */
56     public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000;
57 
58     /**
59      * Hprof timeout. Two minutes.
60      */
61     public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000;
62 
63     private IDevice device;
64     private static ClientUtils clientUtils;
65 
66     private DumpTableModel dataTableModel;
67     private DefaultListModel<Client> clientListModel;
68 
69     private UI ui;
70 
71     // Actions that need to be updated once a device is selected.
72     private Collection<DeviceSpecific> deviceSpecificActions;
73 
74     // Current main instance.
75     private static Main top;
76     private static boolean useJdwpClassDataRetriever = false;
77 
78     public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|"
79             + "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|"
80             + "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" +
81 
82 
83             // Threads
84             "android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|"
85             + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
86             + "(.*\\$NoPreloadHolder$)";
87 
88     /**
89      * @param args
90      */
main(String[] args)91     public static void main(String[] args) {
92         Main m = new Main();
93         top = m;
94 
95         m.startUp();
96     }
97 
Main()98     public Main() {
99         clientListModel = new DefaultListModel<Client>();
100         dataTableModel = new DumpTableModel();
101 
102         clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS);  // Client utils with 10s timeout.
103 
104         List<Action> actions = new ArrayList<Action>();
105         actions.add(new ReloadListAction(clientUtils, null, clientListModel));
106         actions.add(new ClearTableAction(dataTableModel));
107         actions.add(new RunMonkeyAction(null, dataTableModel));
108         actions.add(new ScanPackageAction(clientUtils, null, dataTableModel));
109         actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel));
110         actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2,
111                 CLASS_PRELOAD_BLACKLIST));
112         actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1,
113                 null));
114         actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
115                 CLASS_PRELOAD_BLACKLIST));
116         actions.add(new ShowDataAction(dataTableModel));
117         actions.add(new ImportAction(dataTableModel));
118         actions.add(new ExportAction(dataTableModel));
119 
120         deviceSpecificActions = new ArrayList<DeviceSpecific>();
121         for (Action a : actions) {
122             if (a instanceof DeviceSpecific) {
123                 deviceSpecificActions.add((DeviceSpecific)a);
124             }
125         }
126 
127         ui = new UI(clientListModel, dataTableModel, actions);
128         ui.setVisible(true);
129     }
130 
getUI()131     public static UI getUI() {
132         return top.ui;
133     }
134 
getClassDataRetriever()135     public static ClassDataRetriever getClassDataRetriever() {
136         if (useJdwpClassDataRetriever) {
137             return new JDWPClassDataRetriever();
138         } else {
139             return new Hprof(HPROF_TIMEOUT_MILLIS);
140         }
141     }
142 
getDevice()143     public IDevice getDevice() {
144         return device;
145     }
146 
setDevice(IDevice device)147     public void setDevice(IDevice device) {
148         this.device = device;
149         for (DeviceSpecific ds : deviceSpecificActions) {
150             ds.setDevice(device);
151         }
152     }
153 
getClientListModel()154     public DefaultListModel<Client> getClientListModel() {
155         return clientListModel;
156     }
157 
158     static class DeviceWrapper {
159         IDevice device;
160 
DeviceWrapper(IDevice d)161         public DeviceWrapper(IDevice d) {
162             device = d;
163         }
164 
165         @Override
toString()166         public String toString() {
167             return device.getName() + " (#" + device.getSerialNumber() + ")";
168         }
169     }
170 
startUp()171     private void startUp() {
172         getUI().showWaitDialog();
173         initDevice();
174 
175         // Load clients.
176         new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
177 
178         getUI().hideWaitDialog();
179     }
180 
initDevice()181     private void initDevice() {
182         DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS);
183 
184         IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS);
185         if (devices == null || devices.length == 0) {
186             throw new RuntimeException("Could not find any devices...");
187         }
188 
189         getUI().hideWaitDialog();
190 
191         DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length];
192         for (int i = 0; i < devices.length; i++) {
193             deviceWrappers[i] = new DeviceWrapper(devices[i]);
194         }
195 
196         DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device",
197                 deviceWrappers);
198         if (ret != null) {
199             setDevice(ret.device);
200         } else {
201             System.exit(0);
202         }
203 
204         boolean prepare = Main.getUI().showConfirmDialog("Prepare device?",
205                 "Do you want to prepare the device? This is highly recommended.");
206         if (prepare) {
207             String buildType = DeviceUtils.getBuildType(device);
208             if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) {
209                 Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType
210                         + ")");
211                 return;
212             }
213             if (DeviceUtils.hasPrebuiltBootImage(device)) {
214                 Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot "
215                         + "image!");
216                 return;
217             }
218 
219             if (ENABLE_TRACING) {
220                 DeviceUtils.enableTracing(device);
221             }
222 
223             Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
224                     + "long time. Please be patient.");
225             if (!DeviceUtils.removePreloaded(device, 15 * 60) /* 15m timeout */) {
226                 Main.getUI().showMessageDialog("Removing preloaded-classes failed unexpectedly!");
227             }
228         }
229     }
230 
findAndGetClassData(IDevice device, String packageName)231     public static Map<String, String> findAndGetClassData(IDevice device, String packageName)
232             throws Exception {
233         Client client = clientUtils.findClient(device, packageName, -1);
234         if (client == null) {
235             throw new RuntimeException("Could not find client...");
236         }
237         System.out.println("Found client: " + client);
238 
239         return getClassDataRetriever().getClassData(client);
240     }
241 
242 }
243