关闭

二、Usb mass_storage turn on 的过程

884人阅读 评论(0) 收藏 举报
分类:

转自:http://blog.sina.com.cn/s/blog_6100a4f10101ee3u.html

  下面从framework层的ui来看一下插入usbshare的过程,这个动作的触发是从status bar下面弹出的usb connect开始的。

frameworks/base/packages/SystemUI

通过一系列反跟踪,这个packages是系统级别的,用来展示系统的UI,当插入usb线时,会在下方的status bar上会显示usb连接图标。

         USB connected

         Select to copy files to/from your computer

点击这个项后会谈出 turn on USB storage

资源所在路径:

base/core/res/res/values/strings.xml

    <!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across.  This is the title -->

    <string name="usb_storage_notification_title">USB connected</string>

    <!-- See USB_STORAGE. This is the message. -->

    <string name="usb_storage_notification_message">Select to copy files to/from your computer.</string>

这两个变量是在

/base/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java里边被使用

StorageNotification.java

主要用来处理存储设备相关动作的状态更新、通知。主要涉及两个方面:一是插入usb cabel后的状态栏更新,主要针对ums功能。二是storage状态发生改变时,会调用这个activity,如mountunmount等。

所以入口主要有两个:onUsbMassStorageConnectionChangedonStorageStateChanged分别处理usb连接状态的改变和storage状态的改变。

一 注册StorageManager存储设备状态变更监听器 StorageNotification

       Storagenotification这个activity是怎么被启动的呢?从而触发了usb connect changed的函数动作?

是通过下面的监听器注册来完成的。

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarPolicy.java

// storage

        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);

        mStorageManager.registerListener(

                new com.android.systemui.usb.StorageNotification(context));

这个将StorageNotification注册到mStorageManagerlistener中,没有理解listener的机制。但是猜测应该是当listenser到某个消息时会启动这个注册的activity

注册StorageManager的存储设备状态变更监听器来实现的。

 

二 针对usb线连接动作的通知

       storageNotification这个类的构造函数中,直接调用了下面这个usb 连接状态的处理函数,onUsbMassStorageConnectionChanged(connected);通过和上面的联系起来就是,当监听器监听到变化后,开始启动这个activity,构造函数开始执行,执行一系列动作,包括对usb状态的处理,以及后面将会遇到的storage状态的处理。  

2.1 构造函数:

    public StorageNotification(Context context) {

        mContext = context;

        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);

        final boolean connected = mStorageManager.isUsbMassStorageConnected();

        Slog.d(TAG, String.format( "Startup with UMS connection %s (media state %s)", mUmsAvailable,

                Environment.getExternalStorageState()));

        HandlerThread thr = new HandlerThread("SystemUI StorageNotification");

        thr.start();

        mAsyncEventHandler = new Handler(thr.getLooper());

        mUsbNotifications = new HashSet();

        mLastState = Environment.MEDIA_MOUNTED;

        mLastConnected = false;

        onUsbMassStorageConnectionChanged(connected);

                   ……………………

        StorageVolume[] volumes = mStorageManager.getVolumeList(); 

        for (int i=0; i<volumes.length; i++) {

            String sharePath = volumes[i].getPath();

            String shareState = mStorageManager.getVolumeState(sharePath);

            Slog.d(TAG, "onStorageStateChanged - sharePath: " + sharePath + " shareState: " + shareState);

            if (shareState.equals(Environment.MEDIA_UNMOUNTABLE)) {

                onStorageStateChanged(sharePath, shareState, shareState);           

            }

        }

 

2.2  onUsbMassStorageConnectionChanged 

    @Override

    public void onUsbMassStorageConnectionChanged(final boolean connected) {

        mAsyncEventHandler.post(new Runnable() {

            @Override

            public void run() {

                onUsbMassStorageConnectionChangedAsync(connected);

            }

        });

    }

2.3  onUsbMassStorageConnectionChangedAsync

    private void onUsbMassStorageConnectionChangedAsync(boolean connected) {

              mUmsAvailable = connected;//插上usb ums就使能了,不合适啊,还得根据是否有mass_storage功能

              另外这个函数中代码明确表示ums的优先级高于mtp。如果包含mass_storage功能,就发出status bar通知。

       这个函数中的主要工作是调用updateUsbMassStorageNotification来更新status bar,但是采用什么机制来决定是否调用这个函数进行更新,是会根据mtp/ums功能来选择的,不同的产品应该会有不同的机制。

              这个status bar的更新机制,很容易被误触,有时并不需要ums功能,但是需要光盘功能,却被误打开。尤其是mtp+cdrom的状态。

    void updateUsbMassStorageNotification(boolean available) { 

        if (available) {

            SXlog.d(TAG, "updateUsbMassStorageNotification - [true]");

            Intent intent = new Intent();

            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);

            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                    

                     //准备出等待要执行的activitypi

            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);

            setUsbStorageNotification(//在下面的status bar中显示usb connect

                    com.android.internal.R.string.usb_storage_notification_title,

                    com.android.internal.R.string.usb_storage_notification_message,

                    com.android.internal.R.drawable.stat_sys_data_usb,

                    false, true, pi);

        } else {

            SXlog.d(TAG, "updateUsbMassStorageNotification - [false]");

            setUsbStorageNotification(0, 0, 0, false, false, null);

        }   

    }   

2.4  setUsbStorageNotification

    private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon,

            boolean sound, boolean visible, PendingIntent pi) {

              组装mUsbStorageNotification变量,最后通过 notificationManager发出。

           这个函数在最后有下面的动作,应该是一个通知消息。

        if (visible) {

            notificationManager.notify(notificationId, mUsbStorageNotification);

        } else {

            notificationManager.cancel(notificationId);

        }

       在通过 notificationManager mUsbStorageNotification发出时,会在status bar上出现提示条:usb connect,用户点击这个usb connect后,会弹出一个界面,提示用户是否打开usb mass storage。另外mUsbStorageNotification有一个重要的pendingintent参数,用来提示是否直接执行这个activity

       从这个函数的代码及实验现象来看,是这样设计的,如果没有启用adb,将直接弹出让用户使能ums的全屏(就是启动了pendingintentactivity),如果使能了adb,不会自动弹出来,需要用户自己去展开 status bar.

注意adb这部分的判断信息:

            final boolean adbOn = 1 == Settings.Secure.getInt(

                mContext.getContentResolver(),

                Settings.Secure.ADB_ENABLED,

                0);

注意这块获取的是黄色部分的信息。

下面是UsbDeviceManager.java中的部分

        // make sure the ADB_ENABLED setting value matches the current state

        Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, mAdbEnabled ? 1 : 0);

这个代码是在启动启动systemReady中的,就是说当用户设置的默认function中有adb功能时,将信息更新到Setting.Secure.ADB_ENABLED中,以便setting中同步。如果用户在应用中直接使用setprop的话,setting中是得不到更新的。

       所以 UsbStorageActivity的启动有两种方式,直接启动或者通过点击usb connect启动。

点击usb conect这个动作,没有找到代码,猜测应该是在 notificationManager里边处理了,因为包括要启动的activity都在参数里边了。

2.5 UsbStorageActivity.java

packages/SystemUI/src/com/android/systemui/usb

下面是提示用户打开ums的资源信息:

再看一下那个全屏显示的窗口的信息:

frameworks/base/core/res/res/values/strings.xml

<string name="usb_storage_button_mount">Turn on USB storage</string>

<string name="usb_storage_message" product="default">You have connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>

frameworks/base/core/res/res/layout/usb_storage_activity.xml

android:text="@string/usb_storage_button_mount"

所以整个的用户交互的UI信息都在SystremUI这个系统app里边。

当点击turn on usb storage时,logcat中,跟踪到UsbStorageActivity:oncreatedialoge,这个tagusbstorageactivity.java中发现

UsbStorageActivity这个activityupdateUsbMassStorageNotification已经做好准备了,等待用户turn on后立即启动。 

public Dialog onCreateDialog(int id, Bundle args) {

        Log.i(TAG, "onCreateDialoge");

        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) {

                                mHasCheck = false;

                            switchUsbMassStorage(true);

                        }})

通过点击确认后回弹出一个alertdialog,确认就是这个流程。资源信息在下面。当点击确定按钮后将执行switchUsbMassStorage

    <!-- USB_STORAGE_KILL_STORAGE_USERS dialog  -->

    <string name="dlg_confirm_kill_storage_users_title">Turn on USB storage</string>

    <!-- USB_STORAGE_KILL_STORAGE_USERS dialog message text -->

    <string name="dlg_confirm_kill_storage_users_text">If you turn on USB storage, some applications you are using will stop and may be unavailable until you turn off USB storage.</string>

onClick----checkStorageUsers---checkStorageUsersAsync

scheduleShowDialog 

2.6 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) {

                    mSettingUMS = true;

                    mStorageManager.enableUsbMassStorage();

                } else {

                    mSettingUMS = false;

                    mStorageManager.disableUsbMassStorage();

                }

            }

        });

    }

2.7 StorageManager.java

       frameworks/base/core/java/android/os/storage/StorageManager.java 

mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);

    public void enableUsbMassStorage() {

        try {

            mMountService.setUsbMassStorageEnabled(true);

        } catch (Exception ex) {

            Log.e(TAG, "Failed to enable UMS", ex);

        }

    }

mMountService.setUsbMassStorageEnabled(true)( ImountService.java)

        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));

下面没有跟踪下去,猜想应该会在vold里边完成,但是怎么传达下去的呢?在mountservice.java中也有setUsbMassStorageEnabled函数,这个是services目录下面的。这个函数里边是我们要找的。

2.8 mountservice.java

/framework/base/services/java/com/android/server/mountservice.java

    public void setUsbMassStorageEnabled(boolean enable) {

              ………………

            } else if (enable && state.equals(Environment.MEDIA_UNMOUNTED)) {

                doShareUnshareVolume(path, method, enable);

            }

       将所有的volume都进行处理,方法为”ums”

2.9 Doshareunsharevolume

    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.doCommand(String.format(

                    "volume %sshare %s %s", (enable ? "" : "un"), path, method));

        } catch (NativeDaemonConnectorException e) {

            Slog.e(TAG, "Failed to share/unshare", e);

        }

    }

         上面红色的就是传达下去的命令及参数

2.10 comandlistener.cpp

system/vold/comandlistener.cpp

----àmconnector.docommand,命令应该对应volume,不同的是对应的命令为volume命令集。

mconnector.doCommand进入nativedaemonconnector.java  docommand--à

经过jni进入到comandlistener.cpp该文件位于system/vold文件夹内,有各种命令的监听处理,cdromvolumestorage等。

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

2.11  VolumeManager.cpp

#define MASS_STORAGE_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun/file"

#define MASS_STORAGE_EXTERNAL_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun1/file"

int VolumeManager::shareVolume(const char *label, const char *method) {

分别对内置和外置sd卡都作了处理,看来只支持2个。

    if(primaryStorage) {

        if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {

            SLOGE("Unable to open ums lunfile (%s)", strerror(errno));

            return -1;

        }

    }

    else

    {

        if ((fd = open(MASS_STORAGE_EXTERNAL_FILE_PATH, O_WRONLY)) < 0) {

            SLOGE("Unable to open ums lunfile (%s)", strerror(errno));

            return -1;

        }

    }

    if (write(fd, nodepath, strlen(nodepath)) < 0) {

        SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));

        close(fd);

        return -1;

    }

到此完成了back-file的对应。

三 介质状态发生改变的处理

    这个函数是当存储介质的状态发生改变时,会被调用。调用主要发生在StorageManager.java, MountService.java,  UsbStorageActivity.java等一下文件中。

       public void onStorageStateChanged(final String path, final String oldState, final String newState) {

        mAsyncEventHandler.post(new Runnable() {

            @Override

            public void run() {

                onStorageStateChangedAsync(path, oldState, newState);

            }

        });

    }

       存储的状态发生变化,如挂载完成了、卸载了、等等,所以当挂载完成后,也会去调用更新。

    private void onStorageStateChangedAsync(String path, String oldState, String newState) {

        Slog.i(TAG, String.format(

                "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));

        mLastState = newState;

        StorageVolume volume = null;

        StorageVolume[] Volumes = mStorageManager.getVolumeList();           

        for(int i = 0; i < Volumes.length; i++){

             if(Volumes[i].getPath().equals(path)) {

               volume = Volumes[i];

                   break;                

            }

        }    

              if (volume == null) {

                        Slog.e(TAG, String.format(

                "Can NOT find volume by name {%s}", path));

                        return;

              }

 

        if (newState.equals(Environment.MEDIA_SHARED)) {

       ……………………

        } else if (newState.equals(Environment.MEDIA_MOUNTED)) {

           

            SXlog.d(TAG, "onStorageStateChangedAsync - [MEDIA_MOUNTED]");

            setMediaStorageNotification(path, 0, 0, 0, false, false, null);

            updateUsbMassStorageNotification(mUmsAvailable);

                     //挂载成功后,就会调用更新函数,并且只要usb连接着就更新。难道是有些场景usb一直连接着,但是发生了介质重新mounted的情况,所以需要update

            if("/mnt/sdcard".equals(path)) {

                mUsbNotifications.clear();

            }

        }

todo//storage的逻辑思路,需要详细看下面两个文件:

base/core/java/android/os/storage/StorageManager.java

base/services/java/com/android/server/mountservice.java

frameworkandroid向应用程序开发提供的一个框架,简单理解为API.她创建了一系列的class对象,通过这些对象的接口行为,来操作各种组件功能。Framework根据产品的功能及用户的行为抽象出了各种组件,应用程序开发可以直接调用。那么framework的设计也是有一个框架的,是一个独立的层。麻雀虽小,五脏俱全。

frameworks/base 这个目录下是framework的基本代码,基本代码中的core目录,顾名思义应该是框架的核心骨架代码。这个骨架的实现是需要javacpp的,其间通过jni来实现调用。其中services目录是为framework中功能提供后台服务用的,上层应用是调用不到的。


问题分析试验记录:

1 使用当年的ums功能的,使能mass_storage,adbacm时,ums可以使用 android_usb/f_mass_storage下面有相应的设备backfile

2 当使用mtp时,也是没有看到相应的设备文件。这个bin文件是比较早的,刚刚去掉cdromconfirm dialog的。去掉对话框还是有bug的版本。当插入usb cabel时,下方还显示usb connect。这种情况下mtp进入后看不到盘符。(usb connect后是不是做了什么)

设置setprop sys.usb.config mass_storage,adb,acm后,虽然可以切换成功,但是点击turn on时,不会弹出alert对话框,并且backfile share不成功。

找到一部分原因:没有定义MTK_MASS_STORAGE= yes时,在android.c中是不会创建节点的。mass_storage_function_init验证中。一直出现adboffline。并且usb connect又出现了。Umsmtp共用的情况下会出现adb offline

 

考虑到以前在mtp+cdrom的情况下是去掉usb connect显示的,没有adb也不要弹出usb mass_storage turn on 提示框的。但是这种情形下都出来了(MTK_MASS_STORAGE= yes)

SetUsbStorageNotificationonStorageStateChangedAsync也被调用过。不过这个是判断状态为shared的情况,share成功后显示Turn off USB storage

    private void onStorageStateChangedAsync(String path, String oldState, String newState) {

        Slog.i(TAG, String.format(

                "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));

        mLastState = newState;

        if (newState.equals(Environment.MEDIA_SHARED)) {

            SXlog.d(TAG, "onStorageStateChangedAsync - [MEDIA_SHARED]");

            Intent intent = new Intent();

            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);

            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);

            setUsbStorageNotification(

                    com.android.internal.R.string.usb_storage_stop_notification_title,

                    com.android.internal.R.string.usb_storage_stop_notification_message,

                    com.android.internal.R.drawable.stat_sys_warning, false, true, pi);

            if("/mnt/sdcard".equals(path)) {

                mUsbNotifications.clear();

            }

        }

到底是从哪里触发的呢?

Bar中显示也变为”Connected as USB Storage”

./res/values/strings.xml:2859:    <string name="usb_ums_notification_title">Connected as USB Storage</string>

./res/values/strings.xml:2855:    <string name="usb_mtp_notification_title">Connected as a media device</string>

./res/values/strings.xml:2863:    <string name="usb_cd_installer_notification_title">Connected as an installer</string>

这个更新是在UsbDeviceManager.java里边完成的。

   private void updateUsbNotification() {


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:31246次
    • 积分:442
    • 等级:
    • 排名:千里之外
    • 原创:3篇
    • 转载:47篇
    • 译文:0篇
    • 评论:0条