/* * Copyright (C) 2011 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.chimpchat.adb; import com.google.common.collect.Lists; import com.android.SdkConstants; import com.android.chimpchat.core.IChimpBackend; import com.android.chimpchat.core.IChimpDevice; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IDevice; import java.io.File; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; /** * Backend implementation that works over ADB to talk to the device. */ public class AdbBackend implements IChimpBackend { private static Logger LOG = Logger.getLogger(AdbBackend.class.getCanonicalName()); // How long to wait each time we check for the device to be connected. private static final int CONNECTION_ITERATION_TIMEOUT_MS = 200; private final List<IChimpDevice> devices = Lists.newArrayList(); private final AndroidDebugBridge bridge; private final boolean initAdb; /** * Constructs an AdbBackend with default options. */ public AdbBackend() { this(null, false); } /** * Constructs an AdbBackend. * * @param adbLocation The location of the adb binary. If null, AdbBackend will * attempt to find the binary by itself. * @param noInitAdb If true, AdbBackend will not initialize AndroidDebugBridge. */ public AdbBackend(String adbLocation, boolean noInitAdb) { this.initAdb = !noInitAdb; // [try to] ensure ADB is running if (adbLocation == null) { adbLocation = findAdb(); } if (initAdb) { AndroidDebugBridge.init(false /* debugger support */); } bridge = AndroidDebugBridge.createBridge( adbLocation, true /* forceNewBridge */); } private String findAdb() { String mrParentLocation = System.getProperty("com.android.monkeyrunner.bindir"); //$NON-NLS-1$ // in the new SDK, adb is in the platform-tools, but when run from the command line // in the Android source tree, then adb is next to monkeyrunner. if (mrParentLocation != null && mrParentLocation.length() != 0) { // check if there's a platform-tools folder File platformTools = new File(new File(mrParentLocation).getParent(), SdkConstants.FD_PLATFORM_TOOLS); if (platformTools.isDirectory()) { return platformTools.getAbsolutePath() + File.separator + SdkConstants.FN_ADB; } return mrParentLocation + File.separator + SdkConstants.FN_ADB; } return SdkConstants.FN_ADB; } /** * Checks the attached devices looking for one whose device id matches the specified regex. * * @param deviceIdRegex the regular expression to match against * @return the Device (if found), or null (if not found). */ private IDevice findAttachedDevice(String deviceIdRegex) { Pattern pattern = Pattern.compile(deviceIdRegex); for (IDevice device : bridge.getDevices()) { String serialNumber = device.getSerialNumber(); if (pattern.matcher(serialNumber).matches()) { return device; } } return null; } @Override public IChimpDevice waitForConnection() { return waitForConnection(Integer.MAX_VALUE, ".*"); } @Override public IChimpDevice waitForConnection(long timeoutMs, String deviceIdRegex) { do { IDevice device = findAttachedDevice(deviceIdRegex); // Only return the device when it is online if (device != null && device.getState() == IDevice.DeviceState.ONLINE) { IChimpDevice chimpDevice = new AdbChimpDevice(device); devices.add(chimpDevice); return chimpDevice; } try { Thread.sleep(CONNECTION_ITERATION_TIMEOUT_MS); } catch (InterruptedException e) { LOG.log(Level.SEVERE, "Error sleeping", e); } timeoutMs -= CONNECTION_ITERATION_TIMEOUT_MS; } while (timeoutMs > 0); // Timeout. Give up. return null; } @Override public void shutdown() { for (IChimpDevice device : devices) { device.dispose(); } if (initAdb) { AndroidDebugBridge.terminate(); } } }