android  UsbDeviceManager

(2012-08-07 11:08:34)

转载
标签:

android

usb

杂谈

分类: 技术

一 光盘bicr的流程(UsbDeviceManager.java)

1.1 光盘backfile的控制

sys.usb.mtk_bicr_support:这个值系统变量用来标识是否显示光盘内容,两个值yes,yes_hide.

这个值的初始化发生在UsbDeviceManager.java文件里

if(nativeInitUMSproperty())

SystemProperties.set("sys.usb.mtk_bicr_support","yes");

static jboolean android_server_UsbService_initUMSproperty(JNIEnv *env, jobject thiz)

{

#ifdef MTK_BICR_SUPPORT

return true;

#else

return false;

#endif

}

是否支持光盘内容弹出通过MTK_BICR_SUPPORT宏来决定。光盘作为mass_storage的一个子类,只要在使能了mass_storage功能后,并且在mass_storage驱动中定义了cdrom的lun个数非0后,就会在pc上出现光驱。但是是否有文件系统还需要一个步骤。上面的sys.usb.mtk_bicr_support就是用来控制这个功能的开关。

该值为yes的话就会触发文件系统的挂载。

总体流程:

在UsbDeviceManager.java中showBuiltinInstallerUI,启用了BuiltinInstallerActivity。这个activity会弹出对话框询问用户是否需要光盘,其实是是否挂在光盘内容。

Mountservice.java中,shareCDRom---doshareunshareCDRom--mconnector.doCommand

进入nativedaemonconnector.java docommand--

经过jni进入到comandlistener.cpp该文件位于vold文件夹内,

执行CDROMCmd的runCommand函数,执行bicr.cpp的shareCdRom函数,

const char *Bicr::CD_ROM_PATH = "/dev/block/loop0";

const char *Bicr::CD_ROM_LUN_PATH = "/sys/class/android_usb/android0/f_mass_storage/lun-cdrom/file";

最后通过else if (write(fd, CD_ROM_PATH, strlen(CD_ROM_PATH)) < 0) {

完成了文件对应介质的操作。

1.2 光盘backfile的触发启动

PR:那么showBuiltinInstallerUI是什么时候启动的呢?挂载的介质在拔除usb cabel时有没有被清掉呢?防止下次在界面中虽然设置了hide,依然会显示光盘内容?所以应该是在拔除这个动作发生时清除才对。代验证。

第一种情况:系统启动完成时,但是要判断usb是否连接着,连接着才会考虑

if(action.equals(Intent.ACTION_BOOT_COMPLETED)) {

Slog.i(TAG, "BOOT_COMPLETED");

Handler showBuiltinInstallerHandler = new Handler();

showBuiltinInstallerHandler.postDelayed(mShowBuiltinInstallerRunnable, 14000);

}

private RunnablemShowBuiltinInstallerRunnable = new Runnable()

{

@Override

public void run()

{

Slog.i(TAG, "Delay show");

showBuiltinInstallerUI(mConnected);

}

};

二 系统上电的时候

else if(action.equals(IPO_POWER_ON)) {

SXlog.d(TAG, "onReceive - [IPO_POWER_ON] mDefaultFunctions: " + mDefaultFunctions + ", mSettingUsbCharging: " + mSettingUsbCharging);

if (mSettingUsbCharging) {

mSettingUsbCharging = false;

setCurrentFunction(mDefaultFunctions, false);

}

showBuiltinInstallerUI(mConnected);

三 收到更新消息,并且是发生了硬件重新插拔动作才进行处理,所以如果仅仅是软的连接不会发生这个动作

public voidhandleMessage(Message msg) {

switch (msg.what) {

caseMSG_UPDATE_STATE:

mConnected = (msg.arg1 == 1);

mConfigured = (msg.arg2 == 1);

updateUsbNotification();

updateAdbNotification();

if (containsFunction(mCurrentFunctions,

UsbManager.USB_FUNCTION_ACCESSORY)) {

updateCurrentAccessory();

}

//注意下面这个处理,当usb状态位connect(false),function会切换到默认的功能上,变成false有两种情况:1软断,这种断开后会紧跟着一个设置会进来,这种情况是为了设置新的,才会先断一下,所以要设置的会生效2、真断,这种就是硬件上断开、拔除了,下面这部分代码会将其设置到默认的function上。(目前打算是在setting中设置功能,但是每次设置完后,等再次插入时,又会恢复到默认的状态,mHwDisconnected标识硬件上是否连接的状态)

if (!mConnected && !mSettingUsbCharging) {

// restore defaults when USB is disconnected

SXlog.d(TAG, "handleMessage - MSG_UPDATE_STATE - mConnected: " + mConnected + ", mSettingUsbCharging: " + mSettingUsbCharging);

setEnabledFunctions(mDefaultFunctions, false);

}

if (mBootCompleted) {

updateUsbState();//将传过来的最新usb信息更新到UsbManager及其他全局变量中

Log.w(TAG, "handleMessage mConnected:" + mConnected + ",mConfigured:" + mConfigured +

", mHwDisconnected:" + mHwDisconnected + ", mHwReconnected:" + mHwReconnected);

if(mHwReconnected == true && mConnected == true) {

showBuiltinInstallerUI(true);//只有当硬件重新连接过,才会重新挂载介质

mHwReconnected = false;

}

}

break;

下面这个函数用来更新状态,发送消息,随后上面的handleMessage进行处理

public void updateState(String state)

这个updateState的触发是有kernel层上来的,kernel层会发出uevent消息,所以上面需要接收、处理uevent消息。

如下:

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

//Added for USB Develpment debug, more log for more debuging help

if(DEBUG) Log.w(TAG, "mUEventObserver: onUEvent: state = " + state);

//Added for USB Develpment debug, more log for more debuging help

if (state != null) {

mHandler.updateState(state);

} else if ("START".equals(accessory)) {

if (DEBUG) Slog.d(TAG, "got accessory start");

setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);

}

}

};

下面看一下 mHandler = newUsbHandler(thread.getLooper());

private final classUsbHandler extends Handler {

这个UsbHandler是一个主要的usb处理类。

public voidupdateState(String state) {

………………

Message msg = Message.obtain(this,MSG_UPDATE_STATE);

msg.arg1 = connected;

msg.arg2 = configured;

// debounce disconnects to avoid problems bringing up USB tethering

if (mHwDisconnected ||mSettingUsbCharging) {

SXlog.d(TAG, "updateState - UPDATE_DELAY " + state + " mSettingFunction: " + mSettingFunction);

sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);

}

………………

在updateState函数中,通过传进来的state,重新调整了connected和 configured两个参数,并传递了消息。

然后回到了上面的第三种情况中的消息处理函数handleMessage。

root@android:/sys/class/android_usb/android0 # cat state

CONFIGURED

在updateState函数中有4个state状态:

HWDISCONNECTED硬件上拔除了usb cabel

DISCONNECTED这个应该是软拔除,现在理解是软件上的一种设置

CONNECTED已经连接上了

CONFIGURED已经配置完成

其中有一个重要变量mHwReconnected用来记录这次连接是否是硬件的再次连接,而不是软件设置上的重新连接。

1.3 光盘backfile的unshare

上面有一个疑问是,什么时候将光盘的文件系统介质拿掉的。如下,通过下面的receiver接收到usb的action:ACTION_USB_STATE,如果发生了拔除动作,则shareCDRom(false)卸载掉文件系统介质。

// This class is used to close BuiltInstallerActivity and ims service unMount if it is mounted

public classBuiltinInstallerReceiver extends BroadcastReceiver {

private static final String TAG = "BuiltinInstallerReceiver";

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (UsbManager.ACTION_USB_STATE.equals(action)) {

boolean connected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);

if (!connected &&BuiltinInstallerActivity.getSharedStatus()) {

try {

IMountService ims =BuiltinInstallerActivity.getMountService();

if (ims == null) {

Log.e(TAG, "Cant get mount service");

}

ims.shareCDRom(false);

BuiltinInstallerActivity.setSharedStatus(false);

Log.i(TAG, "STOP sharing builtin installer");

} catch (RemoteException e) {

Log.e(TAG, "Cant call mount service");

}

}

}

}

}

这个receiver在manifest.xml中定义,这种方式类似于下面这种注册的方式

registerReceiver(mUsbStateReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE));

这个receiver收到广播消息后,调用了BuiltinInstallerActivity这个类的static成员函数。而当时修改去掉对话框的方式时没有启动这个activity,导致其中的static成员状态没有被更新。导致再拔除usb时,这个reciever获取不到正确的信息,不能卸载介质。(当发生了拔除动作,并且当前处于share状态,才进行unshare的动作)。这也是我当时去掉对话框后,留下的隐患,查看/sys/class/android_usb/android0/f_mass_storage/lun-cdrom/file始终是/dev/block/loop0。

这块对类的理解:BuiltinInstallerActivity类是一个特殊的对象,外界可以直接调用他的static成员,又可以实例化对象,被实例化的对象之间可以通过static通信,static有点像全局变量,类这个大家庭的全局变量。

PR:所以下面的问题就是消息的问题,当usb没有发生硬插拔时是广播的什么消息?可以确认的是即使广播的消息没有触发showBuiltinInstallerUI动作,也没有关系。因为由于上面BuiltinInstallerReceiver的错误处理,一直都没有unshare光盘的介质,导致后期一直都处于share状态。也就是说直接有是否使能mass_storage这个功能来决定是否弹出光盘(本来应该是两个决定因素:1使能mass_storage功能,2 share介质)。

1.4设置usbfunction的动作

PR:2012-07-04添加了复选框用来使能光盘or not。主要是通过addFunction和removeFunction两个动作来处理usb的function的。但是当使能光盘时,sys.usb.config变为mtp,adb,mass_storage不在init.usb.rc中,所以这个时候就会setUsbConfig失败,转而重新设置为刚才的(mtp,adb).

所以复选框的功能是否应该更改为:1 setCurrentFunction(“mass_storage”). 2 setCurrentFunction(“mtp,adb”).其中2还要看是否使能了debug,如果没有的话还得去掉。

所以这个部分现在只是行为方式上的定义,以及编译时对persist.sys.usb.config的控制(去掉mass_storage).

对于在调用 setCurrentFunction后的动作中,有很多猫腻。setCurrentFunction发送消息,随后在处理函数中调用setEnabledFunctions完成整个设置过程,但这个setEnabledFunctions有对usb function的各种各样的变化。下面看看setEnabledFunctions的处理思路:

setEnabledFunctions(String functions, boolean makeDefault) {

mDefaultFunctions:代表系统默认的function,persist.sys.usb.config

mCurrentFunctions:代表系统当前的usb function

mSettingFunction代表当前要设置的function

functions:参数传入时代表当前要设置的function,但是这个值会在这个函数内部根据系统的功能发生变化,如当定义了cdrom,它会默认加入mass_storage功能等,所以最后设置的functions将有可能不是最初传入的function,最初传入的function一直保存在mSettingFunction中。

根据是否override persist.sys.usb.config进行了分支,persist.sys.usb.config考虑是否被修改为makeDefault。

else {

if (functions == null) {

functions = mDefaultFunctions;//如果传入参数为空,使用persist.sys.usb.config

}

// Override with bootmode specific usb mode if needed

functions = processOemUsbOverride(functions);//留给oem一个插一杠子的机会

mSettingFunction = functions;

//如果要启用MTP function,并且系统还定义了光驱功能,那么就需要在加入一个mass_storage function,有点强奸民意的意思。在驱动中使能了光盘,上层应用就一定要用么?会什么和MTP还有关系呢?难道是,系统默认的存储一个是UMS一个是MTP,两个功能必用一个。如果定义了MTP,又定一个了光盘,那就说明要加入mass_storage,如果没定义MTP,那系统一定定义了mass_storage功能,所以不用再加入,什么狗屁逻辑!都是自我揣测。

if (mUmsAlwaysEnabled && containsFunction(mSettingFunction, UsbManager.USB_FUNCTION_MTP)) {

functions = addFunction(functions, UsbManager.USB_FUNCTION_MASS_STORAGE);

}

//mSettingUsbCharging:UsbManager.USB_FUNCTION_CHARGING_ONLY代表usb只用来充电,这块的意思是如果在非只充电的情况下,用户的function设置,必须遵循系统的一些特性,尊重系统的adb功能,用户的设置会被改动

if (mAdbEnabled && !mSettingUsbCharging) {

functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);

} else {

functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);

}

//acm和adb类似,注意这几个系统级别的function的顺序

if (mAcmEnabled && !mSettingUsbCharging) {

functions = addFunction(functions, UsbManager.USB_FUNCTION_ACM);

} else {

functions = removeFunction(functions, UsbManager.USB_FUNCTION_ACM);

}

if (!mCurrentFunctions.equals(functions)) {//看看是否需要设置,和当前功能没变化就不用设置了

if (!setUsbConfig("none")) {

//先把功能设置成none,相当于软断开,如果失败,则切换到当前的function上

Slog.e(TAG, "Failed to disable USB");

// revert to previous configuration if we fail

setUsbConfig(mCurrentFunctions);

return;

}

//切换到当前需要的功能上,如果切换失败,在切换回刚才的功能上

if (setUsbConfig(functions)) {

mCurrentFunctions = functions;

} else {

Slog.e(TAG, "Failed to switch USB config to " + functions);

// revert to previous configuration if we fail

setUsbConfig(mCurrentFunctions);

}

}

}

}

二 UsbDeviceManager.java的理解

这个函数是usb device主要的处理类:

一、是作为直接调用使用,被usb service调用,

二、是就收消息,对消息进行处理。

功能列表:

2.1 kernel层的event监控

Listens for uevent messages from the kernel to monitor the USB state,如果状态有更新,降调用更新处理函数,随之触发一些列动作

private final UEventObservermUEventObserver = new UEventObserver()

2.2构造函数

进行对象实例化时的一些初始化

publicUsbDeviceManager(Context context, UsbSettingsManager settingsManager) {

2.3 storage功能的信息初始化

public voidsystemReady()

{

1、获取persist.sys.usb.config的值,并去掉可能的adb/acm功能,只保留下可能的存储功能,看来android默认认为除了adb/acm,产品就只剩下mtp/mass_storage了。

2、获取ro.sys.usb.storage.type,usb存储设备的类型mUsbStorageType,mtp/mass_storage

3、比较1和2的两个获取值,如果不相同,将默认的storage的type更新给ro.sys.usb.storage.type

4、如果mUsbStorageType仅为UMS,就会通过StorageManager及STORAGE_SERVICE获取分区情况,进而设置好mUseUsbNotification用来决定是否更新usb通知。

}

2.4初始化rndis地址

private static voidinitRndisAddress() {

设置rndis eth地址

2.5 usb功能的处理

addFunction/removeFunction/containsFunction

这三个都是static函数,类可直接调用

2.6主要的usb处理类

private final classUsbHandler extends Handler {

下面每一个是这个类中的成员

1、定义一个runnable线程,待命执行mShowBuiltinInstallerRunnable

2、定义一个receiver,接收各种信息进行处理,

private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {

3、定义UsbHandler的looper

各种function功能的初始配置

public UsbHandler(Looper looper) {

4、发送消息

sendMessage,消息会有handleMessage来处理

5、updateState

根据event传上来的信息,更新usb状态,并调用sendMessage发送消息

6、setUsbConfig设置usb的功能,SystemProperties.set

7、setAdbEnabled/setAcmEnabled

adb/acm是两个特殊且独立的功能,一般不会出现在defaultFuncation里边,而是有单独的开关来控制,所以在最终调用的setEnabledFunctions,里边的处理是很特殊的(一定要注意添加function后造成的功能顺序是否与init.usb.rc中的配置是否吻合)

8、这个函数比较特殊,逻辑上需要关注,尤其是对adb/acm的处理

private voidsetEnabledFunctions(String functions, boolean makeDefault) {

9、updateCurrentAccessory

10、updateUsbState

更新usb的状态,将usb的状态广播出去。广播的intent为UsbManager.ACTION_USB_STATE,将usb的状态、功能携带到intent中

11、消息处理函数

public void handleMessage(Message msg) {

12、updateUsbNotification/updateAdbNotification

处理状态通知

13、处理光驱介质share的动作

showBuiltinInstallerUI

2.7、openAccessory

2.8、setCurrentFunction这个会发送MSG_SET_CURRENT_FUNCTION消息,进而在消息处理函数中调用到setEnabledFunctions

2.9、setMassStorageBackingFile

下面的是oem是否覆盖persist.sys.usb.config的操作

2.10、readOemUsbOverrideConfig

2.11、needsOemUsbOverride

2.12、processOemUsbOverride

UsbDeviceManager的主要流程:

一 构造函数主要有两个动作:

1创建线程

HandlerThreadthread= new HandlerThread("UsbDeviceManager",

Process.THREAD_PRIORITY_BACKGROUND);

2实例化 mHandler,并给该hander提供looper

mHandler = new UsbHandler(thread.getLooper());

3其他为变量的初始化

二 主要的工作就进入到UsbHandler这个处理类里了

1 UsbHandler的构造函数:a)对usb的function及相关的功能设置,系统属性值进行获取及初始化. b)启用两个监听的动作,监听setting的设置改变以及usb uevent事件的变化。

2 handleMessage的重载,在UsbHandler的成员函数中,会发送消息,那么处理消息的流程是如何被启动的呢?这个流程就是looper来完成的,每个handler内都有message的发送、接收。但是这个handler必须指定looper,有looper来完成消息的分发、管理。Handler中只是完成具体的发送和处理。

三 handleMessage中的几个消息

1 MSG_UPDATE_STATE://usb的连接状态有变化时,收到kernel的uevent信息时

2 MSG_ENABLE_ADB

3 MSG_SET_CURRENT_FUNCTION://功能设置,上面应用传下来的动作

4 MSG_SYSTEM_READY

5 MSG_BOOT_COMPLETED

UsbDeviceManager.java相关推荐

  1. 2022-08-29 AndroidR 修改默认usb连接模式为MTP(Media Transfer Protocol)),UsbDeviceManager.java里面处理OTG口usb设备拔插侦听

    一.默认是做为adb 调试功能,实际测试修改persist.sys.usb.config 是没有用. 二.拔插usb设备默认的选项是No data transfer  三.按下面的修改就可以修改默认u ...

  2. java+usb+教程,带你遨游USB世界

    1.什么是USB USB的全称是Universal Serial Bus,通用串行总线.它的出现主要是为了简化个人计算机与外围设备的连接,增加易用性.USB支持热插拔,并且是即插即用的,另外,它还具有 ...

  3. android xml pid vid,增加属性标识摄像头的vid与pid,以便知道摄像头与设备文件的对应关系...

    Android 在使用多个USB摄像头时,根据加载顺序不同他们的设备文件顺序不同,比如:"video0, video1, video2",每次启动它们的顺序都可能不同,这样APP就 ...

  4. Android 5.0 Usb调试拦截分析及修改

    当我们调试安卓机器时,第一次插上usb线,会弹出一个授权的对话框,(前提是打开了usb调试功能)点击确认,才会允许调试. 如果我们想机器默认就可以调试该怎么做呢? 如果我们想动态拦截,需要用户输入帐号 ...

  5. Adbshell相关命令

    Adb&shell相关命令 作者:韦启发 1. 过滤显示字符 adb logcat | grep MyApp adb logcat | grep -i myapp #忽略大小写. adb lo ...

  6. Android 系统(191)---ODM 开发用户常见需求文档(九)

    Android 系统(191)---ODM 开发用户常见需求文档(九) 阅读数:1122 一:去除摄像头的假对焦框 (vendor/) (mediatek/proprietary/packages/a ...

  7. Android 系统 (128)---ODM 开发用户常见需求文档(二)

    Android6.0 MTK 需求文档(二) 一:相机中的右边的预览窗口查看图片后选择删除,屏幕界面下方会有一条横线(去除横线的办法) (packages/apps/Gallery2/src/com/ ...

  8. Android 系统默认参数的修改

    转自: http://www.th7.cn/Program/Android/201505/447097.shtml 写在前面的话 一般在新项目开始之初,我们需要针对客户需求进行各种系统默认属性的配置, ...

  9. Android USB Audio accessory设备

    这个手机做device, audio accessory是Host. 以高通msm8x26(USB2.0) Lolliop android 5.0/5.1为例1 代码•Kernelkernel/dri ...

最新文章

  1. 为什么用Go编写机器学习的基础架构,而不是Python?
  2. 第一门语言学python好_零基础学编程,哪一门语言比较适合入门?
  3. centos mysql无法启动 sock_linux下mysql无法启动的解决方法
  4. android 系统(85)---MAT 工具使用
  5. php jmail 乱码,ASP实例:解决Jmail发送邮件标题出现乱码
  6. android键盘事件
  7. php文本框显示ip,php实现图形显示Ip地址的代码及注释_PHP教程
  8. 发布自己的CocoaPods的步骤
  9. PyQt4 UI设计和调用 使用eric6
  10. 原工信部副部长杨学山:重基础,促创新,求实效,转观念
  11. python环境window系统安装pyHook3
  12. 今天遇到安装CAD2014提示已安装磁盘空间显示0字节,无法下一步,已解决.#CAD2014提示已安装磁盘空间显示0字节无法下一步
  13. uvm设计分析——reg
  14. Pascal voc 数据集xml格式解析
  15. 华三交换机配置vrrp_VRRP原理与配置 华为、华三交换机,路由器
  16. OSPF——LSA讲解
  17. 跨境电商如何制定社交媒体营销策略?
  18. Typora+PciGo-Core+SMMS自动上传图片
  19. [ZZ]AppiumForWindows 菜鸟计划合集
  20. Cloud Foundry 峰会进入中国 全球专家与你面对面

热门文章

  1. 灵信视觉led。六代卡和五代卡
  2. 软件技术共享社区正式上线
  3. split( )[3].split(:)[0];
  4. Dialog的详细使用
  5. Kafka 认证登录注意事项
  6. 你好,C++(23) 4.4.2 工资程序成长记:用数组处理批量数据,用循环结构执行重复动作...
  7. 远程访问本地搭建的个人云盘【无公网IP】
  8. JAVA微信开发(四), 公众号普通红包
  9. 【SQL Server学习笔记】4:使用SSMS创建数据库表并完善表结构
  10. Android音视频方向进阶路线及资源合集