Android RK356X TVSettings USB调试开关

news2025/4/22 10:13:51

Android RK356X TVSettings USB调试开关

    • 平台
    • 概述
    • 操作-打开USB调试
    • 实现源码
    • 补充说明

平台

在这里插入图片描述

RK3568 + Android 11

概述

RK3568 是瑞芯微(Rockchip)推出的一款高性能处理器,支持 USB OTG(On-The-Go)和 USB Host 功能。USB OTG 和 Host 的切换功能是 RK3568 的一项重要特性,允许设备在不同的 USB 角色之间动态切换,从而实现更灵活的应用场景。

USB OTG 和 Host 的切换功能

  1. USB OTG(On-The-Go)
    USB OTG 是一种允许设备在主机(Host)和设备(Device)之间动态切换的功能。通过 OTG 功能,RK3568 可以在以下两种模式之间切换:
    • 主机模式(Host Mode):RK3568 作为主机,连接其他 USB 设备(如 U 盘、键盘、鼠标等),并控制数据传输。

    • 设备模式(Device Mode):RK3568 作为从设备,连接到主机(如 PC),被主机控制和数据传输。

  2. 动态切换
    RK3568 支持在运行时动态切换 USB OTG 和 Host 模式,无需重新启动设备或重新插拔 USB 线缆。这种切换功能依赖于硬件设计和软件驱动的支持。


应用场景
USB OTG 和 Host 的切换功能在以下场景中有广泛应用:

  1. 移动设备
    • 在智能手机、平板电脑等设备中,OTG 功能允许用户通过 USB 连接外部设备(如 U 盘、键盘、鼠标等),扩展设备的功能。

    • 例如,用户可以将手机作为主机,连接 U 盘进行文件传输,或者连接键盘和鼠标进行办公。

  2. 嵌入式设备
    • 在嵌入式系统中,RK3568 的 OTG 功能可以用于连接各种 USB 设备,如打印机、摄像头、传感器等。

    • 通过动态切换,设备可以在主机和从机模式之间切换,适应不同的应用需求。

  3. 工业控制
    • 在工业自动化领域,RK3568 可以作为主机连接传感器、控制器等设备,也可以作为从机连接到上位机(如 PC)进行数据采集和监控。

    • 动态切换功能使得设备可以根据任务需求灵活调整角色。

  4. 车载系统
    • 在车载娱乐系统或导航设备中,OTG 功能可以用于连接外部存储设备(如 U 盘)播放媒体文件,或者连接诊断工具进行系统维护。

    • 动态切换功能使得设备可以同时支持多种连接方式。

  5. 物联网设备
    • 在物联网设备中,RK3568 可以通过 OTG 功能连接各种传感器或执行器,实现数据采集和控制。

    • 通过动态切换,设备可以根据网络环境或任务需求调整角色。

  6. 调试和开发
    • 在开发阶段,OTG 功能可以用于连接调试工具(如 JTAG 调试器)或烧录固件。

    • 动态切换功能使得开发者可以方便地在不同模式之间切换,提高开发效率。


技术实现
RK3568 的 USB OTG 和 Host 切换功能依赖于以下硬件和软件支持:
• 硬件支持:RK3568 集成了 USB OTG 控制器,支持动态角色切换。

• 软件驱动:需要操作系统(如 Linux)提供相应的驱动程序和工具,支持 OTG 功能的动态切换。

• 外部电路设计:需要设计合适的 USB 接口电路,支持 OTG 功能(如 ID 引脚检测)。

操作-打开USB调试

设置 > 设备偏好设置 > 开发者选项 > USB 连接状态

在这里插入图片描述

实现源码

packages/apps/TvSettings/Settings/src/com/android/tv/settings/system/development/DevelopmentFragment.java

import com.android.tv.settings.dialog.UsbModeSettings;
/**
 * Displays preferences for application developers.
 */
public class DevelopmentFragment extends SettingsPreferenceFragment
        implements Preference.OnPreferenceChangeListener,
        EnableDevelopmentDialog.Callback, OemUnlockDialog.Callback, AdbDialog.Callback {
    private static final String TAG = "DevelopmentSettings";

    private static final String ENABLE_DEVELOPER = "development_settings_enable";
    private static final String ENABLE_ADB = "enable_adb";
    private static final String ENABLE_USB = "enable_usb";
    //...省略代码...
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        mLogdSizeController = new LogdSizePreferenceController(getActivity());
        mLogpersistController = new LogpersistPreferenceController(getActivity(), getLifecycle());
        mUsbModeSetting = new UsbModeSettings(getPreferenceManager().getContext());

        if (!mUm.isAdminUser()
                || mUm.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)
                || Settings.Global.getInt(mContentResolver,
                Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
            // Block access to developer options if the user is not the owner, if user policy
            // restricts it, or if the device has not been provisioned
            mUnavailable = true;
            addPreferencesFromResource(R.xml.development_prefs_not_available);
            return;
        }

        addPreferencesFromResource(R.xml.development_prefs);
        final PreferenceScreen preferenceScreen = getPreferenceScreen();

        // Don't add to prefs lists or it'll disable itself when switched off
        mEnableDeveloper = (SwitchPreference) findPreference(ENABLE_DEVELOPER);

        final PreferenceGroup debugDebuggingCategory = (PreferenceGroup)
                findPreference(DEBUG_DEBUGGING_CATEGORY_KEY);
        mEnableAdb = findAndInitSwitchPref(ENABLE_ADB);
        mEnableUsb = findAndInitSwitchPref(ENABLE_USB);
        mEnableInternetAdb = findAndInitSwitchPref(ENABLE_INTERNET_ADB);
        mEnableAbc = findAndInitSwitchPref(ENABLE_ABC);

        mEnableUsb.setChecked(mUsbModeSetting.getDefaultValue());
        if (mEnableUsb.isChecked()){
            mEnableUsb.setSummary(R.string.usb_connect_to_computer);
        } else {
            mEnableUsb.setSummary(R.string.usb_disconnect_to_computer);
        }
        //...省略代码....
    }

packages/apps/TvSettings/Settings/src/com/android/tv/settings/dialog/UsbModeSettings.java

package com.android.tv.settings.dialog;

import com.android.tv.settings.R;

import android.content.Context;
import android.os.Handler;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import android.os.storage.StorageManager;
import android.os.storage.StorageEventListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.SystemProperties;
import android.text.TextUtils;

import android.util.Log;

public class UsbModeSettings {
    private static final String TAG = "UsbModeSettings";
    // 0 otg 1 host 2 peripheral
    public static final String HOST_MODE = new String("host");
    public static final String SLAVE_MODE = new String("otg");
    public static final String PROP_FAKE_DATA_ROLE = "persist.fake_data_role";
    private static final String FILE_NAME_RK3399 = "/sys/kernel/debug/usb@fe800000/rk_usb_force_mode";
    private static final String FILE_NAME_RK3328 = "/sys/devices/platform/ff450000.syscon/ff450000.syscon:usb2-phy@100/otg_mode";
    private static final String FILE_NAME_RK3229 = "/sys/devices/platform/11000000.syscon/11000000.syscon:usb2-phy@760/otg_mode";
    private static final String FILE_NAME_RK356X = "/sys/devices/platform/fe8a0000.usb2-phy/otg_mode";

    private File file = null;

    private StorageManager mStorageManager = null;
    private String mMode = "";
    private String mSocName = "";

    private Context mContext;

    private boolean mLock = false;

    public UsbModeSettings(Context context) {
        mContext = context;
        mSocName = SystemProperties.get("sys.rk.soc");
        if (TextUtils.isEmpty(mSocName)) {
            mSocName = SystemProperties.get("ro.board.platform");
        }
        if(!TextUtils.isEmpty(mSocName) && mSocName.contains("rk3399")){
            file = new File(FILE_NAME_RK3399);
        }else{
            file = new File(FILE_NAME_RK3328);
        }
        file = getFile();
        mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
        boolean ret = checkFile();
        String mode = ReadFromFile(file);
        if(ret && !TextUtils.isEmpty(mode)) {
            mMode = mode;
        }

    }

    private File getFile() {
        String fileName = FILE_NAME_RK3328;
        if (!TextUtils.isEmpty(mSocName) && mSocName.contains("rk3399")) {
            fileName = FILE_NAME_RK3399;
        } else if (!TextUtils.isEmpty(mSocName) && (mSocName.contains("rk322x") || mSocName.contains("rk3128h"))) {
            fileName = FILE_NAME_RK3229;
        } else if (!TextUtils.isEmpty(mSocName) && mSocName.contains("rk356x")) {
            fileName = FILE_NAME_RK356X;
        } else {
            fileName = FILE_NAME_RK3328;
        }
        return new File(fileName);
    }

    public boolean getDefaultValue() {
        if (isRk3368()) {//通过prop和init来设置otg模式
            return getFakeDataRole();
        }
        if (checkFile()) {
            Log.d("UsbModeSelect", "/data/otg.cfg not exist,but temp file exist");
            if (isRk3368()) {
                return getFakeDataRole();
            }
            if (mMode.equals(HOST_MODE)) {
                return false;
            } else {
                return true;
            }
        } else {
            mMode = HOST_MODE;
            return false;
        }
    }

    private String ReadFromFile(File file) {
        if (checkFile()) {
            try {
                FileInputStream fin = new FileInputStream(file);
                BufferedReader reader = new BufferedReader(new InputStreamReader(fin));
                String config = reader.readLine();
                fin.close();
                return config;
            } catch (IOException e) {
                Log.i(TAG, "ReadFromFile exception:" + e);
                e.printStackTrace();
            }
        }

        return null;
    }

    private void Write2File(File file, String mode) {
        if (!checkFile() || (mode == null))
            return;
        Log.d("UsbModeSelect", "Write2File,write mode = " + mode);

        try {
            FileOutputStream fout = new FileOutputStream(file);
            PrintWriter pWriter = new PrintWriter(fout);
            pWriter.println(mode);
            pWriter.flush();
            pWriter.close();
            fout.close();
        } catch (IOException re) {
        }
    }

    public void onUsbModeClick(String mode) {
        if (isRk3368()) {
            setPropFakeDataRole(mode);
            return;
        }
        if (mLock)
            return;
        mLock = true;
        mMode = mode;
        synchronized (this) {
            Log.d("UsbModeSettings", "synchronized start");
            new Thread(mUsbSwitch).start();
        }
    }

    private Runnable mUsbSwitch = new Runnable() {
        public synchronized void run() {
            Log.d("UsbModeSettings", "mUsbSwitch Runnable() in*******************");
            if (mStorageManager != null) {
                if (mMode == HOST_MODE) {
                    mStorageManager.disableUsbMassStorage();
                    Log.d("UsbModeSettings", "mStorageManager.disableUsbMassStorage()*******************");
                    Write2File(file, mMode);
                } else {
                    Write2File(file, mMode);
                    Log.d("UsbModeSettings", "mStorageManager.enableUsbMassStorage()  in *******************");
                    mStorageManager.enableUsbMassStorage();
                    Log.d("UsbModeSettings", "mStorageManager.enableUsbMassStorage()   out*******************");
                }
            }
            Log.d("UsbModeSettings", "mUsbSwitch Runnable() out*******************");
            mLock = false;
        }
    };

    private boolean checkFile() {
        if (file == null) {
            Log.e(TAG, "file is null pointer");
            return false;
        }
        String fileName = file.getName();
        if (!file.exists()) {
            Log.e(TAG, fileName + " not exist!!!");
            return false;
        }
        if (!file.canRead()) {
            Log.e(TAG, fileName + " can't read!!!");
            return false;
        }
        if (!file.canWrite()) {
            Log.e(TAG, fileName + " can't write!!!");
            return false;
        }
        return true;
    }

    // 判断是否为3368芯片
    private boolean isRk3368() {
        if (!TextUtils.isEmpty(mSocName) && mSocName.contains("rk3368")) {
            return true;
        } else {
            return false;
        }
    }

    private boolean getFakeDataRole() {
        String fakeDataRole = SystemProperties.get(PROP_FAKE_DATA_ROLE, SLAVE_MODE);
        Log.d(TAG, "prop fakeDataRole = " + fakeDataRole);
        if (!TextUtils.isEmpty(fakeDataRole) && fakeDataRole.equals(SLAVE_MODE)) {
            return true;
        } else {
            return false;
        }
    }

    // 将mode转换为Int值,3368的mode为0,1,2
    private void setPropFakeDataRole(String mode) {
        Log.d(TAG, "setprop mode = " + mode);
        SystemProperties.set(PROP_FAKE_DATA_ROLE, mode);
    }
}


补充说明

  1. 以上源码接口需要system及以上权限
  2. StorageManager部分接口可以通过反射获得.

提取关键代码:

    @Override
    public void onClick(View v) {
        StorageManager mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
        File file = new File(FILE_NAME_RK356X);
        //切换为 OTG (USB 调试)
        if(R.id.btOtg == v.getId()) {
            Write2File(file, SLAVE_MODE);
            Log.d("UsbModeSettings", "mStorageManager.enableUsbMassStorage()  in *******************");
            enableUsbMassStorage(mStorageManager);
            Log.d("UsbModeSettings", "mStorageManager.enableUsbMassStorage()   out*******************");
        } else if(R.id.btHost == v.getId()) {//切换为HOST
            disableUsbMassStorage(mStorageManager);
            Log.d("UsbModeSettings", "mStorageManager.disableUsbMassStorage()*******************");
            Write2File(file, HOST_MODE);
        }
    }
    
    //写入 USB的模式: otg 或 host
	private void Write2File(File file, String mode) {
        if (!new File(FILE_NAME_RK356X).exists() || (mode == null))
            return;
        Log.d("UsbModeSelect", "Write2File,write mode = " + mode);

        try {
            FileOutputStream fout = new FileOutputStream(file);
            PrintWriter pWriter = new PrintWriter(fout);
            pWriter.println(mode);
            pWriter.flush();
            pWriter.close();
            fout.close();
        } catch (IOException re) {
        }
    }

	//反射接口
    void enableUsbMassStorage(StorageManager sm){
        try {
            Method enableUsbMassStorage = sm.getClass().getMethod("enableUsbMassStorage");
            enableUsbMassStorage.invoke(sm);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
    void disableUsbMassStorage(StorageManager sm){
        try {
            Method disableUsbMassStorage = sm.getClass().getMethod("disableUsbMassStorage");
            disableUsbMassStorage.invoke(sm);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340030.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

消息队列知识点详解

消息队列场景 什么是消息队列 可以把消息队列理解一个使用队列来通信的组件,它的本质是交换机队列的模式,实现发送消息,存储消息,消费消息的过程。 我们通常说的消息队列,MQ其实就是消息中间件,业界中比较…

序列号绑定的SD卡坏了怎么办?

在给SD卡烧录程序的时候,大家发现有的卡是无法烧录的,如:复印机的SD卡不能被复制通常涉及以下几个技术原因,可能与序列号绑定、加密保护或硬件限制有关: 一、我们以复印机的系统卡为例来简单讲述一下 序列号或硬件绑定…

使用SystemWeaver生成SOME/IP ETS ARXML的完整实战指南

使用SystemWeaver生成SOME/IP ETS ARXML的完整实战指南 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 一、SystemWeaver与SOME/IP基础认知 1.1 SystemWe…

Flutter 状态管理 Riverpod

Android Studio版本 Flutter SDK 版本 将依赖项添加到您的应用 flutter pub add flutter_riverpod flutter pub add riverpod_annotation flutter pub add dev:riverpod_generator flutter pub add dev:build_runner flutter pub add dev:custom_lint flutter pub add dev:riv…

【HarmonyOS 5】VisionKit人脸活体检测详解

【HarmonyOS 5】VisionKit人脸活体检测详解 一、VisionKit人脸活体检测是什么? VisionKit是HamronyOS提供的场景化视觉服务工具包。 华为将常见的解决方案,通常需要三方应用使用SDK进行集成。华为以Kit的形式集成在HarmoyOS系统中,方便三方…

Pycharm(九)函数的闭包、装饰器

目录 一、函数参数 二、闭包 三、装饰器 一、函数参数 def func01():print("func01 shows as follows") func01() # 函数名存放的是函数所在空间的地址 print(func01)#<function func01 at 0x0000023BA9FC04A0> func02func01 print(func02)#<function f…

【深度学习】详解矩阵乘法、点积,内积,外积、哈达玛积极其应用|tensor系列02

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; Yaoyao2024往期回顾&#xff1a;【深度学习】你真的理解张量了吗&#xff1f;|标量、向量、矩阵、张量的秩|01每日一言&#x1f33c;: “脑袋想不明白的&#xff0c;就用脚想”…

MH2103系列coremark1.0跑分数据和优化,及基于arm2d的优化应用

CoreMark 1.0 介绍 CoreMark 是由 EEMBC&#xff08;Embedded Microprocessor Benchmark Consortium&#xff09;组织于 2009 年推出的一款用于衡量嵌入式系统 CPU 或 MCU 性能的标准基准测试工具。它旨在替代陈旧的 Dhrystone 标准&#xff08;Dhrystone 容易受到各种libc不同…

Flowith AI,解锁下一代「知识交易市场」

前言 最近几周自媒体号都在疯狂推Manus&#xff0c;看了几篇测评后&#xff0c;突然在某个时间节点&#xff0c;在特工的文章下&#xff0c;发现了很小众的Flowith。 被这段评论给心动到&#xff0c;于是先去注册了下账号。一翻探索过后&#xff0c;发现比我想象中要有趣的多&…

SpringBoot企业级开发之【文章分类-新增文章分类】

看一下新增文章的需求&#xff1a; 接口文档&#xff1a; 开发思路&#xff1a; 先在controller下去创建add方法&#xff0c;方法内导入Service类获取add的结果&#xff1b;再在Service接口下去创建add的方法&#xff1b;然后在Service实现类下去实现方法的作用&#xff0c;且导…

【AI News | 20250421】每日AI进展

AI Repos 1、langgraph-mcp-agents 基于LangGraph的AI智能体系统&#xff0c;集成了MCP&#xff0c;使AI助手能访问各种数据源和API。提供了Streamlit网页界面&#xff0c;方便与LangGraph和MCP工具交互。可以通过界面动态添加、删除以及配置MCP工具&#xff0c;无需重启应用&…

牛客 | OJ在线编程常见输入输出练习

1.只有输出 言归正传&#xff0c;本张试卷总共包括18个题目&#xff0c;包括了笔试情况下的各种输入输出。 第一题不需要输入&#xff0c;仅需输出字符串 Hello Nowcoder! 即可通过。 #include <iostream> using namespace std; int main(){string s "Hello Nowco…

python生成动态库在c++中调用

一.Windows下生成动态库.pyd 在setup.py的同目录下使用python setup.py build_ext --inplace 二.在vscode的c中使用.pyd文件&#xff08;动态库&#xff09; 1&#xff09;配置python的环境 python -c "import sys; print(sys.executable)" #确定python安装位置 2…

OpenCV基础函数学习4

【大纲笔记见附件pdf】 目录 一、基于OpenCV的形态学操作 二、基于OpenCV的直方图处理 三、基于OpenCV霍夫变换 四、基于OpenCV模板匹配 一、基于OpenCV的形态学操作 二、基于OpenCV的直方图处理 三、基于OpenCV霍夫变换 四、基于OpenCV模板匹配

Nginx反向代理用自定义Header参数

【啰嗦两句】 也不知道为啥&#xff0c;我仅仅想在Nginx的反向代理中使用自己定义的“x-api-key”做Header参数&#xff0c;却发现会被忽略&#xff0c;网上搜的资料都是说用“proxy_set_header”&#xff0c;却只愿意介绍最基本的几个参数&#xff0c;你懂的&#xff0c;那些资…

详解机器学习各算法的优缺点!!

在机器学习这个 “工具库” 里&#xff0c;算法就像各种各样的工具&#xff0c;每一种都有自己的 “脾气” 和 “特长”。有些算法擅长找规律&#xff0c;有些算法能快速分类&#xff0c;还有些在处理复杂数据时特别厉害。 而且&#xff0c;就像锤子适合敲钉子、螺丝刀适合拧螺…

C++23 让 Lambda 表达式中的 () 更可选:P1102R2 提案深度解析

文章目录 一、背景与动机&#xff1a;Lambda 表达式中的痛点1.1 问题的根源 二、P1102R2 提案&#xff1a;让 () 可选2.1 提案的核心内容2.2 语法调整的细节2.3 提案的合理性 三、编译器支持&#xff1a;主流编译器的跟进四、对 C 编程的影响&#xff1a;简化语法与提升一致性4…

在Qt中验证LDAP账户(Windows平台)

一、前言 原本以为在Qt&#xff08;Windows平台&#xff09;中验证 LDAP 账户很简单&#xff1a;集成Open LDAP的开发库即可。结果临了才发现&#xff0c;Open LDAP压根儿不支持Windows平台。沿着重用的原则&#xff0c;考虑迁移Open LDAP的源代码&#xff0c;却发现工作量不小…

【sylar-webserver】重构日志系统

文章目录 主要工作流程图FiberConditionBufferBufferManagerLogEvent 序列化 & 反序列化LoggerRotatingFileLogAppender 主要工作 实现&#xff0c; LogEvent 序列化和反序列化 &#xff08;使用序列化是为了更标准&#xff0c;如果转成最终的日志格式再存储&#xff08;确…

树莓派超全系列教程文档--(38)config.txt视频配置

config.txt视频配置 视频选项HDMI模式树莓派4-系列的HDMI树莓派5-系列的HDMI 复合视频模式enable_tvout LCD显示器和触摸屏ignore_lcddisable_touchscreen 通用显示选项disable_fw_kms_setup 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 视频选…