aboutsummaryrefslogtreecommitdiffstats
path: root/ddms
diff options
context:
space:
mode:
authorRaphael Moll <ralf@android.com>2013-01-11 10:59:25 -0800
committerRaphael Moll <ralf@android.com>2013-01-11 11:17:26 -0800
commit11e58451f45294022625179d01a4b35b65f9ff07 (patch)
tree8d6d42e029fa6e765d8263c6f5162b201c5d2e21 /ddms
parent5b30d8114124620147d411c4e74bac426b7d34d4 (diff)
downloadsdk-11e58451f45294022625179d01a4b35b65f9ff07.zip
sdk-11e58451f45294022625179d01a4b35b65f9ff07.tar.gz
sdk-11e58451f45294022625179d01a4b35b65f9ff07.tar.bz2
SDK: switch ddmlib to prebuilts/devtools/ddmlib/ddmlib.jar
This also removes the ddmlib-tests.jar module. Change-Id: Id44bcc4b91ee76e22a3a50c000cda1b1e7bb972e
Diffstat (limited to 'ddms')
-rw-r--r--ddms/libs/ddmlib/Android.mk30
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbCommandRejectedException.java55
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbHelper.java791
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AllocationInfo.java215
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AndroidDebugBridge.java1163
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/BadPacketException.java35
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CanceledException.java40
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ChunkHandler.java222
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Client.java869
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ClientData.java726
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CollectingOutputReceiver.java83
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmConstants.java64
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmPreferences.java220
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DebugPortManager.java72
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Debugger.java353
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Device.java851
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DeviceMonitor.java947
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/EmulatorConsole.java743
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/FileListingService.java855
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/GetPropReceiver.java75
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleAppName.java116
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleExit.java76
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHeap.java594
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHello.java199
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleNativeHeap.java303
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleProfiling.java304
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleTest.java86
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleThread.java379
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleWait.java91
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HeapSegment.java448
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IDevice.java525
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IShellOutputReceiver.java44
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IStackTraceInfo.java29
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/InstallException.java42
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/JdwpPacket.java371
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Log.java358
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MonitorThread.java790
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MultiLineReceiver.java132
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeAllocationInfo.java305
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeLibraryMapInfo.java73
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeStackCallInfo.java113
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NullOutputReceiver.java53
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/OpenGlTraceChunkHandler.java63
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/RawImage.java222
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ShellCommandUnresponsiveException.java27
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncException.java97
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncService.java883
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ThreadInfo.java140
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/TimeoutException.java26
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventContainer.java462
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventLogParser.java588
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventValueDescription.java216
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/GcEventContainer.java347
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidTypeException.java74
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidValueTypeException.java78
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/LogReceiver.java247
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java236
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/ITestRunListener.java109
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/InstrumentationResultParser.java609
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java317
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestIdentifier.java91
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestResult.java147
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestRunResult.java324
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/XmlTestRunListener.java238
-rw-r--r--ddms/libs/ddmlib/src/main/java/com/android/ddmlib/utils/ArrayHelper.java90
-rw-r--r--ddms/libs/ddmlib/src/test/.classpath9
-rw-r--r--ddms/libs/ddmlib/src/test/.project17
-rw-r--r--ddms/libs/ddmlib/src/test/java/com/android/ddmlib/EmulatorConsoleTest.java45
-rw-r--r--ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java429
-rw-r--r--ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java138
-rw-r--r--ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/XmlTestRunListenerTest.java159
71 files changed, 9 insertions, 20259 deletions
diff --git a/ddms/libs/ddmlib/Android.mk b/ddms/libs/ddmlib/Android.mk
index c0191f9..c479e79 100644
--- a/ddms/libs/ddmlib/Android.mk
+++ b/ddms/libs/ddmlib/Android.mk
@@ -13,32 +13,20 @@
# limitations under the License.
LOCAL_PATH := $(call my-dir)
-
include $(CLEAR_VARS)
-# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_JAVA_RESOURCE_DIRS := src/main/java
-
-LOCAL_JAVA_LIBRARIES := kxml2-2.3.0
+# The ddmlib source has moved to tools/base/ddmlib.
+# The rule below uses the prebuilt ddmlib.jar if found.
+#
+# If you want to run the tests, cd to tools/base/ddmlib
+# and run ./gradlew :ddmlib:test
LOCAL_MODULE := ddmlib
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-# Build tests
-
-include $(CLEAR_VARS)
-
-# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java)
-
-LOCAL_MODULE := ddmlib-tests
LOCAL_MODULE_TAGS := optional
+LOCAL_JAVA_LIBRARIES := kxml2-2.3.0
-LOCAL_JAVA_LIBRARIES := ddmlib junit easymock
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../../../prebuilts/devtools/$(LOCAL_MODULE)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
-include $(BUILD_HOST_JAVA_LIBRARY)
+include $(BUILD_HOST_PREBUILT)
-# Build all sub-directories
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbCommandRejectedException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbCommandRejectedException.java
deleted file mode 100644
index ae7d014..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbCommandRejectedException.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib;
-
-
-/**
- * Exception thrown when adb refuses a command.
- */
-public class AdbCommandRejectedException extends Exception {
- private static final long serialVersionUID = 1L;
- private final boolean mIsDeviceOffline;
- private final boolean mErrorDuringDeviceSelection;
-
- AdbCommandRejectedException(String message) {
- super(message);
- mIsDeviceOffline = "device offline".equals(message);
- mErrorDuringDeviceSelection = false;
- }
-
- AdbCommandRejectedException(String message, boolean errorDuringDeviceSelection) {
- super(message);
- mErrorDuringDeviceSelection = errorDuringDeviceSelection;
- mIsDeviceOffline = "device offline".equals(message);
- }
-
- /**
- * Returns true if the error is due to the device being offline.
- */
- public boolean isDeviceOffline() {
- return mIsDeviceOffline;
- }
-
- /**
- * Returns whether adb refused to target a given device for the command.
- * <p/>If false, adb refused the command itself, if true, it refused to target the given
- * device.
- */
- public boolean wasErrorDuringDeviceSelection() {
- return mErrorDuringDeviceSelection;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbHelper.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbHelper.java
deleted file mode 100644
index c1c9300..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AdbHelper.java
+++ /dev/null
@@ -1,791 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.log.LogReceiver;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.SocketChannel;
-
-/**
- * Helper class to handle requests and connections to adb.
- * <p/>{@link DebugBridgeServer} is the public API to connection to adb, while {@link AdbHelper}
- * does the low level stuff.
- * <p/>This currently uses spin-wait non-blocking I/O. A Selector would be more efficient,
- * but seems like overkill for what we're doing here.
- */
-final class AdbHelper {
-
- // public static final long kOkay = 0x59414b4fL;
- // public static final long kFail = 0x4c494146L;
-
- static final int WAIT_TIME = 5; // spin-wait sleep, in ms
-
- static final String DEFAULT_ENCODING = "ISO-8859-1"; //$NON-NLS-1$
-
- /** do not instantiate */
- private AdbHelper() {
- }
-
- /**
- * Response from ADB.
- */
- static class AdbResponse {
- public AdbResponse() {
- message = "";
- }
-
- public boolean okay; // first 4 bytes in response were "OKAY"?
-
- public String message; // diagnostic string if #okay is false
- }
-
- /**
- * Create and connect a new pass-through socket, from the host to a port on
- * the device.
- *
- * @param adbSockAddr
- * @param device the device to connect to. Can be null in which case the connection will be
- * to the first available device.
- * @param devicePort the port we're opening
- * @throws TimeoutException in case of timeout on the connection.
- * @throws IOException in case of I/O error on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- */
- public static SocketChannel open(InetSocketAddress adbSockAddr,
- Device device, int devicePort)
- throws IOException, TimeoutException, AdbCommandRejectedException {
-
- SocketChannel adbChan = SocketChannel.open(adbSockAddr);
- try {
- adbChan.socket().setTcpNoDelay(true);
- adbChan.configureBlocking(false);
-
- // if the device is not -1, then we first tell adb we're looking to
- // talk to a specific device
- setDevice(adbChan, device);
-
- byte[] req = createAdbForwardRequest(null, devicePort);
- // Log.hexDump(req);
-
- write(adbChan, req);
-
- AdbResponse resp = readAdbResponse(adbChan, false);
- if (resp.okay == false) {
- throw new AdbCommandRejectedException(resp.message);
- }
-
- adbChan.configureBlocking(true);
- } catch (TimeoutException e) {
- adbChan.close();
- throw e;
- } catch (IOException e) {
- adbChan.close();
- throw e;
- }
-
- return adbChan;
- }
-
- /**
- * Creates and connects a new pass-through socket, from the host to a port on
- * the device.
- *
- * @param adbSockAddr
- * @param device the device to connect to. Can be null in which case the connection will be
- * to the first available device.
- * @param pid the process pid to connect to.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public static SocketChannel createPassThroughConnection(InetSocketAddress adbSockAddr,
- Device device, int pid)
- throws TimeoutException, AdbCommandRejectedException, IOException {
-
- SocketChannel adbChan = SocketChannel.open(adbSockAddr);
- try {
- adbChan.socket().setTcpNoDelay(true);
- adbChan.configureBlocking(false);
-
- // if the device is not -1, then we first tell adb we're looking to
- // talk to a specific device
- setDevice(adbChan, device);
-
- byte[] req = createJdwpForwardRequest(pid);
- // Log.hexDump(req);
-
- write(adbChan, req);
-
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) {
- throw new AdbCommandRejectedException(resp.message);
- }
-
- adbChan.configureBlocking(true);
- } catch (TimeoutException e) {
- adbChan.close();
- throw e;
- } catch (IOException e) {
- adbChan.close();
- throw e;
- }
-
- return adbChan;
- }
-
- /**
- * Creates a port forwarding request for adb. This returns an array
- * containing "####tcp:{port}:{addStr}".
- * @param addrStr the host. Can be null.
- * @param port the port on the device. This does not need to be numeric.
- */
- private static byte[] createAdbForwardRequest(String addrStr, int port) {
- String reqStr;
-
- if (addrStr == null)
- reqStr = "tcp:" + port;
- else
- reqStr = "tcp:" + port + ":" + addrStr;
- return formAdbRequest(reqStr);
- }
-
- /**
- * Creates a port forwarding request to a jdwp process. This returns an array
- * containing "####jwdp:{pid}".
- * @param pid the jdwp process pid on the device.
- */
- private static byte[] createJdwpForwardRequest(int pid) {
- String reqStr = String.format("jdwp:%1$d", pid); //$NON-NLS-1$
- return formAdbRequest(reqStr);
- }
-
- /**
- * Create an ASCII string preceeded by four hex digits. The opening "####"
- * is the length of the rest of the string, encoded as ASCII hex (case
- * doesn't matter). "port" and "host" are what we want to forward to. If
- * we're on the host side connecting into the device, "addrStr" should be
- * null.
- */
- static byte[] formAdbRequest(String req) {
- String resultStr = String.format("%04X%s", req.length(), req); //$NON-NLS-1$
- byte[] result;
- try {
- result = resultStr.getBytes(DEFAULT_ENCODING);
- } catch (UnsupportedEncodingException uee) {
- uee.printStackTrace(); // not expected
- return null;
- }
- assert result.length == req.length() + 4;
- return result;
- }
-
- /**
- * Reads the response from ADB after a command.
- * @param chan The socket channel that is connected to adb.
- * @param readDiagString If true, we're expecting an OKAY response to be
- * followed by a diagnostic string. Otherwise, we only expect the
- * diagnostic string to follow a FAIL.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws IOException in case of I/O error on the connection.
- */
- static AdbResponse readAdbResponse(SocketChannel chan, boolean readDiagString)
- throws TimeoutException, IOException {
-
- AdbResponse resp = new AdbResponse();
-
- byte[] reply = new byte[4];
- read(chan, reply);
-
- if (isOkay(reply)) {
- resp.okay = true;
- } else {
- readDiagString = true; // look for a reason after the FAIL
- resp.okay = false;
- }
-
- // not a loop -- use "while" so we can use "break"
- try {
- while (readDiagString) {
- // length string is in next 4 bytes
- byte[] lenBuf = new byte[4];
- read(chan, lenBuf);
-
- String lenStr = replyToString(lenBuf);
-
- int len;
- try {
- len = Integer.parseInt(lenStr, 16);
- } catch (NumberFormatException nfe) {
- Log.w("ddms", "Expected digits, got '" + lenStr + "': "
- + lenBuf[0] + " " + lenBuf[1] + " " + lenBuf[2] + " "
- + lenBuf[3]);
- Log.w("ddms", "reply was " + replyToString(reply));
- break;
- }
-
- byte[] msg = new byte[len];
- read(chan, msg);
-
- resp.message = replyToString(msg);
- Log.v("ddms", "Got reply '" + replyToString(reply) + "', diag='"
- + resp.message + "'");
-
- break;
- }
- } catch (Exception e) {
- // ignore those, since it's just reading the diagnose string, the response will
- // contain okay==false anyway.
- }
-
- return resp;
- }
-
- /**
- * Retrieve the frame buffer from the device.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- static RawImage getFrameBuffer(InetSocketAddress adbSockAddr, Device device)
- throws TimeoutException, AdbCommandRejectedException, IOException {
-
- RawImage imageParams = new RawImage();
- byte[] request = formAdbRequest("framebuffer:"); //$NON-NLS-1$
- byte[] nudge = {
- 0
- };
- byte[] reply;
-
- SocketChannel adbChan = null;
- try {
- adbChan = SocketChannel.open(adbSockAddr);
- adbChan.configureBlocking(false);
-
- // if the device is not -1, then we first tell adb we're looking to talk
- // to a specific device
- setDevice(adbChan, device);
-
- write(adbChan, request);
-
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) {
- throw new AdbCommandRejectedException(resp.message);
- }
-
- // first the protocol version.
- reply = new byte[4];
- read(adbChan, reply);
-
- ByteBuffer buf = ByteBuffer.wrap(reply);
- buf.order(ByteOrder.LITTLE_ENDIAN);
-
- int version = buf.getInt();
-
- // get the header size (this is a count of int)
- int headerSize = RawImage.getHeaderSize(version);
-
- // read the header
- reply = new byte[headerSize * 4];
- read(adbChan, reply);
-
- buf = ByteBuffer.wrap(reply);
- buf.order(ByteOrder.LITTLE_ENDIAN);
-
- // fill the RawImage with the header
- if (imageParams.readHeader(version, buf) == false) {
- Log.e("Screenshot", "Unsupported protocol: " + version);
- return null;
- }
-
- Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size="
- + imageParams.size + ", width=" + imageParams.width
- + ", height=" + imageParams.height);
-
- write(adbChan, nudge);
-
- reply = new byte[imageParams.size];
- read(adbChan, reply);
-
- imageParams.data = reply;
- } finally {
- if (adbChan != null) {
- adbChan.close();
- }
- }
-
- return imageParams;
- }
-
- /**
- * Executes a shell command on the device and retrieve the output. The output is
- * handed to <var>rcvr</var> as it arrives.
- *
- * @param adbSockAddr the {@link InetSocketAddress} to adb.
- * @param command the shell command to execute
- * @param device the {@link IDevice} on which to execute the command.
- * @param rcvr the {@link IShellOutputReceiver} that will receives the output of the shell
- * command
- * @param maxTimeToOutputResponse max time between command output. If more time passes
- * between command output, the method will throw
- * {@link ShellCommandUnresponsiveException}. A value of 0 means the method will
- * wait forever for command output and never throw.
- * @throws TimeoutException in case of timeout on the connection when sending the command.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException in case the shell command doesn't send any output
- * for a period longer than <var>maxTimeToOutputResponse</var>.
- * @throws IOException in case of I/O error on the connection.
- *
- * @see DdmPreferences#getTimeOut()
- */
- static void executeRemoteCommand(InetSocketAddress adbSockAddr,
- String command, IDevice device, IShellOutputReceiver rcvr, int maxTimeToOutputResponse)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- Log.v("ddms", "execute: running " + command);
-
- SocketChannel adbChan = null;
- try {
- adbChan = SocketChannel.open(adbSockAddr);
- adbChan.configureBlocking(false);
-
- // if the device is not -1, then we first tell adb we're looking to
- // talk
- // to a specific device
- setDevice(adbChan, device);
-
- byte[] request = formAdbRequest("shell:" + command); //$NON-NLS-1$
- write(adbChan, request);
-
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) {
- Log.e("ddms", "ADB rejected shell command (" + command + "): " + resp.message);
- throw new AdbCommandRejectedException(resp.message);
- }
-
- byte[] data = new byte[16384];
- ByteBuffer buf = ByteBuffer.wrap(data);
- int timeToResponseCount = 0;
- while (true) {
- int count;
-
- if (rcvr != null && rcvr.isCancelled()) {
- Log.v("ddms", "execute: cancelled");
- break;
- }
-
- count = adbChan.read(buf);
- if (count < 0) {
- // we're at the end, we flush the output
- rcvr.flush();
- Log.v("ddms", "execute '" + command + "' on '" + device + "' : EOF hit. Read: "
- + count);
- break;
- } else if (count == 0) {
- try {
- int wait = WAIT_TIME * 5;
- timeToResponseCount += wait;
- if (maxTimeToOutputResponse > 0 &&
- timeToResponseCount > maxTimeToOutputResponse) {
- throw new ShellCommandUnresponsiveException();
- }
- Thread.sleep(wait);
- } catch (InterruptedException ie) {
- }
- } else {
- // reset timeout
- timeToResponseCount = 0;
-
- // send data to receiver if present
- if (rcvr != null) {
- rcvr.addOutput(buf.array(), buf.arrayOffset(), buf.position());
- }
- buf.rewind();
- }
- }
- } finally {
- if (adbChan != null) {
- adbChan.close();
- }
- Log.v("ddms", "execute: returning");
- }
- }
-
- /**
- * Runs the Event log service on the {@link Device}, and provides its output to the
- * {@link LogReceiver}.
- * <p/>This call is blocking until {@link LogReceiver#isCancelled()} returns true.
- * @param adbSockAddr the socket address to connect to adb
- * @param device the Device on which to run the service
- * @param rcvr the {@link LogReceiver} to receive the log output
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public static void runEventLogService(InetSocketAddress adbSockAddr, Device device,
- LogReceiver rcvr) throws TimeoutException, AdbCommandRejectedException, IOException {
- runLogService(adbSockAddr, device, "events", rcvr); //$NON-NLS-1$
- }
-
- /**
- * Runs a log service on the {@link Device}, and provides its output to the {@link LogReceiver}.
- * <p/>This call is blocking until {@link LogReceiver#isCancelled()} returns true.
- * @param adbSockAddr the socket address to connect to adb
- * @param device the Device on which to run the service
- * @param logName the name of the log file to output
- * @param rcvr the {@link LogReceiver} to receive the log output
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public static void runLogService(InetSocketAddress adbSockAddr, Device device, String logName,
- LogReceiver rcvr) throws TimeoutException, AdbCommandRejectedException, IOException {
- SocketChannel adbChan = null;
-
- try {
- adbChan = SocketChannel.open(adbSockAddr);
- adbChan.configureBlocking(false);
-
- // if the device is not -1, then we first tell adb we're looking to talk
- // to a specific device
- setDevice(adbChan, device);
-
- byte[] request = formAdbRequest("log:" + logName);
- write(adbChan, request);
-
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) {
- throw new AdbCommandRejectedException(resp.message);
- }
-
- byte[] data = new byte[16384];
- ByteBuffer buf = ByteBuffer.wrap(data);
- while (true) {
- int count;
-
- if (rcvr != null && rcvr.isCancelled()) {
- break;
- }
-
- count = adbChan.read(buf);
- if (count < 0) {
- break;
- } else if (count == 0) {
- try {
- Thread.sleep(WAIT_TIME * 5);
- } catch (InterruptedException ie) {
- }
- } else {
- if (rcvr != null) {
- rcvr.parseNewData(buf.array(), buf.arrayOffset(), buf.position());
- }
- buf.rewind();
- }
- }
- } finally {
- if (adbChan != null) {
- adbChan.close();
- }
- }
- }
-
- /**
- * Creates a port forwarding between a local and a remote port.
- * @param adbSockAddr the socket address to connect to adb
- * @param device the device on which to do the port fowarding
- * @param localPortSpec specification of the local port to forward, should be of format
- * tcp:<port number>
- * @param remotePortSpec specification of the remote port to forward to, one of:
- * tcp:<port>
- * localabstract:<unix domain socket name>
- * localreserved:<unix domain socket name>
- * localfilesystem:<unix domain socket name>
- * dev:<character device name>
- * jdwp:<process pid> (remote only)
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public static void createForward(InetSocketAddress adbSockAddr, Device device,
- String localPortSpec, String remotePortSpec)
- throws TimeoutException, AdbCommandRejectedException, IOException {
-
- SocketChannel adbChan = null;
- try {
- adbChan = SocketChannel.open(adbSockAddr);
- adbChan.configureBlocking(false);
-
- byte[] request = formAdbRequest(String.format(
- "host-serial:%1$s:forward:%2$s;%3$s", //$NON-NLS-1$
- device.getSerialNumber(), localPortSpec, remotePortSpec));
-
- write(adbChan, request);
-
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) {
- Log.w("create-forward", "Error creating forward: " + resp.message);
- throw new AdbCommandRejectedException(resp.message);
- }
- } finally {
- if (adbChan != null) {
- adbChan.close();
- }
- }
- }
-
- /**
- * Remove a port forwarding between a local and a remote port.
- * @param adbSockAddr the socket address to connect to adb
- * @param device the device on which to remove the port fowarding
- * @param localPortSpec specification of the local port that was forwarded, should be of format
- * tcp:<port number>
- * @param remotePortSpec specification of the remote port forwarded to, one of:
- * tcp:<port>
- * localabstract:<unix domain socket name>
- * localreserved:<unix domain socket name>
- * localfilesystem:<unix domain socket name>
- * dev:<character device name>
- * jdwp:<process pid> (remote only)
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public static void removeForward(InetSocketAddress adbSockAddr, Device device,
- String localPortSpec, String remotePortSpec)
- throws TimeoutException, AdbCommandRejectedException, IOException {
-
- SocketChannel adbChan = null;
- try {
- adbChan = SocketChannel.open(adbSockAddr);
- adbChan.configureBlocking(false);
-
- byte[] request = formAdbRequest(String.format(
- "host-serial:%1$s:killforward:%2$s;%3$s", //$NON-NLS-1$
- device.getSerialNumber(), localPortSpec, remotePortSpec));
-
- write(adbChan, request);
-
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) {
- Log.w("remove-forward", "Error creating forward: " + resp.message);
- throw new AdbCommandRejectedException(resp.message);
- }
- } finally {
- if (adbChan != null) {
- adbChan.close();
- }
- }
- }
-
- /**
- * Checks to see if the first four bytes in "reply" are OKAY.
- */
- static boolean isOkay(byte[] reply) {
- return reply[0] == (byte)'O' && reply[1] == (byte)'K'
- && reply[2] == (byte)'A' && reply[3] == (byte)'Y';
- }
-
- /**
- * Converts an ADB reply to a string.
- */
- static String replyToString(byte[] reply) {
- String result;
- try {
- result = new String(reply, DEFAULT_ENCODING);
- } catch (UnsupportedEncodingException uee) {
- uee.printStackTrace(); // not expected
- result = "";
- }
- return result;
- }
-
- /**
- * Reads from the socket until the array is filled, or no more data is coming (because
- * the socket closed or the timeout expired).
- * <p/>This uses the default time out value.
- *
- * @param chan the opened socket to read from. It must be in non-blocking
- * mode for timeouts to work
- * @param data the buffer to store the read data into.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws IOException in case of I/O error on the connection.
- */
- static void read(SocketChannel chan, byte[] data) throws TimeoutException, IOException {
- read(chan, data, -1, DdmPreferences.getTimeOut());
- }
-
- /**
- * Reads from the socket until the array is filled, the optional length
- * is reached, or no more data is coming (because the socket closed or the
- * timeout expired). After "timeout" milliseconds since the
- * previous successful read, this will return whether or not new data has
- * been found.
- *
- * @param chan the opened socket to read from. It must be in non-blocking
- * mode for timeouts to work
- * @param data the buffer to store the read data into.
- * @param length the length to read or -1 to fill the data buffer completely
- * @param timeout The timeout value. A timeout of zero means "wait forever".
- */
- static void read(SocketChannel chan, byte[] data, int length, int timeout)
- throws TimeoutException, IOException {
- ByteBuffer buf = ByteBuffer.wrap(data, 0, length != -1 ? length : data.length);
- int numWaits = 0;
-
- while (buf.position() != buf.limit()) {
- int count;
-
- count = chan.read(buf);
- if (count < 0) {
- Log.d("ddms", "read: channel EOF");
- throw new IOException("EOF");
- } else if (count == 0) {
- // TODO: need more accurate timeout?
- if (timeout != 0 && numWaits * WAIT_TIME > timeout) {
- Log.d("ddms", "read: timeout");
- throw new TimeoutException();
- }
- // non-blocking spin
- try {
- Thread.sleep(WAIT_TIME);
- } catch (InterruptedException ie) {
- }
- numWaits++;
- } else {
- numWaits = 0;
- }
- }
- }
-
- /**
- * Write until all data in "data" is written or the connection fails or times out.
- * <p/>This uses the default time out value.
- * @param chan the opened socket to write to.
- * @param data the buffer to send.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws IOException in case of I/O error on the connection.
- */
- static void write(SocketChannel chan, byte[] data) throws TimeoutException, IOException {
- write(chan, data, -1, DdmPreferences.getTimeOut());
- }
-
- /**
- * Write until all data in "data" is written, the optional length is reached,
- * the timeout expires, or the connection fails. Returns "true" if all
- * data was written.
- * @param chan the opened socket to write to.
- * @param data the buffer to send.
- * @param length the length to write or -1 to send the whole buffer.
- * @param timeout The timeout value. A timeout of zero means "wait forever".
- * @throws TimeoutException in case of timeout on the connection.
- * @throws IOException in case of I/O error on the connection.
- */
- static void write(SocketChannel chan, byte[] data, int length, int timeout)
- throws TimeoutException, IOException {
- ByteBuffer buf = ByteBuffer.wrap(data, 0, length != -1 ? length : data.length);
- int numWaits = 0;
-
- while (buf.position() != buf.limit()) {
- int count;
-
- count = chan.write(buf);
- if (count < 0) {
- Log.d("ddms", "write: channel EOF");
- throw new IOException("channel EOF");
- } else if (count == 0) {
- // TODO: need more accurate timeout?
- if (timeout != 0 && numWaits * WAIT_TIME > timeout) {
- Log.d("ddms", "write: timeout");
- throw new TimeoutException();
- }
- // non-blocking spin
- try {
- Thread.sleep(WAIT_TIME);
- } catch (InterruptedException ie) {
- }
- numWaits++;
- } else {
- numWaits = 0;
- }
- }
- }
-
- /**
- * tells adb to talk to a specific device
- *
- * @param adbChan the socket connection to adb
- * @param device The device to talk to.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- static void setDevice(SocketChannel adbChan, IDevice device)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- // if the device is not -1, then we first tell adb we're looking to talk
- // to a specific device
- if (device != null) {
- String msg = "host:transport:" + device.getSerialNumber(); //$NON-NLS-1$
- byte[] device_query = formAdbRequest(msg);
-
- write(adbChan, device_query);
-
- AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
- if (resp.okay == false) {
- throw new AdbCommandRejectedException(resp.message,
- true/*errorDuringDeviceSelection*/);
- }
- }
- }
-
- /**
- * Reboot the device.
- *
- * @param into what to reboot into (recovery, bootloader). Or null to just reboot.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public static void reboot(String into, InetSocketAddress adbSockAddr,
- Device device) throws TimeoutException, AdbCommandRejectedException, IOException {
- byte[] request;
- if (into == null) {
- request = formAdbRequest("reboot:"); //$NON-NLS-1$
- } else {
- request = formAdbRequest("reboot:" + into); //$NON-NLS-1$
- }
-
- SocketChannel adbChan = null;
- try {
- adbChan = SocketChannel.open(adbSockAddr);
- adbChan.configureBlocking(false);
-
- // if the device is not -1, then we first tell adb we're looking to talk
- // to a specific device
- setDevice(adbChan, device);
-
- write(adbChan, request);
- } finally {
- if (adbChan != null) {
- adbChan.close();
- }
- }
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AllocationInfo.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AllocationInfo.java
deleted file mode 100644
index 157b044..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AllocationInfo.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.ddmlib;
-
-import java.util.Comparator;
-import java.util.Locale;
-
-/**
- * Holds an Allocation information.
- */
-public class AllocationInfo implements IStackTraceInfo {
- private final String mAllocatedClass;
- private final int mAllocNumber;
- private final int mAllocationSize;
- private final short mThreadId;
- private final StackTraceElement[] mStackTrace;
-
- public static enum SortMode {
- NUMBER, SIZE, CLASS, THREAD, IN_CLASS, IN_METHOD;
- }
-
- public final static class AllocationSorter implements Comparator<AllocationInfo> {
-
- private SortMode mSortMode = SortMode.SIZE;
- private boolean mDescending = true;
-
- public AllocationSorter() {
- }
-
- public void setSortMode(SortMode mode) {
- if (mSortMode == mode) {
- mDescending = !mDescending;
- } else {
- mSortMode = mode;
- }
- }
-
- public SortMode getSortMode() {
- return mSortMode;
- }
-
- public boolean isDescending() {
- return mDescending;
- }
-
- @Override
- public int compare(AllocationInfo o1, AllocationInfo o2) {
- int diff = 0;
- switch (mSortMode) {
- case NUMBER:
- diff = o1.mAllocNumber - o2.mAllocNumber;
- break;
- case SIZE:
- // pass, since diff is init with 0, we'll use SIZE compare below
- // as a back up anyway.
- break;
- case CLASS:
- diff = o1.mAllocatedClass.compareTo(o2.mAllocatedClass);
- break;
- case THREAD:
- diff = o1.mThreadId - o2.mThreadId;
- break;
- case IN_CLASS:
- String class1 = o1.getFirstTraceClassName();
- String class2 = o2.getFirstTraceClassName();
- diff = compareOptionalString(class1, class2);
- break;
- case IN_METHOD:
- String method1 = o1.getFirstTraceMethodName();
- String method2 = o2.getFirstTraceMethodName();
- diff = compareOptionalString(method1, method2);
- break;
- }
-
- if (diff == 0) {
- // same? compare on size
- diff = o1.mAllocationSize - o2.mAllocationSize;
- }
-
- if (mDescending) {
- diff = -diff;
- }
-
- return diff;
- }
-
- /** compares two strings that could be null */
- private int compareOptionalString(String str1, String str2) {
- if (str1 != null) {
- if (str2 == null) {
- return -1;
- } else {
- return str1.compareTo(str2);
- }
- } else {
- if (str2 == null) {
- return 0;
- } else {
- return 1;
- }
- }
- }
- }
-
- /*
- * Simple constructor.
- */
- AllocationInfo(int allocNumber, String allocatedClass, int allocationSize,
- short threadId, StackTraceElement[] stackTrace) {
- mAllocNumber = allocNumber;
- mAllocatedClass = allocatedClass;
- mAllocationSize = allocationSize;
- mThreadId = threadId;
- mStackTrace = stackTrace;
- }
-
- /**
- * Returns the allocation number. Allocations are numbered as they happen with the most
- * recent one having the highest number
- */
- public int getAllocNumber() {
- return mAllocNumber;
- }
-
- /**
- * Returns the name of the allocated class.
- */
- public String getAllocatedClass() {
- return mAllocatedClass;
- }
-
- /**
- * Returns the size of the allocation.
- */
- public int getSize() {
- return mAllocationSize;
- }
-
- /**
- * Returns the id of the thread that performed the allocation.
- */
- public short getThreadId() {
- return mThreadId;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IStackTraceInfo#getStackTrace()
- */
- @Override
- public StackTraceElement[] getStackTrace() {
- return mStackTrace;
- }
-
- public int compareTo(AllocationInfo otherAlloc) {
- return otherAlloc.mAllocationSize - mAllocationSize;
- }
-
- public String getFirstTraceClassName() {
- if (mStackTrace.length > 0) {
- return mStackTrace[0].getClassName();
- }
-
- return null;
- }
-
- public String getFirstTraceMethodName() {
- if (mStackTrace.length > 0) {
- return mStackTrace[0].getMethodName();
- }
-
- return null;
- }
-
- /**
- * Returns true if the given filter matches case insensitively (according to
- * the given locale) this allocation info.
- */
- public boolean filter(String filter, boolean fullTrace, Locale locale) {
- if (mAllocatedClass.toLowerCase(locale).contains(filter)) {
- return true;
- }
-
- if (mStackTrace.length > 0) {
- // check the top of the stack trace always
- final int length = fullTrace ? mStackTrace.length : 1;
-
- for (int i = 0 ; i < length ; i++) {
- if (mStackTrace[i].getClassName().toLowerCase(locale).contains(filter)) {
- return true;
- }
-
- if (mStackTrace[i].getMethodName().toLowerCase(locale).contains(filter)) {
- return true;
- }
- }
- }
-
- return false;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AndroidDebugBridge.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AndroidDebugBridge.java
deleted file mode 100644
index 5407d7f..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/AndroidDebugBridge.java
+++ /dev/null
@@ -1,1163 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.Log.LogLevel;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.lang.Thread.State;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.security.InvalidParameterException;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A connection to the host-side android debug bridge (adb)
- * <p/>This is the central point to communicate with any devices, emulators, or the applications
- * running on them.
- * <p/><b>{@link #init(boolean)} must be called before anything is done.</b>
- */
-public final class AndroidDebugBridge {
-
- /*
- * Minimum and maximum version of adb supported. This correspond to
- * ADB_SERVER_VERSION found in //device/tools/adb/adb.h
- */
-
- private final static int ADB_VERSION_MICRO_MIN = 20;
- private final static int ADB_VERSION_MICRO_MAX = -1;
-
- private final static Pattern sAdbVersion = Pattern.compile(
- "^.*(\\d+)\\.(\\d+)\\.(\\d+)$"); //$NON-NLS-1$
-
- private final static String ADB = "adb"; //$NON-NLS-1$
- private final static String DDMS = "ddms"; //$NON-NLS-1$
- private final static String SERVER_PORT_ENV_VAR = "ANDROID_ADB_SERVER_PORT"; //$NON-NLS-1$
-
- // Where to find the ADB bridge.
- final static String ADB_HOST = "127.0.0.1"; //$NON-NLS-1$
- final static int ADB_PORT = 5037;
-
- private static InetAddress sHostAddr;
- private static InetSocketAddress sSocketAddr;
-
- private static AndroidDebugBridge sThis;
- private static boolean sInitialized = false;
- private static boolean sClientSupport;
-
- /** Full path to adb. */
- private String mAdbOsLocation = null;
-
- private boolean mVersionCheck;
-
- private boolean mStarted = false;
-
- private DeviceMonitor mDeviceMonitor;
-
- private final static ArrayList<IDebugBridgeChangeListener> sBridgeListeners =
- new ArrayList<IDebugBridgeChangeListener>();
- private final static ArrayList<IDeviceChangeListener> sDeviceListeners =
- new ArrayList<IDeviceChangeListener>();
- private final static ArrayList<IClientChangeListener> sClientListeners =
- new ArrayList<IClientChangeListener>();
-
- // lock object for synchronization
- private static final Object sLock = sBridgeListeners;
-
- /**
- * Classes which implement this interface provide a method that deals
- * with {@link AndroidDebugBridge} changes.
- */
- public interface IDebugBridgeChangeListener {
- /**
- * Sent when a new {@link AndroidDebugBridge} is connected.
- * <p/>
- * This is sent from a non UI thread.
- * @param bridge the new {@link AndroidDebugBridge} object.
- */
- public void bridgeChanged(AndroidDebugBridge bridge);
- }
-
- /**
- * Classes which implement this interface provide methods that deal
- * with {@link IDevice} addition, deletion, and changes.
- */
- public interface IDeviceChangeListener {
- /**
- * Sent when the a device is connected to the {@link AndroidDebugBridge}.
- * <p/>
- * This is sent from a non UI thread.
- * @param device the new device.
- */
- public void deviceConnected(IDevice device);
-
- /**
- * Sent when the a device is connected to the {@link AndroidDebugBridge}.
- * <p/>
- * This is sent from a non UI thread.
- * @param device the new device.
- */
- public void deviceDisconnected(IDevice device);
-
- /**
- * Sent when a device data changed, or when clients are started/terminated on the device.
- * <p/>
- * This is sent from a non UI thread.
- * @param device the device that was updated.
- * @param changeMask the mask describing what changed. It can contain any of the following
- * values: {@link IDevice#CHANGE_BUILD_INFO}, {@link IDevice#CHANGE_STATE},
- * {@link IDevice#CHANGE_CLIENT_LIST}
- */
- public void deviceChanged(IDevice device, int changeMask);
- }
-
- /**
- * Classes which implement this interface provide methods that deal
- * with {@link Client} changes.
- */
- public interface IClientChangeListener {
- /**
- * Sent when an existing client information changed.
- * <p/>
- * This is sent from a non UI thread.
- * @param client the updated client.
- * @param changeMask the bit mask describing the changed properties. It can contain
- * any of the following values: {@link Client#CHANGE_INFO},
- * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE},
- * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE},
- * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA}
- */
- public void clientChanged(Client client, int changeMask);
- }
-
- /**
- * Initializes the <code>ddm</code> library.
- * <p/>This must be called once <b>before</b> any call to
- * {@link #createBridge(String, boolean)}.
- * <p>The library can be initialized in 2 ways:
- * <ul>
- * <li>Mode 1: <var>clientSupport</var> == <code>true</code>.<br>The library monitors the
- * devices and the applications running on them. It will connect to each application, as a
- * debugger of sort, to be able to interact with them through JDWP packets.</li>
- * <li>Mode 2: <var>clientSupport</var> == <code>false</code>.<br>The library only monitors
- * devices. The applications are left untouched, letting other tools built on
- * <code>ddmlib</code> to connect a debugger to them.</li>
- * </ul>
- * <p/><b>Only one tool can run in mode 1 at the same time.</b>
- * <p/>Note that mode 1 does not prevent debugging of applications running on devices. Mode 1
- * lets debuggers connect to <code>ddmlib</code> which acts as a proxy between the debuggers and
- * the applications to debug. See {@link Client#getDebuggerListenPort()}.
- * <p/>The preferences of <code>ddmlib</code> should also be initialized with whatever default
- * values were changed from the default values.
- * <p/>When the application quits, {@link #terminate()} should be called.
- * @param clientSupport Indicates whether the library should enable the monitoring and
- * interaction with applications running on the devices.
- * @see AndroidDebugBridge#createBridge(String, boolean)
- * @see DdmPreferences
- */
- public static synchronized void init(boolean clientSupport) {
- if (sInitialized) {
- throw new IllegalStateException("AndroidDebugBridge.init() has already been called.");
- }
- sInitialized = true;
- sClientSupport = clientSupport;
-
- // Determine port and instantiate socket address.
- initAdbSocketAddr();
-
- MonitorThread monitorThread = MonitorThread.createInstance();
- monitorThread.start();
-
- HandleHello.register(monitorThread);
- HandleAppName.register(monitorThread);
- HandleTest.register(monitorThread);
- HandleThread.register(monitorThread);
- HandleHeap.register(monitorThread);
- HandleWait.register(monitorThread);
- HandleProfiling.register(monitorThread);
- HandleNativeHeap.register(monitorThread);
- }
-
- /**
- * Terminates the ddm library. This must be called upon application termination.
- */
- public static synchronized void terminate() {
- // kill the monitoring services
- if (sThis != null && sThis.mDeviceMonitor != null) {
- sThis.mDeviceMonitor.stop();
- sThis.mDeviceMonitor = null;
- }
-
- MonitorThread monitorThread = MonitorThread.getInstance();
- if (monitorThread != null) {
- monitorThread.quit();
- }
-
- sInitialized = false;
- }
-
- /**
- * Returns whether the ddmlib is setup to support monitoring and interacting with
- * {@link Client}s running on the {@link IDevice}s.
- */
- static boolean getClientSupport() {
- return sClientSupport;
- }
-
- /**
- * Returns the socket address of the ADB server on the host.
- */
- public static InetSocketAddress getSocketAddress() {
- return sSocketAddr;
- }
-
- /**
- * Creates a {@link AndroidDebugBridge} that is not linked to any particular executable.
- * <p/>This bridge will expect adb to be running. It will not be able to start/stop/restart
- * adb.
- * <p/>If a bridge has already been started, it is directly returned with no changes (similar
- * to calling {@link #getBridge()}).
- * @return a connected bridge.
- */
- public static AndroidDebugBridge createBridge() {
- synchronized (sLock) {
- if (sThis != null) {
- return sThis;
- }
-
- try {
- sThis = new AndroidDebugBridge();
- sThis.start();
- } catch (InvalidParameterException e) {
- sThis = null;
- }
-
- // because the listeners could remove themselves from the list while processing
- // their event callback, we make a copy of the list and iterate on it instead of
- // the main list.
- // This mostly happens when the application quits.
- IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
- new IDebugBridgeChangeListener[sBridgeListeners.size()]);
-
- // notify the listeners of the change
- for (IDebugBridgeChangeListener listener : listenersCopy) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.bridgeChanged(sThis);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
-
- return sThis;
- }
- }
-
-
- /**
- * Creates a new debug bridge from the location of the command line tool.
- * <p/>
- * Any existing server will be disconnected, unless the location is the same and
- * <code>forceNewBridge</code> is set to false.
- * @param osLocation the location of the command line tool 'adb'
- * @param forceNewBridge force creation of a new bridge even if one with the same location
- * already exists.
- * @return a connected bridge.
- */
- public static AndroidDebugBridge createBridge(String osLocation, boolean forceNewBridge) {
- synchronized (sLock) {
- if (sThis != null) {
- if (sThis.mAdbOsLocation != null && sThis.mAdbOsLocation.equals(osLocation) &&
- forceNewBridge == false) {
- return sThis;
- } else {
- // stop the current server
- sThis.stop();
- }
- }
-
- try {
- sThis = new AndroidDebugBridge(osLocation);
- sThis.start();
- } catch (InvalidParameterException e) {
- sThis = null;
- }
-
- // because the listeners could remove themselves from the list while processing
- // their event callback, we make a copy of the list and iterate on it instead of
- // the main list.
- // This mostly happens when the application quits.
- IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
- new IDebugBridgeChangeListener[sBridgeListeners.size()]);
-
- // notify the listeners of the change
- for (IDebugBridgeChangeListener listener : listenersCopy) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.bridgeChanged(sThis);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
-
- return sThis;
- }
- }
-
- /**
- * Returns the current debug bridge. Can be <code>null</code> if none were created.
- */
- public static AndroidDebugBridge getBridge() {
- return sThis;
- }
-
- /**
- * Disconnects the current debug bridge, and destroy the object.
- * <p/>This also stops the current adb host server.
- * <p/>
- * A new object will have to be created with {@link #createBridge(String, boolean)}.
- */
- public static void disconnectBridge() {
- synchronized (sLock) {
- if (sThis != null) {
- sThis.stop();
- sThis = null;
-
- // because the listeners could remove themselves from the list while processing
- // their event callback, we make a copy of the list and iterate on it instead of
- // the main list.
- // This mostly happens when the application quits.
- IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
- new IDebugBridgeChangeListener[sBridgeListeners.size()]);
-
- // notify the listeners.
- for (IDebugBridgeChangeListener listener : listenersCopy) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.bridgeChanged(sThis);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
- }
- }
- }
-
- /**
- * Adds the listener to the collection of listeners who will be notified when a new
- * {@link AndroidDebugBridge} is connected, by sending it one of the messages defined
- * in the {@link IDebugBridgeChangeListener} interface.
- * @param listener The listener which should be notified.
- */
- public static void addDebugBridgeChangeListener(IDebugBridgeChangeListener listener) {
- synchronized (sLock) {
- if (sBridgeListeners.contains(listener) == false) {
- sBridgeListeners.add(listener);
- if (sThis != null) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.bridgeChanged(sThis);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
- }
- }
- }
-
- /**
- * Removes the listener from the collection of listeners who will be notified when a new
- * {@link AndroidDebugBridge} is started.
- * @param listener The listener which should no longer be notified.
- */
- public static void removeDebugBridgeChangeListener(IDebugBridgeChangeListener listener) {
- synchronized (sLock) {
- sBridgeListeners.remove(listener);
- }
- }
-
- /**
- * Adds the listener to the collection of listeners who will be notified when a {@link IDevice}
- * is connected, disconnected, or when its properties or its {@link Client} list changed,
- * by sending it one of the messages defined in the {@link IDeviceChangeListener} interface.
- * @param listener The listener which should be notified.
- */
- public static void addDeviceChangeListener(IDeviceChangeListener listener) {
- synchronized (sLock) {
- if (sDeviceListeners.contains(listener) == false) {
- sDeviceListeners.add(listener);
- }
- }
- }
-
- /**
- * Removes the listener from the collection of listeners who will be notified when a
- * {@link IDevice} is connected, disconnected, or when its properties or its {@link Client}
- * list changed.
- * @param listener The listener which should no longer be notified.
- */
- public static void removeDeviceChangeListener(IDeviceChangeListener listener) {
- synchronized (sLock) {
- sDeviceListeners.remove(listener);
- }
- }
-
- /**
- * Adds the listener to the collection of listeners who will be notified when a {@link Client}
- * property changed, by sending it one of the messages defined in the
- * {@link IClientChangeListener} interface.
- * @param listener The listener which should be notified.
- */
- public static void addClientChangeListener(IClientChangeListener listener) {
- synchronized (sLock) {
- if (sClientListeners.contains(listener) == false) {
- sClientListeners.add(listener);
- }
- }
- }
-
- /**
- * Removes the listener from the collection of listeners who will be notified when a
- * {@link Client} property changed.
- * @param listener The listener which should no longer be notified.
- */
- public static void removeClientChangeListener(IClientChangeListener listener) {
- synchronized (sLock) {
- sClientListeners.remove(listener);
- }
- }
-
-
- /**
- * Returns the devices.
- * @see #hasInitialDeviceList()
- */
- public IDevice[] getDevices() {
- synchronized (sLock) {
- if (mDeviceMonitor != null) {
- return mDeviceMonitor.getDevices();
- }
- }
-
- return new IDevice[0];
- }
-
- /**
- * Returns whether the bridge has acquired the initial list from adb after being created.
- * <p/>Calling {@link #getDevices()} right after {@link #createBridge(String, boolean)} will
- * generally result in an empty list. This is due to the internal asynchronous communication
- * mechanism with <code>adb</code> that does not guarantee that the {@link IDevice} list has been
- * built before the call to {@link #getDevices()}.
- * <p/>The recommended way to get the list of {@link IDevice} objects is to create a
- * {@link IDeviceChangeListener} object.
- */
- public boolean hasInitialDeviceList() {
- if (mDeviceMonitor != null) {
- return mDeviceMonitor.hasInitialDeviceList();
- }
-
- return false;
- }
-
- /**
- * Sets the client to accept debugger connection on the custom "Selected debug port".
- * @param selectedClient the client. Can be null.
- */
- public void setSelectedClient(Client selectedClient) {
- MonitorThread monitorThread = MonitorThread.getInstance();
- if (monitorThread != null) {
- monitorThread.setSelectedClient(selectedClient);
- }
- }
-
- /**
- * Returns whether the {@link AndroidDebugBridge} object is still connected to the adb daemon.
- */
- public boolean isConnected() {
- MonitorThread monitorThread = MonitorThread.getInstance();
- if (mDeviceMonitor != null && monitorThread != null) {
- return mDeviceMonitor.isMonitoring() && monitorThread.getState() != State.TERMINATED;
- }
- return false;
- }
-
- /**
- * Returns the number of times the {@link AndroidDebugBridge} object attempted to connect
- * to the adb daemon.
- */
- public int getConnectionAttemptCount() {
- if (mDeviceMonitor != null) {
- return mDeviceMonitor.getConnectionAttemptCount();
- }
- return -1;
- }
-
- /**
- * Returns the number of times the {@link AndroidDebugBridge} object attempted to restart
- * the adb daemon.
- */
- public int getRestartAttemptCount() {
- if (mDeviceMonitor != null) {
- return mDeviceMonitor.getRestartAttemptCount();
- }
- return -1;
- }
-
- /**
- * Creates a new bridge.
- * @param osLocation the location of the command line tool
- * @throws InvalidParameterException
- */
- private AndroidDebugBridge(String osLocation) throws InvalidParameterException {
- if (osLocation == null || osLocation.length() == 0) {
- throw new InvalidParameterException();
- }
- mAdbOsLocation = osLocation;
-
- checkAdbVersion();
- }
-
- /**
- * Creates a new bridge not linked to any particular adb executable.
- */
- private AndroidDebugBridge() {
- }
-
- /**
- * Queries adb for its version number and checks it against {@link #MIN_VERSION_NUMBER} and
- * {@link #MAX_VERSION_NUMBER}
- */
- private void checkAdbVersion() {
- // default is bad check
- mVersionCheck = false;
-
- if (mAdbOsLocation == null) {
- return;
- }
-
- String[] command = new String[2];
- command[0] = mAdbOsLocation;
- command[1] = "version"; //$NON-NLS-1$
- Log.d(DDMS, String.format("Checking '%1$s version'", mAdbOsLocation));
- Process process = null;
- try {
- process = Runtime.getRuntime().exec(command);
- } catch (IOException e) {
- boolean exists = new File(mAdbOsLocation).exists();
- String msg;
- if (exists) {
- msg = String.format(
- "Unexpected exception '%1$s' while attempting to get adb version from '%2$s'",
- e.getMessage(), mAdbOsLocation);
- } else {
- msg = "Unable to locate adb.\n" +
- "Please use SDK Manager and check if Android SDK platform-tools are installed.";
- }
- Log.logAndDisplay(LogLevel.ERROR, ADB, msg);
- return;
- }
-
- ArrayList<String> errorOutput = new ArrayList<String>();
- ArrayList<String> stdOutput = new ArrayList<String>();
- int status;
- try {
- status = grabProcessOutput(process, errorOutput, stdOutput,
- true /* waitForReaders */);
- } catch (InterruptedException e) {
- return;
- }
-
- if (status != 0) {
- StringBuilder builder = new StringBuilder("'adb version' failed!"); //$NON-NLS-1$
- for (String error : errorOutput) {
- builder.append('\n');
- builder.append(error);
- }
- Log.logAndDisplay(LogLevel.ERROR, ADB, builder.toString());
- }
-
- // check both stdout and stderr
- boolean versionFound = false;
- for (String line : stdOutput) {
- versionFound = scanVersionLine(line);
- if (versionFound) {
- break;
- }
- }
- if (!versionFound) {
- for (String line : errorOutput) {
- versionFound = scanVersionLine(line);
- if (versionFound) {
- break;
- }
- }
- }
-
- if (!versionFound) {
- // if we get here, we failed to parse the output.
- StringBuilder builder = new StringBuilder(
- "Failed to parse the output of 'adb version':\n"); //$NON-NLS-1$
- builder.append("Standard Output was:\n"); //$NON-NLS-1$
- for (String line : stdOutput) {
- builder.append(line);
- builder.append('\n');
- }
- builder.append("\nError Output was:\n"); //$NON-NLS-1$
- for (String line : errorOutput) {
- builder.append(line);
- builder.append('\n');
- }
- Log.logAndDisplay(LogLevel.ERROR, ADB, builder.toString());
- }
- }
-
- /**
- * Scans a line resulting from 'adb version' for a potential version number.
- * <p/>
- * If a version number is found, it checks the version number against what is expected
- * by this version of ddms.
- * <p/>
- * Returns true when a version number has been found so that we can stop scanning,
- * whether the version number is in the acceptable range or not.
- *
- * @param line The line to scan.
- * @return True if a version number was found (whether it is acceptable or not).
- */
- @SuppressWarnings("all") // With Eclipse 3.6, replace by @SuppressWarnings("unused")
- private boolean scanVersionLine(String line) {
- if (line != null) {
- Matcher matcher = sAdbVersion.matcher(line);
- if (matcher.matches()) {
- int majorVersion = Integer.parseInt(matcher.group(1));
- int minorVersion = Integer.parseInt(matcher.group(2));
- int microVersion = Integer.parseInt(matcher.group(3));
-
- // check only the micro version for now.
- if (microVersion < ADB_VERSION_MICRO_MIN) {
- String message = String.format(
- "Required minimum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
- + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
- majorVersion, minorVersion, ADB_VERSION_MICRO_MIN,
- microVersion);
- Log.logAndDisplay(LogLevel.ERROR, ADB, message);
- } else if (ADB_VERSION_MICRO_MAX != -1 &&
- microVersion > ADB_VERSION_MICRO_MAX) {
- String message = String.format(
- "Required maximum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
- + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
- majorVersion, minorVersion, ADB_VERSION_MICRO_MAX,
- microVersion);
- Log.logAndDisplay(LogLevel.ERROR, ADB, message);
- } else {
- mVersionCheck = true;
- }
-
- return true;
- }
- }
- return false;
- }
-
- /**
- * Starts the debug bridge.
- * @return true if success.
- */
- boolean start() {
- if (mAdbOsLocation != null && (mVersionCheck == false || startAdb() == false)) {
- return false;
- }
-
- mStarted = true;
-
- // now that the bridge is connected, we start the underlying services.
- mDeviceMonitor = new DeviceMonitor(this);
- mDeviceMonitor.start();
-
- return true;
- }
-
- /**
- * Kills the debug bridge, and the adb host server.
- * @return true if success
- */
- boolean stop() {
- // if we haven't started we return false;
- if (mStarted == false) {
- return false;
- }
-
- // kill the monitoring services
- mDeviceMonitor.stop();
- mDeviceMonitor = null;
-
- if (stopAdb() == false) {
- return false;
- }
-
- mStarted = false;
- return true;
- }
-
- /**
- * Restarts adb, but not the services around it.
- * @return true if success.
- */
- public boolean restart() {
- if (mAdbOsLocation == null) {
- Log.e(ADB,
- "Cannot restart adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
- return false;
- }
-
- if (mVersionCheck == false) {
- Log.logAndDisplay(LogLevel.ERROR, ADB,
- "Attempting to restart adb, but version check failed!"); //$NON-NLS-1$
- return false;
- }
- synchronized (this) {
- stopAdb();
-
- boolean restart = startAdb();
-
- if (restart && mDeviceMonitor == null) {
- mDeviceMonitor = new DeviceMonitor(this);
- mDeviceMonitor.start();
- }
-
- return restart;
- }
- }
-
- /**
- * Notify the listener of a new {@link IDevice}.
- * <p/>
- * The notification of the listeners is done in a synchronized block. It is important to
- * expect the listeners to potentially access various methods of {@link IDevice} as well as
- * {@link #getDevices()} which use internal locks.
- * <p/>
- * For this reason, any call to this method from a method of {@link DeviceMonitor},
- * {@link IDevice} which is also inside a synchronized block, should first synchronize on
- * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
- * @param device the new <code>IDevice</code>.
- * @see #getLock()
- */
- void deviceConnected(IDevice device) {
- // because the listeners could remove themselves from the list while processing
- // their event callback, we make a copy of the list and iterate on it instead of
- // the main list.
- // This mostly happens when the application quits.
- IDeviceChangeListener[] listenersCopy = null;
- synchronized (sLock) {
- listenersCopy = sDeviceListeners.toArray(
- new IDeviceChangeListener[sDeviceListeners.size()]);
- }
-
- // Notify the listeners
- for (IDeviceChangeListener listener : listenersCopy) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.deviceConnected(device);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
- }
-
- /**
- * Notify the listener of a disconnected {@link IDevice}.
- * <p/>
- * The notification of the listeners is done in a synchronized block. It is important to
- * expect the listeners to potentially access various methods of {@link IDevice} as well as
- * {@link #getDevices()} which use internal locks.
- * <p/>
- * For this reason, any call to this method from a method of {@link DeviceMonitor},
- * {@link IDevice} which is also inside a synchronized block, should first synchronize on
- * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
- * @param device the disconnected <code>IDevice</code>.
- * @see #getLock()
- */
- void deviceDisconnected(IDevice device) {
- // because the listeners could remove themselves from the list while processing
- // their event callback, we make a copy of the list and iterate on it instead of
- // the main list.
- // This mostly happens when the application quits.
- IDeviceChangeListener[] listenersCopy = null;
- synchronized (sLock) {
- listenersCopy = sDeviceListeners.toArray(
- new IDeviceChangeListener[sDeviceListeners.size()]);
- }
-
- // Notify the listeners
- for (IDeviceChangeListener listener : listenersCopy) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.deviceDisconnected(device);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
- }
-
- /**
- * Notify the listener of a modified {@link IDevice}.
- * <p/>
- * The notification of the listeners is done in a synchronized block. It is important to
- * expect the listeners to potentially access various methods of {@link IDevice} as well as
- * {@link #getDevices()} which use internal locks.
- * <p/>
- * For this reason, any call to this method from a method of {@link DeviceMonitor},
- * {@link IDevice} which is also inside a synchronized block, should first synchronize on
- * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
- * @param device the modified <code>IDevice</code>.
- * @see #getLock()
- */
- void deviceChanged(IDevice device, int changeMask) {
- // because the listeners could remove themselves from the list while processing
- // their event callback, we make a copy of the list and iterate on it instead of
- // the main list.
- // This mostly happens when the application quits.
- IDeviceChangeListener[] listenersCopy = null;
- synchronized (sLock) {
- listenersCopy = sDeviceListeners.toArray(
- new IDeviceChangeListener[sDeviceListeners.size()]);
- }
-
- // Notify the listeners
- for (IDeviceChangeListener listener : listenersCopy) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.deviceChanged(device, changeMask);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
- }
-
- /**
- * Notify the listener of a modified {@link Client}.
- * <p/>
- * The notification of the listeners is done in a synchronized block. It is important to
- * expect the listeners to potentially access various methods of {@link IDevice} as well as
- * {@link #getDevices()} which use internal locks.
- * <p/>
- * For this reason, any call to this method from a method of {@link DeviceMonitor},
- * {@link IDevice} which is also inside a synchronized block, should first synchronize on
- * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
- * @param device the modified <code>Client</code>.
- * @param changeMask the mask indicating what changed in the <code>Client</code>
- * @see #getLock()
- */
- void clientChanged(Client client, int changeMask) {
- // because the listeners could remove themselves from the list while processing
- // their event callback, we make a copy of the list and iterate on it instead of
- // the main list.
- // This mostly happens when the application quits.
- IClientChangeListener[] listenersCopy = null;
- synchronized (sLock) {
- listenersCopy = sClientListeners.toArray(
- new IClientChangeListener[sClientListeners.size()]);
-
- }
-
- // Notify the listeners
- for (IClientChangeListener listener : listenersCopy) {
- // we attempt to catch any exception so that a bad listener doesn't kill our
- // thread
- try {
- listener.clientChanged(client, changeMask);
- } catch (Exception e) {
- Log.e(DDMS, e);
- }
- }
- }
-
- /**
- * Returns the {@link DeviceMonitor} object.
- */
- DeviceMonitor getDeviceMonitor() {
- return mDeviceMonitor;
- }
-
- /**
- * Starts the adb host side server.
- * @return true if success
- */
- synchronized boolean startAdb() {
- if (mAdbOsLocation == null) {
- Log.e(ADB,
- "Cannot start adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
- return false;
- }
-
- Process proc;
- int status = -1;
-
- try {
- String[] command = new String[2];
- command[0] = mAdbOsLocation;
- command[1] = "start-server"; //$NON-NLS-1$
- Log.d(DDMS,
- String.format("Launching '%1$s %2$s' to ensure ADB is running.", //$NON-NLS-1$
- mAdbOsLocation, command[1]));
- ProcessBuilder processBuilder = new ProcessBuilder(command);
- if (DdmPreferences.getUseAdbHost()) {
- String adbHostValue = DdmPreferences.getAdbHostValue();
- if (adbHostValue != null && adbHostValue.length() > 0) {
- //TODO : check that the String is a valid IP address
- Map<String, String> env = processBuilder.environment();
- env.put("ADBHOST", adbHostValue);
- }
- }
- proc = processBuilder.start();
-
- ArrayList<String> errorOutput = new ArrayList<String>();
- ArrayList<String> stdOutput = new ArrayList<String>();
- status = grabProcessOutput(proc, errorOutput, stdOutput,
- false /* waitForReaders */);
-
- } catch (IOException ioe) {
- Log.d(DDMS, "Unable to run 'adb': " + ioe.getMessage()); //$NON-NLS-1$
- // we'll return false;
- } catch (InterruptedException ie) {
- Log.d(DDMS, "Unable to run 'adb': " + ie.getMessage()); //$NON-NLS-1$
- // we'll return false;
- }
-
- if (status != 0) {
- Log.w(DDMS,
- "'adb start-server' failed -- run manually if necessary"); //$NON-NLS-1$
- return false;
- }
-
- Log.d(DDMS, "'adb start-server' succeeded"); //$NON-NLS-1$
-
- return true;
- }
-
- /**
- * Stops the adb host side server.
- * @return true if success
- */
- private synchronized boolean stopAdb() {
- if (mAdbOsLocation == null) {
- Log.e(ADB,
- "Cannot stop adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
- return false;
- }
-
- Process proc;
- int status = -1;
-
- try {
- String[] command = new String[2];
- command[0] = mAdbOsLocation;
- command[1] = "kill-server"; //$NON-NLS-1$
- proc = Runtime.getRuntime().exec(command);
- status = proc.waitFor();
- }
- catch (IOException ioe) {
- // we'll return false;
- }
- catch (InterruptedException ie) {
- // we'll return false;
- }
-
- if (status != 0) {
- Log.w(DDMS,
- "'adb kill-server' failed -- run manually if necessary"); //$NON-NLS-1$
- return false;
- }
-
- Log.d(DDMS, "'adb kill-server' succeeded"); //$NON-NLS-1$
- return true;
- }
-
- /**
- * Get the stderr/stdout outputs of a process and return when the process is done.
- * Both <b>must</b> be read or the process will block on windows.
- * @param process The process to get the ouput from
- * @param errorOutput The array to store the stderr output. cannot be null.
- * @param stdOutput The array to store the stdout output. cannot be null.
- * @param displayStdOut If true this will display stdout as well
- * @param waitforReaders if true, this will wait for the reader threads.
- * @return the process return code.
- * @throws InterruptedException
- */
- private int grabProcessOutput(final Process process, final ArrayList<String> errorOutput,
- final ArrayList<String> stdOutput, boolean waitforReaders)
- throws InterruptedException {
- assert errorOutput != null;
- assert stdOutput != null;
- // read the lines as they come. if null is returned, it's
- // because the process finished
- Thread t1 = new Thread("") { //$NON-NLS-1$
- @Override
- public void run() {
- // create a buffer to read the stderr output
- InputStreamReader is = new InputStreamReader(process.getErrorStream());
- BufferedReader errReader = new BufferedReader(is);
-
- try {
- while (true) {
- String line = errReader.readLine();
- if (line != null) {
- Log.e(ADB, line);
- errorOutput.add(line);
- } else {
- break;
- }
- }
- } catch (IOException e) {
- // do nothing.
- }
- }
- };
-
- Thread t2 = new Thread("") { //$NON-NLS-1$
- @Override
- public void run() {
- InputStreamReader is = new InputStreamReader(process.getInputStream());
- BufferedReader outReader = new BufferedReader(is);
-
- try {
- while (true) {
- String line = outReader.readLine();
- if (line != null) {
- Log.d(ADB, line);
- stdOutput.add(line);
- } else {
- break;
- }
- }
- } catch (IOException e) {
- // do nothing.
- }
- }
- };
-
- t1.start();
- t2.start();
-
- // it looks like on windows process#waitFor() can return
- // before the thread have filled the arrays, so we wait for both threads and the
- // process itself.
- if (waitforReaders) {
- try {
- t1.join();
- } catch (InterruptedException e) {
- }
- try {
- t2.join();
- } catch (InterruptedException e) {
- }
- }
-
- // get the return code from the process
- return process.waitFor();
- }
-
- /**
- * Returns the singleton lock used by this class to protect any access to the listener.
- * <p/>
- * This includes adding/removing listeners, but also notifying listeners of new bridges,
- * devices, and clients.
- */
- static Object getLock() {
- return sLock;
- }
-
- /**
- * Instantiates sSocketAddr with the address of the host's adb process.
- */
- private static void initAdbSocketAddr() {
- try {
- int adb_port = determineAndValidateAdbPort();
- sHostAddr = InetAddress.getByName(ADB_HOST);
- sSocketAddr = new InetSocketAddress(sHostAddr, adb_port);
- } catch (UnknownHostException e) {
- // localhost should always be known.
- }
- }
-
- /**
- * Determines port where ADB is expected by looking at an env variable.
- * <p/>
- * The value for the environment variable ANDROID_ADB_SERVER_PORT is validated,
- * IllegalArgumentException is thrown on illegal values.
- * <p/>
- * @return The port number where the host's adb should be expected or started.
- * @throws IllegalArgumentException if ANDROID_ADB_SERVER_PORT has a non-numeric value.
- */
- private static int determineAndValidateAdbPort() {
- String adb_env_var;
- int result = ADB_PORT;
- try {
- adb_env_var = System.getenv(SERVER_PORT_ENV_VAR);
-
- if (adb_env_var != null) {
- adb_env_var = adb_env_var.trim();
- }
-
- if (adb_env_var != null && adb_env_var.length() > 0) {
- // C tools (adb, emulator) accept hex and octal port numbers, so need to accept
- // them too.
- result = Integer.decode(adb_env_var);
-
- if (result <= 0) {
- String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
- + ": must be >=0, got " //$NON-NLS-1$
- + System.getenv(SERVER_PORT_ENV_VAR);
- throw new IllegalArgumentException(errMsg);
- }
- }
- } catch (NumberFormatException nfEx) {
- String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
- + ": illegal value '" //$NON-NLS-1$
- + System.getenv(SERVER_PORT_ENV_VAR) + "'"; //$NON-NLS-1$
- throw new IllegalArgumentException(errMsg);
- } catch (SecurityException secEx) {
- // A security manager has been installed that doesn't allow access to env vars.
- // So an environment variable might have been set, but we can't tell.
- // Let's log a warning and continue with ADB's default port.
- // The issue is that adb would be started (by the forked process having access
- // to the env vars) on the desired port, but within this process, we can't figure out
- // what that port is. However, a security manager not granting access to env vars
- // but allowing to fork is a rare and interesting configuration, so the right
- // thing seems to be to continue using the default port, as forking is likely to
- // fail later on in the scenario of the security manager.
- Log.w(DDMS,
- "No access to env variables allowed by current security manager. " //$NON-NLS-1$
- + "If you've set ANDROID_ADB_SERVER_PORT: it's being ignored."); //$NON-NLS-1$
- }
- return result;
- }
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/BadPacketException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/BadPacketException.java
deleted file mode 100644
index 129b312..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/BadPacketException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/* //device/tools/ddms/libs/ddmlib/src/com/android/ddmlib/BadPacketException.java
-**
-** Copyright 2007, 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.ddmlib;
-
-/**
- * Thrown if the contents of a packet are bad.
- */
-@SuppressWarnings("serial")
-class BadPacketException extends RuntimeException {
- public BadPacketException()
- {
- super();
- }
-
- public BadPacketException(String msg)
- {
- super(msg);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CanceledException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CanceledException.java
deleted file mode 100644
index 84eda03..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CanceledException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib;
-
-/**
- * Abstract exception for exception that can be thrown when a user input cancels the action.
- * <p/>
- * {@link #wasCanceled()} returns whether the action was canceled because of user input.
- *
- */
-public abstract class CanceledException extends Exception {
- private static final long serialVersionUID = 1L;
-
- CanceledException(String message) {
- super(message);
- }
-
- CanceledException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Returns true if the action was canceled by user input.
- */
- public abstract boolean wasCanceled();
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ChunkHandler.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ChunkHandler.java
deleted file mode 100644
index 74fa318..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ChunkHandler.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.DebugPortManager.IDebugPortProvider;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * Subclass this with a class that handles one or more chunk types.
- */
-abstract class ChunkHandler {
-
- public static final int CHUNK_HEADER_LEN = 8; // 4-byte type, 4-byte len
- public static final ByteOrder CHUNK_ORDER = ByteOrder.BIG_ENDIAN;
-
- public static final int CHUNK_FAIL = type("FAIL");
-
- ChunkHandler() {}
-
- /**
- * Client is ready. The monitor thread calls this method on all
- * handlers when the client is determined to be DDM-aware (usually
- * after receiving a HELO response.)
- *
- * The handler can use this opportunity to initialize client-side
- * activity. Because there's a fair chance we'll want to send a
- * message to the client, this method can throw an IOException.
- */
- abstract void clientReady(Client client) throws IOException;
-
- /**
- * Client has gone away. Can be used to clean up any resources
- * associated with this client connection.
- */
- abstract void clientDisconnected(Client client);
-
- /**
- * Handle an incoming chunk. The data, of chunk type "type", begins
- * at the start of "data" and continues to data.limit().
- *
- * If "isReply" is set, then "msgId" will be the ID of the request
- * we sent to the client. Otherwise, it's the ID generated by the
- * client for this event. Note that it's possible to receive chunks
- * in reply packets for which we are not registered.
- *
- * The handler may not modify the contents of "data".
- */
- abstract void handleChunk(Client client, int type,
- ByteBuffer data, boolean isReply, int msgId);
-
- /**
- * Handle chunks not recognized by handlers. The handleChunk() method
- * in sub-classes should call this if the chunk type isn't recognized.
- */
- protected void handleUnknownChunk(Client client, int type,
- ByteBuffer data, boolean isReply, int msgId) {
- if (type == CHUNK_FAIL) {
- int errorCode, msgLen;
- String msg;
-
- errorCode = data.getInt();
- msgLen = data.getInt();
- msg = getString(data, msgLen);
- Log.w("ddms", "WARNING: failure code=" + errorCode + " msg=" + msg);
- } else {
- Log.w("ddms", "WARNING: received unknown chunk " + name(type)
- + ": len=" + data.limit() + ", reply=" + isReply
- + ", msgId=0x" + Integer.toHexString(msgId));
- }
- Log.w("ddms", " client " + client + ", handler " + this);
- }
-
-
- /**
- * Utility function to copy a String out of a ByteBuffer.
- *
- * This is here because multiple chunk handlers can make use of it,
- * and there's nowhere better to put it.
- */
- static String getString(ByteBuffer buf, int len) {
- char[] data = new char[len];
- for (int i = 0; i < len; i++)
- data[i] = buf.getChar();
- return new String(data);
- }
-
- /**
- * Utility function to copy a String into a ByteBuffer.
- */
- static void putString(ByteBuffer buf, String str) {
- int len = str.length();
- for (int i = 0; i < len; i++)
- buf.putChar(str.charAt(i));
- }
-
- /**
- * Convert a 4-character string to a 32-bit type.
- */
- static int type(String typeName) {
- int val = 0;
-
- if (typeName.length() != 4) {
- Log.e("ddms", "Type name must be 4 letter long");
- throw new RuntimeException("Type name must be 4 letter long");
- }
-
- for (int i = 0; i < 4; i++) {
- val <<= 8;
- val |= (byte) typeName.charAt(i);
- }
-
- return val;
- }
-
- /**
- * Convert an integer type to a 4-character string.
- */
- static String name(int type) {
- char[] ascii = new char[4];
-
- ascii[0] = (char) ((type >> 24) & 0xff);
- ascii[1] = (char) ((type >> 16) & 0xff);
- ascii[2] = (char) ((type >> 8) & 0xff);
- ascii[3] = (char) (type & 0xff);
-
- return new String(ascii);
- }
-
- /**
- * Allocate a ByteBuffer with enough space to hold the JDWP packet
- * header and one chunk header in addition to the demands of the
- * chunk being created.
- *
- * "maxChunkLen" indicates the size of the chunk contents only.
- */
- static ByteBuffer allocBuffer(int maxChunkLen) {
- ByteBuffer buf =
- ByteBuffer.allocate(JdwpPacket.JDWP_HEADER_LEN + 8 +maxChunkLen);
- buf.order(CHUNK_ORDER);
- return buf;
- }
-
- /**
- * Return the slice of the JDWP packet buffer that holds just the
- * chunk data.
- */
- static ByteBuffer getChunkDataBuf(ByteBuffer jdwpBuf) {
- ByteBuffer slice;
-
- assert jdwpBuf.position() == 0;
-
- jdwpBuf.position(JdwpPacket.JDWP_HEADER_LEN + CHUNK_HEADER_LEN);
- slice = jdwpBuf.slice();
- slice.order(CHUNK_ORDER);
- jdwpBuf.position(0);
-
- return slice;
- }
-
- /**
- * Write the chunk header at the start of the chunk.
- *
- * Pass in the byte buffer returned by JdwpPacket.getPayload().
- */
- static void finishChunkPacket(JdwpPacket packet, int type, int chunkLen) {
- ByteBuffer buf = packet.getPayload();
-
- buf.putInt(0x00, type);
- buf.putInt(0x04, chunkLen);
-
- packet.finishPacket(CHUNK_HEADER_LEN + chunkLen);
- }
-
- /**
- * Check that the client is opened with the proper debugger port for the
- * specified application name, and if not, reopen it.
- * @param client
- * @param uiThread
- * @param appName
- * @return
- */
- protected static Client checkDebuggerPortForAppName(Client client, String appName) {
- IDebugPortProvider provider = DebugPortManager.getProvider();
- if (provider != null) {
- Device device = client.getDeviceImpl();
- int newPort = provider.getPort(device, appName);
-
- if (newPort != IDebugPortProvider.NO_STATIC_PORT &&
- newPort != client.getDebuggerListenPort()) {
-
- AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
- if (bridge != null) {
- DeviceMonitor deviceMonitor = bridge.getDeviceMonitor();
- if (deviceMonitor != null) {
- deviceMonitor.addClientToDropAndReopen(client, newPort);
- client = null;
- }
- }
- }
- }
-
- return client;
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Client.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Client.java
deleted file mode 100644
index f927dd7..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Client.java
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.ClientData.MethodProfilingStatus;
-import com.android.ddmlib.DebugPortManager.IDebugPortProvider;
-import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
-
-import java.io.IOException;
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.SocketChannel;
-import java.util.HashMap;
-
-/**
- * This represents a single client, usually a DAlvik VM process.
- * <p/>This class gives access to basic client information, as well as methods to perform actions
- * on the client.
- * <p/>More detailed information, usually updated in real time, can be access through the
- * {@link ClientData} class. Each <code>Client</code> object has its own <code>ClientData</code>
- * accessed through {@link #getClientData()}.
- */
-public class Client {
-
- private static final int SERVER_PROTOCOL_VERSION = 1;
-
- /** Client change bit mask: application name change */
- public static final int CHANGE_NAME = 0x0001;
- /** Client change bit mask: debugger status change */
- public static final int CHANGE_DEBUGGER_STATUS = 0x0002;
- /** Client change bit mask: debugger port change */
- public static final int CHANGE_PORT = 0x0004;
- /** Client change bit mask: thread update flag change */
- public static final int CHANGE_THREAD_MODE = 0x0008;
- /** Client change bit mask: thread data updated */
- public static final int CHANGE_THREAD_DATA = 0x0010;
- /** Client change bit mask: heap update flag change */
- public static final int CHANGE_HEAP_MODE = 0x0020;
- /** Client change bit mask: head data updated */
- public static final int CHANGE_HEAP_DATA = 0x0040;
- /** Client change bit mask: native heap data updated */
- public static final int CHANGE_NATIVE_HEAP_DATA = 0x0080;
- /** Client change bit mask: thread stack trace updated */
- public static final int CHANGE_THREAD_STACKTRACE = 0x0100;
- /** Client change bit mask: allocation information updated */
- public static final int CHANGE_HEAP_ALLOCATIONS = 0x0200;
- /** Client change bit mask: allocation information updated */
- public static final int CHANGE_HEAP_ALLOCATION_STATUS = 0x0400;
- /** Client change bit mask: allocation information updated */
- public static final int CHANGE_METHOD_PROFILING_STATUS = 0x0800;
-
- /** Client change bit mask: combination of {@link Client#CHANGE_NAME},
- * {@link Client#CHANGE_DEBUGGER_STATUS}, and {@link Client#CHANGE_PORT}.
- */
- public static final int CHANGE_INFO = CHANGE_NAME | CHANGE_DEBUGGER_STATUS | CHANGE_PORT;
-
- private SocketChannel mChan;
-
- // debugger we're associated with, if any
- private Debugger mDebugger;
- private int mDebuggerListenPort;
-
- // list of IDs for requests we have sent to the client
- private HashMap<Integer,ChunkHandler> mOutstandingReqs;
-
- // chunk handlers stash state data in here
- private ClientData mClientData;
-
- // User interface state. Changing the value causes a message to be
- // sent to the client.
- private boolean mThreadUpdateEnabled;
- private boolean mHeapUpdateEnabled;
-
- /*
- * Read/write buffers. We can get large quantities of data from the
- * client, e.g. the response to a "give me the list of all known classes"
- * request from the debugger. Requests from the debugger, and from us,
- * are much smaller.
- *
- * Pass-through debugger traffic is sent without copying. "mWriteBuffer"
- * is only used for data generated within Client.
- */
- private static final int INITIAL_BUF_SIZE = 2*1024;
- private static final int MAX_BUF_SIZE = 200*1024*1024;
- private ByteBuffer mReadBuffer;
-
- private static final int WRITE_BUF_SIZE = 256;
- private ByteBuffer mWriteBuffer;
-
- private Device mDevice;
-
- private int mConnState;
-
- private static final int ST_INIT = 1;
- private static final int ST_NOT_JDWP = 2;
- private static final int ST_AWAIT_SHAKE = 10;
- private static final int ST_NEED_DDM_PKT = 11;
- private static final int ST_NOT_DDM = 12;
- private static final int ST_READY = 13;
- private static final int ST_ERROR = 20;
- private static final int ST_DISCONNECTED = 21;
-
-
- /**
- * Create an object for a new client connection.
- *
- * @param device the device this client belongs to
- * @param chan the connected {@link SocketChannel}.
- * @param pid the client pid.
- */
- Client(Device device, SocketChannel chan, int pid) {
- mDevice = device;
- mChan = chan;
-
- mReadBuffer = ByteBuffer.allocate(INITIAL_BUF_SIZE);
- mWriteBuffer = ByteBuffer.allocate(WRITE_BUF_SIZE);
-
- mOutstandingReqs = new HashMap<Integer,ChunkHandler>();
-
- mConnState = ST_INIT;
-
- mClientData = new ClientData(pid);
-
- mThreadUpdateEnabled = DdmPreferences.getInitialThreadUpdate();
- mHeapUpdateEnabled = DdmPreferences.getInitialHeapUpdate();
- }
-
- /**
- * Returns a string representation of the {@link Client} object.
- */
- @Override
- public String toString() {
- return "[Client pid: " + mClientData.getPid() + "]";
- }
-
- /**
- * Returns the {@link IDevice} on which this Client is running.
- */
- public IDevice getDevice() {
- return mDevice;
- }
-
- /** Returns the {@link Device} on which this Client is running.
- */
- Device getDeviceImpl() {
- return mDevice;
- }
-
- /**
- * Returns the debugger port for this client.
- */
- public int getDebuggerListenPort() {
- return mDebuggerListenPort;
- }
-
- /**
- * Returns <code>true</code> if the client VM is DDM-aware.
- *
- * Calling here is only allowed after the connection has been
- * established.
- */
- public boolean isDdmAware() {
- switch (mConnState) {
- case ST_INIT:
- case ST_NOT_JDWP:
- case ST_AWAIT_SHAKE:
- case ST_NEED_DDM_PKT:
- case ST_NOT_DDM:
- case ST_ERROR:
- case ST_DISCONNECTED:
- return false;
- case ST_READY:
- return true;
- default:
- assert false;
- return false;
- }
- }
-
- /**
- * Returns <code>true</code> if a debugger is currently attached to the client.
- */
- public boolean isDebuggerAttached() {
- return mDebugger.isDebuggerAttached();
- }
-
- /**
- * Return the Debugger object associated with this client.
- */
- Debugger getDebugger() {
- return mDebugger;
- }
-
- /**
- * Returns the {@link ClientData} object containing this client information.
- */
- public ClientData getClientData() {
- return mClientData;
- }
-
- /**
- * Forces the client to execute its garbage collector.
- */
- public void executeGarbageCollector() {
- try {
- HandleHeap.sendHPGC(this);
- } catch (IOException ioe) {
- Log.w("ddms", "Send of HPGC message failed");
- // ignore
- }
- }
-
- /**
- * Makes the VM dump an HPROF file
- */
- public void dumpHprof() {
- boolean canStream = mClientData.hasFeature(ClientData.FEATURE_HPROF_STREAMING);
- try {
- if (canStream) {
- HandleHeap.sendHPDS(this);
- } else {
- String file = "/sdcard/" + mClientData.getClientDescription().replaceAll(
- "\\:.*", "") + ".hprof";
- HandleHeap.sendHPDU(this, file);
- }
- } catch (IOException e) {
- Log.w("ddms", "Send of HPDU message failed");
- // ignore
- }
- }
-
- public void toggleMethodProfiling() {
- boolean canStream = mClientData.hasFeature(ClientData.FEATURE_PROFILING_STREAMING);
- try {
- if (mClientData.getMethodProfilingStatus() == MethodProfilingStatus.ON) {
- if (canStream) {
- HandleProfiling.sendMPSE(this);
- } else {
- HandleProfiling.sendMPRE(this);
- }
- } else {
- int bufferSize = DdmPreferences.getProfilerBufferSizeMb() * 1024 * 1024;
- if (canStream) {
- HandleProfiling.sendMPSS(this, bufferSize, 0 /*flags*/);
- } else {
- String file = "/sdcard/" +
- mClientData.getClientDescription().replaceAll("\\:.*", "") +
- DdmConstants.DOT_TRACE;
- HandleProfiling.sendMPRS(this, file, bufferSize, 0 /*flags*/);
- }
- }
- } catch (IOException e) {
- Log.w("ddms", "Toggle method profiling failed");
- // ignore
- }
- }
-
- public boolean startOpenGlTracing() {
- boolean canTraceOpenGl = mClientData.hasFeature(ClientData.FEATURE_OPENGL_TRACING);
- if (!canTraceOpenGl) {
- return false;
- }
-
- try {
- OpenGlTraceChunkHandler.sendStartGlTracing(this);
- return true;
- } catch (IOException e) {
- Log.w("ddms", "Start OpenGL Tracing failed");
- return false;
- }
- }
-
- public boolean stopOpenGlTracing() {
- boolean canTraceOpenGl = mClientData.hasFeature(ClientData.FEATURE_OPENGL_TRACING);
- if (!canTraceOpenGl) {
- return false;
- }
-
- try {
- OpenGlTraceChunkHandler.sendStopGlTracing(this);
- return true;
- } catch (IOException e) {
- Log.w("ddms", "Stop OpenGL Tracing failed");
- return false;
- }
- }
-
- /**
- * Sends a request to the VM to send the enable status of the method profiling.
- * This is asynchronous.
- * <p/>The allocation status can be accessed by {@link ClientData#getAllocationStatus()}.
- * The notification that the new status is available will be received through
- * {@link IClientChangeListener#clientChanged(Client, int)} with a <code>changeMask</code>
- * containing the mask {@link #CHANGE_HEAP_ALLOCATION_STATUS}.
- */
- public void requestMethodProfilingStatus() {
- try {
- HandleHeap.sendREAQ(this);
- } catch (IOException e) {
- Log.e("ddmlib", e);
- }
- }
-
-
- /**
- * Enables or disables the thread update.
- * <p/>If <code>true</code> the VM will be able to send thread information. Thread information
- * must be requested with {@link #requestThreadUpdate()}.
- * @param enabled the enable flag.
- */
- public void setThreadUpdateEnabled(boolean enabled) {
- mThreadUpdateEnabled = enabled;
- if (enabled == false) {
- mClientData.clearThreads();
- }
-
- try {
- HandleThread.sendTHEN(this, enabled);
- } catch (IOException ioe) {
- // ignore it here; client will clean up shortly
- ioe.printStackTrace();
- }
-
- update(CHANGE_THREAD_MODE);
- }
-
- /**
- * Returns whether the thread update is enabled.
- */
- public boolean isThreadUpdateEnabled() {
- return mThreadUpdateEnabled;
- }
-
- /**
- * Sends a thread update request. This is asynchronous.
- * <p/>The thread info can be accessed by {@link ClientData#getThreads()}. The notification
- * that the new data is available will be received through
- * {@link IClientChangeListener#clientChanged(Client, int)} with a <code>changeMask</code>
- * containing the mask {@link #CHANGE_THREAD_DATA}.
- */
- public void requestThreadUpdate() {
- HandleThread.requestThreadUpdate(this);
- }
-
- /**
- * Sends a thread stack trace update request. This is asynchronous.
- * <p/>The thread info can be accessed by {@link ClientData#getThreads()} and
- * {@link ThreadInfo#getStackTrace()}.
- * <p/>The notification that the new data is available
- * will be received through {@link IClientChangeListener#clientChanged(Client, int)}
- * with a <code>changeMask</code> containing the mask {@link #CHANGE_THREAD_STACKTRACE}.
- */
- public void requestThreadStackTrace(int threadId) {
- HandleThread.requestThreadStackCallRefresh(this, threadId);
- }
-
- /**
- * Enables or disables the heap update.
- * <p/>If <code>true</code>, any GC will cause the client to send its heap information.
- * <p/>The heap information can be accessed by {@link ClientData#getVmHeapData()}.
- * <p/>The notification that the new data is available
- * will be received through {@link IClientChangeListener#clientChanged(Client, int)}
- * with a <code>changeMask</code> containing the value {@link #CHANGE_HEAP_DATA}.
- * @param enabled the enable flag
- */
- public void setHeapUpdateEnabled(boolean enabled) {
- mHeapUpdateEnabled = enabled;
-
- try {
- HandleHeap.sendHPIF(this,
- enabled ? HandleHeap.HPIF_WHEN_EVERY_GC : HandleHeap.HPIF_WHEN_NEVER);
-
- HandleHeap.sendHPSG(this,
- enabled ? HandleHeap.WHEN_GC : HandleHeap.WHEN_DISABLE,
- HandleHeap.WHAT_MERGE);
- } catch (IOException ioe) {
- // ignore it here; client will clean up shortly
- }
-
- update(CHANGE_HEAP_MODE);
- }
-
- /**
- * Returns whether the heap update is enabled.
- * @see #setHeapUpdateEnabled(boolean)
- */
- public boolean isHeapUpdateEnabled() {
- return mHeapUpdateEnabled;
- }
-
- /**
- * Sends a native heap update request. this is asynchronous.
- * <p/>The native heap info can be accessed by {@link ClientData#getNativeAllocationList()}.
- * The notification that the new data is available will be received through
- * {@link IClientChangeListener#clientChanged(Client, int)} with a <code>changeMask</code>
- * containing the mask {@link #CHANGE_NATIVE_HEAP_DATA}.
- */
- public boolean requestNativeHeapInformation() {
- try {
- HandleNativeHeap.sendNHGT(this);
- return true;
- } catch (IOException e) {
- Log.e("ddmlib", e);
- }
-
- return false;
- }
-
- /**
- * Enables or disables the Allocation tracker for this client.
- * <p/>If enabled, the VM will start tracking allocation informations. A call to
- * {@link #requestAllocationDetails()} will make the VM sends the information about all the
- * allocations that happened between the enabling and the request.
- * @param enable
- * @see #requestAllocationDetails()
- */
- public void enableAllocationTracker(boolean enable) {
- try {
- HandleHeap.sendREAE(this, enable);
- } catch (IOException e) {
- Log.e("ddmlib", e);
- }
- }
-
- /**
- * Sends a request to the VM to send the enable status of the allocation tracking.
- * This is asynchronous.
- * <p/>The allocation status can be accessed by {@link ClientData#getAllocationStatus()}.
- * The notification that the new status is available will be received through
- * {@link IClientChangeListener#clientChanged(Client, int)} with a <code>changeMask</code>
- * containing the mask {@link #CHANGE_HEAP_ALLOCATION_STATUS}.
- */
- public void requestAllocationStatus() {
- try {
- HandleHeap.sendREAQ(this);
- } catch (IOException e) {
- Log.e("ddmlib", e);
- }
- }
-
- /**
- * Sends a request to the VM to send the information about all the allocations that have
- * happened since the call to {@link #enableAllocationTracker(boolean)} with <var>enable</var>
- * set to <code>null</code>. This is asynchronous.
- * <p/>The allocation information can be accessed by {@link ClientData#getAllocations()}.
- * The notification that the new data is available will be received through
- * {@link IClientChangeListener#clientChanged(Client, int)} with a <code>changeMask</code>
- * containing the mask {@link #CHANGE_HEAP_ALLOCATIONS}.
- */
- public void requestAllocationDetails() {
- try {
- HandleHeap.sendREAL(this);
- } catch (IOException e) {
- Log.e("ddmlib", e);
- }
- }
-
- /**
- * Sends a kill message to the VM.
- */
- public void kill() {
- try {
- HandleExit.sendEXIT(this, 1);
- } catch (IOException ioe) {
- Log.w("ddms", "Send of EXIT message failed");
- // ignore
- }
- }
-
- /**
- * Registers the client with a Selector.
- */
- void register(Selector sel) throws IOException {
- if (mChan != null) {
- mChan.register(sel, SelectionKey.OP_READ, this);
- }
- }
-
- /**
- * Sets the client to accept debugger connection on the "selected debugger port".
- *
- * @see AndroidDebugBridge#setSelectedClient(Client)
- * @see DdmPreferences#setSelectedDebugPort(int)
- */
- public void setAsSelectedClient() {
- MonitorThread monitorThread = MonitorThread.getInstance();
- if (monitorThread != null) {
- monitorThread.setSelectedClient(this);
- }
- }
-
- /**
- * Returns whether this client is the current selected client, accepting debugger connection
- * on the "selected debugger port".
- *
- * @see #setAsSelectedClient()
- * @see AndroidDebugBridge#setSelectedClient(Client)
- * @see DdmPreferences#setSelectedDebugPort(int)
- */
- public boolean isSelectedClient() {
- MonitorThread monitorThread = MonitorThread.getInstance();
- if (monitorThread != null) {
- return monitorThread.getSelectedClient() == this;
- }
-
- return false;
- }
-
- /**
- * Tell the client to open a server socket channel and listen for
- * connections on the specified port.
- */
- void listenForDebugger(int listenPort) throws IOException {
- mDebuggerListenPort = listenPort;
- mDebugger = new Debugger(this, listenPort);
- }
-
- /**
- * Initiate the JDWP handshake.
- *
- * On failure, closes the socket and returns false.
- */
- boolean sendHandshake() {
- assert mWriteBuffer.position() == 0;
-
- try {
- // assume write buffer can hold 14 bytes
- JdwpPacket.putHandshake(mWriteBuffer);
- int expectedLen = mWriteBuffer.position();
- mWriteBuffer.flip();
- if (mChan.write(mWriteBuffer) != expectedLen)
- throw new IOException("partial handshake write");
- }
- catch (IOException ioe) {
- Log.e("ddms-client", "IO error during handshake: " + ioe.getMessage());
- mConnState = ST_ERROR;
- close(true /* notify */);
- return false;
- }
- finally {
- mWriteBuffer.clear();
- }
-
- mConnState = ST_AWAIT_SHAKE;
-
- return true;
- }
-
-
- /**
- * Send a non-DDM packet to the client.
- *
- * Equivalent to sendAndConsume(packet, null).
- */
- void sendAndConsume(JdwpPacket packet) throws IOException {
- sendAndConsume(packet, null);
- }
-
- /**
- * Send a DDM packet to the client.
- *
- * Ideally, we can do this with a single channel write. If that doesn't
- * happen, we have to prevent anybody else from writing to the channel
- * until this packet completes, so we synchronize on the channel.
- *
- * Another goal is to avoid unnecessary buffer copies, so we write
- * directly out of the JdwpPacket's ByteBuffer.
- */
- void sendAndConsume(JdwpPacket packet, ChunkHandler replyHandler)
- throws IOException {
-
- if (mChan == null) {
- // can happen for e.g. THST packets
- Log.v("ddms", "Not sending packet -- client is closed");
- return;
- }
-
- if (replyHandler != null) {
- /*
- * Add the ID to the list of outstanding requests. We have to do
- * this before sending the packet, in case the response comes back
- * before our thread returns from the packet-send function.
- */
- addRequestId(packet.getId(), replyHandler);
- }
-
- synchronized (mChan) {
- try {
- packet.writeAndConsume(mChan);
- }
- catch (IOException ioe) {
- removeRequestId(packet.getId());
- throw ioe;
- }
- }
- }
-
- /**
- * Forward the packet to the debugger (if still connected to one).
- *
- * Consumes the packet.
- */
- void forwardPacketToDebugger(JdwpPacket packet)
- throws IOException {
-
- Debugger dbg = mDebugger;
-
- if (dbg == null) {
- Log.d("ddms", "Discarding packet");
- packet.consume();
- } else {
- dbg.sendAndConsume(packet);
- }
- }
-
- /**
- * Read data from our channel.
- *
- * This is called when data is known to be available, and we don't yet
- * have a full packet in the buffer. If the buffer is at capacity,
- * expand it.
- */
- void read()
- throws IOException, BufferOverflowException {
-
- int count;
-
- if (mReadBuffer.position() == mReadBuffer.capacity()) {
- if (mReadBuffer.capacity() * 2 > MAX_BUF_SIZE) {
- Log.e("ddms", "Exceeded MAX_BUF_SIZE!");
- throw new BufferOverflowException();
- }
- Log.d("ddms", "Expanding read buffer to "
- + mReadBuffer.capacity() * 2);
-
- ByteBuffer newBuffer = ByteBuffer.allocate(mReadBuffer.capacity() * 2);
-
- // copy entire buffer to new buffer
- mReadBuffer.position(0);
- newBuffer.put(mReadBuffer); // leaves "position" at end of copied
-
- mReadBuffer = newBuffer;
- }
-
- count = mChan.read(mReadBuffer);
- if (count < 0)
- throw new IOException("read failed");
-
- if (Log.Config.LOGV) Log.v("ddms", "Read " + count + " bytes from " + this);
- //Log.hexDump("ddms", Log.DEBUG, mReadBuffer.array(),
- // mReadBuffer.arrayOffset(), mReadBuffer.position());
- }
-
- /**
- * Return information for the first full JDWP packet in the buffer.
- *
- * If we don't yet have a full packet, return null.
- *
- * If we haven't yet received the JDWP handshake, we watch for it here
- * and consume it without admitting to have done so. Upon receipt
- * we send out the "HELO" message, which is why this can throw an
- * IOException.
- */
- JdwpPacket getJdwpPacket() throws IOException {
-
- /*
- * On entry, the data starts at offset 0 and ends at "position".
- * "limit" is set to the buffer capacity.
- */
- if (mConnState == ST_AWAIT_SHAKE) {
- /*
- * The first thing we get from the client is a response to our
- * handshake. It doesn't look like a packet, so we have to
- * handle it specially.
- */
- int result;
-
- result = JdwpPacket.findHandshake(mReadBuffer);
- //Log.v("ddms", "findHand: " + result);
- switch (result) {
- case JdwpPacket.HANDSHAKE_GOOD:
- Log.d("ddms",
- "Good handshake from client, sending HELO to " + mClientData.getPid());
- JdwpPacket.consumeHandshake(mReadBuffer);
- mConnState = ST_NEED_DDM_PKT;
- HandleHello.sendHelloCommands(this, SERVER_PROTOCOL_VERSION);
- // see if we have another packet in the buffer
- return getJdwpPacket();
- case JdwpPacket.HANDSHAKE_BAD:
- Log.d("ddms", "Bad handshake from client");
- if (MonitorThread.getInstance().getRetryOnBadHandshake()) {
- // we should drop the client, but also attempt to reopen it.
- // This is done by the DeviceMonitor.
- mDevice.getMonitor().addClientToDropAndReopen(this,
- IDebugPortProvider.NO_STATIC_PORT);
- } else {
- // mark it as bad, close the socket, and don't retry
- mConnState = ST_NOT_JDWP;
- close(true /* notify */);
- }
- break;
- case JdwpPacket.HANDSHAKE_NOTYET:
- Log.d("ddms", "No handshake from client yet.");
- break;
- default:
- Log.e("ddms", "Unknown packet while waiting for client handshake");
- }
- return null;
- } else if (mConnState == ST_NEED_DDM_PKT ||
- mConnState == ST_NOT_DDM ||
- mConnState == ST_READY) {
- /*
- * Normal packet traffic.
- */
- if (mReadBuffer.position() != 0) {
- if (Log.Config.LOGV) Log.v("ddms",
- "Checking " + mReadBuffer.position() + " bytes");
- }
- return JdwpPacket.findPacket(mReadBuffer);
- } else {
- /*
- * Not expecting data when in this state.
- */
- Log.e("ddms", "Receiving data in state = " + mConnState);
- }
-
- return null;
- }
-
- /*
- * Add the specified ID to the list of request IDs for which we await
- * a response.
- */
- private void addRequestId(int id, ChunkHandler handler) {
- synchronized (mOutstandingReqs) {
- if (Log.Config.LOGV) Log.v("ddms",
- "Adding req 0x" + Integer.toHexString(id) +" to set");
- mOutstandingReqs.put(id, handler);
- }
- }
-
- /*
- * Remove the specified ID from the list, if present.
- */
- void removeRequestId(int id) {
- synchronized (mOutstandingReqs) {
- if (Log.Config.LOGV) Log.v("ddms",
- "Removing req 0x" + Integer.toHexString(id) + " from set");
- mOutstandingReqs.remove(id);
- }
-
- //Log.w("ddms", "Request " + Integer.toHexString(id)
- // + " could not be removed from " + this);
- }
-
- /**
- * Determine whether this is a response to a request we sent earlier.
- * If so, return the ChunkHandler responsible.
- */
- ChunkHandler isResponseToUs(int id) {
-
- synchronized (mOutstandingReqs) {
- ChunkHandler handler = mOutstandingReqs.get(id);
- if (handler != null) {
- if (Log.Config.LOGV) Log.v("ddms",
- "Found 0x" + Integer.toHexString(id)
- + " in request set - " + handler);
- return handler;
- }
- }
-
- return null;
- }
-
- /**
- * An earlier request resulted in a failure. This is the expected
- * response to a HELO message when talking to a non-DDM client.
- */
- void packetFailed(JdwpPacket reply) {
- if (mConnState == ST_NEED_DDM_PKT) {
- Log.d("ddms", "Marking " + this + " as non-DDM client");
- mConnState = ST_NOT_DDM;
- } else if (mConnState != ST_NOT_DDM) {
- Log.w("ddms", "WEIRD: got JDWP failure packet on DDM req");
- }
- }
-
- /**
- * The MonitorThread calls this when it sees a DDM request or reply.
- * If we haven't seen a DDM packet before, we advance the state to
- * ST_READY and return "false". Otherwise, just return true.
- *
- * The idea is to let the MonitorThread know when we first see a DDM
- * packet, so we can send a broadcast to the handlers when a client
- * connection is made. This method is synchronized so that we only
- * send the broadcast once.
- */
- synchronized boolean ddmSeen() {
- if (mConnState == ST_NEED_DDM_PKT) {
- mConnState = ST_READY;
- return false;
- } else if (mConnState != ST_READY) {
- Log.w("ddms", "WEIRD: in ddmSeen with state=" + mConnState);
- }
- return true;
- }
-
- /**
- * Close the client socket channel. If there is a debugger associated
- * with us, close that too.
- *
- * Closing a channel automatically unregisters it from the selector.
- * However, we have to iterate through the selector loop before it
- * actually lets them go and allows the file descriptors to close.
- * The caller is expected to manage that.
- * @param notify Whether or not to notify the listeners of a change.
- */
- void close(boolean notify) {
- Log.d("ddms", "Closing " + this.toString());
-
- mOutstandingReqs.clear();
-
- try {
- if (mChan != null) {
- mChan.close();
- mChan = null;
- }
-
- if (mDebugger != null) {
- mDebugger.close();
- mDebugger = null;
- }
- }
- catch (IOException ioe) {
- Log.w("ddms", "failed to close " + this);
- // swallow it -- not much else to do
- }
-
- mDevice.removeClient(this, notify);
- }
-
- /**
- * Returns whether this {@link Client} has a valid connection to the application VM.
- */
- public boolean isValid() {
- return mChan != null;
- }
-
- void update(int changeMask) {
- mDevice.update(this, changeMask);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ClientData.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ClientData.java
deleted file mode 100644
index f490c1a..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ClientData.java
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.HeapSegment.HeapSegmentElement;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-
-/**
- * Contains the data of a {@link Client}.
- */
-public class ClientData {
- /* This is a place to stash data associated with a Client, such as thread
- * states or heap data. ClientData maps 1:1 to Client, but it's a little
- * cleaner if we separate the data out.
- *
- * Message handlers are welcome to stash arbitrary data here.
- *
- * IMPORTANT: The data here is written by HandleFoo methods and read by
- * FooPanel methods, which run in different threads. All non-trivial
- * access should be synchronized against the ClientData object.
- */
-
-
- /** Temporary name of VM to be ignored. */
- private final static String PRE_INITIALIZED = "<pre-initialized>"; //$NON-NLS-1$
-
- public static enum DebuggerStatus {
- /** Debugger connection status: not waiting on one, not connected to one, but accepting
- * new connections. This is the default value. */
- DEFAULT,
- /**
- * Debugger connection status: the application's VM is paused, waiting for a debugger to
- * connect to it before resuming. */
- WAITING,
- /** Debugger connection status : Debugger is connected */
- ATTACHED,
- /** Debugger connection status: The listening port for debugger connection failed to listen.
- * No debugger will be able to connect. */
- ERROR;
- }
-
- public static enum AllocationTrackingStatus {
- /**
- * Allocation tracking status: unknown.
- * <p/>This happens right after a {@link Client} is discovered
- * by the {@link AndroidDebugBridge}, and before the {@link Client} answered the query
- * regarding its allocation tracking status.
- * @see Client#requestAllocationStatus()
- */
- UNKNOWN,
- /** Allocation tracking status: the {@link Client} is not tracking allocations. */
- OFF,
- /** Allocation tracking status: the {@link Client} is tracking allocations. */
- ON;
- }
-
- public static enum MethodProfilingStatus {
- /**
- * Method profiling status: unknown.
- * <p/>This happens right after a {@link Client} is discovered
- * by the {@link AndroidDebugBridge}, and before the {@link Client} answered the query
- * regarding its method profiling status.
- * @see Client#requestMethodProfilingStatus()
- */
- UNKNOWN,
- /** Method profiling status: the {@link Client} is not profiling method calls. */
- OFF,
- /** Method profiling status: the {@link Client} is profiling method calls. */
- ON;
- }
-
- /**
- * Name of the value representing the max size of the heap, in the {@link Map} returned by
- * {@link #getVmHeapInfo(int)}
- */
- public final static String HEAP_MAX_SIZE_BYTES = "maxSizeInBytes"; //$NON-NLS-1$
- /**
- * Name of the value representing the size of the heap, in the {@link Map} returned by
- * {@link #getVmHeapInfo(int)}
- */
- public final static String HEAP_SIZE_BYTES = "sizeInBytes"; //$NON-NLS-1$
- /**
- * Name of the value representing the number of allocated bytes of the heap, in the
- * {@link Map} returned by {@link #getVmHeapInfo(int)}
- */
- public final static String HEAP_BYTES_ALLOCATED = "bytesAllocated"; //$NON-NLS-1$
- /**
- * Name of the value representing the number of objects in the heap, in the {@link Map}
- * returned by {@link #getVmHeapInfo(int)}
- */
- public final static String HEAP_OBJECTS_ALLOCATED = "objectsAllocated"; //$NON-NLS-1$
-
- /**
- * String for feature enabling starting/stopping method profiling
- * @see #hasFeature(String)
- */
- public final static String FEATURE_PROFILING = "method-trace-profiling"; //$NON-NLS-1$
-
- /**
- * String for feature enabling direct streaming of method profiling data
- * @see #hasFeature(String)
- */
- public final static String FEATURE_PROFILING_STREAMING = "method-trace-profiling-streaming"; //$NON-NLS-1$
-
- /**
- * String for feature indicating support for tracing OpenGL calls.
- * @see #hasFeature(String)
- */
- public final static String FEATURE_OPENGL_TRACING = "opengl-tracing"; //$NON-NLS-1$
-
- /**
- * String for feature allowing to dump hprof files
- * @see #hasFeature(String)
- */
- public final static String FEATURE_HPROF = "hprof-heap-dump"; //$NON-NLS-1$
-
- /**
- * String for feature allowing direct streaming of hprof dumps
- * @see #hasFeature(String)
- */
- public final static String FEATURE_HPROF_STREAMING = "hprof-heap-dump-streaming"; //$NON-NLS-1$
-
- private static IHprofDumpHandler sHprofDumpHandler;
- private static IMethodProfilingHandler sMethodProfilingHandler;
-
- // is this a DDM-aware client?
- private boolean mIsDdmAware;
-
- // the client's process ID
- private final int mPid;
-
- // Java VM identification string
- private String mVmIdentifier;
-
- // client's self-description
- private String mClientDescription;
-
- // client's user id (on device in a multi user environment)
- private int mUserId;
-
- // client's user id is valid
- private boolean mValidUserId;
-
- // how interested are we in a debugger?
- private DebuggerStatus mDebuggerInterest;
-
- // List of supported features by the client.
- private final HashSet<String> mFeatures = new HashSet<String>();
-
- // Thread tracking (THCR, THDE).
- private TreeMap<Integer,ThreadInfo> mThreadMap;
-
- /** VM Heap data */
- private final HeapData mHeapData = new HeapData();
- /** Native Heap data */
- private final HeapData mNativeHeapData = new HeapData();
-
- private HashMap<Integer, HashMap<String, Long>> mHeapInfoMap =
- new HashMap<Integer, HashMap<String, Long>>();
-
-
- /** library map info. Stored here since the backtrace data
- * is computed on a need to display basis.
- */
- private ArrayList<NativeLibraryMapInfo> mNativeLibMapInfo =
- new ArrayList<NativeLibraryMapInfo>();
-
- /** Native Alloc info list */
- private ArrayList<NativeAllocationInfo> mNativeAllocationList =
- new ArrayList<NativeAllocationInfo>();
- private int mNativeTotalMemory;
-
- private AllocationInfo[] mAllocations;
- private AllocationTrackingStatus mAllocationStatus = AllocationTrackingStatus.UNKNOWN;
-
- private String mPendingHprofDump;
-
- private MethodProfilingStatus mProfilingStatus = MethodProfilingStatus.UNKNOWN;
- private String mPendingMethodProfiling;
-
- /**
- * Heap Information.
- * <p/>The heap is composed of several {@link HeapSegment} objects.
- * <p/>A call to {@link #isHeapDataComplete()} will indicate if the segments (available through
- * {@link #getHeapSegments()}) represent the full heap.
- */
- public static class HeapData {
- private TreeSet<HeapSegment> mHeapSegments = new TreeSet<HeapSegment>();
- private boolean mHeapDataComplete = false;
- private byte[] mProcessedHeapData;
- private Map<Integer, ArrayList<HeapSegmentElement>> mProcessedHeapMap;
-
- /**
- * Abandon the current list of heap segments.
- */
- public synchronized void clearHeapData() {
- /* Abandon the old segments instead of just calling .clear().
- * This lets the user hold onto the old set if it wants to.
- */
- mHeapSegments = new TreeSet<HeapSegment>();
- mHeapDataComplete = false;
- }
-
- /**
- * Add raw HPSG chunk data to the list of heap segments.
- *
- * @param data The raw data from an HPSG chunk.
- */
- synchronized void addHeapData(ByteBuffer data) {
- HeapSegment hs;
-
- if (mHeapDataComplete) {
- clearHeapData();
- }
-
- try {
- hs = new HeapSegment(data);
- } catch (BufferUnderflowException e) {
- System.err.println("Discarding short HPSG data (length " + data.limit() + ")");
- return;
- }
-
- mHeapSegments.add(hs);
- }
-
- /**
- * Called when all heap data has arrived.
- */
- synchronized void sealHeapData() {
- mHeapDataComplete = true;
- }
-
- /**
- * Returns whether the heap data has been sealed.
- */
- public boolean isHeapDataComplete() {
- return mHeapDataComplete;
- }
-
- /**
- * Get the collected heap data, if sealed.
- *
- * @return The list of heap segments if the heap data has been sealed, or null if it hasn't.
- */
- public Collection<HeapSegment> getHeapSegments() {
- if (isHeapDataComplete()) {
- return mHeapSegments;
- }
- return null;
- }
-
- /**
- * Sets the processed heap data.
- *
- * @param heapData The new heap data (can be null)
- */
- public void setProcessedHeapData(byte[] heapData) {
- mProcessedHeapData = heapData;
- }
-
- /**
- * Get the processed heap data, if present.
- *
- * @return the processed heap data, or null.
- */
- public byte[] getProcessedHeapData() {
- return mProcessedHeapData;
- }
-
- public void setProcessedHeapMap(Map<Integer, ArrayList<HeapSegmentElement>> heapMap) {
- mProcessedHeapMap = heapMap;
- }
-
- public Map<Integer, ArrayList<HeapSegmentElement>> getProcessedHeapMap() {
- return mProcessedHeapMap;
- }
- }
-
- /**
- * Handlers able to act on HPROF dumps.
- */
- public interface IHprofDumpHandler {
- /**
- * Called when a HPROF dump succeeded.
- * @param remoteFilePath the device-side path of the HPROF file.
- * @param client the client for which the HPROF file was.
- */
- void onSuccess(String remoteFilePath, Client client);
-
- /**
- * Called when a HPROF dump was successful.
- * @param data the data containing the HPROF file, streamed from the VM
- * @param client the client that was profiled.
- */
- void onSuccess(byte[] data, Client client);
-
- /**
- * Called when a hprof dump failed to end on the VM side
- * @param client the client that was profiled.
- * @param message an optional (<code>null<code> ok) error message to be displayed.
- */
- void onEndFailure(Client client, String message);
- }
-
- /**
- * Handlers able to act on Method profiling info
- */
- public interface IMethodProfilingHandler {
- /**
- * Called when a method tracing was successful.
- * @param remoteFilePath the device-side path of the trace file.
- * @param client the client that was profiled.
- */
- void onSuccess(String remoteFilePath, Client client);
-
- /**
- * Called when a method tracing was successful.
- * @param data the data containing the trace file, streamed from the VM
- * @param client the client that was profiled.
- */
- void onSuccess(byte[] data, Client client);
-
- /**
- * Called when method tracing failed to start
- * @param client the client that was profiled.
- * @param message an optional (<code>null<code> ok) error message to be displayed.
- */
- void onStartFailure(Client client, String message);
-
- /**
- * Called when method tracing failed to end on the VM side
- * @param client the client that was profiled.
- * @param message an optional (<code>null<code> ok) error message to be displayed.
- */
- void onEndFailure(Client client, String message);
- }
-
- /**
- * Sets the handler to receive notifications when an HPROF dump succeeded or failed.
- */
- public static void setHprofDumpHandler(IHprofDumpHandler handler) {
- sHprofDumpHandler = handler;
- }
-
- static IHprofDumpHandler getHprofDumpHandler() {
- return sHprofDumpHandler;
- }
-
- /**
- * Sets the handler to receive notifications when an HPROF dump succeeded or failed.
- */
- public static void setMethodProfilingHandler(IMethodProfilingHandler handler) {
- sMethodProfilingHandler = handler;
- }
-
- static IMethodProfilingHandler getMethodProfilingHandler() {
- return sMethodProfilingHandler;
- }
-
- /**
- * Generic constructor.
- */
- ClientData(int pid) {
- mPid = pid;
-
- mDebuggerInterest = DebuggerStatus.DEFAULT;
- mThreadMap = new TreeMap<Integer,ThreadInfo>();
- }
-
- /**
- * Returns whether the process is DDM-aware.
- */
- public boolean isDdmAware() {
- return mIsDdmAware;
- }
-
- /**
- * Sets DDM-aware status.
- */
- void isDdmAware(boolean aware) {
- mIsDdmAware = aware;
- }
-
- /**
- * Returns the process ID.
- */
- public int getPid() {
- return mPid;
- }
-
- /**
- * Returns the Client's VM identifier.
- */
- public String getVmIdentifier() {
- return mVmIdentifier;
- }
-
- /**
- * Sets VM identifier.
- */
- void setVmIdentifier(String ident) {
- mVmIdentifier = ident;
- }
-
- /**
- * Returns the client description.
- * <p/>This is generally the name of the package defined in the
- * <code>AndroidManifest.xml</code>.
- *
- * @return the client description or <code>null</code> if not the description was not yet
- * sent by the client.
- */
- public String getClientDescription() {
- return mClientDescription;
- }
-
- /**
- * Returns the client's user id.
- * @return user id if set, -1 otherwise
- */
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Returns true if the user id of this client was set. Only devices that support multiple
- * users will actually return the user id to ddms. For other/older devices, this will not
- * be set.
- */
- public boolean isValidUserId() {
- return mValidUserId;
- }
-
- /**
- * Sets client description.
- *
- * There may be a race between HELO and APNM. Rather than try
- * to enforce ordering on the device, we just don't allow an empty
- * name to replace a specified one.
- */
- void setClientDescription(String description) {
- if (mClientDescription == null && description.length() > 0) {
- /*
- * The application VM is first named <pre-initialized> before being assigned
- * its real name.
- * Depending on the timing, we can get an APNM chunk setting this name before
- * another one setting the final actual name. So if we get a SetClientDescription
- * with this value we ignore it.
- */
- if (PRE_INITIALIZED.equals(description) == false) {
- mClientDescription = description;
- }
- }
- }
-
- void setUserId(int id) {
- mUserId = id;
- mValidUserId = true;
- }
-
- /**
- * Returns the debugger connection status.
- */
- public DebuggerStatus getDebuggerConnectionStatus() {
- return mDebuggerInterest;
- }
-
- /**
- * Sets debugger connection status.
- */
- void setDebuggerConnectionStatus(DebuggerStatus status) {
- mDebuggerInterest = status;
- }
-
- /**
- * Sets the current heap info values for the specified heap.
- *
- * @param heapId The heap whose info to update
- * @param sizeInBytes The size of the heap, in bytes
- * @param bytesAllocated The number of bytes currently allocated in the heap
- * @param objectsAllocated The number of objects currently allocated in
- * the heap
- */
- // TODO: keep track of timestamp, reason
- synchronized void setHeapInfo(int heapId, long maxSizeInBytes,
- long sizeInBytes, long bytesAllocated, long objectsAllocated) {
- HashMap<String, Long> heapInfo = new HashMap<String, Long>();
- heapInfo.put(HEAP_MAX_SIZE_BYTES, maxSizeInBytes);
- heapInfo.put(HEAP_SIZE_BYTES, sizeInBytes);
- heapInfo.put(HEAP_BYTES_ALLOCATED, bytesAllocated);
- heapInfo.put(HEAP_OBJECTS_ALLOCATED, objectsAllocated);
- mHeapInfoMap.put(heapId, heapInfo);
- }
-
- /**
- * Returns the {@link HeapData} object for the VM.
- */
- public HeapData getVmHeapData() {
- return mHeapData;
- }
-
- /**
- * Returns the {@link HeapData} object for the native code.
- */
- HeapData getNativeHeapData() {
- return mNativeHeapData;
- }
-
- /**
- * Returns an iterator over the list of known VM heap ids.
- * <p/>
- * The caller must synchronize on the {@link ClientData} object while iterating.
- *
- * @return an iterator over the list of heap ids
- */
- public synchronized Iterator<Integer> getVmHeapIds() {
- return mHeapInfoMap.keySet().iterator();
- }
-
- /**
- * Returns the most-recent info values for the specified VM heap.
- *
- * @param heapId The heap whose info should be returned
- * @return a map containing the info values for the specified heap.
- * Returns <code>null</code> if the heap ID is unknown.
- */
- public synchronized Map<String, Long> getVmHeapInfo(int heapId) {
- return mHeapInfoMap.get(heapId);
- }
-
- /**
- * Adds a new thread to the list.
- */
- synchronized void addThread(int threadId, String threadName) {
- ThreadInfo attr = new ThreadInfo(threadId, threadName);
- mThreadMap.put(threadId, attr);
- }
-
- /**
- * Removes a thread from the list.
- */
- synchronized void removeThread(int threadId) {
- mThreadMap.remove(threadId);
- }
-
- /**
- * Returns the list of threads as {@link ThreadInfo} objects.
- * <p/>The list is empty until a thread update was requested with
- * {@link Client#requestThreadUpdate()}.
- */
- public synchronized ThreadInfo[] getThreads() {
- Collection<ThreadInfo> threads = mThreadMap.values();
- return threads.toArray(new ThreadInfo[threads.size()]);
- }
-
- /**
- * Returns the {@link ThreadInfo} by thread id.
- */
- synchronized ThreadInfo getThread(int threadId) {
- return mThreadMap.get(threadId);
- }
-
- synchronized void clearThreads() {
- mThreadMap.clear();
- }
-
- /**
- * Returns the list of {@link NativeAllocationInfo}.
- * @see Client#requestNativeHeapInformation()
- */
- public synchronized List<NativeAllocationInfo> getNativeAllocationList() {
- return Collections.unmodifiableList(mNativeAllocationList);
- }
-
- /**
- * adds a new {@link NativeAllocationInfo} to the {@link Client}
- * @param allocInfo The {@link NativeAllocationInfo} to add.
- */
- synchronized void addNativeAllocation(NativeAllocationInfo allocInfo) {
- mNativeAllocationList.add(allocInfo);
- }
-
- /**
- * Clear the current malloc info.
- */
- synchronized void clearNativeAllocationInfo() {
- mNativeAllocationList.clear();
- }
-
- /**
- * Returns the total native memory.
- * @see Client#requestNativeHeapInformation()
- */
- public synchronized int getTotalNativeMemory() {
- return mNativeTotalMemory;
- }
-
- synchronized void setTotalNativeMemory(int totalMemory) {
- mNativeTotalMemory = totalMemory;
- }
-
- synchronized void addNativeLibraryMapInfo(long startAddr, long endAddr, String library) {
- mNativeLibMapInfo.add(new NativeLibraryMapInfo(startAddr, endAddr, library));
- }
-
- /**
- * Returns the list of native libraries mapped in memory for this client.
- */
- public synchronized List<NativeLibraryMapInfo> getMappedNativeLibraries() {
- return Collections.unmodifiableList(mNativeLibMapInfo);
- }
-
- synchronized void setAllocationStatus(AllocationTrackingStatus status) {
- mAllocationStatus = status;
- }
-
- /**
- * Returns the allocation tracking status.
- * @see Client#requestAllocationStatus()
- */
- public synchronized AllocationTrackingStatus getAllocationStatus() {
- return mAllocationStatus;
- }
-
- synchronized void setAllocations(AllocationInfo[] allocs) {
- mAllocations = allocs;
- }
-
- /**
- * Returns the list of tracked allocations.
- * @see Client#requestAllocationDetails()
- */
- public synchronized AllocationInfo[] getAllocations() {
- return mAllocations;
- }
-
- void addFeature(String feature) {
- mFeatures.add(feature);
- }
-
- /**
- * Returns true if the {@link Client} supports the given <var>feature</var>
- * @param feature The feature to test.
- * @return true if the feature is supported
- *
- * @see ClientData#FEATURE_PROFILING
- * @see ClientData#FEATURE_HPROF
- */
- public boolean hasFeature(String feature) {
- return mFeatures.contains(feature);
- }
-
- /**
- * Sets the device-side path to the hprof file being written
- * @param pendingHprofDump the file to the hprof file
- */
- void setPendingHprofDump(String pendingHprofDump) {
- mPendingHprofDump = pendingHprofDump;
- }
-
- /**
- * Returns the path to the device-side hprof file being written.
- */
- String getPendingHprofDump() {
- return mPendingHprofDump;
- }
-
- public boolean hasPendingHprofDump() {
- return mPendingHprofDump != null;
- }
-
- synchronized void setMethodProfilingStatus(MethodProfilingStatus status) {
- mProfilingStatus = status;
- }
-
- /**
- * Returns the method profiling status.
- * @see Client#requestMethodProfilingStatus()
- */
- public synchronized MethodProfilingStatus getMethodProfilingStatus() {
- return mProfilingStatus;
- }
-
- /**
- * Sets the device-side path to the method profile file being written
- * @param pendingMethodProfiling the file being written
- */
- void setPendingMethodProfiling(String pendingMethodProfiling) {
- mPendingMethodProfiling = pendingMethodProfiling;
- }
-
- /**
- * Returns the path to the device-side method profiling file being written.
- */
- String getPendingMethodProfiling() {
- return mPendingMethodProfiling;
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CollectingOutputReceiver.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CollectingOutputReceiver.java
deleted file mode 100644
index 80aa8e1..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/CollectingOutputReceiver.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib;
-
-
-import java.io.UnsupportedEncodingException;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * A {@link IShellOutputReceiver} which collects the whole shell output into one
- * {@link String}.
- */
-public class CollectingOutputReceiver implements IShellOutputReceiver {
- private CountDownLatch mCompletionLatch;
- private StringBuffer mOutputBuffer = new StringBuffer();
- private boolean mIsCanceled = false;
-
- public CollectingOutputReceiver() {
- }
-
- public CollectingOutputReceiver(CountDownLatch commandCompleteLatch) {
- mCompletionLatch = commandCompleteLatch;
- }
-
- public String getOutput() {
- return mOutputBuffer.toString();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isCancelled() {
- return mIsCanceled;
- }
-
- /**
- * Cancel the output collection
- */
- public void cancel() {
- mIsCanceled = true;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addOutput(byte[] data, int offset, int length) {
- if (!isCancelled()) {
- String s = null;
- try {
- s = new String(data, offset, length, "UTF-8"); //$NON-NLS-1$
- } catch (UnsupportedEncodingException e) {
- // normal encoding didn't work, try the default one
- s = new String(data, offset,length);
- }
- mOutputBuffer.append(s);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void flush() {
- if (mCompletionLatch != null) {
- mCompletionLatch.countDown();
- }
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmConstants.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmConstants.java
deleted file mode 100644
index 0b107e4..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmConstants.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2009 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.ddmlib;
-
-public final class DdmConstants {
-
- public final static int PLATFORM_UNKNOWN = 0;
- public final static int PLATFORM_LINUX = 1;
- public final static int PLATFORM_WINDOWS = 2;
- public final static int PLATFORM_DARWIN = 3;
-
- /**
- * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
- * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
- */
- public final static int CURRENT_PLATFORM = currentPlatform();
-
- /**
- * Extension for Traceview files.
- */
- public final static String DOT_TRACE = ".trace";
-
- /** hprof-conv executable (with extension for the current OS) */
- public final static String FN_HPROF_CONVERTER = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
- "hprof-conv.exe" : "hprof-conv"; //$NON-NLS-1$ //$NON-NLS-2$
-
- /** traceview executable (with extension for the current OS) */
- public final static String FN_TRACEVIEW = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
- "traceview.bat" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$
-
- /**
- * Returns current platform
- *
- * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
- * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
- */
- public static int currentPlatform() {
- String os = System.getProperty("os.name"); //$NON-NLS-1$
- if (os.startsWith("Mac OS")) { //$NON-NLS-1$
- return PLATFORM_DARWIN;
- } else if (os.startsWith("Windows")) { //$NON-NLS-1$
- return PLATFORM_WINDOWS;
- } else if (os.startsWith("Linux")) { //$NON-NLS-1$
- return PLATFORM_LINUX;
- }
-
- return PLATFORM_UNKNOWN;
- }
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmPreferences.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmPreferences.java
deleted file mode 100644
index d286917..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DdmPreferences.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.Log.LogLevel;
-
-/**
- * Preferences for the ddm library.
- * <p/>This class does not handle storing the preferences. It is merely a central point for
- * applications using the ddmlib to override the default values.
- * <p/>Various components of the ddmlib query this class to get their values.
- * <p/>Calls to some <code>set##()</code> methods will update the components using the values
- * right away, while other methods will have no effect once {@link AndroidDebugBridge#init(boolean)}
- * has been called.
- * <p/>Check the documentation of each method.
- */
-public final class DdmPreferences {
-
- /** Default value for thread update flag upon client connection. */
- public final static boolean DEFAULT_INITIAL_THREAD_UPDATE = false;
- /** Default value for heap update flag upon client connection. */
- public final static boolean DEFAULT_INITIAL_HEAP_UPDATE = false;
- /** Default value for the selected client debug port */
- public final static int DEFAULT_SELECTED_DEBUG_PORT = 8700;
- /** Default value for the debug port base */
- public final static int DEFAULT_DEBUG_PORT_BASE = 8600;
- /** Default value for the logcat {@link LogLevel} */
- public final static LogLevel DEFAULT_LOG_LEVEL = LogLevel.ERROR;
- /** Default timeout values for adb connection (milliseconds) */
- public static final int DEFAULT_TIMEOUT = 5000; // standard delay, in ms
- /** Default profiler buffer size (megabytes) */
- public static final int DEFAULT_PROFILER_BUFFER_SIZE_MB = 8;
- /** Default values for the use of the ADBHOST environment variable. */
- public final static boolean DEFAULT_USE_ADBHOST = false;
- public final static String DEFAULT_ADBHOST_VALUE = "127.0.0.1";
-
- private static boolean sThreadUpdate = DEFAULT_INITIAL_THREAD_UPDATE;
- private static boolean sInitialHeapUpdate = DEFAULT_INITIAL_HEAP_UPDATE;
-
- private static int sSelectedDebugPort = DEFAULT_SELECTED_DEBUG_PORT;
- private static int sDebugPortBase = DEFAULT_DEBUG_PORT_BASE;
- private static LogLevel sLogLevel = DEFAULT_LOG_LEVEL;
- private static int sTimeOut = DEFAULT_TIMEOUT;
- private static int sProfilerBufferSizeMb = DEFAULT_PROFILER_BUFFER_SIZE_MB;
-
- private static boolean sUseAdbHost = DEFAULT_USE_ADBHOST;
- private static String sAdbHostValue = DEFAULT_ADBHOST_VALUE;
-
- /**
- * Returns the initial {@link Client} flag for thread updates.
- * @see #setInitialThreadUpdate(boolean)
- */
- public static boolean getInitialThreadUpdate() {
- return sThreadUpdate;
- }
-
- /**
- * Sets the initial {@link Client} flag for thread updates.
- * <p/>This change takes effect right away, for newly created {@link Client} objects.
- */
- public static void setInitialThreadUpdate(boolean state) {
- sThreadUpdate = state;
- }
-
- /**
- * Returns the initial {@link Client} flag for heap updates.
- * @see #setInitialHeapUpdate(boolean)
- */
- public static boolean getInitialHeapUpdate() {
- return sInitialHeapUpdate;
- }
-
- /**
- * Sets the initial {@link Client} flag for heap updates.
- * <p/>If <code>true</code>, the {@link ClientData} will automatically be updated with
- * the VM heap information whenever a GC happens.
- * <p/>This change takes effect right away, for newly created {@link Client} objects.
- */
- public static void setInitialHeapUpdate(boolean state) {
- sInitialHeapUpdate = state;
- }
-
- /**
- * Returns the debug port used by the selected {@link Client}.
- */
- public static int getSelectedDebugPort() {
- return sSelectedDebugPort;
- }
-
- /**
- * Sets the debug port used by the selected {@link Client}.
- * <p/>This change takes effect right away.
- * @param port the new port to use.
- */
- public static void setSelectedDebugPort(int port) {
- sSelectedDebugPort = port;
-
- MonitorThread monitorThread = MonitorThread.getInstance();
- if (monitorThread != null) {
- monitorThread.setDebugSelectedPort(port);
- }
- }
-
- /**
- * Returns the debug port used by the first {@link Client}. Following clients, will use the
- * next port.
- */
- public static int getDebugPortBase() {
- return sDebugPortBase;
- }
-
- /**
- * Sets the debug port used by the first {@link Client}.
- * <p/>Once a port is used, the next Client will use port + 1. Quitting applications will
- * release their debug port, and new clients will be able to reuse them.
- * <p/>This must be called before {@link AndroidDebugBridge#init(boolean)}.
- */
- public static void setDebugPortBase(int port) {
- sDebugPortBase = port;
- }
-
- /**
- * Returns the minimum {@link LogLevel} being displayed.
- */
- public static LogLevel getLogLevel() {
- return sLogLevel;
- }
-
- /**
- * Sets the minimum {@link LogLevel} to display.
- * <p/>This change takes effect right away.
- */
- public static void setLogLevel(String value) {
- sLogLevel = LogLevel.getByString(value);
-
- Log.setLevel(sLogLevel);
- }
-
- /**
- * Returns the timeout to be used in adb connections (milliseconds).
- */
- public static int getTimeOut() {
- return sTimeOut;
- }
-
- /**
- * Sets the timeout value for adb connection.
- * <p/>This change takes effect for newly created connections only.
- * @param timeOut the timeout value (milliseconds).
- */
- public static void setTimeOut(int timeOut) {
- sTimeOut = timeOut;
- }
-
- /**
- * Returns the profiler buffer size (megabytes).
- */
- public static int getProfilerBufferSizeMb() {
- return sProfilerBufferSizeMb;
- }
-
- /**
- * Sets the profiler buffer size value.
- * @param bufferSizeMb the buffer size (megabytes).
- */
- public static void setProfilerBufferSizeMb(int bufferSizeMb) {
- sProfilerBufferSizeMb = bufferSizeMb;
- }
-
- /**
- * Returns a boolean indicating that the user uses or not the variable ADBHOST.
- */
- public static boolean getUseAdbHost() {
- return sUseAdbHost;
- }
-
- /**
- * Sets the value of the boolean indicating that the user uses or not the variable ADBHOST.
- * @param useAdbHost true if the user uses ADBHOST
- */
- public static void setUseAdbHost(boolean useAdbHost) {
- sUseAdbHost = useAdbHost;
- }
-
- /**
- * Returns the value of the ADBHOST variable set by the user.
- */
- public static String getAdbHostValue() {
- return sAdbHostValue;
- }
-
- /**
- * Sets the value of the ADBHOST variable.
- * @param adbHostValue
- */
- public static void setAdbHostValue(String adbHostValue) {
- sAdbHostValue = adbHostValue;
- }
-
- /**
- * Non accessible constructor.
- */
- private DdmPreferences() {
- // pass, only static methods in the class.
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DebugPortManager.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DebugPortManager.java
deleted file mode 100644
index defdc0e..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DebugPortManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.Device;
-
-/**
- * Centralized point to provide a {@link IDebugPortProvider} to ddmlib.
- *
- * <p/>When {@link Client} objects are created, they start listening for debuggers on a specific
- * port. The default behavior is to start with {@link DdmPreferences#getDebugPortBase()} and
- * increment this value for each new <code>Client</code>.
- *
- * <p/>This {@link DebugPortManager} allows applications using ddmlib to provide a custom
- * port provider on a per-<code>Client</code> basis, depending on the device/emulator they are
- * running on, and/or their names.
- */
-public class DebugPortManager {
-
- /**
- * Classes which implement this interface provide a method that provides a non random
- * debugger port for a newly created {@link Client}.
- */
- public interface IDebugPortProvider {
-
- public static final int NO_STATIC_PORT = -1;
-
- /**
- * Returns a non-random debugger port for the specified application running on the
- * specified {@link Device}.
- * @param device The device the application is running on.
- * @param appName The application name, as defined in the <code>AndroidManifest.xml</code>
- * <var>package</var> attribute of the <var>manifest</var> node.
- * @return The non-random debugger port or {@link #NO_STATIC_PORT} if the {@link Client}
- * should use the automatic debugger port provider.
- */
- public int getPort(IDevice device, String appName);
- }
-
- private static IDebugPortProvider sProvider = null;
-
- /**
- * Sets the {@link IDebugPortProvider} that will be used when a new {@link Client} requests
- * a debugger port.
- * @param provider the <code>IDebugPortProvider</code> to use.
- */
- public static void setProvider(IDebugPortProvider provider) {
- sProvider = provider;
- }
-
- /**
- * Returns the
- * @return
- */
- static IDebugPortProvider getProvider() {
- return sProvider;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Debugger.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Debugger.java
deleted file mode 100644
index 9356c13..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Debugger.java
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.ClientData.DebuggerStatus;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.ServerSocketChannel;
-import java.nio.channels.SocketChannel;
-
-/**
- * This represents a pending or established connection with a JDWP debugger.
- */
-class Debugger {
-
- /*
- * Messages from the debugger should be pretty small; may not even
- * need an expanding-buffer implementation for this.
- */
- private static final int INITIAL_BUF_SIZE = 1 * 1024;
- private static final int MAX_BUF_SIZE = 32 * 1024;
- private ByteBuffer mReadBuffer;
-
- private static final int PRE_DATA_BUF_SIZE = 256;
- private ByteBuffer mPreDataBuffer;
-
- /* connection state */
- private int mConnState;
- private static final int ST_NOT_CONNECTED = 1;
- private static final int ST_AWAIT_SHAKE = 2;
- private static final int ST_READY = 3;
-
- /* peer */
- private Client mClient; // client we're forwarding to/from
- private int mListenPort; // listen to me
- private ServerSocketChannel mListenChannel;
-
- /* this goes up and down; synchronize methods that access the field */
- private SocketChannel mChannel;
-
- /**
- * Create a new Debugger object, configured to listen for connections
- * on a specific port.
- */
- Debugger(Client client, int listenPort) throws IOException {
-
- mClient = client;
- mListenPort = listenPort;
-
- mListenChannel = ServerSocketChannel.open();
- mListenChannel.configureBlocking(false); // required for Selector
-
- InetSocketAddress addr = new InetSocketAddress(
- InetAddress.getByName("localhost"), //$NON-NLS-1$
- listenPort);
- mListenChannel.socket().setReuseAddress(true); // enable SO_REUSEADDR
- mListenChannel.socket().bind(addr);
-
- mReadBuffer = ByteBuffer.allocate(INITIAL_BUF_SIZE);
- mPreDataBuffer = ByteBuffer.allocate(PRE_DATA_BUF_SIZE);
- mConnState = ST_NOT_CONNECTED;
-
- Log.d("ddms", "Created: " + this.toString());
- }
-
- /**
- * Returns "true" if a debugger is currently attached to us.
- */
- boolean isDebuggerAttached() {
- return mChannel != null;
- }
-
- /**
- * Represent the Debugger as a string.
- */
- @Override
- public String toString() {
- // mChannel != null means we have connection, ST_READY means it's going
- return "[Debugger " + mListenPort + "-->" + mClient.getClientData().getPid()
- + ((mConnState != ST_READY) ? " inactive]" : " active]");
- }
-
- /**
- * Register the debugger's listen socket with the Selector.
- */
- void registerListener(Selector sel) throws IOException {
- mListenChannel.register(sel, SelectionKey.OP_ACCEPT, this);
- }
-
- /**
- * Return the Client being debugged.
- */
- Client getClient() {
- return mClient;
- }
-
- /**
- * Accept a new connection, but only if we don't already have one.
- *
- * Must be synchronized with other uses of mChannel and mPreBuffer.
- *
- * Returns "null" if we're already talking to somebody.
- */
- synchronized SocketChannel accept() throws IOException {
- return accept(mListenChannel);
- }
-
- /**
- * Accept a new connection from the specified listen channel. This
- * is so we can listen on a dedicated port for the "current" client,
- * where "current" is constantly in flux.
- *
- * Must be synchronized with other uses of mChannel and mPreBuffer.
- *
- * Returns "null" if we're already talking to somebody.
- */
- synchronized SocketChannel accept(ServerSocketChannel listenChan)
- throws IOException {
-
- if (listenChan != null) {
- SocketChannel newChan;
-
- newChan = listenChan.accept();
- if (mChannel != null) {
- Log.w("ddms", "debugger already talking to " + mClient
- + " on " + mListenPort);
- newChan.close();
- return null;
- }
- mChannel = newChan;
- mChannel.configureBlocking(false); // required for Selector
- mConnState = ST_AWAIT_SHAKE;
- return mChannel;
- }
-
- return null;
- }
-
- /**
- * Close the data connection only.
- */
- synchronized void closeData() {
- try {
- if (mChannel != null) {
- mChannel.close();
- mChannel = null;
- mConnState = ST_NOT_CONNECTED;
-
- ClientData cd = mClient.getClientData();
- cd.setDebuggerConnectionStatus(DebuggerStatus.DEFAULT);
- mClient.update(Client.CHANGE_DEBUGGER_STATUS);
- }
- } catch (IOException ioe) {
- Log.w("ddms", "Failed to close data " + this);
- }
- }
-
- /**
- * Close the socket that's listening for new connections and (if
- * we're connected) the debugger data socket.
- */
- synchronized void close() {
- try {
- if (mListenChannel != null) {
- mListenChannel.close();
- }
- mListenChannel = null;
- closeData();
- } catch (IOException ioe) {
- Log.w("ddms", "Failed to close listener " + this);
- }
- }
-
- // TODO: ?? add a finalizer that verifies the channel was closed
-
- /**
- * Read data from our channel.
- *
- * This is called when data is known to be available, and we don't yet
- * have a full packet in the buffer. If the buffer is at capacity,
- * expand it.
- */
- void read() throws IOException {
- int count;
-
- if (mReadBuffer.position() == mReadBuffer.capacity()) {
- if (mReadBuffer.capacity() * 2 > MAX_BUF_SIZE) {
- throw new BufferOverflowException();
- }
- Log.d("ddms", "Expanding read buffer to "
- + mReadBuffer.capacity() * 2);
-
- ByteBuffer newBuffer =
- ByteBuffer.allocate(mReadBuffer.capacity() * 2);
- mReadBuffer.position(0);
- newBuffer.put(mReadBuffer); // leaves "position" at end
-
- mReadBuffer = newBuffer;
- }
-
- count = mChannel.read(mReadBuffer);
- Log.v("ddms", "Read " + count + " bytes from " + this);
- if (count < 0) throw new IOException("read failed");
- }
-
- /**
- * Return information for the first full JDWP packet in the buffer.
- *
- * If we don't yet have a full packet, return null.
- *
- * If we haven't yet received the JDWP handshake, we watch for it here
- * and consume it without admitting to have done so. We also send
- * the handshake response to the debugger, along with any pending
- * pre-connection data, which is why this can throw an IOException.
- */
- JdwpPacket getJdwpPacket() throws IOException {
- /*
- * On entry, the data starts at offset 0 and ends at "position".
- * "limit" is set to the buffer capacity.
- */
- if (mConnState == ST_AWAIT_SHAKE) {
- int result;
-
- result = JdwpPacket.findHandshake(mReadBuffer);
- //Log.v("ddms", "findHand: " + result);
- switch (result) {
- case JdwpPacket.HANDSHAKE_GOOD:
- Log.d("ddms", "Good handshake from debugger");
- JdwpPacket.consumeHandshake(mReadBuffer);
- sendHandshake();
- mConnState = ST_READY;
-
- ClientData cd = mClient.getClientData();
- cd.setDebuggerConnectionStatus(DebuggerStatus.ATTACHED);
- mClient.update(Client.CHANGE_DEBUGGER_STATUS);
-
- // see if we have another packet in the buffer
- return getJdwpPacket();
- case JdwpPacket.HANDSHAKE_BAD:
- // not a debugger, throw an exception so we drop the line
- Log.d("ddms", "Bad handshake from debugger");
- throw new IOException("bad handshake");
- case JdwpPacket.HANDSHAKE_NOTYET:
- break;
- default:
- Log.e("ddms", "Unknown packet while waiting for client handshake");
- }
- return null;
- } else if (mConnState == ST_READY) {
- if (mReadBuffer.position() != 0) {
- Log.v("ddms", "Checking " + mReadBuffer.position() + " bytes");
- }
- return JdwpPacket.findPacket(mReadBuffer);
- } else {
- Log.e("ddms", "Receiving data in state = " + mConnState);
- }
-
- return null;
- }
-
- /**
- * Forward a packet to the client.
- *
- * "mClient" will never be null, though it's possible that the channel
- * in the client has closed and our send attempt will fail.
- *
- * Consumes the packet.
- */
- void forwardPacketToClient(JdwpPacket packet) throws IOException {
- mClient.sendAndConsume(packet);
- }
-
- /**
- * Send the handshake to the debugger. We also send along any packets
- * we already received from the client (usually just a VM_START event,
- * if anything at all).
- */
- private synchronized void sendHandshake() throws IOException {
- ByteBuffer tempBuffer = ByteBuffer.allocate(JdwpPacket.HANDSHAKE_LEN);
- JdwpPacket.putHandshake(tempBuffer);
- int expectedLength = tempBuffer.position();
- tempBuffer.flip();
- if (mChannel.write(tempBuffer) != expectedLength) {
- throw new IOException("partial handshake write");
- }
-
- expectedLength = mPreDataBuffer.position();
- if (expectedLength > 0) {
- Log.d("ddms", "Sending " + mPreDataBuffer.position()
- + " bytes of saved data");
- mPreDataBuffer.flip();
- if (mChannel.write(mPreDataBuffer) != expectedLength) {
- throw new IOException("partial pre-data write");
- }
- mPreDataBuffer.clear();
- }
- }
-
- /**
- * Send a packet to the debugger.
- *
- * Ideally, we can do this with a single channel write. If that doesn't
- * happen, we have to prevent anybody else from writing to the channel
- * until this packet completes, so we synchronize on the channel.
- *
- * Another goal is to avoid unnecessary buffer copies, so we write
- * directly out of the JdwpPacket's ByteBuffer.
- *
- * We must synchronize on "mChannel" before writing to it. We want to
- * coordinate the buffered data with mChannel creation, so this whole
- * method is synchronized.
- */
- synchronized void sendAndConsume(JdwpPacket packet)
- throws IOException {
-
- if (mChannel == null) {
- /*
- * Buffer this up so we can send it to the debugger when it
- * finally does connect. This is essential because the VM_START
- * message might be telling the debugger that the VM is
- * suspended. The alternative approach would be for us to
- * capture and interpret VM_START and send it later if we
- * didn't choose to un-suspend the VM for our own purposes.
- */
- Log.d("ddms", "Saving packet 0x"
- + Integer.toHexString(packet.getId()));
- packet.movePacket(mPreDataBuffer);
- } else {
- packet.writeAndConsume(mChannel);
- }
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Device.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Device.java
deleted file mode 100644
index 0566275..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Device.java
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.log.LogReceiver;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.channels.SocketChannel;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-
-/**
- * A Device. It can be a physical device or an emulator.
- */
-final class Device implements IDevice {
- private static final String DEVICE_MODEL_PROPERTY = "ro.product.model"; //$NON-NLS-1$
- private static final String DEVICE_MANUFACTURER_PROPERTY = "ro.product.manufacturer"; //$NON-NLS-1$
-
- private final static int INSTALL_TIMEOUT = 2*60*1000; //2min
- private static final int BATTERY_TIMEOUT = 2*1000; //2 seconds
- private static final int GETPROP_TIMEOUT = 2*1000; //2 seconds
-
- /** Emulator Serial Number regexp. */
- final static String RE_EMULATOR_SN = "emulator-(\\d+)"; //$NON-NLS-1$
-
- /** Serial number of the device */
- private String mSerialNumber = null;
-
- /** Name of the AVD */
- private String mAvdName = null;
-
- /** State of the device. */
- private DeviceState mState = null;
-
- /** Device properties. */
- private final Map<String, String> mProperties = new HashMap<String, String>();
- private final Map<String, String> mMountPoints = new HashMap<String, String>();
-
- private final ArrayList<Client> mClients = new ArrayList<Client>();
- private DeviceMonitor mMonitor;
-
- private static final String LOG_TAG = "Device";
- private static final char SEPARATOR = '-';
-
- /**
- * Socket for the connection monitoring client connection/disconnection.
- */
- private SocketChannel mSocketChannel;
-
- private boolean mArePropertiesSet = false;
-
- private Integer mLastBatteryLevel = null;
- private long mLastBatteryCheckTime = 0;
-
- private String mName;
-
- /**
- * Output receiver for "pm install package.apk" command line.
- */
- private static final class InstallReceiver extends MultiLineReceiver {
-
- private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
- private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
-
- private String mErrorMessage = null;
-
- public InstallReceiver() {
- }
-
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- if (line.length() > 0) {
- if (line.startsWith(SUCCESS_OUTPUT)) {
- mErrorMessage = null;
- } else {
- Matcher m = FAILURE_PATTERN.matcher(line);
- if (m.matches()) {
- mErrorMessage = m.group(1);
- }
- }
- }
- }
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- public String getErrorMessage() {
- return mErrorMessage;
- }
- }
-
- /**
- * Output receiver for "dumpsys battery" command line.
- */
- private static final class BatteryReceiver extends MultiLineReceiver {
- private static final Pattern BATTERY_LEVEL = Pattern.compile("\\s*level: (\\d+)");
- private static final Pattern SCALE = Pattern.compile("\\s*scale: (\\d+)");
-
- private Integer mBatteryLevel = null;
- private Integer mBatteryScale = null;
-
- /**
- * Get the parsed percent battery level.
- * @return
- */
- public Integer getBatteryLevel() {
- if (mBatteryLevel != null && mBatteryScale != null) {
- return (mBatteryLevel * 100) / mBatteryScale;
- }
- return null;
- }
-
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- Matcher batteryMatch = BATTERY_LEVEL.matcher(line);
- if (batteryMatch.matches()) {
- try {
- mBatteryLevel = Integer.parseInt(batteryMatch.group(1));
- } catch (NumberFormatException e) {
- Log.w(LOG_TAG, String.format("Failed to parse %s as an integer",
- batteryMatch.group(1)));
- }
- }
- Matcher scaleMatch = SCALE.matcher(line);
- if (scaleMatch.matches()) {
- try {
- mBatteryScale = Integer.parseInt(scaleMatch.group(1));
- } catch (NumberFormatException e) {
- Log.w(LOG_TAG, String.format("Failed to parse %s as an integer",
- batteryMatch.group(1)));
- }
- }
- }
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getSerialNumber()
- */
- @Override
- public String getSerialNumber() {
- return mSerialNumber;
- }
-
- /** {@inheritDoc} */
- @Override
- public String getAvdName() {
- return mAvdName;
- }
-
- /**
- * Sets the name of the AVD
- */
- void setAvdName(String avdName) {
- if (isEmulator() == false) {
- throw new IllegalArgumentException(
- "Cannot set the AVD name of the device is not an emulator");
- }
-
- mAvdName = avdName;
- }
-
- @Override
- public String getName() {
- if (mName == null) {
- mName = constructName();
- }
-
- return mName;
- }
-
- private String constructName() {
- if (isEmulator()) {
- String avdName = getAvdName();
- if (avdName != null) {
- return String.format("%s [%s]", avdName, getSerialNumber());
- } else {
- return getSerialNumber();
- }
- } else {
- String manufacturer = cleanupStringForDisplay(
- getProperty(DEVICE_MANUFACTURER_PROPERTY));
- String model = cleanupStringForDisplay(
- getProperty(DEVICE_MODEL_PROPERTY));
-
- StringBuilder sb = new StringBuilder(20);
-
- if (manufacturer != null) {
- sb.append(manufacturer);
- sb.append(SEPARATOR);
- }
-
- if (model != null) {
- sb.append(model);
- sb.append(SEPARATOR);
- }
-
- sb.append(getSerialNumber());
- return sb.toString();
- }
- }
-
- private String cleanupStringForDisplay(String s) {
- if (s == null) {
- return null;
- }
-
- StringBuilder sb = new StringBuilder(s.length());
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
-
- if (Character.isLetterOrDigit(c)) {
- sb.append(Character.toLowerCase(c));
- } else {
- sb.append('_');
- }
- }
-
- return sb.toString();
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getState()
- */
- @Override
- public DeviceState getState() {
- return mState;
- }
-
- /**
- * Changes the state of the device.
- */
- void setState(DeviceState state) {
- mState = state;
- }
-
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getProperties()
- */
- @Override
- public Map<String, String> getProperties() {
- return Collections.unmodifiableMap(mProperties);
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getPropertyCount()
- */
- @Override
- public int getPropertyCount() {
- return mProperties.size();
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getProperty(java.lang.String)
- */
- @Override
- public String getProperty(String name) {
- return mProperties.get(name);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean arePropertiesSet() {
- return mArePropertiesSet;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getPropertyCacheOrSync(String name) throws TimeoutException,
- AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
- if (mArePropertiesSet) {
- return getProperty(name);
- } else {
- return getPropertySync(name);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getPropertySync(String name) throws TimeoutException,
- AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
- CollectingOutputReceiver receiver = new CollectingOutputReceiver();
- executeShellCommand(String.format("getprop '%s'", name), receiver, GETPROP_TIMEOUT);
- String value = receiver.getOutput().trim();
- if (value.isEmpty()) {
- return null;
- }
- return value;
- }
-
- @Override
- public String getMountPoint(String name) {
- return mMountPoints.get(name);
- }
-
-
- @Override
- public String toString() {
- return mSerialNumber;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isOnline()
- */
- @Override
- public boolean isOnline() {
- return mState == DeviceState.ONLINE;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isEmulator()
- */
- @Override
- public boolean isEmulator() {
- return mSerialNumber.matches(RE_EMULATOR_SN);
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isOffline()
- */
- @Override
- public boolean isOffline() {
- return mState == DeviceState.OFFLINE;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isBootLoader()
- */
- @Override
- public boolean isBootLoader() {
- return mState == DeviceState.BOOTLOADER;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#hasClients()
- */
- @Override
- public boolean hasClients() {
- return mClients.size() > 0;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getClients()
- */
- @Override
- public Client[] getClients() {
- synchronized (mClients) {
- return mClients.toArray(new Client[mClients.size()]);
- }
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getClient(java.lang.String)
- */
- @Override
- public Client getClient(String applicationName) {
- synchronized (mClients) {
- for (Client c : mClients) {
- if (applicationName.equals(c.getClientData().getClientDescription())) {
- return c;
- }
- }
-
- }
-
- return null;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getSyncService()
- */
- @Override
- public SyncService getSyncService()
- throws TimeoutException, AdbCommandRejectedException, IOException {
- SyncService syncService = new SyncService(AndroidDebugBridge.getSocketAddress(), this);
- if (syncService.openSync()) {
- return syncService;
- }
-
- return null;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getFileListingService()
- */
- @Override
- public FileListingService getFileListingService() {
- return new FileListingService(this);
- }
-
- @Override
- public RawImage getScreenshot()
- throws TimeoutException, AdbCommandRejectedException, IOException {
- return AdbHelper.getFrameBuffer(AndroidDebugBridge.getSocketAddress(), this);
- }
-
- @Override
- public void executeShellCommand(String command, IShellOutputReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this,
- receiver, DdmPreferences.getTimeOut());
- }
-
- @Override
- public void executeShellCommand(String command, IShellOutputReceiver receiver,
- int maxTimeToOutputResponse)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this,
- receiver, maxTimeToOutputResponse);
- }
-
- @Override
- public void runEventLogService(LogReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.runEventLogService(AndroidDebugBridge.getSocketAddress(), this, receiver);
- }
-
- @Override
- public void runLogService(String logname, LogReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.runLogService(AndroidDebugBridge.getSocketAddress(), this, logname, receiver);
- }
-
- @Override
- public void createForward(int localPort, int remotePort)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this,
- String.format("tcp:%d", localPort), //$NON-NLS-1$
- String.format("tcp:%d", remotePort)); //$NON-NLS-1$
- }
-
- @Override
- public void createForward(int localPort, String remoteSocketName,
- DeviceUnixSocketNamespace namespace) throws TimeoutException,
- AdbCommandRejectedException, IOException {
- AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this,
- String.format("tcp:%d", localPort), //$NON-NLS-1$
- String.format("%s:%s", namespace.getType(), remoteSocketName)); //$NON-NLS-1$
- }
-
- @Override
- public void removeForward(int localPort, int remotePort)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this,
- String.format("tcp:%d", localPort), //$NON-NLS-1$
- String.format("tcp:%d", remotePort)); //$NON-NLS-1$
- }
-
- @Override
- public void removeForward(int localPort, String remoteSocketName,
- DeviceUnixSocketNamespace namespace) throws TimeoutException,
- AdbCommandRejectedException, IOException {
- AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this,
- String.format("tcp:%d", localPort), //$NON-NLS-1$
- String.format("%s:%s", namespace.getType(), remoteSocketName)); //$NON-NLS-1$
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getClientName(int)
- */
- @Override
- public String getClientName(int pid) {
- synchronized (mClients) {
- for (Client c : mClients) {
- if (c.getClientData().getPid() == pid) {
- return c.getClientData().getClientDescription();
- }
- }
- }
-
- return null;
- }
-
-
- Device(DeviceMonitor monitor, String serialNumber, DeviceState deviceState) {
- mMonitor = monitor;
- mSerialNumber = serialNumber;
- mState = deviceState;
- }
-
- DeviceMonitor getMonitor() {
- return mMonitor;
- }
-
- void addClient(Client client) {
- synchronized (mClients) {
- mClients.add(client);
- }
- }
-
- List<Client> getClientList() {
- return mClients;
- }
-
- boolean hasClient(int pid) {
- synchronized (mClients) {
- for (Client client : mClients) {
- if (client.getClientData().getPid() == pid) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- void clearClientList() {
- synchronized (mClients) {
- mClients.clear();
- }
- }
-
- /**
- * Sets the client monitoring socket.
- * @param socketChannel the sockets
- */
- void setClientMonitoringSocket(SocketChannel socketChannel) {
- mSocketChannel = socketChannel;
- }
-
- /**
- * Returns the client monitoring socket.
- */
- SocketChannel getClientMonitoringSocket() {
- return mSocketChannel;
- }
-
- /**
- * Removes a {@link Client} from the list.
- * @param client the client to remove.
- * @param notify Whether or not to notify the listeners of a change.
- */
- void removeClient(Client client, boolean notify) {
- mMonitor.addPortToAvailableList(client.getDebuggerListenPort());
- synchronized (mClients) {
- mClients.remove(client);
- }
- if (notify) {
- mMonitor.getServer().deviceChanged(this, CHANGE_CLIENT_LIST);
- }
- }
-
- void update(int changeMask) {
- if ((changeMask & CHANGE_BUILD_INFO) != 0) {
- mArePropertiesSet = true;
- }
- mMonitor.getServer().deviceChanged(this, changeMask);
- }
-
- void update(Client client, int changeMask) {
- mMonitor.getServer().clientChanged(client, changeMask);
- }
-
- void addProperty(String label, String value) {
- mProperties.put(label, value);
- }
-
- void setMountingPoint(String name, String value) {
- mMountPoints.put(name, value);
- }
-
- @Override
- public void pushFile(String local, String remote)
- throws IOException, AdbCommandRejectedException, TimeoutException, SyncException {
- SyncService sync = null;
- try {
- String targetFileName = getFileName(local);
-
- Log.d(targetFileName, String.format("Uploading %1$s onto device '%2$s'",
- targetFileName, getSerialNumber()));
-
- sync = getSyncService();
- if (sync != null) {
- String message = String.format("Uploading file onto device '%1$s'",
- getSerialNumber());
- Log.d(LOG_TAG, message);
- sync.pushFile(local, remote, SyncService.getNullProgressMonitor());
- } else {
- throw new IOException("Unable to open sync connection!");
- }
- } catch (TimeoutException e) {
- Log.e(LOG_TAG, "Error during Sync: timeout.");
- throw e;
-
- } catch (SyncException e) {
- Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage()));
- throw e;
-
- } catch (IOException e) {
- Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage()));
- throw e;
-
- } finally {
- if (sync != null) {
- sync.close();
- }
- }
- }
-
- @Override
- public void pullFile(String remote, String local)
- throws IOException, AdbCommandRejectedException, TimeoutException, SyncException {
- SyncService sync = null;
- try {
- String targetFileName = getFileName(remote);
-
- Log.d(targetFileName, String.format("Downloading %1$s from device '%2$s'",
- targetFileName, getSerialNumber()));
-
- sync = getSyncService();
- if (sync != null) {
- String message = String.format("Downloding file from device '%1$s'",
- getSerialNumber());
- Log.d(LOG_TAG, message);
- sync.pullFile(remote, local, SyncService.getNullProgressMonitor());
- } else {
- throw new IOException("Unable to open sync connection!");
- }
- } catch (TimeoutException e) {
- Log.e(LOG_TAG, "Error during Sync: timeout.");
- throw e;
-
- } catch (SyncException e) {
- Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage()));
- throw e;
-
- } catch (IOException e) {
- Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage()));
- throw e;
-
- } finally {
- if (sync != null) {
- sync.close();
- }
- }
- }
-
- @Override
- public String installPackage(String packageFilePath, boolean reinstall, String... extraArgs)
- throws InstallException {
- try {
- String remoteFilePath = syncPackageToDevice(packageFilePath);
- String result = installRemotePackage(remoteFilePath, reinstall, extraArgs);
- removeRemotePackage(remoteFilePath);
- return result;
- } catch (IOException e) {
- throw new InstallException(e);
- } catch (AdbCommandRejectedException e) {
- throw new InstallException(e);
- } catch (TimeoutException e) {
- throw new InstallException(e);
- } catch (SyncException e) {
- throw new InstallException(e);
- }
- }
-
- @Override
- public String syncPackageToDevice(String localFilePath)
- throws IOException, AdbCommandRejectedException, TimeoutException, SyncException {
- SyncService sync = null;
- try {
- String packageFileName = getFileName(localFilePath);
- String remoteFilePath = String.format("/data/local/tmp/%1$s", packageFileName); //$NON-NLS-1$
-
- Log.d(packageFileName, String.format("Uploading %1$s onto device '%2$s'",
- packageFileName, getSerialNumber()));
-
- sync = getSyncService();
- if (sync != null) {
- String message = String.format("Uploading file onto device '%1$s'",
- getSerialNumber());
- Log.d(LOG_TAG, message);
- sync.pushFile(localFilePath, remoteFilePath, SyncService.getNullProgressMonitor());
- } else {
- throw new IOException("Unable to open sync connection!");
- }
- return remoteFilePath;
- } catch (TimeoutException e) {
- Log.e(LOG_TAG, "Error during Sync: timeout.");
- throw e;
-
- } catch (SyncException e) {
- Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage()));
- throw e;
-
- } catch (IOException e) {
- Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage()));
- throw e;
-
- } finally {
- if (sync != null) {
- sync.close();
- }
- }
- }
-
- /**
- * Helper method to retrieve the file name given a local file path
- * @param filePath full directory path to file
- * @return {@link String} file name
- */
- private String getFileName(String filePath) {
- return new File(filePath).getName();
- }
-
- @Override
- public String installRemotePackage(String remoteFilePath, boolean reinstall,
- String... extraArgs) throws InstallException {
- try {
- InstallReceiver receiver = new InstallReceiver();
- StringBuilder optionString = new StringBuilder();
- if (reinstall) {
- optionString.append("-r ");
- }
- for (String arg : extraArgs) {
- optionString.append(arg);
- optionString.append(' ');
- }
- String cmd = String.format("pm install %1$s \"%2$s\"", optionString.toString(),
- remoteFilePath);
- executeShellCommand(cmd, receiver, INSTALL_TIMEOUT);
- return receiver.getErrorMessage();
- } catch (TimeoutException e) {
- throw new InstallException(e);
- } catch (AdbCommandRejectedException e) {
- throw new InstallException(e);
- } catch (ShellCommandUnresponsiveException e) {
- throw new InstallException(e);
- } catch (IOException e) {
- throw new InstallException(e);
- }
- }
-
- @Override
- public void removeRemotePackage(String remoteFilePath) throws InstallException {
- try {
- executeShellCommand("rm " + remoteFilePath, new NullOutputReceiver(), INSTALL_TIMEOUT);
- } catch (IOException e) {
- throw new InstallException(e);
- } catch (TimeoutException e) {
- throw new InstallException(e);
- } catch (AdbCommandRejectedException e) {
- throw new InstallException(e);
- } catch (ShellCommandUnresponsiveException e) {
- throw new InstallException(e);
- }
- }
-
- @Override
- public String uninstallPackage(String packageName) throws InstallException {
- try {
- InstallReceiver receiver = new InstallReceiver();
- executeShellCommand("pm uninstall " + packageName, receiver, INSTALL_TIMEOUT);
- return receiver.getErrorMessage();
- } catch (TimeoutException e) {
- throw new InstallException(e);
- } catch (AdbCommandRejectedException e) {
- throw new InstallException(e);
- } catch (ShellCommandUnresponsiveException e) {
- throw new InstallException(e);
- } catch (IOException e) {
- throw new InstallException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#reboot()
- */
- @Override
- public void reboot(String into)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.reboot(into, AndroidDebugBridge.getSocketAddress(), this);
- }
-
- @Override
- public Integer getBatteryLevel() throws TimeoutException, AdbCommandRejectedException,
- IOException, ShellCommandUnresponsiveException {
- // use default of 5 minutes
- return getBatteryLevel(5 * 60 * 1000);
- }
-
- @Override
- public Integer getBatteryLevel(long freshnessMs) throws TimeoutException,
- AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException {
- if (mLastBatteryLevel != null
- && mLastBatteryCheckTime > (System.currentTimeMillis() - freshnessMs)) {
- return mLastBatteryLevel;
- }
- BatteryReceiver receiver = new BatteryReceiver();
- executeShellCommand("dumpsys battery", receiver, BATTERY_TIMEOUT);
- mLastBatteryLevel = receiver.getBatteryLevel();
- mLastBatteryCheckTime = System.currentTimeMillis();
- return mLastBatteryLevel;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DeviceMonitor.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DeviceMonitor.java
deleted file mode 100644
index f70627c..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/DeviceMonitor.java
+++ /dev/null
@@ -1,947 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.AdbHelper.AdbResponse;
-import com.android.ddmlib.ClientData.DebuggerStatus;
-import com.android.ddmlib.DebugPortManager.IDebugPortProvider;
-import com.android.ddmlib.IDevice.DeviceState;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.channels.AsynchronousCloseException;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.SocketChannel;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A Device monitor. This connects to the Android Debug Bridge and get device and
- * debuggable process information from it.
- */
-final class DeviceMonitor {
- private byte[] mLengthBuffer = new byte[4];
- private byte[] mLengthBuffer2 = new byte[4];
-
- private boolean mQuit = false;
-
- private AndroidDebugBridge mServer;
-
- private SocketChannel mMainAdbConnection = null;
- private boolean mMonitoring = false;
- private int mConnectionAttempt = 0;
- private int mRestartAttemptCount = 0;
- private boolean mInitialDeviceListDone = false;
-
- private Selector mSelector;
-
- private final ArrayList<Device> mDevices = new ArrayList<Device>();
-
- private final ArrayList<Integer> mDebuggerPorts = new ArrayList<Integer>();
-
- private final HashMap<Client, Integer> mClientsToReopen = new HashMap<Client, Integer>();
-
- /**
- * Creates a new {@link DeviceMonitor} object and links it to the running
- * {@link AndroidDebugBridge} object.
- * @param server the running {@link AndroidDebugBridge}.
- */
- DeviceMonitor(AndroidDebugBridge server) {
- mServer = server;
-
- mDebuggerPorts.add(DdmPreferences.getDebugPortBase());
- }
-
- /**
- * Starts the monitoring.
- */
- void start() {
- new Thread("Device List Monitor") { //$NON-NLS-1$
- @Override
- public void run() {
- deviceMonitorLoop();
- }
- }.start();
- }
-
- /**
- * Stops the monitoring.
- */
- void stop() {
- mQuit = true;
-
- // wakeup the main loop thread by closing the main connection to adb.
- try {
- if (mMainAdbConnection != null) {
- mMainAdbConnection.close();
- }
- } catch (IOException e1) {
- }
-
- // wake up the secondary loop by closing the selector.
- if (mSelector != null) {
- mSelector.wakeup();
- }
- }
-
-
-
- /**
- * Returns if the monitor is currently connected to the debug bridge server.
- * @return
- */
- boolean isMonitoring() {
- return mMonitoring;
- }
-
- int getConnectionAttemptCount() {
- return mConnectionAttempt;
- }
-
- int getRestartAttemptCount() {
- return mRestartAttemptCount;
- }
-
- /**
- * Returns the devices.
- */
- Device[] getDevices() {
- synchronized (mDevices) {
- return mDevices.toArray(new Device[mDevices.size()]);
- }
- }
-
- boolean hasInitialDeviceList() {
- return mInitialDeviceListDone;
- }
-
- AndroidDebugBridge getServer() {
- return mServer;
- }
-
- void addClientToDropAndReopen(Client client, int port) {
- synchronized (mClientsToReopen) {
- Log.d("DeviceMonitor",
- "Adding " + client + " to list of client to reopen (" + port +").");
- if (mClientsToReopen.get(client) == null) {
- mClientsToReopen.put(client, port);
- }
- }
- mSelector.wakeup();
- }
-
- /**
- * Monitors the devices. This connects to the Debug Bridge
- */
- private void deviceMonitorLoop() {
- do {
- try {
- if (mMainAdbConnection == null) {
- Log.d("DeviceMonitor", "Opening adb connection");
- mMainAdbConnection = openAdbConnection();
- if (mMainAdbConnection == null) {
- mConnectionAttempt++;
- Log.e("DeviceMonitor", "Connection attempts: " + mConnectionAttempt);
- if (mConnectionAttempt > 10) {
- if (mServer.startAdb() == false) {
- mRestartAttemptCount++;
- Log.e("DeviceMonitor",
- "adb restart attempts: " + mRestartAttemptCount);
- } else {
- mRestartAttemptCount = 0;
- }
- }
- waitABit();
- } else {
- Log.d("DeviceMonitor", "Connected to adb for device monitoring");
- mConnectionAttempt = 0;
- }
- }
-
- if (mMainAdbConnection != null && mMonitoring == false) {
- mMonitoring = sendDeviceListMonitoringRequest();
- }
-
- if (mMonitoring) {
- // read the length of the incoming message
- int length = readLength(mMainAdbConnection, mLengthBuffer);
-
- if (length >= 0) {
- // read the incoming message
- processIncomingDeviceData(length);
-
- // flag the fact that we have build the list at least once.
- mInitialDeviceListDone = true;
- }
- }
- } catch (AsynchronousCloseException ace) {
- // this happens because of a call to Quit. We do nothing, and the loop will break.
- } catch (TimeoutException ioe) {
- handleExpectioninMonitorLoop(ioe);
- } catch (IOException ioe) {
- handleExpectioninMonitorLoop(ioe);
- }
- } while (mQuit == false);
- }
-
- private void handleExpectioninMonitorLoop(Exception e) {
- if (mQuit == false) {
- if (e instanceof TimeoutException) {
- Log.e("DeviceMonitor", "Adb connection Error: timeout");
- } else {
- Log.e("DeviceMonitor", "Adb connection Error:" + e.getMessage());
- }
- mMonitoring = false;
- if (mMainAdbConnection != null) {
- try {
- mMainAdbConnection.close();
- } catch (IOException ioe) {
- // we can safely ignore that one.
- }
- mMainAdbConnection = null;
-
- // remove all devices from list
- // because we are going to call mServer.deviceDisconnected which will acquire this
- // lock we lock it first, so that the AndroidDebugBridge lock is always locked
- // first.
- synchronized (AndroidDebugBridge.getLock()) {
- synchronized (mDevices) {
- for (int n = mDevices.size() - 1; n >= 0; n--) {
- Device device = mDevices.get(0);
- removeDevice(device);
- mServer.deviceDisconnected(device);
- }
- }
- }
- }
- }
- }
-
- /**
- * Sleeps for a little bit.
- */
- private void waitABit() {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e1) {
- }
- }
-
- /**
- * Attempts to connect to the debug bridge server.
- * @return a connect socket if success, null otherwise
- */
- private SocketChannel openAdbConnection() {
- Log.d("DeviceMonitor", "Connecting to adb for Device List Monitoring...");
-
- SocketChannel adbChannel = null;
- try {
- adbChannel = SocketChannel.open(AndroidDebugBridge.getSocketAddress());
- adbChannel.socket().setTcpNoDelay(true);
- } catch (IOException e) {
- }
-
- return adbChannel;
- }
-
- /**
- *
- * @return
- * @throws IOException
- */
- private boolean sendDeviceListMonitoringRequest() throws TimeoutException, IOException {
- byte[] request = AdbHelper.formAdbRequest("host:track-devices"); //$NON-NLS-1$
-
- try {
- AdbHelper.write(mMainAdbConnection, request);
-
- AdbResponse resp = AdbHelper.readAdbResponse(mMainAdbConnection,
- false /* readDiagString */);
-
- if (resp.okay == false) {
- // request was refused by adb!
- Log.e("DeviceMonitor", "adb refused request: " + resp.message);
- }
-
- return resp.okay;
- } catch (IOException e) {
- Log.e("DeviceMonitor", "Sending Tracking request failed!");
- mMainAdbConnection.close();
- throw e;
- }
- }
-
- /**
- * Processes an incoming device message from the socket
- * @param socket
- * @param length
- * @throws IOException
- */
- private void processIncomingDeviceData(int length) throws IOException {
- ArrayList<Device> list = new ArrayList<Device>();
-
- if (length > 0) {
- byte[] buffer = new byte[length];
- String result = read(mMainAdbConnection, buffer);
-
- String[] devices = result.split("\n"); //$NON-NLS-1$
-
- for (String d : devices) {
- String[] param = d.split("\t"); //$NON-NLS-1$
- if (param.length == 2) {
- // new adb uses only serial numbers to identify devices
- Device device = new Device(this, param[0] /*serialnumber*/,
- DeviceState.getState(param[1]));
-
- //add the device to the list
- list.add(device);
- }
- }
- }
-
- // now merge the new devices with the old ones.
- updateDevices(list);
- }
-
- /**
- * Updates the device list with the new items received from the monitoring service.
- */
- private void updateDevices(ArrayList<Device> newList) {
- // because we are going to call mServer.deviceDisconnected which will acquire this lock
- // we lock it first, so that the AndroidDebugBridge lock is always locked first.
- synchronized (AndroidDebugBridge.getLock()) {
- // array to store the devices that must be queried for information.
- // it's important to not do it inside the synchronized loop as this could block
- // the whole workspace (this lock is acquired during build too).
- ArrayList<Device> devicesToQuery = new ArrayList<Device>();
- synchronized (mDevices) {
- // For each device in the current list, we look for a matching the new list.
- // * if we find it, we update the current object with whatever new information
- // there is
- // (mostly state change, if the device becomes ready, we query for build info).
- // We also remove the device from the new list to mark it as "processed"
- // * if we do not find it, we remove it from the current list.
- // Once this is done, the new list contains device we aren't monitoring yet, so we
- // add them to the list, and start monitoring them.
-
- for (int d = 0 ; d < mDevices.size() ;) {
- Device device = mDevices.get(d);
-
- // look for a similar device in the new list.
- int count = newList.size();
- boolean foundMatch = false;
- for (int dd = 0 ; dd < count ; dd++) {
- Device newDevice = newList.get(dd);
- // see if it matches in id and serial number.
- if (newDevice.getSerialNumber().equals(device.getSerialNumber())) {
- foundMatch = true;
-
- // update the state if needed.
- if (device.getState() != newDevice.getState()) {
- device.setState(newDevice.getState());
- device.update(Device.CHANGE_STATE);
-
- // if the device just got ready/online, we need to start
- // monitoring it.
- if (device.isOnline()) {
- if (AndroidDebugBridge.getClientSupport() == true) {
- if (startMonitoringDevice(device) == false) {
- Log.e("DeviceMonitor",
- "Failed to start monitoring "
- + device.getSerialNumber());
- }
- }
-
- if (device.getPropertyCount() == 0) {
- devicesToQuery.add(device);
- }
- }
- }
-
- // remove the new device from the list since it's been used
- newList.remove(dd);
- break;
- }
- }
-
- if (foundMatch == false) {
- // the device is gone, we need to remove it, and keep current index
- // to process the next one.
- removeDevice(device);
- mServer.deviceDisconnected(device);
- } else {
- // process the next one
- d++;
- }
- }
-
- // at this point we should still have some new devices in newList, so we
- // process them.
- for (Device newDevice : newList) {
- // add them to the list
- mDevices.add(newDevice);
- mServer.deviceConnected(newDevice);
-
- // start monitoring them.
- if (AndroidDebugBridge.getClientSupport() == true) {
- if (newDevice.isOnline()) {
- startMonitoringDevice(newDevice);
- }
- }
-
- // look for their build info.
- if (newDevice.isOnline()) {
- devicesToQuery.add(newDevice);
- }
- }
- }
-
- // query the new devices for info.
- for (Device d : devicesToQuery) {
- queryNewDeviceForInfo(d);
- }
- }
- newList.clear();
- }
-
- private void removeDevice(Device device) {
- device.clearClientList();
- mDevices.remove(device);
-
- SocketChannel channel = device.getClientMonitoringSocket();
- if (channel != null) {
- try {
- channel.close();
- } catch (IOException e) {
- // doesn't really matter if the close fails.
- }
- }
- }
-
- /**
- * Queries a device for its build info.
- * @param device the device to query.
- */
- private void queryNewDeviceForInfo(Device device) {
- // TODO: do this in a separate thread.
- try {
- // first get the list of properties.
- device.executeShellCommand(GetPropReceiver.GETPROP_COMMAND,
- new GetPropReceiver(device));
-
- queryNewDeviceForMountingPoint(device, IDevice.MNT_EXTERNAL_STORAGE);
- queryNewDeviceForMountingPoint(device, IDevice.MNT_DATA);
- queryNewDeviceForMountingPoint(device, IDevice.MNT_ROOT);
-
- // now get the emulator Virtual Device name (if applicable).
- if (device.isEmulator()) {
- EmulatorConsole console = EmulatorConsole.getConsole(device);
- if (console != null) {
- device.setAvdName(console.getAvdName());
- }
- }
- } catch (TimeoutException e) {
- Log.w("DeviceMonitor", String.format("Connection timeout getting info for device %s",
- device.getSerialNumber()));
-
- } catch (AdbCommandRejectedException e) {
- // This should never happen as we only do this once the device is online.
- Log.w("DeviceMonitor", String.format(
- "Adb rejected command to get device %1$s info: %2$s",
- device.getSerialNumber(), e.getMessage()));
-
- } catch (ShellCommandUnresponsiveException e) {
- Log.w("DeviceMonitor", String.format(
- "Adb shell command took too long returning info for device %s",
- device.getSerialNumber()));
-
- } catch (IOException e) {
- Log.w("DeviceMonitor", String.format(
- "IO Error getting info for device %s",
- device.getSerialNumber()));
- }
- }
-
- private void queryNewDeviceForMountingPoint(final Device device, final String name)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- device.executeShellCommand("echo $" + name, new MultiLineReceiver() { //$NON-NLS-1$
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- if (line.length() > 0) {
- // this should be the only one.
- device.setMountingPoint(name, line);
- }
- }
- }
- });
- }
-
- /**
- * Starts a monitoring service for a device.
- * @param device the device to monitor.
- * @return true if success.
- */
- private boolean startMonitoringDevice(Device device) {
- SocketChannel socketChannel = openAdbConnection();
-
- if (socketChannel != null) {
- try {
- boolean result = sendDeviceMonitoringRequest(socketChannel, device);
- if (result) {
-
- if (mSelector == null) {
- startDeviceMonitorThread();
- }
-
- device.setClientMonitoringSocket(socketChannel);
-
- synchronized (mDevices) {
- // always wakeup before doing the register. The synchronized block
- // ensure that the selector won't select() before the end of this block.
- // @see deviceClientMonitorLoop
- mSelector.wakeup();
-
- socketChannel.configureBlocking(false);
- socketChannel.register(mSelector, SelectionKey.OP_READ, device);
- }
-
- return true;
- }
- } catch (TimeoutException e) {
- try {
- // attempt to close the socket if needed.
- socketChannel.close();
- } catch (IOException e1) {
- // we can ignore that one. It may already have been closed.
- }
- Log.d("DeviceMonitor",
- "Connection Failure when starting to monitor device '"
- + device + "' : timeout");
- } catch (AdbCommandRejectedException e) {
- try {
- // attempt to close the socket if needed.
- socketChannel.close();
- } catch (IOException e1) {
- // we can ignore that one. It may already have been closed.
- }
- Log.d("DeviceMonitor",
- "Adb refused to start monitoring device '"
- + device + "' : " + e.getMessage());
- } catch (IOException e) {
- try {
- // attempt to close the socket if needed.
- socketChannel.close();
- } catch (IOException e1) {
- // we can ignore that one. It may already have been closed.
- }
- Log.d("DeviceMonitor",
- "Connection Failure when starting to monitor device '"
- + device + "' : " + e.getMessage());
- }
- }
-
- return false;
- }
-
- private void startDeviceMonitorThread() throws IOException {
- mSelector = Selector.open();
- new Thread("Device Client Monitor") { //$NON-NLS-1$
- @Override
- public void run() {
- deviceClientMonitorLoop();
- }
- }.start();
- }
-
- private void deviceClientMonitorLoop() {
- do {
- try {
- // This synchronized block stops us from doing the select() if a new
- // Device is being added.
- // @see startMonitoringDevice()
- synchronized (mDevices) {
- }
-
- int count = mSelector.select();
-
- if (mQuit) {
- return;
- }
-
- synchronized (mClientsToReopen) {
- if (mClientsToReopen.size() > 0) {
- Set<Client> clients = mClientsToReopen.keySet();
- MonitorThread monitorThread = MonitorThread.getInstance();
-
- for (Client client : clients) {
- Device device = client.getDeviceImpl();
- int pid = client.getClientData().getPid();
-
- monitorThread.dropClient(client, false /* notify */);
-
- // This is kinda bad, but if we don't wait a bit, the client
- // will never answer the second handshake!
- waitABit();
-
- int port = mClientsToReopen.get(client);
-
- if (port == IDebugPortProvider.NO_STATIC_PORT) {
- port = getNextDebuggerPort();
- }
- Log.d("DeviceMonitor", "Reopening " + client);
- openClient(device, pid, port, monitorThread);
- device.update(Device.CHANGE_CLIENT_LIST);
- }
-
- mClientsToReopen.clear();
- }
- }
-
- if (count == 0) {
- continue;
- }
-
- Set<SelectionKey> keys = mSelector.selectedKeys();
- Iterator<SelectionKey> iter = keys.iterator();
-
- while (iter.hasNext()) {
- SelectionKey key = iter.next();
- iter.remove();
-
- if (key.isValid() && key.isReadable()) {
- Object attachment = key.attachment();
-
- if (attachment instanceof Device) {
- Device device = (Device)attachment;
-
- SocketChannel socket = device.getClientMonitoringSocket();
-
- if (socket != null) {
- try {
- int length = readLength(socket, mLengthBuffer2);
-
- processIncomingJdwpData(device, socket, length);
- } catch (IOException ioe) {
- Log.d("DeviceMonitor",
- "Error reading jdwp list: " + ioe.getMessage());
- socket.close();
-
- // restart the monitoring of that device
- synchronized (mDevices) {
- if (mDevices.contains(device)) {
- Log.d("DeviceMonitor",
- "Restarting monitoring service for " + device);
- startMonitoringDevice(device);
- }
- }
- }
- }
- }
- }
- }
- } catch (IOException e) {
- if (mQuit == false) {
-
- }
- }
-
- } while (mQuit == false);
- }
-
- private boolean sendDeviceMonitoringRequest(SocketChannel socket, Device device)
- throws TimeoutException, AdbCommandRejectedException, IOException {
-
- try {
- AdbHelper.setDevice(socket, device);
-
- byte[] request = AdbHelper.formAdbRequest("track-jdwp"); //$NON-NLS-1$
-
- AdbHelper.write(socket, request);
-
- AdbResponse resp = AdbHelper.readAdbResponse(socket, false /* readDiagString */);
-
- if (resp.okay == false) {
- // request was refused by adb!
- Log.e("DeviceMonitor", "adb refused request: " + resp.message);
- }
-
- return resp.okay;
- } catch (TimeoutException e) {
- Log.e("DeviceMonitor", "Sending jdwp tracking request timed out!");
- throw e;
- } catch (IOException e) {
- Log.e("DeviceMonitor", "Sending jdwp tracking request failed!");
- throw e;
- }
- }
-
- private void processIncomingJdwpData(Device device, SocketChannel monitorSocket, int length)
- throws IOException {
-
- // This methods reads @length bytes from the @monitorSocket channel.
- // These bytes correspond to the pids of the current set of processes on the device.
- // It takes this set of pids and compares them with the existing set of clients
- // for the device. Clients that correspond to pids that are not alive anymore are
- // dropped, and new clients are created for pids that don't have a corresponding Client.
-
- if (length >= 0) {
- // array for the current pids.
- Set<Integer> newPids = new HashSet<Integer>();
-
- // get the string data if there are any
- if (length > 0) {
- byte[] buffer = new byte[length];
- String result = read(monitorSocket, buffer);
-
- // split each line in its own list and create an array of integer pid
- String[] pids = result.split("\n"); //$NON-NLS-1$
-
- for (String pid : pids) {
- try {
- newPids.add(Integer.valueOf(pid));
- } catch (NumberFormatException nfe) {
- // looks like this pid is not really a number. Lets ignore it.
- continue;
- }
- }
- }
-
- MonitorThread monitorThread = MonitorThread.getInstance();
-
- List<Client> clients = device.getClientList();
- Map<Integer, Client> existingClients = new HashMap<Integer, Client>();
-
- synchronized (clients) {
- for (Client c : clients) {
- existingClients.put(
- Integer.valueOf(c.getClientData().getPid()),
- c);
- }
- }
-
- Set<Client> clientsToRemove = new HashSet<Client>();
- for (Integer pid : existingClients.keySet()) {
- if (!newPids.contains(pid)) {
- clientsToRemove.add(existingClients.get(pid));
- }
- }
-
- Set<Integer> pidsToAdd = new HashSet<Integer>(newPids);
- pidsToAdd.removeAll(existingClients.keySet());
-
- monitorThread.dropClients(clientsToRemove, false);
-
- // at this point whatever pid is left in the list needs to be converted into Clients.
- for (int newPid : pidsToAdd) {
- openClient(device, newPid, getNextDebuggerPort(), monitorThread);
- }
-
- if (pidsToAdd.size() > 0 || clientsToRemove.size() > 0) {
- mServer.deviceChanged(device, Device.CHANGE_CLIENT_LIST);
- }
- }
- }
-
- /**
- * Opens and creates a new client.
- * @return
- */
- private void openClient(Device device, int pid, int port, MonitorThread monitorThread) {
-
- SocketChannel clientSocket;
- try {
- clientSocket = AdbHelper.createPassThroughConnection(
- AndroidDebugBridge.getSocketAddress(), device, pid);
-
- // required for Selector
- clientSocket.configureBlocking(false);
- } catch (UnknownHostException uhe) {
- Log.d("DeviceMonitor", "Unknown Jdwp pid: " + pid);
- return;
- } catch (TimeoutException e) {
- Log.w("DeviceMonitor",
- "Failed to connect to client '" + pid + "': timeout");
- return;
- } catch (AdbCommandRejectedException e) {
- Log.w("DeviceMonitor",
- "Adb rejected connection to client '" + pid + "': " + e.getMessage());
- return;
-
- } catch (IOException ioe) {
- Log.w("DeviceMonitor",
- "Failed to connect to client '" + pid + "': " + ioe.getMessage());
- return ;
- }
-
- createClient(device, pid, clientSocket, port, monitorThread);
- }
-
- /**
- * Creates a client and register it to the monitor thread
- * @param device
- * @param pid
- * @param socket
- * @param debuggerPort the debugger port.
- * @param monitorThread the {@link MonitorThread} object.
- */
- private void createClient(Device device, int pid, SocketChannel socket, int debuggerPort,
- MonitorThread monitorThread) {
-
- /*
- * Successfully connected to something. Create a Client object, add
- * it to the list, and initiate the JDWP handshake.
- */
-
- Client client = new Client(device, socket, pid);
-
- if (client.sendHandshake()) {
- try {
- if (AndroidDebugBridge.getClientSupport()) {
- client.listenForDebugger(debuggerPort);
- }
- } catch (IOException ioe) {
- client.getClientData().setDebuggerConnectionStatus(DebuggerStatus.ERROR);
- Log.e("ddms", "Can't bind to local " + debuggerPort + " for debugger");
- // oh well
- }
-
- client.requestAllocationStatus();
- } else {
- Log.e("ddms", "Handshake with " + client + " failed!");
- /*
- * The handshake send failed. We could remove it now, but if the
- * failure is "permanent" we'll just keep banging on it and
- * getting the same result. Keep it in the list with its "error"
- * state so we don't try to reopen it.
- */
- }
-
- if (client.isValid()) {
- device.addClient(client);
- monitorThread.addClient(client);
- } else {
- client = null;
- }
- }
-
- private int getNextDebuggerPort() {
- // get the first port and remove it
- synchronized (mDebuggerPorts) {
- if (mDebuggerPorts.size() > 0) {
- int port = mDebuggerPorts.get(0);
-
- // remove it.
- mDebuggerPorts.remove(0);
-
- // if there's nothing left, add the next port to the list
- if (mDebuggerPorts.size() == 0) {
- mDebuggerPorts.add(port+1);
- }
-
- return port;
- }
- }
-
- return -1;
- }
-
- void addPortToAvailableList(int port) {
- if (port > 0) {
- synchronized (mDebuggerPorts) {
- // because there could be case where clients are closed twice, we have to make
- // sure the port number is not already in the list.
- if (mDebuggerPorts.indexOf(port) == -1) {
- // add the port to the list while keeping it sorted. It's not like there's
- // going to be tons of objects so we do it linearly.
- int count = mDebuggerPorts.size();
- for (int i = 0 ; i < count ; i++) {
- if (port < mDebuggerPorts.get(i)) {
- mDebuggerPorts.add(i, port);
- break;
- }
- }
- // TODO: check if we can compact the end of the list.
- }
- }
- }
- }
-
- /**
- * Reads the length of the next message from a socket.
- * @param socket The {@link SocketChannel} to read from.
- * @return the length, or 0 (zero) if no data is available from the socket.
- * @throws IOException if the connection failed.
- */
- private int readLength(SocketChannel socket, byte[] buffer) throws IOException {
- String msg = read(socket, buffer);
-
- if (msg != null) {
- try {
- return Integer.parseInt(msg, 16);
- } catch (NumberFormatException nfe) {
- // we'll throw an exception below.
- }
- }
-
- // we receive something we can't read. It's better to reset the connection at this point.
- throw new IOException("Unable to read length");
- }
-
- /**
- * Fills a buffer from a socket.
- * @param socket
- * @param buffer
- * @return the content of the buffer as a string, or null if it failed to convert the buffer.
- * @throws IOException
- */
- private String read(SocketChannel socket, byte[] buffer) throws IOException {
- ByteBuffer buf = ByteBuffer.wrap(buffer, 0, buffer.length);
-
- while (buf.position() != buf.limit()) {
- int count;
-
- count = socket.read(buf);
- if (count < 0) {
- throw new IOException("EOF");
- }
- }
-
- try {
- return new String(buffer, 0, buf.position(), AdbHelper.DEFAULT_ENCODING);
- } catch (UnsupportedEncodingException e) {
- // we'll return null below.
- }
-
- return null;
- }
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/EmulatorConsole.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/EmulatorConsole.java
deleted file mode 100644
index 2f4175f..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/EmulatorConsole.java
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-import java.security.InvalidParameterException;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Provides control over emulated hardware of the Android emulator.
- * <p/>This is basically a wrapper around the command line console normally used with telnet.
- *<p/>
- * Regarding line termination handling:<br>
- * One of the issues is that the telnet protocol <b>requires</b> usage of <code>\r\n</code>. Most
- * implementations don't enforce it (the dos one does). In this particular case, this is mostly
- * irrelevant since we don't use telnet in Java, but that means we want to make
- * sure we use the same line termination than what the console expects. The console
- * code removes <code>\r</code> and waits for <code>\n</code>.
- * <p/>However this means you <i>may</i> receive <code>\r\n</code> when reading from the console.
- * <p/>
- * <b>This API will change in the near future.</b>
- */
-public final class EmulatorConsole {
-
- private final static String DEFAULT_ENCODING = "ISO-8859-1"; //$NON-NLS-1$
-
- private final static int WAIT_TIME = 5; // spin-wait sleep, in ms
-
- private final static int STD_TIMEOUT = 5000; // standard delay, in ms
-
- private final static String HOST = "127.0.0.1"; //$NON-NLS-1$
-
- private final static String COMMAND_PING = "help\r\n"; //$NON-NLS-1$
- private final static String COMMAND_AVD_NAME = "avd name\r\n"; //$NON-NLS-1$
- private final static String COMMAND_KILL = "kill\r\n"; //$NON-NLS-1$
- private final static String COMMAND_GSM_STATUS = "gsm status\r\n"; //$NON-NLS-1$
- private final static String COMMAND_GSM_CALL = "gsm call %1$s\r\n"; //$NON-NLS-1$
- private final static String COMMAND_GSM_CANCEL_CALL = "gsm cancel %1$s\r\n"; //$NON-NLS-1$
- private final static String COMMAND_GSM_DATA = "gsm data %1$s\r\n"; //$NON-NLS-1$
- private final static String COMMAND_GSM_VOICE = "gsm voice %1$s\r\n"; //$NON-NLS-1$
- private final static String COMMAND_SMS_SEND = "sms send %1$s %2$s\r\n"; //$NON-NLS-1$
- private final static String COMMAND_NETWORK_STATUS = "network status\r\n"; //$NON-NLS-1$
- private final static String COMMAND_NETWORK_SPEED = "network speed %1$s\r\n"; //$NON-NLS-1$
- private final static String COMMAND_NETWORK_LATENCY = "network delay %1$s\r\n"; //$NON-NLS-1$
- private final static String COMMAND_GPS = "geo fix %1$f %2$f %3$f\r\n"; //$NON-NLS-1$
-
- private final static Pattern RE_KO = Pattern.compile("KO:\\s+(.*)"); //$NON-NLS-1$
-
- /**
- * Array of delay values: no delay, gprs, edge/egprs, umts/3d
- */
- public final static int[] MIN_LATENCIES = new int[] {
- 0, // No delay
- 150, // gprs
- 80, // edge/egprs
- 35 // umts/3g
- };
-
- /**
- * Array of download speeds: full speed, gsm, hscsd, gprs, edge/egprs, umts/3g, hsdpa.
- */
- public final int[] DOWNLOAD_SPEEDS = new int[] {
- 0, // full speed
- 14400, // gsm
- 43200, // hscsd
- 80000, // gprs
- 236800, // edge/egprs
- 1920000, // umts/3g
- 14400000 // hsdpa
- };
-
- /** Arrays of valid network speeds */
- public final static String[] NETWORK_SPEEDS = new String[] {
- "full", //$NON-NLS-1$
- "gsm", //$NON-NLS-1$
- "hscsd", //$NON-NLS-1$
- "gprs", //$NON-NLS-1$
- "edge", //$NON-NLS-1$
- "umts", //$NON-NLS-1$
- "hsdpa", //$NON-NLS-1$
- };
-
- /** Arrays of valid network latencies */
- public final static String[] NETWORK_LATENCIES = new String[] {
- "none", //$NON-NLS-1$
- "gprs", //$NON-NLS-1$
- "edge", //$NON-NLS-1$
- "umts", //$NON-NLS-1$
- };
-
- /** Gsm Mode enum. */
- public static enum GsmMode {
- UNKNOWN((String)null),
- UNREGISTERED(new String[] { "unregistered", "off" }),
- HOME(new String[] { "home", "on" }),
- ROAMING("roaming"),
- SEARCHING("searching"),
- DENIED("denied");
-
- private final String[] tags;
-
- GsmMode(String tag) {
- if (tag != null) {
- this.tags = new String[] { tag };
- } else {
- this.tags = new String[0];
- }
- }
-
- GsmMode(String[] tags) {
- this.tags = tags;
- }
-
- public static GsmMode getEnum(String tag) {
- for (GsmMode mode : values()) {
- for (String t : mode.tags) {
- if (t.equals(tag)) {
- return mode;
- }
- }
- }
- return UNKNOWN;
- }
-
- /**
- * Returns the first tag of the enum.
- */
- public String getTag() {
- if (tags.length > 0) {
- return tags[0];
- }
- return null;
- }
- }
-
- public final static String RESULT_OK = null;
-
- private final static Pattern sEmulatorRegexp = Pattern.compile(Device.RE_EMULATOR_SN);
- private final static Pattern sVoiceStatusRegexp = Pattern.compile(
- "gsm\\s+voice\\s+state:\\s*([a-z]+)", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
- private final static Pattern sDataStatusRegexp = Pattern.compile(
- "gsm\\s+data\\s+state:\\s*([a-z]+)", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
- private final static Pattern sDownloadSpeedRegexp = Pattern.compile(
- "\\s+download\\s+speed:\\s+(\\d+)\\s+bits.*", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
- private final static Pattern sMinLatencyRegexp = Pattern.compile(
- "\\s+minimum\\s+latency:\\s+(\\d+)\\s+ms", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
-
- private final static HashMap<Integer, EmulatorConsole> sEmulators =
- new HashMap<Integer, EmulatorConsole>();
-
- /** Gsm Status class */
- public static class GsmStatus {
- /** Voice status. */
- public GsmMode voice = GsmMode.UNKNOWN;
- /** Data status. */
- public GsmMode data = GsmMode.UNKNOWN;
- }
-
- /** Network Status class */
- public static class NetworkStatus {
- /** network speed status. This is an index in the {@link #DOWNLOAD_SPEEDS} array. */
- public int speed = -1;
- /** network latency status. This is an index in the {@link #MIN_LATENCIES} array. */
- public int latency = -1;
- }
-
- private int mPort;
-
- private SocketChannel mSocketChannel;
-
- private byte[] mBuffer = new byte[1024];
-
- /**
- * Returns an {@link EmulatorConsole} object for the given {@link Device}. This can
- * be an already existing console, or a new one if it hadn't been created yet.
- * @param d The device that the console links to.
- * @return an <code>EmulatorConsole</code> object or <code>null</code> if the connection failed.
- */
- public static synchronized EmulatorConsole getConsole(IDevice d) {
- // we need to make sure that the device is an emulator
- // get the port number. This is the console port.
- Integer port = getEmulatorPort(d.getSerialNumber());
- if (port == null) {
- return null;
- }
-
- EmulatorConsole console = sEmulators.get(port);
-
- if (console != null) {
- // if the console exist, we ping the emulator to check the connection.
- if (console.ping() == false) {
- RemoveConsole(console.mPort);
- console = null;
- }
- }
-
- if (console == null) {
- // no console object exists for this port so we create one, and start
- // the connection.
- console = new EmulatorConsole(port);
- if (console.start()) {
- sEmulators.put(port, console);
- } else {
- console = null;
- }
- }
-
- return console;
- }
-
- /**
- * Return port of emulator given its serial number.
- *
- * @param serialNumber the emulator's serial number
- * @return the integer port or <code>null</code> if it could not be determined
- */
- public static Integer getEmulatorPort(String serialNumber) {
- Matcher m = sEmulatorRegexp.matcher(serialNumber);
- if (m.matches()) {
- // get the port number. This is the console port.
- int port;
- try {
- port = Integer.parseInt(m.group(1));
- if (port > 0) {
- return port;
- }
- } catch (NumberFormatException e) {
- // looks like we failed to get the port number. This is a bit strange since
- // it's coming from a regexp that only accept digit, but we handle the case
- // and return null.
- }
- }
- return null;
- }
-
- /**
- * Removes the console object associated with a port from the map.
- * @param port The port of the console to remove.
- */
- private static synchronized void RemoveConsole(int port) {
- sEmulators.remove(port);
- }
-
- private EmulatorConsole(int port) {
- super();
- mPort = port;
- }
-
- /**
- * Starts the connection of the console.
- * @return true if success.
- */
- private boolean start() {
-
- InetSocketAddress socketAddr;
- try {
- InetAddress hostAddr = InetAddress.getByName(HOST);
- socketAddr = new InetSocketAddress(hostAddr, mPort);
- } catch (UnknownHostException e) {
- return false;
- }
-
- try {
- mSocketChannel = SocketChannel.open(socketAddr);
- } catch (IOException e1) {
- return false;
- }
-
- // read some stuff from it
- readLines();
-
- return true;
- }
-
- /**
- * Ping the emulator to check if the connection is still alive.
- * @return true if the connection is alive.
- */
- private synchronized boolean ping() {
- // it looks like we can send stuff, even when the emulator quit, but we can't read
- // from the socket. So we check the return of readLines()
- if (sendCommand(COMMAND_PING)) {
- return readLines() != null;
- }
-
- return false;
- }
-
- /**
- * Sends a KILL command to the emulator.
- */
- public synchronized void kill() {
- if (sendCommand(COMMAND_KILL)) {
- RemoveConsole(mPort);
- }
- }
-
- public synchronized String getAvdName() {
- if (sendCommand(COMMAND_AVD_NAME)) {
- String[] result = readLines();
- if (result != null && result.length == 2) { // this should be the name on first line,
- // and ok on 2nd line
- return result[0];
- } else {
- // try to see if there's a message after KO
- Matcher m = RE_KO.matcher(result[result.length-1]);
- if (m.matches()) {
- return m.group(1);
- }
- }
- }
-
- return null;
- }
-
- /**
- * Get the network status of the emulator.
- * @return a {@link NetworkStatus} object containing the {@link GsmStatus}, or
- * <code>null</code> if the query failed.
- */
- public synchronized NetworkStatus getNetworkStatus() {
- if (sendCommand(COMMAND_NETWORK_STATUS)) {
- /* Result is in the format
- Current network status:
- download speed: 14400 bits/s (1.8 KB/s)
- upload speed: 14400 bits/s (1.8 KB/s)
- minimum latency: 0 ms
- maximum latency: 0 ms
- */
- String[] result = readLines();
-
- if (isValid(result)) {
- // we only compare agains the min latency and the download speed
- // let's not rely on the order of the output, and simply loop through
- // the line testing the regexp.
- NetworkStatus status = new NetworkStatus();
- for (String line : result) {
- Matcher m = sDownloadSpeedRegexp.matcher(line);
- if (m.matches()) {
- // get the string value
- String value = m.group(1);
-
- // get the index from the list
- status.speed = getSpeedIndex(value);
-
- // move on to next line.
- continue;
- }
-
- m = sMinLatencyRegexp.matcher(line);
- if (m.matches()) {
- // get the string value
- String value = m.group(1);
-
- // get the index from the list
- status.latency = getLatencyIndex(value);
-
- // move on to next line.
- continue;
- }
- }
-
- return status;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the current gsm status of the emulator
- * @return a {@link GsmStatus} object containing the gms status, or <code>null</code>
- * if the query failed.
- */
- public synchronized GsmStatus getGsmStatus() {
- if (sendCommand(COMMAND_GSM_STATUS)) {
- /*
- * result is in the format:
- * gsm status
- * gsm voice state: home
- * gsm data state: home
- */
-
- String[] result = readLines();
- if (isValid(result)) {
-
- GsmStatus status = new GsmStatus();
-
- // let's not rely on the order of the output, and simply loop through
- // the line testing the regexp.
- for (String line : result) {
- Matcher m = sVoiceStatusRegexp.matcher(line);
- if (m.matches()) {
- // get the string value
- String value = m.group(1);
-
- // get the index from the list
- status.voice = GsmMode.getEnum(value.toLowerCase(Locale.US));
-
- // move on to next line.
- continue;
- }
-
- m = sDataStatusRegexp.matcher(line);
- if (m.matches()) {
- // get the string value
- String value = m.group(1);
-
- // get the index from the list
- status.data = GsmMode.getEnum(value.toLowerCase(Locale.US));
-
- // move on to next line.
- continue;
- }
- }
-
- return status;
- }
- }
-
- return null;
- }
-
- /**
- * Sets the GSM voice mode.
- * @param mode the {@link GsmMode} value.
- * @return RESULT_OK if success, an error String otherwise.
- * @throws InvalidParameterException if mode is an invalid value.
- */
- public synchronized String setGsmVoiceMode(GsmMode mode) throws InvalidParameterException {
- if (mode == GsmMode.UNKNOWN) {
- throw new InvalidParameterException();
- }
-
- String command = String.format(COMMAND_GSM_VOICE, mode.getTag());
- return processCommand(command);
- }
-
- /**
- * Sets the GSM data mode.
- * @param mode the {@link GsmMode} value
- * @return {@link #RESULT_OK} if success, an error String otherwise.
- * @throws InvalidParameterException if mode is an invalid value.
- */
- public synchronized String setGsmDataMode(GsmMode mode) throws InvalidParameterException {
- if (mode == GsmMode.UNKNOWN) {
- throw new InvalidParameterException();
- }
-
- String command = String.format(COMMAND_GSM_DATA, mode.getTag());
- return processCommand(command);
- }
-
- /**
- * Initiate an incoming call on the emulator.
- * @param number a string representing the calling number.
- * @return {@link #RESULT_OK} if success, an error String otherwise.
- */
- public synchronized String call(String number) {
- String command = String.format(COMMAND_GSM_CALL, number);
- return processCommand(command);
- }
-
- /**
- * Cancels a current call.
- * @param number the number of the call to cancel
- * @return {@link #RESULT_OK} if success, an error String otherwise.
- */
- public synchronized String cancelCall(String number) {
- String command = String.format(COMMAND_GSM_CANCEL_CALL, number);
- return processCommand(command);
- }
-
- /**
- * Sends an SMS to the emulator
- * @param number The sender phone number
- * @param message The SMS message. \ characters must be escaped. The carriage return is
- * the 2 character sequence {'\', 'n' }
- *
- * @return {@link #RESULT_OK} if success, an error String otherwise.
- */
- public synchronized String sendSms(String number, String message) {
- String command = String.format(COMMAND_SMS_SEND, number, message);
- return processCommand(command);
- }
-
- /**
- * Sets the network speed.
- * @param selectionIndex The index in the {@link #NETWORK_SPEEDS} table.
- * @return {@link #RESULT_OK} if success, an error String otherwise.
- */
- public synchronized String setNetworkSpeed(int selectionIndex) {
- String command = String.format(COMMAND_NETWORK_SPEED, NETWORK_SPEEDS[selectionIndex]);
- return processCommand(command);
- }
-
- /**
- * Sets the network latency.
- * @param selectionIndex The index in the {@link #NETWORK_LATENCIES} table.
- * @return {@link #RESULT_OK} if success, an error String otherwise.
- */
- public synchronized String setNetworkLatency(int selectionIndex) {
- String command = String.format(COMMAND_NETWORK_LATENCY, NETWORK_LATENCIES[selectionIndex]);
- return processCommand(command);
- }
-
- public synchronized String sendLocation(double longitude, double latitude, double elevation) {
-
- // need to make sure the string format uses dot and not comma
- Formatter formatter = new Formatter(Locale.US);
- try {
- formatter.format(COMMAND_GPS, longitude, latitude, elevation);
-
- return processCommand(formatter.toString());
- } finally {
- formatter.close();
- }
- }
-
- /**
- * Sends a command to the emulator console.
- * @param command The command string. <b>MUST BE TERMINATED BY \n</b>.
- * @return true if success
- */
- private boolean sendCommand(String command) {
- boolean result = false;
- try {
- byte[] bCommand;
- try {
- bCommand = command.getBytes(DEFAULT_ENCODING);
- } catch (UnsupportedEncodingException e) {
- // wrong encoding...
- return result;
- }
-
- // write the command
- AdbHelper.write(mSocketChannel, bCommand, bCommand.length, DdmPreferences.getTimeOut());
-
- result = true;
- } catch (Exception e) {
- return false;
- } finally {
- if (result == false) {
- // FIXME connection failed somehow, we need to disconnect the console.
- RemoveConsole(mPort);
- }
- }
-
- return result;
- }
-
- /**
- * Sends a command to the emulator and parses its answer.
- * @param command the command to send.
- * @return {@link #RESULT_OK} if success, an error message otherwise.
- */
- private String processCommand(String command) {
- if (sendCommand(command)) {
- String[] result = readLines();
-
- if (result != null && result.length > 0) {
- Matcher m = RE_KO.matcher(result[result.length-1]);
- if (m.matches()) {
- return m.group(1);
- }
- return RESULT_OK;
- }
-
- return "Unable to communicate with the emulator";
- }
-
- return "Unable to send command to the emulator";
- }
-
- /**
- * Reads line from the console socket. This call is blocking until we read the lines:
- * <ul>
- * <li>OK\r\n</li>
- * <li>KO<msg>\r\n</li>
- * </ul>
- * @return the array of strings read from the emulator.
- */
- private String[] readLines() {
- try {
- ByteBuffer buf = ByteBuffer.wrap(mBuffer, 0, mBuffer.length);
- int numWaits = 0;
- boolean stop = false;
-
- while (buf.position() != buf.limit() && stop == false) {
- int count;
-
- count = mSocketChannel.read(buf);
- if (count < 0) {
- return null;
- } else if (count == 0) {
- if (numWaits * WAIT_TIME > STD_TIMEOUT) {
- return null;
- }
- // non-blocking spin
- try {
- Thread.sleep(WAIT_TIME);
- } catch (InterruptedException ie) {
- }
- numWaits++;
- } else {
- numWaits = 0;
- }
-
- // check the last few char aren't OK. For a valid message to test
- // we need at least 4 bytes (OK/KO + \r\n)
- if (buf.position() >= 4) {
- int pos = buf.position();
- if (endsWithOK(pos) || lastLineIsKO(pos)) {
- stop = true;
- }
- }
- }
-
- String msg = new String(mBuffer, 0, buf.position(), DEFAULT_ENCODING);
- return msg.split("\r\n"); //$NON-NLS-1$
- } catch (IOException e) {
- return null;
- }
- }
-
- /**
- * Returns true if the 4 characters *before* the current position are "OK\r\n"
- * @param currentPosition The current position
- */
- private boolean endsWithOK(int currentPosition) {
- if (mBuffer[currentPosition-1] == '\n' &&
- mBuffer[currentPosition-2] == '\r' &&
- mBuffer[currentPosition-3] == 'K' &&
- mBuffer[currentPosition-4] == 'O') {
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns true if the last line starts with KO and is also terminated by \r\n
- * @param currentPosition the current position
- */
- private boolean lastLineIsKO(int currentPosition) {
- // first check that the last 2 characters are CRLF
- if (mBuffer[currentPosition-1] != '\n' ||
- mBuffer[currentPosition-2] != '\r') {
- return false;
- }
-
- // now loop backward looking for the previous CRLF, or the beginning of the buffer
- int i = 0;
- for (i = currentPosition-3 ; i >= 0; i--) {
- if (mBuffer[i] == '\n') {
- // found \n!
- if (i > 0 && mBuffer[i-1] == '\r') {
- // found \r!
- break;
- }
- }
- }
-
- // here it is either -1 if we reached the start of the buffer without finding
- // a CRLF, or the position of \n. So in both case we look at the characters at i+1 and i+2
- if (mBuffer[i+1] == 'K' && mBuffer[i+2] == 'O') {
- // found error!
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns true if the last line of the result does not start with KO
- */
- private boolean isValid(String[] result) {
- if (result != null && result.length > 0) {
- return !(RE_KO.matcher(result[result.length-1]).matches());
- }
- return false;
- }
-
- private int getLatencyIndex(String value) {
- try {
- // get the int value
- int latency = Integer.parseInt(value);
-
- // check for the speed from the index
- for (int i = 0 ; i < MIN_LATENCIES.length; i++) {
- if (MIN_LATENCIES[i] == latency) {
- return i;
- }
- }
- } catch (NumberFormatException e) {
- // Do nothing, we'll just return -1.
- }
-
- return -1;
- }
-
- private int getSpeedIndex(String value) {
- try {
- // get the int value
- int speed = Integer.parseInt(value);
-
- // check for the speed from the index
- for (int i = 0 ; i < DOWNLOAD_SPEEDS.length; i++) {
- if (DOWNLOAD_SPEEDS[i] == speed) {
- return i;
- }
- }
- } catch (NumberFormatException e) {
- // Do nothing, we'll just return -1.
- }
-
- return -1;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/FileListingService.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/FileListingService.java
deleted file mode 100644
index 97c57b9..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/FileListingService.java
+++ /dev/null
@@ -1,855 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Provides {@link Device} side file listing service.
- * <p/>To get an instance for a known {@link Device}, call {@link Device#getFileListingService()}.
- */
-public final class FileListingService {
-
- /** Pattern to find filenames that match "*.apk" */
- private final static Pattern sApkPattern =
- Pattern.compile(".*\\.apk", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
-
- private final static String PM_FULL_LISTING = "pm list packages -f"; //$NON-NLS-1$
-
- /** Pattern to parse the output of the 'pm -lf' command.<br>
- * The output format looks like:<br>
- * /data/app/myapp.apk=com.mypackage.myapp */
- private final static Pattern sPmPattern = Pattern.compile("^package:(.+?)=(.+)$"); //$NON-NLS-1$
-
- /** Top level data folder. */
- public final static String DIRECTORY_DATA = "data"; //$NON-NLS-1$
- /** Top level sdcard folder. */
- public final static String DIRECTORY_SDCARD = "sdcard"; //$NON-NLS-1$
- /** Top level mount folder. */
- public final static String DIRECTORY_MNT = "mnt"; //$NON-NLS-1$
- /** Top level system folder. */
- public final static String DIRECTORY_SYSTEM = "system"; //$NON-NLS-1$
- /** Top level temp folder. */
- public final static String DIRECTORY_TEMP = "tmp"; //$NON-NLS-1$
- /** Application folder. */
- public final static String DIRECTORY_APP = "app"; //$NON-NLS-1$
-
- public static final long REFRESH_RATE = 5000L;
- /**
- * Refresh test has to be slightly lower for precision issue.
- */
- static final long REFRESH_TEST = (long)(REFRESH_RATE * .8);
-
- /** Entry type: File */
- public static final int TYPE_FILE = 0;
- /** Entry type: Directory */
- public static final int TYPE_DIRECTORY = 1;
- /** Entry type: Directory Link */
- public static final int TYPE_DIRECTORY_LINK = 2;
- /** Entry type: Block */
- public static final int TYPE_BLOCK = 3;
- /** Entry type: Character */
- public static final int TYPE_CHARACTER = 4;
- /** Entry type: Link */
- public static final int TYPE_LINK = 5;
- /** Entry type: Socket */
- public static final int TYPE_SOCKET = 6;
- /** Entry type: FIFO */
- public static final int TYPE_FIFO = 7;
- /** Entry type: Other */
- public static final int TYPE_OTHER = 8;
-
- /** Device side file separator. */
- public static final String FILE_SEPARATOR = "/"; //$NON-NLS-1$
-
- private static final String FILE_ROOT = "/"; //$NON-NLS-1$
-
-
- /**
- * Regexp pattern to parse the result from ls.
- */
- private static final Pattern LS_L_PATTERN = Pattern.compile(
- "^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+(\\S+)\\s+(\\S+)\\s+" +
- "([\\d\\s,]*)\\s+(\\d{4}-\\d\\d-\\d\\d)\\s+(\\d\\d:\\d\\d)\\s+(.*)$"); //$NON-NLS-1$
-
- private static final Pattern LS_LD_PATTERN = Pattern.compile(
- "d[rwx-]{9}\\s+\\S+\\s+\\S+\\s+[0-9-]{10}\\s+\\d{2}:\\d{2}$"); //$NON-NLS-1$
-
-
- private Device mDevice;
- private FileEntry mRoot;
-
- private ArrayList<Thread> mThreadList = new ArrayList<Thread>();
-
- /**
- * Represents an entry in a directory. This can be a file or a directory.
- */
- public final static class FileEntry {
- /** Pattern to escape filenames for shell command consumption.
- * This pattern identifies any special characters that need to be escaped with a
- * backslash. */
- private final static Pattern sEscapePattern = Pattern.compile(
- "([\\\\()*+?\"'&#/\\s])"); //$NON-NLS-1$
-
- /**
- * Comparator object for FileEntry
- */
- private static Comparator<FileEntry> sEntryComparator = new Comparator<FileEntry>() {
- @Override
- public int compare(FileEntry o1, FileEntry o2) {
- if (o1 instanceof FileEntry && o2 instanceof FileEntry) {
- FileEntry fe1 = o1;
- FileEntry fe2 = o2;
- return fe1.name.compareTo(fe2.name);
- }
- return 0;
- }
- };
-
- FileEntry parent;
- String name;
- String info;
- String permissions;
- String size;
- String date;
- String time;
- String owner;
- String group;
- int type;
- boolean isAppPackage;
-
- boolean isRoot;
-
- /**
- * Indicates whether the entry content has been fetched yet, or not.
- */
- long fetchTime = 0;
-
- final ArrayList<FileEntry> mChildren = new ArrayList<FileEntry>();
-
- /**
- * Creates a new file entry.
- * @param parent parent entry or null if entry is root
- * @param name name of the entry.
- * @param type entry type. Can be one of the following: {@link FileListingService#TYPE_FILE},
- * {@link FileListingService#TYPE_DIRECTORY}, {@link FileListingService#TYPE_OTHER}.
- */
- private FileEntry(FileEntry parent, String name, int type, boolean isRoot) {
- this.parent = parent;
- this.name = name;
- this.type = type;
- this.isRoot = isRoot;
-
- checkAppPackageStatus();
- }
-
- /**
- * Returns the name of the entry
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the size string of the entry, as returned by <code>ls</code>.
- */
- public String getSize() {
- return size;
- }
-
- /**
- * Returns the size of the entry.
- */
- public int getSizeValue() {
- return Integer.parseInt(size);
- }
-
- /**
- * Returns the date string of the entry, as returned by <code>ls</code>.
- */
- public String getDate() {
- return date;
- }
-
- /**
- * Returns the time string of the entry, as returned by <code>ls</code>.
- */
- public String getTime() {
- return time;
- }
-
- /**
- * Returns the permission string of the entry, as returned by <code>ls</code>.
- */
- public String getPermissions() {
- return permissions;
- }
-
- /**
- * Returns the owner string of the entry, as returned by <code>ls</code>.
- */
- public String getOwner() {
- return owner;
- }
-
- /**
- * Returns the group owner of the entry, as returned by <code>ls</code>.
- */
- public String getGroup() {
- return group;
- }
-
- /**
- * Returns the extra info for the entry.
- * <p/>For a link, it will be a description of the link.
- * <p/>For an application apk file it will be the application package as returned
- * by the Package Manager.
- */
- public String getInfo() {
- return info;
- }
-
- /**
- * Return the full path of the entry.
- * @return a path string using {@link FileListingService#FILE_SEPARATOR} as separator.
- */
- public String getFullPath() {
- if (isRoot) {
- return FILE_ROOT;
- }
- StringBuilder pathBuilder = new StringBuilder();
- fillPathBuilder(pathBuilder, false);
-
- return pathBuilder.toString();
- }
-
- /**
- * Return the fully escaped path of the entry. This path is safe to use in a
- * shell command line.
- * @return a path string using {@link FileListingService#FILE_SEPARATOR} as separator
- */
- public String getFullEscapedPath() {
- StringBuilder pathBuilder = new StringBuilder();
- fillPathBuilder(pathBuilder, true);
-
- return pathBuilder.toString();
- }
-
- /**
- * Returns the path as a list of segments.
- */
- public String[] getPathSegments() {
- ArrayList<String> list = new ArrayList<String>();
- fillPathSegments(list);
-
- return list.toArray(new String[list.size()]);
- }
-
- /**
- * Returns the Entry type as an int, which will match one of the TYPE_(...) constants
- */
- public int getType() {
- return type;
- }
-
- /**
- * Sets a new type.
- */
- public void setType(int type) {
- this.type = type;
- }
-
- /**
- * Returns if the entry is a folder or a link to a folder.
- */
- public boolean isDirectory() {
- return type == TYPE_DIRECTORY || type == TYPE_DIRECTORY_LINK;
- }
-
- /**
- * Returns the parent entry.
- */
- public FileEntry getParent() {
- return parent;
- }
-
- /**
- * Returns the cached children of the entry. This returns the cache created from calling
- * <code>FileListingService.getChildren()</code>.
- */
- public FileEntry[] getCachedChildren() {
- return mChildren.toArray(new FileEntry[mChildren.size()]);
- }
-
- /**
- * Returns the child {@link FileEntry} matching the name.
- * This uses the cached children list.
- * @param name the name of the child to return.
- * @return the FileEntry matching the name or null.
- */
- public FileEntry findChild(String name) {
- for (FileEntry entry : mChildren) {
- if (entry.name.equals(name)) {
- return entry;
- }
- }
- return null;
- }
-
- /**
- * Returns whether the entry is the root.
- */
- public boolean isRoot() {
- return isRoot;
- }
-
- void addChild(FileEntry child) {
- mChildren.add(child);
- }
-
- void setChildren(ArrayList<FileEntry> newChildren) {
- mChildren.clear();
- mChildren.addAll(newChildren);
- }
-
- boolean needFetch() {
- if (fetchTime == 0) {
- return true;
- }
- long current = System.currentTimeMillis();
- if (current-fetchTime > REFRESH_TEST) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns if the entry is a valid application package.
- */
- public boolean isApplicationPackage() {
- return isAppPackage;
- }
-
- /**
- * Returns if the file name is an application package name.
- */
- public boolean isAppFileName() {
- Matcher m = sApkPattern.matcher(name);
- return m.matches();
- }
-
- /**
- * Recursively fills the pathBuilder with the full path
- * @param pathBuilder a StringBuilder used to create the path.
- * @param escapePath Whether the path need to be escaped for consumption by
- * a shell command line.
- */
- protected void fillPathBuilder(StringBuilder pathBuilder, boolean escapePath) {
- if (isRoot) {
- return;
- }
-
- if (parent != null) {
- parent.fillPathBuilder(pathBuilder, escapePath);
- }
- pathBuilder.append(FILE_SEPARATOR);
- pathBuilder.append(escapePath ? escape(name) : name);
- }
-
- /**
- * Recursively fills the segment list with the full path.
- * @param list The list of segments to fill.
- */
- protected void fillPathSegments(ArrayList<String> list) {
- if (isRoot) {
- return;
- }
-
- if (parent != null) {
- parent.fillPathSegments(list);
- }
-
- list.add(name);
- }
-
- /**
- * Sets the internal app package status flag. This checks whether the entry is in an app
- * directory like /data/app or /system/app
- */
- private void checkAppPackageStatus() {
- isAppPackage = false;
-
- String[] segments = getPathSegments();
- if (type == TYPE_FILE && segments.length == 3 && isAppFileName()) {
- isAppPackage = DIRECTORY_APP.equals(segments[1]) &&
- (DIRECTORY_SYSTEM.equals(segments[0]) || DIRECTORY_DATA.equals(segments[0]));
- }
- }
-
- /**
- * Returns an escaped version of the entry name.
- * @param entryName
- */
- public static String escape(String entryName) {
- return sEscapePattern.matcher(entryName).replaceAll("\\\\$1"); //$NON-NLS-1$
- }
- }
-
- private static class LsReceiver extends MultiLineReceiver {
-
- private ArrayList<FileEntry> mEntryList;
- private ArrayList<String> mLinkList;
- private FileEntry[] mCurrentChildren;
- private FileEntry mParentEntry;
-
- /**
- * Create an ls receiver/parser.
- * @param currentChildren The list of current children. To prevent
- * collapse during update, reusing the same FileEntry objects for
- * files that were already there is paramount.
- * @param entryList the list of new children to be filled by the
- * receiver.
- * @param linkList the list of link path to compute post ls, to figure
- * out if the link pointed to a file or to a directory.
- */
- public LsReceiver(FileEntry parentEntry, ArrayList<FileEntry> entryList,
- ArrayList<String> linkList) {
- mParentEntry = parentEntry;
- mCurrentChildren = parentEntry.getCachedChildren();
- mEntryList = entryList;
- mLinkList = linkList;
- }
-
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- // no need to handle empty lines.
- if (line.length() == 0) {
- continue;
- }
-
- // run the line through the regexp
- Matcher m = LS_L_PATTERN.matcher(line);
- if (m.matches() == false) {
- continue;
- }
-
- // get the name
- String name = m.group(7);
-
- // get the rest of the groups
- String permissions = m.group(1);
- String owner = m.group(2);
- String group = m.group(3);
- String size = m.group(4);
- String date = m.group(5);
- String time = m.group(6);
- String info = null;
-
- // and the type
- int objectType = TYPE_OTHER;
- switch (permissions.charAt(0)) {
- case '-' :
- objectType = TYPE_FILE;
- break;
- case 'b' :
- objectType = TYPE_BLOCK;
- break;
- case 'c' :
- objectType = TYPE_CHARACTER;
- break;
- case 'd' :
- objectType = TYPE_DIRECTORY;
- break;
- case 'l' :
- objectType = TYPE_LINK;
- break;
- case 's' :
- objectType = TYPE_SOCKET;
- break;
- case 'p' :
- objectType = TYPE_FIFO;
- break;
- }
-
-
- // now check what we may be linking to
- if (objectType == TYPE_LINK) {
- String[] segments = name.split("\\s->\\s"); //$NON-NLS-1$
-
- // we should have 2 segments
- if (segments.length == 2) {
- // update the entry name to not contain the link
- name = segments[0];
-
- // and the link name
- info = segments[1];
-
- // now get the path to the link
- String[] pathSegments = info.split(FILE_SEPARATOR);
- if (pathSegments.length == 1) {
- // the link is to something in the same directory,
- // unless the link is ..
- if ("..".equals(pathSegments[0])) { //$NON-NLS-1$
- // set the type and we're done.
- objectType = TYPE_DIRECTORY_LINK;
- } else {
- // either we found the object already
- // or we'll find it later.
- }
- }
- }
-
- // add an arrow in front to specify it's a link.
- info = "-> " + info; //$NON-NLS-1$;
- }
-
- // get the entry, either from an existing one, or a new one
- FileEntry entry = getExistingEntry(name);
- if (entry == null) {
- entry = new FileEntry(mParentEntry, name, objectType, false /* isRoot */);
- }
-
- // add some misc info
- entry.permissions = permissions;
- entry.size = size;
- entry.date = date;
- entry.time = time;
- entry.owner = owner;
- entry.group = group;
- if (objectType == TYPE_LINK) {
- entry.info = info;
- }
-
- mEntryList.add(entry);
- }
- }
-
- /**
- * Queries for an already existing Entry per name
- * @param name the name of the entry
- * @return the existing FileEntry or null if no entry with a matching
- * name exists.
- */
- private FileEntry getExistingEntry(String name) {
- for (int i = 0 ; i < mCurrentChildren.length; i++) {
- FileEntry e = mCurrentChildren[i];
-
- // since we're going to "erase" the one we use, we need to
- // check that the item is not null.
- if (e != null) {
- // compare per name, case-sensitive.
- if (name.equals(e.name)) {
- // erase from the list
- mCurrentChildren[i] = null;
-
- // and return the object
- return e;
- }
- }
- }
-
- // couldn't find any matching object, return null
- return null;
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- /**
- * Determine if any symlinks in the <code entries> list are links-to-directories, and if so
- * mark them as such. This allows us to traverse them properly later on.
- */
- public void finishLinks(IDevice device, ArrayList<FileEntry> entries)
- throws TimeoutException, AdbCommandRejectedException,
- ShellCommandUnresponsiveException, IOException {
- final int[] nLines = {0};
- MultiLineReceiver receiver = new MultiLineReceiver() {
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- Matcher m = LS_LD_PATTERN.matcher(line);
- if (m.matches()) {
- nLines[0]++;
- }
- }
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
- };
-
- for (FileEntry entry : entries) {
- if (entry.getType() != TYPE_LINK) continue;
-
- // We simply need to determine whether the referent is a directory or not.
- // We do this by running `ls -ld ${link}/`. If the referent exists and is a
- // directory, we'll see the normal directory listing. Otherwise, we'll see an
- // error of some sort.
- nLines[0] = 0;
-
- final String command = String.format("ls -l -d %s%s", entry.getFullEscapedPath(),
- FILE_SEPARATOR);
-
- device.executeShellCommand(command, receiver);
-
- if (nLines[0] > 0) {
- // We saw lines matching the directory pattern, so it's a directory!
- entry.setType(TYPE_DIRECTORY_LINK);
- }
- }
- }
- }
-
- /**
- * Classes which implement this interface provide a method that deals with asynchronous
- * result from <code>ls</code> command on the device.
- *
- * @see FileListingService#getChildren(com.android.ddmlib.FileListingService.FileEntry, boolean, com.android.ddmlib.FileListingService.IListingReceiver)
- */
- public interface IListingReceiver {
- public void setChildren(FileEntry entry, FileEntry[] children);
-
- public void refreshEntry(FileEntry entry);
- }
-
- /**
- * Creates a File Listing Service for a specified {@link Device}.
- * @param device The Device the service is connected to.
- */
- FileListingService(Device device) {
- mDevice = device;
- }
-
- /**
- * Returns the root element.
- * @return the {@link FileEntry} object representing the root element or
- * <code>null</code> if the device is invalid.
- */
- public FileEntry getRoot() {
- if (mDevice != null) {
- if (mRoot == null) {
- mRoot = new FileEntry(null /* parent */, "" /* name */, TYPE_DIRECTORY,
- true /* isRoot */);
- }
-
- return mRoot;
- }
-
- return null;
- }
-
- /**
- * Returns the children of a {@link FileEntry}.
- * <p/>
- * This method supports a cache mechanism and synchronous and asynchronous modes.
- * <p/>
- * If <var>receiver</var> is <code>null</code>, the device side <code>ls</code>
- * command is done synchronously, and the method will return upon completion of the command.<br>
- * If <var>receiver</var> is non <code>null</code>, the command is launched is a separate
- * thread and upon completion, the receiver will be notified of the result.
- * <p/>
- * The result for each <code>ls</code> command is cached in the parent
- * <code>FileEntry</code>. <var>useCache</var> allows usage of this cache, but only if the
- * cache is valid. The cache is valid only for {@link FileListingService#REFRESH_RATE} ms.
- * After that a new <code>ls</code> command is always executed.
- * <p/>
- * If the cache is valid and <code>useCache == true</code>, the method will always simply
- * return the value of the cache, whether a {@link IListingReceiver} has been provided or not.
- *
- * @param entry The parent entry.
- * @param useCache A flag to use the cache or to force a new ls command.
- * @param receiver A receiver for asynchronous calls.
- * @return The list of children or <code>null</code> for asynchronous calls.
- *
- * @see FileEntry#getCachedChildren()
- */
- public FileEntry[] getChildren(final FileEntry entry, boolean useCache,
- final IListingReceiver receiver) {
- // first thing we do is check the cache, and if we already have a recent
- // enough children list, we just return that.
- if (useCache && entry.needFetch() == false) {
- return entry.getCachedChildren();
- }
-
- // if there's no receiver, then this is a synchronous call, and we
- // return the result of ls
- if (receiver == null) {
- doLs(entry);
- return entry.getCachedChildren();
- }
-
- // this is a asynchronous call.
- // we launch a thread that will do ls and give the listing
- // to the receiver
- Thread t = new Thread("ls " + entry.getFullPath()) { //$NON-NLS-1$
- @Override
- public void run() {
- doLs(entry);
-
- receiver.setChildren(entry, entry.getCachedChildren());
-
- final FileEntry[] children = entry.getCachedChildren();
- if (children.length > 0 && children[0].isApplicationPackage()) {
- final HashMap<String, FileEntry> map = new HashMap<String, FileEntry>();
-
- for (FileEntry child : children) {
- String path = child.getFullPath();
- map.put(path, child);
- }
-
- // call pm.
- String command = PM_FULL_LISTING;
- try {
- mDevice.executeShellCommand(command, new MultiLineReceiver() {
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- if (line.length() > 0) {
- // get the filepath and package from the line
- Matcher m = sPmPattern.matcher(line);
- if (m.matches()) {
- // get the children with that path
- FileEntry entry = map.get(m.group(1));
- if (entry != null) {
- entry.info = m.group(2);
- receiver.refreshEntry(entry);
- }
- }
- }
- }
- }
- @Override
- public boolean isCancelled() {
- return false;
- }
- });
- } catch (Exception e) {
- // adb failed somehow, we do nothing.
- }
- }
-
-
- // if another thread is pending, launch it
- synchronized (mThreadList) {
- // first remove ourselves from the list
- mThreadList.remove(this);
-
- // then launch the next one if applicable.
- if (mThreadList.size() > 0) {
- Thread t = mThreadList.get(0);
- t.start();
- }
- }
- }
- };
-
- // we don't want to run multiple ls on the device at the same time, so we
- // store the thread in a list and launch it only if there's no other thread running.
- // the thread will launch the next one once it's done.
- synchronized (mThreadList) {
- // add to the list
- mThreadList.add(t);
-
- // if it's the only one, launch it.
- if (mThreadList.size() == 1) {
- t.start();
- }
- }
-
- // and we return null.
- return null;
- }
-
- /**
- * Returns the children of a {@link FileEntry}.
- * <p/>
- * This method is the explicit synchronous version of
- * {@link #getChildren(FileEntry, boolean, IListingReceiver)}. It is roughly equivalent to
- * calling
- * getChildren(FileEntry, false, null)
- *
- * @param entry The parent entry.
- * @return The list of children
- * @throws TimeoutException in case of timeout on the connection when sending the command.
- * @throws AdbCommandRejectedException if adb rejects the command.
- * @throws ShellCommandUnresponsiveException in case the shell command doesn't send any output
- * for a period longer than <var>maxTimeToOutputResponse</var>.
- * @throws IOException in case of I/O error on the connection.
- */
- public FileEntry[] getChildrenSync(final FileEntry entry) throws TimeoutException,
- AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
- doLsAndThrow(entry);
- return entry.getCachedChildren();
- }
-
- private void doLs(FileEntry entry) {
- try {
- doLsAndThrow(entry);
- } catch (Exception e) {
- // do nothing
- }
- }
-
- private void doLsAndThrow(FileEntry entry) throws TimeoutException,
- AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
- // create a list that will receive the list of the entries
- ArrayList<FileEntry> entryList = new ArrayList<FileEntry>();
-
- // create a list that will receive the link to compute post ls;
- ArrayList<String> linkList = new ArrayList<String>();
-
- try {
- // create the command
- String command = "ls -l " + entry.getFullEscapedPath(); //$NON-NLS-1$
- if (entry.isDirectory()) {
- // If we expect a file to behave like a directory, we should stick a "/" at the end.
- // This is a good habit, and is mandatory for symlinks-to-directories, which will
- // otherwise behave like symlinks.
- command += FILE_SEPARATOR;
- }
-
- // create the receiver object that will parse the result from ls
- LsReceiver receiver = new LsReceiver(entry, entryList, linkList);
-
- // call ls.
- mDevice.executeShellCommand(command, receiver);
-
- // finish the process of the receiver to handle links
- receiver.finishLinks(mDevice, entryList);
- } finally {
- // at this point we need to refresh the viewer
- entry.fetchTime = System.currentTimeMillis();
-
- // sort the children and set them as the new children
- Collections.sort(entryList, FileEntry.sEntryComparator);
- entry.setChildren(entryList);
- }
- }
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/GetPropReceiver.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/GetPropReceiver.java
deleted file mode 100644
index 2033f04..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/GetPropReceiver.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A receiver able to parse the result of the execution of
- * {@link #GETPROP_COMMAND} on a device.
- */
-final class GetPropReceiver extends MultiLineReceiver {
- final static String GETPROP_COMMAND = "getprop"; //$NON-NLS-1$
-
- private final static Pattern GETPROP_PATTERN = Pattern.compile("^\\[([^]]+)\\]\\:\\s*\\[(.*)\\]$"); //$NON-NLS-1$
-
- /** indicates if we need to read the first */
- private Device mDevice = null;
-
- /**
- * Creates the receiver with the device the receiver will modify.
- * @param device The device to modify
- */
- public GetPropReceiver(Device device) {
- mDevice = device;
- }
-
- @Override
- public void processNewLines(String[] lines) {
- // We receive an array of lines. We're expecting
- // to have the build info in the first line, and the build
- // date in the 2nd line. There seems to be an empty line
- // after all that.
-
- for (String line : lines) {
- if (line.length() == 0 || line.startsWith("#")) {
- continue;
- }
-
- Matcher m = GETPROP_PATTERN.matcher(line);
- if (m.matches()) {
- String label = m.group(1);
- String value = m.group(2);
-
- if (label.length() > 0) {
- mDevice.addProperty(label, value);
- }
- }
- }
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public void done() {
- mDevice.update(Device.CHANGE_BUILD_INFO);
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleAppName.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleAppName.java
deleted file mode 100644
index da4ade3..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleAppName.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.IOException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-
-/**
- * Handle the "app name" chunk (APNM).
- */
-final class HandleAppName extends ChunkHandler {
-
- public static final int CHUNK_APNM = ChunkHandler.type("APNM");
-
- private static final HandleAppName mInst = new HandleAppName();
-
-
- private HandleAppName() {}
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_APNM, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {}
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data,
- boolean isReply, int msgId) {
-
- Log.d("ddm-appname", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_APNM) {
- assert !isReply;
- handleAPNM(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
- }
-
- /*
- * Handle a reply to our APNM message.
- */
- private static void handleAPNM(Client client, ByteBuffer data) {
- int appNameLen;
- String appName;
-
- appNameLen = data.getInt();
- appName = getString(data, appNameLen);
-
- // Newer devices send user id in the APNM packet.
- int userId = -1;
- boolean validUserId = false;
- if (data.hasRemaining()) {
- try {
- userId = data.getInt();
- validUserId = true;
- } catch (BufferUnderflowException e) {
- // two integers + utf-16 string
- int expectedPacketLength = 8 + appNameLen * 2;
-
- Log.e("ddm-appname", "Insufficient data in APNM chunk to retrieve user id.");
- Log.e("ddm-appname", "Actual chunk length: " + data.capacity());
- Log.e("ddm-appname", "Expected chunk length: " + expectedPacketLength);
- }
- }
-
- Log.d("ddm-appname", "APNM: app='" + appName + "'");
-
- ClientData cd = client.getClientData();
- synchronized (cd) {
- cd.setClientDescription(appName);
-
- if (validUserId) {
- cd.setUserId(userId);
- }
- }
-
- client = checkDebuggerPortForAppName(client, appName);
-
- if (client != null) {
- client.update(Client.CHANGE_NAME);
- }
- }
- }
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleExit.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleExit.java
deleted file mode 100644
index adeedbb..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleExit.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Submit an exit request.
- */
-final class HandleExit extends ChunkHandler {
-
- public static final int CHUNK_EXIT = type("EXIT");
-
- private static final HandleExit mInst = new HandleExit();
-
-
- private HandleExit() {}
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {}
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {}
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
-
- /**
- * Send an EXIT request to the client.
- */
- public static void sendEXIT(Client client, int status)
- throws IOException
- {
- ByteBuffer rawBuf = allocBuffer(4);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.putInt(status);
-
- finishChunkPacket(packet, CHUNK_EXIT, buf.position());
- Log.d("ddm-exit", "Sending " + name(CHUNK_EXIT) + ": " + status);
- client.sendAndConsume(packet, mInst);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHeap.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHeap.java
deleted file mode 100644
index 1761b79..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHeap.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.ClientData.AllocationTrackingStatus;
-import com.android.ddmlib.ClientData.IHprofDumpHandler;
-
-import java.io.IOException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-
-/**
- * Handle heap status updates.
- */
-final class HandleHeap extends ChunkHandler {
-
- public static final int CHUNK_HPIF = type("HPIF");
- public static final int CHUNK_HPST = type("HPST");
- public static final int CHUNK_HPEN = type("HPEN");
- public static final int CHUNK_HPSG = type("HPSG");
- public static final int CHUNK_HPGC = type("HPGC");
- public static final int CHUNK_HPDU = type("HPDU");
- public static final int CHUNK_HPDS = type("HPDS");
- public static final int CHUNK_REAE = type("REAE");
- public static final int CHUNK_REAQ = type("REAQ");
- public static final int CHUNK_REAL = type("REAL");
-
- // args to sendHPSG
- public static final int WHEN_DISABLE = 0;
- public static final int WHEN_GC = 1;
- public static final int WHAT_MERGE = 0; // merge adjacent objects
- public static final int WHAT_OBJ = 1; // keep objects distinct
-
- // args to sendHPIF
- public static final int HPIF_WHEN_NEVER = 0;
- public static final int HPIF_WHEN_NOW = 1;
- public static final int HPIF_WHEN_NEXT_GC = 2;
- public static final int HPIF_WHEN_EVERY_GC = 3;
-
- private static final HandleHeap mInst = new HandleHeap();
-
- private HandleHeap() {}
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_HPIF, mInst);
- mt.registerChunkHandler(CHUNK_HPST, mInst);
- mt.registerChunkHandler(CHUNK_HPEN, mInst);
- mt.registerChunkHandler(CHUNK_HPSG, mInst);
- mt.registerChunkHandler(CHUNK_HPDS, mInst);
- mt.registerChunkHandler(CHUNK_REAQ, mInst);
- mt.registerChunkHandler(CHUNK_REAL, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {
- if (client.isHeapUpdateEnabled()) {
- //sendHPSG(client, WHEN_GC, WHAT_MERGE);
- sendHPIF(client, HPIF_WHEN_EVERY_GC);
- }
- }
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
- Log.d("ddm-heap", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_HPIF) {
- handleHPIF(client, data);
- } else if (type == CHUNK_HPST) {
- handleHPST(client, data);
- } else if (type == CHUNK_HPEN) {
- handleHPEN(client, data);
- } else if (type == CHUNK_HPSG) {
- handleHPSG(client, data);
- } else if (type == CHUNK_HPDU) {
- handleHPDU(client, data);
- } else if (type == CHUNK_HPDS) {
- handleHPDS(client, data);
- } else if (type == CHUNK_REAQ) {
- handleREAQ(client, data);
- } else if (type == CHUNK_REAL) {
- handleREAL(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
- }
-
- /*
- * Handle a heap info message.
- */
- private void handleHPIF(Client client, ByteBuffer data) {
- Log.d("ddm-heap", "HPIF!");
- try {
- int numHeaps = data.getInt();
-
- for (int i = 0; i < numHeaps; i++) {
- int heapId = data.getInt();
- @SuppressWarnings("unused")
- long timeStamp = data.getLong();
- @SuppressWarnings("unused")
- byte reason = data.get();
- long maxHeapSize = (long)data.getInt() & 0x00ffffffff;
- long heapSize = (long)data.getInt() & 0x00ffffffff;
- long bytesAllocated = (long)data.getInt() & 0x00ffffffff;
- long objectsAllocated = (long)data.getInt() & 0x00ffffffff;
-
- client.getClientData().setHeapInfo(heapId, maxHeapSize,
- heapSize, bytesAllocated, objectsAllocated);
- client.update(Client.CHANGE_HEAP_DATA);
- }
- } catch (BufferUnderflowException ex) {
- Log.w("ddm-heap", "malformed HPIF chunk from client");
- }
- }
-
- /**
- * Send an HPIF (HeaP InFo) request to the client.
- */
- public static void sendHPIF(Client client, int when) throws IOException {
- ByteBuffer rawBuf = allocBuffer(1);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.put((byte)when);
-
- finishChunkPacket(packet, CHUNK_HPIF, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_HPIF) + ": when=" + when);
- client.sendAndConsume(packet, mInst);
- }
-
- /*
- * Handle a heap segment series start message.
- */
- private void handleHPST(Client client, ByteBuffer data) {
- /* Clear out any data that's sitting around to
- * get ready for the chunks that are about to come.
- */
-//xxx todo: only clear data that belongs to the heap mentioned in <data>.
- client.getClientData().getVmHeapData().clearHeapData();
- }
-
- /*
- * Handle a heap segment series end message.
- */
- private void handleHPEN(Client client, ByteBuffer data) {
- /* Let the UI know that we've received all of the
- * data for this heap.
- */
-//xxx todo: only seal data that belongs to the heap mentioned in <data>.
- client.getClientData().getVmHeapData().sealHeapData();
- client.update(Client.CHANGE_HEAP_DATA);
- }
-
- /*
- * Handle a heap segment message.
- */
- private void handleHPSG(Client client, ByteBuffer data) {
- byte dataCopy[] = new byte[data.limit()];
- data.rewind();
- data.get(dataCopy);
- data = ByteBuffer.wrap(dataCopy);
- client.getClientData().getVmHeapData().addHeapData(data);
-//xxx todo: add to the heap mentioned in <data>
- }
-
- /**
- * Sends an HPSG (HeaP SeGment) request to the client.
- */
- public static void sendHPSG(Client client, int when, int what)
- throws IOException {
-
- ByteBuffer rawBuf = allocBuffer(2);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.put((byte)when);
- buf.put((byte)what);
-
- finishChunkPacket(packet, CHUNK_HPSG, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_HPSG) + ": when="
- + when + ", what=" + what);
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Sends an HPGC request to the client.
- */
- public static void sendHPGC(Client client)
- throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data
-
- finishChunkPacket(packet, CHUNK_HPGC, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_HPGC));
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Sends an HPDU request to the client.
- *
- * We will get an HPDU response when the heap dump has completed. On
- * failure we get a generic failure response.
- *
- * @param fileName name of output file (on device)
- */
- public static void sendHPDU(Client client, String fileName)
- throws IOException {
- ByteBuffer rawBuf = allocBuffer(4 + fileName.length() * 2);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.putInt(fileName.length());
- putString(buf, fileName);
-
- finishChunkPacket(packet, CHUNK_HPDU, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_HPDU) + " '" + fileName +"'");
- client.sendAndConsume(packet, mInst);
- client.getClientData().setPendingHprofDump(fileName);
- }
-
- /**
- * Sends an HPDS request to the client.
- *
- * We will get an HPDS response when the heap dump has completed. On
- * failure we get a generic failure response.
- *
- * This is more expensive for the device than HPDU, because the entire
- * heap dump is held in RAM instead of spooled out to a temp file. On
- * the other hand, permission to write to /sdcard is not required.
- *
- * @param fileName name of output file (on device)
- */
- public static void sendHPDS(Client client)
- throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- finishChunkPacket(packet, CHUNK_HPDS, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_HPDS));
- client.sendAndConsume(packet, mInst);
- }
-
- /*
- * Handle notification of completion of a HeaP DUmp.
- */
- private void handleHPDU(Client client, ByteBuffer data) {
- byte result;
-
- // get the filename and make the client not have pending HPROF dump anymore.
- String filename = client.getClientData().getPendingHprofDump();
- client.getClientData().setPendingHprofDump(null);
-
- // get the dump result
- result = data.get();
-
- // get the app-level handler for HPROF dump
- IHprofDumpHandler handler = ClientData.getHprofDumpHandler();
- if (handler != null) {
- if (result == 0) {
- handler.onSuccess(filename, client);
-
- Log.d("ddm-heap", "Heap dump request has finished");
- } else {
- handler.onEndFailure(client, null);
- Log.w("ddm-heap", "Heap dump request failed (check device log)");
- }
- }
- }
-
- /*
- * Handle HeaP Dump Streaming response. "data" contains the full
- * hprof dump.
- */
- private void handleHPDS(Client client, ByteBuffer data) {
- IHprofDumpHandler handler = ClientData.getHprofDumpHandler();
- if (handler != null) {
- byte[] stuff = new byte[data.capacity()];
- data.get(stuff, 0, stuff.length);
-
- Log.d("ddm-hprof", "got hprof file, size: " + data.capacity() + " bytes");
-
- handler.onSuccess(stuff, client);
- }
- }
-
- /**
- * Sends a REAE (REcent Allocation Enable) request to the client.
- */
- public static void sendREAE(Client client, boolean enable)
- throws IOException {
- ByteBuffer rawBuf = allocBuffer(1);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.put((byte) (enable ? 1 : 0));
-
- finishChunkPacket(packet, CHUNK_REAE, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_REAE) + ": " + enable);
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Sends a REAQ (REcent Allocation Query) request to the client.
- */
- public static void sendREAQ(Client client)
- throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data
-
- finishChunkPacket(packet, CHUNK_REAQ, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_REAQ));
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Sends a REAL (REcent ALlocation) request to the client.
- */
- public static void sendREAL(Client client)
- throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data
-
- finishChunkPacket(packet, CHUNK_REAL, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_REAL));
- client.sendAndConsume(packet, mInst);
- }
-
- /*
- * Handle the response from our REcent Allocation Query message.
- */
- private void handleREAQ(Client client, ByteBuffer data) {
- boolean enabled;
-
- enabled = (data.get() != 0);
- Log.d("ddm-heap", "REAQ says: enabled=" + enabled);
-
- client.getClientData().setAllocationStatus(enabled ?
- AllocationTrackingStatus.ON : AllocationTrackingStatus.OFF);
- client.update(Client.CHANGE_HEAP_ALLOCATION_STATUS);
- }
-
- /**
- * Converts a VM class descriptor string ("Landroid/os/Debug;") to
- * a dot-notation class name ("android.os.Debug").
- */
- private String descriptorToDot(String str) {
- // count the number of arrays.
- int array = 0;
- while (str.startsWith("[")) {
- str = str.substring(1);
- array++;
- }
-
- int len = str.length();
-
- /* strip off leading 'L' and trailing ';' if appropriate */
- if (len >= 2 && str.charAt(0) == 'L' && str.charAt(len - 1) == ';') {
- str = str.substring(1, len-1);
- str = str.replace('/', '.');
- } else {
- // convert the basic types
- if ("C".equals(str)) {
- str = "char";
- } else if ("B".equals(str)) {
- str = "byte";
- } else if ("Z".equals(str)) {
- str = "boolean";
- } else if ("S".equals(str)) {
- str = "short";
- } else if ("I".equals(str)) {
- str = "int";
- } else if ("J".equals(str)) {
- str = "long";
- } else if ("F".equals(str)) {
- str = "float";
- } else if ("D".equals(str)) {
- str = "double";
- }
- }
-
- // now add the array part
- for (int a = 0 ; a < array; a++) {
- str = str + "[]";
- }
-
- return str;
- }
-
- /**
- * Reads a string table out of "data".
- *
- * This is just a serial collection of strings, each of which is a
- * four-byte length followed by UTF-16 data.
- */
- private void readStringTable(ByteBuffer data, String[] strings) {
- int count = strings.length;
- int i;
-
- for (i = 0; i < count; i++) {
- int nameLen = data.getInt();
- String descriptor = getString(data, nameLen);
- strings[i] = descriptorToDot(descriptor);
- }
- }
-
- /*
- * Handle a REcent ALlocation response.
- *
- * Message header (all values big-endian):
- * (1b) message header len (to allow future expansion); includes itself
- * (1b) entry header len
- * (1b) stack frame len
- * (2b) number of entries
- * (4b) offset to string table from start of message
- * (2b) number of class name strings
- * (2b) number of method name strings
- * (2b) number of source file name strings
- * For each entry:
- * (4b) total allocation size
- * (2b) threadId
- * (2b) allocated object's class name index
- * (1b) stack depth
- * For each stack frame:
- * (2b) method's class name
- * (2b) method name
- * (2b) method source file
- * (2b) line number, clipped to 32767; -2 if native; -1 if no source
- * (xb) class name strings
- * (xb) method name strings
- * (xb) source file strings
- *
- * As with other DDM traffic, strings are sent as a 4-byte length
- * followed by UTF-16 data.
- */
- private void handleREAL(Client client, ByteBuffer data) {
- Log.e("ddm-heap", "*** Received " + name(CHUNK_REAL));
- int messageHdrLen, entryHdrLen, stackFrameLen;
- int numEntries, offsetToStrings;
- int numClassNames, numMethodNames, numFileNames;
-
- /*
- * Read the header.
- */
- messageHdrLen = (data.get() & 0xff);
- entryHdrLen = (data.get() & 0xff);
- stackFrameLen = (data.get() & 0xff);
- numEntries = (data.getShort() & 0xffff);
- offsetToStrings = data.getInt();
- numClassNames = (data.getShort() & 0xffff);
- numMethodNames = (data.getShort() & 0xffff);
- numFileNames = (data.getShort() & 0xffff);
-
-
- /*
- * Skip forward to the strings and read them.
- */
- data.position(offsetToStrings);
-
- String[] classNames = new String[numClassNames];
- String[] methodNames = new String[numMethodNames];
- String[] fileNames = new String[numFileNames];
-
- readStringTable(data, classNames);
- readStringTable(data, methodNames);
- //System.out.println("METHODS: "
- // + java.util.Arrays.deepToString(methodNames));
- readStringTable(data, fileNames);
-
- /*
- * Skip back to a point just past the header and start reading
- * entries.
- */
- data.position(messageHdrLen);
-
- ArrayList<AllocationInfo> list = new ArrayList<AllocationInfo>(numEntries);
- int allocNumber = numEntries; // order value for the entry. This is sent in reverse order.
- for (int i = 0; i < numEntries; i++) {
- int totalSize;
- int threadId, classNameIndex, stackDepth;
-
- totalSize = data.getInt();
- threadId = (data.getShort() & 0xffff);
- classNameIndex = (data.getShort() & 0xffff);
- stackDepth = (data.get() & 0xff);
- /* we've consumed 9 bytes; gobble up any extra */
- for (int skip = 9; skip < entryHdrLen; skip++)
- data.get();
-
- StackTraceElement[] steArray = new StackTraceElement[stackDepth];
-
- /*
- * Pull out the stack trace.
- */
- for (int sti = 0; sti < stackDepth; sti++) {
- int methodClassNameIndex, methodNameIndex;
- int methodSourceFileIndex;
- short lineNumber;
- String methodClassName, methodName, methodSourceFile;
-
- methodClassNameIndex = (data.getShort() & 0xffff);
- methodNameIndex = (data.getShort() & 0xffff);
- methodSourceFileIndex = (data.getShort() & 0xffff);
- lineNumber = data.getShort();
-
- methodClassName = classNames[methodClassNameIndex];
- methodName = methodNames[methodNameIndex];
- methodSourceFile = fileNames[methodSourceFileIndex];
-
- steArray[sti] = new StackTraceElement(methodClassName,
- methodName, methodSourceFile, lineNumber);
-
- /* we've consumed 8 bytes; gobble up any extra */
- for (int skip = 9; skip < stackFrameLen; skip++)
- data.get();
- }
-
- list.add(new AllocationInfo(allocNumber--, classNames[classNameIndex],
- totalSize, (short) threadId, steArray));
- }
-
- client.getClientData().setAllocations(list.toArray(new AllocationInfo[numEntries]));
- client.update(Client.CHANGE_HEAP_ALLOCATIONS);
- }
-
- /*
- * For debugging: dump the contents of an AllocRecord array.
- *
- * The array starts with the oldest known allocation and ends with
- * the most recent allocation.
- */
- @SuppressWarnings("unused")
- private static void dumpRecords(AllocationInfo[] records) {
- System.out.println("Found " + records.length + " records:");
-
- for (AllocationInfo rec: records) {
- System.out.println("tid=" + rec.getThreadId() + " "
- + rec.getAllocatedClass() + " (" + rec.getSize() + " bytes)");
-
- for (StackTraceElement ste: rec.getStackTrace()) {
- if (ste.isNativeMethod()) {
- System.out.println(" " + ste.getClassName()
- + "." + ste.getMethodName()
- + " (Native method)");
- } else {
- System.out.println(" " + ste.getClassName()
- + "." + ste.getMethodName()
- + " (" + ste.getFileName()
- + ":" + ste.getLineNumber() + ")");
- }
- }
- }
- }
-
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHello.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHello.java
deleted file mode 100644
index b5c2968..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleHello.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.IOException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-
-/**
- * Handle the "hello" chunk (HELO) and feature discovery.
- */
-final class HandleHello extends ChunkHandler {
-
- public static final int CHUNK_HELO = ChunkHandler.type("HELO");
- public static final int CHUNK_FEAT = ChunkHandler.type("FEAT");
-
- private static final HandleHello mInst = new HandleHello();
-
- private HandleHello() {}
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_HELO, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {
- Log.d("ddm-hello", "Now ready: " + client);
- }
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {
- Log.d("ddm-hello", "Now disconnected: " + client);
- }
-
- /**
- * Sends HELLO-type commands to the VM after a good handshake.
- * @param client
- * @param serverProtocolVersion
- * @throws IOException
- */
- public static void sendHelloCommands(Client client, int serverProtocolVersion)
- throws IOException {
- sendHELO(client, serverProtocolVersion);
- sendFEAT(client);
- HandleProfiling.sendMPRQ(client);
- }
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
-
- Log.d("ddm-hello", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_HELO) {
- assert isReply;
- handleHELO(client, data);
- } else if (type == CHUNK_FEAT) {
- handleFEAT(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
- }
-
- /*
- * Handle a reply to our HELO message.
- */
- private static void handleHELO(Client client, ByteBuffer data) {
- int version, pid, vmIdentLen, appNameLen;
- String vmIdent, appName;
-
- version = data.getInt();
- pid = data.getInt();
- vmIdentLen = data.getInt();
- appNameLen = data.getInt();
-
- vmIdent = getString(data, vmIdentLen);
- appName = getString(data, appNameLen);
-
- // Newer devices send user id in the APNM packet.
- int userId = -1;
- boolean validUserId = false;
- if (data.hasRemaining()) {
- try {
- userId = data.getInt();
- validUserId = true;
- } catch (BufferUnderflowException e) {
- // five integers + two utf-16 strings
- int expectedPacketLength = 20 + appNameLen * 2 + vmIdentLen * 2;
-
- Log.e("ddm-hello", "Insufficient data in HELO chunk to retrieve user id.");
- Log.e("ddm-hello", "Actual chunk length: " + data.capacity());
- Log.e("ddm-hello", "Expected chunk length: " + expectedPacketLength);
- }
- }
-
- Log.d("ddm-hello", "HELO: v=" + version + ", pid=" + pid
- + ", vm='" + vmIdent + "', app='" + appName + "'");
-
- ClientData cd = client.getClientData();
-
- synchronized (cd) {
- if (cd.getPid() == pid) {
- cd.setVmIdentifier(vmIdent);
- cd.setClientDescription(appName);
- cd.isDdmAware(true);
-
- if (validUserId) {
- cd.setUserId(userId);
- }
- } else {
- Log.e("ddm-hello", "Received pid (" + pid + ") does not match client pid ("
- + cd.getPid() + ")");
- }
- }
-
- client = checkDebuggerPortForAppName(client, appName);
-
- if (client != null) {
- client.update(Client.CHANGE_NAME);
- }
- }
-
-
- /**
- * Send a HELO request to the client.
- */
- public static void sendHELO(Client client, int serverProtocolVersion)
- throws IOException
- {
- ByteBuffer rawBuf = allocBuffer(4);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.putInt(serverProtocolVersion);
-
- finishChunkPacket(packet, CHUNK_HELO, buf.position());
- Log.d("ddm-hello", "Sending " + name(CHUNK_HELO)
- + " ID=0x" + Integer.toHexString(packet.getId()));
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Handle a reply to our FEAT request.
- */
- private static void handleFEAT(Client client, ByteBuffer data) {
- int featureCount;
- int i;
-
- featureCount = data.getInt();
- for (i = 0; i < featureCount; i++) {
- int len = data.getInt();
- String feature = getString(data, len);
- client.getClientData().addFeature(feature);
-
- Log.d("ddm-hello", "Feature: " + feature);
- }
- }
-
- /**
- * Send a FEAT request to the client.
- */
- public static void sendFEAT(Client client) throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data
-
- finishChunkPacket(packet, CHUNK_FEAT, buf.position());
- Log.d("ddm-heap", "Sending " + name(CHUNK_FEAT));
- client.sendAndConsume(packet, mInst);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleNativeHeap.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleNativeHeap.java
deleted file mode 100644
index 5c176cf..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleNativeHeap.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * Handle thread status updates.
- */
-final class HandleNativeHeap extends ChunkHandler {
-
- public static final int CHUNK_NHGT = type("NHGT"); //$NON-NLS-1$
- public static final int CHUNK_NHSG = type("NHSG"); //$NON-NLS-1$
- public static final int CHUNK_NHST = type("NHST"); //$NON-NLS-1$
- public static final int CHUNK_NHEN = type("NHEN"); //$NON-NLS-1$
-
- private static final HandleNativeHeap mInst = new HandleNativeHeap();
-
- private HandleNativeHeap() {
- }
-
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_NHGT, mInst);
- mt.registerChunkHandler(CHUNK_NHSG, mInst);
- mt.registerChunkHandler(CHUNK_NHST, mInst);
- mt.registerChunkHandler(CHUNK_NHEN, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {}
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
-
- Log.d("ddm-nativeheap", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_NHGT) {
- handleNHGT(client, data);
- } else if (type == CHUNK_NHST) {
- // start chunk before any NHSG chunk(s)
- client.getClientData().getNativeHeapData().clearHeapData();
- } else if (type == CHUNK_NHEN) {
- // end chunk after NHSG chunk(s)
- client.getClientData().getNativeHeapData().sealHeapData();
- } else if (type == CHUNK_NHSG) {
- handleNHSG(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
-
- client.update(Client.CHANGE_NATIVE_HEAP_DATA);
- }
-
- /**
- * Send an NHGT (Native Thread GeT) request to the client.
- */
- public static void sendNHGT(Client client) throws IOException {
-
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data in request message
-
- finishChunkPacket(packet, CHUNK_NHGT, buf.position());
- Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHGT));
- client.sendAndConsume(packet, mInst);
-
- rawBuf = allocBuffer(2);
- packet = new JdwpPacket(rawBuf);
- buf = getChunkDataBuf(rawBuf);
-
- buf.put((byte)HandleHeap.WHEN_DISABLE);
- buf.put((byte)HandleHeap.WHAT_OBJ);
-
- finishChunkPacket(packet, CHUNK_NHSG, buf.position());
- Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHSG));
- client.sendAndConsume(packet, mInst);
- }
-
- /*
- * Handle our native heap data.
- */
- private void handleNHGT(Client client, ByteBuffer data) {
- ClientData cd = client.getClientData();
-
- Log.d("ddm-nativeheap", "NHGT: " + data.limit() + " bytes");
-
- // TODO - process incoming data and save in "cd"
- byte[] copy = new byte[data.limit()];
- data.get(copy);
-
- // clear the previous run
- cd.clearNativeAllocationInfo();
-
- ByteBuffer buffer = ByteBuffer.wrap(copy);
- buffer.order(ByteOrder.LITTLE_ENDIAN);
-
-// read the header
-// typedef struct Header {
-// uint32_t mapSize;
-// uint32_t allocSize;
-// uint32_t allocInfoSize;
-// uint32_t totalMemory;
-// uint32_t backtraceSize;
-// };
-
- int mapSize = buffer.getInt();
- int allocSize = buffer.getInt();
- int allocInfoSize = buffer.getInt();
- int totalMemory = buffer.getInt();
- int backtraceSize = buffer.getInt();
-
- Log.d("ddms", "mapSize: " + mapSize);
- Log.d("ddms", "allocSize: " + allocSize);
- Log.d("ddms", "allocInfoSize: " + allocInfoSize);
- Log.d("ddms", "totalMemory: " + totalMemory);
-
- cd.setTotalNativeMemory(totalMemory);
-
- // this means that updates aren't turned on.
- if (allocInfoSize == 0)
- return;
-
- if (mapSize > 0) {
- byte[] maps = new byte[mapSize];
- buffer.get(maps, 0, mapSize);
- parseMaps(cd, maps);
- }
-
- int iterations = allocSize / allocInfoSize;
-
- for (int i = 0 ; i < iterations ; i++) {
- NativeAllocationInfo info = new NativeAllocationInfo(
- buffer.getInt() /* size */,
- buffer.getInt() /* allocations */);
-
- for (int j = 0 ; j < backtraceSize ; j++) {
- long addr = (buffer.getInt()) & 0x00000000ffffffffL;
-
- if (addr == 0x0) {
- // skip past null addresses
- continue;
- }
-
- info.addStackCallAddress(addr);;
- }
-
- cd.addNativeAllocation(info);
- }
- }
-
- private void handleNHSG(Client client, ByteBuffer data) {
- byte dataCopy[] = new byte[data.limit()];
- data.rewind();
- data.get(dataCopy);
- data = ByteBuffer.wrap(dataCopy);
- client.getClientData().getNativeHeapData().addHeapData(data);
-
- if (true) {
- return;
- }
-
- // WORK IN PROGRESS
-
-// Log.e("ddm-nativeheap", "NHSG: ----------------------------------");
-// Log.e("ddm-nativeheap", "NHSG: " + data.limit() + " bytes");
-
- byte[] copy = new byte[data.limit()];
- data.get(copy);
-
- ByteBuffer buffer = ByteBuffer.wrap(copy);
- buffer.order(ByteOrder.BIG_ENDIAN);
-
- int id = buffer.getInt();
- int unitsize = buffer.get();
- long startAddress = buffer.getInt() & 0x00000000ffffffffL;
- int offset = buffer.getInt();
- int allocationUnitCount = buffer.getInt();
-
-// Log.e("ddm-nativeheap", "id: " + id);
-// Log.e("ddm-nativeheap", "unitsize: " + unitsize);
-// Log.e("ddm-nativeheap", "startAddress: 0x" + Long.toHexString(startAddress));
-// Log.e("ddm-nativeheap", "offset: " + offset);
-// Log.e("ddm-nativeheap", "allocationUnitCount: " + allocationUnitCount);
-// Log.e("ddm-nativeheap", "end: 0x" +
-// Long.toHexString(startAddress + unitsize * allocationUnitCount));
-
- // read the usage
- while (buffer.position() < buffer.limit()) {
- int eState = buffer.get() & 0x000000ff;
- int eLen = (buffer.get() & 0x000000ff) + 1;
- //Log.e("ddm-nativeheap", "solidity: " + (eState & 0x7) + " - kind: "
- // + ((eState >> 3) & 0x7) + " - len: " + eLen);
- }
-
-
-// count += unitsize * allocationUnitCount;
-// Log.e("ddm-nativeheap", "count = " + count);
-
- }
-
- private void parseMaps(ClientData cd, byte[] maps) {
- InputStreamReader input = new InputStreamReader(new ByteArrayInputStream(maps));
- BufferedReader reader = new BufferedReader(input);
-
- String line;
-
- try {
-
- // most libraries are defined on several lines, so we need to make sure we parse
- // all the library lines and only add the library at the end
- long startAddr = 0;
- long endAddr = 0;
- String library = null;
-
- while ((line = reader.readLine()) != null) {
- Log.d("ddms", "line: " + line);
- if (line.length() < 16) {
- continue;
- }
-
- try {
- long tmpStart = Long.parseLong(line.substring(0, 8), 16);
- long tmpEnd = Long.parseLong(line.substring(9, 17), 16);
-
- int index = line.indexOf('/');
-
- if (index == -1)
- continue;
-
- String tmpLib = line.substring(index);
-
- if (library == null ||
- (library != null && tmpLib.equals(library) == false)) {
-
- if (library != null) {
- cd.addNativeLibraryMapInfo(startAddr, endAddr, library);
- Log.d("ddms", library + "(" + Long.toHexString(startAddr) +
- " - " + Long.toHexString(endAddr) + ")");
- }
-
- // now init the new library
- library = tmpLib;
- startAddr = tmpStart;
- endAddr = tmpEnd;
- } else {
- // add the new end
- endAddr = tmpEnd;
- }
- } catch (NumberFormatException e) {
- e.printStackTrace();
- }
- }
-
- if (library != null) {
- cd.addNativeLibraryMapInfo(startAddr, endAddr, library);
- Log.d("ddms", library + "(" + Long.toHexString(startAddr) +
- " - " + Long.toHexString(endAddr) + ")");
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleProfiling.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleProfiling.java
deleted file mode 100644
index 9d01fdf..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleProfiling.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2009 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.ddmlib;
-
-import com.android.ddmlib.ClientData.IMethodProfilingHandler;
-import com.android.ddmlib.ClientData.MethodProfilingStatus;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Handle heap status updates.
- */
-final class HandleProfiling extends ChunkHandler {
-
- public static final int CHUNK_MPRS = type("MPRS");
- public static final int CHUNK_MPRE = type("MPRE");
- public static final int CHUNK_MPSS = type("MPSS");
- public static final int CHUNK_MPSE = type("MPSE");
- public static final int CHUNK_MPRQ = type("MPRQ");
- public static final int CHUNK_FAIL = type("FAIL");
-
- private static final HandleProfiling mInst = new HandleProfiling();
-
- private HandleProfiling() {}
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_MPRE, mInst);
- mt.registerChunkHandler(CHUNK_MPSE, mInst);
- mt.registerChunkHandler(CHUNK_MPRQ, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {}
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data,
- boolean isReply, int msgId) {
-
- Log.d("ddm-prof", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_MPRE) {
- handleMPRE(client, data);
- } else if (type == CHUNK_MPSE) {
- handleMPSE(client, data);
- } else if (type == CHUNK_MPRQ) {
- handleMPRQ(client, data);
- } else if (type == CHUNK_FAIL) {
- handleFAIL(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
- }
-
- /**
- * Send a MPRS (Method PRofiling Start) request to the client.
- *
- * The arguments to this method will eventually be passed to
- * android.os.Debug.startMethodTracing() on the device.
- *
- * @param fileName is the name of the file to which profiling data
- * will be written (on the device); it will have {@link DdmConstants#DOT_TRACE}
- * appended if necessary
- * @param bufferSize is the desired buffer size in bytes (8MB is good)
- * @param flags see startMethodTracing() docs; use 0 for default behavior
- */
- public static void sendMPRS(Client client, String fileName, int bufferSize,
- int flags) throws IOException {
-
- ByteBuffer rawBuf = allocBuffer(3*4 + fileName.length() * 2);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.putInt(bufferSize);
- buf.putInt(flags);
- buf.putInt(fileName.length());
- putString(buf, fileName);
-
- finishChunkPacket(packet, CHUNK_MPRS, buf.position());
- Log.d("ddm-prof", "Sending " + name(CHUNK_MPRS) + " '" + fileName
- + "', size=" + bufferSize + ", flags=" + flags);
- client.sendAndConsume(packet, mInst);
-
- // record the filename we asked for.
- client.getClientData().setPendingMethodProfiling(fileName);
-
- // send a status query. this ensure that the status is properly updated if for some
- // reason starting the tracing failed.
- sendMPRQ(client);
- }
-
- /**
- * Send a MPRE (Method PRofiling End) request to the client.
- */
- public static void sendMPRE(Client client) throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data
-
- finishChunkPacket(packet, CHUNK_MPRE, buf.position());
- Log.d("ddm-prof", "Sending " + name(CHUNK_MPRE));
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Handle notification that method profiling has finished writing
- * data to disk.
- */
- private void handleMPRE(Client client, ByteBuffer data) {
- byte result;
-
- // get the filename and make the client not have pending HPROF dump anymore.
- String filename = client.getClientData().getPendingMethodProfiling();
- client.getClientData().setPendingMethodProfiling(null);
-
- result = data.get();
-
- // get the app-level handler for method tracing dump
- IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
- if (handler != null) {
- if (result == 0) {
- handler.onSuccess(filename, client);
-
- Log.d("ddm-prof", "Method profiling has finished");
- } else {
- handler.onEndFailure(client, null /*message*/);
-
- Log.w("ddm-prof", "Method profiling has failed (check device log)");
- }
- }
-
- client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF);
- client.update(Client.CHANGE_METHOD_PROFILING_STATUS);
- }
-
- /**
- * Send a MPSS (Method Profiling Streaming Start) request to the client.
- *
- * The arguments to this method will eventually be passed to
- * android.os.Debug.startMethodTracing() on the device.
- *
- * @param bufferSize is the desired buffer size in bytes (8MB is good)
- * @param flags see startMethodTracing() docs; use 0 for default behavior
- */
- public static void sendMPSS(Client client, int bufferSize,
- int flags) throws IOException {
-
- ByteBuffer rawBuf = allocBuffer(2*4);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.putInt(bufferSize);
- buf.putInt(flags);
-
- finishChunkPacket(packet, CHUNK_MPSS, buf.position());
- Log.d("ddm-prof", "Sending " + name(CHUNK_MPSS)
- + "', size=" + bufferSize + ", flags=" + flags);
- client.sendAndConsume(packet, mInst);
-
- // send a status query. this ensure that the status is properly updated if for some
- // reason starting the tracing failed.
- sendMPRQ(client);
- }
-
- /**
- * Send a MPSE (Method Profiling Streaming End) request to the client.
- */
- public static void sendMPSE(Client client) throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data
-
- finishChunkPacket(packet, CHUNK_MPSE, buf.position());
- Log.d("ddm-prof", "Sending " + name(CHUNK_MPSE));
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Handle incoming profiling data. The MPSE packet includes the
- * complete .trace file.
- */
- private void handleMPSE(Client client, ByteBuffer data) {
- IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
- if (handler != null) {
- byte[] stuff = new byte[data.capacity()];
- data.get(stuff, 0, stuff.length);
-
- Log.d("ddm-prof", "got trace file, size: " + stuff.length + " bytes");
-
- handler.onSuccess(stuff, client);
- }
-
- client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF);
- client.update(Client.CHANGE_METHOD_PROFILING_STATUS);
- }
-
- /**
- * Send a MPRQ (Method PRofiling Query) request to the client.
- */
- public static void sendMPRQ(Client client) throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // no data
-
- finishChunkPacket(packet, CHUNK_MPRQ, buf.position());
- Log.d("ddm-prof", "Sending " + name(CHUNK_MPRQ));
- client.sendAndConsume(packet, mInst);
- }
-
- /**
- * Receive response to query.
- */
- private void handleMPRQ(Client client, ByteBuffer data) {
- byte result;
-
- result = data.get();
-
- if (result == 0) {
- client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF);
- Log.d("ddm-prof", "Method profiling is not running");
- } else {
- client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.ON);
- Log.d("ddm-prof", "Method profiling is running");
- }
- client.update(Client.CHANGE_METHOD_PROFILING_STATUS);
- }
-
- private void handleFAIL(Client client, ByteBuffer data) {
- /*int errorCode =*/ data.getInt();
- int length = data.getInt() * 2;
- String message = null;
- if (length > 0) {
- byte[] messageBuffer = new byte[length];
- data.get(messageBuffer, 0, length);
- message = new String(messageBuffer);
- }
-
- // this can be sent if
- // - MPRS failed (like wrong permission)
- // - MPSE failed for whatever reason
-
- String filename = client.getClientData().getPendingMethodProfiling();
- if (filename != null) {
- // reset the pending file.
- client.getClientData().setPendingMethodProfiling(null);
-
- // and notify of failure
- IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
- if (handler != null) {
- handler.onStartFailure(client, message);
- }
- } else {
- // this is MPRE
- // notify of failure
- IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler();
- if (handler != null) {
- handler.onEndFailure(client, message);
- }
- }
-
- // send a query to know the current status
- try {
- sendMPRQ(client);
- } catch (IOException e) {
- Log.e("HandleProfiling", e);
- }
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleTest.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleTest.java
deleted file mode 100644
index b9f3a74..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.Log.LogLevel;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Handle thread status updates.
- */
-final class HandleTest extends ChunkHandler {
-
- public static final int CHUNK_TEST = type("TEST");
-
- private static final HandleTest mInst = new HandleTest();
-
-
- private HandleTest() {}
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_TEST, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {}
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
-
- Log.d("ddm-test", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_TEST) {
- handleTEST(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
- }
-
- /*
- * Handle a thread creation message.
- */
- private void handleTEST(Client client, ByteBuffer data)
- {
- /*
- * Can't call data.array() on a read-only ByteBuffer, so we make
- * a copy.
- */
- byte[] copy = new byte[data.limit()];
- data.get(copy);
-
- Log.d("ddm-test", "Received:");
- Log.hexDump("ddm-test", LogLevel.DEBUG, copy, 0, copy.length);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleThread.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleThread.java
deleted file mode 100644
index 8430c95..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleThread.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Handle thread status updates.
- */
-final class HandleThread extends ChunkHandler {
-
- public static final int CHUNK_THEN = type("THEN");
- public static final int CHUNK_THCR = type("THCR");
- public static final int CHUNK_THDE = type("THDE");
- public static final int CHUNK_THST = type("THST");
- public static final int CHUNK_THNM = type("THNM");
- public static final int CHUNK_STKL = type("STKL");
-
- private static final HandleThread mInst = new HandleThread();
-
- // only read/written by requestThreadUpdates()
- private static volatile boolean mThreadStatusReqRunning = false;
- private static volatile boolean mThreadStackTraceReqRunning = false;
-
- private HandleThread() {}
-
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_THCR, mInst);
- mt.registerChunkHandler(CHUNK_THDE, mInst);
- mt.registerChunkHandler(CHUNK_THST, mInst);
- mt.registerChunkHandler(CHUNK_THNM, mInst);
- mt.registerChunkHandler(CHUNK_STKL, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {
- Log.d("ddm-thread", "Now ready: " + client);
- if (client.isThreadUpdateEnabled())
- sendTHEN(client, true);
- }
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
-
- Log.d("ddm-thread", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_THCR) {
- handleTHCR(client, data);
- } else if (type == CHUNK_THDE) {
- handleTHDE(client, data);
- } else if (type == CHUNK_THST) {
- handleTHST(client, data);
- } else if (type == CHUNK_THNM) {
- handleTHNM(client, data);
- } else if (type == CHUNK_STKL) {
- handleSTKL(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
- }
-
- /*
- * Handle a thread creation message.
- *
- * We should be tolerant of receiving a duplicate create message. (It
- * shouldn't happen with the current implementation.)
- */
- private void handleTHCR(Client client, ByteBuffer data) {
- int threadId, nameLen;
- String name;
-
- threadId = data.getInt();
- nameLen = data.getInt();
- name = getString(data, nameLen);
-
- Log.v("ddm-thread", "THCR: " + threadId + " '" + name + "'");
-
- client.getClientData().addThread(threadId, name);
- client.update(Client.CHANGE_THREAD_DATA);
- }
-
- /*
- * Handle a thread death message.
- */
- private void handleTHDE(Client client, ByteBuffer data) {
- int threadId;
-
- threadId = data.getInt();
- Log.v("ddm-thread", "THDE: " + threadId);
-
- client.getClientData().removeThread(threadId);
- client.update(Client.CHANGE_THREAD_DATA);
- }
-
- /*
- * Handle a thread status update message.
- *
- * Response has:
- * (1b) header len
- * (1b) bytes per entry
- * (2b) thread count
- * Then, for each thread:
- * (4b) threadId (matches value from THCR)
- * (1b) thread status
- * (4b) tid
- * (4b) utime
- * (4b) stime
- */
- private void handleTHST(Client client, ByteBuffer data) {
- int headerLen, bytesPerEntry, extraPerEntry;
- int threadCount;
-
- headerLen = (data.get() & 0xff);
- bytesPerEntry = (data.get() & 0xff);
- threadCount = data.getShort();
-
- headerLen -= 4; // we've read 4 bytes
- while (headerLen-- > 0)
- data.get();
-
- extraPerEntry = bytesPerEntry - 18; // we want 18 bytes
-
- Log.v("ddm-thread", "THST: threadCount=" + threadCount);
-
- /*
- * For each thread, extract the data, find the appropriate
- * client, and add it to the ClientData.
- */
- for (int i = 0; i < threadCount; i++) {
- int threadId, status, tid, utime, stime;
- boolean isDaemon = false;
-
- threadId = data.getInt();
- status = data.get();
- tid = data.getInt();
- utime = data.getInt();
- stime = data.getInt();
- if (bytesPerEntry >= 18)
- isDaemon = (data.get() != 0);
-
- Log.v("ddm-thread", " id=" + threadId
- + ", status=" + status + ", tid=" + tid
- + ", utime=" + utime + ", stime=" + stime);
-
- ClientData cd = client.getClientData();
- ThreadInfo threadInfo = cd.getThread(threadId);
- if (threadInfo != null)
- threadInfo.updateThread(status, tid, utime, stime, isDaemon);
- else
- Log.d("ddms", "Thread with id=" + threadId + " not found");
-
- // slurp up any extra
- for (int slurp = extraPerEntry; slurp > 0; slurp--)
- data.get();
- }
-
- client.update(Client.CHANGE_THREAD_DATA);
- }
-
- /*
- * Handle a THNM (THread NaMe) message. We get one of these after
- * somebody calls Thread.setName() on a running thread.
- */
- private void handleTHNM(Client client, ByteBuffer data) {
- int threadId, nameLen;
- String name;
-
- threadId = data.getInt();
- nameLen = data.getInt();
- name = getString(data, nameLen);
-
- Log.v("ddm-thread", "THNM: " + threadId + " '" + name + "'");
-
- ThreadInfo threadInfo = client.getClientData().getThread(threadId);
- if (threadInfo != null) {
- threadInfo.setThreadName(name);
- client.update(Client.CHANGE_THREAD_DATA);
- } else {
- Log.d("ddms", "Thread with id=" + threadId + " not found");
- }
- }
-
-
- /**
- * Parse an incoming STKL.
- */
- private void handleSTKL(Client client, ByteBuffer data) {
- StackTraceElement[] trace;
- int i, threadId, stackDepth;
- @SuppressWarnings("unused")
- int future;
-
- future = data.getInt();
- threadId = data.getInt();
-
- Log.v("ddms", "STKL: " + threadId);
-
- /* un-serialize the StackTraceElement[] */
- stackDepth = data.getInt();
- trace = new StackTraceElement[stackDepth];
- for (i = 0; i < stackDepth; i++) {
- String className, methodName, fileName;
- int len, lineNumber;
-
- len = data.getInt();
- className = getString(data, len);
- len = data.getInt();
- methodName = getString(data, len);
- len = data.getInt();
- if (len == 0) {
- fileName = null;
- } else {
- fileName = getString(data, len);
- }
- lineNumber = data.getInt();
-
- trace[i] = new StackTraceElement(className, methodName, fileName,
- lineNumber);
- }
-
- ThreadInfo threadInfo = client.getClientData().getThread(threadId);
- if (threadInfo != null) {
- threadInfo.setStackCall(trace);
- client.update(Client.CHANGE_THREAD_STACKTRACE);
- } else {
- Log.d("STKL", String.format(
- "Got stackcall for thread %1$d, which does not exists (anymore?).", //$NON-NLS-1$
- threadId));
- }
- }
-
-
- /**
- * Send a THEN (THread notification ENable) request to the client.
- */
- public static void sendTHEN(Client client, boolean enable)
- throws IOException {
-
- ByteBuffer rawBuf = allocBuffer(1);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- if (enable)
- buf.put((byte)1);
- else
- buf.put((byte)0);
-
- finishChunkPacket(packet, CHUNK_THEN, buf.position());
- Log.d("ddm-thread", "Sending " + name(CHUNK_THEN) + ": " + enable);
- client.sendAndConsume(packet, mInst);
- }
-
-
- /**
- * Send a STKL (STacK List) request to the client. The VM will suspend
- * the target thread, obtain its stack, and return it. If the thread
- * is no longer running, a failure result will be returned.
- */
- public static void sendSTKL(Client client, int threadId)
- throws IOException {
-
- if (false) {
- Log.d("ddm-thread", "would send STKL " + threadId);
- return;
- }
-
- ByteBuffer rawBuf = allocBuffer(4);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- buf.putInt(threadId);
-
- finishChunkPacket(packet, CHUNK_STKL, buf.position());
- Log.d("ddm-thread", "Sending " + name(CHUNK_STKL) + ": " + threadId);
- client.sendAndConsume(packet, mInst);
- }
-
-
- /**
- * This is called periodically from the UI thread. To avoid locking
- * the UI while we request the updates, we create a new thread.
- *
- */
- static void requestThreadUpdate(final Client client) {
- if (client.isDdmAware() && client.isThreadUpdateEnabled()) {
- if (mThreadStatusReqRunning) {
- Log.w("ddms", "Waiting for previous thread update req to finish");
- return;
- }
-
- new Thread("Thread Status Req") {
- @Override
- public void run() {
- mThreadStatusReqRunning = true;
- try {
- sendTHST(client);
- } catch (IOException ioe) {
- Log.d("ddms", "Unable to request thread updates from "
- + client + ": " + ioe.getMessage());
- } finally {
- mThreadStatusReqRunning = false;
- }
- }
- }.start();
- }
- }
-
- static void requestThreadStackCallRefresh(final Client client, final int threadId) {
- if (client.isDdmAware() && client.isThreadUpdateEnabled()) {
- if (mThreadStackTraceReqRunning ) {
- Log.w("ddms", "Waiting for previous thread stack call req to finish");
- return;
- }
-
- new Thread("Thread Status Req") {
- @Override
- public void run() {
- mThreadStackTraceReqRunning = true;
- try {
- sendSTKL(client, threadId);
- } catch (IOException ioe) {
- Log.d("ddms", "Unable to request thread stack call updates from "
- + client + ": " + ioe.getMessage());
- } finally {
- mThreadStackTraceReqRunning = false;
- }
- }
- }.start();
- }
-
- }
-
- /*
- * Send a THST request to the specified client.
- */
- private static void sendTHST(Client client) throws IOException {
- ByteBuffer rawBuf = allocBuffer(0);
- JdwpPacket packet = new JdwpPacket(rawBuf);
- ByteBuffer buf = getChunkDataBuf(rawBuf);
-
- // nothing much to say
-
- finishChunkPacket(packet, CHUNK_THST, buf.position());
- Log.d("ddm-thread", "Sending " + name(CHUNK_THST));
- client.sendAndConsume(packet, mInst);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleWait.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleWait.java
deleted file mode 100644
index 934cbea..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HandleWait.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.ClientData.DebuggerStatus;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Handle the "wait" chunk (WAIT). These are sent up when the client is
- * waiting for something, e.g. for a debugger to attach.
- */
-final class HandleWait extends ChunkHandler {
-
- public static final int CHUNK_WAIT = ChunkHandler.type("WAIT");
-
- private static final HandleWait mInst = new HandleWait();
-
-
- private HandleWait() {}
-
- /**
- * Register for the packets we expect to get from the client.
- */
- public static void register(MonitorThread mt) {
- mt.registerChunkHandler(CHUNK_WAIT, mInst);
- }
-
- /**
- * Client is ready.
- */
- @Override
- public void clientReady(Client client) throws IOException {}
-
- /**
- * Client went away.
- */
- @Override
- public void clientDisconnected(Client client) {}
-
- /**
- * Chunk handler entry point.
- */
- @Override
- public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
-
- Log.d("ddm-wait", "handling " + ChunkHandler.name(type));
-
- if (type == CHUNK_WAIT) {
- assert !isReply;
- handleWAIT(client, data);
- } else {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
- }
-
- /*
- * Handle a reply to our WAIT message.
- */
- private static void handleWAIT(Client client, ByteBuffer data) {
- byte reason;
-
- reason = data.get();
-
- Log.d("ddm-wait", "WAIT: reason=" + reason);
-
-
- ClientData cd = client.getClientData();
- synchronized (cd) {
- cd.setDebuggerConnectionStatus(DebuggerStatus.WAITING);
- }
-
- client.update(Client.CHANGE_DEBUGGER_STATUS);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HeapSegment.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HeapSegment.java
deleted file mode 100644
index 42f740c..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/HeapSegment.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.text.ParseException;
-
-/**
- * Describes the types and locations of objects in a segment of a heap.
- */
-public final class HeapSegment implements Comparable<HeapSegment> {
-
- /**
- * Describes an object/region encoded in the HPSG data.
- */
- public static class HeapSegmentElement implements Comparable<HeapSegmentElement> {
-
- /*
- * Solidity values, which must match the values in
- * the HPSG data.
- */
-
- /** The element describes a free block. */
- public static int SOLIDITY_FREE = 0;
-
- /** The element is strongly-reachable. */
- public static int SOLIDITY_HARD = 1;
-
- /** The element is softly-reachable. */
- public static int SOLIDITY_SOFT = 2;
-
- /** The element is weakly-reachable. */
- public static int SOLIDITY_WEAK = 3;
-
- /** The element is phantom-reachable. */
- public static int SOLIDITY_PHANTOM = 4;
-
- /** The element is pending finalization. */
- public static int SOLIDITY_FINALIZABLE = 5;
-
- /** The element is not reachable, and is about to be swept/freed. */
- public static int SOLIDITY_SWEEP = 6;
-
- /** The reachability of the object is unknown. */
- public static int SOLIDITY_INVALID = -1;
-
-
- /*
- * Kind values, which must match the values in
- * the HPSG data.
- */
-
- /** The element describes a data object. */
- public static int KIND_OBJECT = 0;
-
- /** The element describes a class object. */
- public static int KIND_CLASS_OBJECT = 1;
-
- /** The element describes an array of 1-byte elements. */
- public static int KIND_ARRAY_1 = 2;
-
- /** The element describes an array of 2-byte elements. */
- public static int KIND_ARRAY_2 = 3;
-
- /** The element describes an array of 4-byte elements. */
- public static int KIND_ARRAY_4 = 4;
-
- /** The element describes an array of 8-byte elements. */
- public static int KIND_ARRAY_8 = 5;
-
- /** The element describes an unknown type of object. */
- public static int KIND_UNKNOWN = 6;
-
- /** The element describes a native object. */
- public static int KIND_NATIVE = 7;
-
- /** The object kind is unknown or unspecified. */
- public static int KIND_INVALID = -1;
-
-
- /**
- * A bit in the HPSG data that indicates that an element should
- * be combined with the element that follows, typically because
- * an element is too large to be described by a single element.
- */
- private static int PARTIAL_MASK = 1 << 7;
-
-
- /**
- * Describes the reachability/solidity of the element. Must
- * be set to one of the SOLIDITY_* values.
- */
- private int mSolidity;
-
- /**
- * Describes the type/kind of the element. Must be set to one
- * of the KIND_* values.
- */
- private int mKind;
-
- /**
- * Describes the length of the element, in bytes.
- */
- private int mLength;
-
-
- /**
- * Creates an uninitialized element.
- */
- public HeapSegmentElement() {
- setSolidity(SOLIDITY_INVALID);
- setKind(KIND_INVALID);
- setLength(-1);
- }
-
- /**
- * Create an element describing the entry at the current
- * position of hpsgData.
- *
- * @param hs The heap segment to pull the entry from.
- * @throws BufferUnderflowException if there is not a whole entry
- * following the current position
- * of hpsgData.
- * @throws ParseException if the provided data is malformed.
- */
- public HeapSegmentElement(HeapSegment hs)
- throws BufferUnderflowException, ParseException {
- set(hs);
- }
-
- /**
- * Replace the element with the entry at the current position of
- * hpsgData.
- *
- * @param hs The heap segment to pull the entry from.
- * @return this object.
- * @throws BufferUnderflowException if there is not a whole entry
- * following the current position of
- * hpsgData.
- * @throws ParseException if the provided data is malformed.
- */
- public HeapSegmentElement set(HeapSegment hs)
- throws BufferUnderflowException, ParseException {
-
- /* TODO: Maybe keep track of the virtual address of each element
- * so that they can be examined independently.
- */
- ByteBuffer data = hs.mUsageData;
- int eState = data.get() & 0x000000ff;
- int eLen = (data.get() & 0x000000ff) + 1;
-
- while ((eState & PARTIAL_MASK) != 0) {
-
- /* If the partial bit was set, the next byte should describe
- * the same object as the current one.
- */
- int nextState = data.get() & 0x000000ff;
- if ((nextState & ~PARTIAL_MASK) != (eState & ~PARTIAL_MASK)) {
- throw new ParseException("State mismatch", data.position());
- }
- eState = nextState;
- eLen += (data.get() & 0x000000ff) + 1;
- }
-
- setSolidity(eState & 0x7);
- setKind((eState >> 3) & 0x7);
- setLength(eLen * hs.mAllocationUnitSize);
-
- return this;
- }
-
- public int getSolidity() {
- return mSolidity;
- }
-
- public void setSolidity(int solidity) {
- this.mSolidity = solidity;
- }
-
- public int getKind() {
- return mKind;
- }
-
- public void setKind(int kind) {
- this.mKind = kind;
- }
-
- public int getLength() {
- return mLength;
- }
-
- public void setLength(int length) {
- this.mLength = length;
- }
-
- @Override
- public int compareTo(HeapSegmentElement other) {
- if (mLength != other.mLength) {
- return mLength < other.mLength ? -1 : 1;
- }
- return 0;
- }
- }
-
- //* The ID of the heap that this segment belongs to.
- protected int mHeapId;
-
- //* The size of an allocation unit, in bytes. (e.g., 8 bytes)
- protected int mAllocationUnitSize;
-
- //* The virtual address of the start of this segment.
- protected long mStartAddress;
-
- //* The offset of this pices from mStartAddress, in bytes.
- protected int mOffset;
-
- //* The number of allocation units described in this segment.
- protected int mAllocationUnitCount;
-
- //* The raw data that describes the contents of this segment.
- protected ByteBuffer mUsageData;
-
- //* mStartAddress is set to this value when the segment becomes invalid.
- private final static long INVALID_START_ADDRESS = -1;
-
- /**
- * Create a new HeapSegment based on the raw contents
- * of an HPSG chunk.
- *
- * @param hpsgData The raw data from an HPSG chunk.
- * @throws BufferUnderflowException if hpsgData is too small
- * to hold the HPSG chunk header data.
- */
- public HeapSegment(ByteBuffer hpsgData) throws BufferUnderflowException {
- /* Read the HPSG chunk header.
- * These get*() calls may throw a BufferUnderflowException
- * if the underlying data isn't big enough.
- */
- hpsgData.order(ByteOrder.BIG_ENDIAN);
- mHeapId = hpsgData.getInt();
- mAllocationUnitSize = hpsgData.get();
- mStartAddress = hpsgData.getInt() & 0x00000000ffffffffL;
- mOffset = hpsgData.getInt();
- mAllocationUnitCount = hpsgData.getInt();
-
- // Hold onto the remainder of the data.
- mUsageData = hpsgData.slice();
- mUsageData.order(ByteOrder.BIG_ENDIAN); // doesn't actually matter
-
- // Validate the data.
-//xxx do it
-//xxx make sure the number of elements matches mAllocationUnitCount.
-//xxx make sure the last element doesn't have P set
- }
-
- /**
- * See if this segment still contains data, and has not been
- * appended to another segment.
- *
- * @return true if this segment has not been appended to
- * another segment.
- */
- public boolean isValid() {
- return mStartAddress != INVALID_START_ADDRESS;
- }
-
- /**
- * See if <code>other</code> comes immediately after this segment.
- *
- * @param other The HeapSegment to check.
- * @return true if <code>other</code> comes immediately after this
- * segment.
- */
- public boolean canAppend(HeapSegment other) {
- return isValid() && other.isValid() && mHeapId == other.mHeapId &&
- mAllocationUnitSize == other.mAllocationUnitSize &&
- getEndAddress() == other.getStartAddress();
- }
-
- /**
- * Append the contents of <code>other</code> to this segment
- * if it describes the segment immediately after this one.
- *
- * @param other The segment to append to this segment, if possible.
- * If appended, <code>other</code> will be invalid
- * when this method returns.
- * @return true if <code>other</code> was successfully appended to
- * this segment.
- */
- public boolean append(HeapSegment other) {
- if (canAppend(other)) {
- /* Preserve the position. The mark is not preserved,
- * but we don't use it anyway.
- */
- int pos = mUsageData.position();
-
- // Guarantee that we have enough room for the new data.
- if (mUsageData.capacity() - mUsageData.limit() <
- other.mUsageData.limit()) {
- /* Grow more than necessary in case another append()
- * is about to happen.
- */
- int newSize = mUsageData.limit() + other.mUsageData.limit();
- ByteBuffer newData = ByteBuffer.allocate(newSize * 2);
-
- mUsageData.rewind();
- newData.put(mUsageData);
- mUsageData = newData;
- }
-
- // Copy the data from the other segment and restore the position.
- other.mUsageData.rewind();
- mUsageData.put(other.mUsageData);
- mUsageData.position(pos);
-
- // Fix this segment's header to cover the new data.
- mAllocationUnitCount += other.mAllocationUnitCount;
-
- // Mark the other segment as invalid.
- other.mStartAddress = INVALID_START_ADDRESS;
- other.mUsageData = null;
-
- return true;
- } else {
- return false;
- }
- }
-
- public long getStartAddress() {
- return mStartAddress + mOffset;
- }
-
- public int getLength() {
- return mAllocationUnitSize * mAllocationUnitCount;
- }
-
- public long getEndAddress() {
- return getStartAddress() + getLength();
- }
-
- public void rewindElements() {
- if (mUsageData != null) {
- mUsageData.rewind();
- }
- }
-
- public HeapSegmentElement getNextElement(HeapSegmentElement reuse) {
- try {
- if (reuse != null) {
- return reuse.set(this);
- } else {
- return new HeapSegmentElement(this);
- }
- } catch (BufferUnderflowException ex) {
- /* Normal "end of buffer" situation.
- */
- } catch (ParseException ex) {
- /* Malformed data.
- */
-//TODO: we should catch this in the constructor
- }
- return null;
- }
-
- /*
- * Method overrides for Comparable
- */
- @Override
- public boolean equals(Object o) {
- if (o instanceof HeapSegment) {
- return compareTo((HeapSegment) o) == 0;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return mHeapId * 31 +
- mAllocationUnitSize * 31 +
- (int) mStartAddress * 31 +
- mOffset * 31 +
- mAllocationUnitCount * 31 +
- mUsageData.hashCode();
- }
-
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder();
-
- str.append("HeapSegment { heap ").append(mHeapId)
- .append(", start 0x")
- .append(Integer.toHexString((int) getStartAddress()))
- .append(", length ").append(getLength())
- .append(" }");
-
- return str.toString();
- }
-
- @Override
- public int compareTo(HeapSegment other) {
- if (mHeapId != other.mHeapId) {
- return mHeapId < other.mHeapId ? -1 : 1;
- }
- if (getStartAddress() != other.getStartAddress()) {
- return getStartAddress() < other.getStartAddress() ? -1 : 1;
- }
-
- /* If two segments have the same start address, the rest of
- * the fields should be equal. Go through the motions, though.
- * Note that we re-check the components of getStartAddress()
- * (mStartAddress and mOffset) to make sure that all fields in
- * an equal segment are equal.
- */
-
- if (mAllocationUnitSize != other.mAllocationUnitSize) {
- return mAllocationUnitSize < other.mAllocationUnitSize ? -1 : 1;
- }
- if (mStartAddress != other.mStartAddress) {
- return mStartAddress < other.mStartAddress ? -1 : 1;
- }
- if (mOffset != other.mOffset) {
- return mOffset < other.mOffset ? -1 : 1;
- }
- if (mAllocationUnitCount != other.mAllocationUnitCount) {
- return mAllocationUnitCount < other.mAllocationUnitCount ? -1 : 1;
- }
- if (mUsageData != other.mUsageData) {
- return mUsageData.compareTo(other.mUsageData);
- }
- return 0;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IDevice.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IDevice.java
deleted file mode 100644
index 452d032..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IDevice.java
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * 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.ddmlib;
-
-import com.android.ddmlib.log.LogReceiver;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * A Device. It can be a physical device or an emulator.
- */
-public interface IDevice {
-
- public final static String PROP_BUILD_VERSION = "ro.build.version.release";
- public final static String PROP_BUILD_API_LEVEL = "ro.build.version.sdk";
- public final static String PROP_BUILD_CODENAME = "ro.build.version.codename";
-
- public final static String PROP_DEBUGGABLE = "ro.debuggable";
-
- /** Serial number of the first connected emulator. */
- public final static String FIRST_EMULATOR_SN = "emulator-5554"; //$NON-NLS-1$
- /** Device change bit mask: {@link DeviceState} change. */
- public static final int CHANGE_STATE = 0x0001;
- /** Device change bit mask: {@link Client} list change. */
- public static final int CHANGE_CLIENT_LIST = 0x0002;
- /** Device change bit mask: build info change. */
- public static final int CHANGE_BUILD_INFO = 0x0004;
-
- /** @deprecated Use {@link #PROP_BUILD_API_LEVEL}. */
- @Deprecated
- public final static String PROP_BUILD_VERSION_NUMBER = PROP_BUILD_API_LEVEL;
-
- public final static String MNT_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; //$NON-NLS-1$
- public final static String MNT_ROOT = "ANDROID_ROOT"; //$NON-NLS-1$
- public final static String MNT_DATA = "ANDROID_DATA"; //$NON-NLS-1$
-
- /**
- * The state of a device.
- */
- public static enum DeviceState {
- BOOTLOADER("bootloader"), //$NON-NLS-1$
- OFFLINE("offline"), //$NON-NLS-1$
- ONLINE("device"), //$NON-NLS-1$
- RECOVERY("recovery"); //$NON-NLS-1$
-
- private String mState;
-
- DeviceState(String state) {
- mState = state;
- }
-
- /**
- * Returns a {@link DeviceState} from the string returned by <code>adb devices</code>.
- *
- * @param state the device state.
- * @return a {@link DeviceState} object or <code>null</code> if the state is unknown.
- */
- public static DeviceState getState(String state) {
- for (DeviceState deviceState : values()) {
- if (deviceState.mState.equals(state)) {
- return deviceState;
- }
- }
- return null;
- }
- }
-
- /**
- * Namespace of a Unix Domain Socket created on the device.
- */
- public static enum DeviceUnixSocketNamespace {
- ABSTRACT("localabstract"), //$NON-NLS-1$
- FILESYSTEM("localfilesystem"), //$NON-NLS-1$
- RESERVED("localreserved"); //$NON-NLS-1$
-
- private String mType;
-
- private DeviceUnixSocketNamespace(String type) {
- mType = type;
- }
-
- String getType() {
- return mType;
- }
- };
-
- /**
- * Returns the serial number of the device.
- */
- public String getSerialNumber();
-
- /**
- * Returns the name of the AVD the emulator is running.
- * <p/>This is only valid if {@link #isEmulator()} returns true.
- * <p/>If the emulator is not running any AVD (for instance it's running from an Android source
- * tree build), this method will return "<code>&lt;build&gt;</code>".
- *
- * @return the name of the AVD or <code>null</code> if there isn't any.
- */
- public String getAvdName();
-
- /**
- * Returns a (humanized) name for this device. Typically this is the AVD name for AVD's, and
- * a combination of the manufacturer name, model name & serial number for devices.
- */
- public String getName();
-
- /**
- * Returns the state of the device.
- */
- public DeviceState getState();
-
- /**
- * Returns the device properties. It contains the whole output of 'getprop'
- */
- public Map<String, String> getProperties();
-
- /**
- * Returns the number of property for this device.
- */
- public int getPropertyCount();
-
- /**
- * Returns the cached property value.
- *
- * @param name the name of the value to return.
- * @return the value or <code>null</code> if the property does not exist or has not yet been
- * cached.
- */
- public String getProperty(String name);
-
- /**
- * Returns <code>true></code> if properties have been cached
- */
- public boolean arePropertiesSet();
-
- /**
- * A variant of {@link #getProperty(String)} that will attempt to retrieve the given
- * property from device directly, without using cache.
- *
- * @param name the name of the value to return.
- * @return the value or <code>null</code> if the property does not exist
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException in case the shell command doesn't send output for a
- * given time.
- * @throws IOException in case of I/O error on the connection.
- */
- public String getPropertySync(String name) throws TimeoutException,
- AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException;
-
- /**
- * A combination of {@link #getProperty(String)} and {@link #getPropertySync(String)} that
- * will attempt to retrieve the property from cache if available, and if not, will query the
- * device directly.
- *
- * @param name the name of the value to return.
- * @return the value or <code>null</code> if the property does not exist
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException in case the shell command doesn't send output for a
- * given time.
- * @throws IOException in case of I/O error on the connection.
- */
- public String getPropertyCacheOrSync(String name) throws TimeoutException,
- AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException;
-
- /**
- * Returns a mount point.
- *
- * @param name the name of the mount point to return
- *
- * @see #MNT_EXTERNAL_STORAGE
- * @see #MNT_ROOT
- * @see #MNT_DATA
- */
- public String getMountPoint(String name);
-
- /**
- * Returns if the device is ready.
- *
- * @return <code>true</code> if {@link #getState()} returns {@link DeviceState#ONLINE}.
- */
- public boolean isOnline();
-
- /**
- * Returns <code>true</code> if the device is an emulator.
- */
- public boolean isEmulator();
-
- /**
- * Returns if the device is offline.
- *
- * @return <code>true</code> if {@link #getState()} returns {@link DeviceState#OFFLINE}.
- */
- public boolean isOffline();
-
- /**
- * Returns if the device is in bootloader mode.
- *
- * @return <code>true</code> if {@link #getState()} returns {@link DeviceState#BOOTLOADER}.
- */
- public boolean isBootLoader();
-
- /**
- * Returns whether the {@link Device} has {@link Client}s.
- */
- public boolean hasClients();
-
- /**
- * Returns the array of clients.
- */
- public Client[] getClients();
-
- /**
- * Returns a {@link Client} by its application name.
- *
- * @param applicationName the name of the application
- * @return the <code>Client</code> object or <code>null</code> if no match was found.
- */
- public Client getClient(String applicationName);
-
- /**
- * Returns a {@link SyncService} object to push / pull files to and from the device.
- *
- * @return <code>null</code> if the SyncService couldn't be created. This can happen if adb
- * refuse to open the connection because the {@link IDevice} is invalid
- * (or got disconnected).
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException if the connection with adb failed.
- */
- public SyncService getSyncService()
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Returns a {@link FileListingService} for this device.
- */
- public FileListingService getFileListingService();
-
- /**
- * Takes a screen shot of the device and returns it as a {@link RawImage}.
- *
- * @return the screenshot as a <code>RawImage</code> or <code>null</code> if something
- * went wrong.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public RawImage getScreenshot() throws TimeoutException, AdbCommandRejectedException,
- IOException;
-
- /**
- * Executes a shell command on the device, and sends the result to a <var>receiver</var>
- * <p/>This is similar to calling
- * <code>executeShellCommand(command, receiver, DdmPreferences.getTimeOut())</code>.
- *
- * @param command the shell command to execute
- * @param receiver the {@link IShellOutputReceiver} that will receives the output of the shell
- * command
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException in case the shell command doesn't send output
- * for a given time.
- * @throws IOException in case of I/O error on the connection.
- *
- * @see #executeShellCommand(String, IShellOutputReceiver, int)
- * @see DdmPreferences#getTimeOut()
- */
- public void executeShellCommand(String command, IShellOutputReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * Executes a shell command on the device, and sends the result to a <var>receiver</var>.
- * <p/><var>maxTimeToOutputResponse</var> is used as a maximum waiting time when expecting the
- * command output from the device.<br>
- * At any time, if the shell command does not output anything for a period longer than
- * <var>maxTimeToOutputResponse</var>, then the method will throw
- * {@link ShellCommandUnresponsiveException}.
- * <p/>For commands like log output, a <var>maxTimeToOutputResponse</var> value of 0, meaning
- * that the method will never throw and will block until the receiver's
- * {@link IShellOutputReceiver#isCancelled()} returns <code>true</code>, should be
- * used.
- *
- * @param command the shell command to execute
- * @param receiver the {@link IShellOutputReceiver} that will receives the output of the shell
- * command
- * @param maxTimeToOutputResponse the maximum amount of time during which the command is allowed
- * to not output any response. A value of 0 means the method will wait forever
- * (until the <var>receiver</var> cancels the execution) for command output and
- * never throw.
- * @throws TimeoutException in case of timeout on the connection when sending the command.
- * @throws AdbCommandRejectedException if adb rejects the command.
- * @throws ShellCommandUnresponsiveException in case the shell command doesn't send any output
- * for a period longer than <var>maxTimeToOutputResponse</var>.
- * @throws IOException in case of I/O error on the connection.
- *
- * @see DdmPreferences#getTimeOut()
- */
- public void executeShellCommand(String command, IShellOutputReceiver receiver,
- int maxTimeToOutputResponse)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * Runs the event log service and outputs the event log to the {@link LogReceiver}.
- * <p/>This call is blocking until {@link LogReceiver#isCancelled()} returns true.
- * @param receiver the receiver to receive the event log entries.
- * @throws TimeoutException in case of timeout on the connection. This can only be thrown if the
- * timeout happens during setup. Once logs start being received, no timeout will occur as it's
- * not possible to detect a difference between no log and timeout.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public void runEventLogService(LogReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Runs the log service for the given log and outputs the log to the {@link LogReceiver}.
- * <p/>This call is blocking until {@link LogReceiver#isCancelled()} returns true.
- *
- * @param logname the logname of the log to read from.
- * @param receiver the receiver to receive the event log entries.
- * @throws TimeoutException in case of timeout on the connection. This can only be thrown if the
- * timeout happens during setup. Once logs start being received, no timeout will
- * occur as it's not possible to detect a difference between no log and timeout.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public void runLogService(String logname, LogReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Creates a port forwarding between a local and a remote port.
- *
- * @param localPort the local port to forward
- * @param remotePort the remote port.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public void createForward(int localPort, int remotePort)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Creates a port forwarding between a local TCP port and a remote Unix Domain Socket.
- *
- * @param localPort the local port to forward
- * @param remoteSocketName name of the unix domain socket created on the device
- * @param namespace namespace in which the unix domain socket was created
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public void createForward(int localPort, String remoteSocketName,
- DeviceUnixSocketNamespace namespace)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Removes a port forwarding between a local and a remote port.
- *
- * @param localPort the local port to forward
- * @param remotePort the remote port.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public void removeForward(int localPort, int remotePort)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Removes an existing port forwarding between a local and a remote port.
- *
- * @param localPort the local port to forward
- * @param remoteSocketName the remote unix domain socket name.
- * @param namespace namespace in which the unix domain socket was created
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- */
- public void removeForward(int localPort, String remoteSocketName,
- DeviceUnixSocketNamespace namespace)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Returns the name of the client by pid or <code>null</code> if pid is unknown
- * @param pid the pid of the client.
- */
- public String getClientName(int pid);
-
- /**
- * Push a single file.
- * @param local the local filepath.
- * @param remote The remote filepath.
- *
- * @throws IOException in case of I/O error on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws TimeoutException in case of a timeout reading responses from the device.
- * @throws SyncException if file could not be pushed
- */
- public void pushFile(String local, String remote)
- throws IOException, AdbCommandRejectedException, TimeoutException, SyncException;
-
- /**
- * Pulls a single file.
- *
- * @param remote the full path to the remote file
- * @param local The local destination.
- *
- * @throws IOException in case of an IO exception.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws TimeoutException in case of a timeout reading responses from the device.
- * @throws SyncException in case of a sync exception.
- */
- public void pullFile(String remote, String local)
- throws IOException, AdbCommandRejectedException, TimeoutException, SyncException;
-
- /**
- * Installs an Android application on device. This is a helper method that combines the
- * syncPackageToDevice, installRemotePackage, and removePackage steps
- *
- * @param packageFilePath the absolute file system path to file on local host to install
- * @param reinstall set to <code>true</code> if re-install of app should be performed
- * @param extraArgs optional extra arguments to pass. See 'adb shell pm install --help' for
- * available options.
- * @return a {@link String} with an error code, or <code>null</code> if success.
- * @throws InstallException if the installation fails.
- */
- public String installPackage(String packageFilePath, boolean reinstall, String... extraArgs)
- throws InstallException;
-
- /**
- * Pushes a file to device
- *
- * @param localFilePath the absolute path to file on local host
- * @return {@link String} destination path on device for file
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException in case of I/O error on the connection.
- * @throws SyncException if an error happens during the push of the package on the device.
- */
- public String syncPackageToDevice(String localFilePath)
- throws TimeoutException, AdbCommandRejectedException, IOException, SyncException;
-
- /**
- * Installs the application package that was pushed to a temporary location on the device.
- *
- * @param remoteFilePath absolute file path to package file on device
- * @param reinstall set to <code>true</code> if re-install of app should be performed
- * @param extraArgs optional extra arguments to pass. See 'adb shell pm install --help' for
- * available options.
- * @throws InstallException if the installation fails.
- */
- public String installRemotePackage(String remoteFilePath, boolean reinstall,
- String... extraArgs) throws InstallException;
-
- /**
- * Removes a file from device.
- *
- * @param remoteFilePath path on device of file to remove
- * @throws InstallException if the installation fails.
- */
- public void removeRemotePackage(String remoteFilePath) throws InstallException;
-
- /**
- * Uninstalls an package from the device.
- *
- * @param packageName the Android application package name to uninstall
- * @return a {@link String} with an error code, or <code>null</code> if success.
- * @throws InstallException if the uninstallation fails.
- */
- public String uninstallPackage(String packageName) throws InstallException;
-
- /**
- * Reboot the device.
- *
- * @param into the bootloader name to reboot into, or null to just reboot the device.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException
- */
- public void reboot(String into)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * Return the device's battery level, from 0 to 100 percent.
- * <p/>
- * The battery level may be cached. Only queries the device for its
- * battery level if 5 minutes have expired since the last successful query.
- *
- * @return the battery level or <code>null</code> if it could not be retrieved
- */
- public Integer getBatteryLevel() throws TimeoutException,
- AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException;
-
- /**
- * Return the device's battery level, from 0 to 100 percent.
- * <p/>
- * The battery level may be cached. Only queries the device for its
- * battery level if <code>freshnessMs</code> ms have expired since the last successful query.
- *
- * @param freshnessMs
- * @return the battery level or <code>null</code> if it could not be retrieved
- * @throws ShellCommandUnresponsiveException
- */
- public Integer getBatteryLevel(long freshnessMs) throws TimeoutException,
- AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException;
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IShellOutputReceiver.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IShellOutputReceiver.java
deleted file mode 100644
index fb671bb..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IShellOutputReceiver.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-/**
- * Classes which implement this interface provide methods that deal with out from a remote shell
- * command on a device/emulator.
- */
-public interface IShellOutputReceiver {
- /**
- * Called every time some new data is available.
- * @param data The new data.
- * @param offset The offset at which the new data starts.
- * @param length The length of the new data.
- */
- public void addOutput(byte[] data, int offset, int length);
-
- /**
- * Called at the end of the process execution (unless the process was
- * canceled). This allows the receiver to terminate and flush whatever
- * data was not yet processed.
- */
- public void flush();
-
- /**
- * Cancel method to stop the execution of the remote shell command.
- * @return true to cancel the execution of the command.
- */
- public boolean isCancelled();
-};
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IStackTraceInfo.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IStackTraceInfo.java
deleted file mode 100644
index 3b9d730..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/IStackTraceInfo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-/**
- * Classes which implement this interface provide a method that returns a stack trace.
- */
-public interface IStackTraceInfo {
-
- /**
- * Returns the stack trace. This can be <code>null</code>.
- */
- public StackTraceElement[] getStackTrace();
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/InstallException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/InstallException.java
deleted file mode 100644
index 7aa718f..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/InstallException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib;
-
-/**
- * Thrown if installation or uninstallation of application fails.
- */
-public class InstallException extends CanceledException {
- private static final long serialVersionUID = 1L;
-
- public InstallException(Throwable cause) {
- super(cause.getMessage(), cause);
- }
-
- public InstallException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Returns true if the installation was canceled by user input. This can typically only
- * happen in the sync phase.
- */
- @Override
- public boolean wasCanceled() {
- Throwable cause = getCause();
- return cause instanceof SyncException && ((SyncException)cause).wasCanceled();
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/JdwpPacket.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/JdwpPacket.java
deleted file mode 100644
index 92bbb82..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/JdwpPacket.java
+++ /dev/null
@@ -1,371 +0,0 @@
-/* //device/tools/ddms/libs/ddmlib/src/com/android/ddmlib/JdwpPacket.java
-**
-** Copyright 2007, 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.ddmlib;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.SocketChannel;
-
-/**
- * A JDWP packet, sitting at the start of a ByteBuffer somewhere.
- *
- * This allows us to wrap a "pointer" to the data with the results of
- * decoding the packet.
- *
- * None of the operations here are synchronized. If multiple threads will
- * be accessing the same ByteBuffers, external sync will be required.
- *
- * Use the constructor to create an empty packet, or "findPacket()" to
- * wrap a JdwpPacket around existing data.
- */
-final class JdwpPacket {
- // header len
- public static final int JDWP_HEADER_LEN = 11;
-
- // results from findHandshake
- public static final int HANDSHAKE_GOOD = 1;
- public static final int HANDSHAKE_NOTYET = 2;
- public static final int HANDSHAKE_BAD = 3;
-
- // our cmdSet/cmd
- private static final int DDMS_CMD_SET = 0xc7; // 'G' + 128
- private static final int DDMS_CMD = 0x01;
-
- // "flags" field
- private static final int REPLY_PACKET = 0x80;
-
- // this is sent and expected at the start of a JDWP connection
- private static final byte[] mHandshake = {
- 'J', 'D', 'W', 'P', '-', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e'
- };
-
- public static final int HANDSHAKE_LEN = mHandshake.length;
-
- private ByteBuffer mBuffer;
- private int mLength, mId, mFlags, mCmdSet, mCmd, mErrCode;
- private boolean mIsNew;
-
- private static int mSerialId = 0x40000000;
-
-
- /**
- * Create a new, empty packet, in "buf".
- */
- JdwpPacket(ByteBuffer buf) {
- mBuffer = buf;
- mIsNew = true;
- }
-
- /**
- * Finish a packet created with newPacket().
- *
- * This always creates a command packet, with the next serial number
- * in sequence.
- *
- * We have to take "payloadLength" as an argument because we can't
- * see the position in the "slice" returned by getPayload(). We could
- * fish it out of the chunk header, but it's legal for there to be
- * more than one chunk in a JDWP packet.
- *
- * On exit, "position" points to the end of the data.
- */
- void finishPacket(int payloadLength) {
- assert mIsNew;
-
- ByteOrder oldOrder = mBuffer.order();
- mBuffer.order(ChunkHandler.CHUNK_ORDER);
-
- mLength = JDWP_HEADER_LEN + payloadLength;
- mId = getNextSerial();
- mFlags = 0;
- mCmdSet = DDMS_CMD_SET;
- mCmd = DDMS_CMD;
-
- mBuffer.putInt(0x00, mLength);
- mBuffer.putInt(0x04, mId);
- mBuffer.put(0x08, (byte) mFlags);
- mBuffer.put(0x09, (byte) mCmdSet);
- mBuffer.put(0x0a, (byte) mCmd);
-
- mBuffer.order(oldOrder);
- mBuffer.position(mLength);
- }
-
- /**
- * Get the next serial number. This creates a unique serial number
- * across all connections, not just for the current connection. This
- * is a useful property when debugging, but isn't necessary.
- *
- * We can't synchronize on an int, so we use a sync method.
- */
- private static synchronized int getNextSerial() {
- return mSerialId++;
- }
-
- /**
- * Return a slice of the byte buffer, positioned past the JDWP header
- * to the start of the chunk header. The buffer's limit will be set
- * to the size of the payload if the size is known; if this is a
- * packet under construction the limit will be set to the end of the
- * buffer.
- *
- * Doesn't examine the packet at all -- works on empty buffers.
- */
- ByteBuffer getPayload() {
- ByteBuffer buf;
- int oldPosn = mBuffer.position();
-
- mBuffer.position(JDWP_HEADER_LEN);
- buf = mBuffer.slice(); // goes from position to limit
- mBuffer.position(oldPosn);
-
- if (mLength > 0)
- buf.limit(mLength - JDWP_HEADER_LEN);
- else
- assert mIsNew;
- buf.order(ChunkHandler.CHUNK_ORDER);
- return buf;
- }
-
- /**
- * Returns "true" if this JDWP packet has a JDWP command type.
- *
- * This never returns "true" for reply packets.
- */
- boolean isDdmPacket() {
- return (mFlags & REPLY_PACKET) == 0 &&
- mCmdSet == DDMS_CMD_SET &&
- mCmd == DDMS_CMD;
- }
-
- /**
- * Returns "true" if this JDWP packet is tagged as a reply.
- */
- boolean isReply() {
- return (mFlags & REPLY_PACKET) != 0;
- }
-
- /**
- * Returns "true" if this JDWP packet is a reply with a nonzero
- * error code.
- */
- boolean isError() {
- return isReply() && mErrCode != 0;
- }
-
- /**
- * Returns "true" if this JDWP packet has no data.
- */
- boolean isEmpty() {
- return (mLength == JDWP_HEADER_LEN);
- }
-
- /**
- * Return the packet's ID. For a reply packet, this allows us to
- * match the reply with the original request.
- */
- int getId() {
- return mId;
- }
-
- /**
- * Return the length of a packet. This includes the header, so an
- * empty packet is 11 bytes long.
- */
- int getLength() {
- return mLength;
- }
-
- /**
- * Write our packet to "chan". Consumes the packet as part of the
- * write.
- *
- * The JDWP packet starts at offset 0 and ends at mBuffer.position().
- */
- void writeAndConsume(SocketChannel chan) throws IOException {
- int oldLimit;
-
- //Log.i("ddms", "writeAndConsume: pos=" + mBuffer.position()
- // + ", limit=" + mBuffer.limit());
-
- assert mLength > 0;
-
- mBuffer.flip(); // limit<-posn, posn<-0
- oldLimit = mBuffer.limit();
- mBuffer.limit(mLength);
- while (mBuffer.position() != mBuffer.limit()) {
- chan.write(mBuffer);
- }
- // position should now be at end of packet
- assert mBuffer.position() == mLength;
-
- mBuffer.limit(oldLimit);
- mBuffer.compact(); // shift posn...limit, posn<-pending data
-
- //Log.i("ddms", " : pos=" + mBuffer.position()
- // + ", limit=" + mBuffer.limit());
- }
-
- /**
- * "Move" the packet data out of the buffer we're sitting on and into
- * buf at the current position.
- */
- void movePacket(ByteBuffer buf) {
- Log.v("ddms", "moving " + mLength + " bytes");
- int oldPosn = mBuffer.position();
-
- mBuffer.position(0);
- mBuffer.limit(mLength);
- buf.put(mBuffer);
- mBuffer.position(mLength);
- mBuffer.limit(oldPosn);
- mBuffer.compact(); // shift posn...limit, posn<-pending data
- }
-
- /**
- * Consume the JDWP packet.
- *
- * On entry and exit, "position" is the #of bytes in the buffer.
- */
- void consume()
- {
- //Log.d("ddms", "consuming " + mLength + " bytes");
- //Log.d("ddms", " posn=" + mBuffer.position()
- // + ", limit=" + mBuffer.limit());
-
- /*
- * The "flip" call sets "limit" equal to the position (usually the
- * end of data) and "position" equal to zero.
- *
- * compact() copies everything from "position" and "limit" to the
- * start of the buffer, sets "position" to the end of data, and
- * sets "limit" to the capacity.
- *
- * On entry, "position" is set to the amount of data in the buffer
- * and "limit" is set to the capacity. We want to call flip()
- * so that position..limit spans our data, advance "position" past
- * the current packet, then compact.
- */
- mBuffer.flip(); // limit<-posn, posn<-0
- mBuffer.position(mLength);
- mBuffer.compact(); // shift posn...limit, posn<-pending data
- mLength = 0;
- //Log.d("ddms", " after compact, posn=" + mBuffer.position()
- // + ", limit=" + mBuffer.limit());
- }
-
- /**
- * Find the JDWP packet at the start of "buf". The start is known,
- * but the length has to be parsed out.
- *
- * On entry, the packet data in "buf" must start at offset 0 and end
- * at "position". "limit" should be set to the buffer capacity. This
- * method does not alter "buf"s attributes.
- *
- * Returns a new JdwpPacket if a full one is found in the buffer. If
- * not, returns null. Throws an exception if the data doesn't look like
- * a valid JDWP packet.
- */
- static JdwpPacket findPacket(ByteBuffer buf) {
- int count = buf.position();
- int length, id, flags, cmdSet, cmd;
-
- if (count < JDWP_HEADER_LEN)
- return null;
-
- ByteOrder oldOrder = buf.order();
- buf.order(ChunkHandler.CHUNK_ORDER);
-
- length = buf.getInt(0x00);
- id = buf.getInt(0x04);
- flags = buf.get(0x08) & 0xff;
- cmdSet = buf.get(0x09) & 0xff;
- cmd = buf.get(0x0a) & 0xff;
-
- buf.order(oldOrder);
-
- if (length < JDWP_HEADER_LEN)
- throw new BadPacketException();
- if (count < length)
- return null;
-
- JdwpPacket pkt = new JdwpPacket(buf);
- //pkt.mBuffer = buf;
- pkt.mLength = length;
- pkt.mId = id;
- pkt.mFlags = flags;
-
- if ((flags & REPLY_PACKET) == 0) {
- pkt.mCmdSet = cmdSet;
- pkt.mCmd = cmd;
- pkt.mErrCode = -1;
- } else {
- pkt.mCmdSet = -1;
- pkt.mCmd = -1;
- pkt.mErrCode = cmdSet | (cmd << 8);
- }
-
- return pkt;
- }
-
- /**
- * Like findPacket(), but when we're expecting the JDWP handshake.
- *
- * Returns one of:
- * HANDSHAKE_GOOD - found handshake, looks good
- * HANDSHAKE_BAD - found enough data, but it's wrong
- * HANDSHAKE_NOTYET - not enough data has been read yet
- */
- static int findHandshake(ByteBuffer buf) {
- int count = buf.position();
- int i;
-
- if (count < mHandshake.length)
- return HANDSHAKE_NOTYET;
-
- for (i = mHandshake.length -1; i >= 0; --i) {
- if (buf.get(i) != mHandshake[i])
- return HANDSHAKE_BAD;
- }
-
- return HANDSHAKE_GOOD;
- }
-
- /**
- * Remove the handshake string from the buffer.
- *
- * On entry and exit, "position" is the #of bytes in the buffer.
- */
- static void consumeHandshake(ByteBuffer buf) {
- // in theory, nothing else can have arrived, so this is overkill
- buf.flip(); // limit<-posn, posn<-0
- buf.position(mHandshake.length);
- buf.compact(); // shift posn...limit, posn<-pending data
- }
-
- /**
- * Copy the handshake string into the output buffer.
- *
- * On exit, "buf"s position will be advanced.
- */
- static void putHandshake(ByteBuffer buf) {
- buf.put(mHandshake);
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Log.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Log.java
deleted file mode 100644
index 55f7aab..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/Log.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-/**
- * Log class that mirrors the API in main Android sources.
- * <p/>Default behavior outputs the log to {@link System#out}. Use
- * {@link #setLogOutput(com.android.ddmlib.Log.ILogOutput)} to redirect the log somewhere else.
- */
-public final class Log {
-
- /**
- * Log Level enum.
- */
- public enum LogLevel {
- VERBOSE(2, "verbose", 'V'), //$NON-NLS-1$
- DEBUG(3, "debug", 'D'), //$NON-NLS-1$
- INFO(4, "info", 'I'), //$NON-NLS-1$
- WARN(5, "warn", 'W'), //$NON-NLS-1$
- ERROR(6, "error", 'E'), //$NON-NLS-1$
- ASSERT(7, "assert", 'A'); //$NON-NLS-1$
-
- private int mPriorityLevel;
- private String mStringValue;
- private char mPriorityLetter;
-
- LogLevel(int intPriority, String stringValue, char priorityChar) {
- mPriorityLevel = intPriority;
- mStringValue = stringValue;
- mPriorityLetter = priorityChar;
- }
-
- public static LogLevel getByString(String value) {
- for (LogLevel mode : values()) {
- if (mode.mStringValue.equals(value)) {
- return mode;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the {@link LogLevel} enum matching the specified letter.
- * @param letter the letter matching a <code>LogLevel</code> enum
- * @return a <code>LogLevel</code> object or <code>null</code> if no match were found.
- */
- public static LogLevel getByLetter(char letter) {
- for (LogLevel mode : values()) {
- if (mode.mPriorityLetter == letter) {
- return mode;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the {@link LogLevel} enum matching the specified letter.
- * <p/>
- * The letter is passed as a {@link String} argument, but only the first character
- * is used.
- * @param letter the letter matching a <code>LogLevel</code> enum
- * @return a <code>LogLevel</code> object or <code>null</code> if no match were found.
- */
- public static LogLevel getByLetterString(String letter) {
- if (letter.length() > 0) {
- return getByLetter(letter.charAt(0));
- }
-
- return null;
- }
-
- /**
- * Returns the letter identifying the priority of the {@link LogLevel}.
- */
- public char getPriorityLetter() {
- return mPriorityLetter;
- }
-
- /**
- * Returns the numerical value of the priority.
- */
- public int getPriority() {
- return mPriorityLevel;
- }
-
- /**
- * Returns a non translated string representing the LogLevel.
- */
- public String getStringValue() {
- return mStringValue;
- }
- }
-
- /**
- * Classes which implement this interface provides methods that deal with outputting log
- * messages.
- */
- public interface ILogOutput {
- /**
- * Sent when a log message needs to be printed.
- * @param logLevel The {@link LogLevel} enum representing the priority of the message.
- * @param tag The tag associated with the message.
- * @param message The message to display.
- */
- public void printLog(LogLevel logLevel, String tag, String message);
-
- /**
- * Sent when a log message needs to be printed, and, if possible, displayed to the user
- * in a dialog box.
- * @param logLevel The {@link LogLevel} enum representing the priority of the message.
- * @param tag The tag associated with the message.
- * @param message The message to display.
- */
- public void printAndPromptLog(LogLevel logLevel, String tag, String message);
- }
-
- private static LogLevel mLevel = DdmPreferences.getLogLevel();
-
- private static ILogOutput sLogOutput;
-
- private static final char[] mSpaceLine = new char[72];
- private static final char[] mHexDigit = new char[]
- { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
- static {
- /* prep for hex dump */
- int i = mSpaceLine.length-1;
- while (i >= 0)
- mSpaceLine[i--] = ' ';
- mSpaceLine[0] = mSpaceLine[1] = mSpaceLine[2] = mSpaceLine[3] = '0';
- mSpaceLine[4] = '-';
- }
-
- static final class Config {
- static final boolean LOGV = true;
- static final boolean LOGD = true;
- };
-
- private Log() {}
-
- /**
- * Outputs a {@link LogLevel#VERBOSE} level message.
- * @param tag The tag associated with the message.
- * @param message The message to output.
- */
- public static void v(String tag, String message) {
- println(LogLevel.VERBOSE, tag, message);
- }
-
- /**
- * Outputs a {@link LogLevel#DEBUG} level message.
- * @param tag The tag associated with the message.
- * @param message The message to output.
- */
- public static void d(String tag, String message) {
- println(LogLevel.DEBUG, tag, message);
- }
-
- /**
- * Outputs a {@link LogLevel#INFO} level message.
- * @param tag The tag associated with the message.
- * @param message The message to output.
- */
- public static void i(String tag, String message) {
- println(LogLevel.INFO, tag, message);
- }
-
- /**
- * Outputs a {@link LogLevel#WARN} level message.
- * @param tag The tag associated with the message.
- * @param message The message to output.
- */
- public static void w(String tag, String message) {
- println(LogLevel.WARN, tag, message);
- }
-
- /**
- * Outputs a {@link LogLevel#ERROR} level message.
- * @param tag The tag associated with the message.
- * @param message The message to output.
- */
- public static void e(String tag, String message) {
- println(LogLevel.ERROR, tag, message);
- }
-
- /**
- * Outputs a log message and attempts to display it in a dialog.
- * @param tag The tag associated with the message.
- * @param message The message to output.
- */
- public static void logAndDisplay(LogLevel logLevel, String tag, String message) {
- if (sLogOutput != null) {
- sLogOutput.printAndPromptLog(logLevel, tag, message);
- } else {
- println(logLevel, tag, message);
- }
- }
-
- /**
- * Outputs a {@link LogLevel#ERROR} level {@link Throwable} information.
- * @param tag The tag associated with the message.
- * @param throwable The {@link Throwable} to output.
- */
- public static void e(String tag, Throwable throwable) {
- if (throwable != null) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
-
- throwable.printStackTrace(pw);
- println(LogLevel.ERROR, tag, throwable.getMessage() + '\n' + sw.toString());
- }
- }
-
- static void setLevel(LogLevel logLevel) {
- mLevel = logLevel;
- }
-
- /**
- * Sets the {@link ILogOutput} to use to print the logs. If not set, {@link System#out}
- * will be used.
- * @param logOutput The {@link ILogOutput} to use to print the log.
- */
- public static void setLogOutput(ILogOutput logOutput) {
- sLogOutput = logOutput;
- }
-
- /**
- * Show hex dump.
- * <p/>
- * Local addition. Output looks like:
- * 1230- 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef
- * <p/>
- * Uses no string concatenation; creates one String object per line.
- */
- static void hexDump(String tag, LogLevel level, byte[] data, int offset, int length) {
-
- int kHexOffset = 6;
- int kAscOffset = 55;
- char[] line = new char[mSpaceLine.length];
- int addr, baseAddr, count;
- int i, ch;
- boolean needErase = true;
-
- //Log.w(tag, "HEX DUMP: off=" + offset + ", length=" + length);
-
- baseAddr = 0;
- while (length != 0) {
- if (length > 16) {
- // full line
- count = 16;
- } else {
- // partial line; re-copy blanks to clear end
- count = length;
- needErase = true;
- }
-
- if (needErase) {
- System.arraycopy(mSpaceLine, 0, line, 0, mSpaceLine.length);
- needErase = false;
- }
-
- // output the address (currently limited to 4 hex digits)
- addr = baseAddr;
- addr &= 0xffff;
- ch = 3;
- while (addr != 0) {
- line[ch] = mHexDigit[addr & 0x0f];
- ch--;
- addr >>>= 4;
- }
-
- // output hex digits and ASCII chars
- ch = kHexOffset;
- for (i = 0; i < count; i++) {
- byte val = data[offset + i];
-
- line[ch++] = mHexDigit[(val >>> 4) & 0x0f];
- line[ch++] = mHexDigit[val & 0x0f];
- ch++;
-
- if (val >= 0x20 && val < 0x7f)
- line[kAscOffset + i] = (char) val;
- else
- line[kAscOffset + i] = '.';
- }
-
- println(level, tag, new String(line));
-
- // advance to next chunk of data
- length -= count;
- offset += count;
- baseAddr += count;
- }
-
- }
-
- /**
- * Dump the entire contents of a byte array with DEBUG priority.
- */
- static void hexDump(byte[] data) {
- hexDump("ddms", LogLevel.DEBUG, data, 0, data.length);
- }
-
- /* currently prints to stdout; could write to a log window */
- private static void println(LogLevel logLevel, String tag, String message) {
- if (logLevel.getPriority() >= mLevel.getPriority()) {
- if (sLogOutput != null) {
- sLogOutput.printLog(logLevel, tag, message);
- } else {
- printLog(logLevel, tag, message);
- }
- }
- }
-
- /**
- * Prints a log message.
- * @param logLevel
- * @param tag
- * @param message
- */
- public static void printLog(LogLevel logLevel, String tag, String message) {
- System.out.print(getLogFormatString(logLevel, tag, message));
- }
-
- /**
- * Formats a log message.
- * @param logLevel
- * @param tag
- * @param message
- */
- public static String getLogFormatString(LogLevel logLevel, String tag, String message) {
- SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss");
- return String.format("%s %c/%s: %s\n", formatter.format(new Date()),
- logLevel.getPriorityLetter(), tag, message);
- }
-}
-
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MonitorThread.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MonitorThread.java
deleted file mode 100644
index eae4707..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MonitorThread.java
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-
-import com.android.ddmlib.DebugPortManager.IDebugPortProvider;
-import com.android.ddmlib.Log.LogLevel;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.nio.channels.CancelledKeyException;
-import java.nio.channels.NotYetBoundException;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.ServerSocketChannel;
-import java.nio.channels.SocketChannel;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-/**
- * Monitor open connections.
- */
-final class MonitorThread extends Thread {
-
- // For broadcasts to message handlers
- //private static final int CLIENT_CONNECTED = 1;
-
- private static final int CLIENT_READY = 2;
-
- private static final int CLIENT_DISCONNECTED = 3;
-
- private volatile boolean mQuit = false;
-
- // List of clients we're paying attention to
- private ArrayList<Client> mClientList;
-
- // The almighty mux
- private Selector mSelector;
-
- // Map chunk types to handlers
- private HashMap<Integer, ChunkHandler> mHandlerMap;
-
- // port for "debug selected"
- private ServerSocketChannel mDebugSelectedChan;
-
- private int mNewDebugSelectedPort;
-
- private int mDebugSelectedPort = -1;
-
- /**
- * "Selected" client setup to answer debugging connection to the mNewDebugSelectedPort port.
- */
- private Client mSelectedClient = null;
-
- // singleton
- private static MonitorThread mInstance;
-
- /**
- * Generic constructor.
- */
- private MonitorThread() {
- super("Monitor");
- mClientList = new ArrayList<Client>();
- mHandlerMap = new HashMap<Integer, ChunkHandler>();
-
- mNewDebugSelectedPort = DdmPreferences.getSelectedDebugPort();
- }
-
- /**
- * Creates and return the singleton instance of the client monitor thread.
- */
- static MonitorThread createInstance() {
- return mInstance = new MonitorThread();
- }
-
- /**
- * Get singleton instance of the client monitor thread.
- */
- static MonitorThread getInstance() {
- return mInstance;
- }
-
-
- /**
- * Sets or changes the port number for "debug selected".
- */
- synchronized void setDebugSelectedPort(int port) throws IllegalStateException {
- if (mInstance == null) {
- return;
- }
-
- if (AndroidDebugBridge.getClientSupport() == false) {
- return;
- }
-
- if (mDebugSelectedChan != null) {
- Log.d("ddms", "Changing debug-selected port to " + port);
- mNewDebugSelectedPort = port;
- wakeup();
- } else {
- // we set mNewDebugSelectedPort instead of mDebugSelectedPort so that it's automatically
- // opened on the first run loop.
- mNewDebugSelectedPort = port;
- }
- }
-
- /**
- * Sets the client to accept debugger connection on the custom "Selected debug port".
- * @param selectedClient the client. Can be null.
- */
- synchronized void setSelectedClient(Client selectedClient) {
- if (mInstance == null) {
- return;
- }
-
- if (mSelectedClient != selectedClient) {
- Client oldClient = mSelectedClient;
- mSelectedClient = selectedClient;
-
- if (oldClient != null) {
- oldClient.update(Client.CHANGE_PORT);
- }
-
- if (mSelectedClient != null) {
- mSelectedClient.update(Client.CHANGE_PORT);
- }
- }
- }
-
- /**
- * Returns the client accepting debugger connection on the custom "Selected debug port".
- */
- Client getSelectedClient() {
- return mSelectedClient;
- }
-
-
- /**
- * Returns "true" if we want to retry connections to clients if we get a bad
- * JDWP handshake back, "false" if we want to just mark them as bad and
- * leave them alone.
- */
- boolean getRetryOnBadHandshake() {
- return true; // TODO? make configurable
- }
-
- /**
- * Get an array of known clients.
- */
- Client[] getClients() {
- synchronized (mClientList) {
- return mClientList.toArray(new Client[0]);
- }
- }
-
- /**
- * Register "handler" as the handler for type "type".
- */
- synchronized void registerChunkHandler(int type, ChunkHandler handler) {
- if (mInstance == null) {
- return;
- }
-
- synchronized (mHandlerMap) {
- if (mHandlerMap.get(type) == null) {
- mHandlerMap.put(type, handler);
- }
- }
- }
-
- /**
- * Watch for activity from clients and debuggers.
- */
- @Override
- public void run() {
- Log.d("ddms", "Monitor is up");
-
- // create a selector
- try {
- mSelector = Selector.open();
- } catch (IOException ioe) {
- Log.logAndDisplay(LogLevel.ERROR, "ddms",
- "Failed to initialize Monitor Thread: " + ioe.getMessage());
- return;
- }
-
- while (!mQuit) {
-
- try {
- /*
- * sync with new registrations: we wait until addClient is done before going through
- * and doing mSelector.select() again.
- * @see {@link #addClient(Client)}
- */
- synchronized (mClientList) {
- }
-
- // (re-)open the "debug selected" port, if it's not opened yet or
- // if the port changed.
- try {
- if (AndroidDebugBridge.getClientSupport()) {
- if ((mDebugSelectedChan == null ||
- mNewDebugSelectedPort != mDebugSelectedPort) &&
- mNewDebugSelectedPort != -1) {
- if (reopenDebugSelectedPort()) {
- mDebugSelectedPort = mNewDebugSelectedPort;
- }
- }
- }
- } catch (IOException ioe) {
- Log.e("ddms",
- "Failed to reopen debug port for Selected Client to: " + mNewDebugSelectedPort);
- Log.e("ddms", ioe);
- mNewDebugSelectedPort = mDebugSelectedPort; // no retry
- }
-
- int count;
- try {
- count = mSelector.select();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- continue;
- } catch (CancelledKeyException cke) {
- continue;
- }
-
- if (count == 0) {
- // somebody called wakeup() ?
- // Log.i("ddms", "selector looping");
- continue;
- }
-
- Set<SelectionKey> keys = mSelector.selectedKeys();
- Iterator<SelectionKey> iter = keys.iterator();
-
- while (iter.hasNext()) {
- SelectionKey key = iter.next();
- iter.remove();
-
- try {
- if (key.attachment() instanceof Client) {
- processClientActivity(key);
- }
- else if (key.attachment() instanceof Debugger) {
- processDebuggerActivity(key);
- }
- else if (key.attachment() instanceof MonitorThread) {
- processDebugSelectedActivity(key);
- }
- else {
- Log.e("ddms", "unknown activity key");
- }
- } catch (Exception e) {
- // we don't want to have our thread be killed because of any uncaught
- // exception, so we intercept all here.
- Log.e("ddms", "Exception during activity from Selector.");
- Log.e("ddms", e);
- }
- }
- } catch (Exception e) {
- // we don't want to have our thread be killed because of any uncaught
- // exception, so we intercept all here.
- Log.e("ddms", "Exception MonitorThread.run()");
- Log.e("ddms", e);
- }
- }
- }
-
-
- /**
- * Returns the port on which the selected client listen for debugger
- */
- int getDebugSelectedPort() {
- return mDebugSelectedPort;
- }
-
- /*
- * Something happened. Figure out what.
- */
- private void processClientActivity(SelectionKey key) {
- Client client = (Client)key.attachment();
-
- try {
- if (key.isReadable() == false || key.isValid() == false) {
- Log.d("ddms", "Invalid key from " + client + ". Dropping client.");
- dropClient(client, true /* notify */);
- return;
- }
-
- client.read();
-
- /*
- * See if we have a full packet in the buffer. It's possible we have
- * more than one packet, so we have to loop.
- */
- JdwpPacket packet = client.getJdwpPacket();
- while (packet != null) {
- if (packet.isDdmPacket()) {
- // unsolicited DDM request - hand it off
- assert !packet.isReply();
- callHandler(client, packet, null);
- packet.consume();
- } else if (packet.isReply()
- && client.isResponseToUs(packet.getId()) != null) {
- // reply to earlier DDM request
- ChunkHandler handler = client
- .isResponseToUs(packet.getId());
- if (packet.isError())
- client.packetFailed(packet);
- else if (packet.isEmpty())
- Log.d("ddms", "Got empty reply for 0x"
- + Integer.toHexString(packet.getId())
- + " from " + client);
- else
- callHandler(client, packet, handler);
- packet.consume();
- client.removeRequestId(packet.getId());
- } else {
- Log.v("ddms", "Forwarding client "
- + (packet.isReply() ? "reply" : "event") + " 0x"
- + Integer.toHexString(packet.getId()) + " to "
- + client.getDebugger());
- client.forwardPacketToDebugger(packet);
- }
-
- // find next
- packet = client.getJdwpPacket();
- }
- } catch (CancelledKeyException e) {
- // key was canceled probably due to a disconnected client before we could
- // read stuff coming from the client, so we drop it.
- dropClient(client, true /* notify */);
- } catch (IOException ex) {
- // something closed down, no need to print anything. The client is simply dropped.
- dropClient(client, true /* notify */);
- } catch (Exception ex) {
- Log.e("ddms", ex);
-
- /* close the client; automatically un-registers from selector */
- dropClient(client, true /* notify */);
-
- if (ex instanceof BufferOverflowException) {
- Log.w("ddms",
- "Client data packet exceeded maximum buffer size "
- + client);
- } else {
- // don't know what this is, display it
- Log.e("ddms", ex);
- }
- }
- }
-
- /*
- * Process an incoming DDM packet. If this is a reply to an earlier request,
- * "handler" will be set to the handler responsible for the original
- * request. The spec allows a JDWP message to include multiple DDM chunks.
- */
- private void callHandler(Client client, JdwpPacket packet,
- ChunkHandler handler) {
-
- // on first DDM packet received, broadcast a "ready" message
- if (!client.ddmSeen())
- broadcast(CLIENT_READY, client);
-
- ByteBuffer buf = packet.getPayload();
- int type, length;
- boolean reply = true;
-
- type = buf.getInt();
- length = buf.getInt();
-
- if (handler == null) {
- // not a reply, figure out who wants it
- synchronized (mHandlerMap) {
- handler = mHandlerMap.get(type);
- reply = false;
- }
- }
-
- if (handler == null) {
- Log.w("ddms", "Received unsupported chunk type "
- + ChunkHandler.name(type) + " (len=" + length + ")");
- } else {
- Log.d("ddms", "Calling handler for " + ChunkHandler.name(type)
- + " [" + handler + "] (len=" + length + ")");
- ByteBuffer ibuf = buf.slice();
- ByteBuffer roBuf = ibuf.asReadOnlyBuffer(); // enforce R/O
- roBuf.order(ChunkHandler.CHUNK_ORDER);
- // do the handling of the chunk synchronized on the client list
- // to be sure there's no concurrency issue when we look for HOME
- // in hasApp()
- synchronized (mClientList) {
- handler.handleChunk(client, type, roBuf, reply, packet.getId());
- }
- }
- }
-
- /**
- * Drops a client from the monitor.
- * <p/>This will lock the {@link Client} list of the {@link Device} running <var>client</var>.
- * @param client
- * @param notify
- */
- synchronized void dropClient(Client client, boolean notify) {
- if (mInstance == null) {
- return;
- }
-
- synchronized (mClientList) {
- if (mClientList.remove(client) == false) {
- return;
- }
- }
- client.close(notify);
- broadcast(CLIENT_DISCONNECTED, client);
-
- /*
- * http://forum.java.sun.com/thread.jspa?threadID=726715&start=0
- * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5073504
- */
- wakeup();
- }
-
- /**
- * Drops the provided list of clients from the monitor. This will lock the {@link Client}
- * list of the {@link Device} running each of the clients.
- */
- synchronized void dropClients(Collection<? extends Client> clients, boolean notify) {
- for (Client c : clients) {
- dropClient(c, notify);
- }
- }
-
- /*
- * Process activity from one of the debugger sockets. This could be a new
- * connection or a data packet.
- */
- private void processDebuggerActivity(SelectionKey key) {
- Debugger dbg = (Debugger)key.attachment();
-
- try {
- if (key.isAcceptable()) {
- try {
- acceptNewDebugger(dbg, null);
- } catch (IOException ioe) {
- Log.w("ddms", "debugger accept() failed");
- ioe.printStackTrace();
- }
- } else if (key.isReadable()) {
- processDebuggerData(key);
- } else {
- Log.d("ddm-debugger", "key in unknown state");
- }
- } catch (CancelledKeyException cke) {
- // key has been cancelled we can ignore that.
- }
- }
-
- /*
- * Accept a new connection from a debugger. If successful, register it with
- * the Selector.
- */
- private void acceptNewDebugger(Debugger dbg, ServerSocketChannel acceptChan)
- throws IOException {
-
- synchronized (mClientList) {
- SocketChannel chan;
-
- if (acceptChan == null)
- chan = dbg.accept();
- else
- chan = dbg.accept(acceptChan);
-
- if (chan != null) {
- chan.socket().setTcpNoDelay(true);
-
- wakeup();
-
- try {
- chan.register(mSelector, SelectionKey.OP_READ, dbg);
- } catch (IOException ioe) {
- // failed, drop the connection
- dbg.closeData();
- throw ioe;
- } catch (RuntimeException re) {
- // failed, drop the connection
- dbg.closeData();
- throw re;
- }
- } else {
- Log.w("ddms", "ignoring duplicate debugger");
- // new connection already closed
- }
- }
- }
-
- /*
- * We have incoming data from the debugger. Forward it to the client.
- */
- private void processDebuggerData(SelectionKey key) {
- Debugger dbg = (Debugger)key.attachment();
-
- try {
- /*
- * Read pending data.
- */
- dbg.read();
-
- /*
- * See if we have a full packet in the buffer. It's possible we have
- * more than one packet, so we have to loop.
- */
- JdwpPacket packet = dbg.getJdwpPacket();
- while (packet != null) {
- Log.v("ddms", "Forwarding dbg req 0x"
- + Integer.toHexString(packet.getId()) + " to "
- + dbg.getClient());
-
- dbg.forwardPacketToClient(packet);
-
- packet = dbg.getJdwpPacket();
- }
- } catch (IOException ioe) {
- /*
- * Close data connection; automatically un-registers dbg from
- * selector. The failure could be caused by the debugger going away,
- * or by the client going away and failing to accept our data.
- * Either way, the debugger connection does not need to exist any
- * longer. We also need to recycle the connection to the client, so
- * that the VM sees the debugger disconnect. For a DDM-aware client
- * this won't be necessary, and we can just send a "debugger
- * disconnected" message.
- */
- Log.d("ddms", "Closing connection to debugger " + dbg);
- dbg.closeData();
- Client client = dbg.getClient();
- if (client.isDdmAware()) {
- // TODO: soft-disconnect DDM-aware clients
- Log.d("ddms", " (recycling client connection as well)");
-
- // we should drop the client, but also attempt to reopen it.
- // This is done by the DeviceMonitor.
- client.getDeviceImpl().getMonitor().addClientToDropAndReopen(client,
- IDebugPortProvider.NO_STATIC_PORT);
- } else {
- Log.d("ddms", " (recycling client connection as well)");
- // we should drop the client, but also attempt to reopen it.
- // This is done by the DeviceMonitor.
- client.getDeviceImpl().getMonitor().addClientToDropAndReopen(client,
- IDebugPortProvider.NO_STATIC_PORT);
- }
- }
- }
-
- /*
- * Tell the thread that something has changed.
- */
- private void wakeup() {
- mSelector.wakeup();
- }
-
- /**
- * Tell the thread to stop. Called from UI thread.
- */
- synchronized void quit() {
- mQuit = true;
- wakeup();
- Log.d("ddms", "Waiting for Monitor thread");
- try {
- this.join();
- // since we're quitting, lets drop all the client and disconnect
- // the DebugSelectedPort
- synchronized (mClientList) {
- for (Client c : mClientList) {
- c.close(false /* notify */);
- broadcast(CLIENT_DISCONNECTED, c);
- }
- mClientList.clear();
- }
-
- if (mDebugSelectedChan != null) {
- mDebugSelectedChan.close();
- mDebugSelectedChan.socket().close();
- mDebugSelectedChan = null;
- }
- mSelector.close();
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- mInstance = null;
- }
-
- /**
- * Add a new Client to the list of things we monitor. Also adds the client's
- * channel and the client's debugger listener to the selection list. This
- * should only be called from one thread (the VMWatcherThread) to avoid a
- * race between "alreadyOpen" and Client creation.
- */
- synchronized void addClient(Client client) {
- if (mInstance == null) {
- return;
- }
-
- Log.d("ddms", "Adding new client " + client);
-
- synchronized (mClientList) {
- mClientList.add(client);
-
- /*
- * Register the Client's socket channel with the selector. We attach
- * the Client to the SelectionKey. If you try to register a new
- * channel with the Selector while it is waiting for I/O, you will
- * block. The solution is to call wakeup() and then hold a lock to
- * ensure that the registration happens before the Selector goes
- * back to sleep.
- */
- try {
- wakeup();
-
- client.register(mSelector);
-
- Debugger dbg = client.getDebugger();
- if (dbg != null) {
- dbg.registerListener(mSelector);
- }
- } catch (IOException ioe) {
- // not really expecting this to happen
- ioe.printStackTrace();
- }
- }
- }
-
- /*
- * Broadcast an event to all message handlers.
- */
- private void broadcast(int event, Client client) {
- Log.d("ddms", "broadcast " + event + ": " + client);
-
- /*
- * The handler objects appear once in mHandlerMap for each message they
- * handle. We want to notify them once each, so we convert the HashMap
- * to a HashSet before we iterate.
- */
- HashSet<ChunkHandler> set;
- synchronized (mHandlerMap) {
- Collection<ChunkHandler> values = mHandlerMap.values();
- set = new HashSet<ChunkHandler>(values);
- }
-
- Iterator<ChunkHandler> iter = set.iterator();
- while (iter.hasNext()) {
- ChunkHandler handler = iter.next();
- switch (event) {
- case CLIENT_READY:
- try {
- handler.clientReady(client);
- } catch (IOException ioe) {
- // Something failed with the client. It should
- // fall out of the list the next time we try to
- // do something with it, so we discard the
- // exception here and assume cleanup will happen
- // later. May need to propagate farther. The
- // trouble is that not all values for "event" may
- // actually throw an exception.
- Log.w("ddms",
- "Got exception while broadcasting 'ready'");
- return;
- }
- break;
- case CLIENT_DISCONNECTED:
- handler.clientDisconnected(client);
- break;
- default:
- throw new UnsupportedOperationException();
- }
- }
-
- }
-
- /**
- * Opens (or reopens) the "debug selected" port and listen for connections.
- * @return true if the port was opened successfully.
- * @throws IOException
- */
- private boolean reopenDebugSelectedPort() throws IOException {
-
- Log.d("ddms", "reopen debug-selected port: " + mNewDebugSelectedPort);
- if (mDebugSelectedChan != null) {
- mDebugSelectedChan.close();
- }
-
- mDebugSelectedChan = ServerSocketChannel.open();
- mDebugSelectedChan.configureBlocking(false); // required for Selector
-
- InetSocketAddress addr = new InetSocketAddress(
- InetAddress.getByName("localhost"), //$NON-NLS-1$
- mNewDebugSelectedPort);
- mDebugSelectedChan.socket().setReuseAddress(true); // enable SO_REUSEADDR
-
- try {
- mDebugSelectedChan.socket().bind(addr);
- if (mSelectedClient != null) {
- mSelectedClient.update(Client.CHANGE_PORT);
- }
-
- mDebugSelectedChan.register(mSelector, SelectionKey.OP_ACCEPT, this);
-
- return true;
- } catch (java.net.BindException e) {
- displayDebugSelectedBindError(mNewDebugSelectedPort);
-
- // do not attempt to reopen it.
- mDebugSelectedChan = null;
- mNewDebugSelectedPort = -1;
-
- return false;
- }
- }
-
- /*
- * We have some activity on the "debug selected" port. Handle it.
- */
- private void processDebugSelectedActivity(SelectionKey key) {
- assert key.isAcceptable();
-
- ServerSocketChannel acceptChan = (ServerSocketChannel)key.channel();
-
- /*
- * Find the debugger associated with the currently-selected client.
- */
- if (mSelectedClient != null) {
- Debugger dbg = mSelectedClient.getDebugger();
-
- if (dbg != null) {
- Log.d("ddms", "Accepting connection on 'debug selected' port");
- try {
- acceptNewDebugger(dbg, acceptChan);
- } catch (IOException ioe) {
- // client should be gone, keep going
- }
-
- return;
- }
- }
-
- Log.w("ddms",
- "Connection on 'debug selected' port, but none selected");
- try {
- SocketChannel chan = acceptChan.accept();
- chan.close();
- } catch (IOException ioe) {
- // not expected; client should be gone, keep going
- } catch (NotYetBoundException e) {
- displayDebugSelectedBindError(mDebugSelectedPort);
- }
- }
-
- private void displayDebugSelectedBindError(int port) {
- String message = String.format(
- "Could not open Selected VM debug port (%1$d). Make sure you do not have another instance of DDMS or of the eclipse plugin running. If it's being used by something else, choose a new port number in the preferences.",
- port);
-
- Log.logAndDisplay(LogLevel.ERROR, "ddms", message);
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MultiLineReceiver.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MultiLineReceiver.java
deleted file mode 100644
index ac1fa91..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/MultiLineReceiver.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-
-/**
- * Base implementation of {@link IShellOutputReceiver}, that takes the raw data coming from the
- * socket, and convert it into {@link String} objects.
- * <p/>Additionally, it splits the string by lines.
- * <p/>Classes extending it must implement {@link #processNewLines(String[])} which receives
- * new parsed lines as they become available.
- */
-public abstract class MultiLineReceiver implements IShellOutputReceiver {
-
- private boolean mTrimLines = true;
-
- /** unfinished message line, stored for next packet */
- private String mUnfinishedLine = null;
-
- private final ArrayList<String> mArray = new ArrayList<String>();
-
- /**
- * Set the trim lines flag.
- * @param trim hether the lines are trimmed, or not.
- */
- public void setTrimLine(boolean trim) {
- mTrimLines = trim;
- }
-
- /* (non-Javadoc)
- * @see com.android.ddmlib.adb.IShellOutputReceiver#addOutput(
- * byte[], int, int)
- */
- @Override
- public final void addOutput(byte[] data, int offset, int length) {
- if (isCancelled() == false) {
- String s = null;
- try {
- s = new String(data, offset, length, "UTF-8"); //$NON-NLS-1$
- } catch (UnsupportedEncodingException e) {
- // normal encoding didn't work, try the default one
- s = new String(data, offset,length);
- }
-
- // ok we've got a string
- if (s != null) {
- // if we had an unfinished line we add it.
- if (mUnfinishedLine != null) {
- s = mUnfinishedLine + s;
- mUnfinishedLine = null;
- }
-
- // now we split the lines
- mArray.clear();
- int start = 0;
- do {
- int index = s.indexOf("\r\n", start); //$NON-NLS-1$
-
- // if \r\n was not found, this is an unfinished line
- // and we store it to be processed for the next packet
- if (index == -1) {
- mUnfinishedLine = s.substring(start);
- break;
- }
-
- // so we found a \r\n;
- // extract the line
- String line = s.substring(start, index);
- if (mTrimLines) {
- line = line.trim();
- }
- mArray.add(line);
-
- // move start to after the \r\n we found
- start = index + 2;
- } while (true);
-
- if (mArray.size() > 0) {
- // at this point we've split all the lines.
- // make the array
- String[] lines = mArray.toArray(new String[mArray.size()]);
-
- // send it for final processing
- processNewLines(lines);
- }
- }
- }
- }
-
- /* (non-Javadoc)
- * @see com.android.ddmlib.adb.IShellOutputReceiver#flush()
- */
- @Override
- public final void flush() {
- if (mUnfinishedLine != null) {
- processNewLines(new String[] { mUnfinishedLine });
- }
-
- done();
- }
-
- /**
- * Terminates the process. This is called after the last lines have been through
- * {@link #processNewLines(String[])}.
- */
- public void done() {
- // do nothing.
- }
-
- /**
- * Called when new lines are being received by the remote process.
- * <p/>It is guaranteed that the lines are complete when they are given to this method.
- * @param lines The array containing the new lines.
- */
- public abstract void processNewLines(String[] lines);
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeAllocationInfo.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeAllocationInfo.java
deleted file mode 100644
index 9b104ba..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeAllocationInfo.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Stores native allocation information.
- * <p/>Contains number of allocations, their size and the stack trace.
- * <p/>Note: the ddmlib does not resolve the stack trace automatically. While this class provides
- * storage for resolved stack trace, this is merely for convenience.
- */
-public final class NativeAllocationInfo {
- /* Keywords used as delimiters in the string representation of a NativeAllocationInfo */
- public static final String END_STACKTRACE_KW = "EndStacktrace";
- public static final String BEGIN_STACKTRACE_KW = "BeginStacktrace:";
- public static final String TOTAL_SIZE_KW = "TotalSize:";
- public static final String SIZE_KW = "Size:";
- public static final String ALLOCATIONS_KW = "Allocations:";
-
- /* constants for flag bits */
- private static final int FLAG_ZYGOTE_CHILD = (1<<31);
- private static final int FLAG_MASK = (FLAG_ZYGOTE_CHILD);
-
- /** Libraries whose methods will be assumed to be not part of the user code. */
- private static final List<String> FILTERED_LIBRARIES = Arrays.asList(new String[] {
- "libc.so",
- "libc_malloc_debug_leak.so",
- });
-
- /** Method names that should be assumed to be not part of the user code. */
- private static final List<Pattern> FILTERED_METHOD_NAME_PATTERNS = Arrays.asList(new Pattern[] {
- Pattern.compile("malloc", Pattern.CASE_INSENSITIVE),
- Pattern.compile("calloc", Pattern.CASE_INSENSITIVE),
- Pattern.compile("realloc", Pattern.CASE_INSENSITIVE),
- Pattern.compile("operator new", Pattern.CASE_INSENSITIVE),
- Pattern.compile("memalign", Pattern.CASE_INSENSITIVE),
- });
-
- private final int mSize;
-
- private final boolean mIsZygoteChild;
-
- private final int mAllocations;
-
- private final ArrayList<Long> mStackCallAddresses = new ArrayList<Long>();
-
- private ArrayList<NativeStackCallInfo> mResolvedStackCall = null;
-
- private boolean mIsStackCallResolved = false;
-
- /**
- * Constructs a new {@link NativeAllocationInfo}.
- * @param size The size of the allocations.
- * @param allocations the allocation count
- */
- public NativeAllocationInfo(int size, int allocations) {
- this.mSize = size & ~FLAG_MASK;
- this.mIsZygoteChild = ((size & FLAG_ZYGOTE_CHILD) != 0);
- this.mAllocations = allocations;
- }
-
- /**
- * Adds a stack call address for this allocation.
- * @param address The address to add.
- */
- public void addStackCallAddress(long address) {
- mStackCallAddresses.add(address);
- }
-
- /**
- * Returns the total size of this allocation.
- */
- public int getSize() {
- return mSize;
- }
-
- /**
- * Returns whether the allocation happened in a child of the zygote
- * process.
- */
- public boolean isZygoteChild() {
- return mIsZygoteChild;
- }
-
- /**
- * Returns the allocation count.
- */
- public int getAllocationCount() {
- return mAllocations;
- }
-
- /**
- * Returns whether the stack call addresses have been resolved into
- * {@link NativeStackCallInfo} objects.
- */
- public boolean isStackCallResolved() {
- return mIsStackCallResolved;
- }
-
- /**
- * Returns the stack call of this allocation as raw addresses.
- * @return the list of addresses where the allocation happened.
- */
- public List<Long> getStackCallAddresses() {
- return mStackCallAddresses;
- }
-
- /**
- * Sets the resolved stack call for this allocation.
- * <p/>
- * If <code>resolvedStackCall</code> is non <code>null</code> then
- * {@link #isStackCallResolved()} will return <code>true</code> after this call.
- * @param resolvedStackCall The list of {@link NativeStackCallInfo}.
- */
- public synchronized void setResolvedStackCall(List<NativeStackCallInfo> resolvedStackCall) {
- if (mResolvedStackCall == null) {
- mResolvedStackCall = new ArrayList<NativeStackCallInfo>();
- } else {
- mResolvedStackCall.clear();
- }
- mResolvedStackCall.addAll(resolvedStackCall);
- mIsStackCallResolved = mResolvedStackCall.size() != 0;
- }
-
- /**
- * Returns the resolved stack call.
- * @return An array of {@link NativeStackCallInfo} or <code>null</code> if the stack call
- * was not resolved.
- * @see #setResolvedStackCall(List)
- * @see #isStackCallResolved()
- */
- public synchronized List<NativeStackCallInfo> getResolvedStackCall() {
- if (mIsStackCallResolved) {
- return mResolvedStackCall;
- }
-
- return null;
- }
-
- /**
- * Indicates whether some other object is "equal to" this one.
- * @param obj the reference object with which to compare.
- * @return <code>true</code> if this object is equal to the obj argument;
- * <code>false</code> otherwise.
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj) {
- if (obj == this)
- return true;
- if (obj instanceof NativeAllocationInfo) {
- NativeAllocationInfo mi = (NativeAllocationInfo)obj;
- // quick compare of size, alloc, and stackcall size
- if (mSize != mi.mSize || mAllocations != mi.mAllocations ||
- mStackCallAddresses.size() != mi.mStackCallAddresses.size()) {
- return false;
- }
- // compare the stack addresses
- int count = mStackCallAddresses.size();
- for (int i = 0 ; i < count ; i++) {
- long a = mStackCallAddresses.get(i);
- long b = mi.mStackCallAddresses.get(i);
- if (a != b) {
- return false;
- }
- }
-
- return true;
- }
- return false;
- }
-
-
- @Override
- public int hashCode() {
- // Follow Effective Java's recipe re hash codes.
- // Includes all the fields looked at by equals().
-
- int result = 17; // arbitrary starting point
-
- result = 31 * result + mSize;
- result = 31 * result + mAllocations;
- result = 31 * result + mStackCallAddresses.size();
-
- for (long addr : mStackCallAddresses) {
- result = 31 * result + (int) (addr ^ (addr >>> 32));
- }
-
- return result;
- }
-
- /**
- * Returns a string representation of the object.
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.append(ALLOCATIONS_KW);
- buffer.append(' ');
- buffer.append(mAllocations);
- buffer.append('\n');
-
- buffer.append(SIZE_KW);
- buffer.append(' ');
- buffer.append(mSize);
- buffer.append('\n');
-
- buffer.append(TOTAL_SIZE_KW);
- buffer.append(' ');
- buffer.append(mSize * mAllocations);
- buffer.append('\n');
-
- if (mResolvedStackCall != null) {
- buffer.append(BEGIN_STACKTRACE_KW);
- buffer.append('\n');
- for (NativeStackCallInfo source : mResolvedStackCall) {
- long addr = source.getAddress();
- if (addr == 0) {
- continue;
- }
-
- if (source.getLineNumber() != -1) {
- buffer.append(String.format("\t%1$08x\t%2$s --- %3$s --- %4$s:%5$d\n", addr,
- source.getLibraryName(), source.getMethodName(),
- source.getSourceFile(), source.getLineNumber()));
- } else {
- buffer.append(String.format("\t%1$08x\t%2$s --- %3$s --- %4$s\n", addr,
- source.getLibraryName(), source.getMethodName(), source.getSourceFile()));
- }
- }
- buffer.append(END_STACKTRACE_KW);
- buffer.append('\n');
- }
-
- return buffer.toString();
- }
-
- /**
- * Returns the first {@link NativeStackCallInfo} that is relevant.
- * <p/>
- * A relevant <code>NativeStackCallInfo</code> is a stack call that is not deep in the
- * lower level of the libc, but the actual method that performed the allocation.
- * @return a <code>NativeStackCallInfo</code> or <code>null</code> if the stack call has not
- * been processed from the raw addresses.
- * @see #setResolvedStackCall(List)
- * @see #isStackCallResolved()
- */
- public synchronized NativeStackCallInfo getRelevantStackCallInfo() {
- if (mIsStackCallResolved && mResolvedStackCall != null) {
- for (NativeStackCallInfo info : mResolvedStackCall) {
- if (isRelevantLibrary(info.getLibraryName())
- && isRelevantMethod(info.getMethodName())) {
- return info;
- }
- }
-
- // couldnt find a relevant one, so we'll return the first one if it exists.
- if (mResolvedStackCall.size() > 0)
- return mResolvedStackCall.get(0);
- }
-
- return null;
- }
-
- private boolean isRelevantLibrary(String libPath) {
- for (String l : FILTERED_LIBRARIES) {
- if (libPath.endsWith(l)) {
- return false;
- }
- }
-
- return true;
- }
-
- private boolean isRelevantMethod(String methodName) {
- for (Pattern p : FILTERED_METHOD_NAME_PATTERNS) {
- Matcher m = p.matcher(methodName);
- if (m.find()) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeLibraryMapInfo.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeLibraryMapInfo.java
deleted file mode 100644
index 5a26317..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeLibraryMapInfo.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-/**
- * Memory address to library mapping for native libraries.
- * <p/>
- * Each instance represents a single native library and its start and end memory addresses.
- */
-public final class NativeLibraryMapInfo {
- private long mStartAddr;
- private long mEndAddr;
-
- private String mLibrary;
-
- /**
- * Constructs a new native library map info.
- * @param startAddr The start address of the library.
- * @param endAddr The end address of the library.
- * @param library The name of the library.
- */
- NativeLibraryMapInfo(long startAddr, long endAddr, String library) {
- this.mStartAddr = startAddr;
- this.mEndAddr = endAddr;
- this.mLibrary = library;
- }
-
- /**
- * Returns the name of the library.
- */
- public String getLibraryName() {
- return mLibrary;
- }
-
- /**
- * Returns the start address of the library.
- */
- public long getStartAddress() {
- return mStartAddr;
- }
-
- /**
- * Returns the end address of the library.
- */
- public long getEndAddress() {
- return mEndAddr;
- }
-
- /**
- * Returns whether the specified address is inside the library.
- * @param address The address to test.
- * @return <code>true</code> if the address is between the start and end address of the library.
- * @see #getStartAddress()
- * @see #getEndAddress()
- */
- public boolean isWithinLibrary(long address) {
- return address >= mStartAddr && address <= mEndAddr;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeStackCallInfo.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeStackCallInfo.java
deleted file mode 100644
index 1d4af86..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NativeStackCallInfo.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Represents a stack call. This is used to return all of the call
- * information as one object.
- */
-public final class NativeStackCallInfo {
- private final static Pattern SOURCE_NAME_PATTERN = Pattern.compile("^(.+):(\\d+)$");
-
- /** address of this stack frame */
- private long mAddress;
-
- /** name of the library */
- private String mLibrary;
-
- /** name of the method */
- private String mMethod;
-
- /**
- * name of the source file + line number in the format<br>
- * &lt;sourcefile&gt;:&lt;linenumber&gt;
- */
- private String mSourceFile;
-
- private int mLineNumber = -1;
-
- /**
- * Basic constructor with library, method, and sourcefile information
- *
- * @param address address of this stack frame
- * @param lib The name of the library
- * @param method the name of the method
- * @param sourceFile the name of the source file and the line number
- * as "[sourcefile]:[fileNumber]"
- */
- public NativeStackCallInfo(long address, String lib, String method, String sourceFile) {
- mAddress = address;
- mLibrary = lib;
- mMethod = method;
-
- Matcher m = SOURCE_NAME_PATTERN.matcher(sourceFile);
- if (m.matches()) {
- mSourceFile = m.group(1);
- try {
- mLineNumber = Integer.parseInt(m.group(2));
- } catch (NumberFormatException e) {
- // do nothing, the line number will stay at -1
- }
- } else {
- mSourceFile = sourceFile;
- }
- }
-
- /**
- * Returns the address of this stack frame.
- */
- public long getAddress() {
- return mAddress;
- }
-
- /**
- * Returns the name of the library name.
- */
- public String getLibraryName() {
- return mLibrary;
- }
-
- /**
- * Returns the name of the method.
- */
- public String getMethodName() {
- return mMethod;
- }
-
- /**
- * Returns the name of the source file.
- */
- public String getSourceFile() {
- return mSourceFile;
- }
-
- /**
- * Returns the line number, or -1 if unknown.
- */
- public int getLineNumber() {
- return mLineNumber;
- }
-
- @Override
- public String toString() {
- return String.format("\t%1$08x\t%2$s --- %3$s --- %4$s:%5$d",
- getAddress(), getLibraryName(), getMethodName(), getSourceFile(), getLineNumber());
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NullOutputReceiver.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NullOutputReceiver.java
deleted file mode 100644
index a963a64..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/NullOutputReceiver.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-/**
- * Implementation of {@link IShellOutputReceiver} that does nothing.
- * <p/>This can be used to execute a remote shell command when the output is not needed.
- */
-public final class NullOutputReceiver implements IShellOutputReceiver {
-
- private static NullOutputReceiver sReceiver = new NullOutputReceiver();
-
- public static IShellOutputReceiver getReceiver() {
- return sReceiver;
- }
-
- /* (non-Javadoc)
- * @see com.android.ddmlib.adb.IShellOutputReceiver#addOutput(byte[], int, int)
- */
- @Override
- public void addOutput(byte[] data, int offset, int length) {
- }
-
- /* (non-Javadoc)
- * @see com.android.ddmlib.adb.IShellOutputReceiver#flush()
- */
- @Override
- public void flush() {
- }
-
- /* (non-Javadoc)
- * @see com.android.ddmlib.adb.IShellOutputReceiver#isCancelled()
- */
- @Override
- public boolean isCancelled() {
- return false;
- }
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/OpenGlTraceChunkHandler.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/OpenGlTraceChunkHandler.java
deleted file mode 100644
index 12ba142..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/OpenGlTraceChunkHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2012 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.ddmlib;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-public class OpenGlTraceChunkHandler extends ChunkHandler {
- /** GL TRace Control: data in the packet enables or disables tracing. */
- public static final int CHUNK_GLTR = type("GLTR");
-
- private OpenGlTraceChunkHandler() {
- }
-
- @Override
- void clientReady(Client client) throws IOException {
- }
-
- @Override
- void clientDisconnected(Client client) {
- }
-
- @Override
- void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
- handleUnknownChunk(client, type, data, isReply, msgId);
- }
-
- public static void sendStartGlTracing(Client client) throws IOException {
- ByteBuffer buf = allocBuffer(4);
- JdwpPacket packet = new JdwpPacket(buf);
-
- ByteBuffer chunkBuf = getChunkDataBuf(buf);
- chunkBuf.putInt(1);
- finishChunkPacket(packet, CHUNK_GLTR, chunkBuf.position());
-
- client.sendAndConsume(packet);
- }
-
- public static void sendStopGlTracing(Client client) throws IOException {
- ByteBuffer buf = allocBuffer(4);
- JdwpPacket packet = new JdwpPacket(buf);
-
- ByteBuffer chunkBuf = getChunkDataBuf(buf);
- chunkBuf.putInt(0);
- finishChunkPacket(packet, CHUNK_GLTR, chunkBuf.position());
-
- client.sendAndConsume(packet);
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/RawImage.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/RawImage.java
deleted file mode 100644
index adb0cc9..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/RawImage.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import java.nio.ByteBuffer;
-
-/**
- * Data representing an image taken from a device frame buffer.
- */
-public final class RawImage {
- public int version;
- public int bpp;
- public int size;
- public int width;
- public int height;
- public int red_offset;
- public int red_length;
- public int blue_offset;
- public int blue_length;
- public int green_offset;
- public int green_length;
- public int alpha_offset;
- public int alpha_length;
-
- public byte[] data;
-
- /**
- * Reads the header of a RawImage from a {@link ByteBuffer}.
- * <p/>The way the data is sent over adb is defined in system/core/adb/framebuffer_service.c
- * @param version the version of the protocol.
- * @param buf the buffer to read from.
- * @return true if success
- */
- public boolean readHeader(int version, ByteBuffer buf) {
- this.version = version;
-
- if (version == 16) {
- // compatibility mode with original protocol
- this.bpp = 16;
-
- // read actual values.
- this.size = buf.getInt();
- this.width = buf.getInt();
- this.height = buf.getInt();
-
- // create default values for the rest. Format is 565
- this.red_offset = 11;
- this.red_length = 5;
- this.green_offset = 5;
- this.green_length = 6;
- this.blue_offset = 0;
- this.blue_length = 5;
- this.alpha_offset = 0;
- this.alpha_length = 0;
- } else if (version == 1) {
- this.bpp = buf.getInt();
- this.size = buf.getInt();
- this.width = buf.getInt();
- this.height = buf.getInt();
- this.red_offset = buf.getInt();
- this.red_length = buf.getInt();
- this.blue_offset = buf.getInt();
- this.blue_length = buf.getInt();
- this.green_offset = buf.getInt();
- this.green_length = buf.getInt();
- this.alpha_offset = buf.getInt();
- this.alpha_length = buf.getInt();
- } else {
- // unsupported protocol!
- return false;
- }
-
- return true;
- }
-
- /**
- * Returns the mask value for the red color.
- * <p/>This value is compatible with org.eclipse.swt.graphics.PaletteData
- */
- public int getRedMask() {
- return getMask(red_length, red_offset);
- }
-
- /**
- * Returns the mask value for the green color.
- * <p/>This value is compatible with org.eclipse.swt.graphics.PaletteData
- */
- public int getGreenMask() {
- return getMask(green_length, green_offset);
- }
-
- /**
- * Returns the mask value for the blue color.
- * <p/>This value is compatible with org.eclipse.swt.graphics.PaletteData
- */
- public int getBlueMask() {
- return getMask(blue_length, blue_offset);
- }
-
- /**
- * Returns the size of the header for a specific version of the framebuffer adb protocol.
- * @param version the version of the protocol
- * @return the number of int that makes up the header.
- */
- public static int getHeaderSize(int version) {
- switch (version) {
- case 16: // compatibility mode
- return 3; // size, width, height
- case 1:
- return 12; // bpp, size, width, height, 4*(length, offset)
- }
-
- return 0;
- }
-
- /**
- * Returns a rotated version of the image
- * The image is rotated counter-clockwise.
- */
- public RawImage getRotated() {
- RawImage rotated = new RawImage();
- rotated.version = this.version;
- rotated.bpp = this.bpp;
- rotated.size = this.size;
- rotated.red_offset = this.red_offset;
- rotated.red_length = this.red_length;
- rotated.blue_offset = this.blue_offset;
- rotated.blue_length = this.blue_length;
- rotated.green_offset = this.green_offset;
- rotated.green_length = this.green_length;
- rotated.alpha_offset = this.alpha_offset;
- rotated.alpha_length = this.alpha_length;
-
- rotated.width = this.height;
- rotated.height = this.width;
-
- int count = this.data.length;
- rotated.data = new byte[count];
-
- int byteCount = this.bpp >> 3; // bpp is in bits, we want bytes to match our array
- final int w = this.width;
- final int h = this.height;
- for (int y = 0 ; y < h ; y++) {
- for (int x = 0 ; x < w ; x++) {
- System.arraycopy(
- this.data, (y * w + x) * byteCount,
- rotated.data, ((w-x-1) * h + y) * byteCount,
- byteCount);
- }
- }
-
- return rotated;
- }
-
- /**
- * Returns an ARGB integer value for the pixel at <var>index</var> in {@link #data}.
- */
- public int getARGB(int index) {
- int value;
- if (bpp == 16) {
- value = data[index] & 0x00FF;
- value |= (data[index+1] << 8) & 0x0FF00;
- } else if (bpp == 32) {
- value = data[index] & 0x00FF;
- value |= (data[index+1] & 0x00FF) << 8;
- value |= (data[index+2] & 0x00FF) << 16;
- value |= (data[index+3] & 0x00FF) << 24;
- } else {
- throw new UnsupportedOperationException("RawImage.getARGB(int) only works in 16 and 32 bit mode.");
- }
-
- int r = ((value >>> red_offset) & getMask(red_length)) << (8 - red_length);
- int g = ((value >>> green_offset) & getMask(green_length)) << (8 - green_length);
- int b = ((value >>> blue_offset) & getMask(blue_length)) << (8 - blue_length);
- int a;
- if (alpha_length == 0) {
- a = 0xFF; // force alpha to opaque if there's no alpha value in the framebuffer.
- } else {
- a = ((value >>> alpha_offset) & getMask(alpha_length)) << (8 - alpha_length);
- }
-
- return a << 24 | r << 16 | g << 8 | b;
- }
-
- /**
- * creates a mask value based on a length and offset.
- * <p/>This value is compatible with org.eclipse.swt.graphics.PaletteData
- */
- private int getMask(int length, int offset) {
- int res = getMask(length) << offset;
-
- // if the bpp is 32 bits then we need to invert it because the buffer is in little endian
- if (bpp == 32) {
- return Integer.reverseBytes(res);
- }
-
- return res;
- }
-
- /**
- * Creates a mask value based on a length.
- * @param length
- * @return
- */
- private static int getMask(int length) {
- return (1 << length) - 1;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ShellCommandUnresponsiveException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ShellCommandUnresponsiveException.java
deleted file mode 100644
index 09823c4..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ShellCommandUnresponsiveException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib;
-
-
-/**
- * Exception thrown when a shell command executed on a device takes too long to send its output.
- * <p/>The command may not actually be unresponsive, it just has spent too much time not outputting
- * any thing to the console.
- */
-public class ShellCommandUnresponsiveException extends Exception {
- private static final long serialVersionUID = 1L;
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncException.java
deleted file mode 100644
index 76de367..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncException.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib;
-
-import java.io.IOException;
-
-/**
- * Exception thrown when a transfer using {@link SyncService} doesn't complete.
- * <p/>This is different from an {@link IOException} because it's not the underlying connection
- * that triggered the error, but the adb transfer protocol that didn't work somehow, or that the
- * targets (local and/or remote) were wrong.
- */
-public class SyncException extends CanceledException {
- private static final long serialVersionUID = 1L;
-
- public enum SyncError {
- /** canceled transfer */
- CANCELED("Operation was canceled by the user."),
- /** Transfer error */
- TRANSFER_PROTOCOL_ERROR("Adb Transfer Protocol Error."),
- /** unknown remote object during a pull */
- NO_REMOTE_OBJECT("Remote object doesn't exist!"),
- /** Result code when attempting to pull multiple files into a file */
- TARGET_IS_FILE("Target object is a file."),
- /** Result code when attempting to pull multiple into a directory that does not exist. */
- NO_DIR_TARGET("Target directory doesn't exist."),
- /** wrong encoding on the remote path. */
- REMOTE_PATH_ENCODING("Remote Path encoding is not supported."),
- /** remote path that is too long. */
- REMOTE_PATH_LENGTH("Remote path is too long."),
- /** error while reading local file. */
- FILE_READ_ERROR("Reading local file failed!"),
- /** error while writing local file. */
- FILE_WRITE_ERROR("Writing local file failed!"),
- /** attempting to push a directory. */
- LOCAL_IS_DIRECTORY("Local path is a directory."),
- /** attempting to push a non-existent file. */
- NO_LOCAL_FILE("Local path doesn't exist."),
- /** when the target path of a multi file push is a file. */
- REMOTE_IS_FILE("Remote path is a file."),
- /** receiving too much data from the remove device at once */
- BUFFER_OVERRUN("Receiving too much data.");
-
- private final String mMessage;
-
- private SyncError(String message) {
- mMessage = message;
- }
-
- public String getMessage() {
- return mMessage;
- }
- }
-
- private final SyncError mError;
-
- public SyncException(SyncError error) {
- super(error.getMessage());
- mError = error;
- }
-
- public SyncException(SyncError error, String message) {
- super(message);
- mError = error;
- }
-
- public SyncException(SyncError error, Throwable cause) {
- super(error.getMessage(), cause);
- mError = error;
- }
-
- public SyncError getErrorCode() {
- return mError;
- }
-
- /**
- * Returns true if the sync was canceled by user input.
- */
- @Override
- public boolean wasCanceled() {
- return mError == SyncError.CANCELED;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncService.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncService.java
deleted file mode 100644
index f207567..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/SyncService.java
+++ /dev/null
@@ -1,883 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-import com.android.ddmlib.AdbHelper.AdbResponse;
-import com.android.ddmlib.FileListingService.FileEntry;
-import com.android.ddmlib.SyncException.SyncError;
-import com.android.ddmlib.utils.ArrayHelper;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.InetSocketAddress;
-import java.nio.channels.SocketChannel;
-import java.util.ArrayList;
-
-/**
- * Sync service class to push/pull to/from devices/emulators, through the debug bridge.
- * <p/>
- * To get a {@link SyncService} object, use {@link Device#getSyncService()}.
- */
-public final class SyncService {
-
- private final static byte[] ID_OKAY = { 'O', 'K', 'A', 'Y' };
- private final static byte[] ID_FAIL = { 'F', 'A', 'I', 'L' };
- private final static byte[] ID_STAT = { 'S', 'T', 'A', 'T' };
- private final static byte[] ID_RECV = { 'R', 'E', 'C', 'V' };
- private final static byte[] ID_DATA = { 'D', 'A', 'T', 'A' };
- private final static byte[] ID_DONE = { 'D', 'O', 'N', 'E' };
- private final static byte[] ID_SEND = { 'S', 'E', 'N', 'D' };
-// private final static byte[] ID_LIST = { 'L', 'I', 'S', 'T' };
-// private final static byte[] ID_DENT = { 'D', 'E', 'N', 'T' };
-
- private final static NullSyncProgresMonitor sNullSyncProgressMonitor =
- new NullSyncProgresMonitor();
-
- private final static int S_ISOCK = 0xC000; // type: symbolic link
- private final static int S_IFLNK = 0xA000; // type: symbolic link
- private final static int S_IFREG = 0x8000; // type: regular file
- private final static int S_IFBLK = 0x6000; // type: block device
- private final static int S_IFDIR = 0x4000; // type: directory
- private final static int S_IFCHR = 0x2000; // type: character device
- private final static int S_IFIFO = 0x1000; // type: fifo
-/*
- private final static int S_ISUID = 0x0800; // set-uid bit
- private final static int S_ISGID = 0x0400; // set-gid bit
- private final static int S_ISVTX = 0x0200; // sticky bit
- private final static int S_IRWXU = 0x01C0; // user permissions
- private final static int S_IRUSR = 0x0100; // user: read
- private final static int S_IWUSR = 0x0080; // user: write
- private final static int S_IXUSR = 0x0040; // user: execute
- private final static int S_IRWXG = 0x0038; // group permissions
- private final static int S_IRGRP = 0x0020; // group: read
- private final static int S_IWGRP = 0x0010; // group: write
- private final static int S_IXGRP = 0x0008; // group: execute
- private final static int S_IRWXO = 0x0007; // other permissions
- private final static int S_IROTH = 0x0004; // other: read
- private final static int S_IWOTH = 0x0002; // other: write
- private final static int S_IXOTH = 0x0001; // other: execute
-*/
-
- private final static int SYNC_DATA_MAX = 64*1024;
- private final static int REMOTE_PATH_MAX_LENGTH = 1024;
-
- /**
- * Classes which implement this interface provide methods that deal
- * with displaying transfer progress.
- */
- public interface ISyncProgressMonitor {
- /**
- * Sent when the transfer starts
- * @param totalWork the total amount of work.
- */
- public void start(int totalWork);
- /**
- * Sent when the transfer is finished or interrupted.
- */
- public void stop();
- /**
- * Sent to query for possible cancellation.
- * @return true if the transfer should be stopped.
- */
- public boolean isCanceled();
- /**
- * Sent when a sub task is started.
- * @param name the name of the sub task.
- */
- public void startSubTask(String name);
- /**
- * Sent when some progress have been made.
- * @param work the amount of work done.
- */
- public void advance(int work);
- }
-
- /**
- * A Sync progress monitor that does nothing
- */
- private static class NullSyncProgresMonitor implements ISyncProgressMonitor {
- @Override
- public void advance(int work) {
- }
- @Override
- public boolean isCanceled() {
- return false;
- }
-
- @Override
- public void start(int totalWork) {
- }
- @Override
- public void startSubTask(String name) {
- }
- @Override
- public void stop() {
- }
- }
-
- private InetSocketAddress mAddress;
- private Device mDevice;
- private SocketChannel mChannel;
-
- /**
- * Buffer used to send data. Allocated when needed and reused afterward.
- */
- private byte[] mBuffer;
-
- /**
- * Creates a Sync service object.
- * @param address The address to connect to
- * @param device the {@link Device} that the service connects to.
- */
- SyncService(InetSocketAddress address, Device device) {
- mAddress = address;
- mDevice = device;
- }
-
- /**
- * Opens the sync connection. This must be called before any calls to push[File] / pull[File].
- * @return true if the connection opened, false if adb refuse the connection. This can happen
- * if the {@link Device} is invalid.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws IOException If the connection to adb failed.
- */
- boolean openSync() throws TimeoutException, AdbCommandRejectedException, IOException {
- try {
- mChannel = SocketChannel.open(mAddress);
- mChannel.configureBlocking(false);
-
- // target a specific device
- AdbHelper.setDevice(mChannel, mDevice);
-
- byte[] request = AdbHelper.formAdbRequest("sync:"); //$NON-NLS-1$
- AdbHelper.write(mChannel, request, -1, DdmPreferences.getTimeOut());
-
- AdbResponse resp = AdbHelper.readAdbResponse(mChannel, false /* readDiagString */);
-
- if (resp.okay == false) {
- Log.w("ddms", "Got unhappy response from ADB sync req: " + resp.message);
- mChannel.close();
- mChannel = null;
- return false;
- }
- } catch (TimeoutException e) {
- if (mChannel != null) {
- try {
- mChannel.close();
- } catch (IOException e2) {
- // we want to throw the original exception, so we ignore this one.
- }
- mChannel = null;
- }
-
- throw e;
- } catch (IOException e) {
- if (mChannel != null) {
- try {
- mChannel.close();
- } catch (IOException e2) {
- // we want to throw the original exception, so we ignore this one.
- }
- mChannel = null;
- }
-
- throw e;
- }
-
- return true;
- }
-
- /**
- * Closes the connection.
- */
- public void close() {
- if (mChannel != null) {
- try {
- mChannel.close();
- } catch (IOException e) {
- // nothing to be done really...
- }
- mChannel = null;
- }
- }
-
- /**
- * Returns a sync progress monitor that does nothing. This allows background tasks that don't
- * want/need to display ui, to pass a valid {@link ISyncProgressMonitor}.
- * <p/>This object can be reused multiple times and can be used by concurrent threads.
- */
- public static ISyncProgressMonitor getNullProgressMonitor() {
- return sNullSyncProgressMonitor;
- }
-
- /**
- * Pulls file(s) or folder(s).
- * @param entries the remote item(s) to pull
- * @param localPath The local destination. If the entries count is > 1 or
- * if the unique entry is a folder, this should be a folder.
- * @param monitor The progress monitor. Cannot be null.
- * @throws SyncException
- * @throws IOException
- * @throws TimeoutException
- *
- * @see FileListingService.FileEntry
- * @see #getNullProgressMonitor()
- */
- public void pull(FileEntry[] entries, String localPath, ISyncProgressMonitor monitor)
- throws SyncException, IOException, TimeoutException {
-
- // first we check the destination is a directory and exists
- File f = new File(localPath);
- if (f.exists() == false) {
- throw new SyncException(SyncError.NO_DIR_TARGET);
- }
- if (f.isDirectory() == false) {
- throw new SyncException(SyncError.TARGET_IS_FILE);
- }
-
- // get a FileListingService object
- FileListingService fls = new FileListingService(mDevice);
-
- // compute the number of file to move
- int total = getTotalRemoteFileSize(entries, fls);
-
- // start the monitor
- monitor.start(total);
-
- doPull(entries, localPath, fls, monitor);
-
- monitor.stop();
- }
-
- /**
- * Pulls a single file.
- * @param remote the remote file
- * @param localFilename The local destination.
- * @param monitor The progress monitor. Cannot be null.
- *
- * @throws IOException in case of an IO exception.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- * @throws SyncException in case of a sync exception.
- *
- * @see FileListingService.FileEntry
- * @see #getNullProgressMonitor()
- */
- public void pullFile(FileEntry remote, String localFilename, ISyncProgressMonitor monitor)
- throws IOException, SyncException, TimeoutException {
- int total = remote.getSizeValue();
- monitor.start(total);
-
- doPullFile(remote.getFullPath(), localFilename, monitor);
-
- monitor.stop();
- }
-
- /**
- * Pulls a single file.
- * <p/>Because this method just deals with a String for the remote file instead of a
- * {@link FileEntry}, the size of the file being pulled is unknown and the
- * {@link ISyncProgressMonitor} will not properly show the progress
- * @param remoteFilepath the full path to the remote file
- * @param localFilename The local destination.
- * @param monitor The progress monitor. Cannot be null.
- *
- * @throws IOException in case of an IO exception.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- * @throws SyncException in case of a sync exception.
- *
- * @see #getNullProgressMonitor()
- */
- public void pullFile(String remoteFilepath, String localFilename,
- ISyncProgressMonitor monitor) throws TimeoutException, IOException, SyncException {
- Integer mode = readMode(remoteFilepath);
- if (mode == null) {
- // attempts to download anyway
- } else if (mode == 0) {
- throw new SyncException(SyncError.NO_REMOTE_OBJECT);
- }
-
- monitor.start(0);
- //TODO: use the {@link FileListingService} to get the file size.
-
- doPullFile(remoteFilepath, localFilename, monitor);
-
- monitor.stop();
- }
-
- /**
- * Push several files.
- * @param local An array of loca files to push
- * @param remote the remote {@link FileEntry} representing a directory.
- * @param monitor The progress monitor. Cannot be null.
- * @throws SyncException if file could not be pushed
- * @throws IOException in case of I/O error on the connection.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- */
- public void push(String[] local, FileEntry remote, ISyncProgressMonitor monitor)
- throws SyncException, IOException, TimeoutException {
- if (remote.isDirectory() == false) {
- throw new SyncException(SyncError.REMOTE_IS_FILE);
- }
-
- // make a list of File from the list of String
- ArrayList<File> files = new ArrayList<File>();
- for (String path : local) {
- files.add(new File(path));
- }
-
- // get the total count of the bytes to transfer
- File[] fileArray = files.toArray(new File[files.size()]);
- int total = getTotalLocalFileSize(fileArray);
-
- monitor.start(total);
-
- doPush(fileArray, remote.getFullPath(), monitor);
-
- monitor.stop();
- }
-
- /**
- * Push a single file.
- * @param local the local filepath.
- * @param remote The remote filepath.
- * @param monitor The progress monitor. Cannot be null.
- *
- * @throws SyncException if file could not be pushed
- * @throws IOException in case of I/O error on the connection.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- */
- public void pushFile(String local, String remote, ISyncProgressMonitor monitor)
- throws SyncException, IOException, TimeoutException {
- File f = new File(local);
- if (f.exists() == false) {
- throw new SyncException(SyncError.NO_LOCAL_FILE);
- }
-
- if (f.isDirectory()) {
- throw new SyncException(SyncError.LOCAL_IS_DIRECTORY);
- }
-
- monitor.start((int)f.length());
-
- doPushFile(local, remote, monitor);
-
- monitor.stop();
- }
-
- /**
- * compute the recursive file size of all the files in the list. Folder
- * have a weight of 1.
- * @param entries
- * @param fls
- * @return
- */
- private int getTotalRemoteFileSize(FileEntry[] entries, FileListingService fls) {
- int count = 0;
- for (FileEntry e : entries) {
- int type = e.getType();
- if (type == FileListingService.TYPE_DIRECTORY) {
- // get the children
- FileEntry[] children = fls.getChildren(e, false, null);
- count += getTotalRemoteFileSize(children, fls) + 1;
- } else if (type == FileListingService.TYPE_FILE) {
- count += e.getSizeValue();
- }
- }
-
- return count;
- }
-
- /**
- * compute the recursive file size of all the files in the list. Folder
- * have a weight of 1.
- * This does not check for circular links.
- * @param files
- * @return
- */
- private int getTotalLocalFileSize(File[] files) {
- int count = 0;
-
- for (File f : files) {
- if (f.exists()) {
- if (f.isDirectory()) {
- return getTotalLocalFileSize(f.listFiles()) + 1;
- } else if (f.isFile()) {
- count += f.length();
- }
- }
- }
-
- return count;
- }
-
- /**
- * Pulls multiple files/folders recursively.
- * @param entries The list of entry to pull
- * @param localPath the localpath to a directory
- * @param fileListingService a FileListingService object to browse through remote directories.
- * @param monitor the progress monitor. Must be started already.
- *
- * @throws SyncException if file could not be pushed
- * @throws IOException in case of I/O error on the connection.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- */
- private void doPull(FileEntry[] entries, String localPath,
- FileListingService fileListingService,
- ISyncProgressMonitor monitor) throws SyncException, IOException, TimeoutException {
-
- for (FileEntry e : entries) {
- // check if we're cancelled
- if (monitor.isCanceled() == true) {
- throw new SyncException(SyncError.CANCELED);
- }
-
- // get type (we only pull directory and files for now)
- int type = e.getType();
- if (type == FileListingService.TYPE_DIRECTORY) {
- monitor.startSubTask(e.getFullPath());
- String dest = localPath + File.separator + e.getName();
-
- // make the directory
- File d = new File(dest);
- d.mkdir();
-
- // then recursively call the content. Since we did a ls command
- // to get the number of files, we can use the cache
- FileEntry[] children = fileListingService.getChildren(e, true, null);
- doPull(children, dest, fileListingService, monitor);
- monitor.advance(1);
- } else if (type == FileListingService.TYPE_FILE) {
- monitor.startSubTask(e.getFullPath());
- String dest = localPath + File.separator + e.getName();
- doPullFile(e.getFullPath(), dest, monitor);
- }
- }
- }
-
- /**
- * Pulls a remote file
- * @param remotePath the remote file (length max is 1024)
- * @param localPath the local destination
- * @param monitor the monitor. The monitor must be started already.
- * @throws SyncException if file could not be pushed
- * @throws IOException in case of I/O error on the connection.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- */
- private void doPullFile(String remotePath, String localPath,
- ISyncProgressMonitor monitor) throws IOException, SyncException, TimeoutException {
- byte[] msg = null;
- byte[] pullResult = new byte[8];
-
- final int timeOut = DdmPreferences.getTimeOut();
-
- try {
- byte[] remotePathContent = remotePath.getBytes(AdbHelper.DEFAULT_ENCODING);
-
- if (remotePathContent.length > REMOTE_PATH_MAX_LENGTH) {
- throw new SyncException(SyncError.REMOTE_PATH_LENGTH);
- }
-
- // create the full request message
- msg = createFileReq(ID_RECV, remotePathContent);
-
- // and send it.
- AdbHelper.write(mChannel, msg, -1, timeOut);
-
- // read the result, in a byte array containing 2 ints
- // (id, size)
- AdbHelper.read(mChannel, pullResult, -1, timeOut);
-
- // check we have the proper data back
- if (checkResult(pullResult, ID_DATA) == false &&
- checkResult(pullResult, ID_DONE) == false) {
- throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR,
- readErrorMessage(pullResult, timeOut));
- }
- } catch (UnsupportedEncodingException e) {
- throw new SyncException(SyncError.REMOTE_PATH_ENCODING, e);
- }
-
- // access the destination file
- File f = new File(localPath);
-
- // create the stream to write in the file. We use a new try/catch block to differentiate
- // between file and network io exceptions.
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(f);
-
- // the buffer to read the data
- byte[] data = new byte[SYNC_DATA_MAX];
-
- // loop to get data until we're done.
- while (true) {
- // check if we're cancelled
- if (monitor.isCanceled() == true) {
- throw new SyncException(SyncError.CANCELED);
- }
-
- // if we're done, we stop the loop
- if (checkResult(pullResult, ID_DONE)) {
- break;
- }
- if (checkResult(pullResult, ID_DATA) == false) {
- // hmm there's an error
- throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR,
- readErrorMessage(pullResult, timeOut));
- }
- int length = ArrayHelper.swap32bitFromArray(pullResult, 4);
- if (length > SYNC_DATA_MAX) {
- // buffer overrun!
- // error and exit
- throw new SyncException(SyncError.BUFFER_OVERRUN);
- }
-
- // now read the length we received
- AdbHelper.read(mChannel, data, length, timeOut);
-
- // get the header for the next packet.
- AdbHelper.read(mChannel, pullResult, -1, timeOut);
-
- // write the content in the file
- fos.write(data, 0, length);
-
- monitor.advance(length);
- }
-
- fos.flush();
- } catch (IOException e) {
- Log.e("ddms", String.format("Failed to open local file %s for writing, Reason: %s",
- f.getAbsolutePath(), e.toString()));
- throw new SyncException(SyncError.FILE_WRITE_ERROR);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- }
-
-
- /**
- * Push multiple files
- * @param fileArray
- * @param remotePath
- * @param monitor
- *
- * @throws SyncException if file could not be pushed
- * @throws IOException in case of I/O error on the connection.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- */
- private void doPush(File[] fileArray, String remotePath, ISyncProgressMonitor monitor)
- throws SyncException, IOException, TimeoutException {
- for (File f : fileArray) {
- // check if we're canceled
- if (monitor.isCanceled() == true) {
- throw new SyncException(SyncError.CANCELED);
- }
- if (f.exists()) {
- if (f.isDirectory()) {
- // append the name of the directory to the remote path
- String dest = remotePath + "/" + f.getName(); // $NON-NLS-1S
- monitor.startSubTask(dest);
- doPush(f.listFiles(), dest, monitor);
-
- monitor.advance(1);
- } else if (f.isFile()) {
- // append the name of the file to the remote path
- String remoteFile = remotePath + "/" + f.getName(); // $NON-NLS-1S
- monitor.startSubTask(remoteFile);
- doPushFile(f.getAbsolutePath(), remoteFile, monitor);
- }
- }
- }
- }
-
- /**
- * Push a single file
- * @param localPath the local file to push
- * @param remotePath the remote file (length max is 1024)
- * @param monitor the monitor. The monitor must be started already.
- *
- * @throws SyncException if file could not be pushed
- * @throws IOException in case of I/O error on the connection.
- * @throws TimeoutException in case of a timeout reading responses from the device.
- */
- private void doPushFile(String localPath, String remotePath,
- ISyncProgressMonitor monitor) throws SyncException, IOException, TimeoutException {
- FileInputStream fis = null;
- byte[] msg;
-
- final int timeOut = DdmPreferences.getTimeOut();
-
- try {
- byte[] remotePathContent = remotePath.getBytes(AdbHelper.DEFAULT_ENCODING);
-
- if (remotePathContent.length > REMOTE_PATH_MAX_LENGTH) {
- throw new SyncException(SyncError.REMOTE_PATH_LENGTH);
- }
-
- File f = new File(localPath);
-
- // create the stream to read the file
- fis = new FileInputStream(f);
-
- // create the header for the action
- msg = createSendFileReq(ID_SEND, remotePathContent, 0644);
-
- // and send it. We use a custom try/catch block to make the difference between
- // file and network IO exceptions.
- AdbHelper.write(mChannel, msg, -1, timeOut);
-
- // create the buffer used to read.
- // we read max SYNC_DATA_MAX, but we need 2 4 bytes at the beginning.
- if (mBuffer == null) {
- mBuffer = new byte[SYNC_DATA_MAX + 8];
- }
- System.arraycopy(ID_DATA, 0, mBuffer, 0, ID_DATA.length);
-
- // look while there is something to read
- while (true) {
- // check if we're canceled
- if (monitor.isCanceled() == true) {
- throw new SyncException(SyncError.CANCELED);
- }
-
- // read up to SYNC_DATA_MAX
- int readCount = fis.read(mBuffer, 8, SYNC_DATA_MAX);
-
- if (readCount == -1) {
- // we reached the end of the file
- break;
- }
-
- // now send the data to the device
- // first write the amount read
- ArrayHelper.swap32bitsToArray(readCount, mBuffer, 4);
-
- // now write it
- AdbHelper.write(mChannel, mBuffer, readCount+8, timeOut);
-
- // and advance the monitor
- monitor.advance(readCount);
- }
- } catch (UnsupportedEncodingException e) {
- throw new SyncException(SyncError.REMOTE_PATH_ENCODING, e);
- } finally {
- // close the local file
- if (fis != null) {
- fis.close();
- }
- }
-
- // create the DONE message
- long time = System.currentTimeMillis() / 1000;
- msg = createReq(ID_DONE, (int)time);
-
- // and send it.
- AdbHelper.write(mChannel, msg, -1, timeOut);
-
- // read the result, in a byte array containing 2 ints
- // (id, size)
- byte[] result = new byte[8];
- AdbHelper.read(mChannel, result, -1 /* full length */, timeOut);
-
- if (checkResult(result, ID_OKAY) == false) {
- throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR,
- readErrorMessage(result, timeOut));
- }
- }
-
- /**
- * Reads an error message from the opened {@link #mChannel}.
- * @param result the current adb result. Must contain both FAIL and the length of the message.
- * @param timeOut
- * @return
- * @throws TimeoutException in case of a timeout reading responses from the device.
- * @throws IOException
- */
- private String readErrorMessage(byte[] result, final int timeOut) throws TimeoutException,
- IOException {
- if (checkResult(result, ID_FAIL)) {
- int len = ArrayHelper.swap32bitFromArray(result, 4);
-
- if (len > 0) {
- AdbHelper.read(mChannel, mBuffer, len, timeOut);
-
- String message = new String(mBuffer, 0, len);
- Log.e("ddms", "transfer error: " + message);
-
- return message;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the mode of the remote file.
- * @param path the remote file
- * @return an Integer containing the mode if all went well or null
- * otherwise
- * @throws IOException
- * @throws TimeoutException in case of a timeout reading responses from the device.
- */
- private Integer readMode(String path) throws TimeoutException, IOException {
- // create the stat request message.
- byte[] msg = createFileReq(ID_STAT, path);
-
- AdbHelper.write(mChannel, msg, -1 /* full length */, DdmPreferences.getTimeOut());
-
- // read the result, in a byte array containing 4 ints
- // (id, mode, size, time)
- byte[] statResult = new byte[16];
- AdbHelper.read(mChannel, statResult, -1 /* full length */, DdmPreferences.getTimeOut());
-
- // check we have the proper data back
- if (checkResult(statResult, ID_STAT) == false) {
- return null;
- }
-
- // we return the mode (2nd int in the array)
- return ArrayHelper.swap32bitFromArray(statResult, 4);
- }
-
- /**
- * Create a command with a code and an int values
- * @param command
- * @param value
- * @return
- */
- private static byte[] createReq(byte[] command, int value) {
- byte[] array = new byte[8];
-
- System.arraycopy(command, 0, array, 0, 4);
- ArrayHelper.swap32bitsToArray(value, array, 4);
-
- return array;
- }
-
- /**
- * Creates the data array for a stat request.
- * @param command the 4 byte command (ID_STAT, ID_RECV, ...)
- * @param path The path of the remote file on which to execute the command
- * @return the byte[] to send to the device through adb
- */
- private static byte[] createFileReq(byte[] command, String path) {
- byte[] pathContent = null;
- try {
- pathContent = path.getBytes(AdbHelper.DEFAULT_ENCODING);
- } catch (UnsupportedEncodingException e) {
- return null;
- }
-
- return createFileReq(command, pathContent);
- }
-
- /**
- * Creates the data array for a file request. This creates an array with a 4 byte command + the
- * remote file name.
- * @param command the 4 byte command (ID_STAT, ID_RECV, ...).
- * @param path The path, as a byte array, of the remote file on which to
- * execute the command.
- * @return the byte[] to send to the device through adb
- */
- private static byte[] createFileReq(byte[] command, byte[] path) {
- byte[] array = new byte[8 + path.length];
-
- System.arraycopy(command, 0, array, 0, 4);
- ArrayHelper.swap32bitsToArray(path.length, array, 4);
- System.arraycopy(path, 0, array, 8, path.length);
-
- return array;
- }
-
- private static byte[] createSendFileReq(byte[] command, byte[] path, int mode) {
- // make the mode into a string
- String modeStr = "," + (mode & 0777); // $NON-NLS-1S
- byte[] modeContent = null;
- try {
- modeContent = modeStr.getBytes(AdbHelper.DEFAULT_ENCODING);
- } catch (UnsupportedEncodingException e) {
- return null;
- }
-
- byte[] array = new byte[8 + path.length + modeContent.length];
-
- System.arraycopy(command, 0, array, 0, 4);
- ArrayHelper.swap32bitsToArray(path.length + modeContent.length, array, 4);
- System.arraycopy(path, 0, array, 8, path.length);
- System.arraycopy(modeContent, 0, array, 8 + path.length, modeContent.length);
-
- return array;
-
-
- }
-
- /**
- * Checks the result array starts with the provided code
- * @param result The result array to check
- * @param code The 4 byte code.
- * @return true if the code matches.
- */
- private static boolean checkResult(byte[] result, byte[] code) {
- if (result[0] != code[0] ||
- result[1] != code[1] ||
- result[2] != code[2] ||
- result[3] != code[3]) {
- return false;
- }
-
- return true;
-
- }
-
- private static int getFileType(int mode) {
- if ((mode & S_ISOCK) == S_ISOCK) {
- return FileListingService.TYPE_SOCKET;
- }
-
- if ((mode & S_IFLNK) == S_IFLNK) {
- return FileListingService.TYPE_LINK;
- }
-
- if ((mode & S_IFREG) == S_IFREG) {
- return FileListingService.TYPE_FILE;
- }
-
- if ((mode & S_IFBLK) == S_IFBLK) {
- return FileListingService.TYPE_BLOCK;
- }
-
- if ((mode & S_IFDIR) == S_IFDIR) {
- return FileListingService.TYPE_DIRECTORY;
- }
-
- if ((mode & S_IFCHR) == S_IFCHR) {
- return FileListingService.TYPE_CHARACTER;
- }
-
- if ((mode & S_IFIFO) == S_IFIFO) {
- return FileListingService.TYPE_FIFO;
- }
-
- return FileListingService.TYPE_OTHER;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ThreadInfo.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ThreadInfo.java
deleted file mode 100644
index 93db931..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/ThreadInfo.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib;
-
-/**
- * Holds a thread information.
- */
-public final class ThreadInfo implements IStackTraceInfo {
- private int mThreadId;
- private String mThreadName;
- private int mStatus;
- private int mTid;
- private int mUtime;
- private int mStime;
- private boolean mIsDaemon;
- private StackTraceElement[] mTrace;
- private long mTraceTime;
-
- // priority?
- // total CPU used?
- // method at top of stack?
-
- /**
- * Construct with basic identification.
- */
- ThreadInfo(int threadId, String threadName) {
- mThreadId = threadId;
- mThreadName = threadName;
-
- mStatus = -1;
- //mTid = mUtime = mStime = 0;
- //mIsDaemon = false;
- }
-
- /**
- * Set with the values we get from a THST chunk.
- */
- void updateThread(int status, int tid, int utime, int stime, boolean isDaemon) {
-
- mStatus = status;
- mTid = tid;
- mUtime = utime;
- mStime = stime;
- mIsDaemon = isDaemon;
- }
-
- /**
- * Sets the stack call of the thread.
- * @param trace stackcall information.
- */
- void setStackCall(StackTraceElement[] trace) {
- mTrace = trace;
- mTraceTime = System.currentTimeMillis();
- }
-
- /**
- * Returns the thread's ID.
- */
- public int getThreadId() {
- return mThreadId;
- }
-
- /**
- * Returns the thread's name.
- */
- public String getThreadName() {
- return mThreadName;
- }
-
- void setThreadName(String name) {
- mThreadName = name;
- }
-
- /**
- * Returns the system tid.
- */
- public int getTid() {
- return mTid;
- }
-
- /**
- * Returns the VM thread status.
- */
- public int getStatus() {
- return mStatus;
- }
-
- /**
- * Returns the cumulative user time.
- */
- public int getUtime() {
- return mUtime;
- }
-
- /**
- * Returns the cumulative system time.
- */
- public int getStime() {
- return mStime;
- }
-
- /**
- * Returns whether this is a daemon thread.
- */
- public boolean isDaemon() {
- return mIsDaemon;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IStackTraceInfo#getStackTrace()
- */
- @Override
- public StackTraceElement[] getStackTrace() {
- return mTrace;
- }
-
- /**
- * Returns the approximate time of the stacktrace data.
- * @see #getStackTrace()
- */
- public long getStackCallTime() {
- return mTraceTime;
- }
-}
-
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/TimeoutException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/TimeoutException.java
deleted file mode 100644
index 78f5db7..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/TimeoutException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib;
-
-
-/**
- * Exception thrown when a connection to Adb failed with a timeout.
- *
- */
-public class TimeoutException extends Exception {
- private static final long serialVersionUID = 1L;
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventContainer.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventContainer.java
deleted file mode 100644
index 0afdf5d..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventContainer.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * 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.ddmlib.log;
-
-import com.android.ddmlib.log.LogReceiver.LogEntry;
-
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Represents an event and its data.
- */
-public class EventContainer {
-
- /**
- * Comparison method for {@link EventContainer#testValue(int, Object, com.android.ddmlib.log.EventContainer.CompareMethod)}
- *
- */
- public enum CompareMethod {
- EQUAL_TO("equals", "=="),
- LESSER_THAN("less than or equals to", "<="),
- LESSER_THAN_STRICT("less than", "<"),
- GREATER_THAN("greater than or equals to", ">="),
- GREATER_THAN_STRICT("greater than", ">"),
- BIT_CHECK("bit check", "&");
-
- private final String mName;
- private final String mTestString;
-
- private CompareMethod(String name, String testString) {
- mName = name;
- mTestString = testString;
- }
-
- /**
- * Returns the display string.
- */
- @Override
- public String toString() {
- return mName;
- }
-
- /**
- * Returns a short string representing the comparison.
- */
- public String testString() {
- return mTestString;
- }
- }
-
-
- /**
- * Type for event data.
- */
- public static enum EventValueType {
- UNKNOWN(0),
- INT(1),
- LONG(2),
- STRING(3),
- LIST(4),
- TREE(5);
-
- private final static Pattern STORAGE_PATTERN = Pattern.compile("^(\\d+)@(.*)$"); //$NON-NLS-1$
-
- private int mValue;
-
- /**
- * Returns a {@link EventValueType} from an integer value, or <code>null</code> if no match
- * was found.
- * @param value the integer value.
- */
- static EventValueType getEventValueType(int value) {
- for (EventValueType type : values()) {
- if (type.mValue == value) {
- return type;
- }
- }
-
- return null;
- }
-
- /**
- * Returns a storage string for an {@link Object} of type supported by
- * {@link EventValueType}.
- * <p/>
- * Strings created by this method can be reloaded with
- * {@link #getObjectFromStorageString(String)}.
- * <p/>
- * NOTE: for now, only {@link #STRING}, {@link #INT}, and {@link #LONG} are supported.
- * @param object the object to "convert" into a storage string.
- * @return a string storing the object and its type or null if the type was not recognized.
- */
- public static String getStorageString(Object object) {
- if (object instanceof String) {
- return STRING.mValue + "@" + (String)object; //$NON-NLS-1$
- } else if (object instanceof Integer) {
- return INT.mValue + "@" + object.toString(); //$NON-NLS-1$
- } else if (object instanceof Long) {
- return LONG.mValue + "@" + object.toString(); //$NON-NLS-1$
- }
-
- return null;
- }
-
- /**
- * Creates an {@link Object} from a storage string created with
- * {@link #getStorageString(Object)}.
- * @param value the storage string
- * @return an {@link Object} or null if the string or type were not recognized.
- */
- public static Object getObjectFromStorageString(String value) {
- Matcher m = STORAGE_PATTERN.matcher(value);
- if (m.matches()) {
- try {
- EventValueType type = getEventValueType(Integer.parseInt(m.group(1)));
-
- if (type == null) {
- return null;
- }
-
- switch (type) {
- case STRING:
- return m.group(2);
- case INT:
- return Integer.valueOf(m.group(2));
- case LONG:
- return Long.valueOf(m.group(2));
- }
- } catch (NumberFormatException nfe) {
- return null;
- }
- }
-
- return null;
- }
-
-
- /**
- * Returns the integer value of the enum.
- */
- public int getValue() {
- return mValue;
- }
-
- @Override
- public String toString() {
- return super.toString().toLowerCase(Locale.US);
- }
-
- private EventValueType(int value) {
- mValue = value;
- }
- }
-
- public int mTag;
- public int pid; /* generating process's pid */
- public int tid; /* generating process's tid */
- public int sec; /* seconds since Epoch */
- public int nsec; /* nanoseconds */
-
- private Object mData;
-
- /**
- * Creates an {@link EventContainer} from a {@link LogEntry}.
- * @param entry the LogEntry from which pid, tid, and time info is copied.
- * @param tag the event tag value
- * @param data the data of the EventContainer.
- */
- EventContainer(LogEntry entry, int tag, Object data) {
- getType(data);
- mTag = tag;
- mData = data;
-
- pid = entry.pid;
- tid = entry.tid;
- sec = entry.sec;
- nsec = entry.nsec;
- }
-
- /**
- * Creates an {@link EventContainer} with raw data
- */
- EventContainer(int tag, int pid, int tid, int sec, int nsec, Object data) {
- getType(data);
- mTag = tag;
- mData = data;
-
- this.pid = pid;
- this.tid = tid;
- this.sec = sec;
- this.nsec = nsec;
- }
-
- /**
- * Returns the data as an int.
- * @throws InvalidTypeException if the data type is not {@link EventValueType#INT}.
- * @see #getType()
- */
- public final Integer getInt() throws InvalidTypeException {
- if (getType(mData) == EventValueType.INT) {
- return (Integer)mData;
- }
-
- throw new InvalidTypeException();
- }
-
- /**
- * Returns the data as a long.
- * @throws InvalidTypeException if the data type is not {@link EventValueType#LONG}.
- * @see #getType()
- */
- public final Long getLong() throws InvalidTypeException {
- if (getType(mData) == EventValueType.LONG) {
- return (Long)mData;
- }
-
- throw new InvalidTypeException();
- }
-
- /**
- * Returns the data as a String.
- * @throws InvalidTypeException if the data type is not {@link EventValueType#STRING}.
- * @see #getType()
- */
- public final String getString() throws InvalidTypeException {
- if (getType(mData) == EventValueType.STRING) {
- return (String)mData;
- }
-
- throw new InvalidTypeException();
- }
-
- /**
- * Returns a value by index. The return type is defined by its type.
- * @param valueIndex the index of the value. If the data is not a list, this is ignored.
- */
- public Object getValue(int valueIndex) {
- return getValue(mData, valueIndex, true);
- }
-
- /**
- * Returns a value by index as a double.
- * @param valueIndex the index of the value. If the data is not a list, this is ignored.
- * @throws InvalidTypeException if the data type is not {@link EventValueType#INT},
- * {@link EventValueType#LONG}, {@link EventValueType#LIST}, or if the item in the
- * list at index <code>valueIndex</code> is not of type {@link EventValueType#INT} or
- * {@link EventValueType#LONG}.
- * @see #getType()
- */
- public double getValueAsDouble(int valueIndex) throws InvalidTypeException {
- return getValueAsDouble(mData, valueIndex, true);
- }
-
- /**
- * Returns a value by index as a String.
- * @param valueIndex the index of the value. If the data is not a list, this is ignored.
- * @throws InvalidTypeException if the data type is not {@link EventValueType#INT},
- * {@link EventValueType#LONG}, {@link EventValueType#STRING}, {@link EventValueType#LIST},
- * or if the item in the list at index <code>valueIndex</code> is not of type
- * {@link EventValueType#INT}, {@link EventValueType#LONG}, or {@link EventValueType#STRING}
- * @see #getType()
- */
- public String getValueAsString(int valueIndex) throws InvalidTypeException {
- return getValueAsString(mData, valueIndex, true);
- }
-
- /**
- * Returns the type of the data.
- */
- public EventValueType getType() {
- return getType(mData);
- }
-
- /**
- * Returns the type of an object.
- */
- public final EventValueType getType(Object data) {
- if (data instanceof Integer) {
- return EventValueType.INT;
- } else if (data instanceof Long) {
- return EventValueType.LONG;
- } else if (data instanceof String) {
- return EventValueType.STRING;
- } else if (data instanceof Object[]) {
- // loop through the list to see if we have another list
- Object[] objects = (Object[])data;
- for (Object obj : objects) {
- EventValueType type = getType(obj);
- if (type == EventValueType.LIST || type == EventValueType.TREE) {
- return EventValueType.TREE;
- }
- }
- return EventValueType.LIST;
- }
-
- return EventValueType.UNKNOWN;
- }
-
- /**
- * Checks that the <code>index</code>-th value of this event against a provided value.
- * @param index the index of the value to test
- * @param value the value to test against
- * @param compareMethod the method of testing
- * @return true if the test passed.
- * @throws InvalidTypeException in case of type mismatch between the value to test and the value
- * to test against, or if the compare method is incompatible with the type of the values.
- * @see CompareMethod
- */
- public boolean testValue(int index, Object value,
- CompareMethod compareMethod) throws InvalidTypeException {
- EventValueType type = getType(mData);
- if (index > 0 && type != EventValueType.LIST) {
- throw new InvalidTypeException();
- }
-
- Object data = mData;
- if (type == EventValueType.LIST) {
- data = ((Object[])mData)[index];
- }
-
- if (data.getClass().equals(data.getClass()) == false) {
- throw new InvalidTypeException();
- }
-
- switch (compareMethod) {
- case EQUAL_TO:
- return data.equals(value);
- case LESSER_THAN:
- if (data instanceof Integer) {
- return (((Integer)data).compareTo((Integer)value) <= 0);
- } else if (data instanceof Long) {
- return (((Long)data).compareTo((Long)value) <= 0);
- }
-
- // other types can't use this compare method.
- throw new InvalidTypeException();
- case LESSER_THAN_STRICT:
- if (data instanceof Integer) {
- return (((Integer)data).compareTo((Integer)value) < 0);
- } else if (data instanceof Long) {
- return (((Long)data).compareTo((Long)value) < 0);
- }
-
- // other types can't use this compare method.
- throw new InvalidTypeException();
- case GREATER_THAN:
- if (data instanceof Integer) {
- return (((Integer)data).compareTo((Integer)value) >= 0);
- } else if (data instanceof Long) {
- return (((Long)data).compareTo((Long)value) >= 0);
- }
-
- // other types can't use this compare method.
- throw new InvalidTypeException();
- case GREATER_THAN_STRICT:
- if (data instanceof Integer) {
- return (((Integer)data).compareTo((Integer)value) > 0);
- } else if (data instanceof Long) {
- return (((Long)data).compareTo((Long)value) > 0);
- }
-
- // other types can't use this compare method.
- throw new InvalidTypeException();
- case BIT_CHECK:
- if (data instanceof Integer) {
- return (((Integer)data).intValue() & ((Integer)value).intValue()) != 0;
- } else if (data instanceof Long) {
- return (((Long)data).longValue() & ((Long)value).longValue()) != 0;
- }
-
- // other types can't use this compare method.
- throw new InvalidTypeException();
- default :
- throw new InvalidTypeException();
- }
- }
-
- private final Object getValue(Object data, int valueIndex, boolean recursive) {
- EventValueType type = getType(data);
-
- switch (type) {
- case INT:
- case LONG:
- case STRING:
- return data;
- case LIST:
- if (recursive) {
- Object[] list = (Object[]) data;
- if (valueIndex >= 0 && valueIndex < list.length) {
- return getValue(list[valueIndex], valueIndex, false);
- }
- }
- }
-
- return null;
- }
-
- private final double getValueAsDouble(Object data, int valueIndex, boolean recursive)
- throws InvalidTypeException {
- EventValueType type = getType(data);
-
- switch (type) {
- case INT:
- return ((Integer)data).doubleValue();
- case LONG:
- return ((Long)data).doubleValue();
- case STRING:
- throw new InvalidTypeException();
- case LIST:
- if (recursive) {
- Object[] list = (Object[]) data;
- if (valueIndex >= 0 && valueIndex < list.length) {
- return getValueAsDouble(list[valueIndex], valueIndex, false);
- }
- }
- }
-
- throw new InvalidTypeException();
- }
-
- private final String getValueAsString(Object data, int valueIndex, boolean recursive)
- throws InvalidTypeException {
- EventValueType type = getType(data);
-
- switch (type) {
- case INT:
- return ((Integer)data).toString();
- case LONG:
- return ((Long)data).toString();
- case STRING:
- return (String)data;
- case LIST:
- if (recursive) {
- Object[] list = (Object[]) data;
- if (valueIndex >= 0 && valueIndex < list.length) {
- return getValueAsString(list[valueIndex], valueIndex, false);
- }
- } else {
- throw new InvalidTypeException(
- "getValueAsString() doesn't support EventValueType.TREE");
- }
- }
-
- throw new InvalidTypeException(
- "getValueAsString() unsupported type:" + type);
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventLogParser.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventLogParser.java
deleted file mode 100644
index b2d8256..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventLogParser.java
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * 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.ddmlib.log;
-
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.MultiLineReceiver;
-import com.android.ddmlib.log.EventContainer.EventValueType;
-import com.android.ddmlib.log.EventValueDescription.ValueType;
-import com.android.ddmlib.log.LogReceiver.LogEntry;
-import com.android.ddmlib.utils.ArrayHelper;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Parser for the "event" log.
- */
-public final class EventLogParser {
-
- /** Location of the tag map file on the device */
- private final static String EVENT_TAG_MAP_FILE = "/system/etc/event-log-tags"; //$NON-NLS-1$
-
- /**
- * Event log entry types. These must match up with the declarations in
- * java/android/android/util/EventLog.java.
- */
- private final static int EVENT_TYPE_INT = 0;
- private final static int EVENT_TYPE_LONG = 1;
- private final static int EVENT_TYPE_STRING = 2;
- private final static int EVENT_TYPE_LIST = 3;
-
- private final static Pattern PATTERN_SIMPLE_TAG = Pattern.compile(
- "^(\\d+)\\s+([A-Za-z0-9_]+)\\s*$"); //$NON-NLS-1$
- private final static Pattern PATTERN_TAG_WITH_DESC = Pattern.compile(
- "^(\\d+)\\s+([A-Za-z0-9_]+)\\s*(.*)\\s*$"); //$NON-NLS-1$
- private final static Pattern PATTERN_DESCRIPTION = Pattern.compile(
- "\\(([A-Za-z0-9_\\s]+)\\|(\\d+)(\\|\\d+){0,1}\\)"); //$NON-NLS-1$
-
- private final static Pattern TEXT_LOG_LINE = Pattern.compile(
- "(\\d\\d)-(\\d\\d)\\s(\\d\\d):(\\d\\d):(\\d\\d).(\\d{3})\\s+I/([a-zA-Z0-9_]+)\\s*\\(\\s*(\\d+)\\):\\s+(.*)"); //$NON-NLS-1$
-
- private final TreeMap<Integer, String> mTagMap = new TreeMap<Integer, String>();
-
- private final TreeMap<Integer, EventValueDescription[]> mValueDescriptionMap =
- new TreeMap<Integer, EventValueDescription[]>();
-
- public EventLogParser() {
- }
-
- /**
- * Inits the parser for a specific Device.
- * <p/>
- * This methods reads the event-log-tags located on the device to find out
- * what tags are being written to the event log and what their format is.
- * @param device The device.
- * @return <code>true</code> if success, <code>false</code> if failure or cancellation.
- */
- public boolean init(IDevice device) {
- // read the event tag map file on the device.
- try {
- device.executeShellCommand("cat " + EVENT_TAG_MAP_FILE, //$NON-NLS-1$
- new MultiLineReceiver() {
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- processTagLine(line);
- }
- }
- @Override
- public boolean isCancelled() {
- return false;
- }
- });
- } catch (Exception e) {
- // catch all possible exceptions and return false.
- return false;
- }
-
- return true;
- }
-
- /**
- * Inits the parser with the content of a tag file.
- * @param tagFileContent the lines of a tag file.
- * @return <code>true</code> if success, <code>false</code> if failure.
- */
- public boolean init(String[] tagFileContent) {
- for (String line : tagFileContent) {
- processTagLine(line);
- }
- return true;
- }
-
- /**
- * Inits the parser with a specified event-log-tags file.
- * @param filePath
- * @return <code>true</code> if success, <code>false</code> if failure.
- */
- public boolean init(String filePath) {
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new FileReader(filePath));
-
- String line = null;
- do {
- line = reader.readLine();
- if (line != null) {
- processTagLine(line);
- }
- } while (line != null);
-
- return true;
- } catch (IOException e) {
- return false;
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- // ignore
- }
- }
- }
-
- /**
- * Processes a line from the event-log-tags file.
- * @param line the line to process
- */
- private void processTagLine(String line) {
- // ignore empty lines and comment lines
- if (line.length() > 0 && line.charAt(0) != '#') {
- Matcher m = PATTERN_TAG_WITH_DESC.matcher(line);
- if (m.matches()) {
- try {
- int value = Integer.parseInt(m.group(1));
- String name = m.group(2);
- if (name != null && mTagMap.get(value) == null) {
- mTagMap.put(value, name);
- }
-
- // special case for the GC tag. We ignore what is in the file,
- // and take what the custom GcEventContainer class tells us.
- // This is due to the event encoding several values on 2 longs.
- // @see GcEventContainer
- if (value == GcEventContainer.GC_EVENT_TAG) {
- mValueDescriptionMap.put(value,
- GcEventContainer.getValueDescriptions());
- } else {
-
- String description = m.group(3);
- if (description != null && description.length() > 0) {
- EventValueDescription[] desc =
- processDescription(description);
-
- if (desc != null) {
- mValueDescriptionMap.put(value, desc);
- }
- }
- }
- } catch (NumberFormatException e) {
- // failed to convert the number into a string. just ignore it.
- }
- } else {
- m = PATTERN_SIMPLE_TAG.matcher(line);
- if (m.matches()) {
- int value = Integer.parseInt(m.group(1));
- String name = m.group(2);
- if (name != null && mTagMap.get(value) == null) {
- mTagMap.put(value, name);
- }
- }
- }
- }
- }
-
- private EventValueDescription[] processDescription(String description) {
- String[] descriptions = description.split("\\s*,\\s*"); //$NON-NLS-1$
-
- ArrayList<EventValueDescription> list = new ArrayList<EventValueDescription>();
-
- for (String desc : descriptions) {
- Matcher m = PATTERN_DESCRIPTION.matcher(desc);
- if (m.matches()) {
- try {
- String name = m.group(1);
-
- String typeString = m.group(2);
- int typeValue = Integer.parseInt(typeString);
- EventValueType eventValueType = EventValueType.getEventValueType(typeValue);
- if (eventValueType == null) {
- // just ignore this description if the value is not recognized.
- // TODO: log the error.
- }
-
- typeString = m.group(3);
- if (typeString != null && typeString.length() > 0) {
- //skip the |
- typeString = typeString.substring(1);
-
- typeValue = Integer.parseInt(typeString);
- ValueType valueType = ValueType.getValueType(typeValue);
-
- list.add(new EventValueDescription(name, eventValueType, valueType));
- } else {
- list.add(new EventValueDescription(name, eventValueType));
- }
- } catch (NumberFormatException nfe) {
- // just ignore this description if one number is malformed.
- // TODO: log the error.
- } catch (InvalidValueTypeException e) {
- // just ignore this description if data type and data unit don't match
- // TODO: log the error.
- }
- } else {
- Log.e("EventLogParser", //$NON-NLS-1$
- String.format("Can't parse %1$s", description)); //$NON-NLS-1$
- }
- }
-
- if (list.size() == 0) {
- return null;
- }
-
- return list.toArray(new EventValueDescription[list.size()]);
-
- }
-
- public EventContainer parse(LogEntry entry) {
- if (entry.len < 4) {
- return null;
- }
-
- int inOffset = 0;
-
- int tagValue = ArrayHelper.swap32bitFromArray(entry.data, inOffset);
- inOffset += 4;
-
- String tag = mTagMap.get(tagValue);
- if (tag == null) {
- Log.e("EventLogParser", String.format("unknown tag number: %1$d", tagValue));
- }
-
- ArrayList<Object> list = new ArrayList<Object>();
- if (parseBinaryEvent(entry.data, inOffset, list) == -1) {
- return null;
- }
-
- Object data;
- if (list.size() == 1) {
- data = list.get(0);
- } else{
- data = list.toArray();
- }
-
- EventContainer event = null;
- if (tagValue == GcEventContainer.GC_EVENT_TAG) {
- event = new GcEventContainer(entry, tagValue, data);
- } else {
- event = new EventContainer(entry, tagValue, data);
- }
-
- return event;
- }
-
- public EventContainer parse(String textLogLine) {
- // line will look like
- // 04-29 23:16:16.691 I/dvm_gc_info( 427): <data>
- // where <data> is either
- // [value1,value2...]
- // or
- // value
- if (textLogLine.length() == 0) {
- return null;
- }
-
- // parse the header first
- Matcher m = TEXT_LOG_LINE.matcher(textLogLine);
- if (m.matches()) {
- try {
- int month = Integer.parseInt(m.group(1));
- int day = Integer.parseInt(m.group(2));
- int hours = Integer.parseInt(m.group(3));
- int minutes = Integer.parseInt(m.group(4));
- int seconds = Integer.parseInt(m.group(5));
- int milliseconds = Integer.parseInt(m.group(6));
-
- // convert into seconds since epoch and nano-seconds.
- Calendar cal = Calendar.getInstance();
- cal.set(cal.get(Calendar.YEAR), month-1, day, hours, minutes, seconds);
- int sec = (int)Math.floor(cal.getTimeInMillis()/1000);
- int nsec = milliseconds * 1000000;
-
- String tag = m.group(7);
-
- // get the numerical tag value
- int tagValue = -1;
- Set<Entry<Integer, String>> tagSet = mTagMap.entrySet();
- for (Entry<Integer, String> entry : tagSet) {
- if (tag.equals(entry.getValue())) {
- tagValue = entry.getKey();
- break;
- }
- }
-
- if (tagValue == -1) {
- return null;
- }
-
- int pid = Integer.parseInt(m.group(8));
-
- Object data = parseTextData(m.group(9), tagValue);
- if (data == null) {
- return null;
- }
-
- // now we can allocate and return the EventContainer
- EventContainer event = null;
- if (tagValue == GcEventContainer.GC_EVENT_TAG) {
- event = new GcEventContainer(tagValue, pid, -1 /* tid */, sec, nsec, data);
- } else {
- event = new EventContainer(tagValue, pid, -1 /* tid */, sec, nsec, data);
- }
-
- return event;
- } catch (NumberFormatException e) {
- return null;
- }
- }
-
- return null;
- }
-
- public Map<Integer, String> getTagMap() {
- return mTagMap;
- }
-
- public Map<Integer, EventValueDescription[]> getEventInfoMap() {
- return mValueDescriptionMap;
- }
-
- /**
- * Recursively convert binary log data to printable form.
- *
- * This needs to be recursive because you can have lists of lists.
- *
- * If we run out of room, we stop processing immediately. It's important
- * for us to check for space on every output element to avoid producing
- * garbled output.
- *
- * Returns the amount read on success, -1 on failure.
- */
- private static int parseBinaryEvent(byte[] eventData, int dataOffset, ArrayList<Object> list) {
-
- if (eventData.length - dataOffset < 1)
- return -1;
-
- int offset = dataOffset;
-
- int type = eventData[offset++];
-
- //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
-
- switch (type) {
- case EVENT_TYPE_INT: { /* 32-bit signed int */
- int ival;
-
- if (eventData.length - offset < 4)
- return -1;
- ival = ArrayHelper.swap32bitFromArray(eventData, offset);
- offset += 4;
-
- list.add(new Integer(ival));
- }
- break;
- case EVENT_TYPE_LONG: { /* 64-bit signed long */
- long lval;
-
- if (eventData.length - offset < 8)
- return -1;
- lval = ArrayHelper.swap64bitFromArray(eventData, offset);
- offset += 8;
-
- list.add(new Long(lval));
- }
- break;
- case EVENT_TYPE_STRING: { /* UTF-8 chars, not NULL-terminated */
- int strLen;
-
- if (eventData.length - offset < 4)
- return -1;
- strLen = ArrayHelper.swap32bitFromArray(eventData, offset);
- offset += 4;
-
- if (eventData.length - offset < strLen)
- return -1;
-
- // get the string
- try {
- String str = new String(eventData, offset, strLen, "UTF-8"); //$NON-NLS-1$
- list.add(str);
- } catch (UnsupportedEncodingException e) {
- }
- offset += strLen;
- break;
- }
- case EVENT_TYPE_LIST: { /* N items, all different types */
-
- if (eventData.length - offset < 1)
- return -1;
-
- int count = eventData[offset++];
-
- // make a new temp list
- ArrayList<Object> subList = new ArrayList<Object>();
- for (int i = 0; i < count; i++) {
- int result = parseBinaryEvent(eventData, offset, subList);
- if (result == -1) {
- return result;
- }
-
- offset += result;
- }
-
- list.add(subList.toArray());
- }
- break;
- default:
- Log.e("EventLogParser", //$NON-NLS-1$
- String.format("Unknown binary event type %1$d", type)); //$NON-NLS-1$
- return -1;
- }
-
- return offset - dataOffset;
- }
-
- private Object parseTextData(String data, int tagValue) {
- // first, get the description of what we're supposed to parse
- EventValueDescription[] desc = mValueDescriptionMap.get(tagValue);
-
- if (desc == null) {
- // TODO parse and create string values.
- return null;
- }
-
- if (desc.length == 1) {
- return getObjectFromString(data, desc[0].getEventValueType());
- } else if (data.startsWith("[") && data.endsWith("]")) {
- data = data.substring(1, data.length() - 1);
-
- // get each individual values as String
- String[] values = data.split(",");
-
- if (tagValue == GcEventContainer.GC_EVENT_TAG) {
- // special case for the GC event!
- Object[] objects = new Object[2];
-
- objects[0] = getObjectFromString(values[0], EventValueType.LONG);
- objects[1] = getObjectFromString(values[1], EventValueType.LONG);
-
- return objects;
- } else {
- // must be the same number as the number of descriptors.
- if (values.length != desc.length) {
- return null;
- }
-
- Object[] objects = new Object[values.length];
-
- for (int i = 0 ; i < desc.length ; i++) {
- Object obj = getObjectFromString(values[i], desc[i].getEventValueType());
- if (obj == null) {
- return null;
- }
- objects[i] = obj;
- }
-
- return objects;
- }
- }
-
- return null;
- }
-
-
- private Object getObjectFromString(String value, EventValueType type) {
- try {
- switch (type) {
- case INT:
- return Integer.valueOf(value);
- case LONG:
- return Long.valueOf(value);
- case STRING:
- return value;
- }
- } catch (NumberFormatException e) {
- // do nothing, we'll return null.
- }
-
- return null;
- }
-
- /**
- * Recreates the event-log-tags at the specified file path.
- * @param filePath the file path to write the file.
- * @throws IOException
- */
- public void saveTags(String filePath) throws IOException {
- File destFile = new File(filePath);
- destFile.createNewFile();
- FileOutputStream fos = null;
-
- try {
-
- fos = new FileOutputStream(destFile);
-
- for (Integer key : mTagMap.keySet()) {
- // get the tag name
- String tagName = mTagMap.get(key);
-
- // get the value descriptions
- EventValueDescription[] descriptors = mValueDescriptionMap.get(key);
-
- String line = null;
- if (descriptors != null) {
- StringBuilder sb = new StringBuilder();
- sb.append(String.format("%1$d %2$s", key, tagName)); //$NON-NLS-1$
- boolean first = true;
- for (EventValueDescription evd : descriptors) {
- if (first) {
- sb.append(" ("); //$NON-NLS-1$
- first = false;
- } else {
- sb.append(",("); //$NON-NLS-1$
- }
- sb.append(evd.getName());
- sb.append("|"); //$NON-NLS-1$
- sb.append(evd.getEventValueType().getValue());
- sb.append("|"); //$NON-NLS-1$
- sb.append(evd.getValueType().getValue());
- sb.append("|)"); //$NON-NLS-1$
- }
- sb.append("\n"); //$NON-NLS-1$
-
- line = sb.toString();
- } else {
- line = String.format("%1$d %2$s\n", key, tagName); //$NON-NLS-1$
- }
-
- byte[] buffer = line.getBytes();
- fos.write(buffer);
- }
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- }
-
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventValueDescription.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventValueDescription.java
deleted file mode 100644
index 58d147c..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/EventValueDescription.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * 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.ddmlib.log;
-
-import com.android.ddmlib.log.EventContainer.EventValueType;
-
-import java.util.Locale;
-
-
-/**
- * Describes an {@link EventContainer} value.
- * <p/>
- * This is a stand-alone object, not linked to a particular Event. It describes the value, by
- * name, type ({@link EventValueType}), and (if needed) value unit ({@link ValueType}).
- * <p/>
- * The index of the value is not contained within this class, and is instead dependent on the
- * index of this particular object in the array of {@link EventValueDescription} returned by
- * {@link EventLogParser#getEventInfoMap()} when queried for a particular event tag.
- *
- */
-public final class EventValueDescription {
-
- /**
- * Represents the type of a numerical value. This is used to display values of vastly different
- * type/range in graphs.
- */
- public static enum ValueType {
- NOT_APPLICABLE(0),
- OBJECTS(1),
- BYTES(2),
- MILLISECONDS(3),
- ALLOCATIONS(4),
- ID(5),
- PERCENT(6);
-
- private int mValue;
-
- /**
- * Checks that the {@link EventValueType} is compatible with the {@link ValueType}.
- * @param type the {@link EventValueType} to check.
- * @throws InvalidValueTypeException if the types are not compatible.
- */
- public void checkType(EventValueType type) throws InvalidValueTypeException {
- if ((type != EventValueType.INT && type != EventValueType.LONG)
- && this != NOT_APPLICABLE) {
- throw new InvalidValueTypeException(
- String.format("%1$s doesn't support type %2$s", type, this));
- }
- }
-
- /**
- * Returns a {@link ValueType} from an integer value, or <code>null</code> if no match
- * were found.
- * @param value the integer value.
- */
- public static ValueType getValueType(int value) {
- for (ValueType type : values()) {
- if (type.mValue == value) {
- return type;
- }
- }
- return null;
- }
-
- /**
- * Returns the integer value of the enum.
- */
- public int getValue() {
- return mValue;
- }
-
- @Override
- public String toString() {
- return super.toString().toLowerCase(Locale.US);
- }
-
- private ValueType(int value) {
- mValue = value;
- }
- }
-
- private String mName;
- private EventValueType mEventValueType;
- private ValueType mValueType;
-
- /**
- * Builds a {@link EventValueDescription} with a name and a type.
- * <p/>
- * If the type is {@link EventValueType#INT} or {@link EventValueType#LONG}, the
- * {@link #mValueType} is set to {@link ValueType#BYTES} by default. It set to
- * {@link ValueType#NOT_APPLICABLE} for all other {@link EventValueType} values.
- * @param name
- * @param type
- */
- EventValueDescription(String name, EventValueType type) {
- mName = name;
- mEventValueType = type;
- if (mEventValueType == EventValueType.INT || mEventValueType == EventValueType.LONG) {
- mValueType = ValueType.BYTES;
- } else {
- mValueType = ValueType.NOT_APPLICABLE;
- }
- }
-
- /**
- * Builds a {@link EventValueDescription} with a name and a type, and a {@link ValueType}.
- * <p/>
- * @param name
- * @param type
- * @param valueType
- * @throws InvalidValueTypeException if type and valuetype are not compatible.
- *
- */
- EventValueDescription(String name, EventValueType type, ValueType valueType)
- throws InvalidValueTypeException {
- mName = name;
- mEventValueType = type;
- mValueType = valueType;
- mValueType.checkType(mEventValueType);
- }
-
- /**
- * @return the Name.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * @return the {@link EventValueType}.
- */
- public EventValueType getEventValueType() {
- return mEventValueType;
- }
-
- /**
- * @return the {@link ValueType}.
- */
- public ValueType getValueType() {
- return mValueType;
- }
-
- @Override
- public String toString() {
- if (mValueType != ValueType.NOT_APPLICABLE) {
- return String.format("%1$s (%2$s, %3$s)", mName, mEventValueType.toString(),
- mValueType.toString());
- }
-
- return String.format("%1$s (%2$s)", mName, mEventValueType.toString());
- }
-
- /**
- * Checks if the value is of the proper type for this receiver.
- * @param value the value to check.
- * @return true if the value is of the proper type for this receiver.
- */
- public boolean checkForType(Object value) {
- switch (mEventValueType) {
- case INT:
- return value instanceof Integer;
- case LONG:
- return value instanceof Long;
- case STRING:
- return value instanceof String;
- case LIST:
- return value instanceof Object[];
- }
-
- return false;
- }
-
- /**
- * Returns an object of a valid type (based on the value returned by
- * {@link #getEventValueType()}) from a String value.
- * <p/>
- * IMPORTANT {@link EventValueType#LIST} and {@link EventValueType#TREE} are not
- * supported.
- * @param value the value of the object expressed as a string.
- * @return an object or null if the conversion could not be done.
- */
- public Object getObjectFromString(String value) {
- switch (mEventValueType) {
- case INT:
- try {
- return Integer.valueOf(value);
- } catch (NumberFormatException e) {
- return null;
- }
- case LONG:
- try {
- return Long.valueOf(value);
- } catch (NumberFormatException e) {
- return null;
- }
- case STRING:
- return value;
- }
-
- return null;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/GcEventContainer.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/GcEventContainer.java
deleted file mode 100644
index 7bae202..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/GcEventContainer.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * 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.ddmlib.log;
-
-import com.android.ddmlib.log.EventValueDescription.ValueType;
-import com.android.ddmlib.log.LogReceiver.LogEntry;
-
-/**
- * Custom Event Container for the Gc event since this event doesn't simply output data in
- * int or long format, but encodes several values on 4 longs.
- * <p/>
- * The array of {@link EventValueDescription}s parsed from the "event-log-tags" file must
- * be ignored, and instead, the array returned from {@link #getValueDescriptions()} must be used.
- */
-final class GcEventContainer extends EventContainer {
-
- public final static int GC_EVENT_TAG = 20001;
-
- private String processId;
- private long gcTime;
- private long bytesFreed;
- private long objectsFreed;
- private long actualSize;
- private long allowedSize;
- private long softLimit;
- private long objectsAllocated;
- private long bytesAllocated;
- private long zActualSize;
- private long zAllowedSize;
- private long zObjectsAllocated;
- private long zBytesAllocated;
- private long dlmallocFootprint;
- private long mallinfoTotalAllocatedSpace;
- private long externalLimit;
- private long externalBytesAllocated;
-
- GcEventContainer(LogEntry entry, int tag, Object data) {
- super(entry, tag, data);
- init(data);
- }
-
- GcEventContainer(int tag, int pid, int tid, int sec, int nsec, Object data) {
- super(tag, pid, tid, sec, nsec, data);
- init(data);
- }
-
- /**
- * @param data
- */
- private void init(Object data) {
- if (data instanceof Object[]) {
- Object[] values = (Object[])data;
- for (int i = 0; i < values.length; i++) {
- if (values[i] instanceof Long) {
- parseDvmHeapInfo((Long)values[i], i);
- }
- }
- }
- }
-
- @Override
- public EventValueType getType() {
- return EventValueType.LIST;
- }
-
- @Override
- public boolean testValue(int index, Object value, CompareMethod compareMethod)
- throws InvalidTypeException {
- // do a quick easy check on the type.
- if (index == 0) {
- if ((value instanceof String) == false) {
- throw new InvalidTypeException();
- }
- } else if ((value instanceof Long) == false) {
- throw new InvalidTypeException();
- }
-
- switch (compareMethod) {
- case EQUAL_TO:
- if (index == 0) {
- return processId.equals(value);
- } else {
- return getValueAsLong(index) == ((Long)value).longValue();
- }
- case LESSER_THAN:
- return getValueAsLong(index) <= ((Long)value).longValue();
- case LESSER_THAN_STRICT:
- return getValueAsLong(index) < ((Long)value).longValue();
- case GREATER_THAN:
- return getValueAsLong(index) >= ((Long)value).longValue();
- case GREATER_THAN_STRICT:
- return getValueAsLong(index) > ((Long)value).longValue();
- case BIT_CHECK:
- return (getValueAsLong(index) & ((Long)value).longValue()) != 0;
- }
-
- throw new ArrayIndexOutOfBoundsException();
- }
-
- @Override
- public Object getValue(int valueIndex) {
- if (valueIndex == 0) {
- return processId;
- }
-
- try {
- return new Long(getValueAsLong(valueIndex));
- } catch (InvalidTypeException e) {
- // this would only happened if valueIndex was 0, which we test above.
- }
-
- return null;
- }
-
- @Override
- public double getValueAsDouble(int valueIndex) throws InvalidTypeException {
- return (double)getValueAsLong(valueIndex);
- }
-
- @Override
- public String getValueAsString(int valueIndex) {
- switch (valueIndex) {
- case 0:
- return processId;
- default:
- try {
- return Long.toString(getValueAsLong(valueIndex));
- } catch (InvalidTypeException e) {
- // we shouldn't stop there since we test, in this method first.
- }
- }
-
- throw new ArrayIndexOutOfBoundsException();
- }
-
- /**
- * Returns a custom array of {@link EventValueDescription} since the actual content of this
- * event (list of (long, long) does not match the values encoded into those longs.
- */
- static EventValueDescription[] getValueDescriptions() {
- try {
- return new EventValueDescription[] {
- new EventValueDescription("Process Name", EventValueType.STRING),
- new EventValueDescription("GC Time", EventValueType.LONG,
- ValueType.MILLISECONDS),
- new EventValueDescription("Freed Objects", EventValueType.LONG,
- ValueType.OBJECTS),
- new EventValueDescription("Freed Bytes", EventValueType.LONG, ValueType.BYTES),
- new EventValueDescription("Soft Limit", EventValueType.LONG, ValueType.BYTES),
- new EventValueDescription("Actual Size (aggregate)", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("Allowed Size (aggregate)", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("Allocated Objects (aggregate)",
- EventValueType.LONG, ValueType.OBJECTS),
- new EventValueDescription("Allocated Bytes (aggregate)", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("Actual Size", EventValueType.LONG, ValueType.BYTES),
- new EventValueDescription("Allowed Size", EventValueType.LONG, ValueType.BYTES),
- new EventValueDescription("Allocated Objects", EventValueType.LONG,
- ValueType.OBJECTS),
- new EventValueDescription("Allocated Bytes", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("Actual Size (zygote)", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("Allowed Size (zygote)", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("Allocated Objects (zygote)", EventValueType.LONG,
- ValueType.OBJECTS),
- new EventValueDescription("Allocated Bytes (zygote)", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("External Allocation Limit", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("External Bytes Allocated", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("dlmalloc Footprint", EventValueType.LONG,
- ValueType.BYTES),
- new EventValueDescription("Malloc Info: Total Allocated Space",
- EventValueType.LONG, ValueType.BYTES),
- };
- } catch (InvalidValueTypeException e) {
- // this shouldn't happen since we control manual the EventValueType and the ValueType
- // values. For development purpose, we assert if this happens.
- assert false;
- }
-
- // this shouldn't happen, but the compiler complains otherwise.
- return null;
- }
-
- private void parseDvmHeapInfo(long data, int index) {
- switch (index) {
- case 0:
- // [63 ] Must be zero
- // [62-24] ASCII process identifier
- // [23-12] GC time in ms
- // [11- 0] Bytes freed
-
- gcTime = float12ToInt((int)((data >> 12) & 0xFFFL));
- bytesFreed = float12ToInt((int)(data & 0xFFFL));
-
- // convert the long into an array, in the proper order so that we can convert the
- // first 5 char into a string.
- byte[] dataArray = new byte[8];
- put64bitsToArray(data, dataArray, 0);
-
- // get the name from the string
- processId = new String(dataArray, 0, 5);
- break;
- case 1:
- // [63-62] 10
- // [61-60] Reserved; must be zero
- // [59-48] Objects freed
- // [47-36] Actual size (current footprint)
- // [35-24] Allowed size (current hard max)
- // [23-12] Objects allocated
- // [11- 0] Bytes allocated
- objectsFreed = float12ToInt((int)((data >> 48) & 0xFFFL));
- actualSize = float12ToInt((int)((data >> 36) & 0xFFFL));
- allowedSize = float12ToInt((int)((data >> 24) & 0xFFFL));
- objectsAllocated = float12ToInt((int)((data >> 12) & 0xFFFL));
- bytesAllocated = float12ToInt((int)(data & 0xFFFL));
- break;
- case 2:
- // [63-62] 11
- // [61-60] Reserved; must be zero
- // [59-48] Soft limit (current soft max)
- // [47-36] Actual size (current footprint)
- // [35-24] Allowed size (current hard max)
- // [23-12] Objects allocated
- // [11- 0] Bytes allocated
- softLimit = float12ToInt((int)((data >> 48) & 0xFFFL));
- zActualSize = float12ToInt((int)((data >> 36) & 0xFFFL));
- zAllowedSize = float12ToInt((int)((data >> 24) & 0xFFFL));
- zObjectsAllocated = float12ToInt((int)((data >> 12) & 0xFFFL));
- zBytesAllocated = float12ToInt((int)(data & 0xFFFL));
- break;
- case 3:
- // [63-48] Reserved; must be zero
- // [47-36] dlmallocFootprint
- // [35-24] mallinfo: total allocated space
- // [23-12] External byte limit
- // [11- 0] External bytes allocated
- dlmallocFootprint = float12ToInt((int)((data >> 36) & 0xFFFL));
- mallinfoTotalAllocatedSpace = float12ToInt((int)((data >> 24) & 0xFFFL));
- externalLimit = float12ToInt((int)((data >> 12) & 0xFFFL));
- externalBytesAllocated = float12ToInt((int)(data & 0xFFFL));
- break;
- default:
- break;
- }
- }
-
- /**
- * Converts a 12 bit float representation into an unsigned int (returned as a long)
- * @param f12
- */
- private static long float12ToInt(int f12) {
- return (f12 & 0x1FF) << ((f12 >>> 9) * 4);
- }
-
- /**
- * puts an unsigned value in an array.
- * @param value The value to put.
- * @param dest the destination array
- * @param offset the offset in the array where to put the value.
- * Array length must be at least offset + 8
- */
- private static void put64bitsToArray(long value, byte[] dest, int offset) {
- dest[offset + 7] = (byte)(value & 0x00000000000000FFL);
- dest[offset + 6] = (byte)((value & 0x000000000000FF00L) >> 8);
- dest[offset + 5] = (byte)((value & 0x0000000000FF0000L) >> 16);
- dest[offset + 4] = (byte)((value & 0x00000000FF000000L) >> 24);
- dest[offset + 3] = (byte)((value & 0x000000FF00000000L) >> 32);
- dest[offset + 2] = (byte)((value & 0x0000FF0000000000L) >> 40);
- dest[offset + 1] = (byte)((value & 0x00FF000000000000L) >> 48);
- dest[offset + 0] = (byte)((value & 0xFF00000000000000L) >> 56);
- }
-
- /**
- * Returns the long value of the <code>valueIndex</code>-th value.
- * @param valueIndex the index of the value.
- * @throws InvalidTypeException if index is 0 as it is a string value.
- */
- private final long getValueAsLong(int valueIndex) throws InvalidTypeException {
- switch (valueIndex) {
- case 0:
- throw new InvalidTypeException();
- case 1:
- return gcTime;
- case 2:
- return objectsFreed;
- case 3:
- return bytesFreed;
- case 4:
- return softLimit;
- case 5:
- return actualSize;
- case 6:
- return allowedSize;
- case 7:
- return objectsAllocated;
- case 8:
- return bytesAllocated;
- case 9:
- return actualSize - zActualSize;
- case 10:
- return allowedSize - zAllowedSize;
- case 11:
- return objectsAllocated - zObjectsAllocated;
- case 12:
- return bytesAllocated - zBytesAllocated;
- case 13:
- return zActualSize;
- case 14:
- return zAllowedSize;
- case 15:
- return zObjectsAllocated;
- case 16:
- return zBytesAllocated;
- case 17:
- return externalLimit;
- case 18:
- return externalBytesAllocated;
- case 19:
- return dlmallocFootprint;
- case 20:
- return mallinfoTotalAllocatedSpace;
- }
-
- throw new ArrayIndexOutOfBoundsException();
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidTypeException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidTypeException.java
deleted file mode 100644
index 016f8aa..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidTypeException.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.ddmlib.log;
-
-import java.io.Serializable;
-
-/**
- * Exception thrown when accessing an {@link EventContainer} value with the wrong type.
- */
-public final class InvalidTypeException extends Exception {
-
- /**
- * Needed by {@link Serializable}.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructs a new exception with the default detail message.
- * @see java.lang.Exception
- */
- public InvalidTypeException() {
- super("Invalid Type");
- }
-
- /**
- * Constructs a new exception with the specified detail message.
- * @param message the detail message. The detail message is saved for later retrieval
- * by the {@link Throwable#getMessage()} method.
- * @see java.lang.Exception
- */
- public InvalidTypeException(String message) {
- super(message);
- }
-
- /**
- * Constructs a new exception with the specified cause and a detail message of
- * <code>(cause==null ? null : cause.toString())</code> (which typically contains
- * the class and detail message of cause).
- * @param cause the cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code> value is permitted,
- * and indicates that the cause is nonexistent or unknown.)
- * @see java.lang.Exception
- */
- public InvalidTypeException(Throwable cause) {
- super(cause);
- }
-
- /**
- * Constructs a new exception with the specified detail message and cause.
- * @param message the detail message. The detail message is saved for later retrieval
- * by the {@link Throwable#getMessage()} method.
- * @param cause the cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code> value is permitted,
- * and indicates that the cause is nonexistent or unknown.)
- * @see java.lang.Exception
- */
- public InvalidTypeException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidValueTypeException.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidValueTypeException.java
deleted file mode 100644
index a3050c8..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/InvalidValueTypeException.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.ddmlib.log;
-
-import com.android.ddmlib.log.EventContainer.EventValueType;
-import com.android.ddmlib.log.EventValueDescription.ValueType;
-
-import java.io.Serializable;
-
-/**
- * Exception thrown when associating an {@link EventValueType} with an incompatible
- * {@link ValueType}.
- */
-public final class InvalidValueTypeException extends Exception {
-
- /**
- * Needed by {@link Serializable}.
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructs a new exception with the default detail message.
- * @see java.lang.Exception
- */
- public InvalidValueTypeException() {
- super("Invalid Type");
- }
-
- /**
- * Constructs a new exception with the specified detail message.
- * @param message the detail message. The detail message is saved for later retrieval
- * by the {@link Throwable#getMessage()} method.
- * @see java.lang.Exception
- */
- public InvalidValueTypeException(String message) {
- super(message);
- }
-
- /**
- * Constructs a new exception with the specified cause and a detail message of
- * <code>(cause==null ? null : cause.toString())</code> (which typically contains
- * the class and detail message of cause).
- * @param cause the cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code> value is permitted,
- * and indicates that the cause is nonexistent or unknown.)
- * @see java.lang.Exception
- */
- public InvalidValueTypeException(Throwable cause) {
- super(cause);
- }
-
- /**
- * Constructs a new exception with the specified detail message and cause.
- * @param message the detail message. The detail message is saved for later retrieval
- * by the {@link Throwable#getMessage()} method.
- * @param cause the cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code> value is permitted,
- * and indicates that the cause is nonexistent or unknown.)
- * @see java.lang.Exception
- */
- public InvalidValueTypeException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/LogReceiver.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/LogReceiver.java
deleted file mode 100644
index b49f025..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/log/LogReceiver.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * 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.ddmlib.log;
-
-
-import com.android.ddmlib.utils.ArrayHelper;
-
-import java.security.InvalidParameterException;
-
-/**
- * Receiver able to provide low level parsing for device-side log services.
- */
-public final class LogReceiver {
-
- private final static int ENTRY_HEADER_SIZE = 20; // 2*2 + 4*4; see LogEntry.
-
- /**
- * Represents a log entry and its raw data.
- */
- public final static class LogEntry {
- /*
- * See //device/include/utils/logger.h
- */
- /** 16bit unsigned: length of the payload. */
- public int len; /* This is normally followed by a 16 bit padding */
- /** pid of the process that generated this {@link LogEntry} */
- public int pid;
- /** tid of the process that generated this {@link LogEntry} */
- public int tid;
- /** Seconds since epoch. */
- public int sec;
- /** nanoseconds. */
- public int nsec;
- /** The entry's raw data. */
- public byte[] data;
- };
-
- /**
- * Classes which implement this interface provide a method that deals
- * with {@link LogEntry} objects coming from log service through a {@link LogReceiver}.
- * <p/>This interface provides two methods.
- * <ul>
- * <li>{@link #newEntry(com.android.ddmlib.log.LogReceiver.LogEntry)} provides a
- * first level of parsing, extracting {@link LogEntry} objects out of the log service output.</li>
- * <li>{@link #newData(byte[], int, int)} provides a way to receive the raw information
- * coming directly from the log service.</li>
- * </ul>
- */
- public interface ILogListener {
- /**
- * Sent when a new {@link LogEntry} has been parsed by the {@link LogReceiver}.
- * @param entry the new log entry.
- */
- public void newEntry(LogEntry entry);
-
- /**
- * Sent when new raw data is coming from the log service.
- * @param data the raw data buffer.
- * @param offset the offset into the buffer signaling the beginning of the new data.
- * @param length the length of the new data.
- */
- public void newData(byte[] data, int offset, int length);
- }
-
- /** Current {@link LogEntry} being read, before sending it to the listener. */
- private LogEntry mCurrentEntry;
-
- /** Temp buffer to store partial entry headers. */
- private byte[] mEntryHeaderBuffer = new byte[ENTRY_HEADER_SIZE];
- /** Offset in the partial header buffer */
- private int mEntryHeaderOffset = 0;
- /** Offset in the partial entry data */
- private int mEntryDataOffset = 0;
-
- /** Listener waiting for receive fully read {@link LogEntry} objects */
- private ILogListener mListener;
-
- private boolean mIsCancelled = false;
-
- /**
- * Creates a {@link LogReceiver} with an {@link ILogListener}.
- * <p/>
- * The {@link ILogListener} will receive new log entries as they are parsed, in the form
- * of {@link LogEntry} objects.
- * @param listener the listener to receive new log entries.
- */
- public LogReceiver(ILogListener listener) {
- mListener = listener;
- }
-
-
- /**
- * Parses new data coming from the log service.
- * @param data the data buffer
- * @param offset the offset into the buffer signaling the beginning of the new data.
- * @param length the length of the new data.
- */
- public void parseNewData(byte[] data, int offset, int length) {
- // notify the listener of new raw data
- if (mListener != null) {
- mListener.newData(data, offset, length);
- }
-
- // loop while there is still data to be read and the receiver has not be cancelled.
- while (length > 0 && mIsCancelled == false) {
- // first check if we have no current entry.
- if (mCurrentEntry == null) {
- if (mEntryHeaderOffset + length < ENTRY_HEADER_SIZE) {
- // if we don't have enough data to finish the header, save
- // the data we have and return
- System.arraycopy(data, offset, mEntryHeaderBuffer, mEntryHeaderOffset, length);
- mEntryHeaderOffset += length;
- return;
- } else {
- // we have enough to fill the header, let's do it.
- // did we store some part at the beginning of the header?
- if (mEntryHeaderOffset != 0) {
- // copy the rest of the entry header into the header buffer
- int size = ENTRY_HEADER_SIZE - mEntryHeaderOffset;
- System.arraycopy(data, offset, mEntryHeaderBuffer, mEntryHeaderOffset,
- size);
-
- // create the entry from the header buffer
- mCurrentEntry = createEntry(mEntryHeaderBuffer, 0);
-
- // since we used the whole entry header buffer, we reset the offset
- mEntryHeaderOffset = 0;
-
- // adjust current offset and remaining length to the beginning
- // of the entry data
- offset += size;
- length -= size;
- } else {
- // create the entry directly from the data array
- mCurrentEntry = createEntry(data, offset);
-
- // adjust current offset and remaining length to the beginning
- // of the entry data
- offset += ENTRY_HEADER_SIZE;
- length -= ENTRY_HEADER_SIZE;
- }
- }
- }
-
- // at this point, we have an entry, and offset/length have been updated to skip
- // the entry header.
-
- // if we have enough data for this entry or more, we'll need to end this entry
- if (length >= mCurrentEntry.len - mEntryDataOffset) {
- // compute and save the size of the data that we have to read for this entry,
- // based on how much we may already have read.
- int dataSize = mCurrentEntry.len - mEntryDataOffset;
-
- // we only read what we need, and put it in the entry buffer.
- System.arraycopy(data, offset, mCurrentEntry.data, mEntryDataOffset, dataSize);
-
- // notify the listener of a new entry
- if (mListener != null) {
- mListener.newEntry(mCurrentEntry);
- }
-
- // reset some flags: we have read 0 data of the current entry.
- // and we have no current entry being read.
- mEntryDataOffset = 0;
- mCurrentEntry = null;
-
- // and update the data buffer info to the end of the current entry / start
- // of the next one.
- offset += dataSize;
- length -= dataSize;
- } else {
- // we don't have enough data to fill this entry, so we store what we have
- // in the entry itself.
- System.arraycopy(data, offset, mCurrentEntry.data, mEntryDataOffset, length);
-
- // save the amount read for the data.
- mEntryDataOffset += length;
- return;
- }
- }
- }
-
- /**
- * Returns whether this receiver is canceling the remote service.
- */
- public boolean isCancelled() {
- return mIsCancelled;
- }
-
- /**
- * Cancels the current remote service.
- */
- public void cancel() {
- mIsCancelled = true;
- }
-
- /**
- * Creates a {@link LogEntry} from the array of bytes. This expects the data buffer size
- * to be at least <code>offset + {@link #ENTRY_HEADER_SIZE}</code>.
- * @param data the data buffer the entry is read from.
- * @param offset the offset of the first byte from the buffer representing the entry.
- * @return a new {@link LogEntry} or <code>null</code> if some error happened.
- */
- private LogEntry createEntry(byte[] data, int offset) {
- if (data.length < offset + ENTRY_HEADER_SIZE) {
- throw new InvalidParameterException(
- "Buffer not big enough to hold full LoggerEntry header");
- }
-
- // create the new entry and fill it.
- LogEntry entry = new LogEntry();
- entry.len = ArrayHelper.swapU16bitFromArray(data, offset);
-
- // we've read only 16 bits, but since there's also a 16 bit padding,
- // we can skip right over both.
- offset += 4;
-
- entry.pid = ArrayHelper.swap32bitFromArray(data, offset);
- offset += 4;
- entry.tid = ArrayHelper.swap32bitFromArray(data, offset);
- offset += 4;
- entry.sec = ArrayHelper.swap32bitFromArray(data, offset);
- offset += 4;
- entry.nsec = ArrayHelper.swap32bitFromArray(data, offset);
- offset += 4;
-
- // allocate the data
- entry.data = new byte[entry.len];
-
- return entry;
- }
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java
deleted file mode 100644
index 7d3d6bf..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib.testrunner;
-
-import com.android.ddmlib.AdbCommandRejectedException;
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.ShellCommandUnresponsiveException;
-import com.android.ddmlib.TimeoutException;
-
-import java.io.IOException;
-import java.util.Collection;
-
-/**
- * Interface for running a Android test command remotely and reporting result to a listener.
- */
-public interface IRemoteAndroidTestRunner {
-
- public static enum TestSize {
- /** Run tests annotated with SmallTest */
- SMALL("small"),
- /** Run tests annotated with MediumTest */
- MEDIUM("medium"),
- /** Run tests annotated with LargeTest */
- LARGE("large");
-
- private String mRunnerValue;
-
- /**
- * Create a {@link TestSize}.
- *
- * @param runnerValue the {@link String} value that represents the size that is passed to
- * device. Defined on device in android.test.InstrumentationTestRunner.
- */
- TestSize(String runnerValue) {
- mRunnerValue = runnerValue;
- }
-
- String getRunnerValue() {
- return mRunnerValue;
- }
-
- /**
- * Return the {@link TestSize} corresponding to the given Android platform defined value.
- *
- * @throws IllegalArgumentException if {@link TestSize} cannot be found.
- */
- public static TestSize getTestSize(String value) {
- // build the error message in the success case too, to avoid two for loops
- StringBuilder msgBuilder = new StringBuilder("Unknown TestSize ");
- msgBuilder.append(value);
- msgBuilder.append(", Must be one of ");
- for (TestSize size : values()) {
- if (size.getRunnerValue().equals(value)) {
- return size;
- }
- msgBuilder.append(size.getRunnerValue());
- msgBuilder.append(", ");
- }
- throw new IllegalArgumentException(msgBuilder.toString());
- }
- }
-
- /**
- * Returns the application package name.
- */
- public String getPackageName();
-
- /**
- * Returns the runnerName.
- */
- public String getRunnerName();
-
- /**
- * Sets to run only tests in this class
- * Must be called before 'run'.
- *
- * @param className fully qualified class name (eg x.y.z)
- */
- public void setClassName(String className);
-
- /**
- * Sets to run only tests in the provided classes
- * Must be called before 'run'.
- * <p>
- * If providing more than one class, requires a InstrumentationTestRunner that supports
- * the multiple class argument syntax.
- *
- * @param classNames array of fully qualified class names (eg x.y.z)
- */
- public void setClassNames(String[] classNames);
-
- /**
- * Sets to run only specified test method
- * Must be called before 'run'.
- *
- * @param className fully qualified class name (eg x.y.z)
- * @param testName method name
- */
- public void setMethodName(String className, String testName);
-
- /**
- * Sets to run all tests in specified package
- * Must be called before 'run'.
- *
- * @param packageName fully qualified package name (eg x.y.z)
- */
- public void setTestPackageName(String packageName);
-
- /**
- * Sets to run only tests of given size.
- * Must be called before 'run'.
- *
- * @param size the {@link TestSize} to run.
- */
- public void setTestSize(TestSize size);
-
- /**
- * Adds a argument to include in instrumentation command.
- * <p/>
- * Must be called before 'run'. If an argument with given name has already been provided, it's
- * value will be overridden.
- *
- * @param name the name of the instrumentation bundle argument
- * @param value the value of the argument
- */
- public void addInstrumentationArg(String name, String value);
-
- /**
- * Removes a previously added argument.
- *
- * @param name the name of the instrumentation bundle argument to remove
- */
- public void removeInstrumentationArg(String name);
-
- /**
- * Adds a boolean argument to include in instrumentation command.
- * <p/>
- * @see RemoteAndroidTestRunner#addInstrumentationArg
- *
- * @param name the name of the instrumentation bundle argument
- * @param value the value of the argument
- */
- public void addBooleanArg(String name, boolean value);
-
- /**
- * Sets this test run to log only mode - skips test execution.
- */
- public void setLogOnly(boolean logOnly);
-
- /**
- * Sets this debug mode of this test run. If true, the Android test runner will wait for a
- * debugger to attach before proceeding with test execution.
- */
- public void setDebug(boolean debug);
-
- /**
- * Sets this code coverage mode of this test run.
- */
- public void setCoverage(boolean coverage);
-
- /**
- * Sets the maximum time allowed between output of the shell command running the tests on
- * the devices.
- * <p/>
- * This allows setting a timeout in case the tests can become stuck and never finish. This is
- * different from the normal timeout on the connection.
- * <p/>
- * By default no timeout will be specified.
- *
- * @see IDevice#executeShellCommand(String, com.android.ddmlib.IShellOutputReceiver, int)
- */
- public void setMaxtimeToOutputResponse(int maxTimeToOutputResponse);
-
- /**
- * Set a custom run name to be reported to the {@link ITestRunListener} on {@link #run}
- * <p/>
- * If unspecified, will use package name
- *
- * @param runName
- */
- public void setRunName(String runName);
-
- /**
- * Execute this test run.
- * <p/>
- * Convenience method for {@link #run(Collection)}.
- *
- * @param listeners listens for test results
- * @throws TimeoutException in case of a timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException if the device did not output any test result for
- * a period longer than the max time to output.
- * @throws IOException if connection to device was lost.
- *
- * @see #setMaxtimeToOutputResponse(int)
- */
- public void run(ITestRunListener... listeners)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * Execute this test run.
- *
- * @param listeners collection of listeners for test results
- * @throws TimeoutException in case of a timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException if the device did not output any test result for
- * a period longer than the max time to output.
- * @throws IOException if connection to device was lost.
- *
- * @see #setMaxtimeToOutputResponse(int)
- */
- public void run(Collection<ITestRunListener> listeners)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * Requests cancellation of this test run.
- */
- public void cancel();
-
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/ITestRunListener.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/ITestRunListener.java
deleted file mode 100644
index 7e20c9f..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/ITestRunListener.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.ddmlib.testrunner;
-
-import java.util.Map;
-
-/**
- * Receives event notifications during instrumentation test runs.
- * <p/>
- * Patterned after junit.runner.TestRunListener.
- * <p/>
- * The sequence of calls will be:
- * <ul>
- * <li> testRunStarted
- * <li> testStarted
- * <li> [testFailed]
- * <li> testEnded
- * <li> ....
- * <li> [testRunFailed]
- * <li> testRunEnded
- * </ul>
- */
-public interface ITestRunListener {
-
- /**
- * Types of test failures.
- */
- enum TestFailure {
- /** Test failed due to unanticipated uncaught exception. */
- ERROR,
- /** Test failed due to a false assertion. */
- FAILURE
- }
-
- /**
- * Reports the start of a test run.
- *
- * @param runName the test run name
- * @param testCount total number of tests in test run
- */
- public void testRunStarted(String runName, int testCount);
-
- /**
- * Reports the start of an individual test case.
- *
- * @param test identifies the test
- */
- public void testStarted(TestIdentifier test);
-
- /**
- * Reports the failure of a individual test case.
- * <p/>
- * Will be called between testStarted and testEnded.
- *
- * @param status failure type
- * @param test identifies the test
- * @param trace stack trace of failure
- */
- public void testFailed(TestFailure status, TestIdentifier test, String trace);
-
- /**
- * Reports the execution end of an individual test case.
- * <p/>
- * If {@link #testFailed} was not invoked, this test passed. Also returns any key/value
- * metrics which may have been emitted during the test case's execution.
- *
- * @param test identifies the test
- * @param testMetrics a {@link Map} of the metrics emitted
- */
- public void testEnded(TestIdentifier test, Map<String, String> testMetrics);
-
- /**
- * Reports test run failed to complete due to a fatal error.
- *
- * @param errorMessage {@link String} describing reason for run failure.
- */
- public void testRunFailed(String errorMessage);
-
- /**
- * Reports test run stopped before completion due to a user request.
- * <p/>
- * TODO: currently unused, consider removing
- *
- * @param elapsedTime device reported elapsed time, in milliseconds
- */
- public void testRunStopped(long elapsedTime);
-
- /**
- * Reports end of test run.
- *
- * @param elapsedTime device reported elapsed time, in milliseconds
- * @param runMetrics key-value pairs reported at the end of a test run
- */
- public void testRunEnded(long elapsedTime, Map<String, String> runMetrics);
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/InstrumentationResultParser.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/InstrumentationResultParser.java
deleted file mode 100644
index 71f329a..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/InstrumentationResultParser.java
+++ /dev/null
@@ -1,609 +0,0 @@
-/*
- * 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.ddmlib.testrunner;
-
-import com.android.ddmlib.IShellOutputReceiver;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.MultiLineReceiver;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Parses the 'raw output mode' results of an instrumentation test run from shell and informs a
- * ITestRunListener of the results.
- *
- * <p>Expects the following output:
- *
- * <p>If fatal error occurred when attempted to run the tests:
- * <pre>
- * INSTRUMENTATION_STATUS: Error=error Message
- * INSTRUMENTATION_FAILED:
- * </pre>
- * <p>or
- * <pre>
- * INSTRUMENTATION_RESULT: shortMsg=error Message
- * </pre>
- *
- * <p>Otherwise, expect a series of test results, each one containing a set of status key/value
- * pairs, delimited by a start(1)/pass(0)/fail(-2)/error(-1) status code result. At end of test
- * run, expects that the elapsed test time in seconds will be displayed
- *
- * <p>For example:
- * <pre>
- * INSTRUMENTATION_STATUS_CODE: 1
- * INSTRUMENTATION_STATUS: class=com.foo.FooTest
- * INSTRUMENTATION_STATUS: test=testFoo
- * INSTRUMENTATION_STATUS: numtests=2
- * INSTRUMENTATION_STATUS: stack=com.foo.FooTest#testFoo:312
- * com.foo.X
- * INSTRUMENTATION_STATUS_CODE: -2
- * ...
- *
- * Time: X
- * </pre>
- * <p>Note that the "value" portion of the key-value pair may wrap over several text lines
- */
-public class InstrumentationResultParser extends MultiLineReceiver {
-
- /** Relevant test status keys. */
- private static class StatusKeys {
- private static final String TEST = "test";
- private static final String CLASS = "class";
- private static final String STACK = "stack";
- private static final String NUMTESTS = "numtests";
- private static final String ERROR = "Error";
- private static final String SHORTMSG = "shortMsg";
- }
-
- /** The set of expected status keys. Used to filter which keys should be stored as metrics */
- private static final Set<String> KNOWN_KEYS = new HashSet<String>();
- static {
- KNOWN_KEYS.add(StatusKeys.TEST);
- KNOWN_KEYS.add(StatusKeys.CLASS);
- KNOWN_KEYS.add(StatusKeys.STACK);
- KNOWN_KEYS.add(StatusKeys.NUMTESTS);
- KNOWN_KEYS.add(StatusKeys.ERROR);
- KNOWN_KEYS.add(StatusKeys.SHORTMSG);
- // unused, but regularly occurring status keys.
- KNOWN_KEYS.add("stream");
- KNOWN_KEYS.add("id");
- KNOWN_KEYS.add("current");
- }
-
- /** Test result status codes. */
- private static class StatusCodes {
- private static final int FAILURE = -2;
- private static final int START = 1;
- private static final int ERROR = -1;
- private static final int OK = 0;
- private static final int IN_PROGRESS = 2;
- }
-
- /** Prefixes used to identify output. */
- private static class Prefixes {
- private static final String STATUS = "INSTRUMENTATION_STATUS: ";
- private static final String STATUS_CODE = "INSTRUMENTATION_STATUS_CODE: ";
- private static final String STATUS_FAILED = "INSTRUMENTATION_FAILED: ";
- private static final String CODE = "INSTRUMENTATION_CODE: ";
- private static final String RESULT = "INSTRUMENTATION_RESULT: ";
- private static final String TIME_REPORT = "Time: ";
- }
-
- private final Collection<ITestRunListener> mTestListeners;
-
- /**
- * Test result data
- */
- private static class TestResult {
- private Integer mCode = null;
- private String mTestName = null;
- private String mTestClass = null;
- private String mStackTrace = null;
- private Integer mNumTests = null;
-
- /** Returns true if all expected values have been parsed */
- boolean isComplete() {
- return mCode != null && mTestName != null && mTestClass != null;
- }
-
- /** Provides a more user readable string for TestResult, if possible */
- @Override
- public String toString() {
- StringBuilder output = new StringBuilder();
- if (mTestClass != null ) {
- output.append(mTestClass);
- output.append('#');
- }
- if (mTestName != null) {
- output.append(mTestName);
- }
- if (output.length() > 0) {
- return output.toString();
- }
- return "unknown result";
- }
- }
-
- /** the name to provide to {@link ITestRunListener#testRunStarted(String, int)} */
- private final String mTestRunName;
-
- /** Stores the status values for the test result currently being parsed */
- private TestResult mCurrentTestResult = null;
-
- /** Stores the status values for the test result last parsed */
- private TestResult mLastTestResult = null;
-
- /** Stores the current "key" portion of the status key-value being parsed. */
- private String mCurrentKey = null;
-
- /** Stores the current "value" portion of the status key-value being parsed. */
- private StringBuilder mCurrentValue = null;
-
- /** True if start of test has already been reported to listener. */
- private boolean mTestStartReported = false;
-
- /** True if the completion of the test run has been detected. */
- private boolean mTestRunFinished = false;
-
- /** True if test run failure has already been reported to listener. */
- private boolean mTestRunFailReported = false;
-
- /** The elapsed time of the test run, in milliseconds. */
- private long mTestTime = 0;
-
- /** True if current test run has been canceled by user. */
- private boolean mIsCancelled = false;
-
- /** The number of tests currently run */
- private int mNumTestsRun = 0;
-
- /** The number of tests expected to run */
- private int mNumTestsExpected = 0;
-
- /** True if the parser is parsing a line beginning with "INSTRUMENTATION_RESULT" */
- private boolean mInInstrumentationResultKey = false;
-
- /**
- * Stores key-value pairs under INSTRUMENTATION_RESULT header, these are printed at the
- * end of a test run, if applicable
- */
- private Map<String, String> mInstrumentationResultBundle = new HashMap<String, String>();
-
- /**
- * Stores key-value pairs of metrics emitted during the execution of each test case. Note that
- * standard keys that are stored in the TestResults class are filtered out of this Map.
- */
- private Map<String, String> mTestMetrics = new HashMap<String, String>();
-
- private static final String LOG_TAG = "InstrumentationResultParser";
-
- /** Error message supplied when no parseable test results are received from test run. */
- static final String NO_TEST_RESULTS_MSG = "No test results";
-
- /** Error message supplied when a test start bundle is parsed, but not the test end bundle. */
- static final String INCOMPLETE_TEST_ERR_MSG_PREFIX = "Test failed to run to completion";
- static final String INCOMPLETE_TEST_ERR_MSG_POSTFIX = "Check device logcat for details";
-
- /** Error message supplied when the test run is incomplete. */
- static final String INCOMPLETE_RUN_ERR_MSG_PREFIX = "Test run failed to complete";
-
- /**
- * Creates the InstrumentationResultParser.
- *
- * @param runName the test run name to provide to
- * {@link ITestRunListener#testRunStarted(String, int)}
- * @param listeners informed of test results as the tests are executing
- */
- public InstrumentationResultParser(String runName, Collection<ITestRunListener> listeners) {
- mTestRunName = runName;
- mTestListeners = new ArrayList<ITestRunListener>(listeners);
- }
-
- /**
- * Creates the InstrumentationResultParser for a single listener.
- *
- * @param runName the test run name to provide to
- * {@link ITestRunListener#testRunStarted(String, int)}
- * @param listener informed of test results as the tests are executing
- */
- public InstrumentationResultParser(String runName, ITestRunListener listener) {
- this(runName, Collections.singletonList(listener));
- }
-
- /**
- * Processes the instrumentation test output from shell.
- *
- * @see MultiLineReceiver#processNewLines
- */
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- parse(line);
- // in verbose mode, dump all adb output to log
- Log.v(LOG_TAG, line);
- }
- }
-
- /**
- * Parse an individual output line. Expects a line that is one of:
- * <ul>
- * <li>
- * The start of a new status line (starts with Prefixes.STATUS or Prefixes.STATUS_CODE),
- * and thus there is a new key=value pair to parse, and the previous key-value pair is
- * finished.
- * </li>
- * <li>
- * A continuation of the previous status (the "value" portion of the key has wrapped
- * to the next line).
- * </li>
- * <li> A line reporting a fatal error in the test run (Prefixes.STATUS_FAILED) </li>
- * <li> A line reporting the total elapsed time of the test run. (Prefixes.TIME_REPORT) </li>
- * </ul>
- *
- * @param line Text output line
- */
- private void parse(String line) {
- if (line.startsWith(Prefixes.STATUS_CODE)) {
- // Previous status key-value has been collected. Store it.
- submitCurrentKeyValue();
- mInInstrumentationResultKey = false;
- parseStatusCode(line);
- } else if (line.startsWith(Prefixes.STATUS)) {
- // Previous status key-value has been collected. Store it.
- submitCurrentKeyValue();
- mInInstrumentationResultKey = false;
- parseKey(line, Prefixes.STATUS.length());
- } else if (line.startsWith(Prefixes.RESULT)) {
- // Previous status key-value has been collected. Store it.
- submitCurrentKeyValue();
- mInInstrumentationResultKey = true;
- parseKey(line, Prefixes.RESULT.length());
- } else if (line.startsWith(Prefixes.STATUS_FAILED) ||
- line.startsWith(Prefixes.CODE)) {
- // Previous status key-value has been collected. Store it.
- submitCurrentKeyValue();
- mInInstrumentationResultKey = false;
- // these codes signal the end of the instrumentation run
- mTestRunFinished = true;
- // just ignore the remaining data on this line
- } else if (line.startsWith(Prefixes.TIME_REPORT)) {
- parseTime(line);
- } else {
- if (mCurrentValue != null) {
- // this is a value that has wrapped to next line.
- mCurrentValue.append("\r\n");
- mCurrentValue.append(line);
- } else if (line.trim().length() > 0){
- Log.d(LOG_TAG, "unrecognized line " + line);
- }
- }
- }
-
- /**
- * Stores the currently parsed key-value pair in the appropriate place.
- */
- private void submitCurrentKeyValue() {
- if (mCurrentKey != null && mCurrentValue != null) {
- String statusValue = mCurrentValue.toString();
- if (mInInstrumentationResultKey) {
- if (!KNOWN_KEYS.contains(mCurrentKey)) {
- mInstrumentationResultBundle.put(mCurrentKey, statusValue);
- } else if (mCurrentKey.equals(StatusKeys.SHORTMSG)) {
- // test run must have failed
- handleTestRunFailed(String.format("Instrumentation run failed due to '%1$s'",
- statusValue));
- }
- } else {
- TestResult testInfo = getCurrentTestInfo();
-
- if (mCurrentKey.equals(StatusKeys.CLASS)) {
- testInfo.mTestClass = statusValue.trim();
- } else if (mCurrentKey.equals(StatusKeys.TEST)) {
- testInfo.mTestName = statusValue.trim();
- } else if (mCurrentKey.equals(StatusKeys.NUMTESTS)) {
- try {
- testInfo.mNumTests = Integer.parseInt(statusValue);
- } catch (NumberFormatException e) {
- Log.w(LOG_TAG, "Unexpected integer number of tests, received "
- + statusValue);
- }
- } else if (mCurrentKey.equals(StatusKeys.ERROR)) {
- // test run must have failed
- handleTestRunFailed(statusValue);
- } else if (mCurrentKey.equals(StatusKeys.STACK)) {
- testInfo.mStackTrace = statusValue;
- } else if (!KNOWN_KEYS.contains(mCurrentKey)) {
- // Not one of the recognized key/value pairs, so dump it in mTestMetrics
- mTestMetrics.put(mCurrentKey, statusValue);
- }
- }
-
- mCurrentKey = null;
- mCurrentValue = null;
- }
- }
-
- /**
- * A utility method to return the test metrics from the current test case execution and get
- * ready for the next one.
- */
- private Map<String, String> getAndResetTestMetrics() {
- Map<String, String> retVal = mTestMetrics;
- mTestMetrics = new HashMap<String, String>();
- return retVal;
- }
-
- private TestResult getCurrentTestInfo() {
- if (mCurrentTestResult == null) {
- mCurrentTestResult = new TestResult();
- }
- return mCurrentTestResult;
- }
-
- private void clearCurrentTestInfo() {
- mLastTestResult = mCurrentTestResult;
- mCurrentTestResult = null;
- }
-
- /**
- * Parses the key from the current line.
- * Expects format of "key=value".
- *
- * @param line full line of text to parse
- * @param keyStartPos the starting position of the key in the given line
- */
- private void parseKey(String line, int keyStartPos) {
- int endKeyPos = line.indexOf('=', keyStartPos);
- if (endKeyPos != -1) {
- mCurrentKey = line.substring(keyStartPos, endKeyPos).trim();
- parseValue(line, endKeyPos + 1);
- }
- }
-
- /**
- * Parses the start of a key=value pair.
- *
- * @param line - full line of text to parse
- * @param valueStartPos - the starting position of the value in the given line
- */
- private void parseValue(String line, int valueStartPos) {
- mCurrentValue = new StringBuilder();
- mCurrentValue.append(line.substring(valueStartPos));
- }
-
- /**
- * Parses out a status code result.
- */
- private void parseStatusCode(String line) {
- String value = line.substring(Prefixes.STATUS_CODE.length()).trim();
- TestResult testInfo = getCurrentTestInfo();
- testInfo.mCode = StatusCodes.ERROR;
- try {
- testInfo.mCode = Integer.parseInt(value);
- } catch (NumberFormatException e) {
- Log.w(LOG_TAG, "Expected integer status code, received: " + value);
- testInfo.mCode = StatusCodes.ERROR;
- }
- if (testInfo.mCode != StatusCodes.IN_PROGRESS) {
- // this means we're done with current test result bundle
- reportResult(testInfo);
- clearCurrentTestInfo();
- }
- }
-
- /**
- * Returns true if test run canceled.
- *
- * @see IShellOutputReceiver#isCancelled()
- */
- @Override
- public boolean isCancelled() {
- return mIsCancelled;
- }
-
- /**
- * Requests cancellation of test run.
- */
- public void cancel() {
- mIsCancelled = true;
- }
-
- /**
- * Reports a test result to the test run listener. Must be called when a individual test
- * result has been fully parsed.
- *
- * @param statusMap key-value status pairs of test result
- */
- private void reportResult(TestResult testInfo) {
- if (!testInfo.isComplete()) {
- Log.w(LOG_TAG, "invalid instrumentation status bundle " + testInfo.toString());
- return;
- }
- reportTestRunStarted(testInfo);
- TestIdentifier testId = new TestIdentifier(testInfo.mTestClass, testInfo.mTestName);
- Map<String, String> metrics;
-
- switch (testInfo.mCode) {
- case StatusCodes.START:
- for (ITestRunListener listener : mTestListeners) {
- listener.testStarted(testId);
- }
- break;
- case StatusCodes.FAILURE:
- metrics = getAndResetTestMetrics();
- for (ITestRunListener listener : mTestListeners) {
- listener.testFailed(ITestRunListener.TestFailure.FAILURE, testId,
- getTrace(testInfo));
-
- listener.testEnded(testId, metrics);
- }
- mNumTestsRun++;
- break;
- case StatusCodes.ERROR:
- metrics = getAndResetTestMetrics();
- for (ITestRunListener listener : mTestListeners) {
- listener.testFailed(ITestRunListener.TestFailure.ERROR, testId,
- getTrace(testInfo));
- listener.testEnded(testId, metrics);
- }
- mNumTestsRun++;
- break;
- case StatusCodes.OK:
- metrics = getAndResetTestMetrics();
- for (ITestRunListener listener : mTestListeners) {
- listener.testEnded(testId, metrics);
- }
- mNumTestsRun++;
- break;
- default:
- metrics = getAndResetTestMetrics();
- Log.e(LOG_TAG, "Unknown status code received: " + testInfo.mCode);
- for (ITestRunListener listener : mTestListeners) {
- listener.testEnded(testId, metrics);
- }
- mNumTestsRun++;
- break;
- }
-
- }
-
- /**
- * Reports the start of a test run, and the total test count, if it has not been previously
- * reported.
- *
- * @param testInfo current test status values
- */
- private void reportTestRunStarted(TestResult testInfo) {
- // if start test run not reported yet
- if (!mTestStartReported && testInfo.mNumTests != null) {
- for (ITestRunListener listener : mTestListeners) {
- listener.testRunStarted(mTestRunName, testInfo.mNumTests);
- }
- mNumTestsExpected = testInfo.mNumTests;
- mTestStartReported = true;
- }
- }
-
- /**
- * Returns the stack trace of the current failed test, from the provided testInfo.
- */
- private String getTrace(TestResult testInfo) {
- if (testInfo.mStackTrace != null) {
- return testInfo.mStackTrace;
- } else {
- Log.e(LOG_TAG, "Could not find stack trace for failed test ");
- return new Throwable("Unknown failure").toString();
- }
- }
-
- /**
- * Parses out and store the elapsed time.
- */
- private void parseTime(String line) {
- final Pattern timePattern = Pattern.compile(String.format("%s\\s*([\\d\\.]+)",
- Prefixes.TIME_REPORT));
- Matcher timeMatcher = timePattern.matcher(line);
- if (timeMatcher.find()) {
- String timeString = timeMatcher.group(1);
- try {
- float timeSeconds = Float.parseFloat(timeString);
- mTestTime = (long) (timeSeconds * 1000);
- } catch (NumberFormatException e) {
- Log.w(LOG_TAG, String.format("Unexpected time format %1$s", line));
- }
- } else {
- Log.w(LOG_TAG, String.format("Unexpected time format %1$s", line));
- }
- }
-
- /**
- * Inform the parser of a instrumentation run failure. Should be called when the adb command
- * used to run the test fails.
- */
- public void handleTestRunFailed(String errorMsg) {
- errorMsg = (errorMsg == null ? "Unknown error" : errorMsg);
- Log.i(LOG_TAG, String.format("test run failed: '%1$s'", errorMsg));
- if (mLastTestResult != null &&
- mLastTestResult.isComplete() &&
- StatusCodes.START == mLastTestResult.mCode) {
-
- // received test start msg, but not test complete
- // assume test caused this, report as test failure
- TestIdentifier testId = new TestIdentifier(mLastTestResult.mTestClass,
- mLastTestResult.mTestName);
- for (ITestRunListener listener : mTestListeners) {
- listener.testFailed(ITestRunListener.TestFailure.ERROR, testId,
- String.format("%1$s. Reason: '%2$s'. %3$s", INCOMPLETE_TEST_ERR_MSG_PREFIX,
- errorMsg, INCOMPLETE_TEST_ERR_MSG_POSTFIX));
- listener.testEnded(testId, getAndResetTestMetrics());
- }
- }
- for (ITestRunListener listener : mTestListeners) {
- if (!mTestStartReported) {
- // test run wasn't started - must have crashed before it started
- listener.testRunStarted(mTestRunName, 0);
- }
- listener.testRunFailed(errorMsg);
- listener.testRunEnded(mTestTime, mInstrumentationResultBundle);
- }
- mTestStartReported = true;
- mTestRunFailReported = true;
- }
-
- /**
- * Called by parent when adb session is complete.
- */
- @Override
- public void done() {
- super.done();
- if (!mTestRunFailReported) {
- handleOutputDone();
- }
- }
-
- /**
- * Handles the end of the adb session when a test run failure has not been reported yet
- */
- private void handleOutputDone() {
- if (!mTestStartReported && !mTestRunFinished) {
- // no results
- handleTestRunFailed(NO_TEST_RESULTS_MSG);
- } else if (mNumTestsExpected > mNumTestsRun) {
- final String message =
- String.format("%1$s. Expected %2$d tests, received %3$d",
- INCOMPLETE_RUN_ERR_MSG_PREFIX, mNumTestsExpected, mNumTestsRun);
- handleTestRunFailed(message);
- } else {
- for (ITestRunListener listener : mTestListeners) {
- if (!mTestStartReported) {
- // test run wasn't started, but it finished successfully. Must be a run with
- // no tests
- listener.testRunStarted(mTestRunName, 0);
- }
- listener.testRunEnded(mTestTime, mInstrumentationResultBundle);
- }
- }
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java
deleted file mode 100644
index 124df7d..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * 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.ddmlib.testrunner;
-
-
-import com.android.ddmlib.AdbCommandRejectedException;
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.ShellCommandUnresponsiveException;
-import com.android.ddmlib.TimeoutException;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Runs a Android test command remotely and reports results.
- */
-public class RemoteAndroidTestRunner implements IRemoteAndroidTestRunner {
-
- private final String mPackageName;
- private final String mRunnerName;
- private IDevice mRemoteDevice;
- // default to no timeout
- private int mMaxTimeToOutputResponse = 0;
- private String mRunName = null;
-
- /** map of name-value instrumentation argument pairs */
- private Map<String, String> mArgMap;
- private InstrumentationResultParser mParser;
-
- private static final String LOG_TAG = "RemoteAndroidTest";
- private static final String DEFAULT_RUNNER_NAME = "android.test.InstrumentationTestRunner";
-
- private static final char CLASS_SEPARATOR = ',';
- private static final char METHOD_SEPARATOR = '#';
- private static final char RUNNER_SEPARATOR = '/';
-
- // defined instrumentation argument names
- private static final String CLASS_ARG_NAME = "class";
- private static final String LOG_ARG_NAME = "log";
- private static final String DEBUG_ARG_NAME = "debug";
- private static final String COVERAGE_ARG_NAME = "coverage";
- private static final String PACKAGE_ARG_NAME = "package";
- private static final String SIZE_ARG_NAME = "size";
-
- /**
- * Creates a remote Android test runner.
- *
- * @param packageName the Android application package that contains the tests to run
- * @param runnerName the instrumentation test runner to execute. If null, will use default
- * runner
- * @param remoteDevice the Android device to execute tests on
- */
- public RemoteAndroidTestRunner(String packageName,
- String runnerName,
- IDevice remoteDevice) {
-
- mPackageName = packageName;
- mRunnerName = runnerName;
- mRemoteDevice = remoteDevice;
- mArgMap = new Hashtable<String, String>();
- }
-
- /**
- * Alternate constructor. Uses default instrumentation runner.
- *
- * @param packageName the Android application package that contains the tests to run
- * @param remoteDevice the Android device to execute tests on
- */
- public RemoteAndroidTestRunner(String packageName,
- IDevice remoteDevice) {
- this(packageName, null, remoteDevice);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getPackageName() {
- return mPackageName;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getRunnerName() {
- if (mRunnerName == null) {
- return DEFAULT_RUNNER_NAME;
- }
- return mRunnerName;
- }
-
- /**
- * Returns the complete instrumentation component path.
- */
- private String getRunnerPath() {
- return getPackageName() + RUNNER_SEPARATOR + getRunnerName();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setClassName(String className) {
- addInstrumentationArg(CLASS_ARG_NAME, className);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setClassNames(String[] classNames) {
- StringBuilder classArgBuilder = new StringBuilder();
-
- for (int i = 0; i < classNames.length; i++) {
- if (i != 0) {
- classArgBuilder.append(CLASS_SEPARATOR);
- }
- classArgBuilder.append(classNames[i]);
- }
- setClassName(classArgBuilder.toString());
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setMethodName(String className, String testName) {
- setClassName(className + METHOD_SEPARATOR + testName);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setTestPackageName(String packageName) {
- addInstrumentationArg(PACKAGE_ARG_NAME, packageName);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addInstrumentationArg(String name, String value) {
- if (name == null || value == null) {
- throw new IllegalArgumentException("name or value arguments cannot be null");
- }
- mArgMap.put(name, value);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeInstrumentationArg(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name argument cannot be null");
- }
- mArgMap.remove(name);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addBooleanArg(String name, boolean value) {
- addInstrumentationArg(name, Boolean.toString(value));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setLogOnly(boolean logOnly) {
- addBooleanArg(LOG_ARG_NAME, logOnly);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setDebug(boolean debug) {
- addBooleanArg(DEBUG_ARG_NAME, debug);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setCoverage(boolean coverage) {
- addBooleanArg(COVERAGE_ARG_NAME, coverage);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setTestSize(TestSize size) {
- addInstrumentationArg(SIZE_ARG_NAME, size.getRunnerValue());
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setMaxtimeToOutputResponse(int maxTimeToOutputResponse) {
- mMaxTimeToOutputResponse = maxTimeToOutputResponse;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setRunName(String runName) {
- mRunName = runName;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void run(ITestRunListener... listeners)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- run(Arrays.asList(listeners));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void run(Collection<ITestRunListener> listeners)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- final String runCaseCommandStr = String.format("am instrument -w -r %1$s %2$s",
- getArgsCommand(), getRunnerPath());
- Log.i(LOG_TAG, String.format("Running %1$s on %2$s", runCaseCommandStr,
- mRemoteDevice.getSerialNumber()));
- String runName = mRunName == null ? mPackageName : mRunName;
- mParser = new InstrumentationResultParser(runName, listeners);
-
- try {
- mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser, mMaxTimeToOutputResponse);
- } catch (IOException e) {
- Log.w(LOG_TAG, String.format("IOException %1$s when running tests %2$s on %3$s",
- e.toString(), getPackageName(), mRemoteDevice.getSerialNumber()));
- // rely on parser to communicate results to listeners
- mParser.handleTestRunFailed(e.toString());
- throw e;
- } catch (ShellCommandUnresponsiveException e) {
- Log.w(LOG_TAG, String.format(
- "ShellCommandUnresponsiveException %1$s when running tests %2$s on %3$s",
- e.toString(), getPackageName(), mRemoteDevice.getSerialNumber()));
- mParser.handleTestRunFailed(String.format(
- "Failed to receive adb shell test output within %1$d ms. " +
- "Test may have timed out, or adb connection to device became unresponsive",
- mMaxTimeToOutputResponse));
- throw e;
- } catch (TimeoutException e) {
- Log.w(LOG_TAG, String.format(
- "TimeoutException when running tests %1$s on %2$s", getPackageName(),
- mRemoteDevice.getSerialNumber()));
- mParser.handleTestRunFailed(e.toString());
- throw e;
- } catch (AdbCommandRejectedException e) {
- Log.w(LOG_TAG, String.format(
- "AdbCommandRejectedException %1$s when running tests %2$s on %3$s",
- e.toString(), getPackageName(), mRemoteDevice.getSerialNumber()));
- mParser.handleTestRunFailed(e.toString());
- throw e;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void cancel() {
- if (mParser != null) {
- mParser.cancel();
- }
- }
-
- /**
- * Returns the full instrumentation command line syntax for the provided instrumentation
- * arguments.
- * Returns an empty string if no arguments were specified.
- */
- private String getArgsCommand() {
- StringBuilder commandBuilder = new StringBuilder();
- for (Entry<String, String> argPair : mArgMap.entrySet()) {
- final String argCmd = String.format(" -e %1$s %2$s", argPair.getKey(),
- argPair.getValue());
- commandBuilder.append(argCmd);
- }
- return commandBuilder.toString();
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestIdentifier.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestIdentifier.java
deleted file mode 100644
index 7de5736..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestIdentifier.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.ddmlib.testrunner;
-
-/**
- * Identifies a parsed instrumentation test.
- */
-public class TestIdentifier {
-
- private final String mClassName;
- private final String mTestName;
-
- /**
- * Creates a test identifier.
- *
- * @param className fully qualified class name of the test. Cannot be null.
- * @param testName name of the test. Cannot be null.
- */
- public TestIdentifier(String className, String testName) {
- if (className == null || testName == null) {
- throw new IllegalArgumentException("className and testName must " +
- "be non-null");
- }
- mClassName = className;
- mTestName = testName;
- }
-
- /**
- * Returns the fully qualified class name of the test.
- */
- public String getClassName() {
- return mClassName;
- }
-
- /**
- * Returns the name of the test.
- */
- public String getTestName() {
- return mTestName;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mClassName == null) ? 0 : mClassName.hashCode());
- result = prime * result + ((mTestName == null) ? 0 : mTestName.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- TestIdentifier other = (TestIdentifier) obj;
- if (mClassName == null) {
- if (other.mClassName != null)
- return false;
- } else if (!mClassName.equals(other.mClassName))
- return false;
- if (mTestName == null) {
- if (other.mTestName != null)
- return false;
- } else if (!mTestName.equals(other.mTestName))
- return false;
- return true;
- }
-
- @Override
- public String toString() {
- return String.format("%s#%s", getClassName(), getTestName());
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestResult.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestResult.java
deleted file mode 100644
index 57e91f7..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestResult.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib.testrunner;
-
-import java.util.Arrays;
-import java.util.Map;
-
-/**
- * Container for a result of a single test.
- */
-public class TestResult {
-
- public enum TestStatus {
- /** Test error */
- ERROR,
- /** Test failed. */
- FAILURE,
- /** Test passed */
- PASSED,
- /** Test started but not ended */
- INCOMPLETE
- }
-
- private TestStatus mStatus;
- private String mStackTrace;
- private Map<String, String> mMetrics;
- // the start and end time of the test, measured via {@link System#currentTimeMillis()}
- private long mStartTime = 0;
- private long mEndTime = 0;
-
- public TestResult() {
- mStatus = TestStatus.INCOMPLETE;
- mStartTime = System.currentTimeMillis();
- }
-
- /**
- * Get the {@link TestStatus} result of the test.
- */
- public TestStatus getStatus() {
- return mStatus;
- }
-
- /**
- * Get the associated {@link String} stack trace. Should be <code>null</code> if
- * {@link #getStatus()} is {@link TestStatus.PASSED}.
- */
- public String getStackTrace() {
- return mStackTrace;
- }
-
- /**
- * Get the associated test metrics.
- */
- public Map<String, String> getMetrics() {
- return mMetrics;
- }
-
- /**
- * Set the test metrics, overriding any previous values.
- */
- public void setMetrics(Map<String, String> metrics) {
- mMetrics = metrics;
- }
-
- /**
- * Return the {@link System#currentTimeMillis()} time that the
- * {@link ITestInvocationListener#testStarted(TestIdentifier)} event was received.
- */
- public long getStartTime() {
- return mStartTime;
- }
-
- /**
- * Return the {@link System#currentTimeMillis()} time that the
- * {@link ITestInvocationListener#testEnded(TestIdentifier)} event was received.
- */
- public long getEndTime() {
- return mEndTime;
- }
-
- /**
- * Set the {@link TestStatus}.
- */
- public TestResult setStatus(TestStatus status) {
- mStatus = status;
- return this;
- }
-
- /**
- * Set the stack trace.
- */
- public void setStackTrace(String trace) {
- mStackTrace = trace;
- }
-
- /**
- * Sets the end time
- */
- public void setEndTime(long currentTimeMillis) {
- mEndTime = currentTimeMillis;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return Arrays.hashCode(new Object[] {mMetrics, mStackTrace, mStatus});
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- TestResult other = (TestResult) obj;
- return equal(mMetrics, other.mMetrics) &&
- equal(mStackTrace, other.mStackTrace) &&
- equal(mStatus, other.mStatus);
- }
-
- private static boolean equal(Object a, Object b) {
- return a == b || (a != null && a.equals(b));
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestRunResult.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestRunResult.java
deleted file mode 100644
index 14bb477..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/TestRunResult.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2010 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.ddmlib.testrunner;
-
-import com.android.ddmlib.Log;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Holds results from a single test run.
- * <p/>
- * Maintains an accurate count of tests during execution, and tracks incomplete tests.
- */
-public class TestRunResult {
- private static final String LOG_TAG = TestRunResult.class.getSimpleName();
- private final String mTestRunName;
- // Uses a synchronized map to make thread safe.
- // Uses a LinkedHashmap to have predictable iteration order
- private Map<TestIdentifier, TestResult> mTestResults =
- Collections.synchronizedMap(new LinkedHashMap<TestIdentifier, TestResult>());
- private Map<String, String> mRunMetrics = new HashMap<String, String>();
- private boolean mIsRunComplete = false;
- private long mElapsedTime = 0;
- private int mNumFailedTests = 0;
- private int mNumErrorTests = 0;
- private int mNumPassedTests = 0;
- private int mNumInCompleteTests = 0;
- private String mRunFailureError = null;
-
- /**
- * Create a {@link TestRunResult}.
- *
- * @param runName
- */
- public TestRunResult(String runName) {
- mTestRunName = runName;
- }
-
- /**
- * Create an empty{@link TestRunResult}.
- */
- public TestRunResult() {
- this("not started");
- }
-
- /**
- * @return the test run name
- */
- public String getName() {
- return mTestRunName;
- }
-
- /**
- * Gets a map of the test results.
- * @return
- */
- public Map<TestIdentifier, TestResult> getTestResults() {
- return mTestResults;
- }
-
- /**
- * Adds test run metrics.
- * <p/>
- * @param runMetrics the run metrics
- * @param aggregateMetrics if <code>true</code>, attempt to add given metrics values to any
- * currently stored values. If <code>false</code>, replace any currently stored metrics with
- * the same key.
- */
- public void addMetrics(Map<String, String> runMetrics, boolean aggregateMetrics) {
- if (aggregateMetrics) {
- for (Map.Entry<String, String> entry : runMetrics.entrySet()) {
- String existingValue = mRunMetrics.get(entry.getKey());
- String combinedValue = combineValues(existingValue, entry.getValue());
- mRunMetrics.put(entry.getKey(), combinedValue);
- }
- } else {
- mRunMetrics.putAll(runMetrics);
- }
- }
-
- /**
- * Combine old and new metrics value
- *
- * @param existingValue
- * @param value
- * @return
- */
- private String combineValues(String existingValue, String newValue) {
- if (existingValue != null) {
- try {
- Long existingLong = Long.parseLong(existingValue);
- Long newLong = Long.parseLong(newValue);
- return Long.toString(existingLong + newLong);
- } catch (NumberFormatException e) {
- // not a long, skip to next
- }
- try {
- Double existingDouble = Double.parseDouble(existingValue);
- Double newDouble = Double.parseDouble(newValue);
- return Double.toString(existingDouble + newDouble);
- } catch (NumberFormatException e) {
- // not a double either, fall through
- }
- }
- // default to overriding existingValue
- return newValue;
- }
-
- /**
- * @return a {@link Map} of the test test run metrics.
- */
- public Map<String, String> getRunMetrics() {
- return mRunMetrics;
- }
-
- /**
- * Gets the set of completed tests.
- */
- public Set<TestIdentifier> getCompletedTests() {
- Set<TestIdentifier> completedTests = new LinkedHashSet<TestIdentifier>();
- for (Map.Entry<TestIdentifier, TestResult> testEntry : getTestResults().entrySet()) {
- if (!testEntry.getValue().getStatus().equals(TestStatus.INCOMPLETE)) {
- completedTests.add(testEntry.getKey());
- }
- }
- return completedTests;
- }
-
- /**
- * @return <code>true</code> if test run failed.
- */
- public boolean isRunFailure() {
- return mRunFailureError != null;
- }
-
- /**
- * @return <code>true</code> if test run finished.
- */
- public boolean isRunComplete() {
- return mIsRunComplete;
- }
-
- void setRunComplete(boolean runComplete) {
- mIsRunComplete = runComplete;
- }
-
- void addElapsedTime(long elapsedTime) {
- mElapsedTime+= elapsedTime;
- }
-
- void setRunFailureError(String errorMessage) {
- mRunFailureError = errorMessage;
- }
-
- /**
- * Gets the number of passed tests for this run.
- */
- public int getNumPassedTests() {
- return mNumPassedTests;
- }
-
- /**
- * Gets the number of tests in this run.
- */
- public int getNumTests() {
- return mTestResults.size();
- }
-
- /**
- * Gets the number of complete tests in this run ie with status != incomplete.
- */
- public int getNumCompleteTests() {
- return getNumTests() - getNumIncompleteTests();
- }
-
- /**
- * Gets the number of failed tests in this run.
- */
- public int getNumFailedTests() {
- return mNumFailedTests;
- }
-
- /**
- * Gets the number of error tests in this run.
- */
- public int getNumErrorTests() {
- return mNumErrorTests;
- }
-
- /**
- * Gets the number of incomplete tests in this run.
- */
- public int getNumIncompleteTests() {
- return mNumInCompleteTests;
- }
-
- /**
- * @return <code>true</code> if test run had any failed or error tests.
- */
- public boolean hasFailedTests() {
- return getNumErrorTests() > 0 || getNumFailedTests() > 0;
- }
-
- /**
- * @return
- */
- public long getElapsedTime() {
- return mElapsedTime;
- }
-
- /**
- * Return the run failure error message, <code>null</code> if run did not fail.
- */
- public String getRunFailureMessage() {
- return mRunFailureError;
- }
-
- /**
- * Report the start of a test.
- * @param test
- */
- void reportTestStarted(TestIdentifier test) {
- TestResult result = mTestResults.get(test);
-
- if (result != null) {
- Log.d(LOG_TAG, String.format("Replacing result for %s", test));
- switch (result.getStatus()) {
- case ERROR:
- mNumErrorTests--;
- break;
- case FAILURE:
- mNumFailedTests--;
- break;
- case PASSED:
- mNumPassedTests--;
- break;
- case INCOMPLETE:
- // ignore
- break;
- }
- } else {
- mNumInCompleteTests++;
- }
- mTestResults.put(test, new TestResult());
- }
-
- /**
- * Report a test failure.
- *
- * @param test
- * @param status
- * @param trace
- */
- void reportTestFailure(TestIdentifier test, TestStatus status, String trace) {
- TestResult result = mTestResults.get(test);
- if (result == null) {
- Log.d(LOG_TAG, String.format("Received test failure for %s without testStarted", test));
- result = new TestResult();
- mTestResults.put(test, result);
- } else if (result.getStatus().equals(TestStatus.PASSED)) {
- // this should never happen...
- Log.d(LOG_TAG, String.format("Replacing passed result for %s", test));
- mNumPassedTests--;
- }
-
- result.setStackTrace(trace);
- switch (status) {
- case ERROR:
- mNumErrorTests++;
- result.setStatus(TestStatus.ERROR);
- break;
- case FAILURE:
- result.setStatus(TestStatus.FAILURE);
- mNumFailedTests++;
- break;
- }
- }
-
- /**
- * Report the end of the test
- *
- * @param test
- * @param testMetrics
- * @return <code>true</code> if test was recorded as passed, false otherwise
- */
- boolean reportTestEnded(TestIdentifier test, Map<String, String> testMetrics) {
- TestResult result = mTestResults.get(test);
- if (result == null) {
- Log.d(LOG_TAG, String.format("Received test ended for %s without testStarted", test));
- result = new TestResult();
- mTestResults.put(test, result);
- } else {
- mNumInCompleteTests--;
- }
-
- result.setEndTime(System.currentTimeMillis());
- result.setMetrics(testMetrics);
- if (result.getStatus().equals(TestStatus.INCOMPLETE)) {
- result.setStatus(TestStatus.PASSED);
- mNumPassedTests++;
- return true;
- }
- return false;
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/XmlTestRunListener.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/XmlTestRunListener.java
deleted file mode 100644
index 27ba476..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/testrunner/XmlTestRunListener.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2009 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.ddmlib.testrunner;
-
-import com.android.ddmlib.Log;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
-
-import org.kxml2.io.KXmlSerializer;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
-import java.util.TimeZone;
-
-/**
- * Writes JUnit results to an XML files in a format consistent with
- * Ant's XMLJUnitResultFormatter.
- * <p/>
- * Creates a separate XML file per test run.
- * <p/>
- */
-public class XmlTestRunListener implements ITestRunListener {
-
- private static final String LOG_TAG = "XmlResultReporter";
-
- private static final String TEST_RESULT_FILE_SUFFIX = ".xml";
- private static final String TEST_RESULT_FILE_PREFIX = "test_result_";
-
- private static final String TESTSUITE = "testsuite";
- private static final String TESTCASE = "testcase";
- private static final String ERROR = "error";
- private static final String FAILURE = "failure";
- private static final String ATTR_NAME = "name";
- private static final String ATTR_TIME = "time";
- private static final String ATTR_ERRORS = "errors";
- private static final String ATTR_FAILURES = "failures";
- private static final String ATTR_TESTS = "tests";
- //private static final String ATTR_TYPE = "type";
- //private static final String ATTR_MESSAGE = "message";
- private static final String PROPERTIES = "properties";
- private static final String ATTR_CLASSNAME = "classname";
- private static final String TIMESTAMP = "timestamp";
- private static final String HOSTNAME = "hostname";
-
- /** the XML namespace */
- private static final String ns = null;
-
- private File mReportDir = new File(System.getProperty("java.io.tmpdir"));
-
- private String mReportPath = "";
-
- private TestRunResult mRunResult = new TestRunResult();
-
- /**
- * Sets the report file to use.
- */
- public void setReportDir(File file) {
- mReportDir = file;
- }
-
- @Override
- public void testRunStarted(String runName, int numTests) {
- mRunResult = new TestRunResult(runName);
- }
-
- @Override
- public void testStarted(TestIdentifier test) {
- mRunResult.reportTestStarted(test);
- }
-
- @Override
- public void testFailed(TestFailure status, TestIdentifier test, String trace) {
- if (status.equals(TestFailure.ERROR)) {
- mRunResult.reportTestFailure(test, TestStatus.ERROR, trace);
- } else {
- mRunResult.reportTestFailure(test, TestStatus.FAILURE, trace);
- }
- Log.d(LOG_TAG, String.format("%s %s: %s", test, status, trace));
- }
-
- @Override
- public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
- mRunResult.reportTestEnded(test, testMetrics);
- }
-
- @Override
- public void testRunFailed(String errorMessage) {
- mRunResult.setRunFailureError(errorMessage);
- }
-
- @Override
- public void testRunStopped(long arg0) {
- // ignore
- }
-
- @Override
- public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {
- mRunResult.setRunComplete(true);
- generateDocument(mReportDir, elapsedTime);
- }
-
- /**
- * Creates a report file and populates it with the report data from the completed tests.
- */
- private void generateDocument(File reportDir, long elapsedTime) {
- String timestamp = getTimestamp();
-
- OutputStream stream = null;
- try {
- stream = createOutputResultStream(reportDir);
- KXmlSerializer serializer = new KXmlSerializer();
- serializer.setOutput(stream, "UTF-8");
- serializer.startDocument("UTF-8", null);
- serializer.setFeature(
- "http://xmlpull.org/v1/doc/features.html#indent-output", true);
- // TODO: insert build info
- printTestResults(serializer, timestamp, elapsedTime);
- serializer.endDocument();
- String msg = String.format("XML test result file generated at %s. Total tests %d, " +
- "Failed %d, Error %d", getAbsoluteReportPath(), mRunResult.getNumTests(),
- mRunResult.getNumFailedTests(), mRunResult.getNumErrorTests());
- Log.logAndDisplay(LogLevel.INFO, LOG_TAG, msg);
- } catch (IOException e) {
- Log.e(LOG_TAG, "Failed to generate report data");
- // TODO: consider throwing exception
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException ignored) {
- }
- }
- }
- }
-
- private String getAbsoluteReportPath() {
- return mReportPath ;
- }
-
- /**
- * Return the current timestamp as a {@link String}.
- */
- String getTimestamp() {
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
- TimeZone gmt = TimeZone.getTimeZone("UTC");
- dateFormat.setTimeZone(gmt);
- dateFormat.setLenient(true);
- String timestamp = dateFormat.format(new Date());
- return timestamp;
- }
-
- /**
- * Creates the output stream to use for test results. Exposed for mocking.
- */
- OutputStream createOutputResultStream(File reportDir) throws IOException {
- File reportFile = File.createTempFile(TEST_RESULT_FILE_PREFIX, TEST_RESULT_FILE_SUFFIX,
- reportDir);
- Log.i(LOG_TAG, String.format("Created xml report file at %s",
- reportFile.getAbsolutePath()));
- mReportPath = reportFile.getAbsolutePath();
- return new BufferedOutputStream(new FileOutputStream(reportFile));
- }
-
- void printTestResults(KXmlSerializer serializer, String timestamp, long elapsedTime)
- throws IOException {
- serializer.startTag(ns, TESTSUITE);
- serializer.attribute(ns, ATTR_NAME, mRunResult.getName());
- serializer.attribute(ns, ATTR_TESTS, Integer.toString(mRunResult.getNumTests()));
- serializer.attribute(ns, ATTR_FAILURES, Integer.toString(mRunResult.getNumFailedTests()));
- serializer.attribute(ns, ATTR_ERRORS, Integer.toString(mRunResult.getNumErrorTests()));
- serializer.attribute(ns, ATTR_TIME, Long.toString(elapsedTime));
- serializer.attribute(ns, TIMESTAMP, timestamp);
- serializer.attribute(ns, HOSTNAME, "localhost");
- serializer.startTag(ns, PROPERTIES);
- serializer.endTag(ns, PROPERTIES);
-
- Map<TestIdentifier, TestResult> testResults = mRunResult.getTestResults();
- for (Map.Entry<TestIdentifier, TestResult> testEntry : testResults.entrySet()) {
- print(serializer, testEntry.getKey(), testEntry.getValue());
- }
-
- serializer.endTag(ns, TESTSUITE);
- }
-
- void print(KXmlSerializer serializer, TestIdentifier testId, TestResult testResult)
- throws IOException {
-
- serializer.startTag(ns, TESTCASE);
- serializer.attribute(ns, ATTR_NAME, testId.getTestName());
- serializer.attribute(ns, ATTR_CLASSNAME, testId.getClassName());
- long elapsedTimeMs = testResult.getEndTime() - testResult.getStartTime();
- serializer.attribute(ns, ATTR_TIME, Long.toString(elapsedTimeMs));
-
- if (!TestStatus.PASSED.equals(testResult.getStatus())) {
- String result = testResult.getStatus().equals(TestStatus.FAILURE) ? FAILURE : ERROR;
- serializer.startTag(ns, result);
- // TODO: get message of stack trace ?
-// String msg = testResult.getStackTrace();
-// if (msg != null && msg.length() > 0) {
-// serializer.attribute(ns, ATTR_MESSAGE, msg);
-// }
- // TODO: get class name of stackTrace exception
- //serializer.attribute(ns, ATTR_TYPE, testId.getClassName());
- String stackText = sanitize(testResult.getStackTrace());
- serializer.text(stackText);
- serializer.endTag(ns, result);
- }
-
- serializer.endTag(ns, TESTCASE);
- }
-
- /**
- * Returns the text in a format that is safe for use in an XML document.
- */
- private String sanitize(String text) {
- return text.replace("\0", "<\\0>");
- }
-}
diff --git a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/utils/ArrayHelper.java b/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/utils/ArrayHelper.java
deleted file mode 100644
index 8167e5d..0000000
--- a/ddms/libs/ddmlib/src/main/java/com/android/ddmlib/utils/ArrayHelper.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddmlib.utils;
-
-/**
- * Utility class providing array to int/long conversion for data received from devices through adb.
- */
-public final class ArrayHelper {
-
- /**
- * Swaps an unsigned value around, and puts the result in an array that can be sent to a device.
- * @param value The value to swap.
- * @param dest the destination array
- * @param offset the offset in the array where to put the swapped value.
- * Array length must be at least offset + 4
- */
- public static void swap32bitsToArray(int value, byte[] dest, int offset) {
- dest[offset] = (byte)(value & 0x000000FF);
- dest[offset + 1] = (byte)((value & 0x0000FF00) >> 8);
- dest[offset + 2] = (byte)((value & 0x00FF0000) >> 16);
- dest[offset + 3] = (byte)((value & 0xFF000000) >> 24);
- }
-
- /**
- * Reads a signed 32 bit integer from an array coming from a device.
- * @param value the array containing the int
- * @param offset the offset in the array at which the int starts
- * @return the integer read from the array
- */
- public static int swap32bitFromArray(byte[] value, int offset) {
- int v = 0;
- v |= ((int)value[offset]) & 0x000000FF;
- v |= (((int)value[offset + 1]) & 0x000000FF) << 8;
- v |= (((int)value[offset + 2]) & 0x000000FF) << 16;
- v |= (((int)value[offset + 3]) & 0x000000FF) << 24;
-
- return v;
- }
-
- /**
- * Reads an unsigned 16 bit integer from an array coming from a device,
- * and returns it as an 'int'
- * @param value the array containing the 16 bit int (2 byte).
- * @param offset the offset in the array at which the int starts
- * Array length must be at least offset + 2
- * @return the integer read from the array.
- */
- public static int swapU16bitFromArray(byte[] value, int offset) {
- int v = 0;
- v |= ((int)value[offset]) & 0x000000FF;
- v |= (((int)value[offset + 1]) & 0x000000FF) << 8;
-
- return v;
- }
-
- /**
- * Reads a signed 64 bit integer from an array coming from a device.
- * @param value the array containing the int
- * @param offset the offset in the array at which the int starts
- * Array length must be at least offset + 8
- * @return the integer read from the array
- */
- public static long swap64bitFromArray(byte[] value, int offset) {
- long v = 0;
- v |= ((long)value[offset]) & 0x00000000000000FFL;
- v |= (((long)value[offset + 1]) & 0x00000000000000FFL) << 8;
- v |= (((long)value[offset + 2]) & 0x00000000000000FFL) << 16;
- v |= (((long)value[offset + 3]) & 0x00000000000000FFL) << 24;
- v |= (((long)value[offset + 4]) & 0x00000000000000FFL) << 32;
- v |= (((long)value[offset + 5]) & 0x00000000000000FFL) << 40;
- v |= (((long)value[offset + 6]) & 0x00000000000000FFL) << 48;
- v |= (((long)value[offset + 7]) & 0x00000000000000FFL) << 56;
-
- return v;
- }
-}
diff --git a/ddms/libs/ddmlib/src/test/.classpath b/ddms/libs/ddmlib/src/test/.classpath
deleted file mode 100644
index 3fcac6c..0000000
--- a/ddms/libs/ddmlib/src/test/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
- <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/easymock.jar"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/ddms/libs/ddmlib/src/test/.project b/ddms/libs/ddmlib/src/test/.project
deleted file mode 100644
index 81a7f69..0000000
--- a/ddms/libs/ddmlib/src/test/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>ddmlib-tests</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
diff --git a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/EmulatorConsoleTest.java b/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/EmulatorConsoleTest.java
deleted file mode 100644
index 1697acd..0000000
--- a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/EmulatorConsoleTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.ddmlib;
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for {@link EmulatorConsole}.
- */
-public class EmulatorConsoleTest extends TestCase {
-
- /**
- * Test success case for {@link EmulatorConsole#getEmulatorPort(String)}.
- */
- public void testGetEmulatorPort() {
- assertEquals(Integer.valueOf(5554), EmulatorConsole.getEmulatorPort("emulator-5554"));
- }
-
- /**
- * Test {@link EmulatorConsole#getEmulatorPort(String)} when input serial has invalid format.
- */
- public void testGetEmulatorPort_invalid() {
- assertNull(EmulatorConsole.getEmulatorPort("invalidserial"));
- }
-
- /**
- * Test {@link EmulatorConsole#getEmulatorPort(String)} when port is not a number.
- */
- public void testGetEmulatorPort_nan() {
- assertNull(EmulatorConsole.getEmulatorPort("emulator-NaN"));
- }
-}
diff --git a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java b/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java
deleted file mode 100644
index 478e09e..0000000
--- a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * 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.ddmlib.testrunner;
-
-import com.android.ddmlib.testrunner.ITestRunListener.TestFailure;
-
-import junit.framework.TestCase;
-
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Unit tests for {@link @InstrumentationResultParser}.
- */
-@SuppressWarnings("unchecked")
-public class InstrumentationResultParserTest extends TestCase {
-
- private InstrumentationResultParser mParser;
- private ITestRunListener mMockListener;
-
- // static dummy test names to use for validation
- private static final String RUN_NAME = "foo";
- private static final String CLASS_NAME = "com.test.FooTest";
- private static final String TEST_NAME = "testFoo";
- private static final String STACK_TRACE = "java.lang.AssertionFailedException";
- private static final TestIdentifier TEST_ID = new TestIdentifier(CLASS_NAME, TEST_NAME);
-
- /**
- * @param name - test name
- */
- public InstrumentationResultParserTest(String name) {
- super(name);
- }
-
- /**
- * @see junit.framework.TestCase#setUp()
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- // use a strict mock to verify order of method calls
- mMockListener = EasyMock.createStrictMock(ITestRunListener.class);
- mParser = new InstrumentationResultParser(RUN_NAME, mMockListener);
- }
-
- /**
- * Tests parsing empty output.
- */
- public void testParse_empty() {
- mMockListener.testRunStarted(RUN_NAME, 0);
- mMockListener.testRunFailed(InstrumentationResultParser.NO_TEST_RESULTS_MSG);
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString("");
- }
-
- /**
- * Tests parsing output for a successful test run with no tests.
- */
- public void testParse_noTests() {
- StringBuilder output = new StringBuilder();
- addLine(output, "INSTRUMENTATION_RESULT: stream=");
- addLine(output, "Test results for InstrumentationTestRunner=");
- addLine(output, "Time: 0.001");
- addLine(output, "OK (0 tests)");
- addLine(output, "INSTRUMENTATION_CODE: -1");
-
- mMockListener.testRunStarted(RUN_NAME, 0);
- mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Tests parsing output for a single successful test execution.
- */
- public void testParse_singleTest() {
- StringBuilder output = createSuccessTest();
-
- mMockListener.testRunStarted(RUN_NAME, 1);
- mMockListener.testStarted(TEST_ID);
- mMockListener.testEnded(TEST_ID, Collections.EMPTY_MAP);
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Tests parsing output for a successful test execution with metrics.
- */
- public void testParse_testMetrics() {
- StringBuilder output = buildCommonResult();
-
- addStatusKey(output, "randomKey", "randomValue");
- addSuccessCode(output);
-
- final Capture<Map<String, String>> captureMetrics = new Capture<Map<String, String>>();
- mMockListener.testRunStarted(RUN_NAME, 1);
- mMockListener.testStarted(TEST_ID);
- mMockListener.testEnded(EasyMock.eq(TEST_ID), EasyMock.capture(captureMetrics));
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
-
- assertEquals("randomValue", captureMetrics.getValue().get("randomKey"));
- }
-
- /**
- * Test parsing output for a test that produces repeated metrics values
- * <p/>
- * This mimics launch performance test output.
- */
- public void testParse_repeatedTestMetrics() {
- StringBuilder output = new StringBuilder();
- // add test start output
- addCommonStatus(output);
- addStartCode(output);
-
- addStatusKey(output, "currentiterations", "1");
- addStatusCode(output, "2");
- addStatusKey(output, "currentiterations", "2");
- addStatusCode(output, "2");
- addStatusKey(output, "currentiterations", "3");
- addStatusCode(output, "2");
-
- // add test end
- addCommonStatus(output);
- addStatusKey(output, "numiterations", "3");
- addSuccessCode(output);
-
- final Capture<Map<String, String>> captureMetrics = new Capture<Map<String, String>>();
- mMockListener.testRunStarted(RUN_NAME, 1);
- mMockListener.testStarted(TEST_ID);
- mMockListener.testEnded(EasyMock.eq(TEST_ID), EasyMock.capture(captureMetrics));
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
-
- assertEquals("3", captureMetrics.getValue().get("currentiterations"));
- assertEquals("3", captureMetrics.getValue().get("numiterations"));
- }
-
- /**
- * Test parsing output for a test failure.
- */
- public void testParse_testFailed() {
- StringBuilder output = buildCommonResult();
- addStackTrace(output);
- addFailureCode(output);
-
- mMockListener.testRunStarted(RUN_NAME, 1);
- mMockListener.testStarted(TEST_ID);
- mMockListener.testFailed(TestFailure.FAILURE, TEST_ID, STACK_TRACE);
- mMockListener.testEnded(TEST_ID, Collections.EMPTY_MAP);
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Test parsing and conversion of time output that contains extra chars.
- */
- public void testParse_timeBracket() {
- StringBuilder output = createSuccessTest();
- output.append("Time: 0.001)");
-
- mMockListener.testRunStarted(RUN_NAME, 1);
- mMockListener.testStarted(TEST_ID);
- mMockListener.testEnded(TEST_ID, Collections.EMPTY_MAP);
- mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Test parsing output for a test run failure.
- */
- public void testParse_runFailed() {
- StringBuilder output = new StringBuilder();
- final String errorMessage = "Unable to find instrumentation info";
- addStatusKey(output, "Error", errorMessage);
- addStatusCode(output, "-1");
- output.append("INSTRUMENTATION_FAILED: com.dummy/android.test.InstrumentationTestRunner");
- addLineBreak(output);
-
- mMockListener.testRunStarted(RUN_NAME, 0);
- mMockListener.testRunFailed(errorMessage);
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Test parsing output when a status code cannot be parsed
- */
- public void testParse_invalidCode() {
- StringBuilder output = new StringBuilder();
- addLine(output, "android.util.AndroidException: INSTRUMENTATION_FAILED: foo/foo");
- addLine(output, "INSTRUMENTATION_STATUS: id=ActivityManagerService");
- addLine(output, "INSTRUMENTATION_STATUS: Error=Unable to find instrumentation target package: foo");
- addLine(output, "INSTRUMENTATION_STATUS_CODE: -1at com.android.commands.am.Am.runInstrument(Am.java:532)");
- addLine(output, "");
- addLine(output, " at com.android.commands.am.Am.run(Am.java:111)");
- addLineBreak(output);
-
- mMockListener.testRunStarted(RUN_NAME, 0);
- mMockListener.testRunFailed((String)EasyMock.anyObject());
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Test parsing output for a test run failure, where an instrumentation component failed to
- * load.
- * <p/>
- * Parsing input takes the from of INSTRUMENTATION_RESULT: fff
- */
- public void testParse_failedResult() {
- StringBuilder output = new StringBuilder();
- final String errorMessage = "Unable to instantiate instrumentation";
- output.append("INSTRUMENTATION_RESULT: shortMsg=");
- output.append(errorMessage);
- addLineBreak(output);
- output.append("INSTRUMENTATION_CODE: 0");
- addLineBreak(output);
-
- mMockListener.testRunStarted(RUN_NAME, 0);
- mMockListener.testRunFailed(EasyMock.contains(errorMessage));
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Test parsing output for a test run that did not complete.
- * <p/>
- * This can occur if device spontaneously reboots, or if test method could not be found.
- */
- public void testParse_incomplete() {
- StringBuilder output = new StringBuilder();
- // add a start test sequence, but without an end test sequence
- addCommonStatus(output);
- addStartCode(output);
-
- mMockListener.testRunStarted(RUN_NAME, 1);
- mMockListener.testStarted(TEST_ID);
- mMockListener.testFailed(EasyMock.eq(TestFailure.ERROR), EasyMock.eq(TEST_ID),
- EasyMock.startsWith(InstrumentationResultParser.INCOMPLETE_TEST_ERR_MSG_PREFIX));
- mMockListener.testEnded(TEST_ID, Collections.EMPTY_MAP);
- mMockListener.testRunFailed(EasyMock.startsWith(
- InstrumentationResultParser.INCOMPLETE_RUN_ERR_MSG_PREFIX));
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Test parsing output for a test run that did not start due to incorrect syntax supplied to am.
- */
- public void testParse_amFailed() {
- StringBuilder output = new StringBuilder();
- addLine(output, "usage: am [subcommand] [options]");
- addLine(output, "start an Activity: am start [-D] [-W] <INTENT>");
- addLine(output, "-D: enable debugging");
- addLine(output, "-W: wait for launch to complete");
- addLine(output, "start a Service: am startservice <INTENT>");
- addLine(output, "Error: Bad component name: wfsdafddfasasdf");
-
- mMockListener.testRunStarted(RUN_NAME, 0);
- mMockListener.testRunFailed(InstrumentationResultParser.NO_TEST_RESULTS_MSG);
- mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
-
- injectAndVerifyTestString(output.toString());
- }
-
- /**
- * Test parsing output for a test run that produces INSTRUMENTATION_RESULT output.
- * <p/>
- * This mimics launch performance test output.
- */
- public void testParse_instrumentationResults() {
- StringBuilder output = new StringBuilder();
- addResultKey(output, "other_pss", "2390");
- addResultKey(output, "java_allocated", "2539");
- addResultKey(output, "foo", "bar");
- addResultKey(output, "stream", "should not be captured");
- addLine(output, "INSTRUMENTATION_CODE: -1");
-
- Capture<Map<String, String>> captureMetrics = new Capture<Map<String, String>>();
- mMockListener.testRunStarted(RUN_NAME, 0);
- mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.capture(captureMetrics));
-
- injectAndVerifyTestString(output.toString());
-
- assertEquals("2390", captureMetrics.getValue().get("other_pss"));
- assertEquals("2539", captureMetrics.getValue().get("java_allocated"));
- assertEquals("bar", captureMetrics.getValue().get("foo"));
- assertEquals(3, captureMetrics.getValue().size());
- }
-
- /**
- * Builds a common test result using TEST_NAME and TEST_CLASS.
- */
- private StringBuilder buildCommonResult() {
- StringBuilder output = new StringBuilder();
- // add test start bundle
- addCommonStatus(output);
- addStartCode(output);
- // add end test bundle, without status
- addCommonStatus(output);
- return output;
- }
-
- /**
- * Create instrumentation output for a successful single test case execution.
- */
- private StringBuilder createSuccessTest() {
- StringBuilder output = buildCommonResult();
- addSuccessCode(output);
- return output;
- }
-
- /**
- * Adds common status results to the provided output.
- */
- private void addCommonStatus(StringBuilder output) {
- addStatusKey(output, "stream", "\r\n" + CLASS_NAME);
- addStatusKey(output, "test", TEST_NAME);
- addStatusKey(output, "class", CLASS_NAME);
- addStatusKey(output, "current", "1");
- addStatusKey(output, "numtests", "1");
- addStatusKey(output, "id", "InstrumentationTestRunner");
- }
-
- /**
- * Adds a stack trace status bundle to output.
- */
- private void addStackTrace(StringBuilder output) {
- addStatusKey(output, "stack", STACK_TRACE);
- }
-
- /**
- * Helper method to add a status key-value bundle.
- */
- private void addStatusKey(StringBuilder outputBuilder, String key,
- String value) {
- outputBuilder.append("INSTRUMENTATION_STATUS: ");
- outputBuilder.append(key);
- outputBuilder.append('=');
- outputBuilder.append(value);
- addLineBreak(outputBuilder);
- }
-
- /**
- * Helper method to add a result key value bundle.
- */
- private void addResultKey(StringBuilder outputBuilder, String key,
- String value) {
- outputBuilder.append("INSTRUMENTATION_RESULT: ");
- outputBuilder.append(key);
- outputBuilder.append('=');
- outputBuilder.append(value);
- addLineBreak(outputBuilder);
- }
-
- /**
- * Append a line to output.
- */
- private void addLine(StringBuilder outputBuilder, String lineContent) {
- outputBuilder.append(lineContent);
- addLineBreak(outputBuilder);
- }
-
- /**
- * Append line break characters to output
- */
- private void addLineBreak(StringBuilder outputBuilder) {
- outputBuilder.append("\r\n");
- }
-
- private void addStartCode(StringBuilder outputBuilder) {
- addStatusCode(outputBuilder, "1");
- }
-
- private void addSuccessCode(StringBuilder outputBuilder) {
- addStatusCode(outputBuilder, "0");
- }
-
- private void addFailureCode(StringBuilder outputBuilder) {
- addStatusCode(outputBuilder, "-2");
- }
-
- private void addStatusCode(StringBuilder outputBuilder, String value) {
- outputBuilder.append("INSTRUMENTATION_STATUS_CODE: ");
- outputBuilder.append(value);
- addLineBreak(outputBuilder);
- }
-
- /**
- * Inject a test string into the result parser, and verify the mock listener.
- *
- * @param result the string to inject into parser under test.
- */
- private void injectAndVerifyTestString(String result) {
- EasyMock.replay(mMockListener);
- byte[] data = result.getBytes();
- mParser.addOutput(data, 0, data.length);
- mParser.flush();
- EasyMock.verify(mMockListener);
- }
-}
diff --git a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java b/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java
deleted file mode 100644
index 8bde492..0000000
--- a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.ddmlib.testrunner;
-
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IShellOutputReceiver;
-
-import org.easymock.EasyMock;
-
-import java.io.IOException;
-import java.util.Collections;
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for {@link RemoteAndroidTestRunner}.
- */
-public class RemoteAndroidTestRunnerTest extends TestCase {
-
- private RemoteAndroidTestRunner mRunner;
- private IDevice mMockDevice;
- private ITestRunListener mMockListener;
-
- private static final String TEST_PACKAGE = "com.test";
- private static final String TEST_RUNNER = "com.test.InstrumentationTestRunner";
-
- /**
- * @see junit.framework.TestCase#setUp()
- */
- @Override
- protected void setUp() throws Exception {
- mMockDevice = EasyMock.createMock(IDevice.class);
- EasyMock.expect(mMockDevice.getSerialNumber()).andStubReturn("serial");
- mMockListener = EasyMock.createNiceMock(ITestRunListener.class);
- mRunner = new RemoteAndroidTestRunner(TEST_PACKAGE, TEST_RUNNER, mMockDevice);
- }
-
- /**
- * Test the basic case building of the instrumentation runner command with no arguments.
- */
- public void testRun() throws Exception {
- String expectedCmd = EasyMock.eq(String.format("am instrument -w -r %s/%s", TEST_PACKAGE,
- TEST_RUNNER));
- runAndVerify(expectedCmd);
- }
-
- /**
- * Test the building of the instrumentation runner command with log set.
- */
- public void testRun_withLog() throws Exception {
- mRunner.setLogOnly(true);
- String expectedCmd = EasyMock.contains("-e log true");
- runAndVerify(expectedCmd);
- }
-
- /**
- * Test the building of the instrumentation runner command with method set.
- */
- public void testRun_withMethod() throws Exception {
- final String className = "FooTest";
- final String testName = "fooTest";
- mRunner.setMethodName(className, testName);
- String expectedCmd = EasyMock.contains(String.format("-e class %s#%s", className,
- testName));
- runAndVerify(expectedCmd);
- }
-
- /**
- * Test the building of the instrumentation runner command with test package set.
- */
- public void testRun_withPackage() throws Exception {
- final String packageName = "foo.test";
- mRunner.setTestPackageName(packageName);
- String expectedCmd = EasyMock.contains(String.format("-e package %s", packageName));
- runAndVerify(expectedCmd);
- }
-
- /**
- * Test the building of the instrumentation runner command with extra argument added.
- */
- public void testRun_withAddInstrumentationArg() throws Exception {
- final String extraArgName = "blah";
- final String extraArgValue = "blahValue";
- mRunner.addInstrumentationArg(extraArgName, extraArgValue);
- String expectedCmd = EasyMock.contains(String.format("-e %s %s", extraArgName,
- extraArgValue));
- runAndVerify(expectedCmd);
- }
-
- /**
- * Test run when the device throws a IOException
- */
- @SuppressWarnings("unchecked")
- public void testRun_ioException() throws Exception {
- mMockDevice.executeShellCommand((String)EasyMock.anyObject(), (IShellOutputReceiver)
- EasyMock.anyObject(), EasyMock.eq(0));
- EasyMock.expectLastCall().andThrow(new IOException());
- // verify that the listeners run started, run failure, and run ended methods are called
- mMockListener.testRunStarted(TEST_PACKAGE, 0);
- mMockListener.testRunFailed((String)EasyMock.anyObject());
- mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
-
- EasyMock.replay(mMockDevice, mMockListener);
- try {
- mRunner.run(mMockListener);
- fail("IOException not thrown");
- } catch (IOException e) {
- // expected
- }
- EasyMock.verify(mMockDevice, mMockListener);
- }
-
- /**
- * Calls {@link RemoteAndroidTestRunner#run(ITestRunListener...)} and verifies the given
- * <var>expectedCmd</var> pattern was received by the mock device.
- */
- private void runAndVerify(String expectedCmd) throws Exception {
- mMockDevice.executeShellCommand(expectedCmd, (IShellOutputReceiver)
- EasyMock.anyObject(), EasyMock.eq(0));
- EasyMock.replay(mMockDevice);
- mRunner.run(mMockListener);
- EasyMock.verify(mMockDevice);
- }
-}
diff --git a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/XmlTestRunListenerTest.java b/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/XmlTestRunListenerTest.java
deleted file mode 100644
index f5672fa..0000000
--- a/ddms/libs/ddmlib/src/test/java/com/android/ddmlib/testrunner/XmlTestRunListenerTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2012 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.ddmlib.testrunner;
-
-import com.android.ddmlib.testrunner.ITestRunListener.TestFailure;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Unit tests for {@link XmlTestRunListener}.
- */
-public class XmlTestRunListenerTest extends TestCase {
-
- private XmlTestRunListener mResultReporter;
- private ByteArrayOutputStream mOutputStream;
- private File mReportDir;
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mOutputStream = new ByteArrayOutputStream();
- mResultReporter = new XmlTestRunListener() {
- @Override
- OutputStream createOutputResultStream(File reportDir) throws IOException {
- return mOutputStream;
- }
-
- @Override
- String getTimestamp() {
- return "ignore";
- }
- };
- // TODO: use mock file dir instead
- mReportDir = createTmpDir();
- mResultReporter.setReportDir(mReportDir);
- }
-
- private File createTmpDir() throws IOException {
- // create a temp file with unique name, then make it a directory
- File tmpDir = File.createTempFile("foo", "dir");
- tmpDir.delete();
- if (!tmpDir.mkdirs()) {
- throw new IOException("unable to create directory");
- }
- return tmpDir;
- }
-
- /**
- * Recursively delete given file and all its contents
- */
- private static void recursiveDelete(File rootDir) {
- if (rootDir.isDirectory()) {
- File[] childFiles = rootDir.listFiles();
- if (childFiles != null) {
- for (File child : childFiles) {
- recursiveDelete(child);
- }
- }
- }
- rootDir.delete();
- }
-
- @Override
- protected void tearDown() throws Exception {
- if (mReportDir != null) {
- recursiveDelete(mReportDir);
- }
- super.tearDown();
- }
-
- /**
- * A simple test to ensure expected output is generated for test run with no tests.
- */
- public void testEmptyGeneration() {
- final String expectedOutput = "<?xml version='1.0' encoding='UTF-8' ?>" +
- "<testsuite name=\"test\" tests=\"0\" failures=\"0\" errors=\"0\" time=\"1\" " +
- "timestamp=\"ignore\" hostname=\"localhost\"> " +
- "<properties />" +
- "</testsuite>";
- mResultReporter.testRunStarted("test", 1);
- mResultReporter.testRunEnded(1, Collections.<String, String> emptyMap());
- assertEquals(expectedOutput, getOutput());
- }
-
- /**
- * A simple test to ensure expected output is generated for test run with a single passed test.
- */
- public void testSinglePass() {
- Map<String, String> emptyMap = Collections.emptyMap();
- final TestIdentifier testId = new TestIdentifier("FooTest", "testFoo");
- mResultReporter.testRunStarted("run", 1);
- mResultReporter.testStarted(testId);
- mResultReporter.testEnded(testId, emptyMap);
- mResultReporter.testRunEnded(3, emptyMap);
- String output = getOutput();
- // TODO: consider doing xml based compare
- assertTrue(output.contains("tests=\"1\" failures=\"0\" errors=\"0\""));
- final String testCaseTag = String.format("<testcase name=\"%s\" classname=\"%s\"",
- testId.getTestName(), testId.getClassName());
- assertTrue(output.contains(testCaseTag));
- }
-
- /**
- * A simple test to ensure expected output is generated for test run with a single failed test.
- */
- public void testSingleFail() {
- Map<String, String> emptyMap = Collections.emptyMap();
- final TestIdentifier testId = new TestIdentifier("FooTest", "testFoo");
- final String trace = "this is a trace";
- mResultReporter.testRunStarted("run", 1);
- mResultReporter.testStarted(testId);
- mResultReporter.testFailed(TestFailure.FAILURE, testId, trace);
- mResultReporter.testEnded(testId, emptyMap);
- mResultReporter.testRunEnded(3, emptyMap);
- String output = getOutput();
- // TODO: consider doing xml based compare
- assertTrue(output.contains("tests=\"1\" failures=\"1\" errors=\"0\""));
- final String testCaseTag = String.format("<testcase name=\"%s\" classname=\"%s\"",
- testId.getTestName(), testId.getClassName());
- assertTrue(output.contains(testCaseTag));
- final String failureTag = String.format("<failure>%s</failure>", trace);
- assertTrue(output.contains(failureTag));
- }
-
- /**
- * Gets the output produced, stripping it of extraneous whitespace characters.
- */
- private String getOutput() {
- String output = mOutputStream.toString();
- // ignore newlines and tabs whitespace
- output = output.replaceAll("[\\r\\n\\t]", "");
- // replace two ws chars with one
- return output.replaceAll(" ", " ");
- }
-}