当前位置: 首页 > news >正文

MTK-USB模式动态设置

需求:在应用里面实现USB模式动态设置。
场景:不同客户根据自己需求会默认USB模式。 我自己作为开发者来说,如果客户可以动态设置USB模式岂不更好,但是动态设置交给应用,不要去系统设置里面去设置,去系统设置里面设置就不方便了,而且部分客户产品对系统设置是不可见的。

文章目录

  • USB模式基础
    • 文件传输(MTP - Media Transfer Protocol)
    • USB 网络共享(USB Tethering)
    • MIDI(Musical Instrument Digital Interface)
    • PTP(Picture Transfer Protocol)
    • 不用于数据传输(仅充电)
    • 如何选择?
  • 涉及系统源码参考
  • 代码分析
    • 从设置模块进入USB模式,找对应相关信息
    • UsbDefaultFragment - 显示界面-模式选择
      • 设置选项 setDefaultKey 方法
      • 获取选项- FUNCTIONS_MAP
        • 获取默认模式
    • UsbBackend - 提供USB系统功能入口类
      • 设置USB模式 setDefaultUsbFunctions
      • 获取USB模式 getDefaultUsbFunctions
    • UsbDetailsFunctionsController-模式选择的button
      • UsbManager 相关key定义
      • GadgetFunction 相关key定义
    • UsbManager - USB模式控制核心
  • 总结


USB模式基础

我们先看一下手机端吧,大家每次连接将自己的Android手机连接电脑充电时候,会弹出一个框,这个界面是大家常见到的,用户能够感受到的界面,这里先看看弹框图。
在这里插入图片描述

从用户的角度,用户能理解的是仅充电、传输文件和传输照片,从研发角度需要知晓每个选项的实际对应的场景。

提到的 USB 模式 是 Android 设备连接电脑时的几种常见选项,每种模式有不同的用途,下面简要说明

文件传输(MTP - Media Transfer Protocol)

  • 用途:在电脑和手机之间传输文件(如照片、视频、文档等)。

  • 适用场景:需要管理手机存储中的文件时使用。

USB 网络共享(USB Tethering)

  • 用途:将手机的移动网络通过 USB 共享给电脑,使电脑可以上网。
  • 注意:会消耗手机流量,需确保有足够的流量或 Wi-Fi 热点不可用时使用。

MIDI(Musical Instrument Digital Interface)

  • 用途:连接音乐设备(如 MIDI 键盘、音频接口),用于音乐制作或音频应用。
  • 适用场景:音乐创作、DAW(数字音频工作站)软件控制。

PTP(Picture Transfer Protocol)

  • 用途:传输照片(早期相机常用协议),比 MTP 更简单,但功能有限。
  • 注意:现代安卓设备通常优先用 MTP,PTP 兼容性更好但仅支持图片。

不用于数据传输(仅充电)

  • 用途:仅通过 USB 充电,禁止数据传输(保护隐私或节省电量)。

如何选择?

  • 传文件 → 文件传输(MTP)

  • 共享网络 → USB 网络共享

  • 音乐制作 → MIDI

  • 旧设备传图 → PTP

  • 仅充电/安全 → 不用于数据传输

涉及系统源码参考

MtkSettings/src/com/android/settings/connecteddevice/usb/UsbDefaultFragment.java
MtkSettings/src/com/android/settings/connecteddevice/usb/UsbBackend.java
MtkSettings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
frameworks/base/core/java/android/hardware/usb/UsbManager.java

代码分析

从设置模块进入USB模式,找对应相关信息

进入设置->开发者选项-》默认USB配置
在这里插入图片描述
在这里插入图片描述

我们观察到 logcat 日志有相关内容如下:

 D  Switching to fragment com.android.settings.connecteddevice.usb.UsbDefaultFragmentD  Launching fragment com.android.settings.connecteddevice.usb.UsbDefaultFragment

所以我么找下这个文件,对应的其实是设置里面的类,大概目录如下:

在这里插入图片描述

这不就是设置里面跟USB 模块相关的内容吗,UsbDefaultFragment 只是展示内容而已。

UsbDefaultFragment - 显示界面-模式选择

看注释,童工默认的USB模式设置

/*** Provides options for selecting the default USB mode.*/

代码量不大,这里我们分析一下设置和获取逻辑,找到对应的位置:

设置选项 setDefaultKey 方法

@Override
protected boolean setDefaultKey(String key) {
long functions = UsbBackend.usbFunctionsFromString(key);
mPreviousFunctions = mUsbBackend.getCurrentFunctions();
if (!Utils.isMonkeyRunning()) {
if (functions == UsbManager.FUNCTION_RNDIS || functions == UsbManager.FUNCTION_NCM) {
// We need to have entitlement check for usb tethering, so use API in
// TetheringManager.
mCurrentFunctions = functions;
startTethering();
} else {
mIsStartTethering = false;
mCurrentFunctions = functions;
mUsbBackend.setDefaultUsbFunctions(functions);
}

    }return true;
}

这里关注到一个重要的类 mUsbBackend,方法,后面讲解

获取选项- FUNCTIONS_MAP

  @Overrideprotected List<? extends CandidateInfo> getCandidates() {List<CandidateInfo> ret = Lists.newArrayList();for (final long option : UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet()) {final String title = getContext().getString(UsbDetailsFunctionsController.FUNCTIONS_MAP.get(option));final String key = UsbBackend.usbFunctionsToString(option);// Only show supported functionsif (mUsbBackend.areFunctionsSupported(option)) {ret.add(new CandidateInfo(true /* enabled */) {@Overridepublic CharSequence loadLabel() {return title;}@Overridepublic Drawable loadIcon() {return null;}@Overridepublic String getKey() {return key;}});}}return ret;}

这里关注到 UsbDetailsFunctionsController.FUNCTIONS_MAP ,后面讲解

获取默认模式

从源码里面可以看到获取默认模式的方法的。

mUsbBackend.getDefaultUsbFunctions();

在这里插入图片描述

在这里插入图片描述

UsbBackend - 提供USB系统功能入口类

看注释:

Provides access to underlying system USB functionality.

看方法 setDefaultUsbFunctions,最终调用了 UsbManager.java 类的 setScreenUnlockedFunctions 方法了。

设置USB模式 setDefaultUsbFunctions

    public void setDefaultUsbFunctions(long functions) {mUsbManager.setScreenUnlockedFunctions(functions);}

上面已经分析获取默认的模式方法

获取USB模式 getDefaultUsbFunctions

   public long getDefaultUsbFunctions() {return mUsbManager.getScreenUnlockedFunctions();}

UsbDetailsFunctionsController-模式选择的button

看注释

/*** This class controls the radio buttons for choosing between different USB functions.*/

看上面引用到的核心代码

 static final Map<Long, Integer> FUNCTIONS_MAP = new LinkedHashMap<>();static {FUNCTIONS_MAP.put(UsbManager.FUNCTION_MTP, R.string.usb_use_file_transfers);FUNCTIONS_MAP.put(UsbManager.FUNCTION_RNDIS, R.string.usb_use_tethering);FUNCTIONS_MAP.put(UsbManager.FUNCTION_MIDI, R.string.usb_use_MIDI);FUNCTIONS_MAP.put(UsbManager.FUNCTION_PTP, R.string.usb_use_photo_transfers);FUNCTIONS_MAP.put(UsbManager.FUNCTION_NONE, R.string.usb_use_charging_only);}

所以,这里可以这么理解:

  • 在UsbDefaultFragment 类中,显示的不同的model 值包括实际的key 值,都是从 UsbDetailsFunctionsController 类中获取的。然后创建对应的Preference
  • UsbDetailsFunctionsController 类中的定义了key 和 value 值,key 又是在UsbManager里面定义的。

UsbManager 相关key定义

UsbManager 源码位置

/frameworks/base/core/java/android/hardware/usb/UsbManager.java

查看FUNCTION_MTP 、 FUNCTION_RNDIS 、FUNCTION_MIDI、FUNCTION_PTP、FUNCTION_NONE 是如何定义的。

找到===@SystemApipublic static final long FUNCTION_NONE = 0;@SystemApipublic static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;@SystemApipublic static final long FUNCTION_PTP = GadgetFunction.PTP;@SystemApipublic static final long FUNCTION_MIDI = GadgetFunction.MIDI;@SystemApipublic static final long FUNCTION_MTP = GadgetFunction.MTP;

他们是系统的API,居然又是通过GadgeFunction 类定义的。

GadgetFunction 相关key定义

继续追踪 GadgetFunction 代码:

/out_sys/soong/.intermediates/hardware/interfaces/usb/gadget/1.2/android.hardware.usb.gadget-V1.2-java_gen_java/gen/srcs/android/hardware/usb/gadget/V1_2/GadgetFunction.java

是编译出来的代码,查看对应的 RNDIS PTP MIDI MTP 值:

/*** Media Transfer protocol function.*/public static final long MTP = 4L /* 1 << 2 */;/*** Peripheral mode USB Midi function.*/public static final long MIDI = 8L /* 1 << 3 */;/*** Picture transfer protocol function.*/public static final long PTP = 16L /* 1 << 4 */;/*** Tethering function.*/public static final long RNDIS = 32L /* 1 << 5 */;	

这里隐隐约约感觉模式的值 设置和获取的值就是这些0L 、4L、8L、16L、32L

UsbManager - USB模式控制核心

上面已经分析了相关的业务,其中模式的获取和设置在 UsbBackend 类中 分析了其最终调用的方法如下

  • 获取USB模式 mUsbManager.getDefaultUsbFunctions();
  public long getDefaultUsbFunctions() {return mUsbManager.getScreenUnlockedFunctions();}
  • 设置USB模式 mUsbBackend.setDefaultUsbFunctions(functions)
ublic void setDefaultUsbFunctions(long functions) {mUsbManager.setScreenUnlockedFunctions(functions);}

那么我们跟踪到UsbManager类,方法如下:

    /*** Sets the screen unlocked functions, which are persisted and set as the current functions* whenever the screen is unlocked.* <p>* A zero mask has the effect of switching off this feature, so functions* no longer change on screen unlock.* </p><p>* Note: When the screen is on, this method will apply given functions as current functions,* which is asynchronous and may fail silently without applying the requested changes.* </p>** @param functions functions to set, in a bitwise mask.*                  Must satisfy {@link UsbManager#areSettableFunctions}** {@hide}*/public void setScreenUnlockedFunctions(long functions) {try {mService.setScreenUnlockedFunctions(functions);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}/*** Gets the current screen unlocked functions.** @return The currently set screen enabled functions.* A zero mask indicates that the screen unlocked functions feature is not enabled.** {@hide}*/public long getScreenUnlockedFunctions() {try {return mService.getScreenUnlockedFunctions();} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

都是隐藏的方法,那么我们通过 应用来获取看看到底什么值

 fun getScreenUnlockedFunctions(): Long? {return try {// 获取 UsbManager 实例val usbManager = ContextProvider.get().context.getSystemService(Context.USB_SERVICE) as UsbManager// 获取 UsbManager 的 Class 对象val usbManagerClass: Class<*> = usbManager.javaClass// 获取隐藏的 getScreenUnlockedFunctions 方法val method: Method = usbManagerClass.getMethod("getScreenUnlockedFunctions")// 调用方法并返回结果method.invoke(usbManager) as Long} catch (e: Exception) {Log.d(TAG,"  getScreenUnlockedFunctions error ")e.printStackTrace()null}}/*** 设置屏幕解锁时的 USB 功能* @param context 上下文对象* @param functions 要设置的功能值* @return 是否设置成功*/fun setScreenUnlockedFunctions(functions: Long): Boolean {return try {// 获取 UsbManager 实例val usbManager = ContextProvider.get().context.getSystemService(Context.USB_SERVICE) as UsbManager// 获取 UsbManager 的 Class 对象val usbManagerClass: Class<*> = usbManager.javaClass// 获取隐藏的 setScreenUnlockedFunctions 方法val method: Method = usbManagerClass.getMethod("setScreenUnlockedFunctions",Long::class.javaPrimitiveType)// 调用方法method.invoke(usbManager, functions)true} catch (e: Exception) {e.printStackTrace()false}}

简单的测试界面如下,配合实验验证:
在这里插入图片描述

通过实验发现,系统设置里面切换不同的USB模式,在应用里面去获取,得到的模式值如下:

模式得到的值
不用于数据传输0
文件传输4
MIDI8
PTP16
USB 网络共享32

设置值恰好就是获取的值,对应的其实就是UsbManager 中的常量值:
FUNCTION_MTP 、 FUNCTION_RNDIS 、FUNCTION_MIDI、FUNCTION_PTP、FUNCTION_NONE

总结

  1. 实现应用层对USB模式的动态设置,对UsbManager类中关联的方法进行反射调用
  2. USB模式相关切换的源码分析

备注:在实际场景中 开机后系统默认某个模式,网上也大量这样的讲解,这里暂不讨论,只针对动态设置模式的需求进行研究一次。

http://www.xdnf.cn/news/990703.html

相关文章:

  • VScode安装配置PYQT6
  • MS7200+MS1824 HD转AV/S-Video/VGA/YPbPr/RGB888/BT601、656/BT1120转换器
  • Pandas时间数据处理:从基础到进阶的实战指南
  • 利用高分辨率卫星遥感数据以更智能、更快速的方式勘测评估能源开采现场
  • 第四章 文件管理
  • 软件测试用例设计总结
  • Position Embedding 有哪些方式?
  • @Indexed原理与实战
  • Java大模型开发入门 (3/15): 拥抱官方标准 - 使用OpenAI官方Java SDK调用DeepSeek
  • 航电系统之轨迹克隆技术篇
  • pyvis报错AttributeError: ‘NoneType‘ object has no attribute ‘render‘
  • python打卡day51@浙大疏锦行
  • 期权末日轮实值期权盈利未平仓怎么办?
  • 【多模态/T5】[特殊字符] 为什么视频生成模型还在用T5?聊聊模型选择的学问
  • Windows版PostgreSQL 安装 postgis扩展
  • 大数据下的分页通用架构设计:从随机IO到顺序IO
  • Gartner<Reference Architecture Brief: Data Integration>学习心得
  • 嵌入式程序存储结构
  • HW中常态化反钓鱼训练的具体战略部署
  • 【网络】每天掌握一个Linux命令 - netperf
  • 6. TypeScript 函数
  • 提升集装箱及金属包装容器制造交付效率:数字化项目管理系统的核心优势
  • 异常谋杀案--Java异常处理篇
  • 工程论文: TORL: Scaling Tool-Integrated RL
  • StackOverflowError
  • (javaSE)继承和多态:成员变量,super,子类构造方法,super和this,初始化, protected 继承方式 final关键字 继承与组合
  • Dify-7: RAG 知识系统
  • 什么是项目进度管理?项目进度管理有哪些核心功能?
  • LLM 系列(二) :基础概念篇
  • 力扣-347.前K个高频元素