dongle加密协议规范与演示
一、通信端点:03
二、PID/VID
PID:0xB006
VID:0x1006
三、加密协议
1、 主机检测到 Dongle 插入,一秒钟后每隔 5 秒钟发送查询命令(只发送 5 次):
0x0D+0x43+0x57+0x52+0x55+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+crc8(Byte1-Byte18)
Dongle 答复:
0x0D+0x44+0x44+0x49+0x4e+0x47+0x4B+0x45+0x20+0x52+0x45+0x4d+0x4F+0x54+0x45+0x00+0x00+0x00+0x00+crc8(Byte1-Byte18)
2、 加密过程
主机收到 Dongle 答复后,生成两组 6 个随机数用作校验比如
unsigned char ramdom_tbl1[6] = {0x33, 0x44, 0x55, 0x31, 0x4e, 0xb9};
unsigned char ramdom_tbl2[6] = {0x88, 0x25, 0x4e, 0x99, 0xa7, 0xc7};
然后把第一组随机数组异或一组固定的数据
byte xor_table1[6] = {0xA8, 0x25, 0x3f, 0x97, 0x4e, 0xb9};
for(int i = 0; i < 6; i++)
{
Data[i] = ramdom_tbl1 [i]^xor_table1[i];
}
主机把 Data 数组组合成加密数据包发送给 Dongle,格式如下:
0x0D+0x53+data[0]+data[1]+data[2]+data[3]+data[4]+data[5]+ ramdom_tbl2 [0]+ramdom_tbl2 [1]+ ramdom_tbl2 [2]+ ramdom_tbl2 [3]+ ramdom_tbl2 [4]+ramdom_tbl2 [5]+0x00+0x00+0x00+0x00+0x00+ crc8(Byte1-Byte18)
Dongle 收到加密验证代码后,会把收到第一组数据异或 xor_table1 恢复原值,然后把 ramdom 的数据跟 Dongle 的 Mac 地址进行相加,只保留低 8 位(溢出丢弃),得到的数据再跟一组固定数据进行异或计算得到 encrypt_tbl [6];
byte Xor_table2[6] = {0x1c, 0xab, 0x17, 0x95, 0x3e, 0x9f};
Mac 地址的数据同样会进行异或 xor_table2 的计算得到 mac[6];Dongle 的回包格式即为
0x0D+0x54+encrypt[0]+ encrypt[1]+ encrypt[2]+ encrypt[3]+ encrypt[4]+encrypt[5]+mac[0]+mac[1]+mac[2]+mac[3]+mac[4]+mac[5]+0x00+0x00+0x00+0x00+0x00+crc8(Byte1-Byte18)
主机收到 Dongle 的回包后,把加密数据以及 Dongle 的 Mac 地址异或 xor_table2恢复回来,然后判断 encrypt 数据是否跟 ramdom_tbl1 跟 mac 数组各元素的和相等,如果都符合,则验证通过,不符合则验证失败。
四、示例
1、 原始数据
byte ramdom_tbl1[6] = {0x33, 0x44, 0x55, 0x31, 0x4e, 0xb9};
byte ramdom_tbl2[6] = {0x88, 0x25, 0x4e, 0x99, 0xa7, 0xc7};
byte xor_tbl1[6] = {0xA8, 0x25, 0x3f, 0x97, 0x4e, 0xb9};
byte xor_tbl2[6] = {0x1c, 0xab, 0x17, 0x95, 0x3e, 0x9f};
byte mac[6] = {0x13, 0x32, 0xbc, 0x55, 0x33, 0x55};
2、 交互过程
Master 发送:
0x0D+0x43+0x57+0x52+0x55+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x5d
Dongle 答复:
0x0D+0x44+0x44+0x49+0x4e+0x47+0x4B+0x45+0x20+0x52+0x45+0x4d+0x4F+0x54+0x45+0x00+0x00+0x00+0x00+0x9b
Master 发送:
0x0d+0x53+0x9b+0x61+0x6a+0xa6+0x00+0x00+0x88+0x25+0x4e+0x99+0xa7+0xc7+0x00+0x00+0x00+0x00+0x00+0xee
Dongle 答复:
0x0d+0x54+0x5a+0xdd+0x06+0x13+0xbf+0x91+0x0f+0x99+0xab+0xc0+0x0d+0xca+0x00+0x00+0x00+0x00+0x00+0xfb
五、CRC 校验算法
public static byte getCrc(byte[] data, int offset, int length) {
byte crc = 0;
for (int i = offset; i < length; i++) {
crc = (byte) (crc + data[i]);
for (int j = 0; j < 8; j++) {
if ((crc & 0x80) == 0) {
crc = (byte) (crc << 1);
} else {
crc = (byte) ((crc << 1) ^ 0x31);
}
}
}
return crc;
}
我是在androidFramework中去处理加密,目的是加密协议校验通过的遥控器可以操作电视。
下面就是具体的代码实现;通过插拔dongle开始进行处理;
可以在PhoneWindowManager中的interceptKeyBeforeDispatching方法调用isKeyEventAvailable方法做拦截处理
package com.android.internal.policy.impl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.InputDevice;
import android.view.KeyEvent;
public class UsbDeviceManager extends BroadcastReceiver {
private static final String TAG = "UsbDeviceManager";
public static final char[] HEX = "0123456789ABCDEF".toCharArray();
public static final int VID = 4310;
public static final int PID = 45062;
private final Context mContext;
private final Object mLock = new Object();
private final SparseArray<Device> mDevices = new SparseArray<Device>();
public UsbDeviceManager(Context context) {
mContext = context;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction("com.toptech.action.REQUEST_MAC_ADDRESS");
mContext.registerReceiver(this, filter);
}
protected UsbManager getUsbManager() {
return (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
}
protected void onBootCompleted() {
Log.d(TAG, "UsbDeviceManager - onBootCompleted.");
UsbManager usbManager = getUsbManager();
if (usbManager == null) {
return;
}
HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
if (devices == null || devices.isEmpty()) {
return;
}
for (UsbDevice usbDevice : devices.values()) {
onUsbDeviceAdded(usbDevice);
}
}
protected void onUsbDeviceAdded(UsbDevice usbDevice) {
if (usbDevice == null) {
return;
}
Device device = new Device(usbDevice);
Log.d(TAG, "UsbDeviceManager - onUsbDeviceAdded: " + usbDevice + " >>> name: " + device.name());
checkDevice(device);
synchronized (mLock) {
mDevices.put(usbDevice.getDeviceId(), device);
}
}
protected void onUsbDeviceRemoved(UsbDevice usbDevice) {
if (usbDevice == null) {
return;
}
Log.d(TAG, "UsbDeviceManager - onUsbDeviceRemoved: " + usbDevice);
Device device = mDevices.get(usbDevice.getDeviceId());
if (device == null) {
return;
}
device.status.set(Device.STATUS_REMOVED);
synchronized (mLock) {
mDevices.remove(usbDevice.getDeviceId());
}
}
protected boolean checkPermission(UsbDevice device) {
UsbManager usbManager = getUsbManager();
if (usbManager == null) {
return false;
}
if (device == null) {
return false;
}
return usbManager.hasPermission(device);
}
protected boolean grantPermission(UsbDevice device) {
if (device == null) {
return false;
}
if (checkPermission(device)) {
return true;
}
IBinder binder = ServiceManager.getService(Context.USB_SERVICE);
IUsbManager manager = IUsbManager.Stub.asInterface(binder);
final int uid = Binder.getCallingUid();
try {
manager.grantDevicePermission(device, uid);
manager.setDevicePackage(device, mContext.getPackageName(), UserHandle.getUserId(uid));
} catch (Exception e) {
return false;
}
return checkPermission(device);
}
protected void checkDevice(Device device) {
UsbManager usbManager = getUsbManager();
if (usbManager == null) {
return;
}
if (device == null) {
return;
}
UsbDevice usbDevice = device.device();
if (usbDevice.getVendorId() == VID && usbDevice.getProductId() == PID) {
UsbDeviceConnection usbConnection = usbManager.openDevice(usbDevice);
if (usbConnection == null) {
device.status.set(Device.STATUS_INVALID);
return;
}
UsbInterface usbInterface = getUsbInterface(usbDevice);
if (usbInterface == null) {
device.status.set(Device.STATUS_INVALID);
return;
}
if (!usbConnection.claimInterface(usbInterface, true)) {
device.status.set(Device.STATUS_INVALID);
return;
}
if (!checkPermission(usbDevice)) {
if (!grantPermission(usbDevice)) {
Log.w(TAG, "Grant permission failed.");
device.status.set(Device.STATUS_INVALID);
return;
}
}
new DeviceCheckThread(device, usbConnection, usbInterface).start();
} else {
device.status.set(Device.STATUS_CHECKED);
}
}
protected Device getUsbDevice(String name) {
if (TextUtils.isEmpty(name)) {
return null;
}
synchronized (mLock) {
for (int i = 0, j = mDevices.size(); i < j; i++) {
Device device = mDevices.valueAt(i);
if (name.equals(device.name())) {
return device;
}
}
}
return null;
}
protected String getMacAddress(int vendorId, int productId) {
synchronized (mLock) {
for (int i = 0, j = mDevices.size(); i < j; i++) {
Device device = mDevices.valueAt(i);
if (device.device().getVendorId() == vendorId && device.device().getProductId() == productId) {
if (TextUtils.isEmpty(device.mac())) {
continue;
}
return device.mac();
}
}
}
return null;
}
public boolean isKeyEventAvailable(KeyEvent event) {
if (event == null) {
return false;
}
InputDevice device = event.getDevice();
if (device.getVendorId() == 0 && device.getProductId() == 0) {
return true;
}
Device usbDevice = getUsbDevice(device.getName());
if (usbDevice == null) {
return true;
}
return usbDevice.status() == Device.STATUS_CHECKED;
}
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG, "action: " + action);
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
onBootCompleted();
return;
}
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
onUsbDeviceAdded((UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));
return;
}
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
onUsbDeviceRemoved((UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));
return;
}
if ("com.toptech.action.REQUEST_MAC_ADDRESS".equals(action)) {
Bundle extras = intent.getExtras();
if (extras == null || extras.isEmpty()) {
return;
}
int vendorId = extras.getInt("VendorId", 0);
int productId = extras.getInt("ProductId", 0);
if (vendorId == 0 && productId == 0) {
return;
}
Log.d(TAG, "Request mac address -> vid: " + vendorId + ", pid: " + productId);
String macAddress = getMacAddress(vendorId, productId);
if (TextUtils.isEmpty(macAddress)) {
return;
}
IBinder binder = extras.getBinder("Messenger");
if (binder == null) {
return;
}
Bundle result = new Bundle();
result.putString("MacAddress", macAddress);
Message message = Message.obtain();
message.what = 0;
message.obj = result;
Messenger messenger = new Messenger(binder);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
return;
}
}
private static UsbInterface getUsbInterface(UsbDevice device) {
if (device == null) {
return null;
}
for (int i = 0, j = device.getInterfaceCount(); i < j; i++) {
UsbInterface usbInterface = device.getInterface(i);
if (getInput(usbInterface) == null) {
continue;
}
if (getOutput(usbInterface) == null) {
continue;
}
return usbInterface;
}
return null;
}
private static UsbEndpoint getInput(UsbInterface usbInterface) {
for (int i = 0; i < usbInterface.getEndpointCount(); ++i) {
UsbEndpoint end = usbInterface.getEndpoint(i);
if (end.getDirection() == UsbConstants.USB_DIR_IN) {
return end;
}
}
return null;
}
private static UsbEndpoint getOutput(UsbInterface usbInterface) {
for (int i = 0; i < usbInterface.getEndpointCount(); ++i) {
UsbEndpoint end = usbInterface.getEndpoint(i);
if (end.getDirection() == UsbConstants.USB_DIR_OUT) {
return end;
}
}
return null;
}
private static List<String> getUsbPaths() {
File directory = new File("/sys/bus/usb/devices");
File[] files = directory.listFiles();
if (files == null || files.length == 0) {
return Collections.emptyList();
}
List<String> paths = new ArrayList<String>();
for (File file : files) {
String name = file.getName();
if (TextUtils.isEmpty(name)) {
continue;
}
if (!name.matches("\\d+-\\d+")) {
continue;
}
String realPath;
try {
realPath = file.getCanonicalPath();
} catch (IOException e) {
continue;
}
paths.add(realPath);
}
return paths;
}
private static String getUsbDevicePath(File event) {
if (event == null || !event.exists()) {
return null;
}
Scanner scanner;
try {
scanner = new Scanner(event);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.startsWith("DEVNAME=")) {
return line.replace("DEVNAME=", "/dev/");
}
}
} catch (FileNotFoundException e) {
return null;
}
return null;
}
private static Map<String, String> getUsbDevices() {
Map<String, String> devices = new HashMap<String, String>();
List<String> paths = getUsbPaths();
for (String path : paths) {
File file = new File(path);
if (!file.exists()) {
continue;
}
File event = new File(file, "uevent");
String devicePath = getUsbDevicePath(event);
if (TextUtils.isEmpty(devicePath)) {
continue;
}
devices.put(path, devicePath);
}
return devices;
}
private static String getUsbDevicePath(UsbDevice device) {
if (device == null) {
return null;
}
final String name = device.getDeviceName();
if (TextUtils.isEmpty(name)) {
return null;
}
Map<String, String> devices = getUsbDevices();
if (devices == null || devices.isEmpty()) {
return null;
}
for (String path : devices.keySet()) {
if (name.equals(devices.get(path))) {
return path;
}
}
return null;
}
private static void send(UsbDeviceConnection connection, UsbEndpoint out, byte[] data) {
if (connection == null || out == null) {
return;
}
if (data == null || data.length == 0) {
return;
}
String hex = bytesToHex(data);
Log.d(TAG, "request: " + hex);
try {
connection.bulkTransfer(out, data, data.length, 0);
} catch (Exception e) {
Log.e(TAG, "send error.", e);
}
}
private static byte[] read(UsbDeviceConnection connection, UsbEndpoint in, int timeout, int retry) {
if (connection == null || in == null) {
return null;
}
byte[] data = new byte[in.getMaxPacketSize()];
for (int i = retry; i > 0; i--) {
int length;
try {
length = connection.bulkTransfer(in, data, data.length, timeout);
if (length <= 0) {
continue;
}
} catch (Exception e) {
continue;
}
String hex = bytesToHex(data, length);
Log.d(TAG, "response: " + hex);
return Arrays.copyOf(data, length);
}
return null;
}
public static String bytesToHex(byte[] bytes) {
return bytesToHex(bytes, bytes.length);
}
public static String bytesToHex(byte[] bytes, int length) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < Math.min(length, bytes.length); j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX[v >>> 4];
hexChars[j * 2 + 1] = HEX[v & 0x0F];
}
return new String(hexChars);
}
public static byte[] hex2Byte(String hex) {
String[] parts = hex.split(" ");
byte[] bytes = new byte[parts.length];
for (int i = 0; i < parts.length; i++) {
bytes[i] = (byte) Integer.parseInt(parts[i], 16);
}
return bytes;
}
public static boolean allEquals(byte[] bytes, byte value) {
if (bytes == null || bytes.length == 0) {
return false;
}
for (int i = 0; i < bytes.length; i++) {
if (bytes[i] != value) {
return false;
}
}
return true;
}
public static String randomHexString(int length) {
StringBuffer result = new StringBuffer();
Random random = new Random();
try {
for (int i = 0; i < length; i++) {
String hexString = Integer.toHexString(random.nextInt(255));
if (hexString.length() == 1) {
result.append("0");
}
result.append(hexString).append(" ");
}
return result.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte getCrc(byte[] data, int offset, int length) {
byte crc = 0;
for (int i = offset; i < length; i++) {
crc = (byte) (crc + data[i]);
for (int j = 0; j < 8; j++) {
if ((crc & 0x80) == 0) {
crc = (byte) (crc << 1);
} else {
crc = (byte) ((crc << 1) ^ 0x31);
}
}
}
return crc;
}
private static String read(File file) {
if (file == null || !file.exists()) {
return null;
}
StringBuilder builder = new StringBuilder();
Scanner scanner;
try {
scanner = new Scanner(file);
while (scanner.hasNextLine()) {
builder.append(scanner.nextLine()).append('\n');
}
builder.deleteCharAt(builder.length() - 1);
} catch (FileNotFoundException e) {
return null;
}
if (scanner != null) {
scanner.close();
}
return builder.toString();
}
public static void write(File file, String content) {
if (file == null) {
return;
}
FileWriter writer;
try {
writer = new FileWriter(file);
writer.write(content);
writer.flush();
} catch (IOException e) {
return;
}
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class DeviceCheckThread extends Thread {
final Device device;
final UsbDeviceConnection usbConnection;
final UsbInterface usbInterface;
final UsbEndpoint in;
final UsbEndpoint out;
public DeviceCheckThread(Device device, UsbDeviceConnection usbConnection, UsbInterface usbInterface) {
this.device = device;
this.usbConnection = usbConnection;
this.usbInterface = usbInterface;
this.in = getInput(usbInterface);
this.out = getOutput(usbInterface);
}
public boolean checkDevice(UsbDeviceConnection usbConnection, UsbEndpoint in, UsbEndpoint out) {
if (usbConnection == null || in == null || out == null) {
return false;
}
final byte[] xor_table1 = { (byte) 0xA8, (byte) 0x25, (byte) 0x3f, (byte) 0x97, (byte) 0x4e, (byte) 0xb9 };
final byte[] xor_table2 = { (byte) 0x1c, (byte) 0xab, (byte) 0x17, (byte) 0x95, (byte) 0x3e, (byte) 0x9f };
final byte[] random_table1 = hex2Byte(randomHexString(6));
final byte[] random_table2 = hex2Byte(randomHexString(6));
{
byte[] request = new byte[20];
Arrays.fill(request, (byte) 0x00);
request[0] = (byte) 0x0D;
request[1] = (byte) 0x43;
request[2] = (byte) 0x57;
request[3] = (byte) 0x52;
request[4] = (byte) 0x55;
send(usbConnection, out, request);
}
{
byte[] response = read(usbConnection, in, 500, 3);
if (response == null || response.length == 0) {
Log.w(TAG, "Check device -> step 2: none response.");
return false;
}
if (response.length < 2 || response[0] != (byte) 0x0D || response[1] != (byte) 0x44) {
Log.w(TAG, "Check device -> step 2: invalid response.");
return false;
}
byte[] request = new byte[20];
Arrays.fill(request, (byte) 0x00);
request[0] = (byte) 0x0D;
request[1] = (byte) 0x53;
request[2] = (byte) (random_table1[0] ^ xor_table1[0]);
request[3] = (byte) (random_table1[1] ^ xor_table1[1]);
request[4] = (byte) (random_table1[2] ^ xor_table1[2]);
request[5] = (byte) (random_table1[3] ^ xor_table1[3]);
request[6] = (byte) (random_table1[4] ^ xor_table1[4]);
request[7] = (byte) (random_table1[5] ^ xor_table1[5]);
request[8] = random_table2[0];
request[9] = random_table2[1];
request[10] = random_table2[2];
request[11] = random_table2[3];
request[12] = random_table2[4];
request[13] = random_table2[5];
request[19] = getCrc(request, 1, request.length - 1);
send(usbConnection, out, request);
}
{
byte[] response = read(usbConnection, in, 500, 3);
if (response == null || response.length == 0) {
Log.w(TAG, "Check device -> step 3: none response.");
return false;
}
if (response.length < 14 || response[0] != (byte) 0x0D || response[1] != (byte) 0x54) {
Log.w(TAG, "Check device -> step 3: invalid response.");
return false;
}
byte[] data = Arrays.copyOfRange(response, 2, 2 + 6);
byte[] mac = Arrays.copyOfRange(response, 8, 8 + 6);
byte[] data_xor = new byte[data.length];
for (int i = 0; i < data.length; i++) {
data_xor[i] = (byte) (data[i] ^ xor_table2[i]);
}
byte[] mac_xor = new byte[mac.length];
for (int i = 0; i < mac.length; i++) {
mac_xor[i] = (byte) (mac[i] ^ xor_table2[i]);
}
byte[] encrypt_xor = new byte[6];
for (int i = 0; i < encrypt_xor.length; i++) {
encrypt_xor[i] = (byte) (mac_xor[i] + random_table1[i]);
}
if (Arrays.equals(data_xor, encrypt_xor)) {
Log.i(TAG, "Check device succeed.");
return true;
} else {
Log.w(TAG, "Check device failed.");
return false;
}
}
}
public String requestMacAddress(UsbDeviceConnection usbConnection, UsbEndpoint in, UsbEndpoint out) {
if (usbConnection == null || in == null || out == null) {
return null;
}
final byte[] mac = new byte[6];
Arrays.fill(mac, (byte) 0x00);
{
byte[] request = new byte[9];
Arrays.fill(request, (byte) 0x00);
request[0] = (byte) 0x0D;
request[1] = (byte) 0xDB;
request[2] = (byte) 0x61;
request[3] = (byte) 0xBB;
request[4] = (byte) 0x01;
send(usbConnection, out, request);
}
{
byte[] response = read(usbConnection, in, 500, 3);
if (response == null || response.length == 0) {
Log.w(TAG, "Request mac address -> step 2: none response.");
return null;
}
if (response.length < 3 || response[0] != (byte) 0x0D || response[1] != (byte) 0xDC || response[2] != (byte) 0x71) {
Log.w(TAG, "Request mac address -> step 2: invalid response.");
return null;
}
if (response.length < 9) {
Log.w(TAG, "Request mac address -> step 2: invalid length.");
return null;
} else {
for (int i = 0; i < mac.length; i++) {
mac[i] = response[3 + i];
}
if (allEquals(mac, (byte) 0x00)) {
Log.w(TAG, "Request mac address -> step 2: invalid data.");
return null;
}
Log.d(TAG, "Check mac address: " + bytesToHex(mac));
}
byte[] request = new byte[9];
Arrays.fill(request, (byte) 0x00);
request[0] = (byte) 0x0D;
request[1] = (byte) 0xDB;
request[2] = (byte) 0x62;
for (int i = 0; i < mac.length; i++) {
request[i + 3] = mac[i];
}
send(usbConnection, out, request);
}
{
byte[] response = read(usbConnection, in, 500, 3);
if (response == null || response.length == 0) {
Log.w(TAG, "Request mac address -> step 3: none response.");
return null;
}
if (response.length < 3 || response[0] != (byte) 0x0D || response[1] != (byte) 0xDC || response[2] != (byte) 0x72) {
Log.w(TAG, "Request mac address -> step 3: invalid response.");
return null;
}
if (response.length < 5 || response[3] != (byte) 0x06 || response[4] != (byte) 0x06) {
Log.w(TAG, "Request mac address -> step 3: check failed.");
return null;
}
}
return bytesToHex(mac);
}
@Override
public void run() {
try {
device.status.set(Device.STATUS_CHECKING);
if (checkDevice(usbConnection, in, out)) {
if (device.status() != Device.STATUS_REMOVED) {
device.status.set(Device.STATUS_CHECKED);
}
while (device.status() != Device.STATUS_REMOVED) {
String mac = requestMacAddress(usbConnection, in, out);
if (TextUtils.isEmpty(mac)) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
device.mac.set(mac);
if (!TextUtils.isEmpty(device.path())) {
File file = new File(device.path(), "mac");
write(file, mac);
}
break;
}
} else {
if (device.status() != Device.STATUS_REMOVED) {
device.status.set(Device.STATUS_INVALID);
}
}
} finally {
try {
usbConnection.releaseInterface(usbInterface);
usbConnection.close();
} catch (Exception e) {
}
}
}
}
static class Device {
public static final int STATUS_IDLE = 0;
public static final int STATUS_CHECKING = 1;
public static final int STATUS_CHECKED = 2;
public static final int STATUS_INVALID = 3;
public static final int STATUS_REMOVED = 4;
final AtomicInteger status = new AtomicInteger(STATUS_IDLE);
final AtomicReference<String> mac = new AtomicReference<String>();
final UsbDevice device;
final String path;
final String manufacturer;
final String product;
public Device(UsbDevice device) {
this.device = device;
path = getUsbDevicePath(device);
if (TextUtils.isEmpty(path)) {
manufacturer = null;
product = null;
} else {
manufacturer = read(new File(path, "manufacturer"));
product = read(new File(path, "product"));
}
}
public String path() {
return path;
}
public String manufacturer() {
return manufacturer;
}
public String product() {
return product;
}
public String name() {
if (TextUtils.isEmpty(manufacturer) || TextUtils.isEmpty(product)) {
return null;
}
return manufacturer + " " + product;
}
public int status() {
return status.get();
}
public String mac() {
return mac.get();
}
public UsbDevice device() {
return device;
}
}
}
|