Main.java revision 554d7ee0f5d177b6c0bce805f5a5917b6b211978
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
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;
32import com.android.preload.classdataretrieval.ClassDataRetriever;
33import com.android.preload.classdataretrieval.hprof.Hprof;
34import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
35import com.android.preload.ui.UI;
36
37import java.util.ArrayList;
38import java.util.Collection;
39import java.util.List;
40import java.util.Map;
41
42import javax.swing.Action;
43import javax.swing.DefaultListModel;
44
45public 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     */
91    public static void main(String[] args) {
92        Main m = new Main();
93        top = m;
94
95        m.startUp();
96    }
97
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
131    public static UI getUI() {
132        return top.ui;
133    }
134
135    public static ClassDataRetriever getClassDataRetriever() {
136        if (useJdwpClassDataRetriever) {
137            return new JDWPClassDataRetriever();
138        } else {
139            return new Hprof(HPROF_TIMEOUT_MILLIS);
140        }
141    }
142
143    public IDevice getDevice() {
144        return device;
145    }
146
147    public void setDevice(IDevice device) {
148        this.device = device;
149        for (DeviceSpecific ds : deviceSpecificActions) {
150            ds.setDevice(device);
151        }
152    }
153
154    public DefaultListModel<Client> getClientListModel() {
155        return clientListModel;
156    }
157
158    static class DeviceWrapper {
159        IDevice device;
160
161        public DeviceWrapper(IDevice d) {
162            device = d;
163        }
164
165        @Override
166        public String toString() {
167            return device.getName() + " (#" + device.getSerialNumber() + ")";
168        }
169    }
170
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
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
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