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 的切换功能
-
USB OTG(On-The-Go)
USB OTG 是一种允许设备在主机(Host)和设备(Device)之间动态切换的功能。通过 OTG 功能,RK3568 可以在以下两种模式之间切换:
• 主机模式(Host Mode):RK3568 作为主机,连接其他 USB 设备(如 U 盘、键盘、鼠标等),并控制数据传输。• 设备模式(Device Mode):RK3568 作为从设备,连接到主机(如 PC),被主机控制和数据传输。
-
动态切换
RK3568 支持在运行时动态切换 USB OTG 和 Host 模式,无需重新启动设备或重新插拔 USB 线缆。这种切换功能依赖于硬件设计和软件驱动的支持。
应用场景
USB OTG 和 Host 的切换功能在以下场景中有广泛应用:
-
移动设备
• 在智能手机、平板电脑等设备中,OTG 功能允许用户通过 USB 连接外部设备(如 U 盘、键盘、鼠标等),扩展设备的功能。• 例如,用户可以将手机作为主机,连接 U 盘进行文件传输,或者连接键盘和鼠标进行办公。
-
嵌入式设备
• 在嵌入式系统中,RK3568 的 OTG 功能可以用于连接各种 USB 设备,如打印机、摄像头、传感器等。• 通过动态切换,设备可以在主机和从机模式之间切换,适应不同的应用需求。
-
工业控制
• 在工业自动化领域,RK3568 可以作为主机连接传感器、控制器等设备,也可以作为从机连接到上位机(如 PC)进行数据采集和监控。• 动态切换功能使得设备可以根据任务需求灵活调整角色。
-
车载系统
• 在车载娱乐系统或导航设备中,OTG 功能可以用于连接外部存储设备(如 U 盘)播放媒体文件,或者连接诊断工具进行系统维护。• 动态切换功能使得设备可以同时支持多种连接方式。
-
物联网设备
• 在物联网设备中,RK3568 可以通过 OTG 功能连接各种传感器或执行器,实现数据采集和控制。• 通过动态切换,设备可以根据网络环境或任务需求调整角色。
-
调试和开发
• 在开发阶段,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);
}
}
补充说明
- 以上源码接口需要
system
及以上权限 - 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();
}
}