213 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| #define TRACE_TAG TRANSPORT
 | |
| 
 | |
| #include "sysdeps.h"
 | |
| 
 | |
| #include "client/usb.h"
 | |
| 
 | |
| #include <memory>
 | |
| 
 | |
| #include "sysdeps.h"
 | |
| #include "transport.h"
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "adb.h"
 | |
| 
 | |
| #if ADB_HOST
 | |
| 
 | |
| #if defined(__APPLE__)
 | |
| #define CHECK_PACKET_OVERFLOW 0
 | |
| #else
 | |
| #define CHECK_PACKET_OVERFLOW 1
 | |
| #endif
 | |
| 
 | |
| // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
 | |
| // to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
 | |
| static int UsbReadMessage(usb_handle* h, amessage* msg) {
 | |
|     D("UsbReadMessage");
 | |
| 
 | |
| #if CHECK_PACKET_OVERFLOW
 | |
|     size_t usb_packet_size = usb_get_max_packet_size(h);
 | |
|     CHECK_GE(usb_packet_size, sizeof(*msg));
 | |
|     CHECK_LT(usb_packet_size, 4096ULL);
 | |
| 
 | |
|     char buffer[4096];
 | |
|     int n = usb_read(h, buffer, usb_packet_size);
 | |
|     if (n != sizeof(*msg)) {
 | |
|         D("usb_read returned unexpected length %d (expected %zu)", n, sizeof(*msg));
 | |
|         return -1;
 | |
|     }
 | |
|     memcpy(msg, buffer, sizeof(*msg));
 | |
|     return n;
 | |
| #else
 | |
|     return usb_read(h, msg, sizeof(*msg));
 | |
| #endif
 | |
| }
 | |
| 
 | |
| // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
 | |
| // to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
 | |
| static int UsbReadPayload(usb_handle* h, apacket* p) {
 | |
|     D("UsbReadPayload(%d)", p->msg.data_length);
 | |
| 
 | |
|     if (p->msg.data_length > MAX_PAYLOAD) {
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
| #if CHECK_PACKET_OVERFLOW
 | |
|     size_t usb_packet_size = usb_get_max_packet_size(h);
 | |
| 
 | |
|     // Round the data length up to the nearest packet size boundary.
 | |
|     // The device won't send a zero packet for packet size aligned payloads,
 | |
|     // so don't read any more packets than needed.
 | |
|     size_t len = p->msg.data_length;
 | |
|     size_t rem_size = len % usb_packet_size;
 | |
|     if (rem_size) {
 | |
|         len += usb_packet_size - rem_size;
 | |
|     }
 | |
| 
 | |
|     p->payload.resize(len);
 | |
|     int rc = usb_read(h, &p->payload[0], p->payload.size());
 | |
|     if (rc != static_cast<int>(p->msg.data_length)) {
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     p->payload.resize(rc);
 | |
|     return rc;
 | |
| #else
 | |
|     p->payload.resize(p->msg.data_length);
 | |
|     return usb_read(h, &p->payload[0], p->payload.size());
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static int remote_read(apacket* p, usb_handle* usb) {
 | |
|     int n = UsbReadMessage(usb, &p->msg);
 | |
|     if (n < 0) {
 | |
|         D("remote usb: read terminated (message)");
 | |
|         return -1;
 | |
|     }
 | |
|     if (static_cast<size_t>(n) != sizeof(p->msg)) {
 | |
|         D("remote usb: read received unexpected header length %d", n);
 | |
|         return -1;
 | |
|     }
 | |
|     if (p->msg.data_length) {
 | |
|         n = UsbReadPayload(usb, p);
 | |
|         if (n < 0) {
 | |
|             D("remote usb: terminated (data)");
 | |
|             return -1;
 | |
|         }
 | |
|         if (static_cast<uint32_t>(n) != p->msg.data_length) {
 | |
|             D("remote usb: read payload failed (need %u bytes, give %d bytes), skip it",
 | |
|               p->msg.data_length, n);
 | |
|             return -1;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #else
 | |
| 
 | |
| // On Android devices, we rely on the kernel to provide buffered read.
 | |
| // So we can recover automatically from EOVERFLOW.
 | |
| static int remote_read(apacket* p, usb_handle* usb) {
 | |
|     if (usb_read(usb, &p->msg, sizeof(amessage)) != sizeof(amessage)) {
 | |
|         PLOG(ERROR) << "remote usb: read terminated (message)";
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     if (p->msg.data_length) {
 | |
|         if (p->msg.data_length > MAX_PAYLOAD) {
 | |
|             PLOG(ERROR) << "remote usb: read overflow (data length = " << p->msg.data_length << ")";
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         p->payload.resize(p->msg.data_length);
 | |
|         if (usb_read(usb, &p->payload[0], p->payload.size()) !=
 | |
|             static_cast<int>(p->payload.size())) {
 | |
|             PLOG(ERROR) << "remote usb: terminated (data)";
 | |
|             return -1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| UsbConnection::~UsbConnection() {
 | |
|     usb_close(handle_);
 | |
| }
 | |
| 
 | |
| bool UsbConnection::Read(apacket* packet) {
 | |
|     int rc = remote_read(packet, handle_);
 | |
|     return rc == 0;
 | |
| }
 | |
| 
 | |
| bool UsbConnection::Write(apacket* packet) {
 | |
|     int size = packet->msg.data_length;
 | |
| 
 | |
|     if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != sizeof(packet->msg)) {
 | |
|         PLOG(ERROR) << "remote usb: 1 - write terminated";
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (packet->msg.data_length != 0 && usb_write(handle_, packet->payload.data(), size) != size) {
 | |
|         PLOG(ERROR) << "remote usb: 2 - write terminated";
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool UsbConnection::DoTlsHandshake(RSA* key, std::string* auth_key) {
 | |
|     // TODO: support TLS for usb connections
 | |
|     LOG(FATAL) << "Not supported yet.";
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| void UsbConnection::Reset() {
 | |
|     usb_reset(handle_);
 | |
|     usb_kick(handle_);
 | |
| }
 | |
| 
 | |
| void UsbConnection::Close() {
 | |
|     usb_kick(handle_);
 | |
| }
 | |
| 
 | |
| void init_usb_transport(atransport* t, usb_handle* h) {
 | |
|     D("transport: usb");
 | |
|     auto connection = std::make_unique<UsbConnection>(h);
 | |
|     t->SetConnection(std::make_unique<BlockingConnectionAdapter>(std::move(connection)));
 | |
|     t->type = kTransportUsb;
 | |
|     t->SetUsbHandle(h);
 | |
| }
 | |
| 
 | |
| int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) {
 | |
|     return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
 | |
| }
 | |
| 
 | |
| bool should_use_libusb() {
 | |
| #if !ADB_HOST
 | |
|     return false;
 | |
| #else
 | |
|     static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
 | |
|     return enable;
 | |
| #endif
 | |
| }
 |