/* * 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 clientListModel; private UI ui; // Actions that need to be updated once a device is selected. private Collection 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(); dataTableModel = new DumpTableModel(); clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS); // Client utils with 10s timeout. List actions = new ArrayList(); 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(); 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 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 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); } }