1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adb;
18 
19 import android.hardware.usb.UsbRequest;
20 
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 
24 /* This class encapsulates and adb command packet */
25 public class AdbMessage {
26 
27     // command names
28     public static final int A_SYNC = 0x434e5953;
29     public static final int A_CNXN = 0x4e584e43;
30     public static final int A_OPEN = 0x4e45504f;
31     public static final int A_OKAY = 0x59414b4f;
32     public static final int A_CLSE = 0x45534c43;
33     public static final int A_WRTE = 0x45545257;
34 
35     // ADB protocol version
36     public static final int A_VERSION = 0x01000000;
37 
38     public static final int MAX_PAYLOAD = 4096;
39 
40     private final ByteBuffer mMessageBuffer;
41     private final ByteBuffer mDataBuffer;
42 
AdbMessage()43     public AdbMessage() {
44         mMessageBuffer = ByteBuffer.allocate(24);
45         mDataBuffer = ByteBuffer.allocate(MAX_PAYLOAD);
46         mMessageBuffer.order(ByteOrder.LITTLE_ENDIAN);
47         mDataBuffer.order(ByteOrder.LITTLE_ENDIAN);
48     }
49 
50     // sets the fields in the command header
set(int command, int arg0, int arg1, byte[] data)51     public void set(int command, int arg0, int arg1, byte[] data) {
52         mMessageBuffer.putInt(0, command);
53         mMessageBuffer.putInt(4, arg0);
54         mMessageBuffer.putInt(8, arg1);
55         mMessageBuffer.putInt(12, (data == null ? 0 : data.length));
56         mMessageBuffer.putInt(16, (data == null ? 0 : checksum(data)));
57         mMessageBuffer.putInt(20, command ^ 0xFFFFFFFF);
58         if (data != null) {
59             mDataBuffer.put(data, 0, data.length);
60         }
61     }
62 
set(int command, int arg0, int arg1)63     public void set(int command, int arg0, int arg1) {
64         set(command, arg0, arg1, (byte[])null);
65     }
set(int command, int arg0, int arg1, String data)66     public void set(int command, int arg0, int arg1, String data) {
67         // add trailing zero
68         data += "\0";
69         set(command, arg0, arg1, data.getBytes());
70     }
71 
72     // returns the command's message ID
getCommand()73     public int getCommand() {
74         return mMessageBuffer.getInt(0);
75     }
76 
77     // returns command's first argument
getArg0()78     public int getArg0() {
79         return mMessageBuffer.getInt(4);
80     }
81 
82     // returns command's second argument
getArg1()83     public int getArg1() {
84         return mMessageBuffer.getInt(8);
85     }
86 
87     // returns command's data buffer
getData()88     public ByteBuffer getData() {
89         return mDataBuffer;
90     }
91 
92     // returns command's data length
getDataLength()93     public int getDataLength() {
94         return mMessageBuffer.getInt(12);
95     }
96 
97     // returns command's data as a string
getDataString()98     public String getDataString() {
99         int length = getDataLength();
100         if (length == 0) return null;
101         // trim trailing zero
102         return new String(mDataBuffer.array(), 0, length - 1);
103     }
104 
105 
write(AdbDevice device)106     public boolean write(AdbDevice device) {
107         synchronized (device) {
108             UsbRequest request = device.getOutRequest();
109             request.setClientData(this);
110             if (request.queue(mMessageBuffer, 24)) {
111                 int length = getDataLength();
112                 if (length > 0) {
113                     request = device.getOutRequest();
114                     request.setClientData(this);
115                     if (request.queue(mDataBuffer, length)) {
116                         return true;
117                     } else {
118                         device.releaseOutRequest(request);
119                         return false;
120                     }
121                 }
122                 return true;
123             } else {
124                 device.releaseOutRequest(request);
125                 return false;
126             }
127         }
128     }
129 
readCommand(UsbRequest request)130     public boolean readCommand(UsbRequest request) {
131         request.setClientData(this);
132         return request.queue(mMessageBuffer, 24);
133     }
134 
readData(UsbRequest request, int length)135     public boolean readData(UsbRequest request, int length) {
136         request.setClientData(this);
137         return request.queue(mDataBuffer, length);
138     }
139 
extractString(ByteBuffer buffer, int offset, int length)140     private static String extractString(ByteBuffer buffer, int offset, int length) {
141         byte[] bytes = new byte[length];
142         for (int i = 0; i < length; i++) {
143             bytes[i] = buffer.get(offset++);
144         }
145         return new String(bytes);
146     }
147 
148     @Override
toString()149     public String toString() {
150         String commandName = extractString(mMessageBuffer, 0, 4);
151         int dataLength = getDataLength();
152         String result = "Adb Message: " + commandName + " arg0: " + getArg0() +
153              " arg1: " + getArg1() + " dataLength: " + dataLength;
154         if (dataLength > 0) {
155             result += (" data: \"" + getDataString() + "\"");
156         }
157         return result;
158     }
159 
checksum(byte[] data)160     private static int checksum(byte[] data) {
161         int result = 0;
162         for (int i = 0; i < data.length; i++) {
163             int x = data[i];
164             // dang, no unsigned ints in java
165             if (x < 0) x += 256;
166             result += x;
167         }
168         return result;
169     }
170 }