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();
        }
    }
相关推荐
用户2018792831673 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子3 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜82273 小时前
安卓接入Max广告源
android
齊家治國平天下3 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO3 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel3 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢3 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱
IT酷盖3 小时前
Android解决隐藏依赖冲突
android·前端·vue.js
努力学习的小廉5 小时前
初识MYSQL —— 数据库基础
android·数据库·mysql
风起云涌~5 小时前
【Android】浅谈androidx.startup.InitializationProvider
android