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