Home | History | Annotate | Download | only in preload
      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      */
     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