1554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe/* 2554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Copyright (C) 2015 The Android Open Source Project 3554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * 4554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License"); 5554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * you may not use this file except in compliance with the License. 6554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * You may obtain a copy of the License at 7554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * 8554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * http://www.apache.org/licenses/LICENSE-2.0 9554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * 10554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Unless required by applicable law or agreed to in writing, software 11554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS, 12554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * See the License for the specific language governing permissions and 14554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * limitations under the License. 15554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 16554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 17554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampepackage com.android.preload; 18554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 19286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeldimport com.android.ddmlib.AdbCommandRejectedException; 20554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport com.android.ddmlib.AndroidDebugBridge; 21554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; 22554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport com.android.preload.classdataretrieval.hprof.Hprof; 23554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport com.android.ddmlib.DdmPreferences; 24554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport com.android.ddmlib.IDevice; 25554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport com.android.ddmlib.IShellOutputReceiver; 26286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeldimport com.android.ddmlib.SyncException; 27286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeldimport com.android.ddmlib.TimeoutException; 28554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 29286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeldimport java.io.File; 30286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeldimport java.io.IOException; 31554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.Date; 32554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.concurrent.Future; 33554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampeimport java.util.concurrent.TimeUnit; 34554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 35554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe/** 36554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Helper class for some device routines. 37554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 38554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampepublic class DeviceUtils { 39554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 40286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Locations 41286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String PRELOADED_CLASSES_FILE = "/etc/preloaded-classes"; 42286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Shell commands 43286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String CREATE_EMPTY_PRELOADED_CMD = "touch " + PRELOADED_CLASSES_FILE; 44286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String DELETE_CACHE_CMD = "rm /data/dalvik-cache/*/*boot.art"; 45286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String DELETE_PRELOADED_CMD = "rm " + PRELOADED_CLASSES_FILE; 46286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String READ_PRELOADED_CMD = "cat " + PRELOADED_CLASSES_FILE; 47286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String START_SHELL_CMD = "start"; 48286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String STOP_SHELL_CMD = "stop"; 49286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String REMOUNT_SYSTEM_CMD = "mount -o rw,remount /system"; 50286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static final String UNSET_BOOTCOMPLETE_CMD = "setprop dev.bootcomplete \"0\""; 51286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld 52554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static void init(int debugPort) { 53554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe DdmPreferences.setSelectedDebugPort(debugPort); 54554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 55554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe Hprof.init(); 56554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 57554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe AndroidDebugBridge.init(true); 58554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 59554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe AndroidDebugBridge.createBridge(); 60554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 61554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 62554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 63554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Run a command in the shell on the device. 64554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 65554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static void doShell(IDevice device, String cmdline, long timeout, TimeUnit unit) { 66554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, cmdline, new NullShellOutputReceiver(), timeout, unit); 67554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 68554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 69554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 70554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Run a command in the shell on the device. Collects and returns the console output. 71554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 72554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static String doShellReturnString(IDevice device, String cmdline, long timeout, 73554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe TimeUnit unit) { 74554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe CollectStringShellOutputReceiver rec = new CollectStringShellOutputReceiver(); 75554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, cmdline, rec, timeout, unit); 76554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return rec.toString(); 77554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 78554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 79554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 80554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Run a command in the shell on the device, directing all output to the given receiver. 81554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 82554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static void doShell(IDevice device, String cmdline, IShellOutputReceiver receiver, 83554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe long timeout, TimeUnit unit) { 84554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe try { 85554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe device.executeShellCommand(cmdline, receiver, timeout, unit); 86554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } catch (Exception e) { 87554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe e.printStackTrace(); 88554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 89554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 90554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 91554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 92554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Run am start on the device. 93554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 94554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static void doAMStart(IDevice device, String name, String activity) { 95554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, "am start -n " + name + " /." + activity, 30, TimeUnit.SECONDS); 96554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 97554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 98554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 99554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Find the device with the given serial. Give up after the given timeout (in milliseconds). 100554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 101554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static IDevice findDevice(String serial, int timeout) { 102554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe WaitForDevice wfd = new WaitForDevice(serial, timeout); 103554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return wfd.get(); 104554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 105554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 106554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 107554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Get all devices ddms knows about. Wait at most for the given timeout. 108554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 109554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static IDevice[] findDevices(int timeout) { 110554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe WaitForDevice wfd = new WaitForDevice(null, timeout); 111554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe wfd.get(); 112554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return AndroidDebugBridge.getBridge().getDevices(); 113554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 114554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 115554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 116554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Return the build type of the given device. This is the value of the "ro.build.type" 117554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * system property. 118554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 119554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static String getBuildType(IDevice device) { 120554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe try { 121554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe Future<String> buildType = device.getSystemProperty("ro.build.type"); 122554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return buildType.get(500, TimeUnit.MILLISECONDS); 123554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } catch (Exception e) { 124554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 125554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return null; 126554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 127554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 128554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 129554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Check whether the given device has a pre-optimized boot image. More precisely, checks 130554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * whether /system/framework/ * /boot.art exists. 131554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 132554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static boolean hasPrebuiltBootImage(IDevice device) { 133554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe String ret = 134554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShellReturnString(device, "ls /system/framework/*/boot.art", 500, TimeUnit.MILLISECONDS); 135554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 136554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return !ret.contains("No such file or directory"); 137554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 138554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 139286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld /** 140286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * Write over the preloaded-classes file with an empty or existing file and regenerate the boot 141286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * image as necessary. 142286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * 143286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @param device 144286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @param pcFile 145286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @param bootTimeout 146286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @throws AdbCommandRejectedException 147286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @throws IOException 148286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @throws TimeoutException 149286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @throws SyncException 150286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld * @return true if successfully overwritten, false otherwise 151286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld */ 152286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld public static boolean overwritePreloaded(IDevice device, File pcFile, long bootTimeout) 153286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld throws AdbCommandRejectedException, IOException, TimeoutException, SyncException { 154286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld boolean writeEmpty = (pcFile == null); 155286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld if (writeEmpty) { 156286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Check if the preloaded-classes file is already empty. 157286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld String oldContent = 158286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShellReturnString(device, READ_PRELOADED_CMD, 1, TimeUnit.SECONDS); 159286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld if (oldContent.trim().equals("")) { 160286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld System.out.println("Preloaded-classes already empty."); 161286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld return true; 162286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld } 163286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld } 164286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld 165286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Stop the system server etc. 166286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShell(device, STOP_SHELL_CMD, 1, TimeUnit.SECONDS); 167286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Remount the read-only system partition 168286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShell(device, REMOUNT_SYSTEM_CMD, 1, TimeUnit.SECONDS); 169286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Delete the preloaded-classes file 170286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShell(device, DELETE_PRELOADED_CMD, 1, TimeUnit.SECONDS); 171286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Delete the dalvik cache files 172286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShell(device, DELETE_CACHE_CMD, 1, TimeUnit.SECONDS); 173286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld if (writeEmpty) { 174286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Write an empty preloaded-classes file 175286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShell(device, CREATE_EMPTY_PRELOADED_CMD, 500, TimeUnit.MILLISECONDS); 176286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld } else { 177286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Push the new preloaded-classes file 178286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld device.pushFile(pcFile.getAbsolutePath(), PRELOADED_CLASSES_FILE); 179286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld } 180286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Manually reset the boot complete flag 181286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShell(device, UNSET_BOOTCOMPLETE_CMD, 1, TimeUnit.SECONDS); 182286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Restart system server on the device 183286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld doShell(device, START_SHELL_CMD, 1, TimeUnit.SECONDS); 184286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld // Wait for the boot complete flag and return the outcome. 185286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld return waitForBootComplete(device, bootTimeout); 186286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld } 187554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 188286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld private static boolean waitForBootComplete(IDevice device, long timeout) { 189554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Do a loop checking each second whether bootcomplete. Wait for at most the given 190554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // threshold. 191554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe Date startDate = new Date(); 192554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe for (;;) { 193554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe try { 194554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe Thread.sleep(1000); 195554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } catch (InterruptedException e) { 196554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Ignore spurious wakeup. 197554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 198554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Check whether bootcomplete. 199554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe String ret = 200554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShellReturnString(device, "getprop dev.bootcomplete", 500, TimeUnit.MILLISECONDS); 201554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (ret.trim().equals("1")) { 202554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe break; 203554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 204554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe System.out.println("Still not booted: " + ret); 205554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 206554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Check whether we timed out. This is a simplistic check that doesn't take into account 207554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // things like switches in time. 208554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe Date endDate = new Date(); 209554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe long seconds = 210554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS); 211286839e40d302563befa0f43b071d8a19d744004Michael Rosenfeld if (seconds > timeout) { 212554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return false; 213554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 214554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 215554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 216554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return true; 217554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 218554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 219554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe /** 220554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe * Enable method-tracing on device. The system should be restarted after this. 221554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe */ 222554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public static void enableTracing(IDevice device) { 223554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Disable selinux. 224554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, "setenforce 0", 100, TimeUnit.MILLISECONDS); 225554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 226554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Make the profile directory world-writable. 227554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, "chmod 777 /data/dalvik-cache/profiles", 100, TimeUnit.MILLISECONDS); 228554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 229554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Enable streaming method tracing with a small 1K buffer. 230554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, "setprop dalvik.vm.method-trace true", 100, TimeUnit.MILLISECONDS); 231554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, "setprop dalvik.vm.method-trace-file " 232554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe + "/data/dalvik-cache/profiles/zygote.trace.bin", 100, TimeUnit.MILLISECONDS); 233554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, "setprop dalvik.vm.method-trace-file-siz 1024", 100, TimeUnit.MILLISECONDS); 234554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe doShell(device, "setprop dalvik.vm.method-trace-stream true", 100, TimeUnit.MILLISECONDS); 235554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 236554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 237554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private static class NullShellOutputReceiver implements IShellOutputReceiver { 238554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 239554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public boolean isCancelled() { 240554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return false; 241554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 242554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 243554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 244554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void flush() {} 245554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 246554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 247554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void addOutput(byte[] arg0, int arg1, int arg2) {} 248554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 249554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 250554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private static class CollectStringShellOutputReceiver implements IShellOutputReceiver { 251554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 252554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private StringBuilder builder = new StringBuilder(); 253554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 254554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 255554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public String toString() { 256554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe String ret = builder.toString(); 257554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Strip trailing newlines. They are especially ugly because adb uses DOS line endings. 258554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe while (ret.endsWith("\r") || ret.endsWith("\n")) { 259554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe ret = ret.substring(0, ret.length() - 1); 260554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 261554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return ret; 262554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 263554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 264554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 265554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void addOutput(byte[] arg0, int arg1, int arg2) { 266554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe builder.append(new String(arg0, arg1, arg2)); 267554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 268554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 269554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 270554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void flush() {} 271554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 272554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 273554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public boolean isCancelled() { 274554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return false; 275554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 276554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 277554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 278554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private static class WaitForDevice { 279554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 280554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private String serial; 281554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private long timeout; 282554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private IDevice device; 283554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 284554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public WaitForDevice(String serial, long timeout) { 285554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe this.serial = serial; 286554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe this.timeout = timeout; 287554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe device = null; 288554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 289554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 290554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public IDevice get() { 291554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (device == null) { 292554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe WaitForDeviceListener wfdl = new WaitForDeviceListener(serial); 293554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe synchronized (wfdl) { 294554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe AndroidDebugBridge.addDeviceChangeListener(wfdl); 295554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 296554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Check whether we already know about this device. 297554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe IDevice[] devices = AndroidDebugBridge.getBridge().getDevices(); 298554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (serial != null) { 299554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe for (IDevice d : devices) { 300554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (serial.equals(d.getSerialNumber())) { 301554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Only accept if there are clients already. Else wait for the callback informing 302554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // us that we now have clients. 303554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (d.hasClients()) { 304554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe device = d; 305554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 306554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 307554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe break; 308554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 309554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 310554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } else { 311554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (devices.length > 0) { 312554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe device = devices[0]; 313554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 314554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 315554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 316554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (device == null) { 317554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe try { 318f2a9933fa7082daf97d8290c0f9d001ba63b62aaAndreas Gampe wfdl.wait(timeout); 319554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } catch (InterruptedException e) { 320554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Ignore spurious wakeups. 321554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 322554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe device = wfdl.getDevice(); 323554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 324554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 325554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe AndroidDebugBridge.removeDeviceChangeListener(wfdl); 326554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 327554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 328554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 329554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (device != null) { 330554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Wait for clients. 331554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe WaitForClientsListener wfcl = new WaitForClientsListener(device); 332554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe synchronized (wfcl) { 333554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe AndroidDebugBridge.addDeviceChangeListener(wfcl); 334554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 335554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (!device.hasClients()) { 336554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe try { 337f2a9933fa7082daf97d8290c0f9d001ba63b62aaAndreas Gampe wfcl.wait(timeout); 338554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } catch (InterruptedException e) { 339554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Ignore spurious wakeups. 340554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 341554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 342554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 343554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe AndroidDebugBridge.removeDeviceChangeListener(wfcl); 344554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 345554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 346554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 347554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return device; 348554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 349554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 350554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private static class WaitForDeviceListener implements IDeviceChangeListener { 351554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 352554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private String serial; 353554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private IDevice device; 354554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 355554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public WaitForDeviceListener(String serial) { 356554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe this.serial = serial; 357554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 358554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 359554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public IDevice getDevice() { 360554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return device; 361554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 362554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 363554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 364554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void deviceChanged(IDevice arg0, int arg1) { 365554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // We may get a device changed instead of connected. Handle like a connection. 366554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe deviceConnected(arg0); 367554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 368554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 369554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 370554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void deviceConnected(IDevice arg0) { 371554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (device != null) { 372554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Ignore updates. 373554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe return; 374554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 375554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 376554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (serial == null || serial.equals(arg0.getSerialNumber())) { 377554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe device = arg0; 378554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe synchronized (this) { 379554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe notifyAll(); 380554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 381554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 382554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 383554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 384554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 385554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void deviceDisconnected(IDevice arg0) { 386554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Ignore disconnects. 387554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 388554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 389554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 390554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 391554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private static class WaitForClientsListener implements IDeviceChangeListener { 392554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 393554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe private IDevice myDevice; 394554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 395554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public WaitForClientsListener(IDevice myDevice) { 396554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe this.myDevice = myDevice; 397554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 398554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 399554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 400554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void deviceChanged(IDevice arg0, int arg1) { 401554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe if (arg0 == myDevice && (arg1 & IDevice.CHANGE_CLIENT_LIST) != 0) { 402554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe // Got a client list, done here. 403554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe synchronized (this) { 404554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe notifyAll(); 405554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 406554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 407554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 408554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 409554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 410554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void deviceConnected(IDevice arg0) { 411554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 412554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 413554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe @Override 414554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe public void deviceDisconnected(IDevice arg0) { 415554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 416554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 417554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 418554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe } 419554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe 420554d7ee0f5d177b6c0bce805f5a5917b6b211978Andreas Gampe} 421