Add a new preload tool based on hprof dumps. This means that only a userdebug build (to adjust the pre-existing preloaded-classes file) is required now, not a recompiled runtime. Change-Id: Ib0c00de3b248e49fa8271cbace67c5d4a50170a1
243 lines
8.2 KiB
Java
243 lines
8.2 KiB
Java
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.preload;
|
|
|
|
import com.android.ddmlib.Client;
|
|
import com.android.ddmlib.IDevice;
|
|
import com.android.preload.actions.ClearTableAction;
|
|
import com.android.preload.actions.ComputeThresholdAction;
|
|
import com.android.preload.actions.ComputeThresholdXAction;
|
|
import com.android.preload.actions.DeviceSpecific;
|
|
import com.android.preload.actions.ExportAction;
|
|
import com.android.preload.actions.ImportAction;
|
|
import com.android.preload.actions.ReloadListAction;
|
|
import com.android.preload.actions.RunMonkeyAction;
|
|
import com.android.preload.actions.ScanAllPackagesAction;
|
|
import com.android.preload.actions.ScanPackageAction;
|
|
import com.android.preload.actions.ShowDataAction;
|
|
import com.android.preload.classdataretrieval.ClassDataRetriever;
|
|
import com.android.preload.classdataretrieval.hprof.Hprof;
|
|
import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
|
|
import com.android.preload.ui.UI;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import javax.swing.Action;
|
|
import javax.swing.DefaultListModel;
|
|
|
|
public class Main {
|
|
|
|
/**
|
|
* Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is
|
|
* off for now.
|
|
*/
|
|
public final static boolean ENABLE_TRACING = false;
|
|
|
|
/**
|
|
* Ten-second timeout.
|
|
*/
|
|
public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000;
|
|
|
|
/**
|
|
* Hprof timeout. Two minutes.
|
|
*/
|
|
public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000;
|
|
|
|
private IDevice device;
|
|
private static ClientUtils clientUtils;
|
|
|
|
private DumpTableModel dataTableModel;
|
|
private DefaultListModel<Client> clientListModel;
|
|
|
|
private UI ui;
|
|
|
|
// Actions that need to be updated once a device is selected.
|
|
private Collection<DeviceSpecific> deviceSpecificActions;
|
|
|
|
// Current main instance.
|
|
private static Main top;
|
|
private static boolean useJdwpClassDataRetriever = false;
|
|
|
|
public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|"
|
|
+ "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|"
|
|
+ "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" +
|
|
|
|
|
|
// Threads
|
|
"android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|"
|
|
+ "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
|
|
+ "(.*\\$NoPreloadHolder$)";
|
|
|
|
/**
|
|
* @param args
|
|
*/
|
|
public static void main(String[] args) {
|
|
Main m = new Main();
|
|
top = m;
|
|
|
|
m.startUp();
|
|
}
|
|
|
|
public Main() {
|
|
clientListModel = new DefaultListModel<Client>();
|
|
dataTableModel = new DumpTableModel();
|
|
|
|
clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS); // Client utils with 10s timeout.
|
|
|
|
List<Action> actions = new ArrayList<Action>();
|
|
actions.add(new ReloadListAction(clientUtils, null, clientListModel));
|
|
actions.add(new ClearTableAction(dataTableModel));
|
|
actions.add(new RunMonkeyAction(null, dataTableModel));
|
|
actions.add(new ScanPackageAction(clientUtils, null, dataTableModel));
|
|
actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel));
|
|
actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2,
|
|
CLASS_PRELOAD_BLACKLIST));
|
|
actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1,
|
|
null));
|
|
actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
|
|
CLASS_PRELOAD_BLACKLIST));
|
|
actions.add(new ShowDataAction(dataTableModel));
|
|
actions.add(new ImportAction(dataTableModel));
|
|
actions.add(new ExportAction(dataTableModel));
|
|
|
|
deviceSpecificActions = new ArrayList<DeviceSpecific>();
|
|
for (Action a : actions) {
|
|
if (a instanceof DeviceSpecific) {
|
|
deviceSpecificActions.add((DeviceSpecific)a);
|
|
}
|
|
}
|
|
|
|
ui = new UI(clientListModel, dataTableModel, actions);
|
|
ui.setVisible(true);
|
|
}
|
|
|
|
public static UI getUI() {
|
|
return top.ui;
|
|
}
|
|
|
|
public static ClassDataRetriever getClassDataRetriever() {
|
|
if (useJdwpClassDataRetriever) {
|
|
return new JDWPClassDataRetriever();
|
|
} else {
|
|
return new Hprof(HPROF_TIMEOUT_MILLIS);
|
|
}
|
|
}
|
|
|
|
public IDevice getDevice() {
|
|
return device;
|
|
}
|
|
|
|
public void setDevice(IDevice device) {
|
|
this.device = device;
|
|
for (DeviceSpecific ds : deviceSpecificActions) {
|
|
ds.setDevice(device);
|
|
}
|
|
}
|
|
|
|
public DefaultListModel<Client> getClientListModel() {
|
|
return clientListModel;
|
|
}
|
|
|
|
static class DeviceWrapper {
|
|
IDevice device;
|
|
|
|
public DeviceWrapper(IDevice d) {
|
|
device = d;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return device.getName() + " (#" + device.getSerialNumber() + ")";
|
|
}
|
|
}
|
|
|
|
private void startUp() {
|
|
getUI().showWaitDialog();
|
|
initDevice();
|
|
|
|
// Load clients.
|
|
new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
|
|
|
|
getUI().hideWaitDialog();
|
|
}
|
|
|
|
private void initDevice() {
|
|
DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS);
|
|
|
|
IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS);
|
|
if (devices == null || devices.length == 0) {
|
|
throw new RuntimeException("Could not find any devices...");
|
|
}
|
|
|
|
getUI().hideWaitDialog();
|
|
|
|
DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length];
|
|
for (int i = 0; i < devices.length; i++) {
|
|
deviceWrappers[i] = new DeviceWrapper(devices[i]);
|
|
}
|
|
|
|
DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device",
|
|
deviceWrappers);
|
|
if (ret != null) {
|
|
setDevice(ret.device);
|
|
} else {
|
|
System.exit(0);
|
|
}
|
|
|
|
boolean prepare = Main.getUI().showConfirmDialog("Prepare device?",
|
|
"Do you want to prepare the device? This is highly recommended.");
|
|
if (prepare) {
|
|
String buildType = DeviceUtils.getBuildType(device);
|
|
if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) {
|
|
Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType
|
|
+ ")");
|
|
return;
|
|
}
|
|
if (DeviceUtils.hasPrebuiltBootImage(device)) {
|
|
Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot "
|
|
+ "image!");
|
|
return;
|
|
}
|
|
|
|
if (ENABLE_TRACING) {
|
|
DeviceUtils.enableTracing(device);
|
|
}
|
|
|
|
Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
|
|
+ "long time. Please be patient.");
|
|
if (!DeviceUtils.removePreloaded(device, 15 * 60) /* 15m timeout */) {
|
|
Main.getUI().showMessageDialog("Removing preloaded-classes failed unexpectedly!");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Map<String, String> findAndGetClassData(IDevice device, String packageName)
|
|
throws Exception {
|
|
Client client = clientUtils.findClient(device, packageName, -1);
|
|
if (client == null) {
|
|
throw new RuntimeException("Could not find client...");
|
|
}
|
|
System.out.println("Found client: " + client);
|
|
|
|
return getClassDataRetriever().getClassData(client);
|
|
}
|
|
|
|
}
|