5

当 USB 设备连接到 Android 设备时会发生什么?

 3 weeks ago
source link: https://www.51cto.com/article/785258.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

当 USB 设备连接到 Android 设备时会发生什么?

作者:Reathin 2024-04-02 11:31:33
当USB设备挂载连接到时,操作系统会检测设备的VID和PID,根据这些信息加载相应的驱动程序,确保设备能够正常工作。

当USB设备连接到Android设备时,我们会收到如下系统广播数据,通过UsbDevice对象,你可以获取设备的VID、PID、产品名称、制造商名称等基本信息。

UsbDevice[
    mName=/dev/bus/usb/002/005,
    mVendorId=1008,
    mProductId=1694,
    mClass=0,
    mSubclass=0,
    mProtocol=0,
    mManufacturerName=HP Inc.,
    mProductName=HP Laser 1008a,
    mVersion=2.0,
    mSerialNumber=CNB1RC683F,
    mConfigurations=[
        UsbConfiguration[
            mId=1,
            mName=null,
            mAttributes=192,
            mMaxPower=1,
            mInterfaces=[
                UsbInterface[
                    mId=0,
                    mAlternateSetting=0,
                    mName=null,
                    mClass=7,
                    mSubclass=1,
                    mProtocol=2,
                    mEndpoints=[
                        UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                        UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                    ]
                UsbInterface[
                    mId=0,
                    mAlternateSetting=1,
                    mName=null,
                    mClass=7,
                    mSubclass=1,
                    mProtocol=4,
                    mEndpoints=[
                        UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                        UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                    ]
                UsbInterface[
                    mId=1,
                    mAlternateSetting=0,
                    mName=null,
                    mClass=255,
                    mSubclass=4,
                    mProtocol=1,
                    mEndpoints=[
                        UsbEndpoint[mAddress=6,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                        UsbEndpoint[mAddress=133,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                    ]
                UsbInterface[
                    mId=1,
                    mAlternateSetting=1,
                    mName=null,
                    mClass=7,
                    mSubclass=1,
                    mProtocol=4,
                    mEndpoints=[
                        UsbEndpoint[mAddress=6,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                        UsbEndpoint[mAddress=133,mAttributes=2,mMaxPacketSize=512,mInterval=10]
                    ]
                ]
            ]

(Vendor ID)是USB设备的一个标识符,由USB Implementers Forum(USB-IF)分配给设备制造商的一个16位的十六进制数,用于标识其生产的设备。每个设备制造商都有一个唯一的VID。

在USB设备中,VID与PID(Product ID)一起使用,用于识别和管理设备。当USB设备连接到计算机时,操作系统会检测设备的VID和PID,并根据这些信息加载相应的驱动程序,确保设备能够正常工作。

厂商在开发USB产品前,需要从USB-IF取得厂商标识符(Vendor ID)。申请VID的方式包括成为USB-IF会员并缴纳年费,或者通过第三方机构进行申请。获得VID后,厂商可以进行USB测试,并将测试结果连同USB商标许可协议递交给USB-IF协会进行审核。

(Product ID)是USB设备的一个标识符,用于标识同一制造商生产的不同设备。PID由设备制造商定义,长度通常为8位,由低4位的类型字段和高4位的校验字段组成。类型字段的不同组合用于标识不同类型的USB数据包,如令牌包、握手包、数据包和特殊包。

在USB通信中,PID字段用于指明数据传输的方向、帧开始、数据传输的结果以及数据包的奇偶性等。

在USB设备的识别和管理中,VID和PID一起发挥着关键作用。当USB设备挂载连接到时,操作系统会检测设备的VID和PID,根据这些信息加载相应的驱动程序,确保设备能够正常工作。VID和PID还用于设备管理,包括设备的连接和断开、设备的状态监测和控制等。

ADB WiFi中USB连接处理

通用获取USB设备方法:

UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);  
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();  
if (!deviceList.isEmpty()) {  
    for (Map.Entry<String, UsbDevice> entry : deviceList.entrySet()) {  
        UsbDevice device = entry.getValue();  
        int vendorId = device.getVendorId();  
        int productId = device.getProductId();  
        String deviceName = device.getDeviceName();  
        String productName = device.getProductName();  
        String manufacturerName = device.getManufacturerName();  
          
        // 打印设备信息  
        Log.d("USB设备信息", "Vendor ID: " + vendorId);  
        Log.d("USB设备信息", "Product ID: " + productId);  
        Log.d("USB设备信息", "Device Name: " + deviceName);  
        Log.d("USB设备信息", "Product Name: " + productName);  
        Log.d("USB设备信息", "Manufacturer: " + manufacturerName);  
    }  
} else {  
    Log.d("USB设备信息", "没有USB设备连接.");  
}

广播实时监听USB设备接入拔出:

public class MainActivity extends AppCompatActivity {  
    private UsbReceiver usbReceiver;  
    private UsbManager usbManager;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
  
        usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);  
        usbReceiver = new UsbReceiver();  
        IntentFilter filter = new IntentFilter();  
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);  
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);  
        registerReceiver(usbReceiver, filter);  
    }  
  
    @Override  
    protected void onResume() {  
        super.onResume();  
        registerReceiver(usbReceiver, new IntentFilter(UsbManager.ACTION_USB_PERMISSION));  
    }  
  
    @Override  
    protected void onPause() {  
        super.onPause();  
        unregisterReceiver(usbReceiver);  
    }  
  
    private final class UsbReceiver extends BroadcastReceiver {  
        public void onReceive(Context context, Intent intent) {  
            String action = intent.getAction();  
            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {  
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);  
                if (device != null) {  
                    // 请求USB设备访问权限  
                    PendingIntent pi = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);  
                    usbManager.requestPermission(device, pi);  
                }  
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {  
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);  
                if (device != null) {  
                    // 处理USB设备拔出事件  
                }  
            } else if (UsbManager.ACTION_USB_PERMISSION.equals(action)) {  
                synchronized (this) {  
                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);  
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {  
                        if (device != null) {  
                            // USB设备权限被授予,可以进行通信了  
                        }  
                    } else {  
                        // 权限被拒绝,处理逻辑  
                    }  
                }  
            }  
        }  
    }  
}

ADB WiFi实时监听USB设备接入处理:

public class ADBControlEntrance {

    private static final String TAG = ADBControlEntrance.class.getSimpleName();

    private static volatile ADBControlEntrance sInstance;

    private UsbManager mUsbManager;
    private UsbDevice mUsbDevice;
    private AdbCrypto mCrypto;
    private AdbConnection mConnection;
    private AdbStream mStream;

    private final List<TerminalDataListener> mTerminalDataListenerList = Collections.synchronizedList(new ArrayList<>());

    private final List<String> mWriteDataList = new ArrayList<>();
    private final Object mWriteSyncLock = new Object();

    private ReadDataThread mReadDataThread;
    private WriteDataThread mWriteDataThread;
    private Thread mConnectThread;

    private ADBControlEntrance() {

    }

    public static ADBControlEntrance getInstance() {
        if (sInstance == null) {
            synchronized (ADBControlEntrance.class) {
                if (sInstance == null) {
                    sInstance = new ADBControlEntrance();
                }
            }
        }
        return sInstance;
    }

    public void init(Context context) {
        mUsbManager = (UsbManager) context.getApplicationContext().getSystemService(Context.USB_SERVICE);

        try {
            mCrypto = AdbCrypto.generateAdbKeyPair(new Base64Impl());
            mCrypto.saveAdbKeyPair(new File(context.getFilesDir(), "private_key"), new File(context.getFilesDir(), "public_key"));
        } catch (NoSuchAlgorithmException | IOException e) {
            Log.e(TAG, "初始化创建密钥对失败:", e);
        }

        mReadDataThread = new ReadDataThread();
        mReadDataThread.start();

        mWriteDataThread = new WriteDataThread();
        mWriteDataThread.start();

        //注册USB广播
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Constants.USB_PERMISSION);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.registerReceiver(mUsbDeviceReceiver, intentFilter, Context.RECEIVER_EXPORTED);
        } else {
            context.registerReceiver(mUsbDeviceReceiver, intentFilter);
        }

        //遍历USB设备
        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        for (UsbDevice device : deviceList.values()) {
            if (mUsbManager.hasPermission(device)) {
                asyncRefreshConnection(device);
            } else {
                //请求权限
                requestPermission(context, device);
            }
        }
    }

    public void addTerminalDataListener(TerminalDataListener terminalDataListener) {
        mTerminalDataListenerList.add(terminalDataListener);
    }

    public void removeTerminalDataListener(TerminalDataListener terminalDataListener) {
        mTerminalDataListenerList.remove(terminalDataListener);
    }

    public void removeAllTerminalDataListener() {
        mTerminalDataListenerList.clear();
    }

    public void release() {
        closeConnection(false);
        if (mReadDataThread != null) {
            mReadDataThread.interrupt();
            mReadDataThread = null;
        }
        if (mWriteDataThread != null) {
            mWriteDataThread.interrupt();
            mWriteDataThread = null;
        }
        mTerminalDataListenerList.clear();
    }

    public boolean isConnected() {
        return mConnection != null && mConnection.isConnected();
    }

    private void asyncRefreshConnection(UsbDevice device) {
        closeConnection(true);
        if (device == null) return;
        UsbInterface usbInterface = null;
        for (int index = 0; index < device.getInterfaceCount(); index++) {
            UsbInterface interface1 = device.getInterface(index);
            if (interface1.getInterfaceClass() == 255 && interface1.getInterfaceSubclass() == 66 && interface1.getInterfaceProtocol() == 1) {
                usbInterface = interface1;
                break;
            }
        }
        if (usbInterface == null) return;
        UsbDeviceConnection deviceConnection = mUsbManager.openDevice(device);
        if (deviceConnection.claimInterface(usbInterface, false)) {
            UsbChannel usbChannel = new UsbChannel(deviceConnection, usbInterface);
            try {
                mConnection = AdbConnection.create(usbChannel, mCrypto);
                mConnection.connect();
                mStream = mConnection.open("shell:");
                mUsbDevice = device;
                //设备已连接
                for (TerminalDataListener terminalDataListener : mTerminalDataListenerList) {
                    terminalDataListener.onDeviceConnect(0);
                }
                Log.d(TAG, "USB ADB连接:成功");
            } catch (IOException | InterruptedException e) {
                Log.e(TAG, "USB ADB连接", e);
                for (TerminalDataListener terminalDataListener : mTerminalDataListenerList) {
                    terminalDataListener.onDeviceDisConnect();
                }
            }
        } else {
            deviceConnection.close();
            for (TerminalDataListener terminalDataListener : mTerminalDataListenerList) {
                terminalDataListener.onDeviceDisConnect();
            }
        }
    }

    public void asyncRefreshConnection(String host) {
        closeConnection(false);
        if (TextUtils.isEmpty(host)) return;

        if (mConnectThread != null) {
            mConnectThread.interrupt();
            mConnectThread = null;
        }
        mConnectThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Socket socket = new Socket(host, 5555);
                    TcpChannel tcpChannel = new TcpChannel(socket);
                    mConnection = AdbConnection.create(tcpChannel, mCrypto);
                    mConnection.connect();
                    mStream = mConnection.open("shell:");
                    //设备已连接
                    for (TerminalDataListener terminalDataListener : mTerminalDataListenerList) {
                        terminalDataListener.onDeviceConnect(1);
                    }
                    Log.d(TAG, "TCP ADB连接:成功");
                } catch (IOException | InterruptedException e) {
                    Log.e(TAG, "TCP ADB连接:", e);
                    for (TerminalDataListener terminalDataListener : mTerminalDataListenerList) {
                        terminalDataListener.onDeviceDisConnect();
                    }
                }
            }
        });
        mConnectThread.start();
    }

    private class ReadDataThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!interrupted()) {
                asyncReadBuffer();
            }
        }
    }

    private void asyncReadBuffer() {
        if (mConnection != null && mStream != null) {
            while (!mStream.isClosed()) {
                try {
                    byte[] buffer = mStream.read();
                    String output = new String(buffer, StandardCharsets.US_ASCII);
                    for (TerminalDataListener terminalDataListener : mTerminalDataListenerList) {
                        terminalDataListener.onTerminalOutput(output);
                    }
                } catch (InterruptedException | IOException e) {
                    Log.e(TAG, "读取终端数据:", e);
                }
            }
        }
    }

    private class WriteDataThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                if (mWriteDataList.isEmpty()) {
                    try {
                        synchronized (mWriteSyncLock) {
                            mWriteSyncLock.wait();
                        }
                    } catch (InterruptedException e) {
                        Log.e(TAG, "发送终端数据:", e);
                    }
                } else {
                    String command = mWriteDataList.remove(0);
                    try {
                        //发送命令
                        mStream.write((command + "\n").getBytes(StandardCharsets.UTF_8));
                    } catch (IOException | InterruptedException e) {
                        Log.e(TAG, "发送终端数据:", e);
                    }
                }
            }
        }
    }

    public boolean asyncWriteBuffer(String command) {
        if (TextUtils.isEmpty(command)) return false;
        if (mStream == null || mStream.isClosed()) return false;
        mWriteDataList.add(command);
        synchronized (mWriteSyncLock) {
            mWriteSyncLock.notify();
        }
        return true;
    }

    public void closeConnection(boolean callback) {
        //关闭连接
        if (mConnection != null) {
            try {
                mConnection.close();
            } catch (IOException e) {
                Log.e(TAG, "关闭USB ADB连接:", e);
            }
            mConnection = null;
        }
        if (callback) {
            for (TerminalDataListener terminalDataListener : mTerminalDataListenerList) {
                terminalDataListener.onDeviceDisConnect();
            }
        }
    }

    private void requestPermission(Context context, UsbDevice device) {
        mUsbManager.requestPermission(device, PendingIntent.getBroadcast(context.getApplicationContext(), 0, new Intent(Constants.USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE));
    }

    private final BroadcastReceiver mUsbDeviceReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (device != null && mUsbDevice != null) {
                    //断开连接的和当前连接的是同一个设备 断开连接
                    if (mUsbDevice.getDeviceName().equals(device.getDeviceName())) {
                        //关闭连接
                        closeConnection(true);
                    }
                }
            }
            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (device != null && mUsbDevice != null) {
                    //连接的和当前连接的不是同一个设备
                    if (!mUsbDevice.getDeviceName().equals(device.getDeviceName())) {
                        //开始连接
                        if (mUsbManager.hasPermission(device)) {
                            asyncRefreshConnection(device);
                        } else {
                            //请求权限
                            requestPermission(context, device);
                        }
                    }
                }
            }

            if (Constants.USB_PERMISSION.equals(intent.getAction())) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                //开始连接
                if (mUsbManager.hasPermission(device)) {
                    asyncRefreshConnection(device);
                } else {
                    //请求权限
                    requestPermission(context, device);
                }
            }
        }
    };
}
责任编辑:赵宁宁 来源: 沐雨花飞蝶

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK