Android RK356X TVSettings USB调试开关

Android RK356X TVSettings 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

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

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部分接口可以通过反射获得.

提取关键代码:

java 复制代码
    @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();
        }
    }
相关推荐
鸿蒙布道师5 分钟前
鸿蒙NEXT开发权限工具类(申请授权相关)(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师6 分钟前
鸿蒙NEXT开发定位工具类 (WGS-84坐标系)(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
AscendKing14 分钟前
电脑安装adb并且连接华为手机mate60pro后查看设备
adb·智能手机
alexhilton1 小时前
深入理解Jetpack Compose中的函数的执行顺序
android·kotlin·android jetpack
李新_2 小时前
Android 画中画避坑指北
android
一一Null3 小时前
Android studio—socketIO库return与emit的使用
android·java·网络·ide·websocket·网络协议·android studio
全栈极简4 小时前
Android串口通信
android
jiaxingcode4 小时前
MAC系统下完全卸载Android Studio
android·macos·android studio
张力尹4 小时前
「架构篇 1」认识 MVC / MVP / MVVM / MVI
android·面试·架构