當(dāng) USB 設(shè)備連接到 Android 設(shè)備時(shí)會(huì)發(fā)生什么?
當(dāng)USB設(shè)備連接到Android設(shè)備時(shí),我們會(huì)收到如下系統(tǒng)廣播數(shù)據(jù),通過UsbDevice對(duì)象,你可以獲取設(shè)備的VID、PID、產(chǎn)品名稱、制造商名稱等基本信息。
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]
]
]
]
VID
(Vendor ID)是USB設(shè)備的一個(gè)標(biāo)識(shí)符,由USB Implementers Forum(USB-IF)分配給設(shè)備制造商的一個(gè)16位的十六進(jìn)制數(shù),用于標(biāo)識(shí)其生產(chǎn)的設(shè)備。每個(gè)設(shè)備制造商都有一個(gè)唯一的VID。
在USB設(shè)備中,VID與PID(Product ID)一起使用,用于識(shí)別和管理設(shè)備。當(dāng)USB設(shè)備連接到計(jì)算機(jī)時(shí),操作系統(tǒng)會(huì)檢測(cè)設(shè)備的VID和PID,并根據(jù)這些信息加載相應(yīng)的驅(qū)動(dòng)程序,確保設(shè)備能夠正常工作。
廠商在開發(fā)USB產(chǎn)品前,需要從USB-IF取得廠商標(biāo)識(shí)符(Vendor ID)。申請(qǐng)VID的方式包括成為USB-IF會(huì)員并繳納年費(fèi),或者通過第三方機(jī)構(gòu)進(jìn)行申請(qǐng)。獲得VID后,廠商可以進(jìn)行USB測(cè)試,并將測(cè)試結(jié)果連同USB商標(biāo)許可協(xié)議遞交給USB-IF協(xié)會(huì)進(jìn)行審核。
PID
(Product ID)是USB設(shè)備的一個(gè)標(biāo)識(shí)符,用于標(biāo)識(shí)同一制造商生產(chǎn)的不同設(shè)備。PID由設(shè)備制造商定義,長(zhǎng)度通常為8位,由低4位的類型字段和高4位的校驗(yàn)字段組成。類型字段的不同組合用于標(biāo)識(shí)不同類型的USB數(shù)據(jù)包,如令牌包、握手包、數(shù)據(jù)包和特殊包。
在USB通信中,PID字段用于指明數(shù)據(jù)傳輸?shù)姆较?、幀開始、數(shù)據(jù)傳輸?shù)慕Y(jié)果以及數(shù)據(jù)包的奇偶性等。
在USB設(shè)備的識(shí)別和管理中,VID和PID一起發(fā)揮著關(guān)鍵作用。當(dāng)USB設(shè)備掛載連接到時(shí),操作系統(tǒng)會(huì)檢測(cè)設(shè)備的VID和PID,根據(jù)這些信息加載相應(yīng)的驅(qū)動(dòng)程序,確保設(shè)備能夠正常工作。VID和PID還用于設(shè)備管理,包括設(shè)備的連接和斷開、設(shè)備的狀態(tài)監(jiān)測(cè)和控制等。
ADB WiFi中USB連接處理
通用獲取USB設(shè)備方法:
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();
// 打印設(shè)備信息
Log.d("USB設(shè)備信息", "Vendor ID: " + vendorId);
Log.d("USB設(shè)備信息", "Product ID: " + productId);
Log.d("USB設(shè)備信息", "Device Name: " + deviceName);
Log.d("USB設(shè)備信息", "Product Name: " + productName);
Log.d("USB設(shè)備信息", "Manufacturer: " + manufacturerName);
}
} else {
Log.d("USB設(shè)備信息", "沒有USB設(shè)備連接.");
}
廣播實(shí)時(shí)監(jiān)聽USB設(shè)備接入拔出:
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) {
// 請(qǐng)求USB設(shè)備訪問權(quán)限
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設(shè)備拔出事件
}
} 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設(shè)備權(quán)限被授予,可以進(jìn)行通信了
}
} else {
// 權(quán)限被拒絕,處理邏輯
}
}
}
}
}
}
ADB WiFi實(shí)時(shí)監(jiān)聽USB設(shè)備接入處理:
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, "初始化創(chuàng)建密鑰對(duì)失敗:", e);
}
mReadDataThread = new ReadDataThread();
mReadDataThread.start();
mWriteDataThread = new WriteDataThread();
mWriteDataThread.start();
//注冊(cè)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設(shè)備
HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
for (UsbDevice device : deviceList.values()) {
if (mUsbManager.hasPermission(device)) {
asyncRefreshConnection(device);
} else {
//請(qǐng)求權(quán)限
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;
//設(shè)備已連接
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:");
//設(shè)備已連接
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, "讀取終端數(shù)據(jù):", 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, "發(fā)送終端數(shù)據(jù):", e);
}
} else {
String command = mWriteDataList.remove(0);
try {
//發(fā)送命令
mStream.write((command + "\n").getBytes(StandardCharsets.UTF_8));
} catch (IOException | InterruptedException e) {
Log.e(TAG, "發(fā)送終端數(shù)據(jù):", 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) {
//關(guān)閉連接
if (mConnection != null) {
try {
mConnection.close();
} catch (IOException e) {
Log.e(TAG, "關(guān)閉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) {
//斷開連接的和當(dāng)前連接的是同一個(gè)設(shè)備 斷開連接
if (mUsbDevice.getDeviceName().equals(device.getDeviceName())) {
//關(guān)閉連接
closeConnection(true);
}
}
}
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null && mUsbDevice != null) {
//連接的和當(dāng)前連接的不是同一個(gè)設(shè)備
if (!mUsbDevice.getDeviceName().equals(device.getDeviceName())) {
//開始連接
if (mUsbManager.hasPermission(device)) {
asyncRefreshConnection(device);
} else {
//請(qǐng)求權(quán)限
requestPermission(context, device);
}
}
}
}
if (Constants.USB_PERMISSION.equals(intent.getAction())) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
//開始連接
if (mUsbManager.hasPermission(device)) {
asyncRefreshConnection(device);
} else {
//請(qǐng)求權(quán)限
requestPermission(context, device);
}
}
}
};
}