Android MTP 客户端打开整个设备而不是单个界面
Android MTP client opens a whole device and not a single interface
我有一个复合 USB 小工具,我想连接到 Android phone。它包含以下串行、MTP 和大容量存储接口:
interface :: id : 0, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 1, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 2, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
我的问题是试图同时打开串行和 MTP 接口。这是我的代码:
private class SetupInterfacesRunnable implements Runnable
{
@Override
public void run()
{
synchronized(MyService.this)
{
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
usbConnection = usbManager.openDevice(usbDevice);
/*
interface :: id : 0, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 1, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 2, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
*/
// Interface 1 on the composite usb device is cdc acm data.
serialPort = UsbSerialDevice.createUsbSerialDevice(usbDevice, usbConnection, 1);
if(serialPort != null)
{
if(serialPort.open())
{
serialPort.setBaudRate(115200);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
mUIHandler.post(notifyRadgetConnected);
// set the callback to catch serial data
serialPort.read(mCallback);
mUIHandler.post(handshake);
}else
{
// Serial port could not be opened, maybe an I/O error or it CDC driver was chosen it does not really fit
LoggerV2.e("Failed to open device serial port");
}
}else
{
// No driver for given device, even generic CDC driver could not be loaded
LoggerV2.e("Failed to find driver for the serial device");
}
// Interface 2 on the composite usb device is MTP.
MtpDevice mtpDevice = new MtpDevice(usbDevice);
if (!mtpDevice.open(usbConnection)) {
LoggerV2.e("Failed to obtain device mtp storage");
}
}
}
}
我正在使用的串行实现 (felHR85/UsbSerial) 能够打开单个界面,但是,我找不到以这种方式实现 MTPDevice class 的简单方法。
似乎Android MTP API 想要在调用打开函数时打开整个device/connection。
native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
API 文档: https://developer.android.com/reference/android/mtp/MtpDevice.html
我看不到只打开一个界面的方法。我是否缺少使用连接在同一设备上打开多个接口的一些简单方法?
短answer/workaround是运行接口0上的MTP响应器,然后打开MTP设备后的串口。
较长的答案是...
深入研究代码后,我发现 native_open 调用通过以下源文件进行过滤:
- MtpDevice.java
- android_mtp_MtpDevice.cpp
- MtpDevice.cpp
MtpDevice.cpp: https://android.googlesource.com/platform/frameworks/av/+/master/media/mtp/MtpDevice.cpp
在 MtpDevice.cpp 中,似乎我会失败并在日志中打印 "endpoints not found\n" 错误消息,就好像找不到正确的端点一样。
现在我通过首先使用 MTP 重新排序接口来解决这个问题:
interface :: id : 0, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 1, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 2, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
这让我可以先打开MTP设备,然后通过接口打开串口:
private class SetupInterfacesRunnable implements Runnable
{
@Override
public void run()
{
synchronized(RadgetService.this)
{
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
usbConnection = usbManager.openDevice(usbDevice);
/*
interface :: id : 0, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 1, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 2, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
*/
// Interface 0 on the composite device is MTP
MtpDevice mtpDevice = new MtpDevice(usbDevice);
if (!mtpDevice.open(usbConnection)) {
LoggerV2.e("Failed to obtain radget mtp storage");
}
else
{
LoggerV2.i("Opened MTP storage: %s", mtpDevice.getDeviceName());
int[] storageIds = mtpDevice.getStorageIds();
if (storageIds == null) {
LoggerV2.i("No mtp storage id's found");
return;
}
/*
* scan each storage
*/
for (int storageId : storageIds) {
LoggerV2.i("~~~~Storage id: %d~~~~", storageId);
scanObjectsInStorage(mtpDevice, storageId, 0, 0);
}
}
// Interface 2 on the composite usb device is cdc acm data.
serialPort = UsbSerialDevice.createUsbSerialDevice(usbDevice, usbConnection, 2);
if(serialPort != null)
{
if(serialPort.open())
{
serialPort.setBaudRate(115200);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
mUIHandler.post(notifyRadgetConnected);
// set the callback to catch serial data
serialPort.read(mCallback);
mUIHandler.post(handshake);
}else
{
// Serial port could not be opened, maybe an I/O error or it CDC driver was chosen it does not really fit
LoggerV2.e("Failed to open device serial port");
}
}else
{
// No driver for given device, even generic CDC driver could not be loaded
LoggerV2.e("Failed to find driver for serial device");
}
}
}
}
我有一个复合 USB 小工具,我想连接到 Android phone。它包含以下串行、MTP 和大容量存储接口:
interface :: id : 0, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 1, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 2, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
我的问题是试图同时打开串行和 MTP 接口。这是我的代码:
private class SetupInterfacesRunnable implements Runnable
{
@Override
public void run()
{
synchronized(MyService.this)
{
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
usbConnection = usbManager.openDevice(usbDevice);
/*
interface :: id : 0, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 1, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 2, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
*/
// Interface 1 on the composite usb device is cdc acm data.
serialPort = UsbSerialDevice.createUsbSerialDevice(usbDevice, usbConnection, 1);
if(serialPort != null)
{
if(serialPort.open())
{
serialPort.setBaudRate(115200);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
mUIHandler.post(notifyRadgetConnected);
// set the callback to catch serial data
serialPort.read(mCallback);
mUIHandler.post(handshake);
}else
{
// Serial port could not be opened, maybe an I/O error or it CDC driver was chosen it does not really fit
LoggerV2.e("Failed to open device serial port");
}
}else
{
// No driver for given device, even generic CDC driver could not be loaded
LoggerV2.e("Failed to find driver for the serial device");
}
// Interface 2 on the composite usb device is MTP.
MtpDevice mtpDevice = new MtpDevice(usbDevice);
if (!mtpDevice.open(usbConnection)) {
LoggerV2.e("Failed to obtain device mtp storage");
}
}
}
}
我正在使用的串行实现 (felHR85/UsbSerial) 能够打开单个界面,但是,我找不到以这种方式实现 MTPDevice class 的简单方法。
似乎Android MTP API 想要在调用打开函数时打开整个device/connection。
native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
API 文档: https://developer.android.com/reference/android/mtp/MtpDevice.html
我看不到只打开一个界面的方法。我是否缺少使用连接在同一设备上打开多个接口的一些简单方法?
短answer/workaround是运行接口0上的MTP响应器,然后打开MTP设备后的串口。
较长的答案是... 深入研究代码后,我发现 native_open 调用通过以下源文件进行过滤:
- MtpDevice.java
- android_mtp_MtpDevice.cpp
- MtpDevice.cpp
- android_mtp_MtpDevice.cpp
MtpDevice.cpp: https://android.googlesource.com/platform/frameworks/av/+/master/media/mtp/MtpDevice.cpp
在 MtpDevice.cpp 中,似乎我会失败并在日志中打印 "endpoints not found\n" 错误消息,就好像找不到正确的端点一样。
现在我通过首先使用 MTP 重新排序接口来解决这个问题:
interface :: id : 0, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 1, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 2, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
这让我可以先打开MTP设备,然后通过接口打开串口:
private class SetupInterfacesRunnable implements Runnable
{
@Override
public void run()
{
synchronized(RadgetService.this)
{
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
usbConnection = usbManager.openDevice(usbDevice);
/*
interface :: id : 0, name : MTP, alt 0 [00ffh:00ffh:0000h] Vendor Specific
interface :: id : 1, name : CDC Abstract Control Model (ACM), alt 0 [0002h:0002h:0001h] CDC Control
interface :: id : 2, name : CDC ACM Data, alt 0 [000ah:0000h:0000h] CDC Data
interface :: id : 3, name : Mass Storage, alt 0 [0008h:0006h:0050h] Mass Storage
*/
// Interface 0 on the composite device is MTP
MtpDevice mtpDevice = new MtpDevice(usbDevice);
if (!mtpDevice.open(usbConnection)) {
LoggerV2.e("Failed to obtain radget mtp storage");
}
else
{
LoggerV2.i("Opened MTP storage: %s", mtpDevice.getDeviceName());
int[] storageIds = mtpDevice.getStorageIds();
if (storageIds == null) {
LoggerV2.i("No mtp storage id's found");
return;
}
/*
* scan each storage
*/
for (int storageId : storageIds) {
LoggerV2.i("~~~~Storage id: %d~~~~", storageId);
scanObjectsInStorage(mtpDevice, storageId, 0, 0);
}
}
// Interface 2 on the composite usb device is cdc acm data.
serialPort = UsbSerialDevice.createUsbSerialDevice(usbDevice, usbConnection, 2);
if(serialPort != null)
{
if(serialPort.open())
{
serialPort.setBaudRate(115200);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
mUIHandler.post(notifyRadgetConnected);
// set the callback to catch serial data
serialPort.read(mCallback);
mUIHandler.post(handshake);
}else
{
// Serial port could not be opened, maybe an I/O error or it CDC driver was chosen it does not really fit
LoggerV2.e("Failed to open device serial port");
}
}else
{
// No driver for given device, even generic CDC driver could not be loaded
LoggerV2.e("Failed to find driver for serial device");
}
}
}
}