Add AdbTest sample program
This sample implements the "adb logcat" command using USB host APIs. Change-Id: Ifbf122e99358bd3a1cd2a7967c364ffd59f003b3 Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
12
samples/USB/AdbTest/Android.mk
Normal file
12
samples/USB/AdbTest/Android.mk
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := samples
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := AdbTest
|
||||||
|
|
||||||
|
LOCAL_SDK_VERSION := current
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
24
samples/USB/AdbTest/AndroidManifest.xml
Normal file
24
samples/USB/AdbTest/AndroidManifest.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.adb">
|
||||||
|
|
||||||
|
<uses-feature android:name="android.hardware.usb.host" />
|
||||||
|
<uses-sdk android:minSdkVersion="12" />
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<activity android:name="AdbTestActivity" android:label="ADB Test">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||||
|
android:resource="@xml/device_filter" />
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
11
samples/USB/AdbTest/README.txt
Normal file
11
samples/USB/AdbTest/README.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
AdbTest is a sample program that implements a subset of the adb USB protocol.
|
||||||
|
Currently it only implements the "adb logcat" command and displays the log
|
||||||
|
output in a text view and only allows connecting to one device at a time.
|
||||||
|
However the support classes are structured in a way that would allow
|
||||||
|
connecting to multiple devices and running multiple adb commands simultaneously.
|
||||||
|
|
||||||
|
This program serves as an example of the following USB host features:
|
||||||
|
|
||||||
|
- Matching devices based on interface class, subclass and protocol (see device_filter.xml)
|
||||||
|
|
||||||
|
- Asynchronous IO on bulk endpoints
|
||||||
13
samples/USB/AdbTest/_index.html
Normal file
13
samples/USB/AdbTest/_index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<p>AdbTest is a sample program that implements a subset of the <code>adb</code> USB protocol.
|
||||||
|
Currently it only implements the <code>adb logcat</code> command and displays the log
|
||||||
|
output in a text view and only allows connecting to one device at a time.
|
||||||
|
However, the support classes are structured in a way that would allow
|
||||||
|
connecting to multiple devices and running multiple <code>adb</code> commands simultaneously.</p>
|
||||||
|
|
||||||
|
<p>This program serves as an example of the following USB host features:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Matching devices based on interface class, subclass and protocol (see <code>device_filter.xml</code>)</li>
|
||||||
|
|
||||||
|
<li>Asynchronous IO on bulk endpoints</li>
|
||||||
|
</ul>
|
||||||
11
samples/USB/AdbTest/default.properties
Normal file
11
samples/USB/AdbTest/default.properties
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system use,
|
||||||
|
# "build.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-12
|
||||||
33
samples/USB/AdbTest/res/layout/adb.xml
Normal file
33
samples/USB/AdbTest/res/layout/adb.xml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/log"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="25dp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="#ffffffff"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
18
samples/USB/AdbTest/res/xml/device_filter.xml
Normal file
18
samples/USB/AdbTest/res/xml/device_filter.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<usb-device class="255" subclass="66" protocol="1" />
|
||||||
|
</resources>
|
||||||
253
samples/USB/AdbTest/src/com/android/adb/AdbDevice.java
Normal file
253
samples/USB/AdbTest/src/com/android/adb/AdbDevice.java
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.adb;
|
||||||
|
|
||||||
|
import android.hardware.usb.UsbConstants;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
|
import android.hardware.usb.UsbEndpoint;
|
||||||
|
import android.hardware.usb.UsbInterface;
|
||||||
|
import android.hardware.usb.UsbRequest;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
/* This class represents a USB device that supports the adb protocol. */
|
||||||
|
public class AdbDevice {
|
||||||
|
|
||||||
|
private final AdbTestActivity mActivity;
|
||||||
|
private final UsbDeviceConnection mDeviceConnection;
|
||||||
|
private final UsbEndpoint mEndpointOut;
|
||||||
|
private final UsbEndpoint mEndpointIn;
|
||||||
|
|
||||||
|
private String mSerial;
|
||||||
|
|
||||||
|
// pool of requests for the OUT endpoint
|
||||||
|
private final LinkedList<UsbRequest> mOutRequestPool = new LinkedList<UsbRequest>();
|
||||||
|
// pool of requests for the IN endpoint
|
||||||
|
private final LinkedList<UsbRequest> mInRequestPool = new LinkedList<UsbRequest>();
|
||||||
|
// list of currently opened sockets
|
||||||
|
private final SparseArray<AdbSocket> mSockets = new SparseArray<AdbSocket>();
|
||||||
|
private int mNextSocketId = 1;
|
||||||
|
|
||||||
|
private final WaiterThread mWaiterThread = new WaiterThread();
|
||||||
|
|
||||||
|
public AdbDevice(AdbTestActivity activity, UsbDeviceConnection connection,
|
||||||
|
UsbInterface intf) {
|
||||||
|
mActivity = activity;
|
||||||
|
mDeviceConnection = connection;
|
||||||
|
mSerial = connection.getSerial();
|
||||||
|
|
||||||
|
UsbEndpoint epOut = null;
|
||||||
|
UsbEndpoint epIn = null;
|
||||||
|
// look for our bulk endpoints
|
||||||
|
for (int i = 0; i < intf.getEndpointCount(); i++) {
|
||||||
|
UsbEndpoint ep = intf.getEndpoint(i);
|
||||||
|
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
||||||
|
if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
|
||||||
|
epOut = ep;
|
||||||
|
} else {
|
||||||
|
epIn = ep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (epOut == null || epIn == null) {
|
||||||
|
throw new IllegalArgumentException("not all endpoints found");
|
||||||
|
}
|
||||||
|
mEndpointOut = epOut;
|
||||||
|
mEndpointIn = epIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return device serial number
|
||||||
|
public String getSerial() {
|
||||||
|
return mSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get an OUT request from our pool
|
||||||
|
public UsbRequest getOutRequest() {
|
||||||
|
synchronized(mOutRequestPool) {
|
||||||
|
if (mOutRequestPool.isEmpty()) {
|
||||||
|
UsbRequest request = new UsbRequest();
|
||||||
|
request.initialize(mDeviceConnection, mEndpointOut);
|
||||||
|
return request;
|
||||||
|
} else {
|
||||||
|
return mOutRequestPool.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return an OUT request to the pool
|
||||||
|
public void releaseOutRequest(UsbRequest request) {
|
||||||
|
synchronized (mOutRequestPool) {
|
||||||
|
mOutRequestPool.add(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get an IN request from the pool
|
||||||
|
public UsbRequest getInRequest() {
|
||||||
|
synchronized(mInRequestPool) {
|
||||||
|
if (mInRequestPool.isEmpty()) {
|
||||||
|
UsbRequest request = new UsbRequest();
|
||||||
|
request.initialize(mDeviceConnection, mEndpointIn);
|
||||||
|
return request;
|
||||||
|
} else {
|
||||||
|
return mInRequestPool.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
mWaiterThread.start();
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdbSocket openSocket(String destination) {
|
||||||
|
AdbSocket socket;
|
||||||
|
synchronized (mSockets) {
|
||||||
|
int id = mNextSocketId++;
|
||||||
|
socket = new AdbSocket(this, id);
|
||||||
|
mSockets.put(id, socket);
|
||||||
|
}
|
||||||
|
if (socket.open(destination)) {
|
||||||
|
return socket;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AdbSocket getSocket(int id) {
|
||||||
|
synchronized (mSockets) {
|
||||||
|
return mSockets.get(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void socketClosed(AdbSocket socket) {
|
||||||
|
synchronized (mSockets) {
|
||||||
|
mSockets.remove(socket.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a connect command
|
||||||
|
private void connect() {
|
||||||
|
AdbMessage message = new AdbMessage();
|
||||||
|
message.set(AdbMessage.A_CNXN, AdbMessage.A_VERSION, AdbMessage.MAX_PAYLOAD, "host::\0");
|
||||||
|
message.write(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle connect response
|
||||||
|
private void handleConnect(AdbMessage message) {
|
||||||
|
if (message.getDataString().startsWith("device:")) {
|
||||||
|
log("connected");
|
||||||
|
mActivity.deviceOnline(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
synchronized (mWaiterThread) {
|
||||||
|
mWaiterThread.mStop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dispatch a message from the device
|
||||||
|
void dispatchMessage(AdbMessage message) {
|
||||||
|
int command = message.getCommand();
|
||||||
|
switch (command) {
|
||||||
|
case AdbMessage.A_SYNC:
|
||||||
|
log("got A_SYNC");
|
||||||
|
break;
|
||||||
|
case AdbMessage.A_CNXN:
|
||||||
|
handleConnect(message);
|
||||||
|
break;
|
||||||
|
case AdbMessage.A_OPEN:
|
||||||
|
case AdbMessage.A_OKAY:
|
||||||
|
case AdbMessage.A_CLSE:
|
||||||
|
case AdbMessage.A_WRTE:
|
||||||
|
AdbSocket socket = getSocket(message.getArg1());
|
||||||
|
if (socket == null) {
|
||||||
|
log("ERROR socket not found");
|
||||||
|
} else {
|
||||||
|
socket.handleMessage(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(String s) {
|
||||||
|
mActivity.log(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class WaiterThread extends Thread {
|
||||||
|
public boolean mStop;
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
// start out with a command read
|
||||||
|
AdbMessage currentCommand = new AdbMessage();
|
||||||
|
AdbMessage currentData = null;
|
||||||
|
// FIXME error checking
|
||||||
|
currentCommand.readCommand(getInRequest());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (mStop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UsbRequest request = mDeviceConnection.requestWait();
|
||||||
|
if (request == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdbMessage message = (AdbMessage)request.getClientData();
|
||||||
|
request.setClientData(null);
|
||||||
|
AdbMessage messageToDispatch = null;
|
||||||
|
|
||||||
|
if (message == currentCommand) {
|
||||||
|
int dataLength = message.getDataLength();
|
||||||
|
// read data if length > 0
|
||||||
|
if (dataLength > 0) {
|
||||||
|
message.readData(getInRequest(), dataLength);
|
||||||
|
currentData = message;
|
||||||
|
} else {
|
||||||
|
messageToDispatch = message;
|
||||||
|
}
|
||||||
|
currentCommand = null;
|
||||||
|
} else if (message == currentData) {
|
||||||
|
messageToDispatch = message;
|
||||||
|
currentData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageToDispatch != null) {
|
||||||
|
// queue another read first
|
||||||
|
currentCommand = new AdbMessage();
|
||||||
|
currentCommand.readCommand(getInRequest());
|
||||||
|
|
||||||
|
// then dispatch the current message
|
||||||
|
dispatchMessage(messageToDispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// put request back into the appropriate pool
|
||||||
|
if (request.getEndpoint() == mEndpointOut) {
|
||||||
|
releaseOutRequest(request);
|
||||||
|
} else {
|
||||||
|
synchronized (mInRequestPool) {
|
||||||
|
mInRequestPool.add(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
170
samples/USB/AdbTest/src/com/android/adb/AdbMessage.java
Normal file
170
samples/USB/AdbTest/src/com/android/adb/AdbMessage.java
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.adb;
|
||||||
|
|
||||||
|
import android.hardware.usb.UsbRequest;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
/* This class encapsulates and adb command packet */
|
||||||
|
public class AdbMessage {
|
||||||
|
|
||||||
|
// command names
|
||||||
|
public static final int A_SYNC = 0x434e5953;
|
||||||
|
public static final int A_CNXN = 0x4e584e43;
|
||||||
|
public static final int A_OPEN = 0x4e45504f;
|
||||||
|
public static final int A_OKAY = 0x59414b4f;
|
||||||
|
public static final int A_CLSE = 0x45534c43;
|
||||||
|
public static final int A_WRTE = 0x45545257;
|
||||||
|
|
||||||
|
// ADB protocol version
|
||||||
|
public static final int A_VERSION = 0x01000000;
|
||||||
|
|
||||||
|
public static final int MAX_PAYLOAD = 4096;
|
||||||
|
|
||||||
|
private final ByteBuffer mMessageBuffer;
|
||||||
|
private final ByteBuffer mDataBuffer;
|
||||||
|
|
||||||
|
public AdbMessage() {
|
||||||
|
mMessageBuffer = ByteBuffer.allocate(24);
|
||||||
|
mDataBuffer = ByteBuffer.allocate(MAX_PAYLOAD);
|
||||||
|
mMessageBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
mDataBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets the fields in the command header
|
||||||
|
public void set(int command, int arg0, int arg1, byte[] data) {
|
||||||
|
mMessageBuffer.putInt(0, command);
|
||||||
|
mMessageBuffer.putInt(4, arg0);
|
||||||
|
mMessageBuffer.putInt(8, arg1);
|
||||||
|
mMessageBuffer.putInt(12, (data == null ? 0 : data.length));
|
||||||
|
mMessageBuffer.putInt(16, (data == null ? 0 : checksum(data)));
|
||||||
|
mMessageBuffer.putInt(20, command ^ 0xFFFFFFFF);
|
||||||
|
if (data != null) {
|
||||||
|
mDataBuffer.put(data, 0, data.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int command, int arg0, int arg1) {
|
||||||
|
set(command, arg0, arg1, (byte[])null);
|
||||||
|
}
|
||||||
|
public void set(int command, int arg0, int arg1, String data) {
|
||||||
|
// add trailing zero
|
||||||
|
data += "\0";
|
||||||
|
set(command, arg0, arg1, data.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the command's message ID
|
||||||
|
public int getCommand() {
|
||||||
|
return mMessageBuffer.getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns command's first argument
|
||||||
|
public int getArg0() {
|
||||||
|
return mMessageBuffer.getInt(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns command's second argument
|
||||||
|
public int getArg1() {
|
||||||
|
return mMessageBuffer.getInt(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns command's data buffer
|
||||||
|
public ByteBuffer getData() {
|
||||||
|
return mDataBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns command's data length
|
||||||
|
public int getDataLength() {
|
||||||
|
return mMessageBuffer.getInt(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns command's data as a string
|
||||||
|
public String getDataString() {
|
||||||
|
int length = getDataLength();
|
||||||
|
if (length == 0) return null;
|
||||||
|
// trim trailing zero
|
||||||
|
return new String(mDataBuffer.array(), 0, length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean write(AdbDevice device) {
|
||||||
|
synchronized (device) {
|
||||||
|
UsbRequest request = device.getOutRequest();
|
||||||
|
request.setClientData(this);
|
||||||
|
if (request.queue(mMessageBuffer, 24)) {
|
||||||
|
int length = getDataLength();
|
||||||
|
if (length > 0) {
|
||||||
|
request = device.getOutRequest();
|
||||||
|
request.setClientData(this);
|
||||||
|
if (request.queue(mDataBuffer, length)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
device.releaseOutRequest(request);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
device.releaseOutRequest(request);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean readCommand(UsbRequest request) {
|
||||||
|
request.setClientData(this);
|
||||||
|
return request.queue(mMessageBuffer, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean readData(UsbRequest request, int length) {
|
||||||
|
request.setClientData(this);
|
||||||
|
return request.queue(mDataBuffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String extractString(ByteBuffer buffer, int offset, int length) {
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
bytes[i] = buffer.get(offset++);
|
||||||
|
}
|
||||||
|
return new String(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String commandName = extractString(mMessageBuffer, 0, 4);
|
||||||
|
int dataLength = getDataLength();
|
||||||
|
String result = "Adb Message: " + commandName + " arg0: " + getArg0() +
|
||||||
|
" arg1: " + getArg1() + " dataLength: " + dataLength;
|
||||||
|
if (dataLength > 0) {
|
||||||
|
result += (" data: \"" + getDataString() + "\"");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int checksum(byte[] data) {
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
int x = data[i];
|
||||||
|
// dang, no unsigned ints in java
|
||||||
|
if (x < 0) x += 256;
|
||||||
|
result += x;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
75
samples/USB/AdbTest/src/com/android/adb/AdbSocket.java
Normal file
75
samples/USB/AdbTest/src/com/android/adb/AdbSocket.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.adb;
|
||||||
|
|
||||||
|
/* This class represents an adb socket. adb supports multiple independent
|
||||||
|
* socket connections to a single device. Typically a socket is created
|
||||||
|
* for each adb command that is executed.
|
||||||
|
*/
|
||||||
|
public class AdbSocket {
|
||||||
|
|
||||||
|
private final AdbDevice mDevice;
|
||||||
|
private final int mId;
|
||||||
|
private int mPeerId;
|
||||||
|
|
||||||
|
public AdbSocket(AdbDevice device, int id) {
|
||||||
|
mDevice = device;
|
||||||
|
mId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean open(String destination) {
|
||||||
|
AdbMessage message = new AdbMessage();
|
||||||
|
message.set(AdbMessage.A_OPEN, mId, 0, destination);
|
||||||
|
if (! message.write(mDevice)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleMessage(AdbMessage message) {
|
||||||
|
switch (message.getCommand()) {
|
||||||
|
case AdbMessage.A_OKAY:
|
||||||
|
mPeerId = message.getArg0();
|
||||||
|
synchronized (this) {
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AdbMessage.A_WRTE:
|
||||||
|
mDevice.log(message.getDataString());
|
||||||
|
sendReady();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendReady() {
|
||||||
|
AdbMessage message = new AdbMessage();
|
||||||
|
message.set(AdbMessage.A_OKAY, mId, mPeerId);
|
||||||
|
message.write(mDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
211
samples/USB/AdbTest/src/com/android/adb/AdbTestActivity.java
Normal file
211
samples/USB/AdbTest/src/com/android/adb/AdbTestActivity.java
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.adb;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
|
import android.hardware.usb.UsbInterface;
|
||||||
|
import android.hardware.usb.UsbManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
/* Main activity for the adb test program */
|
||||||
|
public class AdbTestActivity extends Activity {
|
||||||
|
|
||||||
|
private static final String TAG = "AdbTestActivity";
|
||||||
|
|
||||||
|
private TextView mLog;
|
||||||
|
private UsbManager mManager;
|
||||||
|
private UsbDevice mDevice;
|
||||||
|
private UsbDeviceConnection mDeviceConnection;
|
||||||
|
private UsbInterface mInterface;
|
||||||
|
private AdbDevice mAdbDevice;
|
||||||
|
|
||||||
|
private static final int MESSAGE_LOG = 1;
|
||||||
|
private static final int MESSAGE_DEVICE_ONLINE = 2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.adb);
|
||||||
|
mLog = (TextView)findViewById(R.id.log);
|
||||||
|
|
||||||
|
mManager = (UsbManager)getSystemService(Context.USB_SERVICE);
|
||||||
|
|
||||||
|
// check for existing devices
|
||||||
|
for (UsbDevice device : mManager.getDeviceList().values()) {
|
||||||
|
UsbInterface intf = findAdbInterface(device);
|
||||||
|
if (setAdbInterface(device, intf)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// listen for new devices
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
|
||||||
|
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
|
||||||
|
registerReceiver(mUsbReceiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
unregisterReceiver(mUsbReceiver);
|
||||||
|
setAdbInterface(null, null);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(String s) {
|
||||||
|
Message m = Message.obtain(mHandler, MESSAGE_LOG);
|
||||||
|
m.obj = s;
|
||||||
|
mHandler.sendMessage(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendLog(String text) {
|
||||||
|
Rect r = new Rect();
|
||||||
|
mLog.getDrawingRect(r);
|
||||||
|
int maxLines = r.height() / mLog.getLineHeight() - 1;
|
||||||
|
text = mLog.getText() + "\n" + text;
|
||||||
|
|
||||||
|
// see how many lines we have
|
||||||
|
int index = text.lastIndexOf('\n');
|
||||||
|
int count = 0;
|
||||||
|
while (index > 0 && count <= maxLines) {
|
||||||
|
count++;
|
||||||
|
index = text.lastIndexOf('\n', index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate to maxLines
|
||||||
|
if (index > 0) {
|
||||||
|
text = text.substring(index + 1);
|
||||||
|
}
|
||||||
|
mLog.setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deviceOnline(AdbDevice device) {
|
||||||
|
Message m = Message.obtain(mHandler, MESSAGE_DEVICE_ONLINE);
|
||||||
|
m.obj = device;
|
||||||
|
mHandler.sendMessage(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDeviceOnline(AdbDevice device) {
|
||||||
|
log("device online: " + device.getSerial());
|
||||||
|
device.openSocket("shell:exec logcat");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the current USB device and interface
|
||||||
|
private boolean setAdbInterface(UsbDevice device, UsbInterface intf) {
|
||||||
|
if (mDeviceConnection != null) {
|
||||||
|
if (mInterface != null) {
|
||||||
|
mDeviceConnection.releaseInterface(mInterface);
|
||||||
|
mInterface = null;
|
||||||
|
}
|
||||||
|
mDeviceConnection.close();
|
||||||
|
mDevice = null;
|
||||||
|
mDeviceConnection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device != null && intf != null) {
|
||||||
|
UsbDeviceConnection connection = mManager.openDevice(device);
|
||||||
|
if (connection != null) {
|
||||||
|
log("open succeeded");
|
||||||
|
if (connection.claimInterface(intf, false)) {
|
||||||
|
log("claim interface succeeded");
|
||||||
|
mDevice = device;
|
||||||
|
mDeviceConnection = connection;
|
||||||
|
mInterface = intf;
|
||||||
|
mAdbDevice = new AdbDevice(this, mDeviceConnection, intf);
|
||||||
|
log("call start");
|
||||||
|
mAdbDevice.start();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log("claim interface failed");
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log("open failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDeviceConnection == null && mAdbDevice != null) {
|
||||||
|
mAdbDevice.stop();
|
||||||
|
mAdbDevice = null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// searches for an adb interface on the given USB device
|
||||||
|
static private UsbInterface findAdbInterface(UsbDevice device) {
|
||||||
|
Log.d(TAG, "findAdbInterface " + device);
|
||||||
|
int count = device.getInterfaceCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
UsbInterface intf = device.getInterface(i);
|
||||||
|
if (intf.getInterfaceClass() == 255 && intf.getInterfaceSubclass() == 66 &&
|
||||||
|
intf.getInterfaceProtocol() == 1) {
|
||||||
|
return intf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
|
||||||
|
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
|
||||||
|
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||||
|
UsbInterface intf = findAdbInterface(device);
|
||||||
|
if (intf != null) {
|
||||||
|
log("Found adb interface " + intf);
|
||||||
|
setAdbInterface(device, intf);
|
||||||
|
}
|
||||||
|
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
|
||||||
|
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||||
|
String deviceName = device.getDeviceName();
|
||||||
|
if (mDevice != null && mDevice.equals(deviceName)) {
|
||||||
|
log("adb interface removed");
|
||||||
|
setAdbInterface(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Handler mHandler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case MESSAGE_LOG:
|
||||||
|
appendLog((String)msg.obj);
|
||||||
|
break;
|
||||||
|
case MESSAGE_DEVICE_ONLINE:
|
||||||
|
handleDeviceOnline((AdbDevice)msg.obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user