aboutsummaryrefslogtreecommitdiff
path: root/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java
diff options
context:
space:
mode:
Diffstat (limited to 'hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java')
-rw-r--r--hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java237
1 files changed, 237 insertions, 0 deletions
diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java b/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java
new file mode 100644
index 000000000..f585ea66f
--- /dev/null
+++ b/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2008 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.hierarchyviewer.device;
+
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.MultiLineReceiver;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.TimeoutException;
+import com.android.hierarchyviewer.scene.VersionLoader;
+
+import java.io.IOException;
+import java.io.File;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DeviceBridge {
+ private static AndroidDebugBridge bridge;
+
+ private static final HashMap<IDevice, Integer> devicePortMap = new HashMap<IDevice, Integer>();
+ private static int nextLocalPort = Configuration.DEFAULT_SERVER_PORT;
+
+ public static void initDebugBridge() {
+ if (bridge == null) {
+ AndroidDebugBridge.init(false /* debugger support */);
+ }
+ if (bridge == null || !bridge.isConnected()) {
+ String adbLocation = System.getProperty("hierarchyviewer.adb");
+ if (adbLocation != null && adbLocation.length() != 0) {
+ adbLocation += File.separator + "adb";
+ } else {
+ adbLocation = "adb";
+ }
+
+ bridge = AndroidDebugBridge.createBridge(adbLocation, true);
+ }
+ }
+
+ public static void startListenForDevices(AndroidDebugBridge.IDeviceChangeListener listener) {
+ AndroidDebugBridge.addDeviceChangeListener(listener);
+ }
+
+ public static IDevice[] getDevices() {
+ return bridge.getDevices();
+ }
+
+ public static boolean isViewServerRunning(IDevice device) {
+ initDebugBridge();
+ final boolean[] result = new boolean[1];
+ try {
+ if (device.isOnline()) {
+ device.executeShellCommand(buildIsServerRunningShellCommand(),
+ new BooleanResultReader(result));
+ if (!result[0]) {
+ if (VersionLoader.loadProtocolVersion(device) > 2) {
+ result[0] = true;
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (TimeoutException e) {
+ e.printStackTrace();
+ } catch (AdbCommandRejectedException e) {
+ e.printStackTrace();
+ } catch (ShellCommandUnresponsiveException e) {
+ e.printStackTrace();
+ }
+ return result[0];
+ }
+
+ public static boolean startViewServer(IDevice device) {
+ return startViewServer(device, Configuration.DEFAULT_SERVER_PORT);
+ }
+
+ public static boolean startViewServer(IDevice device, int port) {
+ initDebugBridge();
+ final boolean[] result = new boolean[1];
+ try {
+ if (device.isOnline()) {
+ device.executeShellCommand(buildStartServerShellCommand(port),
+ new BooleanResultReader(result));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (TimeoutException e) {
+ e.printStackTrace();
+ } catch (AdbCommandRejectedException e) {
+ e.printStackTrace();
+ } catch (ShellCommandUnresponsiveException e) {
+ e.printStackTrace();
+ }
+ return result[0];
+ }
+
+ public static boolean stopViewServer(IDevice device) {
+ initDebugBridge();
+ final boolean[] result = new boolean[1];
+ try {
+ if (device.isOnline()) {
+ device.executeShellCommand(buildStopServerShellCommand(),
+ new BooleanResultReader(result));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (TimeoutException e) {
+ e.printStackTrace();
+ } catch (AdbCommandRejectedException e) {
+ e.printStackTrace();
+ } catch (ShellCommandUnresponsiveException e) {
+ e.printStackTrace();
+ }
+ return result[0];
+ }
+
+ public static void terminate() {
+ AndroidDebugBridge.terminate();
+ }
+
+ /**
+ * Sets up a just-connected device to work with the view server.
+ * <p/>This starts a port forwarding between a local port and a port on the device.
+ * @param device
+ */
+ public static void setupDeviceForward(IDevice device) {
+ synchronized (devicePortMap) {
+ if (device.getState() == IDevice.DeviceState.ONLINE) {
+ int localPort = nextLocalPort++;
+ try {
+ device.createForward(localPort, Configuration.DEFAULT_SERVER_PORT);
+ devicePortMap.put(device, localPort);
+ } catch (TimeoutException e) {
+ Log.e("hierarchy", "Timeout setting up port forwarding for " + device);
+ } catch (AdbCommandRejectedException e) {
+ Log.e("hierarchy", String.format(
+ "Adb rejected forward command for device %1$s: %2$s",
+ device, e.getMessage()));
+ } catch (IOException e) {
+ Log.e("hierarchy", String.format(
+ "Failed to create forward for device %1$s: %2$s",
+ device, e.getMessage()));
+ }
+ }
+ }
+ }
+
+ public static void removeDeviceForward(IDevice device) {
+ synchronized (devicePortMap) {
+ final Integer localPort = devicePortMap.get(device);
+ if (localPort != null) {
+ try {
+ device.removeForward(localPort, Configuration.DEFAULT_SERVER_PORT);
+ devicePortMap.remove(device);
+ } catch (TimeoutException e) {
+ Log.e("hierarchy", "Timeout removing port forwarding for " + device);
+ } catch (AdbCommandRejectedException e) {
+ Log.e("hierarchy", String.format(
+ "Adb rejected remove-forward command for device %1$s: %2$s",
+ device, e.getMessage()));
+ } catch (IOException e) {
+ Log.e("hierarchy", String.format(
+ "Failed to remove forward for device %1$s: %2$s",
+ device, e.getMessage()));
+ }
+ }
+ }
+ }
+
+ public static int getDeviceLocalPort(IDevice device) {
+ synchronized (devicePortMap) {
+ Integer port = devicePortMap.get(device);
+ if (port != null) {
+ return port;
+ }
+
+ Log.e("hierarchy", "Missing forwarded port for " + device.getSerialNumber());
+ return -1;
+ }
+
+ }
+
+ private static String buildStartServerShellCommand(int port) {
+ return String.format("service call window %d i32 %d",
+ Configuration.SERVICE_CODE_START_SERVER, port);
+ }
+
+ private static String buildStopServerShellCommand() {
+ return String.format("service call window %d", Configuration.SERVICE_CODE_STOP_SERVER);
+ }
+
+ private static String buildIsServerRunningShellCommand() {
+ return String.format("service call window %d",
+ Configuration.SERVICE_CODE_IS_SERVER_RUNNING);
+ }
+
+ private static class BooleanResultReader extends MultiLineReceiver {
+ private final boolean[] mResult;
+
+ public BooleanResultReader(boolean[] result) {
+ mResult = result;
+ }
+
+ @Override
+ public void processNewLines(String[] strings) {
+ if (strings.length > 0) {
+ Pattern pattern = Pattern.compile(".*?\\([0-9]{8} ([0-9]{8}).*");
+ Matcher matcher = pattern.matcher(strings[0]);
+ if (matcher.matches()) {
+ if (Integer.parseInt(matcher.group(1)) == 1) {
+ mResult[0] = true;
+ }
+ }
+ }
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+ }
+}