Bundle-ActivationPolicy: lazy
Import-Package: com.samsung.slp.common.conn.device,
com.samsung.slp.common.util
+Bundle-ClassPath: .
output.. = bin/
bin.includes = META-INF/,\
.
+jars.compile.order = .,\
+ sdblib.jar
package com.samsung.slp.common.connection;
-import java.util.ArrayList;
import java.util.Properties;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
-import com.samsung.slp.common.connection.ddmlib.Client;
-
import com.samsung.slp.common.connection.ddmuilib.DdmUiPreferences;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge;
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
+import com.samsung.slp.sdblib.IDevice;
//import com.samsung.slp.common.connection.device.DeviceMonitor;
//import com.samsung.slp.common.connection.sdb.SdbHelper;
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import java.io.IOException;
-
-/**
- * Exception thrown when adb refuses a command.
- */
-public class AdbCommandRejectedException extends IOException {
- 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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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 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 static void createForward(InetSocketAddress adbSockAddr, Device device, int localPort,
- int remotePort) 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:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$
- device.getSerialNumber(), localPort, remotePort));
-
- 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 localPort the local port of the 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 static void removeForward(InetSocketAddress adbSockAddr, Device device, int localPort,
- int remotePort) 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:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$
- device.getSerialNumber(), localPort, remotePort));
-
- 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();
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-/**
- * Holds an Allocation information.
- */
-public class AllocationInfo implements Comparable<AllocationInfo>, IStackTraceInfo {
- private String mAllocatedClass;
- private int mAllocationSize;
- private short mThreadId;
- private StackTraceElement[] mStackTrace;
-
- /*
- * Simple constructor.
- */
- AllocationInfo(String allocatedClass, int allocationSize,
- short threadId, StackTraceElement[] stackTrace) {
- mAllocatedClass = allocatedClass;
- mAllocationSize = allocationSize;
- mThreadId = threadId;
- mStackTrace = stackTrace;
- }
-
- /**
- * 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()
- */
- public StackTraceElement[] getStackTrace() {
- return mStackTrace;
- }
-
- public int compareTo(AllocationInfo otherAlloc) {
- return otherAlloc.mAllocationSize - mAllocationSize;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.ddmlib.Log.LogLevel;
-
-import java.io.BufferedReader;
-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.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_MIN = 0;
- 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;
- final static int ADB_PORT = 7037;
-
- private static InetAddress sHostAddr;
- private static InetSocketAddress sSocketAddr;
-
- private static AndroidDebugBridge sThis;
- 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 void init(boolean clientSupport) {
- 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);
- }
-
- /**
- * Terminates the ddm library. This must be called upon application termination.
- */
- public static 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();
- }
- }
-
- /**
- * 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;
- }
-
- try {
- String[] command = new String[2];
- command[0] = mAdbOsLocation;
- command[1] = "version"; //$NON-NLS-1$
- Log.d(DDMS, String.format("Checking '%1$s version'", mAdbOsLocation)); //$NON-NLS-1$
- Process process = Runtime.getRuntime().exec(command);
-
- ArrayList<String> errorOutput = new ArrayList<String>();
- ArrayList<String> stdOutput = new ArrayList<String>();
- int status = grabProcessOutput(process, errorOutput, stdOutput,
- true /* waitForReaders */);
-
- 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.
- Log.logAndDisplay(LogLevel.ERROR, ADB,
- "Failed to parse the output of 'adb version'"); //$NON-NLS-1$
- }
-
- } catch (IOException e) {
- Log.logAndDisplay(LogLevel.ERROR, ADB,
- "Failed to get the adb version: " + e.getMessage()); //$NON-NLS-1$
- } catch (InterruptedException e) {
- } finally {
-
- }
- }
-
- /**
- * 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).
- */
- 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]));
- proc = Runtime.getRuntime().exec(command);
-
- 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;
- }
-
-}
+++ /dev/null
-/* //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.samsung.slp.common.connection.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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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;
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.samsung.slp.common.connection.ddmlib.ClientData.MethodProfilingStatus;
-import com.samsung.slp.common.connection.ddmlib.DebugPortManager.IDebugPortProvider;
-
-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 {
- if (canStream) {
- HandleProfiling.sendMPSS(this, 8*1024*1024, 0 /*flags*/);
- } else {
- String file = "/sdcard/" + mClientData.getClientDescription().replaceAll("\\:.*", "") +
- ".trace";
- HandleProfiling.sendMPRS(this, file, 8*1024*1024, 0 /*flags*/);
- }
- }
- } catch (IOException e) {
- Log.w("ddms", "Toggle method profiling failed");
- // ignore
- }
- }
-
- /**
- * 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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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 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;
-
- // 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;
- }
-
- /**
- * 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;
- }
- }
- }
-
- /**
- * 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 an {@link Iterator} on {@link NativeLibraryMapInfo} objects.
- * <p/>
- * The caller must synchronize on the {@link ClientData} object while iterating.
- */
- public synchronized Iterator<NativeLibraryMapInfo> getNativeLibraryMapInfo() {
- return mNativeLibMapInfo.iterator();
- }
-
- 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;
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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();
-
- /** 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;
- }
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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
-
- 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;
-
- /**
- * 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;
- }
-
- /**
- * Non accessible constructor.
- */
- private DdmPreferences() {
- // pass, only static methods in the class.
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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);
- }
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.ddmlib.log.LogReceiver;
-import com.samsung.slp.common.connection.ddmlib.SyncService.SyncResult;
-
-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 final static int INSTALL_TIMEOUT = 2*60*1000; //2min
-
- /** 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";
-
- /**
- * Socket for the connection monitoring client connection/disconnection.
- */
- private SocketChannel mSocketChannel;
-
- /**
- * 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);
- }
- }
- }
- }
- }
-
- public boolean isCancelled() {
- return false;
- }
-
- public String getErrorMessage() {
- return mErrorMessage;
- }
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getSerialNumber()
- */
- public String getSerialNumber() {
- return mSerialNumber;
- }
-
- /** {@inheritDoc} */
- 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;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getState()
- */
- 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()
- */
- public Map<String, String> getProperties() {
- return Collections.unmodifiableMap(mProperties);
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getPropertyCount()
- */
- public int getPropertyCount() {
- return mProperties.size();
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getProperty(java.lang.String)
- */
- public String getProperty(String name) {
- return mProperties.get(name);
- }
-
- public String getMountPoint(String name) {
- return mMountPoints.get(name);
- }
-
-
- @Override
- public String toString() {
- return mSerialNumber;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isOnline()
- */
- public boolean isOnline() {
- return mState == DeviceState.ONLINE;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isEmulator()
- */
- public boolean isEmulator() {
- return mSerialNumber.matches(RE_EMULATOR_SN);
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isOffline()
- */
- public boolean isOffline() {
- return mState == DeviceState.OFFLINE;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#isBootLoader()
- */
- public boolean isBootLoader() {
- return mState == DeviceState.BOOTLOADER;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#hasClients()
- */
- public boolean hasClients() {
- return mClients.size() > 0;
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getClients()
- */
- public Client[] getClients() {
- synchronized (mClients) {
- return mClients.toArray(new Client[mClients.size()]);
- }
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getClient(java.lang.String)
- */
- 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()
- */
- 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()
- */
- public FileListingService getFileListingService() {
- return new FileListingService(this);
- }
-
- public RawImage getScreenshot()
- throws TimeoutException, AdbCommandRejectedException, IOException {
- return AdbHelper.getFrameBuffer(AndroidDebugBridge.getSocketAddress(), this);
- }
-
- public void executeShellCommand(String command, IShellOutputReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this,
- receiver, DdmPreferences.getTimeOut());
- }
-
- public void executeShellCommand(String command, IShellOutputReceiver receiver,
- int maxTimeToOutputResponse)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this,
- receiver, maxTimeToOutputResponse);
- }
-
- public void runEventLogService(LogReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.runEventLogService(AndroidDebugBridge.getSocketAddress(), this, receiver);
- }
-
- public void runLogService(String logname, LogReceiver receiver)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.runLogService(AndroidDebugBridge.getSocketAddress(), this, logname, receiver);
- }
-
- public void createForward(int localPort, int remotePort)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this, localPort, remotePort);
- }
-
- public void removeForward(int localPort, int remotePort)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this, localPort, remotePort);
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#getClientName(int)
- */
- 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) {
- 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);
- }
-
- public String installPackage(String packageFilePath, boolean reinstall)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- String remoteFilePath = syncPackageToDevice(packageFilePath);
- String result = installRemotePackage(remoteFilePath, reinstall);
- removeRemotePackage(remoteFilePath);
- return result;
- }
-
- public String syncPackageToDevice(String localFilePath)
- throws IOException, AdbCommandRejectedException, TimeoutException {
- 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()));
-
- SyncService sync = getSyncService();
- if (sync != null) {
- String message = String.format("Uploading file onto device '%1$s'",
- getSerialNumber());
- Log.d(LOG_TAG, message);
- SyncResult result = sync.pushFile(localFilePath, remoteFilePath,
- SyncService.getNullProgressMonitor());
-
- if (result.getCode() != SyncService.RESULT_OK) {
- throw new IOException(String.format("Unable to upload file: %1$s",
- result.getMessage()));
- }
- } else {
- throw new IOException("Unable to open sync connection!");
- }
- return remoteFilePath;
- } catch (TimeoutException e) {
- Log.e(LOG_TAG, "Unable to open sync connection! Timeout.");
- throw e;
- } catch (IOException e) {
- Log.e(LOG_TAG, String.format("Unable to open sync connection! reason: %1$s",
- e.getMessage()));
- throw e;
- }
- }
-
- /**
- * 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();
- }
-
- public String installRemotePackage(String remoteFilePath, boolean reinstall)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- InstallReceiver receiver = new InstallReceiver();
- String cmd = String.format(reinstall ? "pm install -r \"%1$s\"" : "pm install \"%1$s\"",
- remoteFilePath);
- executeShellCommand(cmd, receiver, INSTALL_TIMEOUT);
- return receiver.getErrorMessage();
- }
-
- /**
- * {@inheritDoc}
- */
- public void removeRemotePackage(String remoteFilePath)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- // now we delete the app we sync'ed
- try {
- executeShellCommand("rm " + remoteFilePath, new NullOutputReceiver(), INSTALL_TIMEOUT);
- } catch (IOException e) {
- Log.e(LOG_TAG, String.format("Failed to delete temporary package: %1$s",
- e.getMessage()));
- throw e;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public String uninstallPackage(String packageName)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException {
- InstallReceiver receiver = new InstallReceiver();
- executeShellCommand("pm uninstall " + packageName, receiver, INSTALL_TIMEOUT);
- return receiver.getErrorMessage();
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ddmlib.IDevice#reboot()
- */
- public void reboot(String into)
- throws TimeoutException, AdbCommandRejectedException, IOException {
- AdbHelper.reboot(into, AndroidDebugBridge.getSocketAddress(), this);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.ddmlib.AdbHelper.AdbResponse;
-import com.samsung.slp.common.connection.ddmlib.ClientData.DebuggerStatus;
-import com.samsung.slp.common.connection.ddmlib.DebugPortManager.IDebugPortProvider;
-import com.samsung.slp.common.connection.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.Iterator;
-import java.util.List;
-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;
- }
- }
- }
-
- /**
- * 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).
- // FIXME : sdb
- if (device.isEmulator()) {
- EmulatorConsole console = EmulatorConsole.getConsole(device);
- if (console != null) {
- device.setAvdName("test");
- }
- }
- } 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$
- 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 {
- if (length >= 0) {
- // array for the current pids.
- ArrayList<Integer> pidList = new ArrayList<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 {
- pidList.add(Integer.valueOf(pid));
- } catch (NumberFormatException nfe) {
- // looks like this pid is not really a number. Lets ignore it.
- continue;
- }
- }
- }
-
- MonitorThread monitorThread = MonitorThread.getInstance();
-
- // Now we merge the current list with the old one.
- // this is the same mechanism as the merging of the device list.
-
- // For each client in the current list, we look for a matching the pid in the new list.
- // * if we find it, we do nothing, except removing the pid from its list,
- // to mark it as "processed"
- // * if we do not find any match, we remove the client from the current list.
- // Once this is done, the new list contains pids for which we don't have clients yet,
- // so we create clients for them, add them to the list, and start monitoring them.
-
- List<Client> clients = device.getClientList();
-
- boolean changed = false;
-
- // because MonitorThread#dropClient acquires first the monitorThread lock and then the
- // Device client list lock (when removing the Client from the list), we have to make
- // sure we acquire the locks in the same order, since another thread (MonitorThread),
- // could call dropClient itself.
- synchronized (monitorThread) {
- synchronized (clients) {
- for (int c = 0 ; c < clients.size() ;) {
- Client client = clients.get(c);
- int pid = client.getClientData().getPid();
-
- // look for a matching pid
- Integer match = null;
- for (Integer matchingPid : pidList) {
- if (pid == matchingPid.intValue()) {
- match = matchingPid;
- break;
- }
- }
-
- if (match != null) {
- pidList.remove(match);
- c++; // move on to the next client.
- } else {
- // we need to drop the client. the client will remove itself from the
- // list of its device which is 'clients', so there's no need to
- // increment c.
- // We ask the monitor thread to not send notification, as we'll do
- // it once at the end.
- monitorThread.dropClient(client, false /* notify */);
- changed = true;
- }
- }
- }
- }
-
- // at this point whatever pid is left in the list needs to be converted into Clients.
- for (int newPid : pidList) {
- openClient(device, newPid, getNextDebuggerPort(), monitorThread);
- changed = true;
- }
-
- if (changed) {
- 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;
- }
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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
- Matcher m = sEmulatorRegexp.matcher(d.getSerialNumber());
- 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 null;
- }
- } 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;
- }
-
- 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 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());
-
- // 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());
-
- // 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);
- formatter.format(COMMAND_GPS, longitude, latitude, elevation);
-
- return processCommand(formatter.toString());
- }
-
- /**
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-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$
-
- private final static String[] sRootLevelApprovedItems = { DIRECTORY_DATA,
- DIRECTORY_SDCARD, DIRECTORY_SYSTEM, DIRECTORY_TEMP, DIRECTORY_MNT, };
-
- 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;
- /** Entry type: root */
- public static final int TYPE_ROOT_EMULATOR = 9;
- public static final int TYPE_ROOT_DEVICE = 10;
-
- /** 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.
- * Do not think the same format between Emulator and Device such as "ls -l --time-style=long-iso"
- */
-
- private static String patternPermisions = "([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])";
- private static String patternFilecount = "(\\d{1,})";
- private static String patternOwner = "(\\S+)";
- private static String patternGroup = "(\\S+)";
- private static String patternSize = "([\\d\\s,]*)";
- private static String patternDate = "([a-zA-Z]{3}\\s+\\d{1,2})";
- private static String patternTime = "(\\d{1,2}:\\d{1,2})";
- private static String patternName = "(.*)";
- private static String patternLs = "^" + patternPermisions + "\\s+"
- + patternFilecount + "\\s+" + patternOwner + "\\s+" + patternGroup
- + "\\s+" + patternSize + "\\s+" + patternDate + "\\s+"
- + patternTime + "\\s+" + patternName + "$";
-
- // private static Pattern sLsPattern = 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 Pattern sLsPattern = Pattern.compile(patternLs);
- 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. */
- private final static Pattern sEscapePattern = Pattern
- .compile("([\\\\()*+?\"'#/\\s])"); //$NON-NLS-1$
-
- /**
- * Comparator object for FileEntry
- */
- private static Comparator<FileEntry> sEntryComparator = new Comparator<FileEntry>() {
- public int compare(FileEntry o1, FileEntry o2) {
- if (o1 instanceof FileEntry && o2 instanceof FileEntry) {
- FileEntry fe1 = (FileEntry) o1;
- FileEntry fe2 = (FileEntry) 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;
- String linkPath;
- FileListingService fileListingService;
- 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}.
- */
- public FileEntry(FileEntry parent, String name, int type,
- boolean isRoot, FileListingService service) {
- this.parent = parent;
- this.name = name;
- this.type = type;
- this.isRoot = isRoot;
- this.fileListingService = service;
- }
-
- /**
- * 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 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;
- }
- public String getLinkFullPath() {
- return linkPath;
- }
- /**
- * 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 true if the entry is a directory, false otherwise;
- */
- public int getType() {
- return type;
- }
-
- public FileListingService getFileListingService()
- {
- return fileListingService;
- }
-
- /**
- * 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);
- }
-
- /**
- * Returns an escaped version of the entry name.
- *
- * @param entryName
- */
- private String escape(String entryName) {
- return sEscapePattern.matcher(entryName).replaceAll("\\\\$1"); //$NON-NLS-1$
- }
- }
-
- private class LsReceiver extends MultiLineReceiver {
-
- private ArrayList<FileEntry> mEntryList;
- private ArrayList<String> mLinkList;
- private FileEntry[] mCurrentChildren;
- private FileEntry mParentEntry;
- int linkType = -1;
- /**
- * 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 = sLsPattern.matcher(line);
- if (m.matches() == false) {
- continue;
- }
-
- // get the name
- String name = m.group(8);
- // get the rest of the groups
- String permissions = m.group(1);
- String owner = m.group(3);
- String group = m.group(4);
- String size = m.group(5);
- String date = m.group(6);
- String time = m.group(7);
- String info = null;
- String linkTo = null;
- int objectType = getFileType(permissions.charAt(0));
-
- // 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];
- linkTo = segments[1];
-
- // add an arrow in front to specify
- // it's a link.
- info = "-> " + info; //$NON-NLS-1$;
- // now get the path to the link
- String[] pathSegments = info.split(FILE_SEPARATOR);
-
- if (pathSegments.length >= 1) {
- // FIXME : not fully impl
- String command = "ls -al ";
- if (linkTo.charAt(0) != '/')
- command = command + "/";
- command = command + linkTo;
- try {
- LsLinkReceiver receiver = new LsLinkReceiver();
- mDevice.executeShellCommand(command,receiver);
- if (receiver.isDirectoryLink == true)
- objectType = TYPE_DIRECTORY_LINK;
- } catch (Exception e) {
- // adb failed somehow, we do nothing.
- }
- }
- }
- }
- // 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 */, mParentEntry.fileListingService);
- }
-
- // 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 || objectType == TYPE_DIRECTORY_LINK) {
- entry.info = info;
- entry.linkPath = linkTo;
- }
-
- mEntryList.add(entry);
- }
- }
- final class LsLinkReceiver extends MultiLineReceiver {
- boolean isDirectoryLink = false;
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- if (line.length() > 0) {
- Matcher m = sLsPattern.matcher(line);
- if (m.matches()) {
- int objectType = getFileType(m.group(1).charAt(0));
- String name = m.group(8);
- if (".".equals(name) && objectType == TYPE_DIRECTORY) {
- isDirectoryLink = true;
- break;
- }
- }
- }
- }
-
- }
-
- public boolean isCancelled() {
- return false;
- }
- }
- /**
- * 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;
- }
-
- public boolean isCancelled() {
- return false;
- }
-
- public void finishLinks() {
- // TODO Handle links in the listing service
- }
- private int getFileType(char type){
- // and the type
- int objectType = TYPE_OTHER;
- switch (type) {
- 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;
- }
- return objectType;
- }
- }
-
- /**
- * 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 */, this);
- }
-
- 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);
- }
- }
- }
- }
- }
-
- 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;
- }
-
- public IDevice getDevice()
- {
- return mDevice;
- }
-
- private void doLs(FileEntry entry) {
- // 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 = null;
- if (entry.getType() == FileListingService.TYPE_LINK || entry.getType() == FileListingService.TYPE_DIRECTORY_LINK) {
- if (entry.getLinkFullPath().charAt(0) == '/')
- command = "ls -l " + entry.getLinkFullPath(); //$NON-NLS-1$
- else
- command = "ls -l /" + entry.getLinkFullPath(); //$NON-NLS-1$
- }else {
- command = "ls -l " + entry.getFullPath(); //$NON-NLS-1$
- }
-
- // 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();
- } catch (Exception e) {
- // catch all and do nothing.
- }
-
- // 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);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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);
- }
- }
- }
- }
-
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public void done() {
- mDevice.update(Device.CHANGE_BUILD_INFO);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import java.io.IOException;
-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);
-
- Log.d("ddm-appname", "APNM: app='" + appName + "'");
-
- ClientData cd = client.getClientData();
- synchronized (cd) {
- cd.setClientDescription(appName);
- }
-
- client = checkDebuggerPortForAppName(client, appName);
-
- if (client != null) {
- client.update(Client.CHANGE_NAME);
- }
- }
- }
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.ddmlib.ClientData.AllocationTrackingStatus;
-import com.samsung.slp.common.connection.ddmlib.ClientData.IHprofDumpHandler;
-
-import java.io.IOException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * 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);
- 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(classNames[classNameIndex],
- totalSize, (short) threadId, steArray));
- }
-
- // sort biggest allocations first.
- Collections.sort(list);
-
- 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() + ")");
- }
- }
- }
- }
-
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import java.io.IOException;
-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);
-
- 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);
- } 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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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_GC);
- 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 = ((long)buffer.getInt()) & 0x00000000ffffffffL;
-
- 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 = (int) buffer.get();
- long startAddress = (long) 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 = (int)buffer.get() & 0x000000ff;
- int eLen = ((int)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);
-
- /*
- * only check for library addresses as defined in
- * //device/config/prelink-linux-arm.map
- */
- if (tmpStart >= 0x0000000080000000L && tmpStart <= 0x00000000BFFFFFFFL) {
-
- 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();
- }
- }
-
-
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.ddmlib.ClientData.IMethodProfilingHandler;
-import com.samsung.slp.common.connection.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 ".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);
- }
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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 = (int)data.get() & 0x000000ff;
- int eLen = ((int)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 = (int)data.get() & 0x000000ff;
- if ((nextState & ~PARTIAL_MASK) != (eState & ~PARTIAL_MASK)) {
- throw new ParseException("State mismatch", data.position());
- }
- eState = nextState;
- eLen += ((int)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;
- }
-
- 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 = (int) hpsgData.get();
- mStartAddress = (long) 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();
- }
-
- 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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.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}. */
- 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$
-
- 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;
- }
- }
-
- /**
- * 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><build></code>".
- *
- * @return the name of the AVD or <code>null</code> if there isn't any.
- */
- public String getAvdName();
-
- /**
- * 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 a property value.
- *
- * @param name the name of the value to return.
- * @return the value or <code>null</code> if the property does not exist.
- */
- public String getProperty(String name);
-
- /**
- * 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.
- * @return <code>true</code> if success.
- * @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;
-
- /**
- * Removes a port forwarding between a local and a remote port.
- *
- * @param localPort the local port to forward
- * @param remotePort the remote port.
- * @return <code>true</code> if success.
- * @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;
-
- /**
- * 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);
-
- /**
- * 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
- * @return a {@link String} with an error code, or <code>null</code> if success.
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when
- * performing the action.
- * @throws IOException in case of I/O error on the connection.
- */
- public String installPackage(String packageFilePath, boolean reinstall)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * 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.
- */
- public String syncPackageToDevice(String localFilePath)
- throws TimeoutException, AdbCommandRejectedException, IOException;
-
- /**
- * 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
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when
- * performing the action.
- * @throws IOException if installation failed
- */
- public String installRemotePackage(String remoteFilePath, boolean reinstall)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * Removes a file from device.
- *
- * @param remoteFilePath path on device of file to remove
- * @throws TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when
- * performing the action.
- * @throws IOException if file removal failed
- */
- public void removeRemotePackage(String remoteFilePath)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * 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 TimeoutException in case of timeout on the connection.
- * @throws AdbCommandRejectedException if adb rejects the command
- * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when
- * performing the action.
- * @throws IOException
- */
- public String uninstallPackage(String packageName)
- throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
- IOException;
-
- /**
- * 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;
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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();
-};
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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();
-
-}
+++ /dev/null
-/* //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.samsung.slp.common.connection.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);
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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);
- }
-}
-
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-
-import com.samsung.slp.common.connection.ddmlib.DebugPortManager.IDebugPortProvider;
-import com.samsung.slp.common.connection.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();
- }
-
- /*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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)
- */
- public final void addOutput(byte[] data, int offset, int length) {
- if (isCancelled() == false) {
- String s = null;
- try {
- s = new String(data, offset, length, "ISO-8859-1"); //$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()
- */
- 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);
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * 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 {
- /* constants for flag bits */
- private static final int FLAG_ZYGOTE_CHILD = (1<<31);
- private static final int FLAG_MASK = (FLAG_ZYGOTE_CHILD);
-
- /**
- * list of alloc functions that are filtered out when attempting to display
- * a relevant method responsible for an allocation
- */
- private static ArrayList<String> sAllocFunctionFilter;
- static {
- sAllocFunctionFilter = new ArrayList<String>();
- sAllocFunctionFilter.add("malloc"); //$NON-NLS-1$
- sAllocFunctionFilter.add("calloc"); //$NON-NLS-1$
- sAllocFunctionFilter.add("realloc"); //$NON-NLS-1$
- sAllocFunctionFilter.add("get_backtrace"); //$NON-NLS-1$
- sAllocFunctionFilter.add("get_hash"); //$NON-NLS-1$
- sAllocFunctionFilter.add("??"); //$NON-NLS-1$
- sAllocFunctionFilter.add("internal_free"); //$NON-NLS-1$
- sAllocFunctionFilter.add("operator new"); //$NON-NLS-1$
- sAllocFunctionFilter.add("leak_free"); //$NON-NLS-1$
- sAllocFunctionFilter.add("chk_free"); //$NON-NLS-1$
- sAllocFunctionFilter.add("chk_memalign"); //$NON-NLS-1$
- sAllocFunctionFilter.add("Malloc"); //$NON-NLS-1$
- sAllocFunctionFilter.add("leak_memalign"); //$NON-NLS-1$
- }
-
- 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
- */
- 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.
- */
- 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 Long[] getStackCallAddresses() {
- return mStackCallAddresses.toArray(new Long[mStackCallAddresses.size()]);
- }
-
- /**
- * 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(ArrayList)
- * @see #isStackCallResolved()
- */
- public synchronized NativeStackCallInfo[] getResolvedStackCall() {
- if (mIsStackCallResolved) {
- return mResolvedStackCall.toArray(new NativeStackCallInfo[mResolvedStackCall.size()]);
- }
-
- 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;
- }
-
- /**
- * Returns a string representation of the object.
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.append("Allocations: ");
- buffer.append(mAllocations);
- buffer.append("\n"); //$NON-NLS-1$
-
- buffer.append("Size: ");
- buffer.append(mSize);
- buffer.append("\n"); //$NON-NLS-1$
-
- buffer.append("Total Size: ");
- buffer.append(mSize * mAllocations);
- buffer.append("\n"); //$NON-NLS-1$
-
- Iterator<Long> addrIterator = mStackCallAddresses.iterator();
- Iterator<NativeStackCallInfo> sourceIterator = mResolvedStackCall.iterator();
-
- while (sourceIterator.hasNext()) {
- long addr = addrIterator.next();
- NativeStackCallInfo source = sourceIterator.next();
- 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()));
- }
- }
-
- 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(ArrayList)
- * @see #isStackCallResolved()
- */
- public synchronized NativeStackCallInfo getRelevantStackCallInfo() {
- if (mIsStackCallResolved && mResolvedStackCall != null) {
- Iterator<NativeStackCallInfo> sourceIterator = mResolvedStackCall.iterator();
- Iterator<Long> addrIterator = mStackCallAddresses.iterator();
-
- while (sourceIterator.hasNext() && addrIterator.hasNext()) {
- long addr = addrIterator.next();
- NativeStackCallInfo info = sourceIterator.next();
- if (addr != 0 && info != null) {
- if (isRelevant(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;
- }
-
- /**
- * Returns true if the method name is relevant.
- * @param methodName the method name to test.
- */
- private boolean isRelevant(String methodName) {
- for (String filter : sAllocFunctionFilter) {
- if (methodName.contains(filter)) {
- return false;
- }
- }
-
- return true;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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+)$");
-
- /** 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>
- * <sourcefile>:<linenumber>
- */
- private String mSourceFile;
-
- private int mLineNumber = -1;
-
- /**
- * Basic constructor with library, method, and sourcefile information
- *
- * @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(String lib, String method, String sourceFile) {
- 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 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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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)
- */
- public void addOutput(byte[] data, int offset, int length) {
- }
-
- /* (non-Javadoc)
- * @see com.android.ddmlib.adb.IShellOutputReceiver#flush()
- */
- public void flush() {
- }
-
- /* (non-Javadoc)
- * @see com.android.ddmlib.adb.IShellOutputReceiver#isCancelled()
- */
- public boolean isCancelled() {
- return false;
- }
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import java.io.IOException;
-
-/**
- * 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 IOException {
- private static final long serialVersionUID = 1L;
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import com.samsung.slp.common.connection.ddmlib.utils.ArrayHelper;
-import com.samsung.slp.common.connection.ddmlib.AdbHelper.AdbResponse;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-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;
-
- /** Result code for transfer success. */
- public static final int RESULT_OK = 0;
- /** Result code for canceled transfer */
- public static final int RESULT_CANCELED = 1;
- /** Result code for unknown error */
- public static final int RESULT_UNKNOWN_ERROR = 2;
- /** Result code for network connection error */
- public static final int RESULT_CONNECTION_ERROR = 3;
- /** Result code for unknown remote object during a pull */
- public static final int RESULT_NO_REMOTE_OBJECT = 4;
- /** Result code when attempting to pull multiple files into a file */
- public static final int RESULT_TARGET_IS_FILE = 5;
- /** Result code when attempting to pull multiple into a directory that does not exist. */
- public static final int RESULT_NO_DIR_TARGET = 6;
- /** Result code for wrong encoding on the remote path. */
- public static final int RESULT_REMOTE_PATH_ENCODING = 7;
- /** Result code for remote path that is too long. */
- public static final int RESULT_REMOTE_PATH_LENGTH = 8;
- /** Result code for error while writing local file. */
- public static final int RESULT_FILE_WRITE_ERROR = 9;
- /** Result code for error while reading local file. */
- public static final int RESULT_FILE_READ_ERROR = 10;
- /** Result code for attempting to push a file that does not exist. */
- public static final int RESULT_NO_LOCAL_FILE = 11;
- /** Result code for attempting to push a directory. */
- public static final int RESULT_LOCAL_IS_DIRECTORY = 12;
- /** Result code for when the target path of a multi file push is a file. */
- public static final int RESULT_REMOTE_IS_FILE = 13;
- /** Result code for receiving too much data from the remove device at once */
- public static final int RESULT_BUFFER_OVERRUN = 14;
- /** Result code for network connection timeout */
- public static final int RESULT_CONNECTION_TIMEOUT = 15;
-
- /**
- * A file transfer result.
- * <p/>
- * This contains a code, and an optional string
- */
- public static class SyncResult {
- private int mCode;
- private String mMessage;
- SyncResult(int code, String message) {
- mCode = code;
- mMessage = message;
- }
-
- SyncResult(int code, Exception e) {
- this(code, e.getMessage());
- }
-
- SyncResult(int code) {
- this(code, errorCodeToString(code));
- }
-
- public int getCode() {
- return mCode;
- }
-
- public String getMessage() {
- return mMessage;
- }
- }
-
- /**
- * 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 {
- public void advance(int work) {
- }
- public boolean isCanceled() {
- return false;
- }
-
- public void start(int totalWork) {
- }
- public void startSubTask(String name) {
- }
- 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;
- }
-
- /**
- * Converts an error code into a non-localized string
- * @param code the error code;
- */
- private static String errorCodeToString(int code) {
- switch (code) {
- case RESULT_OK:
- return "Success.";
- case RESULT_CANCELED:
- return "Tranfert canceled by the user.";
- case RESULT_UNKNOWN_ERROR:
- return "Unknown Error.";
- case RESULT_CONNECTION_ERROR:
- return "Adb Connection Error.";
- case RESULT_NO_REMOTE_OBJECT:
- return "Remote object doesn't exist!";
- case RESULT_TARGET_IS_FILE:
- return "Target object is a file.";
- case RESULT_NO_DIR_TARGET:
- return "Target directory doesn't exist.";
- case RESULT_REMOTE_PATH_ENCODING:
- return "Remote Path encoding is not supported.";
- case RESULT_REMOTE_PATH_LENGTH:
- return "Remove path is too long.";
- case RESULT_FILE_WRITE_ERROR:
- return "Writing local file failed!";
- case RESULT_FILE_READ_ERROR:
- return "Reading local file failed!";
- case RESULT_NO_LOCAL_FILE:
- return "Local file doesn't exist.";
- case RESULT_LOCAL_IS_DIRECTORY:
- return "Local path is a directory.";
- case RESULT_REMOTE_IS_FILE:
- return "Remote path is a file.";
- case RESULT_BUFFER_OVERRUN:
- return "Receiving too much data.";
- case RESULT_CONNECTION_TIMEOUT:
- return "timeout";
- }
-
- throw new RuntimeException();
- }
-
- /**
- * 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.
- * @return a {@link SyncResult} object with a code and an optional message.
- *
- * @see FileListingService.FileEntry
- * @see #getNullProgressMonitor()
- */
- public SyncResult pull(FileEntry[] entries, String localPath, ISyncProgressMonitor monitor) {
-
- // first we check the destination is a directory and exists
- File f = new File(localPath);
- if (f.exists() == false) {
- return new SyncResult(RESULT_NO_DIR_TARGET);
- }
- if (f.isDirectory() == false) {
- return new SyncResult(RESULT_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);
-
- SyncResult result = doPull(entries, localPath, fls, monitor);
-
- monitor.stop();
-
- return result;
- }
-
- /**
- * Pulls a single file.
- * @param remote the remote file
- * @param localFilename The local destination.
- * @param monitor The progress monitor. Cannot be null.
- * @return a {@link SyncResult} object with a code and an optional message.
- *
- * @see FileListingService.FileEntry
- * @see #getNullProgressMonitor()
- */
- public SyncResult pullFile(FileEntry remote, String localFilename,
- ISyncProgressMonitor monitor) {
- int total = remote.getSizeValue();
- monitor.start(total);
-
- SyncResult result = doPullFile(remote.getFullPath(), localFilename, monitor);
-
- monitor.stop();
- return result;
- }
-
- /**
- * 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.
- * @return a {@link SyncResult} object with a code and an optional message.
- *
- * @see #getNullProgressMonitor()
- */
- public SyncResult pullFile(String remoteFilepath, String localFilename,
- ISyncProgressMonitor monitor) {
- monitor.start(0);
- //TODO: use the {@link FileListingService} to get the file size.
-
- SyncResult result = doPullFile(remoteFilepath, localFilename, monitor);
-
- monitor.stop();
- return result;
- }
-
- /**
- * 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.
- * @return a {@link SyncResult} object with a code and an optional message.
- */
- public SyncResult push(String[] local, FileEntry remote, ISyncProgressMonitor monitor) {
- if (remote.isDirectory() == false) {
- return new SyncResult(RESULT_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);
-
- SyncResult result = doPush(fileArray, remote.getFullPath(), monitor);
-
- monitor.stop();
-
- return result;
- }
-
- /**
- * Push a single file.
- * @param local the local filepath.
- * @param remote The remote filepath.
- * @param monitor The progress monitor. Cannot be null.
- * @return a {@link SyncResult} object with a code and an optional message.
- */
- public SyncResult pushFile(String local, String remote, ISyncProgressMonitor monitor) {
- File f = new File(local);
- if (f.exists() == false) {
- return new SyncResult(RESULT_NO_LOCAL_FILE);
- }
-
- if (f.isDirectory()) {
- return new SyncResult(RESULT_LOCAL_IS_DIRECTORY);
- }
-
- monitor.start((int)f.length());
-
- SyncResult result = doPushFile(local, remote, monitor);
-
- monitor.stop();
-
- return result;
- }
-
- /**
- * 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.
- * @return a {@link SyncResult} object with a code and an optional message.
- */
- private SyncResult doPull(FileEntry[] entries, String localPath,
- FileListingService fileListingService,
- ISyncProgressMonitor monitor) {
-
- for (FileEntry e : entries) {
- // check if we're cancelled
- if (monitor.isCanceled() == true) {
- return new SyncResult(RESULT_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);
- SyncResult result = doPull(children, dest, fileListingService, monitor);
- if (result.mCode != RESULT_OK) {
- return result;
- }
- monitor.advance(1);
- } else if (type == FileListingService.TYPE_FILE) {
- monitor.startSubTask(e.getFullPath());
- String dest = localPath + File.separator + e.getName();
- SyncResult result = doPullFile(e.getFullPath(), dest, monitor);
- if (result.mCode != RESULT_OK) {
- return result;
- }
- }
- }
-
- return new SyncResult(RESULT_OK);
- }
-
- /**
- * 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.
- * @return a {@link SyncResult} object with a code and an optional message.
- */
- private SyncResult doPullFile(String remotePath, String localPath,
- ISyncProgressMonitor monitor) {
- 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) {
- return new SyncResult(RESULT_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) {
- return new SyncResult(RESULT_CONNECTION_ERROR);
- }
- } catch (UnsupportedEncodingException e) {
- return new SyncResult(RESULT_REMOTE_PATH_ENCODING, e);
- } catch (TimeoutException e) {
- return new SyncResult(RESULT_CONNECTION_TIMEOUT, e);
- } catch (IOException e) {
- return new SyncResult(RESULT_CONNECTION_ERROR, 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);
- } catch (FileNotFoundException e) {
- return new SyncResult(RESULT_FILE_WRITE_ERROR, e);
- }
-
- // 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) {
- return new SyncResult(RESULT_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
- return new SyncResult(RESULT_CONNECTION_ERROR);
- }
- int length = ArrayHelper.swap32bitFromArray(pullResult, 4);
- if (length > SYNC_DATA_MAX) {
- // buffer overrun!
- // error and exit
- return new SyncResult(RESULT_BUFFER_OVERRUN);
- }
-
- try {
- // 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);
- } catch (TimeoutException e) {
- return new SyncResult(RESULT_CONNECTION_TIMEOUT, e);
- } catch (IOException e) {
- return new SyncResult(RESULT_CONNECTION_ERROR, e);
- }
-
- // write the content in the file
- try {
- fos.write(data, 0, length);
- } catch (IOException e) {
- return new SyncResult(RESULT_FILE_WRITE_ERROR, e);
- }
-
- monitor.advance(length);
- }
-
- try {
- fos.flush();
- } catch (IOException e) {
- return new SyncResult(RESULT_FILE_WRITE_ERROR, e);
- }
- return new SyncResult(RESULT_OK);
- }
-
-
- /**
- * Push multiple files
- * @param fileArray
- * @param remotePath
- * @param monitor
- * @return a {@link SyncResult} object with a code and an optional message.
- */
- private SyncResult doPush(File[] fileArray, String remotePath, ISyncProgressMonitor monitor) {
- for (File f : fileArray) {
- // check if we're canceled
- if (monitor.isCanceled() == true) {
- return new SyncResult(RESULT_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);
- SyncResult result = doPush(f.listFiles(), dest, monitor);
-
- if (result.mCode != RESULT_OK) {
- return result;
- }
-
- 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);
- SyncResult result = doPushFile(f.getAbsolutePath(), remoteFile, monitor);
- if (result.mCode != RESULT_OK) {
- return result;
- }
- }
- }
- }
-
- return new SyncResult(RESULT_OK);
- }
-
- /**
- * 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.
- * @return a {@link SyncResult} object with a code and an optional message.
- */
- private SyncResult doPushFile(String localPath, String remotePath,
- ISyncProgressMonitor monitor) {
- 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) {
- return new SyncResult(RESULT_REMOTE_PATH_LENGTH);
- }
-
- File f = new File(localPath);
-
- // this shouldn't happen but still...
- if (f.exists() == false) {
- return new SyncResult(RESULT_NO_LOCAL_FILE);
- }
-
- // create the stream to read the file
- fis = new FileInputStream(f);
-
- // create the header for the action
- msg = createSendFileReq(ID_SEND, remotePathContent, 0644);
- } catch (UnsupportedEncodingException e) {
- return new SyncResult(RESULT_REMOTE_PATH_ENCODING, e);
- } catch (FileNotFoundException e) {
- return new SyncResult(RESULT_FILE_READ_ERROR, e);
- }
-
- // and send it. We use a custom try/catch block to make the difference between
- // file and network IO exceptions.
- try {
- AdbHelper.write(mChannel, msg, -1, timeOut);
- } catch (TimeoutException e) {
- return new SyncResult(RESULT_CONNECTION_TIMEOUT, e);
- } catch (IOException e) {
- return new SyncResult(RESULT_CONNECTION_ERROR, e);
- }
-
- // 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) {
- return new SyncResult(RESULT_CANCELED);
- }
-
- // read up to SYNC_DATA_MAX
- int readCount = 0;
- try {
- readCount = fis.read(mBuffer, 8, SYNC_DATA_MAX);
- } catch (IOException e) {
- return new SyncResult(RESULT_FILE_READ_ERROR, e);
- }
-
- 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
- try {
- AdbHelper.write(mChannel, mBuffer, readCount+8, timeOut);
- } catch (TimeoutException e) {
- return new SyncResult(RESULT_CONNECTION_TIMEOUT, e);
- } catch (IOException e) {
- return new SyncResult(RESULT_CONNECTION_ERROR, e);
- }
-
- // and advance the monitor
- monitor.advance(readCount);
- }
- // close the local file
- try {
- fis.close();
- } catch (IOException e) {
- return new SyncResult(RESULT_FILE_READ_ERROR, e);
- }
-
- try {
- // 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) {
- if (checkResult(result, ID_FAIL)) {
- // read some error message...
- int len = ArrayHelper.swap32bitFromArray(result, 4);
-
- AdbHelper.read(mChannel, mBuffer, len, timeOut);
-
- // output the result?
- String message = new String(mBuffer, 0, len);
- Log.e("ddms", "transfer error: " + message);
- return new SyncResult(RESULT_UNKNOWN_ERROR, message);
- }
-
- return new SyncResult(RESULT_UNKNOWN_ERROR);
- }
- } catch (TimeoutException e) {
- return new SyncResult(RESULT_CONNECTION_TIMEOUT, e);
- } catch (IOException e) {
- return new SyncResult(RESULT_CONNECTION_ERROR, e);
- }
-
- return new SyncResult(RESULT_OK);
- }
-
- /**
- * Returns the mode of the remote file.
- * @param path the remote file
- * @return and Integer containing the mode if all went well or null
- * otherwise
- * @throws IOException
- * @throws TimeoutException
- */
- 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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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()
- */
- public StackTraceElement[] getStackTrace() {
- return mTrace;
- }
-
- /**
- * Returns the approximate time of the stacktrace data.
- * @see #getStackTrace()
- */
- public long getStackCallTime() {
- return mTraceTime;
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib;
-
-import java.io.IOException;
-
-/**
- * Exception thrown when a connection to Adb failed with a timeout.
- *
- */
-public class TimeoutException extends IOException {
- private static final long serialVersionUID = 1L;
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib.log;
-
-import com.samsung.slp.common.connection.ddmlib.log.LogReceiver.LogEntry;
-
-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.samsung.slp.common.connection.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();
- }
-
- 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);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib.log;
-
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.Log;
-import com.samsung.slp.common.connection.ddmlib.MultiLineReceiver;
-import com.samsung.slp.common.connection.ddmlib.log.EventContainer.EventValueType;
-import com.samsung.slp.common.connection.ddmlib.log.EventValueDescription.ValueType;
-import com.samsung.slp.common.connection.ddmlib.log.LogReceiver.LogEntry;
-import com.samsung.slp.common.connection.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.Set;
-import java.util.TreeMap;
-import java.util.Map.Entry;
-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);
- }
- }
- 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) {
- try {
- BufferedReader 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;
- }
- }
-
- /**
- * 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();
- }
- }
- }
-
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib.log;
-
-import com.samsung.slp.common.connection.ddmlib.log.EventContainer.EventValueType;
-
-
-/**
- * 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();
- }
-
- 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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib.log;
-
-import com.samsung.slp.common.connection.ddmlib.log.EventValueDescription.ValueType;
-import com.samsung.slp.common.connection.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();
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib.log;
-
-import com.samsung.slp.common.connection.ddmlib.log.EventContainer.EventValueType;
-import com.samsung.slp.common.connection.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);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmlib.log;
-
-
-import com.samsung.slp.common.connection.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;
- }
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.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;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.*;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.Collection;
-import java.util.HashMap;
-
-/**
- * Represents an addr2line process to get filename/method information from a
- * memory address.<br>
- * Each process can only handle one library, which should be provided when
- * creating a new process.<br>
- * <br>
- * The processes take some time to load as they need to parse the library files.
- * For this reason, processes cannot be manually started. Instead the class
- * keeps an internal list of processes and one asks for a process for a specific
- * library, using <code>getProcess(String library)<code>.<br></br>
- * Internally, the processes are started in pipe mode to be able to query them
- * with multiple addresses.
- */
-public class Addr2Line {
-
- /**
- * Loaded processes list. This is also used as a locking object for any
- * methods dealing with starting/stopping/creating processes/querying for
- * method.
- */
- private static final HashMap<String, Addr2Line> sProcessCache =
- new HashMap<String, Addr2Line>();
-
- /**
- * byte array representing a carriage return. Used to push addresses in the
- * process pipes.
- */
- private static final byte[] sCrLf = {
- '\n'
- };
-
- /** Path to the library */
- private String mLibrary;
-
- /** the command line process */
- private Process mProcess;
-
- /** buffer to read the result of the command line process from */
- private BufferedReader mResultReader;
-
- /**
- * output stream to provide new addresses to decode to the command line
- * process
- */
- private BufferedOutputStream mAddressWriter;
-
- /**
- * Returns the instance of a Addr2Line process for the specified library.
- * <br>The library should be in a format that makes<br>
- * <code>$ANDROID_PRODUCT_OUT + "/symbols" + library</code> a valid file.
- *
- * @param library the library in which to look for addresses.
- * @return a new Addr2Line object representing a started process, ready to
- * be queried for addresses. If any error happened when launching a
- * new process, <code>null</code> will be returned.
- */
- public static Addr2Line getProcess(final String library) {
- // synchronize around the hashmap object
- if (library != null) {
- synchronized (sProcessCache) {
- // look for an existing process
- Addr2Line process = sProcessCache.get(library);
-
- // if we don't find one, we create it
- if (process == null) {
- process = new Addr2Line(library);
-
- // then we start it
- boolean status = process.start();
-
- if (status) {
- // if starting the process worked, then we add it to the
- // list.
- sProcessCache.put(library, process);
- } else {
- // otherwise we just drop the object, to return null
- process = null;
- }
- }
- // return the process
- return process;
- }
- }
- return null;
- }
-
- /**
- * Construct the object with a library name.
- * <br>The library should be in a format that makes<br>
- * <code>$ANDROID_PRODUCT_OUT + "/symbols" + library</code> a valid file.
- *
- * @param library the library in which to look for address.
- */
- private Addr2Line(final String library) {
- mLibrary = library;
- }
-
- /**
- * Starts the command line process.
- *
- * @return true if the process was started, false if it failed to start, or
- * if there was any other errors.
- */
- private boolean start() {
- // because this is only called from getProcess() we know we don't need
- // to synchronize this code.
-
- // get the output directory.
- String symbols = System.getenv("ANDROID_SYMBOLS");
- if (symbols == null) {
- symbols = DdmUiPreferences.getSymbolDirectory();
- }
-
- // build the command line
- String[] command = new String[5];
- command[0] = DdmUiPreferences.getAddr2Line();
- command[1] = "-C";
- command[2] = "-f";
- command[3] = "-e";
- command[4] = symbols + mLibrary;
-
- try {
- // attempt to start the process
- mProcess = Runtime.getRuntime().exec(command);
-
- if (mProcess != null) {
- // get the result reader
- InputStreamReader is = new InputStreamReader(mProcess
- .getInputStream());
- mResultReader = new BufferedReader(is);
-
- // get the outstream to write the addresses
- mAddressWriter = new BufferedOutputStream(mProcess
- .getOutputStream());
-
- // check our streams are here
- if (mResultReader == null || mAddressWriter == null) {
- // not here? stop the process and return false;
- mProcess.destroy();
- mProcess = null;
- return false;
- }
-
- // return a success
- return true;
- }
-
- } catch (IOException e) {
- // log the error
- String msg = String.format(
- "Error while trying to start %1$s process for library %2$s",
- DdmUiPreferences.getAddr2Line(), mLibrary);
- Log.e("ddm-Addr2Line", msg);
-
- // drop the process just in case
- if (mProcess != null) {
- mProcess.destroy();
- mProcess = null;
- }
- }
-
- // we can be here either cause the allocation of mProcess failed, or we
- // caught an exception
- return false;
- }
-
- /**
- * Stops the command line process.
- */
- public void stop() {
- synchronized (sProcessCache) {
- if (mProcess != null) {
- // remove the process from the list
- sProcessCache.remove(mLibrary);
-
- // then stops the process
- mProcess.destroy();
-
- // set the reference to null.
- // this allows to make sure another thread calling getAddress()
- // will not query a stopped thread
- mProcess = null;
- }
- }
- }
-
- /**
- * Stops all current running processes.
- */
- public static void stopAll() {
- // because of concurrent access (and our use of HashMap.values()), we
- // can't rely on the synchronized inside stop(). We need to put one
- // around the whole loop.
- synchronized (sProcessCache) {
- // just a basic loop on all the values in the hashmap and call to
- // stop();
- Collection<Addr2Line> col = sProcessCache.values();
- for (Addr2Line a2l : col) {
- a2l.stop();
- }
- }
- }
-
- /**
- * Looks up an address and returns method name, source file name, and line
- * number.
- *
- * @param addr the address to look up
- * @return a BacktraceInfo object containing the method/filename/linenumber
- * or null if the process we stopped before the query could be
- * processed, or if an IO exception happened.
- */
- public NativeStackCallInfo getAddress(long addr) {
- // even though we don't access the hashmap object, we need to
- // synchronized on it to prevent
- // another thread from stopping the process we're going to query.
- synchronized (sProcessCache) {
- // check the process is still alive/allocated
- if (mProcess != null) {
- // prepare to the write the address to the output buffer.
-
- // first, conversion to a string containing the hex value.
- String tmp = Long.toString(addr, 16);
-
- try {
- // write the address to the buffer
- mAddressWriter.write(tmp.getBytes());
-
- // add CR-LF
- mAddressWriter.write(sCrLf);
-
- // flush it all.
- mAddressWriter.flush();
-
- // read the result. We need to read 2 lines
- String method = mResultReader.readLine();
- String source = mResultReader.readLine();
-
- // make the backtrace object and return it
- if (method != null && source != null) {
- return new NativeStackCallInfo(mLibrary, method, source);
- }
- } catch (IOException e) {
- // log the error
- Log.e("ddms",
- "Error while trying to get information for addr: "
- + tmp + " in library: " + mLibrary);
- // we'll return null later
- }
- }
- }
- return null;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.AllocationInfo;
-import com.samsung.slp.common.connection.ddmlib.Client;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.samsung.slp.common.connection.ddmlib.ClientData.AllocationTrackingStatus;
-
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.viewers.ILabelProviderListener;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.ITableLabelProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.SWTException;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.FormAttachment;
-import org.eclipse.swt.layout.FormData;
-import org.eclipse.swt.layout.FormLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Sash;
-import org.eclipse.swt.widgets.Table;
-
-/**
- * Base class for our information panels.
- */
-public class AllocationPanel extends TablePanel {
-
- private final static String PREFS_ALLOC_COL_SIZE = "allocPanel.Col0"; //$NON-NLS-1$
- private final static String PREFS_ALLOC_COL_CLASS = "allocPanel.Col1"; //$NON-NLS-1$
- private final static String PREFS_ALLOC_COL_THREAD = "allocPanel.Col2"; //$NON-NLS-1$
- private final static String PREFS_ALLOC_COL_TRACE_CLASS = "allocPanel.Col3"; //$NON-NLS-1$
- private final static String PREFS_ALLOC_COL_TRACE_METHOD = "allocPanel.Col4"; //$NON-NLS-1$
-
- private final static String PREFS_ALLOC_SASH = "allocPanel.sash"; //$NON-NLS-1$
-
- private static final String PREFS_STACK_COL_CLASS = "allocPanel.stack.col0"; //$NON-NLS-1$
- private static final String PREFS_STACK_COL_METHOD = "allocPanel.stack.col1"; //$NON-NLS-1$
- private static final String PREFS_STACK_COL_FILE = "allocPanel.stack.col2"; //$NON-NLS-1$
- private static final String PREFS_STACK_COL_LINE = "allocPanel.stack.col3"; //$NON-NLS-1$
- private static final String PREFS_STACK_COL_NATIVE = "allocPanel.stack.col4"; //$NON-NLS-1$
-
- private Composite mAllocationBase;
- private Table mAllocationTable;
- private TableViewer mAllocationViewer;
-
- private StackTracePanel mStackTracePanel;
- private Table mStackTraceTable;
- private Button mEnableButton;
- private Button mRequestButton;
-
- /**
- * Content Provider to display the allocations of a client.
- * Expected input is a {@link Client} object, elements used in the table are of type
- * {@link AllocationInfo}.
- */
- private static class AllocationContentProvider implements IStructuredContentProvider {
- public Object[] getElements(Object inputElement) {
- if (inputElement instanceof Client) {
- AllocationInfo[] allocs = ((Client)inputElement).getClientData().getAllocations();
- if (allocs != null) {
- return allocs;
- }
- }
-
- return new Object[0];
- }
-
- public void dispose() {
- // pass
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- // pass
- }
- }
-
- /**
- * A Label Provider to use with {@link AllocationContentProvider}. It expects the elements to be
- * of type {@link AllocationInfo}.
- */
- private static class AllocationLabelProvider implements ITableLabelProvider {
-
- public Image getColumnImage(Object element, int columnIndex) {
- return null;
- }
-
- public String getColumnText(Object element, int columnIndex) {
- if (element instanceof AllocationInfo) {
- AllocationInfo alloc = (AllocationInfo)element;
- switch (columnIndex) {
- case 0:
- return Integer.toString(alloc.getSize());
- case 1:
- return alloc.getAllocatedClass();
- case 2:
- return Short.toString(alloc.getThreadId());
- case 3:
- StackTraceElement[] traces = alloc.getStackTrace();
- if (traces.length > 0) {
- return traces[0].getClassName();
- }
- break;
- case 4:
- traces = alloc.getStackTrace();
- if (traces.length > 0) {
- return traces[0].getMethodName();
- }
- break;
- }
- }
-
- return null;
- }
-
- public void addListener(ILabelProviderListener listener) {
- // pass
- }
-
- public void dispose() {
- // pass
- }
-
- public boolean isLabelProperty(Object element, String property) {
- // pass
- return false;
- }
-
- public void removeListener(ILabelProviderListener listener) {
- // pass
- }
- }
-
- /**
- * Create our control(s).
- */
- @Override
- protected Control createControl(Composite parent) {
- final IPreferenceStore store = DdmUiPreferences.getStore();
-
- // base composite for selected client with enabled thread update.
- mAllocationBase = new Composite(parent, SWT.NONE);
- mAllocationBase.setLayout(new FormLayout());
-
- // table above the sash
- Composite topParent = new Composite(mAllocationBase, SWT.NONE);
- topParent.setLayout(new GridLayout(2, false));
-
- mEnableButton = new Button(topParent, SWT.PUSH);
- mEnableButton.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- Client current = getCurrentClient();
- AllocationTrackingStatus status = current.getClientData().getAllocationStatus();
- if (status == AllocationTrackingStatus.ON) {
- current.enableAllocationTracker(false);
- } else {
- current.enableAllocationTracker(true);
- }
- current.requestAllocationStatus();
- }
- });
-
- mRequestButton = new Button(topParent, SWT.PUSH);
- mRequestButton.setText("Get Allocations");
- mRequestButton.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- getCurrentClient().requestAllocationDetails();
- }
- });
-
- setUpButtons(false /* enabled */, AllocationTrackingStatus.OFF);
-
- mAllocationTable = new Table(topParent, SWT.MULTI | SWT.FULL_SELECTION);
- GridData gridData;
- mAllocationTable.setLayoutData(gridData = new GridData(GridData.FILL_BOTH));
- gridData.horizontalSpan = 2;
- mAllocationTable.setHeaderVisible(true);
- mAllocationTable.setLinesVisible(true);
-
- TableHelper.createTableColumn(
- mAllocationTable,
- "Allocation Size",
- SWT.RIGHT,
- "888", //$NON-NLS-1$
- PREFS_ALLOC_COL_SIZE, store);
-
- TableHelper.createTableColumn(
- mAllocationTable,
- "Allocated Class",
- SWT.LEFT,
- "Allocated Class", //$NON-NLS-1$
- PREFS_ALLOC_COL_CLASS, store);
-
- TableHelper.createTableColumn(
- mAllocationTable,
- "Thread Id",
- SWT.LEFT,
- "999", //$NON-NLS-1$
- PREFS_ALLOC_COL_THREAD, store);
-
- TableHelper.createTableColumn(
- mAllocationTable,
- "Allocated in",
- SWT.LEFT,
- "utime", //$NON-NLS-1$
- PREFS_ALLOC_COL_TRACE_CLASS, store);
-
- TableHelper.createTableColumn(
- mAllocationTable,
- "Allocated in",
- SWT.LEFT,
- "utime", //$NON-NLS-1$
- PREFS_ALLOC_COL_TRACE_METHOD, store);
-
- mAllocationViewer = new TableViewer(mAllocationTable);
- mAllocationViewer.setContentProvider(new AllocationContentProvider());
- mAllocationViewer.setLabelProvider(new AllocationLabelProvider());
-
- mAllocationViewer.addSelectionChangedListener(new ISelectionChangedListener() {
- public void selectionChanged(SelectionChangedEvent event) {
- AllocationInfo selectedAlloc = getAllocationSelection(event.getSelection());
- updateAllocationStackTrace(selectedAlloc);
- }
- });
-
- // the separating sash
- final Sash sash = new Sash(mAllocationBase, SWT.HORIZONTAL);
- Color darkGray = parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
- sash.setBackground(darkGray);
-
- // the UI below the sash
- mStackTracePanel = new StackTracePanel();
- mStackTraceTable = mStackTracePanel.createPanel(mAllocationBase,
- PREFS_STACK_COL_CLASS,
- PREFS_STACK_COL_METHOD,
- PREFS_STACK_COL_FILE,
- PREFS_STACK_COL_LINE,
- PREFS_STACK_COL_NATIVE,
- store);
-
- // now setup the sash.
- // form layout data
- FormData data = new FormData();
- data.top = new FormAttachment(0, 0);
- data.bottom = new FormAttachment(sash, 0);
- data.left = new FormAttachment(0, 0);
- data.right = new FormAttachment(100, 0);
- topParent.setLayoutData(data);
-
- final FormData sashData = new FormData();
- if (store != null && store.contains(PREFS_ALLOC_SASH)) {
- sashData.top = new FormAttachment(0, store.getInt(PREFS_ALLOC_SASH));
- } else {
- sashData.top = new FormAttachment(50,0); // 50% across
- }
- sashData.left = new FormAttachment(0, 0);
- sashData.right = new FormAttachment(100, 0);
- sash.setLayoutData(sashData);
-
- data = new FormData();
- data.top = new FormAttachment(sash, 0);
- data.bottom = new FormAttachment(100, 0);
- data.left = new FormAttachment(0, 0);
- data.right = new FormAttachment(100, 0);
- mStackTraceTable.setLayoutData(data);
-
- // allow resizes, but cap at minPanelWidth
- sash.addListener(SWT.Selection, new Listener() {
- public void handleEvent(Event e) {
- Rectangle sashRect = sash.getBounds();
- Rectangle panelRect = mAllocationBase.getClientArea();
- int bottom = panelRect.height - sashRect.height - 100;
- e.y = Math.max(Math.min(e.y, bottom), 100);
- if (e.y != sashRect.y) {
- sashData.top = new FormAttachment(0, e.y);
- store.setValue(PREFS_ALLOC_SASH, e.y);
- mAllocationBase.layout();
- }
- }
- });
-
- return mAllocationBase;
- }
-
- /**
- * Sets the focus to the proper control inside the panel.
- */
- @Override
- public void setFocus() {
- mAllocationTable.setFocus();
- }
-
- /**
- * 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_NAME}
- * {@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}
- *
- * @see IClientChangeListener#clientChanged(Client, int)
- */
- public void clientChanged(final Client client, int changeMask) {
- if (client == getCurrentClient()) {
- if ((changeMask & Client.CHANGE_HEAP_ALLOCATIONS) != 0) {
- try {
- mAllocationTable.getDisplay().asyncExec(new Runnable() {
- public void run() {
- mAllocationViewer.refresh();
- updateAllocationStackCall();
- }
- });
- } catch (SWTException e) {
- // widget is disposed, we do nothing
- }
- } else if ((changeMask & Client.CHANGE_HEAP_ALLOCATION_STATUS) != 0) {
- try {
- mAllocationTable.getDisplay().asyncExec(new Runnable() {
- public void run() {
- setUpButtons(true, client.getClientData().getAllocationStatus());
- }
- });
- } catch (SWTException e) {
- // widget is disposed, we do nothing
- }
- }
- }
- }
-
- /**
- * Sent when a new device is selected. The new device can be accessed
- * with {@link #getCurrentDevice()}.
- */
- @Override
- public void deviceSelected() {
- // pass
- }
-
- /**
- * Sent when a new client is selected. The new client can be accessed
- * with {@link #getCurrentClient()}.
- */
- @Override
- public void clientSelected() {
- if (mAllocationTable.isDisposed()) {
- return;
- }
-
- Client client = getCurrentClient();
-
- mStackTracePanel.setCurrentClient(client);
- mStackTracePanel.setViewerInput(null); // always empty on client selection change.
-
- if (client != null) {
- setUpButtons(true /* enabled */, client.getClientData().getAllocationStatus());
- } else {
- setUpButtons(false /* enabled */, AllocationTrackingStatus.OFF);
- }
-
- mAllocationViewer.setInput(client);
- }
-
- /**
- * Updates the stack call of the currently selected thread.
- * <p/>
- * This <b>must</b> be called from the UI thread.
- */
- private void updateAllocationStackCall() {
- Client client = getCurrentClient();
- if (client != null) {
- // get the current selection in the ThreadTable
- AllocationInfo selectedAlloc = getAllocationSelection(null);
-
- if (selectedAlloc != null) {
- updateAllocationStackTrace(selectedAlloc);
- } else {
- updateAllocationStackTrace(null);
- }
- }
- }
-
- /**
- * updates the stackcall of the specified allocation. If <code>null</code> the UI is emptied
- * of current data.
- * @param thread
- */
- private void updateAllocationStackTrace(AllocationInfo alloc) {
- mStackTracePanel.setViewerInput(alloc);
- }
-
- @Override
- protected void setTableFocusListener() {
- addTableToFocusListener(mAllocationTable);
- addTableToFocusListener(mStackTraceTable);
- }
-
- /**
- * Returns the current allocation selection or <code>null</code> if none is found.
- * If a {@link ISelection} object is specified, the first {@link AllocationInfo} from this
- * selection is returned, otherwise, the <code>ISelection</code> returned by
- * {@link TableViewer#getSelection()} is used.
- * @param selection the {@link ISelection} to use, or <code>null</code>
- */
- private AllocationInfo getAllocationSelection(ISelection selection) {
- if (selection == null) {
- selection = mAllocationViewer.getSelection();
- }
-
- if (selection instanceof IStructuredSelection) {
- IStructuredSelection structuredSelection = (IStructuredSelection)selection;
- Object object = structuredSelection.getFirstElement();
- if (object instanceof AllocationInfo) {
- return (AllocationInfo)object;
- }
- }
-
- return null;
- }
-
- /**
- *
- * @param enabled
- * @param trackingStatus
- */
- private void setUpButtons(boolean enabled, AllocationTrackingStatus trackingStatus) {
- if (enabled) {
- switch (trackingStatus) {
- case UNKNOWN:
- mEnableButton.setText("?");
- mEnableButton.setEnabled(false);
- mRequestButton.setEnabled(false);
- break;
- case OFF:
- mEnableButton.setText("Start Tracking");
- mEnableButton.setEnabled(true);
- mRequestButton.setEnabled(false);
- break;
- case ON:
- mEnableButton.setText("Stop Tracking");
- mEnableButton.setEnabled(true);
- mRequestButton.setEnabled(true);
- break;
- }
- } else {
- mEnableButton.setEnabled(false);
- mRequestButton.setEnabled(false);
- mEnableButton.setText("Start Tracking");
- }
- }
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.Log;
-
-/**
- * base background thread class. The class provides a synchronous quit method
- * which sets a quitting flag to true. Inheriting classes should regularly test
- * this flag with <code>isQuitting()</code> and should finish if the flag is
- * true.
- */
-public abstract class BackgroundThread extends Thread {
- private boolean mQuit = false;
-
- /**
- * Tell the thread to exit. This is usually called from the UI thread. The
- * call is synchronous and will only return once the thread has terminated
- * itself.
- */
- public final void quit() {
- mQuit = true;
- Log.d("ddms", "Waiting for BackgroundThread to quit");
- try {
- this.join();
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
-
- /** returns if the thread was asked to quit. */
- protected final boolean isQuitting() {
- return mQuit;
- }
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.HeapSegment;
-import com.samsung.slp.common.connection.ddmlib.ClientData.HeapData;
-import com.samsung.slp.common.connection.ddmlib.HeapSegment.HeapSegmentElement;
-
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.PaletteData;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeMap;
-
-
-/**
- * Base Panel for heap panels.
- */
-public abstract class BaseHeapPanel extends TablePanel {
-
- /** store the processed heap segment, so that we don't recompute Image for nothing */
- protected byte[] mProcessedHeapData;
- private Map<Integer, ArrayList<HeapSegmentElement>> mHeapMap;
-
- /**
- * Serialize the heap data into an array. The resulting array is available through
- * <code>getSerializedData()</code>.
- * @param heapData The heap data to serialize
- * @return true if the data changed.
- */
- protected boolean serializeHeapData(HeapData heapData) {
- Collection<HeapSegment> heapSegments;
-
- // Atomically get and clear the heap data.
- synchronized (heapData) {
- // get the segments
- heapSegments = heapData.getHeapSegments();
-
-
- if (heapSegments != null) {
- // if they are not null, we never processed them.
- // Before we process then, we drop them from the HeapData
- heapData.clearHeapData();
-
- // process them into a linear byte[]
- doSerializeHeapData(heapSegments);
- heapData.setProcessedHeapData(mProcessedHeapData);
- heapData.setProcessedHeapMap(mHeapMap);
-
- } else {
- // the heap segments are null. Let see if the heapData contains a
- // list that is already processed.
-
- byte[] pixData = heapData.getProcessedHeapData();
-
- // and compare it to the one we currently have in the panel.
- if (pixData == mProcessedHeapData) {
- // looks like its the same
- return false;
- } else {
- mProcessedHeapData = pixData;
- }
-
- Map<Integer, ArrayList<HeapSegmentElement>> heapMap =
- heapData.getProcessedHeapMap();
- mHeapMap = heapMap;
- }
- }
-
- return true;
- }
-
- /**
- * Returns the serialized heap data
- */
- protected byte[] getSerializedData() {
- return mProcessedHeapData;
- }
-
- /**
- * Processes and serialize the heapData.
- * <p/>
- * The resulting serialized array is {@link #mProcessedHeapData}.
- * <p/>
- * the resulting map is {@link #mHeapMap}.
- * @param heapData the collection of {@link HeapSegment} that forms the heap data.
- */
- private void doSerializeHeapData(Collection<HeapSegment> heapData) {
- mHeapMap = new TreeMap<Integer, ArrayList<HeapSegmentElement>>();
-
- Iterator<HeapSegment> iterator;
- ByteArrayOutputStream out;
-
- out = new ByteArrayOutputStream(4 * 1024);
-
- iterator = heapData.iterator();
- while (iterator.hasNext()) {
- HeapSegment hs = iterator.next();
-
- HeapSegmentElement e = null;
- while (true) {
- int v;
-
- e = hs.getNextElement(null);
- if (e == null) {
- break;
- }
-
- if (e.getSolidity() == HeapSegmentElement.SOLIDITY_FREE) {
- v = 1;
- } else {
- v = e.getKind() + 2;
- }
-
- // put the element in the map
- ArrayList<HeapSegmentElement> elementList = mHeapMap.get(v);
- if (elementList == null) {
- elementList = new ArrayList<HeapSegmentElement>();
- mHeapMap.put(v, elementList);
- }
- elementList.add(e);
-
-
- int len = e.getLength() / 8;
- while (len > 0) {
- out.write(v);
- --len;
- }
- }
- }
- mProcessedHeapData = out.toByteArray();
-
- // sort the segment element in the heap info.
- Collection<ArrayList<HeapSegmentElement>> elementLists = mHeapMap.values();
- for (ArrayList<HeapSegmentElement> elementList : elementLists) {
- Collections.sort(elementList);
- }
- }
-
- /**
- * Creates a linear image of the heap data.
- * @param pixData
- * @param h
- * @param palette
- * @return
- */
- protected ImageData createLinearHeapImage(byte[] pixData, int h, PaletteData palette) {
- int w = pixData.length / h;
- if (pixData.length % h != 0) {
- w++;
- }
-
- // Create the heap image.
- ImageData id = new ImageData(w, h, 8, palette);
-
- int x = 0;
- int y = 0;
- for (byte b : pixData) {
- if (b >= 0) {
- id.setPixel(x, y, b);
- }
-
- y++;
- if (y >= h) {
- y = 0;
- x++;
- }
- }
-
- return id;
- }
-
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IClientChangeListener;
-
-public abstract class ClientDisplayPanel extends SelectionDependentPanel
- implements IClientChangeListener {
-
- @Override
- protected void postCreation() {
- AndroidDebugBridge.addClientChangeListener(this);
- }
-
- public void dispose() {
- AndroidDebugBridge.removeClientChangeListener(this);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge;
-import com.samsung.slp.common.connection.ddmlib.Client;
-import com.samsung.slp.common.connection.ddmlib.ClientData;
-import com.samsung.slp.common.connection.ddmlib.DdmPreferences;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
-import com.samsung.slp.common.connection.ddmlib.ClientData.DebuggerStatus;
-import com.samsung.slp.common.connection.ddmlib.IDevice.DeviceState;
-
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.viewers.ILabelProviderListener;
-import org.eclipse.jface.viewers.ITableLabelProvider;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.TreeSelection;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.SWTException;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeColumn;
-import org.eclipse.swt.widgets.TreeItem;
-
-import java.util.ArrayList;
-
-/**
- * A display of both the devices and their clients.
- */
-public final class DevicePanel extends Panel implements IDebugBridgeChangeListener,
- IDeviceChangeListener, IClientChangeListener {
-
- private final static String PREFS_COL_NAME_SERIAL = "devicePanel.Col0"; //$NON-NLS-1$
- private final static String PREFS_COL_PID_STATE = "devicePanel.Col1"; //$NON-NLS-1$
- private final static String PREFS_COL_PORT_BUILD = "devicePanel.Col4"; //$NON-NLS-1$
-
- private final static int DEVICE_COL_SERIAL = 0;
- private final static int DEVICE_COL_STATE = 1;
- // col 2, 3 not used.
- private final static int DEVICE_COL_BUILD = 4;
-
- private final static int CLIENT_COL_NAME = 0;
- private final static int CLIENT_COL_PID = 1;
- private final static int CLIENT_COL_THREAD = 2;
- private final static int CLIENT_COL_HEAP = 3;
- private final static int CLIENT_COL_PORT = 4;
-
- public final static int ICON_WIDTH = 16;
- public final static String ICON_THREAD = "thread.png"; //$NON-NLS-1$
- public final static String ICON_HEAP = "heap.png"; //$NON-NLS-1$
- public final static String ICON_HALT = "halt.png"; //$NON-NLS-1$
- public final static String ICON_GC = "gc.png"; //$NON-NLS-1$
- public final static String ICON_HPROF = "hprof.png"; //$NON-NLS-1$
- public final static String ICON_TRACING_START = "tracing_start.png"; //$NON-NLS-1$
- public final static String ICON_TRACING_STOP = "tracing_stop.png"; //$NON-NLS-1$
-
- private IDevice mCurrentDevice;
- private Client mCurrentClient;
-
- private Tree mTree;
- private TreeViewer mTreeViewer;
-
- private Image mDeviceImage;
- private Image mEmulatorImage;
-
- private Image mThreadImage;
- private Image mHeapImage;
- private Image mWaitingImage;
- private Image mDebuggerImage;
- private Image mDebugErrorImage;
-
- private final ArrayList<IUiSelectionListener> mListeners = new ArrayList<IUiSelectionListener>();
-
- private final ArrayList<IDevice> mDevicesToExpand = new ArrayList<IDevice>();
-
- private boolean mAdvancedPortSupport;
-
- /**
- * A Content provider for the {@link TreeViewer}.
- * <p/>
- * The input is a {@link AndroidDebugBridge}. First level elements are {@link IDevice} objects,
- * and second level elements are {@link Client} object.
- */
- private class ContentProvider implements ITreeContentProvider {
- public Object[] getChildren(Object parentElement) {
- if (parentElement instanceof IDevice) {
- return ((IDevice)parentElement).getClients();
- }
- return new Object[0];
- }
-
- public Object getParent(Object element) {
- if (element instanceof Client) {
- return ((Client)element).getDevice();
- }
- return null;
- }
-
- public boolean hasChildren(Object element) {
- if (element instanceof IDevice) {
- return ((IDevice)element).hasClients();
- }
-
- // Clients never have children.
- return false;
- }
-
- public Object[] getElements(Object inputElement) {
- if (inputElement instanceof AndroidDebugBridge) {
- return ((AndroidDebugBridge)inputElement).getDevices();
- }
- return new Object[0];
- }
-
- public void dispose() {
- // pass
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- // pass
- }
- }
-
- /**
- * A Label Provider for the {@link TreeViewer} in {@link DevicePanel}. It provides
- * labels and images for {@link IDevice} and {@link Client} objects.
- */
- private class LabelProvider implements ITableLabelProvider {
-
- public Image getColumnImage(Object element, int columnIndex) {
- if (columnIndex == DEVICE_COL_SERIAL && element instanceof IDevice) {
- IDevice device = (IDevice)element;
- if (device.isEmulator()) {
- return mEmulatorImage;
- }
-
- return mDeviceImage;
- } else if (element instanceof Client) {
- Client client = (Client)element;
- ClientData cd = client.getClientData();
-
- switch (columnIndex) {
- case CLIENT_COL_NAME:
- switch (cd.getDebuggerConnectionStatus()) {
- case DEFAULT:
- return null;
- case WAITING:
- return mWaitingImage;
- case ATTACHED:
- return mDebuggerImage;
- case ERROR:
- return mDebugErrorImage;
- }
- return null;
- case CLIENT_COL_THREAD:
- if (client.isThreadUpdateEnabled()) {
- return mThreadImage;
- }
- return null;
- case CLIENT_COL_HEAP:
- if (client.isHeapUpdateEnabled()) {
- return mHeapImage;
- }
- return null;
- }
- }
- return null;
- }
-
- public String getColumnText(Object element, int columnIndex) {
- if (element instanceof IDevice) {
- IDevice device = (IDevice)element;
- switch (columnIndex) {
- case DEVICE_COL_SERIAL:
- return device.getSerialNumber();
- case DEVICE_COL_STATE:
- return getStateString(device);
- case DEVICE_COL_BUILD: {
- String version = device.getProperty(IDevice.PROP_BUILD_VERSION);
- if (version != null) {
- String debuggable = device.getProperty(IDevice.PROP_DEBUGGABLE);
- if (device.isEmulator()) {
- String avdName = device.getAvdName();
- if (avdName == null) {
- avdName = "?"; // the device is probably not online yet, so
- // we don't know its AVD name just yet.
- }
- if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
- return String.format("%1$s [%2$s, debug]", avdName,
- version);
- } else {
- return String.format("%1$s [%2$s]", avdName, version); //$NON-NLS-1$
- }
- } else {
- if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
- return String.format("%1$s, debug", version);
- } else {
- return String.format("%1$s", version); //$NON-NLS-1$
- }
- }
- } else {
- return "unknown";
- }
- }
- }
- } else if (element instanceof Client) {
- Client client = (Client)element;
- ClientData cd = client.getClientData();
-
- switch (columnIndex) {
- case CLIENT_COL_NAME:
- String name = cd.getClientDescription();
- if (name != null) {
- return name;
- }
- return "?";
- case CLIENT_COL_PID:
- return Integer.toString(cd.getPid());
- case CLIENT_COL_PORT:
- if (mAdvancedPortSupport) {
- int port = client.getDebuggerListenPort();
- String portString = "?";
- if (port != 0) {
- portString = Integer.toString(port);
- }
- if (client.isSelectedClient()) {
- return String.format("%1$s / %2$d", portString, //$NON-NLS-1$
- DdmPreferences.getSelectedDebugPort());
- }
-
- return portString;
- }
- }
- }
- return null;
- }
-
- public void addListener(ILabelProviderListener listener) {
- // pass
- }
-
- public void dispose() {
- // pass
- }
-
- public boolean isLabelProperty(Object element, String property) {
- // pass
- return false;
- }
-
- public void removeListener(ILabelProviderListener listener) {
- // pass
- }
- }
-
- /**
- * Classes which implement this interface provide methods that deals
- * with {@link IDevice} and {@link Client} selection changes coming from the ui.
- */
- public interface IUiSelectionListener {
- /**
- * Sent when a new {@link IDevice} and {@link Client} are selected.
- * @param selectedDevice the selected device. If null, no devices are selected.
- * @param selectedClient The selected client. If null, no clients are selected.
- */
- public void selectionChanged(IDevice selectedDevice, Client selectedClient);
- }
-
- /**
- * Creates the {@link DevicePanel} object.
- * @param loader
- * @param advancedPortSupport if true the device panel will add support for selected client port
- * and display the ports in the ui.
- */
- public DevicePanel(boolean advancedPortSupport) {
- mAdvancedPortSupport = advancedPortSupport;
- }
-
- public void addSelectionListener(IUiSelectionListener listener) {
- mListeners.add(listener);
- }
-
- public void removeSelectionListener(IUiSelectionListener listener) {
- mListeners.remove(listener);
- }
-
- @Override
- protected Control createControl(Composite parent) {
- loadImages(parent.getDisplay());
-
- parent.setLayout(new FillLayout());
-
- // create the tree and its column
- mTree = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION);
- mTree.setHeaderVisible(true);
- mTree.setLinesVisible(true);
-
- IPreferenceStore store = DdmUiPreferences.getStore();
-
- TableHelper.createTreeColumn(mTree, "Name", SWT.LEFT,
- "com.android.home", //$NON-NLS-1$
- PREFS_COL_NAME_SERIAL, store);
- TableHelper.createTreeColumn(mTree, "", SWT.LEFT, //$NON-NLS-1$
- "Offline", //$NON-NLS-1$
- PREFS_COL_PID_STATE, store);
-
- TreeColumn col = new TreeColumn(mTree, SWT.NONE);
- col.setWidth(ICON_WIDTH + 8);
- col.setResizable(false);
- col = new TreeColumn(mTree, SWT.NONE);
- col.setWidth(ICON_WIDTH + 8);
- col.setResizable(false);
-
- TableHelper.createTreeColumn(mTree, "", SWT.LEFT, //$NON-NLS-1$
- "9999-9999", //$NON-NLS-1$
- PREFS_COL_PORT_BUILD, store);
-
- // create the tree viewer
- mTreeViewer = new TreeViewer(mTree);
-
- // make the device auto expanded.
- mTreeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
-
- // set up the content and label providers.
- mTreeViewer.setContentProvider(new ContentProvider());
- mTreeViewer.setLabelProvider(new LabelProvider());
-
- mTree.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- notifyListeners();
- }
- });
-
- return mTree;
- }
-
- /**
- * Sets the focus to the proper control inside the panel.
- */
- @Override
- public void setFocus() {
- mTree.setFocus();
- }
-
- @Override
- protected void postCreation() {
- // ask for notification of changes in AndroidDebugBridge (a new one is created when
- // adb is restarted from a different location), IDevice and Client objects.
- AndroidDebugBridge.addDebugBridgeChangeListener(this);
- AndroidDebugBridge.addDeviceChangeListener(this);
- AndroidDebugBridge.addClientChangeListener(this);
- }
-
- public void dispose() {
- AndroidDebugBridge.removeDebugBridgeChangeListener(this);
- AndroidDebugBridge.removeDeviceChangeListener(this);
- AndroidDebugBridge.removeClientChangeListener(this);
- }
-
- /**
- * Returns the selected {@link Client}. May be null.
- */
- public Client getSelectedClient() {
- return mCurrentClient;
- }
-
- /**
- * Returns the selected {@link IDevice}. If a {@link Client} is selected, it returns the
- * IDevice object containing the client.
- */
- public IDevice getSelectedDevice() {
- return mCurrentDevice;
- }
-
- /**
- * Kills the selected {@link Client} by sending its VM a halt command.
- */
- public void killSelectedClient() {
- if (mCurrentClient != null) {
- Client client = mCurrentClient;
-
- // reset the selection to the device.
- TreePath treePath = new TreePath(new Object[] { mCurrentDevice });
- TreeSelection treeSelection = new TreeSelection(treePath);
- mTreeViewer.setSelection(treeSelection);
-
- client.kill();
- }
- }
-
- /**
- * Forces a GC on the selected {@link Client}.
- */
- public void forceGcOnSelectedClient() {
- if (mCurrentClient != null) {
- mCurrentClient.executeGarbageCollector();
- }
- }
-
- public void dumpHprof() {
- if (mCurrentClient != null) {
- mCurrentClient.dumpHprof();
- }
- }
-
- public void toggleMethodProfiling() {
- if (mCurrentClient != null) {
- mCurrentClient.toggleMethodProfiling();
- }
- }
-
- public void setEnabledHeapOnSelectedClient(boolean enable) {
- if (mCurrentClient != null) {
- mCurrentClient.setHeapUpdateEnabled(enable);
- }
- }
-
- public void setEnabledThreadOnSelectedClient(boolean enable) {
- if (mCurrentClient != null) {
- mCurrentClient.setThreadUpdateEnabled(enable);
- }
- }
-
- /**
- * Sent when a new {@link AndroidDebugBridge} is started.
- * <p/>
- * This is sent from a non UI thread.
- * @param bridge the new {@link AndroidDebugBridge} object.
- *
- * @see IDebugBridgeChangeListener#serverChanged(AndroidDebugBridge)
- */
- public void bridgeChanged(final AndroidDebugBridge bridge) {
- if (mTree.isDisposed() == false) {
- exec(new Runnable() {
- public void run() {
- if (mTree.isDisposed() == false) {
- // set up the data source.
- mTreeViewer.setInput(bridge);
-
- // notify the listener of a possible selection change.
- notifyListeners();
- } else {
- // tree is disposed, we need to do something.
- // lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
- }
- }
- });
- }
-
- // all current devices are obsolete
- synchronized (mDevicesToExpand) {
- mDevicesToExpand.clear();
- }
- }
-
- /**
- * 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.
- *
- * @see IDeviceChangeListener#deviceConnected(IDevice)
- */
- public void deviceConnected(IDevice device) {
- exec(new Runnable() {
- public void run() {
- if (mTree.isDisposed() == false) {
- // refresh all
- mTreeViewer.refresh();
-
- // notify the listener of a possible selection change.
- notifyListeners();
- } else {
- // tree is disposed, we need to do something.
- // lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
- }
- }
- });
-
- // if it doesn't have clients yet, it'll need to be manually expanded when it gets them.
- if (device.hasClients() == false) {
- synchronized (mDevicesToExpand) {
- mDevicesToExpand.add(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.
- *
- * @see IDeviceChangeListener#deviceDisconnected(IDevice)
- */
- public void deviceDisconnected(IDevice device) {
- deviceConnected(device);
-
- // just in case, we remove it from the list of devices to expand.
- synchronized (mDevicesToExpand) {
- mDevicesToExpand.remove(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 indicating what changed.
- *
- * @see IDeviceChangeListener#deviceChanged(IDevice)
- */
- public void deviceChanged(final IDevice device, int changeMask) {
- boolean expand = false;
- synchronized (mDevicesToExpand) {
- int index = mDevicesToExpand.indexOf(device);
- if (device.hasClients() && index != -1) {
- mDevicesToExpand.remove(index);
- expand = true;
- }
- }
-
- final boolean finalExpand = expand;
-
- exec(new Runnable() {
- public void run() {
- if (mTree.isDisposed() == false) {
- // look if the current device is selected. This is done in case the current
- // client of this particular device was killed. In this case, we'll need to
- // manually reselect the device.
-
- IDevice selectedDevice = getSelectedDevice();
-
- // refresh the device
- mTreeViewer.refresh(device);
-
- // if the selected device was the changed device and the new selection is
- // empty, we reselect the device.
- if (selectedDevice == device && mTreeViewer.getSelection().isEmpty()) {
- mTreeViewer.setSelection(new TreeSelection(new TreePath(
- new Object[] { device })));
- }
-
- // notify the listener of a possible selection change.
- notifyListeners();
-
- if (finalExpand) {
- mTreeViewer.setExpandedState(device, true);
- }
- } else {
- // tree is disposed, we need to do something.
- // lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
- }
- }
- });
- }
-
- /**
- * 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}
- *
- * @see IClientChangeListener#clientChanged(Client, int)
- */
- public void clientChanged(final Client client, final int changeMask) {
- exec(new Runnable() {
- public void run() {
- if (mTree.isDisposed() == false) {
- // refresh the client
- mTreeViewer.refresh(client);
-
- if ((changeMask & Client.CHANGE_DEBUGGER_STATUS) ==
- Client.CHANGE_DEBUGGER_STATUS &&
- client.getClientData().getDebuggerConnectionStatus() ==
- DebuggerStatus.WAITING) {
- // make sure the device is expanded. Normally the setSelection below
- // will auto expand, but the children of device may not already exist
- // at this time. Forcing an expand will make the TreeViewer create them.
- IDevice device = client.getDevice();
- if (mTreeViewer.getExpandedState(device) == false) {
- mTreeViewer.setExpandedState(device, true);
- }
-
- // create and set the selection
- TreePath treePath = new TreePath(new Object[] { device, client});
- TreeSelection treeSelection = new TreeSelection(treePath);
- mTreeViewer.setSelection(treeSelection);
-
- if (mAdvancedPortSupport) {
- client.setAsSelectedClient();
- }
-
- // notify the listener of a possible selection change.
- notifyListeners(device, client);
- }
- } else {
- // tree is disposed, we need to do something.
- // lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
- AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
- }
- }
- });
- }
-
- private void loadImages(Display display) {
- ImageLoader loader = ImageLoader.getDdmUiLibLoader();
-
- if (mDeviceImage == null) {
- mDeviceImage = loader.loadImage(display, "device.png", //$NON-NLS-1$
- ICON_WIDTH, ICON_WIDTH,
- display.getSystemColor(SWT.COLOR_RED));
- }
- if (mEmulatorImage == null) {
- mEmulatorImage = loader.loadImage(display,
- "emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
- display.getSystemColor(SWT.COLOR_BLUE));
- }
- if (mThreadImage == null) {
- mThreadImage = loader.loadImage(display, ICON_THREAD,
- ICON_WIDTH, ICON_WIDTH,
- display.getSystemColor(SWT.COLOR_YELLOW));
- }
- if (mHeapImage == null) {
- mHeapImage = loader.loadImage(display, ICON_HEAP,
- ICON_WIDTH, ICON_WIDTH,
- display.getSystemColor(SWT.COLOR_BLUE));
- }
- if (mWaitingImage == null) {
- mWaitingImage = loader.loadImage(display,
- "debug-wait.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
- display.getSystemColor(SWT.COLOR_RED));
- }
- if (mDebuggerImage == null) {
- mDebuggerImage = loader.loadImage(display,
- "debug-attach.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
- display.getSystemColor(SWT.COLOR_GREEN));
- }
- if (mDebugErrorImage == null) {
- mDebugErrorImage = loader.loadImage(display,
- "debug-error.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
- display.getSystemColor(SWT.COLOR_RED));
- }
- }
-
- /**
- * Returns a display string representing the state of the device.
- * @param d the device
- */
- private static String getStateString(IDevice d) {
- DeviceState deviceState = d.getState();
- if (deviceState == DeviceState.ONLINE) {
- return "Online";
- } else if (deviceState == DeviceState.OFFLINE) {
- return "Offline";
- } else if (deviceState == DeviceState.BOOTLOADER) {
- return "Bootloader";
- }
-
- return "??";
- }
-
- /**
- * Executes the {@link Runnable} in the UI thread.
- * @param runnable the runnable to execute.
- */
- private void exec(Runnable runnable) {
- try {
- Display display = mTree.getDisplay();
- display.asyncExec(runnable);
- } catch (SWTException e) {
- // tree is disposed, we need to do something. lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(this);
- AndroidDebugBridge.removeDeviceChangeListener(this);
- AndroidDebugBridge.removeClientChangeListener(this);
- }
- }
-
- private void notifyListeners() {
- // get the selection
- TreeItem[] items = mTree.getSelection();
-
- Client client = null;
- IDevice device = null;
-
- if (items.length == 1) {
- Object object = items[0].getData();
- if (object instanceof Client) {
- client = (Client)object;
- device = client.getDevice();
- } else if (object instanceof IDevice) {
- device = (IDevice)object;
- }
- }
-
- notifyListeners(device, client);
- }
-
- private void notifyListeners(IDevice selectedDevice, Client selectedClient) {
- if (selectedDevice != mCurrentDevice || selectedClient != mCurrentClient) {
- mCurrentDevice = selectedDevice;
- mCurrentClient = selectedClient;
-
- for (IUiSelectionListener listener : mListeners) {
- // notify the listener with a try/catch-all to make sure this thread won't die
- // because of an uncaught exception before all the listeners were notified.
- try {
- listener.selectionChanged(selectedDevice, selectedClient);
- } catch (Exception e) {
- }
- }
- }
- }
-
-}
package com.samsung.slp.common.connection.ddmuilib;
-import com.samsung.slp.common.connection.ddmlib.Log;
+//import com.samsung.slp.common.connection.ddmlib.Log;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
Image img = loadImage(fileName, display);
if (img == null) {
- Log.w("ddms", "Couldn't load " + fileName);
+// Log.w("ddms", "Couldn't load " + fileName);
// if we had the extra parameter to create replacement image then we
// create and return it.
if (width != -1 && height != -1) {
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.Log;
-import com.samsung.slp.common.connection.ddmlib.RawImage;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.SWTException;
-import org.eclipse.swt.dnd.Clipboard;
-import org.eclipse.swt.dnd.ImageTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.PaletteData;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Dialog;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-
-import java.io.IOException;
-
-
-/**
- * Gather a screen shot from the device and save it to a file.
- */
-public class ScreenShotDialog extends Dialog {
-
- private Label mBusyLabel;
- private Label mImageLabel;
- private Button mSave;
- private IDevice mDevice;
- private RawImage mRawImage;
- private Clipboard mClipboard;
-
-
- /**
- * Create with default style.
- */
- public ScreenShotDialog(Shell parent) {
- this(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
- mClipboard = new Clipboard(parent.getDisplay());
- }
-
- /**
- * Create with app-defined style.
- */
- public ScreenShotDialog(Shell parent, int style) {
- super(parent, style);
- }
-
- /**
- * Prepare and display the dialog.
- * @param device The {@link IDevice} from which to get the screenshot.
- */
- public void open(IDevice device) {
- mDevice = device;
-
- Shell parent = getParent();
- Shell shell = new Shell(parent, getStyle());
- shell.setText("Device Screen Capture");
-
- createContents(shell);
- shell.pack();
- shell.open();
-
- updateDeviceImage(shell);
-
- Display display = parent.getDisplay();
- while (!shell.isDisposed()) {
- if (!display.readAndDispatch())
- display.sleep();
- }
-
- }
-
- /*
- * Create the screen capture dialog contents.
- */
- private void createContents(final Shell shell) {
- GridData data;
-
- final int colCount = 5;
-
- shell.setLayout(new GridLayout(colCount, true));
-
- // "refresh" button
- Button refresh = new Button(shell, SWT.PUSH);
- refresh.setText("Refresh");
- data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
- data.widthHint = 80;
- refresh.setLayoutData(data);
- refresh.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- updateDeviceImage(shell);
- }
- });
-
- // "rotate" button
- Button rotate = new Button(shell, SWT.PUSH);
- rotate.setText("Rotate");
- data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
- data.widthHint = 80;
- rotate.setLayoutData(data);
- rotate.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- if (mRawImage != null) {
- mRawImage = mRawImage.getRotated();
- updateImageDisplay(shell);
- }
- }
- });
-
- // "save" button
- mSave = new Button(shell, SWT.PUSH);
- mSave.setText("Save");
- data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
- data.widthHint = 80;
- mSave.setLayoutData(data);
- mSave.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- saveImage(shell);
- }
- });
-
- Button copy = new Button(shell, SWT.PUSH);
- copy.setText("Copy");
- copy.setToolTipText("Copy the screenshot to the clipboard");
- data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
- data.widthHint = 80;
- copy.setLayoutData(data);
- copy.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- copy();
- }
- });
-
-
- // "done" button
- Button done = new Button(shell, SWT.PUSH);
- done.setText("Done");
- data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
- data.widthHint = 80;
- done.setLayoutData(data);
- done.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- shell.close();
- }
- });
-
- // title/"capturing" label
- mBusyLabel = new Label(shell, SWT.NONE);
- mBusyLabel.setText("Preparing...");
- data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
- data.horizontalSpan = colCount;
- mBusyLabel.setLayoutData(data);
-
- // space for the image
- mImageLabel = new Label(shell, SWT.BORDER);
- data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
- data.horizontalSpan = colCount;
- mImageLabel.setLayoutData(data);
- Display display = shell.getDisplay();
- mImageLabel.setImage(ImageLoader.createPlaceHolderArt(
- display, 50, 50, display.getSystemColor(SWT.COLOR_BLUE)));
-
-
- shell.setDefaultButton(done);
- }
-
- /**
- * Copies the content of {@link #mImageLabel} to the clipboard.
- */
- private void copy() {
- mClipboard.setContents(
- new Object[] {
- mImageLabel.getImage().getImageData()
- }, new Transfer[] {
- ImageTransfer.getInstance()
- });
- }
-
- /**
- * Captures a new image from the device, and display it.
- */
- private void updateDeviceImage(Shell shell) {
- mBusyLabel.setText("Capturing..."); // no effect
-
- shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
-
- mRawImage = getDeviceImage();
-
- updateImageDisplay(shell);
- }
-
- /**
- * Updates the display with {@link #mRawImage}.
- * @param shell
- */
- private void updateImageDisplay(Shell shell) {
- Image image;
- if (mRawImage == null) {
- Display display = shell.getDisplay();
- image = ImageLoader.createPlaceHolderArt(
- display, 320, 240, display.getSystemColor(SWT.COLOR_BLUE));
-
- mSave.setEnabled(false);
- mBusyLabel.setText("Screen not available");
- } else {
- // convert raw data to an Image.
- PaletteData palette = new PaletteData(
- mRawImage.getRedMask(),
- mRawImage.getGreenMask(),
- mRawImage.getBlueMask());
-
- ImageData imageData = new ImageData(mRawImage.width, mRawImage.height,
- mRawImage.bpp, palette, 1, mRawImage.data);
- image = new Image(getParent().getDisplay(), imageData);
-
- mSave.setEnabled(true);
- mBusyLabel.setText("Captured image:");
- }
-
- mImageLabel.setImage(image);
- mImageLabel.pack();
- shell.pack();
-
- // there's no way to restore old cursor; assume it's ARROW
- shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
- }
-
- /**
- * Grabs an image from an ADB-connected device and returns it as a {@link RawImage}.
- */
- private RawImage getDeviceImage() {
- try {
- return mDevice.getScreenshot();
- }
- catch (IOException ioe) {
- Log.w("ddms", "Unable to get frame buffer: " + ioe.getMessage());
- return null;
- }
- }
-
- /*
- * Prompt the user to save the image to disk.
- */
- private void saveImage(Shell shell) {
- FileDialog dlg = new FileDialog(shell, SWT.SAVE);
- String fileName;
-
- dlg.setText("Save image...");
- dlg.setFileName("device.png");
- dlg.setFilterPath(DdmUiPreferences.getStore().getString("lastImageSaveDir"));
- dlg.setFilterNames(new String[] {
- "PNG Files (*.png)"
- });
- dlg.setFilterExtensions(new String[] {
- "*.png" //$NON-NLS-1$
- });
-
- fileName = dlg.open();
- if (fileName != null) {
- DdmUiPreferences.getStore().setValue("lastImageSaveDir", dlg.getFilterPath());
-
- Log.d("ddms", "Saving image to " + fileName);
- ImageData imageData = mImageLabel.getImage().getImageData();
-
- try {
- org.eclipse.swt.graphics.ImageLoader loader =
- new org.eclipse.swt.graphics.ImageLoader();
-
- loader.data = new ImageData[] { imageData };
- loader.save(fileName, SWT.IMAGE_PNG);
- }
- catch (SWTException e) {
- Log.w("ddms", "Unable to save " + fileName + ": " + e.getMessage());
- }
- }
- }
-
-}
-
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.Client;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-
-/**
- * A Panel that requires {@link Device}/{@link Client} selection notifications.
- */
-public abstract class SelectionDependentPanel extends Panel {
- private IDevice mCurrentDevice = null;
- private Client mCurrentClient = null;
-
- /**
- * Returns the current {@link Device}.
- * @return the current device or null if none are selected.
- */
- protected final IDevice getCurrentDevice() {
- return mCurrentDevice;
- }
-
- /**
- * Returns the current {@link Client}.
- * @return the current client or null if none are selected.
- */
- protected final Client getCurrentClient() {
- return mCurrentClient;
- }
-
- /**
- * Sent when a new device is selected.
- * @param selectedDevice the selected device.
- */
- public final void deviceSelected(IDevice selectedDevice) {
- if (selectedDevice != mCurrentDevice) {
- mCurrentDevice = selectedDevice;
- deviceSelected();
- }
- }
-
- /**
- * Sent when a new client is selected.
- * @param selectedClient the selected client.
- */
- public final void clientSelected(Client selectedClient) {
- if (selectedClient != mCurrentClient) {
- mCurrentClient = selectedClient;
- clientSelected();
- }
- }
-
- /**
- * Sent when a new device is selected. The new device can be accessed
- * with {@link #getCurrentDevice()}.
- */
- public abstract void deviceSelected();
-
- /**
- * Sent when a new client is selected. The new client can be accessed
- * with {@link #getCurrentClient()}.
- */
- public abstract void clientSelected();
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmlib.Client;
-import com.samsung.slp.common.connection.ddmlib.IStackTraceInfo;
-
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ILabelProviderListener;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.ITableLabelProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Table;
-
-/**
- * Stack Trace Panel.
- * <p/>This is not a panel in the regular sense. Instead this is just an object around the creation
- * and management of a Stack Trace display.
- * <p/>UI creation is done through
- * {@link #createPanel(Composite, String, String, String, String, String, IPreferenceStore)}.
- *
- */
-public final class StackTracePanel {
-
- private static ISourceRevealer sSourceRevealer;
-
- private Table mStackTraceTable;
- private TableViewer mStackTraceViewer;
-
- private Client mCurrentClient;
-
-
- /**
- * Content Provider to display the stack trace of a thread.
- * Expected input is a {@link IStackTraceInfo} object.
- */
- private static class StackTraceContentProvider implements IStructuredContentProvider {
- public Object[] getElements(Object inputElement) {
- if (inputElement instanceof IStackTraceInfo) {
- // getElement cannot return null, so we return an empty array
- // if there's no stack trace
- StackTraceElement trace[] = ((IStackTraceInfo)inputElement).getStackTrace();
- if (trace != null) {
- return trace;
- }
- }
-
- return new Object[0];
- }
-
- public void dispose() {
- // pass
- }
-
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- // pass
- }
- }
-
-
- /**
- * A Label Provider to use with {@link StackTraceContentProvider}. It expects the elements to be
- * of type {@link StackTraceElement}.
- */
- private static class StackTraceLabelProvider implements ITableLabelProvider {
-
- public Image getColumnImage(Object element, int columnIndex) {
- return null;
- }
-
- public String getColumnText(Object element, int columnIndex) {
- if (element instanceof StackTraceElement) {
- StackTraceElement traceElement = (StackTraceElement)element;
- switch (columnIndex) {
- case 0:
- return traceElement.getClassName();
- case 1:
- return traceElement.getMethodName();
- case 2:
- return traceElement.getFileName();
- case 3:
- return Integer.toString(traceElement.getLineNumber());
- case 4:
- return Boolean.toString(traceElement.isNativeMethod());
- }
- }
-
- return null;
- }
-
- public void addListener(ILabelProviderListener listener) {
- // pass
- }
-
- public void dispose() {
- // pass
- }
-
- public boolean isLabelProperty(Object element, String property) {
- // pass
- return false;
- }
-
- public void removeListener(ILabelProviderListener listener) {
- // pass
- }
- }
-
- /**
- * Classes which implement this interface provide a method that is able to reveal a method
- * in a source editor
- */
- public interface ISourceRevealer {
- /**
- * Sent to reveal a particular line in a source editor
- * @param applicationName the name of the application running the source.
- * @param className the fully qualified class name
- * @param line the line to reveal
- */
- public void reveal(String applicationName, String className, int line);
- }
-
-
- /**
- * Sets the {@link ISourceRevealer} object able to reveal source code in a source editor.
- * @param revealer
- */
- public static void setSourceRevealer(ISourceRevealer revealer) {
- sSourceRevealer = revealer;
- }
-
- /**
- * Creates the controls for the StrackTrace display.
- * <p/>This method will set the parent {@link Composite} to use a {@link GridLayout} with
- * 2 columns.
- * @param parent the parent composite.
- * @param prefs_stack_col_class
- * @param prefs_stack_col_method
- * @param prefs_stack_col_file
- * @param prefs_stack_col_line
- * @param prefs_stack_col_native
- * @param store
- */
- public Table createPanel(Composite parent, String prefs_stack_col_class,
- String prefs_stack_col_method, String prefs_stack_col_file, String prefs_stack_col_line,
- String prefs_stack_col_native, IPreferenceStore store) {
-
- mStackTraceTable = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION);
- mStackTraceTable.setHeaderVisible(true);
- mStackTraceTable.setLinesVisible(true);
-
- TableHelper.createTableColumn(
- mStackTraceTable,
- "Class",
- SWT.LEFT,
- "SomeLongClassName", //$NON-NLS-1$
- prefs_stack_col_class, store);
-
- TableHelper.createTableColumn(
- mStackTraceTable,
- "Method",
- SWT.LEFT,
- "someLongMethod", //$NON-NLS-1$
- prefs_stack_col_method, store);
-
- TableHelper.createTableColumn(
- mStackTraceTable,
- "File",
- SWT.LEFT,
- "android/somepackage/someotherpackage/somefile.class", //$NON-NLS-1$
- prefs_stack_col_file, store);
-
- TableHelper.createTableColumn(
- mStackTraceTable,
- "Line",
- SWT.RIGHT,
- "99999", //$NON-NLS-1$
- prefs_stack_col_line, store);
-
- TableHelper.createTableColumn(
- mStackTraceTable,
- "Native",
- SWT.LEFT,
- "Native", //$NON-NLS-1$
- prefs_stack_col_native, store);
-
- mStackTraceViewer = new TableViewer(mStackTraceTable);
- mStackTraceViewer.setContentProvider(new StackTraceContentProvider());
- mStackTraceViewer.setLabelProvider(new StackTraceLabelProvider());
-
- mStackTraceViewer.addDoubleClickListener(new IDoubleClickListener() {
- public void doubleClick(DoubleClickEvent event) {
- if (sSourceRevealer != null && mCurrentClient != null) {
- // get the selected stack trace element
- ISelection selection = mStackTraceViewer.getSelection();
-
- if (selection instanceof IStructuredSelection) {
- IStructuredSelection structuredSelection = (IStructuredSelection)selection;
- Object object = structuredSelection.getFirstElement();
- if (object instanceof StackTraceElement) {
- StackTraceElement traceElement = (StackTraceElement)object;
-
- if (traceElement.isNativeMethod() == false) {
- sSourceRevealer.reveal(
- mCurrentClient.getClientData().getClientDescription(),
- traceElement.getClassName(),
- traceElement.getLineNumber());
- }
- }
- }
- }
- }
- });
-
- return mStackTraceTable;
- }
-
- /**
- * Sets the input for the {@link TableViewer}.
- * @param input the {@link IStackTraceInfo} that will provide the viewer with the list of
- * {@link StackTraceElement}
- */
- public void setViewerInput(IStackTraceInfo input) {
- mStackTraceViewer.setInput(input);
- mStackTraceViewer.refresh();
- }
-
- /**
- * Sets the current client running the stack trace.
- * @param currentClient the {@link Client}.
- */
- public void setCurrentClient(Client currentClient) {
- mCurrentClient = currentClient;
- }
-}
package com.samsung.slp.common.connection.ddmuilib;
-import com.samsung.slp.common.connection.ddmlib.SyncService.ISyncProgressMonitor;
-
import org.eclipse.core.runtime.IProgressMonitor;
+import com.samsung.slp.sdblib.SyncService.ISyncProgressMonitor;
+
/**
* Implementation of the {@link ISyncProgressMonitor} wrapping an Eclipse {@link IProgressMonitor}.
*/
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib;
-
-import com.samsung.slp.common.connection.ddmuilib.ITableFocusListener.IFocusedTableActivator;
-
-import org.eclipse.swt.dnd.Clipboard;
-import org.eclipse.swt.dnd.TextTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableItem;
-
-import java.util.Arrays;
-
-/**
- * Base class for panel containing Table that need to support copy-paste-selectAll
- */
-public abstract class TablePanel extends ClientDisplayPanel {
- private ITableFocusListener mGlobalListener;
-
- /**
- * Sets a TableFocusListener which will be notified when one of the tables
- * gets or loses focus.
- *
- * @param listener
- */
- public final void setTableFocusListener(ITableFocusListener listener) {
- // record the global listener, to make sure table created after
- // this call will still be setup.
- mGlobalListener = listener;
-
- setTableFocusListener();
- }
-
- /**
- * Sets up the Table of object of the panel to work with the global listener.<br>
- * Default implementation does nothing.
- */
- protected void setTableFocusListener() {
-
- }
-
- /**
- * Sets up a Table object to notify the global Table Focus listener when it
- * gets or loses the focus.
- *
- * @param table the Table object.
- * @param colStart
- * @param colEnd
- */
- protected final void addTableToFocusListener(final Table table,
- final int colStart, final int colEnd) {
- // create the activator for this table
- final IFocusedTableActivator activator = new IFocusedTableActivator() {
- public void copy(Clipboard clipboard) {
- int[] selection = table.getSelectionIndices();
-
- // we need to sort the items to be sure.
- Arrays.sort(selection);
-
- // all lines must be concatenated.
- StringBuilder sb = new StringBuilder();
-
- // loop on the selection and output the file.
- for (int i : selection) {
- TableItem item = table.getItem(i);
- for (int c = colStart ; c <= colEnd ; c++) {
- sb.append(item.getText(c));
- sb.append('\t');
- }
- sb.append('\n');
- }
-
- // now add that to the clipboard if the string has content
- String data = sb.toString();
- if (data != null || data.length() > 0) {
- clipboard.setContents(
- new Object[] { data },
- new Transfer[] { TextTransfer.getInstance() });
- }
- }
-
- public void selectAll() {
- table.selectAll();
- }
- };
-
- // add the focus listener on the table to notify the global listener
- table.addFocusListener(new FocusListener() {
- public void focusGained(FocusEvent e) {
- mGlobalListener.focusGained(activator);
- }
-
- public void focusLost(FocusEvent e) {
- mGlobalListener.focusLost(activator);
- }
- });
- }
-
- /**
- * Sets up a Table object to notify the global Table Focus listener when it
- * gets or loses the focus.<br>
- * When the copy method is invoked, all columns are put in the clipboard, separated
- * by tabs
- *
- * @param table the Table object.
- */
- protected final void addTableToFocusListener(final Table table) {
- addTableToFocusListener(table, 0, table.getColumnCount()-1);
- }
-
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib.explorer;
-
-import com.samsung.slp.common.connection.ddmlib.FileListingService;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.IListingReceiver;
-
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Tree;
-
-/**
- * Content provider class for device Explorer.
- */
-public class DeviceContentProvider implements ITreeContentProvider {
-
- private TreeViewer mViewer;
- private FileListingService mFileListingService;
- private FileEntry mRootEntry;
-
- private IListingReceiver sListingReceiver = new IListingReceiver() {
- public void setChildren(final FileEntry entry, FileEntry[] children) {
- final Tree t = mViewer.getTree();
- if (t != null && t.isDisposed() == false) {
- Display display = t.getDisplay();
- if (display.isDisposed() == false) {
- display.asyncExec(new Runnable() {
- public void run() {
- if (t.isDisposed() == false) {
- // refresh the entry.
- mViewer.refresh(entry);
-
- // force it open, since on linux and windows
- // when getChildren() returns null, the node is
- // not considered expanded.
- mViewer.setExpandedState(entry, true);
- }
- }
- });
- }
- }
- }
-
- public void refreshEntry(final FileEntry entry) {
- final Tree t = mViewer.getTree();
- if (t != null && t.isDisposed() == false) {
- Display display = t.getDisplay();
- if (display.isDisposed() == false) {
- display.asyncExec(new Runnable() {
- public void run() {
- if (t.isDisposed() == false) {
- // refresh the entry.
- mViewer.refresh(entry);
- }
- }
- });
- }
- }
- }
- };
-
- /**
- *
- */
- public DeviceContentProvider() {
- }
-
- public void setListingService(FileListingService fls) {
- mFileListingService = fls;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
- */
- public Object[] getChildren(Object parentElement) {
- if (parentElement instanceof FileEntry) {
- FileEntry parentEntry = (FileEntry)parentElement;
-
- Object[] oldEntries = parentEntry.getCachedChildren();
- Object[] newEntries = mFileListingService.getChildren(parentEntry,
- true, sListingReceiver);
-
- if (newEntries != null) {
- return newEntries;
- } else {
- // if null was returned, this means the cache was not valid,
- // and a thread was launched for ls. sListingReceiver will be
- // notified with the new entries.
- return oldEntries;
- }
- }
- return new Object[0];
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
- */
- public Object getParent(Object element) {
- if (element instanceof FileEntry) {
- FileEntry entry = (FileEntry)element;
-
- return entry.getParent();
- }
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
- */
- public boolean hasChildren(Object element) {
- if (element instanceof FileEntry) {
- FileEntry entry = (FileEntry)element;
- if (entry.getType() == FileListingService.TYPE_LINK)
- return true;
- else
- return (entry.getType() == FileListingService.TYPE_DIRECTORY);
- }
- return false;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
- */
- public Object[] getElements(Object inputElement) {
- if (inputElement instanceof FileEntry) {
- FileEntry entry = (FileEntry)inputElement;
- if (entry.isRoot()) {
- return getChildren(mRootEntry);
- }
- }
-
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.IContentProvider#dispose()
- */
- public void dispose() {
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
- */
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- if (viewer instanceof TreeViewer) {
- mViewer = (TreeViewer)viewer;
- }
- if (newInput instanceof FileEntry) {
- mRootEntry = (FileEntry)newInput;
- }
- }
- public void setRootEntry(FileEntry fe) {
- mRootEntry = fe;
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib.explorer;
-
-import com.samsung.slp.common.connection.ddmlib.FileListingService;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.IShellOutputReceiver;
-import com.samsung.slp.common.connection.ddmlib.SyncService;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-import com.samsung.slp.common.connection.ddmlib.SyncService.ISyncProgressMonitor;
-import com.samsung.slp.common.connection.ddmlib.SyncService.SyncResult;
-import com.samsung.slp.common.connection.ddmuilib.DdmUiPreferences;
-import com.samsung.slp.common.connection.ddmuilib.ImageLoader;
-import com.samsung.slp.common.connection.ddmuilib.Panel;
-import com.samsung.slp.common.connection.ddmuilib.SyncProgressMonitor;
-import com.samsung.slp.common.connection.ddmuilib.TableHelper;
-import com.samsung.slp.common.connection.ddmuilib.actions.ICommonAction;
-import com.samsung.slp.common.connection.ddmuilib.console.DdmConsole;
-import com.samsung.slp.common.connection.ui.ConnectionExplorerContentProvider;
-import com.samsung.slp.common.connection.ui.ConnectionExplorerLabelProvider;
-
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.dialogs.ProgressMonitorDialog;
-import org.eclipse.jface.operation.IRunnableWithProgress;
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.ViewerDropAdapter;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.dnd.DND;
-import org.eclipse.swt.dnd.FileTransfer;
-import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.dnd.TransferData;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.DirectoryDialog;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeItem;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Device filesystem explorer class.
- */
-public class DeviceExplorer extends Panel {
-
- private final static String TRACE_KEY_EXT = ".key"; // $NON-NLS-1S
- private final static String TRACE_DATA_EXT = ".data"; // $NON-NLS-1S
-
- private static Pattern mKeyFilePattern = Pattern.compile("(.+)\\"
- + TRACE_KEY_EXT); // $NON-NLS-1S
- private static Pattern mDataFilePattern = Pattern.compile("(.+)\\"
- + TRACE_DATA_EXT); // $NON-NLS-1S
-
- public static String COLUMN_NAME = "android.explorer.name"; //$NON-NLS-1S
- public static String COLUMN_SIZE = "android.explorer.size"; //$NON-NLS-1S
- public static String COLUMN_DATE = "android.explorer.data"; //$NON-NLS-1S
- public static String COLUMN_TIME = "android.explorer.time"; //$NON-NLS-1S
- public static String COLUMN_PERMISSIONS = "android.explorer.permissions"; // $NON-NLS-1S
- public static String COLUMN_INFO = "android.explorer.info"; // $NON-NLS-1S
-
- private Composite mParent;
- private TreeViewer mTreeViewer;
- private Tree mTree;
- private ConnectionExplorerContentProvider mContentProvider;
-
- private ICommonAction mPushAction;
- private ICommonAction mPullAction;
- private ICommonAction mDeleteAction;
-
- private Image mFileImage;
- private Image mFolderImage;
- private Image mPackageImage;
- private Image mOtherImage;
-
- private IDevice mCurrentDevice;
-
- private String mDefaultSave;
-
- public DeviceExplorer() {
- }
-
- /**
- * Sets custom images for the device explorer. If none are set then defaults
- * are used. This can be useful to set platform-specific explorer icons.
- *
- * This should be called before {@link #createControl(Composite)}.
- *
- * @param fileImage
- * the icon to represent a file.
- * @param folderImage
- * the icon to represent a folder.
- * @param packageImage
- * the icon to represent an apk.
- * @param otherImage
- * the icon to represent other types of files.
- */
- public void setCustomImages(Image fileImage, Image folderImage,
- Image packageImage, Image otherImage) {
- mFileImage = fileImage;
- mFolderImage = folderImage;
- mPackageImage = packageImage;
- mOtherImage = otherImage;
- }
-
- /**
- * Sets the actions so that the device explorer can enable/disable them
- * based on the current selection
- *
- * @param pushAction
- * @param pullAction
- * @param deleteAction
- */
- public void setActions(ICommonAction pushAction, ICommonAction pullAction,
- ICommonAction deleteAction) {
- mPushAction = pushAction;
- mPullAction = pullAction;
- mDeleteAction = deleteAction;
- }
-
- /**
- * Creates a control capable of displaying some information. This is called
- * once, when the application is initializing, from the UI thread.
- */
- @Override
- protected Control createControl(Composite parent) {
- mParent = parent;
- parent.setLayout(new FillLayout());
-
- ImageLoader loader = ImageLoader.getDdmUiLibLoader();
- if (mFileImage == null) {
- mFileImage = loader.loadImage("file.gif", mParent.getDisplay());
- }
- if (mFolderImage == null) {
- mFolderImage = loader.loadImage("folder.gif", mParent.getDisplay());
- }
- if (mPackageImage == null) {
- mPackageImage = loader.loadImage("android.png",
- mParent.getDisplay());
- }
- if (mOtherImage == null) {
- // TODO: find a default image for other.
- }
-
- mTree = new Tree(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.VIRTUAL);
- mTree.setHeaderVisible(true);
-
- IPreferenceStore store = DdmUiPreferences.getStore();
-
- // create columns
- TableHelper.createTreeColumn(mTree, "Name", SWT.LEFT,
- "0000drwxrwxrwx", COLUMN_NAME, store); //$NON-NLS-1$
- TableHelper.createTreeColumn(mTree, "Size", SWT.RIGHT,
- "000000", COLUMN_SIZE, store); //$NON-NLS-1$
- TableHelper.createTreeColumn(mTree, "Date", SWT.LEFT,
- "2007-08-14", COLUMN_DATE, store); //$NON-NLS-1$
- TableHelper.createTreeColumn(mTree, "Time", SWT.LEFT,
- "20:54", COLUMN_TIME, store); //$NON-NLS-1$
- TableHelper.createTreeColumn(mTree, "Permissions", SWT.LEFT,
- "drwxrwxrwx", COLUMN_PERMISSIONS, store); //$NON-NLS-1$
- TableHelper.createTreeColumn(mTree, "Info", SWT.LEFT,
- "drwxrwxrwx", COLUMN_INFO, store); //$NON-NLS-1$
-
- // create the jface wrapper
- mTreeViewer = new TreeViewer(mTree);
-
- // setup data provider
- mContentProvider = new ConnectionExplorerContentProvider();
- mTreeViewer.setContentProvider(mContentProvider);
-// mTreeViewer.setLabelProvider(new ConnectionExplorerLabelProvider(mFileImage,
-// mFolderImage, mPackageImage, mOtherImage));
-
- // setup a listener for selection
- mTreeViewer
- .addSelectionChangedListener(new ISelectionChangedListener() {
- public void selectionChanged(SelectionChangedEvent event) {
- ISelection sel = event.getSelection();
- if (sel.isEmpty()) {
- mPullAction.setEnabled(false);
- mPushAction.setEnabled(false);
- mDeleteAction.setEnabled(false);
- return;
- }
- if (sel instanceof IStructuredSelection) {
- IStructuredSelection selection = (IStructuredSelection) sel;
- Object element = selection.getFirstElement();
- if (element == null)
- return;
- if (element instanceof FileEntry) {
- mPullAction.setEnabled(true);
- mPushAction.setEnabled(selection.size() == 1);
- if (selection.size() == 1) {
- setDeleteEnabledState((FileEntry) element);
- } else {
- mDeleteAction.setEnabled(false);
- }
- }
- }
- }
- });
-
- // add support for double click
- mTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
- public void doubleClick(DoubleClickEvent event) {
- ISelection sel = event.getSelection();
-
- if (sel instanceof IStructuredSelection) {
- IStructuredSelection selection = (IStructuredSelection) sel;
-
- if (selection.size() == 1) {
- FileEntry entry = (FileEntry) selection
- .getFirstElement();
- String name = entry.getName();
-
- FileEntry parentEntry = entry.getParent();
-
- // can't really do anything with no parent
- if (parentEntry == null) {
- return;
- }
-
- // check this is a file like we want.
- Matcher m = mKeyFilePattern.matcher(name);
- if (m.matches()) {
- // get the name w/o the extension
- String baseName = m.group(1);
-
- // add the data extension
- String dataName = baseName + TRACE_DATA_EXT;
-
- FileEntry dataEntry = parentEntry
- .findChild(dataName);
-
- handleTraceDoubleClick(baseName, entry, dataEntry);
-
- } else {
- m = mDataFilePattern.matcher(name);
- if (m.matches()) {
- // get the name w/o the extension
- String baseName = m.group(1);
-
- // add the key extension
- String keyName = baseName + TRACE_KEY_EXT;
-
- FileEntry keyEntry = parentEntry
- .findChild(keyName);
-
- handleTraceDoubleClick(baseName, keyEntry,
- entry);
- }
- }
- }
- }
- }
- });
-
- // setup drop listener
- mTreeViewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE,
- new Transfer[] { FileTransfer.getInstance() },
- new ViewerDropAdapter(mTreeViewer) {
- @Override
- public boolean performDrop(Object data) {
- // get the item on which we dropped the item(s)
- FileEntry target = (FileEntry) getCurrentTarget();
-
- // in case we drop at the same level as root
- if (target == null) {
- return false;
- }
-
- // if the target is not a directory, we get the parent
- // directory
- if (target.isDirectory() == false) {
- target = target.getParent();
- }
-
- if (target == null) {
- return false;
- }
-
- // get the list of files to drop
- String[] files = (String[]) data;
-
- // do the drop
- pushFiles(files, target);
-
- // we need to finish with a refresh
- refresh(target);
-
- return true;
- }
-
- @Override
- public boolean validateDrop(Object target, int operation,
- TransferData transferType) {
- if (target == null) {
- return false;
- }
-
- // convert to the real item
- FileEntry targetEntry = (FileEntry) target;
-
- // if the target is not a directory, we get the parent
- // directory
- if (targetEntry.isDirectory() == false) {
- target = targetEntry.getParent();
- }
-
- if (target == null) {
- return false;
- }
-
- return true;
- }
- });
-
- // create and start the refresh thread
- new Thread("Device Ls refresher") {
- @Override
- public void run() {
- while (true) {
- try {
- sleep(FileListingService.REFRESH_RATE);
- } catch (InterruptedException e) {
- return;
- }
-
- if (mTree != null && mTree.isDisposed() == false) {
- Display display = mTree.getDisplay();
- if (display.isDisposed() == false) {
- display.asyncExec(new Runnable() {
- public void run() {
- if (mTree.isDisposed() == false) {
- //TODO : SDB fixed
- //mTreeViewer.refresh(true);
- }
- }
- });
- } else {
- return;
- }
- } else {
- return;
- }
- }
-
- }
- }.start();
-
- return mTree;
- }
-
- @Override
- protected void postCreation() {
-
- }
-
- /**
- * Sets the focus to the proper control inside the panel.
- */
- @Override
- public void setFocus() {
- mTree.setFocus();
- }
-
- /**
- * Processes a double click on a trace file
- *
- * @param baseName
- * the base name of the 2 files.
- * @param keyEntry
- * The FileEntry for the .key file.
- * @param dataEntry
- * The FileEntry for the .data file.
- */
- private void handleTraceDoubleClick(String baseName, FileEntry keyEntry,
- FileEntry dataEntry) {
- // first we need to download the files.
- File keyFile;
- File dataFile;
- String path;
- try {
- // create a temp file for keyFile
- File f = File.createTempFile(baseName, ".trace");
- f.delete();
- f.mkdir();
-
- path = f.getAbsolutePath();
-
- keyFile = new File(path + File.separator + keyEntry.getName());
- dataFile = new File(path + File.separator + dataEntry.getName());
- } catch (IOException e) {
- return;
- }
-
- // download the files
- try {
- SyncService sync = mCurrentDevice.getSyncService();
- if (sync != null) {
- ISyncProgressMonitor monitor = SyncService
- .getNullProgressMonitor();
- SyncResult result = sync.pullFile(keyEntry,
- keyFile.getAbsolutePath(), monitor);
- if (result.getCode() != SyncService.RESULT_OK) {
- DdmConsole.printErrorToConsole(String.format(
- "Failed to pull %1$s: %2$s", keyEntry.getName(),
- result.getMessage()));
- return;
- }
-
- result = sync.pullFile(dataEntry, dataFile.getAbsolutePath(),
- monitor);
- if (result.getCode() != SyncService.RESULT_OK) {
- DdmConsole.printErrorToConsole(String.format(
- "Failed to pull %1$s: %2$s", dataEntry.getName(),
- result.getMessage()));
- return;
- }
-
- // now that we have the file, we need to launch traceview
- String[] command = new String[2];
- command[0] = DdmUiPreferences.getTraceview();
- command[1] = path + File.separator + baseName;
-
- try {
- final Process p = Runtime.getRuntime().exec(command);
-
- // create a thread for the output
- new Thread("Traceview output") {
- @Override
- public void run() {
- // create a buffer to read the stderr output
- InputStreamReader is = new InputStreamReader(
- p.getErrorStream());
- BufferedReader resultReader = new BufferedReader(is);
-
- // read the lines as they come. if null is returned,
- // it's
- // because the process finished
- try {
- while (true) {
- String line = resultReader.readLine();
- if (line != null) {
- DdmConsole
- .printErrorToConsole("Traceview: "
- + line);
- } else {
- break;
- }
- }
- // get the return code from the process
- p.waitFor();
- } catch (IOException e) {
- } catch (InterruptedException e) {
-
- }
- }
- }.start();
-
- } catch (IOException e) {
- }
- }
- } catch (IOException e) {
- DdmConsole.printErrorToConsole(String.format(
- "Failed to pull %1$s: %2$s", keyEntry.getName(),
- e.getMessage()));
- return;
- }
- }
-
- /**
- * Pull the current selection on the local drive. This method displays a
- * dialog box to let the user select where to store the file(s) and
- * folder(s).
- */
- public void pullSelection() {
- // get the selection
- TreeItem[] items = mTree.getSelection();
-
- // name of the single file pull, or null if we're pulling a directory
- // or more than one object.
- String filePullName = null;
- FileEntry singleEntry = null;
-
- // are we pulling a single file?
- if (items.length == 1) {
- singleEntry = (FileEntry) items[0].getData();
- if (singleEntry.getType() == FileListingService.TYPE_FILE) {
- filePullName = singleEntry.getName();
- }
- }
-
- // where do we save by default?
- String defaultPath = mDefaultSave;
- if (defaultPath == null) {
- defaultPath = System.getProperty("user.home"); //$NON-NLS-1$
- }
-
- if (filePullName != null) {
- FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.SAVE);
-
- fileDialog.setText("Get Device File");
- fileDialog.setFileName(filePullName);
- fileDialog.setFilterPath(defaultPath);
-
- String fileName = fileDialog.open();
- if (fileName != null) {
- mDefaultSave = fileDialog.getFilterPath();
-
- pullFile(singleEntry, fileName);
- }
- } else {
- DirectoryDialog directoryDialog = new DirectoryDialog(
- mParent.getShell(), SWT.SAVE);
-
- directoryDialog.setText("Get Device Files/Folders");
- directoryDialog.setFilterPath(defaultPath);
-
- String directoryName = directoryDialog.open();
- if (directoryName != null) {
- pullSelection(items, directoryName);
- }
- }
- }
-
- /**
- * Push new file(s) and folder(s) into the current selection. Current
- * selection must be single item. If the current selection is not a
- * directory, the parent directory is used. This method displays a dialog to
- * let the user choose file to push to the device.
- */
- public void pushIntoSelection() {
- // get the name of the object we're going to pull
- TreeItem[] items = mTree.getSelection();
-
- if (items.length == 0) {
- return;
- }
-
- FileDialog dlg = new FileDialog(mParent.getShell(), SWT.OPEN);
- String fileName;
-
- dlg.setText("Put File on Device");
-
- // There should be only one.
- FileEntry entry = (FileEntry) items[0].getData();
- dlg.setFileName(entry.getName());
-
- String defaultPath = mDefaultSave;
- if (defaultPath == null) {
- defaultPath = System.getProperty("user.home"); //$NON-NLS-1$
- }
- dlg.setFilterPath(defaultPath);
-
- fileName = dlg.open();
- if (fileName != null) {
- mDefaultSave = dlg.getFilterPath();
-
- // we need to figure out the remote path based on the current
- // selection type.
- String remotePath;
- FileEntry toRefresh = entry;
- if (entry.isDirectory()) {
- remotePath = entry.getFullPath();
- } else {
- toRefresh = entry.getParent();
- remotePath = toRefresh.getFullPath();
- }
-
- pushFile(fileName, remotePath);
- mTreeViewer.refresh(toRefresh);
- }
- }
-
- public void deleteSelection() {
- // get the name of the object we're going to pull
- TreeItem[] items = mTree.getSelection();
-
- if (items.length != 1) {
- return;
- }
-
- FileEntry entry = (FileEntry) items[0].getData();
- final FileEntry parentEntry = entry.getParent();
-
- // create the delete command
- String command = "rm " + entry.getFullEscapedPath(); //$NON-NLS-1$
-
- try {
- mCurrentDevice.executeShellCommand(command,
- new IShellOutputReceiver() {
- public void addOutput(byte[] data, int offset,
- int length) {
- // pass
- // TODO get output to display errors if any.
- }
-
- public void flush() {
- mTreeViewer.refresh(parentEntry);
- }
-
- public boolean isCancelled() {
- return false;
- }
- });
- } catch (IOException e) {
- // adb failed somehow, we do nothing. We should be displaying the
- // error from the output
- // of the shell command.
- }
-
- }
-
- /**
- * Force a full refresh of the explorer.
- */
- public void refresh() {
- mTreeViewer.refresh(true);
- }
-
-// /**
-// * Sets the new device to explorer
-// */
-// public void switchDevice(final IDevice device) {
-// if (device != mCurrentDevice) {
-// mCurrentDevice = device;
-// // now we change the input. but we need to do that in the
-// // ui thread.
-// if (mTree.isDisposed() == false) {
-// Display d = mTree.getDisplay();
-// d.asyncExec(new Runnable() {
-// public void run() {
-// if (mTree.isDisposed() == false) {
-// // new service
-// if (mCurrentDevice != null) {
-// FileListingService fls = mCurrentDevice
-// .getFileListingService();
-// mContentProvider.setListingService(fls);
-// mTreeViewer.setInput(fls.getRoot());
-// }
-// }
-// }
-// });
-// }
-// }
-// }
-
- /**
- * Refresh an entry from a non ui thread.
- *
- * @param entry
- * the entry to refresh.
- */
- private void refresh(final FileEntry entry) {
- Display d = mTreeViewer.getTree().getDisplay();
- d.asyncExec(new Runnable() {
- public void run() {
- mTreeViewer.refresh(entry);
- }
- });
- }
-
- /**
- * Pulls the selection from a device.
- *
- * @param items
- * the tree selection the remote file on the device
- * @param localDirector
- * the local directory in which to save the files.
- */
- private void pullSelection(TreeItem[] items, final String localDirectory) {
- try {
- final SyncService sync = mCurrentDevice.getSyncService();
- if (sync != null) {
- // make a list of the FileEntry.
- ArrayList<FileEntry> entries = new ArrayList<FileEntry>();
- for (TreeItem item : items) {
- Object data = item.getData();
- if (data instanceof FileEntry) {
- entries.add((FileEntry) data);
- }
- }
- final FileEntry[] entryArray = entries
- .toArray(new FileEntry[entries.size()]);
-
- // get a progressdialog
- new ProgressMonitorDialog(mParent.getShell()).run(true, true,
- new IRunnableWithProgress() {
- public void run(IProgressMonitor monitor)
- throws InvocationTargetException,
- InterruptedException {
- // create a monitor wrapper around the jface
- // monitor
- SyncResult result = sync
- .pull(entryArray,
- localDirectory,
- (ISyncProgressMonitor) new SyncProgressMonitor(
- monitor,
- "Pulling file(s) from the device"));
-
- if (result.getCode() != SyncService.RESULT_OK) {
- DdmConsole.printErrorToConsole(String
- .format("Failed to pull selection: %1$s",
- result.getMessage()));
- }
- sync.close();
- }
- });
- }
- } catch (Exception e) {
- DdmConsole.printErrorToConsole("Failed to pull selection");
- DdmConsole.printErrorToConsole(e.getMessage());
- }
- }
-
- /**
- * Pulls a file from a device.
- *
- * @param remote
- * the remote file on the device
- * @param local
- * the destination filepath
- */
- private void pullFile(final FileEntry remote, final String local) {
- try {
- final SyncService sync = mCurrentDevice.getSyncService();
- if (sync != null) {
- new ProgressMonitorDialog(mParent.getShell()).run(true, true,
- new IRunnableWithProgress() {
- public void run(IProgressMonitor monitor)
- throws InvocationTargetException,
- InterruptedException {
- SyncResult result = sync
- .pullFile(
- remote,
- local,
- (ISyncProgressMonitor) new SyncProgressMonitor(
- monitor,
- String.format(
- "Pulling %1$s from the device",
- remote.getName())));
- if (result.getCode() != SyncService.RESULT_OK) {
- DdmConsole.printErrorToConsole(String
- .format("Failed to pull %1$s: %2$s",
- remote, result.getMessage()));
- }
-
- sync.close();
- }
- });
- }
- } catch (Exception e) {
- DdmConsole.printErrorToConsole("Failed to pull selection");
- DdmConsole.printErrorToConsole(e.getMessage());
- }
- }
-
- /**
- * Pushes several files and directory into a remote directory.
- *
- * @param localFiles
- * @param remoteDirectory
- */
- private void pushFiles(final String[] localFiles,
- final FileEntry remoteDirectory) {
- try {
- final SyncService sync = mCurrentDevice.getSyncService();
- if (sync != null) {
- new ProgressMonitorDialog(mParent.getShell()).run(true, true,
- new IRunnableWithProgress() {
- public void run(IProgressMonitor monitor)
- throws InvocationTargetException,
- InterruptedException {
- SyncResult result = sync
- .push(localFiles,
- remoteDirectory,
- (ISyncProgressMonitor) new SyncProgressMonitor(
- monitor,
- "Pushing file(s) to the device"));
- if (result.getCode() != SyncService.RESULT_OK) {
- DdmConsole.printErrorToConsole(String
- .format("Failed to push the items: %1$s",
- result.getMessage()));
- }
-
- sync.close();
- }
- });
- }
- } catch (Exception e) {
- DdmConsole.printErrorToConsole("Failed to push the items");
- DdmConsole.printErrorToConsole(e.getMessage());
- }
- }
-
- /**
- * Pushes a file on a device.
- *
- * @param local
- * the local filepath of the file to push
- * @param remoteDirectory
- * the remote destination directory on the device
- */
- private void pushFile(final String local, final String remoteDirectory) {
- try {
- final SyncService sync = mCurrentDevice.getSyncService();
- if (sync != null) {
- new ProgressMonitorDialog(mParent.getShell()).run(true, true,
- new IRunnableWithProgress() {
- public void run(IProgressMonitor monitor)
- throws InvocationTargetException,
- InterruptedException {
- // get the file name
- String[] segs = local.split(Pattern
- .quote(File.separator));
- String name = segs[segs.length - 1];
- String remoteFile = remoteDirectory
- + FileListingService.FILE_SEPARATOR
- + name;
-
- SyncResult result = sync
- .pushFile(
- local,
- remoteFile,
- (ISyncProgressMonitor) new SyncProgressMonitor(
- monitor,
- String.format(
- "Pushing %1$s to the device.",
- name)));
- if (result.getCode() != SyncService.RESULT_OK) {
- DdmConsole.printErrorToConsole(String
- .format("Failed to push %1$s on %2$s: %3$s",
- name, mCurrentDevice
- .getSerialNumber(),
- result.getMessage()));
- }
-
- sync.close();
- }
- });
- }
- } catch (Exception e) {
- DdmConsole.printErrorToConsole("Failed to push the item(s).");
- DdmConsole.printErrorToConsole(e.getMessage());
- }
- }
-
- /**
- * Sets the enabled state based on a FileEntry properties
- *
- * @param element
- * The selected FileEntry
- */
- protected void setDeleteEnabledState(FileEntry element) {
- mDeleteAction
- .setEnabled(element.getType() == FileListingService.TYPE_FILE);
- }
-}
+++ /dev/null
-/*
- * 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.samsung.slp.common.connection.ddmuilib.explorer;
-
-import com.samsung.slp.common.connection.ddmlib.FileListingService;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.ILabelProviderListener;
-import org.eclipse.jface.viewers.ITableLabelProvider;
-import org.eclipse.swt.graphics.Image;
-
-/**
- * Label provider for the FileEntry.
- */
-class FileLabelProvider implements ILabelProvider, ITableLabelProvider {
-
- private Image mFileImage;
- private Image mFolderImage;
- private Image mPackageImage;
- private Image mOtherImage;
-
- /**
- * Creates Label provider with custom images.
- * @param fileImage the Image to represent a file
- * @param folderImage the Image to represent a folder
- * @param packageImage the Image to represent a .apk file. If null,
- * fileImage is used instead.
- * @param otherImage the Image to represent all other entry type.
- */
- public FileLabelProvider(Image fileImage, Image folderImage,
- Image packageImage, Image otherImage) {
- mFileImage = fileImage;
- mFolderImage = folderImage;
- mOtherImage = otherImage;
- if (packageImage != null) {
- mPackageImage = packageImage;
- } else {
- mPackageImage = fileImage;
- }
- }
-
- /**
- * Creates a label provider with default images.
- *
- */
- public FileLabelProvider() {
-
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
- */
- public Image getImage(Object element) {
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
- */
- public String getText(Object element) {
- return null;
- }
-
- public Image getColumnImage(Object element, int columnIndex) {
- if (columnIndex == 0) {
- if (element instanceof FileEntry) {
- FileEntry entry = (FileEntry)element;
- switch (entry.getType()) {
- case FileListingService.TYPE_FILE:
- case FileListingService.TYPE_LINK:
- // get the name and extension
- if (entry.isApplicationPackage()) {
- return mPackageImage;
- }
- return mFileImage;
- case FileListingService.TYPE_DIRECTORY:
- case FileListingService.TYPE_DIRECTORY_LINK:
- return mFolderImage;
- }
- }
-
- // default case return a different image.
- return mOtherImage;
- }
- return null;
- }
-
- public String getColumnText(Object element, int columnIndex) {
- if (element instanceof FileEntry) {
- FileEntry entry = (FileEntry)element;
-
- switch (columnIndex) {
- case 0:
- return entry.getName();
- case 1:
- return entry.getSize();
- case 2:
- return entry.getDate();
- case 3:
- return entry.getTime();
- case 4:
- return entry.getPermissions();
- case 5:
- return entry.getInfo();
- }
- }else if (element instanceof IDevice) {
- IDevice device = (IDevice)element;
- return device.getSerialNumber();
- }
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
- */
- public void addListener(ILabelProviderListener listener) {
- // we don't need listeners.
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
- */
- public void dispose() {
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
- */
- public boolean isLabelProperty(Object element, String property) {
- return false;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
- */
- public void removeListener(ILabelProviderListener listener) {
- // we don't need listeners
- }
-
-}
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.dialogs.PropertyPage;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
public class ConnectionExplorerInfoPropertyPages extends PropertyPage {
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.dialogs.PropertyPage;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
public class ConnectionExplorerPermissionPropertyPages extends PropertyPage {
import java.io.File;
import java.io.IOException;
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.ui.part.IDropActionDelegate;
import com.samsung.slp.common.connection.ConnectionActivator;
-import com.samsung.slp.common.connection.ddmlib.AdbCommandRejectedException;
-import com.samsung.slp.common.connection.ddmlib.SyncService;
-import com.samsung.slp.common.connection.ddmlib.SyncService.ISyncProgressMonitor;
-import com.samsung.slp.common.connection.ddmlib.SyncService.SyncResult;
-import com.samsung.slp.common.connection.ddmlib.TimeoutException;
import com.samsung.slp.common.connection.ddmuilib.FileDialogUtils;
import com.samsung.slp.common.connection.ddmuilib.console.DdmConsole;
+import com.samsung.slp.sdblib.SdbCommandRejectedException;
+import com.samsung.slp.sdblib.SyncService;
+import com.samsung.slp.sdblib.SyncService.ISyncProgressMonitor;
+import com.samsung.slp.sdblib.SyncService.SyncResult;
+import com.samsung.slp.sdblib.TimeoutException;
public class FileEntryDropAdapter implements IDropActionDelegate {
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
- } catch (AdbCommandRejectedException e) {
+ } catch (SdbCommandRejectedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
import org.eclipse.swt.dnd.ByteArrayTransfer;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-//Reference: http://www.eclipse.org/articles/Article-SWT-DND/DND-in-SWT.html
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
public class FileEntryTransfer extends ByteArrayTransfer {
import com.samsung.slp.common.connection.ConnectionActivator;
import com.samsung.slp.common.connection.ConnectionActivator.ISelectionListener;
-import com.samsung.slp.common.connection.ddmlib.FileListingService;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
import com.samsung.slp.common.connection.ddmuilib.FileDialogUtils;
import com.samsung.slp.common.connection.ddmuilib.ImageLoader;
-import com.samsung.slp.common.connection.ddmuilib.explorer.DeviceExplorer;
import com.samsung.slp.common.properties.InstallPathConfig;
import com.samsung.slp.common.util.HostUtil;
+import com.samsung.slp.sdblib.FileListingService;
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
+import com.samsung.slp.sdblib.IDevice;
public class ConnectionExplorer extends ViewPart implements ISelectionListener {
+ ".explorer.permissions"; //$NON-NLS-1S
private final static String COLUMN_INFO = ConnectionActivator.PLUGIN_ID
+ ".explorer.info"; //$NON-NLS-1$
-
+
private final static boolean USE_SELECTED_DEBUG_PORT = true;
private ConnectionExplorerPanel mPanel;
private ImageLoader mloader;
private void createFileExplorerView(Composite parent) {
- DeviceExplorer.COLUMN_NAME = COLUMN_NAME;
- DeviceExplorer.COLUMN_SIZE = COLUMN_SIZE;
- DeviceExplorer.COLUMN_DATE = COLUMN_DATE;
- DeviceExplorer.COLUMN_TIME = COLUMN_TIME;
- DeviceExplorer.COLUMN_PERMISSIONS = COLUMN_PERMISSIONS;
- DeviceExplorer.COLUMN_INFO = COLUMN_INFO;
+// DeviceExplorer.COLUMN_NAME = COLUMN_NAME;
+// DeviceExplorer.COLUMN_SIZE = COLUMN_SIZE;
+// DeviceExplorer.COLUMN_DATE = COLUMN_DATE;
+// DeviceExplorer.COLUMN_TIME = COLUMN_TIME;
+// DeviceExplorer.COLUMN_PERMISSIONS = COLUMN_PERMISSIONS;
+// DeviceExplorer.COLUMN_INFO = COLUMN_INFO;
// device explorer
mPanel = new ConnectionExplorerPanel();
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge;
-import com.samsung.slp.common.connection.ddmlib.FileListingService;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.IListingReceiver;
+import com.samsung.slp.sdblib.FileListingService;
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
+import com.samsung.slp.sdblib.FileListingService.IListingReceiver;
+import com.samsung.slp.sdblib.IDevice;
+import com.samsung.slp.sdblib.SmartDevelopmentBridge;
public class ConnectionExplorerContentProvider implements ITreeContentProvider {
@Override
public Object[] getElements(Object arg0) {
- IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
+ IDevice[] devices = SmartDevelopmentBridge.getBridge().getDevices();
FileEntry[] entries = new FileEntry[ devices.length ];
for( int i = 0; i < devices.length ; i++)
{
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
-import com.samsung.slp.common.connection.ddmlib.FileListingService;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
import com.samsung.slp.common.connection.ddmuilib.ImageLoader;
+import com.samsung.slp.sdblib.FileListingService;
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
+import com.samsung.slp.sdblib.IDevice;
public class ConnectionExplorerLabelProvider implements ITableLabelProvider {
import com.samsung.slp.common.connection.ConnectionActivator;
import com.samsung.slp.common.connection.ConnectionActivator.ISelectionListener;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener;
-import com.samsung.slp.common.connection.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
-import com.samsung.slp.common.connection.ddmlib.FileListingService;
-import com.samsung.slp.common.connection.ddmlib.FileListingService.FileEntry;
-import com.samsung.slp.common.connection.ddmlib.IDevice;
-import com.samsung.slp.common.connection.ddmlib.IShellOutputReceiver;
-import com.samsung.slp.common.connection.ddmlib.SyncService;
-import com.samsung.slp.common.connection.ddmlib.SyncService.ISyncProgressMonitor;
-import com.samsung.slp.common.connection.ddmlib.SyncService.SyncResult;
import com.samsung.slp.common.connection.ddmuilib.DdmUiPreferences;
import com.samsung.slp.common.connection.ddmuilib.Panel;
import com.samsung.slp.common.connection.ddmuilib.SyncProgressMonitor;
import com.samsung.slp.common.connection.ddmuilib.TableHelper;
import com.samsung.slp.common.connection.ddmuilib.console.DdmConsole;
import com.samsung.slp.common.connection.sdblib.dnd.FileEntryTransfer;
-
-public class ConnectionExplorerPanel extends Panel implements IDeviceChangeListener, IDebugBridgeChangeListener{
+import com.samsung.slp.sdblib.FileListingService;
+import com.samsung.slp.sdblib.FileListingService.FileEntry;
+import com.samsung.slp.sdblib.IDevice;
+import com.samsung.slp.sdblib.IShellOutputReceiver;
+import com.samsung.slp.sdblib.SmartDevelopmentBridge;
+import com.samsung.slp.sdblib.SmartDevelopmentBridge.IDebugBridgeChangeListener;
+import com.samsung.slp.sdblib.SmartDevelopmentBridge.IDeviceChangeListener;
+import com.samsung.slp.sdblib.SyncService;
+import com.samsung.slp.sdblib.SyncService.ISyncProgressMonitor;
+import com.samsung.slp.sdblib.SyncService.SyncResult;
+
+public class ConnectionExplorerPanel extends Panel implements SmartDevelopmentBridge.IDeviceChangeListener, SmartDevelopmentBridge.IDebugBridgeChangeListener{
private final static String TRACE_KEY_EXT = ".key"; // $NON-NLS-1S
private final static String TRACE_DATA_EXT = ".data"; // $NON-NLS-1S
public ConnectionExplorerPanel() {
- AndroidDebugBridge.addDebugBridgeChangeListener(this);
- AndroidDebugBridge.addDeviceChangeListener(this);
}
/**
@Override
protected void postCreation() {
- AndroidDebugBridge.init(false);
- AndroidDebugBridge.createBridge("/home/kenoz/sdb/sdb",true);
+ SmartDevelopmentBridge sdbBridge = SmartDevelopmentBridge.getBridge();
+ IDevice[] devices = null;
+ if ( sdbBridge != null )
+ {
+ devices = sdbBridge.getDevices();
+ }
+ if( devices.length != 0 )
+ {
+ for( IDevice device : devices )
+ {
+ this.deviceConnected(device);
+ }
+ }
+ SmartDevelopmentBridge.addDebugBridgeChangeListener(this);
+ SmartDevelopmentBridge.addDeviceChangeListener(this);
}
/**
}
/**
- * Sent when a new {@link AndroidDebugBridge} is started.
+ * Sent when a new {@link SmartDevelopmentBridge} is started.
* <p/>
* This is sent from a non UI thread.
- * @param bridge the new {@link AndroidDebugBridge} object.
+ * @param bridge the new {@link SmartDevelopmentBridge} object.
*
- * @see IDebugBridgeChangeListener#serverChanged(AndroidDebugBridge)
+ * @see IDebugBridgeChangeListener#serverChanged(SmartDevelopmentBridge)
*/
- public void bridgeChanged(final AndroidDebugBridge bridge) {
+ public void bridgeChanged(final SmartDevelopmentBridge bridge) {
if (mTree.isDisposed() == false) {
exec(new Runnable() {
public void run() {
} else {
// tree is disposed, we need to do something.
// lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
}
}
});
// }
/**
- * Sent when the a device is connected to the {@link AndroidDebugBridge}.
+ * Sent when the a device is connected to the {@link SmartDevelopmentBridge}.
* <p/>
* This is sent from a non UI thread.
* @param device the new device.
} else {
// tree is disposed, we need to do something.
// lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
}
}
});
} else {
// tree is disposed, we need to do something.
// lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
}
}
});
display.asyncExec(runnable);
} catch (SWTException e) {
// tree is disposed, we need to do something. lets remove ourselves from the listener.
- AndroidDebugBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
- AndroidDebugBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDebugBridgeChangeListener(ConnectionExplorerPanel.this);
+ SmartDevelopmentBridge.removeDeviceChangeListener(ConnectionExplorerPanel.this);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
+ <classpathentry exported="true" kind="lib" path="sdblib.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: SLP SDK Common
-Bundle-SymbolicName: com.samsung.slp.common
+Bundle-SymbolicName: com.samsung.slp.common;singleton:=true
Bundle-Version: 1.3.20.qualifier
Bundle-Vendor: Samsung Electronics
Require-Bundle: org.eclipse.ui,
com.samsung.slp.common.model,
com.samsung.slp.common.properties,
com.samsung.slp.common.swt,
- com.samsung.slp.common.util
+ com.samsung.slp.common.util,
+ com.samsung.slp.sdblib
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: org.eclipse.jface.text,
org.eclipse.ui.console
Bundle-Activator: com.samsung.slp.common.Activator
Bundle-ActivationPolicy: lazy
+Bundle-ClassPath: sdblib.jar,
+ .
source.. = src/\r
output.. = bin/\r
bin.includes = META-INF/,\\r
- .\rjavacSource = 1.6
+ .,\\r
+ plugin.xml,\\r
+ sdblib.jar\r
+javacSource = 1.6
javacTarget = 1.6
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
+import com.samsung.slp.common.properties.InstallPathConfig;
+import com.samsung.slp.sdblib.SmartDevelopmentBridge;
+
/**
* Log.
* @author Changhyun Lee {@literal <changhyun1.lee@samsung.com>} (S-Core)
* The constructor
*/
public Activator() {
+ SmartDevelopmentBridge.init();
+ String sdbPath = InstallPathConfig.getSDKPath() + "/SDK/sdb/sdb";
+ SmartDevelopmentBridge.createBridge(sdbPath,true);
}
/*