引:因爲某些特殊需求,需要在某些設備接入車機的時候,動態UnMount USB設備,因爲代碼其中有一些方法是自定義過的,所以該文章僅供思路參考。
一:第一種方法是在java層做處理
如下需要涉及到/System/Vold 和frameWork 以及device層的修改。
其實主要是在framework層的修改,用到的方法也很簡單,需要用到:
StorageManager
StorageVolume
根據我當前項目的需求,是要求插入某一個device 的時候,判斷出是當前需要的設備的時候,卸載/禁止USB2 端口。
裏面可能有一些方法是已經重寫過的,正規的API 不一定有,比如getUsbId()就沒有,不過還是如篇頭所說提供下解決思路吧。
思路:爲了設備使用期間,USB2不能被使用,除了主動unmount之後,還需要保證下一次USB插拔的時候攔截USB掛載消息。(主動卸載只是生效一次),所以步驟就是2個,先主動unmount,在設置prop屬性在Vold中攔截USB掛載消息。
核心代碼:
**
* <P>if device Connected Unmount USB2</P>
* <P>beibei 20191231</P>
*/
private StorageManager mStorageManager;
private final String UNMOUNT_DEVICE_ID = "USB2";
private void StartUnmountUsbAccessory() {
Log.d(TAG, "StartUnmountUsbAccessory");
try {
if (mStorageManager == null){
Log.d(TAG, "mStorageManager is null");
mStorageManager = mContext.getSystemService(StorageManager.class);
}
List<StorageVolume> volumes =mStorageManager.getStorageVolumes();
for (int i = 0; i < volumes.size(); i++) {
Log.d(TAG, "StorageVolume start foreach");
//if usb the not's emulated/Primary , It's not an external usb
if (!volumes.get(i).isEmulated() && !volumes.get(i).isPrimary()) {
Log.d(TAG, "isEmulated && isPrimary");
if (UNMOUNT_DEVICE_ID.equals(volumes.get(i).getUsbId())) {
Log.d(TAG, "imStorageManager.unmount Success");
mStorageManager.unmount(volumes.get(i).getId());
}
}
}
} catch(Exception e){
e.printStackTrace();
}
}
解釋:通過StorageManager 獲取到StorageVolume,並通過循環遍歷,之後通過isPrimary(不是外部存儲卷)和isEmulated (不是模擬卷)過濾後,
下面的就是匹配自己想要UnMount的ID了,匹配成功後,調用mStorageManager.unmount。
**注意:**該方法調用會拋出System.error ,需要處理異常。
必須增加 try catch
/**
* Returns true if the volume is the primary shared/external storage, which is the volume
* backed by {@link Environment#getExternalStorageDirectory()}.
*/
public boolean isPrimary() {
return mPrimary;
}
/**
* Returns true if the volume is emulated.
*
* @return is removable
*/
public boolean isEmulated() {
return mEmulated;
}
然後其次就是 設置 prop
case MSG_PROJECTION_DEVICE_CONNECTED_SUCCESS:
StartUnmountUsbAccessory();
SystemProperties.set(UNMOUNT_DEVICE_PROP_STATE,"true");
break;
case MSG_PROJECTION_DEVICE_DISCONNECTED_SUCCESS:
SystemProperties.set(UNMOUNT_DEVICE_PROP_STATE,"false");
break;
關鍵的攔截USB mount的在/system/vold/ NetlinkHandler.cpp,的onEvent消息事件中。
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
/***Add usb2 disable temporary scheme 20191231 start***/
char args[PROPERTY_VALUE_MAX];
property_get("vendor.device.usb2",args,"false");
if (strcmp(args,"true")==0){
const char *path = evt->findParam("DEVPATH");
if (strstr(path,USB_2_PATH)!=NULL){
SLOGW("DISABLE USB2");
return;
}
}
/***Add usb2 disable temporary scheme 20191231 end***/
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);
}
}
至於Prop怎麼設置,百度下,一般寫在device/fsl/… 的 .mk文件中
https://blog.csdn.net/qq_31332467/article/details/104751769
Ps: PRODUCT_PROPERTY_OVERRIDES +=
vendor.device.usb2 = false
二:第二種可以在C++ 層
主要的一個代碼就是 echo shell 命令
#include<stdlib.h>
system("echo ‘1-1.2" >/sys/bus/usb/drivers/usb/unbind");
思路步驟是這樣的:
在C++代碼中找到合適的位置,先判斷出什麼情況下,接入什麼設備需要unMound USB,增加tag,當滿足的時候就執行system(“echo ‘1-1.2” >/sys/bus/usb/drivers/usb/unbind");
這個我也是在串口命令進行過測試,實際在代碼中,我沒有測試過,因爲有了第一種方法。
測試方法有效性:
串口進入到Android板子內部:
解綁:echo “1-1.2” > unbind
綁定:echo “1-1.2” > bind
具體代碼中實際應用沒有測試。