USB gadget: mass_storage's android layer

USB gadget worked as mass_storage:

kernel层数据的发送:

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);
    }
}

UsbDeviceManager.java

监测到这个事件后:
    /*
     * 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";

StorageNotification.java

frameworks/base/packages/systemui2/src/com/android/systemui/usb/storagenotification.java

   public StorageNotification(Context context) {
           mContext = context;
    onUsbMassStorageConnectionChanged(connected);
        onStorageStateChanged(sharePath,shareState, shareState);

     }

UsbStorageActivity.java

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");
                }
            }
        });
    }

MountService.java

    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);
        }
    }


vold/VolumeManager.cpp


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打开的这个过程,就是上面这个样子。


USB fuction的设置和enable

        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 又来自哪里?请参考:

android下usb框架系列文章---(5)Usb setting 中tethering 设置流程


你可能感兴趣的:(USB gadget: mass_storage's android layer)