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