android下usb框架系列文章---(2)Usb mass_storage turn on的过程
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 phoneto a computer via USB, we show a notification asking if he wants toshare files across.? This is the title-->
???<string name="usb_storage_notification_title">USBconnected</string>
???<!-- See USB_STORAGE. This is the message.-->
???<string name="usb_storage_notification_message">Selectto copy files to/from yourcomputer.</string>
?
這兩個變量是在
/base/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java里邊被使用
?
StorageNotification.java
主要用來處理存儲設備相關動作的狀態更新、通知。主要涉及兩個方面:一是插入usb cabel后的狀態欄更新,主要針對ums功能。二是storage狀態發生改變時,會調用這個activity,如mount、unmount等。
所以入口主要有兩個:onUsbMassStorageConnectionChanged和onStorageStateChanged分別處理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(
???????????????newcom.android.systemui.usb.StorageNotification(context));
這個將StorageNotification注冊到mStorageManager的listener中,沒有理解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 (mediastate %s)", mUmsAvailable,
???????????????Environment.getExternalStorageState()));
?
???????HandlerThread thr = new HandlerThread("SystemUIStorageNotification");
???????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(finalboolean connected) {
???????mAsyncEventHandler.post(new Runnable() {
???????????@Override
???????????public void run() {
???????????????onUsbMassStorageConnectionChangedAsync(connected);
???????????}
???????});
???}
2.3?onUsbMassStorageConnectionChangedAsync
???private void onUsbMassStorageConnectionChangedAsync(booleanconnected) {
?????????????mUmsAvailable = connected;//插上usb ums就使能了,不合適啊,還得根據是否有mass_storage功能
?????????????另外這個函數中代碼明確表示ums的優先級高于mtp。如果包含mass_storage功能,就發出status bar通知。
??????這個函數中的主要工作是調用updateUsbMassStorageNotification來更新status bar,但是采用什么機制來決定是否調用這個函數進行更新,是會根據mtp/ums功能來選擇的,不同的產品應該會有不同的機制。
?????????????這個status bar的更新機制,很容易被誤觸,有時并不需要ums功能,但是需要光盤功能,卻被誤打開。尤其是mtp+cdrom的狀態。
????
??? voidupdateUsbMassStorageNotification(booleanavailable) {
?
???????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);
????????????????????
????????????????????//準備出等待要執行的activity,pi
???????????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, intmessageId, 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的全屏(就是啟動了pendingintent的activity),如果使能了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 currentstate
???????Settings.Secure.putInt(mContentResolver,Settings.Secure.ADB_ENABLED, mAdbEnabled ? 1 : 0);
這個代碼是在啟動啟動systemReady中的,就是說當用戶設置的默認function中有adb功能時,將信息更新到Setting.Secure.ADB_ENABLED中,以便setting中同步。如果用戶在應用中直接使用setprop的話,setting中是得不到更新的。
??????所以 UsbStorageActivity的啟動有兩種方式,直接啟動或者通過點擊usb connect啟動。
點擊usbconect這個動作,沒有找到代碼,猜測應該是在notificationManager里邊處理了,因為包括要啟動的activity都在參數里邊了。
?
2.5 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){
???????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_USERSdialog? -->
???<string name="dlg_confirm_kill_storage_users_title">Turnon USB storage</string>
???<!-- USB_STORAGE_KILL_STORAGE_USERS dialog messagetext -->
???<stringname="dlg_confirm_kill_storage_users_text">If youturn on USB storage, some applications you are using will stop andmay be unavailable until you turn off USBstorage.</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 (orfails)
???????????}
???????});
?
???????// 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, Stringmethod, boolean enable) {
???????// TODO: Add support for multiple share methods
???????if (!method.equals("ums")) {
???????????throw new IllegalArgumentException(String.format("Method %s notsupported", 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文件夾內,有各種命令的監聽處理,cdrom、volume、storage等。
??? }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"
#defineMASS_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的對應。
?
2.12 流程圖
三介質狀態發生改變的處理
?
???這個函數是當存儲介質的狀態發生改變時,會被調用。調用主要發生在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
framework是android向應用程序開發提供的一個框架,簡單理解為API.她創建了一系列的class對象,通過這些對象的接口行為,來操作各種組件功能。Framework根據產品的功能及用戶的行為抽象出了各種組件,應用程序開發可以直接調用。那么framework的設計也是有一個框架的,是一個獨立的層。麻雀雖小,五臟俱全。
frameworks/base 這個目錄下是framework的基本代碼,基本代碼中的core目錄,顧名思義應該是框架的核心骨架代碼。這個骨架的實現是需要java和cpp的,其間通過jni來實現調用。其中services目錄是為framework中功能提供后臺服務用的,上層應用是調用不到的。
?
?
?
問題分析試驗記錄:
1 使用當年的ums功能的,使能mass_storage,adb,acm時,ums可以使用,android_usb/f_mass_storage下面有相應的設備backfile
2 當使用mtp時,也是沒有看到相應的設備文件。這個bin文件是比較早的,剛剛去掉cdrom的confirm dialog的。去掉對話框還是有bug的版本。當插入usb cabel時,下方還顯示usb connect。這種情況下mtp進入后看不到盤符。(usb connect后是不是做了什么)
設置setprop sys.usb.configmass_storage,adb,acm后,雖然可以切換成功,但是點擊turn on時,不會彈出alert對話框,并且backfile share不成功。
找到一部分原因:沒有定義MTK_MASS_STORAGE= yes時,在android.c中是不會創建節點的。mass_storage_function_init驗證中。一直出現adboffline。并且usb connect又出現了。Ums和mtp共用的情況下會出現adb offline?
?
考慮到以前在mtp+cdrom的情況下是去掉usb connect顯示的,沒有adb也不要彈出usb mass_storage turn on 提示框的。但是這種情形下都出來了(MTK_MASS_STORAGE= yes)。
SetUsbStorageNotification在onStorageStateChangedAsync也被調用過。不過這個是判斷狀態為shared的情況,share成功后顯示Turn off USB storage。
?
???private void onStorageStateChangedAsync(String path, StringoldState, 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:???<stringname="usb_ums_notification_title">Connected as USBStorage</string>
./res/values/strings.xml:2855:???<stringname="usb_mtp_notification_title">Connected as amedia device</string>
./res/values/strings.xml:2863:???<stringname="usb_cd_installer_notification_title">Connectedas an installer</string>
這個更新是在UsbDeviceManager.java里邊完成的。
?? private voidupdateUsbNotification() {
總結
以上是生活随笔為你收集整理的android下usb框架系列文章---(2)Usb mass_storage turn on的过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【PHP】初学者开篇入门版
- 下一篇: 微信内置浏览器下载APP(包括安卓apk