blob: f585ea66fe91db96fdec4c9de4dd2d5428b395c2 [file] [log] [blame]
/*
* 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;
}
}
}