Android 5.x中 UsbDevice mInterfaces为空的解决方法

前提

最近做的项目在android5.0的系统的开发板连多个usb设备,偶尔会出现设备无反应的情况,通过调试发现UsbDevice的mInterfaces会离奇出现空的情况,刷回4.4则没这个情况出现,我感觉应该是系统api的问题,于是上网搜索,发现
android framework之旅(六)Usb多串口同时打开 有大神也遇到这种情况并分析是系统api的锅,文中作者的解决方法是修改系统api,重编译Android Framework 模块并写进系统。

应用级别的解决方案

看到原作者的分析,如果只是设备信息丢失的话,是否可以通过反射UsbDevice来把usb设备的信息补全呢?看了下源码果然是可以的
下面是UsbDevice 部分源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class UsbDevice implements Parcelable {
/** All configurations for this device, only null during creation */
private @Nullable Parcelable[] mConfigurations;
/** All interfaces on the device. Initialized on first call to getInterfaceList */
private @Nullable UsbInterface[] mInterfaces;
public @NonNull UsbInterface getInterface(int index) {
return getInterfaceList()[index];
}
private @Nullable UsbInterface[] getInterfaceList() {
if (mInterfaces == null) {
int configurationCount = mConfigurations.length;
int interfaceCount = 0;
for (int i = 0; i < configurationCount; i++) {
UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
interfaceCount += configuration.getInterfaceCount();
}
mInterfaces = new UsbInterface[interfaceCount];
int offset = 0;
for (int i = 0; i < configurationCount; i++) {
UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
interfaceCount = configuration.getInterfaceCount();
for (int j = 0; j < interfaceCount; j++) {
mInterfaces[offset++] = configuration.getInterface(j);
}
}
}
return mInterfaces;
}
}

下面是UsbConfiguration 部分源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class UsbConfiguration implements Parcelable {
private final int mId;
private final @Nullable String mName;
private final int mAttributes;
private final int mMaxPower;
/** All interfaces for this config, only null during creation */
private @Nullable Parcelable[] mInterfaces;
public UsbConfiguration(int id, @Nullable String name, int attributes, int maxPower) {
mId = id;
mName = name;
mAttributes = attributes;
mMaxPower = maxPower;
}
}

下面是UsbInterface 部分源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class UsbInterface implements Parcelable {
private final int mId;
private final int mAlternateSetting;
private @Nullable final String mName;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
/** All endpoints of this interface, only null during creation */
private Parcelable[] mEndpoints;
/**
* UsbInterface should only be instantiated by UsbService implementation
* @hide
*/
public UsbInterface(int id, int alternateSetting, @Nullable String name,
int Class, int subClass, int protocol) {
mId = id;
mAlternateSetting = alternateSetting;
mName = name;
mClass = Class;
mSubclass = subClass;
mProtocol = protocol;
}
}

下面是UsbEndpoint 部分源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UsbEndpoint implements Parcelable {
private final int mAddress;
private final int mAttributes;
private final int mMaxPacketSize;
private final int mInterval;
/**
* UsbEndpoint should only be instantiated by UsbService implementation
* @hide
*/
public UsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
mAddress = address;
mAttributes = attributes;
mMaxPacketSize = maxPacketSize;
mInterval = interval;
}
}

其中UsbDevice的getInterface是我们应用能访问到的接口,通过分析getInterfaceList可见,只要修改mConfigurations里面的mInterfaces即可达到补齐信息的效果,那么我们可以记录设备的信息再通过以下反射类的代码把信息补全即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void change(UsbDevice device) {
try {
Class<?> usbInterfaceClass = UsbInterface.class;
Class<?> usbEndpointClass = UsbEndpoint.class;
Class<?> deviceClass=device.getClass();
Field mConfigurations = deviceClass.getDeclaredField("mConfigurations");
mConfigurations.setAccessible(true);
Parcelable[] configurations= (Parcelable[]) mConfigurations.get(device);
UsbConfiguration usbConfiguration= (UsbConfiguration) configurations[0];
Constructor usbEndpointConstructor = usbEndpointClass.getDeclaredConstructor(int.class, int.class, int.class, int.class);
UsbEndpoint usbEndpoint = (UsbEndpoint) usbEndpointConstructor.newInstance(1, 2, 3, 4);//这里写入需要的UsbEndpoint信息
Parcelable[] usbEndpointParcelables=new Parcelable[]{usbEndpoint};
Constructor usbInterfaceClassDeclaredConstructor = usbInterfaceClass.getDeclaredConstructor(int.class,int.class, String.class,
int.class, int.class, int.class);
UsbInterface usbInterface= (UsbInterface) usbInterfaceClassDeclaredConstructor.newInstance(2,2,"test",2,2,2);//这里写入需要的UsbInterface信息
Field field = usbInterfaceClass.getDeclaredField("mEndpoints");
field.setAccessible(true);
field.set(usbInterface,usbEndpointParcelables);
Parcelable[] usbInterfaceParcelables=new Parcelable[]{usbInterface};
Field field2 = usbConfiguration.getClass().getDeclaredField("mInterfaces");
field2.setAccessible(true);
field2.set(usbConfiguration,usbInterfaceParcelables);
} catch (Exception e) {
e.printStackTrace();
}
}