USB gadget worked as mass_storage:
static void android_work(struct work_struct *data)
{
struct android_dev *dev = container_of(data, struct android_dev, work);
struct usb_composite_dev *cdev = dev->cdev;
char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
char *connected[2] = { "USB_STATE=CONNECTED", NULL };
char *configured[2] = { "USB_STATE=CONFIGURED", NULL };
char **uevent_envp = NULL;
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
if (cdev->config)
uevent_envp = configured;
else if (dev->connected != dev->sw_connected) {
if (dev->connected) {
wake_lock(&g_wake_lock);
} else {
wake_unlock(&g_wake_lock);
}
uevent_envp = dev->connected ? connected : disconnected;
}
dev->sw_connected = dev->connected;
g_flag_conn = dev->connected;
spin_unlock_irqrestore(&cdev->lock, flags);
if (uevent_envp) {
kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
} else {
pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
dev->connected, dev->sw_connected, cdev->config);
}
}
监测到这个事件后:
/*
* Listens for uevent messages from the kernel to monitor the USB state
*/
private final UEventObserver mUEventObserver = new UEventObserver() {
@Override
public void onUEvent(UEventObserver.UEvent event) {
if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
String state = event.get("USB_STATE");
String accessory = event.get("ACCESSORY");
if (state != null) {
mHandler.updateState(state);
} else if ("START".equals(accessory)) {
if (DEBUG) Slog.d(TAG, "got accessory start");
startAccessoryMode();
}
}
};
/*mHandler.updateState(state)-> updateState;*/
public void updateState(String state) {
int connected, configured;
if ("DISCONNECTED".equals(state)) {
connected = 0;
configured = 0;
} else if ("CONNECTED".equals(state)) {
connected = 1;
configured = 0;
} else if ("CONFIGURED".equals(state)) {
connected = 1;
configured = 1;
} else {
Slog.e(TAG, "unknown state " + state);
return;
}
removeMessages(MSG_UPDATE_STATE);
Message msg = Message.obtain(this, MSG_UPDATE_STATE);
msg.arg1 = connected;
msg.arg2 = configured;
// debounce disconnects to avoid problems bringing up USB tethering
sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
}
private static final String USB_STATE_MATCH =
"DEVPATH=/devices/virtual/android_usb/android0";
frameworks/base/packages/systemui2/src/com/android/systemui/usb/storagenotification.java
public StorageNotification(Context context) {
mContext = context;
onUsbMassStorageConnectionChanged(connected);
onStorageStateChanged(sharePath,shareState, shareState);
}
packages/SystemUI/src/com/android/systemui/usb
下面是提示用户打开ums的资源信息:
再看一下那个全屏显示的窗口的信息:
frameworks/base/core/res/res/values/strings.xml
<stringname="usb_storage_button_mount">Turn on USBstorage</string>
<string name="usb_storage_message"product="default">You have connected to yourcomputer via USB. Touch the button below if you want to copy filesbetween your computer and your Android\u2018s SDcard.</string>
frameworks/base/core/res/res/layout/usb_storage_activity.xml
android:text="@string/usb_storage_button_mount"
所以整个的用户交互的UI信息都在SystremUI这个系统app里边。
当点击turn on usbstorage时,logcat中,跟踪到UsbStorageActivity:oncreatedialoge,这个tag在usbstorageactivity.java 中发现
UsbStorageActivity这个activity在updateUsbMassStorageNotification已经做好准备了,等待用户turn on后立即启动。
public Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DLG_CONFIRM_KILL_STORAGE_USERS:
return new AlertDialog.Builder(this)
.setTitle(R.string.dlg_confirm_kill_storage_users_title)
.setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switchUsbMassStorage(true);
}})
.setNegativeButton(R.string.cancel, null)
.setMessage(R.string.dlg_confirm_kill_storage_users_text)
.setOnCancelListener(this)
.create();
}
/*switchUsbMassStorage*/
private void switchUsbMassStorage(final boolean on) {
// things to do on the UI thread
mUIHandler.post(new Runnable() {
@Override
public void run() {
mUnmountButton.setVisibility(View.GONE);
mMountButton.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
// will be hidden once USB mass storage kicks in (or fails)
}
});
// things to do elsewhere
mAsyncStorageHandler.post(new Runnable() {
@Override
public void run() {
if (on) {
//SystemProperties.set("sys.connect.UsbMassStorage","share");
//SystemClock.sleep(100);
mStorageManager.enableUsbMassStorage();
} else {
//SystemProperties.set("sys.connect.UsbMassStorage","unshare");
//SystemClock.sleep(100);
mStorageManager.disableUsbMassStorage();
//SystemClock.sleep(100);
//SystemProperties.set("sys.connect.UsbMassStorage","share");
}
}
});
}
public void setUsbMassStorageEnabled(boolean enable) {
waitForReady();
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
final StorageVolume primary = getPrimaryPhysicalVolume();
if (primary == null) return;
// TODO: Add support for multiple share methods
/*
* If the volume is mounted and we're enabling then unmount it
*/
String path = primary.getPath();
String vs = getVolumeState(path);
String method = "ums";
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
// Override for isUsbMassStorageEnabled()
setUmsEnabling(enable);
UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
// Clear override
setUmsEnabling(false);
}
//
//support /mnt/sdcard and /mnt/sdcardEx for ums
String TFcard_path = Environment.getTFcardStorageDirectory().getPath();
String TFcard_vs = getVolumeState(TFcard_path);
if (enable && TFcard_vs.equals(Environment.MEDIA_MOUNTED)) {
// Override for isUsbMassStorageEnabled()
setUmsEnabling(enable);
UmsEnableCallBack TFcard_umscb = new UmsEnableCallBack(TFcard_path, method, true);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, TFcard_umscb));
// Clear override
setUmsEnabling(false);
}
/*
* If we disabled UMS then mount the volume
*/
if (!enable) {
doShareUnshareVolume(path, method, enable);
if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
Slog.e(TAG, "Failed to remount " + path +
" after disabling share method " + method);
/*
* Even though the mount failed, the unshare didn't so don't indicate an error.
* The mountVolume() call will have set the storage state and sent the necessary
* broadcasts.
*/
}
}
//
//support /mnt/sdcard and /mnt/sdcardEx for ums
//LWC@nusmart modify,if tfcard is shared,we diable ums(for tfcard)
if (!enable) {
if (TFcard_vs.equals(Environment.MEDIA_SHARED)){
doShareUnshareVolume(TFcard_path, method, enable);
if (doMountVolume(TFcard_path) != StorageResultCode.OperationSucceeded) {
Slog.e(TAG, "Failed to remount " + TFcard_path +
" after disabling share method " + method);
/*
* Even though the mount failed, the unshare didn't so don't indicate an error.
* The mountVolume() call will have set the storage state and sent the necessary
* broadcasts.
*/
}
}
}
}
/************************************************************************/
private NativeDaemonConnector mConnector;
private void doShareUnshareVolume(String path, String method, boolean enable) {
// TODO: Add support for multiple share methods
if (!method.equals("ums")) {
throw new IllegalArgumentException(String.format("Method %s not supported", method));
}
try {
mConnector.execute("volume", enable ? "share" : "unshare", path, method);
} catch (NativeDaemonConnectorException e) {
Slog.e(TAG, "Failed to share/unshare", e);
}
}
int VolumeManager::shareVolume(const char *label, const char *method) {
Volume *v = lookupVolume(label);
-----
else if (!strcmp(argv[1], "share")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: volume share <path> <method>", false);
return 0;
}
rc = vm->shareVolume(argv[2], argv[3]);
}
#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
#define TFCARD_MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun1/file"
int VolumeManager::shareVolume(const char *label, const char *method) {
Volume *v = lookupVolume(label);
if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
return -1;
}
if ((tfcard_fd = open(TFCARD_MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
SLOGE("Unable to open ums lunfile1 (%s)", strerror(errno));
return -1;
}
}
从USB 的插入到 对应的back file打开的这个过程,就是上面这个样子。
private boolean setUsbConfig(String config) {
if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
SystemProperties.set("sys.usb.config", config);
return waitForState(config);
}
private void setEnabledFunctions(String functions, boolean makeDefault) {
setUsbConfig(mCurrentFunctions);
}
usb的功能是应用程序设置的,而写属性文件是在下面实现的。
on property:sys.usb.config=acm,adb
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 271f
write /sys/class/android_usb/android0/idProduct 8702
write /sys/class/android_usb/android0/functions ${sys.usb.config} [write the sysfs: /sys/class/android_usb/android0/functions]
write /sys/class/android_usb/android0/f_acm/instances 2
write /sys/class/android_usb/android0/enable 1 [write the sysfs: write /sys/class/android_usb/android0/enable]
start tty_trans_1
start tty_trans_2
start adbd
setprop sys.usb.state ${sys.usb.config}
default.prop: persist.sys.usb.config=mass_storage,adb
那么SystemProperties.set("sys.usb.config", config);里的config 又来自哪里?请参考: