USB偏好设置
- 1、USB偏好设置界面和入口
- 2、USB功能设置
- 2.1 USB功能对应模式
- 2.2 点击设置
- 2.3 广播监听刷新
- 3、日志开关
- 3.1 Evet日志
- 3.2 代码中日志开关
- 3.3 关键日志
- 4、异常
1、USB偏好设置界面和入口
设置》已连接的设备》USB
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
packages/apps/Settings/res/xml/usb_details_fragment.xml
private static List<UsbDetailsController> createControllerList(Context context,
UsbBackend usbBackend, UsbDetailsFragment fragment) {
List<UsbDetailsController> ret = new ArrayList<>();
ret.add(new UsbDetailsHeaderController(context, fragment, usbBackend));
ret.add(new UsbDetailsDataRoleController(context, fragment, usbBackend));
ret.add(new UsbDetailsFunctionsController(context, fragment, usbBackend));
ret.add(new UsbDetailsPowerRoleController(context, fragment, usbBackend));
ret.add(new UsbDetailsTranscodeMtpController(context, fragment, usbBackend));
return ret;
}
2、USB功能设置
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
2.1 USB功能对应模式
FWK模式 | 对应值 | 字符串显示 | 节点 |
---|---|---|---|
FUNCTION_NONE = 0 | NONE = 0 | ||
FUNCTION_MTP = GadgetFunction.MTP | MTP = 1 << 2 | “文件传输” | |
FUNCTION_PTP = GadgetFunction.PTP | PTP = 1 << 4 | “PTP” | |
FUNCTION_RNDIS = GadgetFunction.RNDIS | RNDIS = 1 << 5 | “USB 网络共享” | |
FUNCTION_MIDI = GadgetFunction.MIDI | MIDI = 1 << 3 | “MIDI” | |
FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY | ACCESSORY = 1 << 1 | ||
FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE | AUDIO_SOURCE = 1 << 6 | ||
FUNCTION_ADB = GadgetFunction.ADB | ADB = 1 << 0 | “不用于数据传输” |
frameworks/base/core/java/android/hardware/usb/UsbManager.java
hardware/interfaces/usb/gadget/1.0/types.hal
frameworks/base/core/proto/android/service/usb.proto
/* Same as android.hardware.usb.gadget.V1_0.GadgetFunction.* */
enum Function {
FUNCTION_ADB = 1;
FUNCTION_ACCESSORY = 2;
FUNCTION_MTP = 4;
FUNCTION_MIDI = 8;
FUNCTION_PTP = 16;
FUNCTION_RNDIS = 32;
FUNCTION_AUDIO_SOURCE = 64;
}
2.2 点击设置
mUsbBackend
通过UsbManager.java、UsbService.java、UsbDeviceManager.java设置
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
@Override
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
final long function = UsbBackend.usbFunctionsFromString(preference.getKey());
final long previousFunction = mUsbBackend.getCurrentFunctions();
if (DEBUG) {
Log.d(TAG, "onRadioButtonClicked() function : " + function + ", toString() : "
+ UsbManager.usbFunctionsToString(function) + ", previousFunction : "
+ previousFunction + ", toString() : "
+ UsbManager.usbFunctionsToString(previousFunction));
}
if (function != previousFunction && !Utils.isMonkeyRunning()
&& !isClickEventIgnored(function, previousFunction)) {
mPreviousFunction = previousFunction;
//Update the UI in advance to make it looks smooth
final SelectorWithWidgetPreference prevPref =
(SelectorWithWidgetPreference) mProfilesContainer.findPreference(
UsbBackend.usbFunctionsToString(mPreviousFunction));
if (prevPref != null) {
prevPref.setChecked(false);
preference.setChecked(true);
}
if (function == UsbManager.FUNCTION_RNDIS || function == UsbManager.FUNCTION_NCM) {
// We need to have entitlement check for usb tethering, so use API in
// TetheringManager.
mTetheringManager.startTethering(
TetheringManager.TETHERING_USB, new HandlerExecutor(mHandler),
mOnStartTetheringCallback);
} else {
mUsbBackend.setCurrentFunctions(function);
}
}
}
frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
public void setCurrentFunctions(long functions) {
if (DEBUG) {
Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");
}
if (functions == UsbManager.FUNCTION_NONE) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_CHARGING);
} else if (functions == UsbManager.FUNCTION_MTP) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP);
} else if (functions == UsbManager.FUNCTION_PTP) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_PTP);
} else if (functions == UsbManager.FUNCTION_MIDI) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MIDI);
} else if (functions == UsbManager.FUNCTION_RNDIS) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_RNDIS);
} else if (functions == UsbManager.FUNCTION_ACCESSORY) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);
}
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
}
private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) {
String functions = null;
if (usbFunctions != UsbManager.FUNCTION_NONE) {
functions = UsbManager.usbFunctionsToString(usbFunctions);
}
mCurrentFunctions = usbFunctions;
if (functions == null || applyAdbFunction(functions)
.equals(UsbManager.USB_FUNCTION_NONE)) {
functions = UsbManager.usbFunctionsToString(getChargingFunctions());
}
functions = applyAdbFunction(functions);
String oemFunctions = applyOemOverrideFunction(functions);
if (!isNormalBoot() && !mCurrentFunctionsStr.equals(functions)) {
setSystemProperty(getPersistProp(true), functions);
}
if ((!functions.equals(oemFunctions)
&& !mCurrentOemFunctions.equals(oemFunctions))
|| !mCurrentFunctionsStr.equals(functions)
|| !mCurrentFunctionsApplied
|| forceRestart) {
Slog.i(TAG, "Setting USB config to " + functions);
mCurrentFunctionsStr = functions;
mCurrentOemFunctions = oemFunctions;
mCurrentFunctionsApplied = false;
/**
* Kick the USB stack to close existing connections.
*/
setUsbConfig(UsbManager.USB_FUNCTION_NONE);
if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
Slog.e(TAG, "Failed to kick USB config");
return false;
}
/**
* Set the new USB configuration.
*/
setUsbConfig(oemFunctions);
if (mBootCompleted
&& (containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
|| containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
/**
* Start up dependent services.
*/
updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
}
if (!waitForState(oemFunctions)) {
Slog.e(TAG, "Failed to switch USB config to " + functions);
return false;
}
mCurrentFunctionsApplied = true;
}
return true;
}
hardware/interfaces/usb/gadget/1.2/default/UsbGadget.cpp
V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
const sp<V1_0::IUsbGadgetCallback>& callback,
uint64_t timeout) {
bool ffsEnabled = false;
int i = 0;
if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
V1_0::Status::SUCCESS)
return V1_0::Status::ERROR;
if ((functions & V1_2::GadgetFunction::ADB) != 0) {
ffsEnabled = true;
if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
}
// Pull up the gadget right away when there are no ffs functions.
if (!ffsEnabled) {
if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;
mCurrentUsbFunctionsApplied = true;
if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
return V1_0::Status::SUCCESS;
}
monitorFfs.registerFunctionsAppliedCallback(¤tFunctionsAppliedCallback, this);
// Monitors the ffs paths to pull up the gadget when descriptors are written.
// Also takes of the pulling up the gadget again if the userspace process
// dies and restarts.
monitorFfs.startMonitor();
if (kDebug) ALOGI("Mainthread in Cv");
if (callback) {
bool pullup = monitorFfs.waitForPullUp(timeout);
Return<void> ret = callback->setCurrentUsbFunctionsCb(
functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);
if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
}
return V1_0::Status::SUCCESS;
}
Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
const sp<V1_0::IUsbGadgetCallback>& callback,
uint64_t timeout) {
std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
mCurrentUsbFunctions = functions;
mCurrentUsbFunctionsApplied = false;
// Unlink the gadget and stop the monitor if running.
V1_0::Status status = tearDownGadget();
if (status != V1_0::Status::SUCCESS) {
goto error;
}
ALOGI("Returned from tearDown gadget");
// Leave the gadget pulled down to give time for the host to sense disconnect.
usleep(kDisconnectWaitUs);
if (functions == static_cast<uint64_t>(V1_2::GadgetFunction::NONE)) {
if (callback == NULL) return Void();
Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
if (!ret.isOk())
ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
return Void();
}
status = validateAndSetVidPid(functions);
if (status != V1_0::Status::SUCCESS) {
goto error;
}
status = setupFunctions(functions, callback, timeout);
if (status != V1_0::Status::SUCCESS) {
goto error;
}
ALOGI("Usb Gadget setcurrent functions called successfully");
return Void();
error:
ALOGI("Usb Gadget setcurrent functions failed");
if (callback == NULL) return Void();
Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
if (!ret.isOk())
ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
return Void();
}
hardware/interfaces/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
int* functionCount) {
if (((functions & GadgetFunction::MTP) != 0)) {
*ffsEnabled = true;
ALOGI("setCurrentUsbFunctions mtp");
if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;
if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;
// Add endpoints to be monitored.
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
} else if (((functions & GadgetFunction::PTP) != 0)) {
*ffsEnabled = true;
ALOGI("setCurrentUsbFunctions ptp");
if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;
if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;
// Add endpoints to be monitored.
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
}
if ((functions & GadgetFunction::MIDI) != 0) {
ALOGI("setCurrentUsbFunctions MIDI");
if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::ACCESSORY) != 0) {
ALOGI("setCurrentUsbFunctions Accessory");
if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
ALOGI("setCurrentUsbFunctions Audio Source");
if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::RNDIS) != 0) {
ALOGI("setCurrentUsbFunctions rndis");
if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
if (rndisFunction != "") {
if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
} else {
// link gsi.rndis for older pixel projects
if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
}
}
if ((functions & GadgetFunction::NCM) != 0) {
ALOGI("setCurrentUsbFunctions ncm");
if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;
}
return Status::SUCCESS;
}
了解 USB Gadget HAL API 架构
2.3 广播监听刷新
广播监听刷新
onUsbConnectionChanged > refresh
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
/**
* Interface definition for a callback to be invoked when usb connection is changed.
*/
interface UsbConnectionListener {
void onUsbConnectionChanged(boolean connected, long functions, int powerRole, int dataRole,
boolean isUsbConfigured);
}
private UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
(connected, functions, powerRole, dataRole, isUsbFigured) -> {
for (UsbDetailsController controller : mControllers) {
controller.refresh(connected, functions, powerRole, dataRole);
}
};
3、日志开关
3.1 Evet日志
如:
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP);
frameworks/base/core/java/com/android/internal/logging/MetricsLogger.java
frameworks/base/core/java/android/metrics/LogMaker.java
frameworks/base/proto/src/metrics_constants/metrics_constants.proto
// The view or control was activated.
TYPE_ACTION = 4;
// These values should never appear in log outputs - they are reserved for
// internal platform metrics use.
RESERVED_FOR_LOGBUILDER_CATEGORY = 757;
RESERVED_FOR_LOGBUILDER_TYPE = 758;
RESERVED_FOR_LOGBUILDER_SUBTYPE = 759;
// ACTION: Usb config has been changed to charging
// CATEGORY: SETTINGS
// OS: P
ACTION_USB_CONFIG_CHARGING = 1275;
// ACTION: Usb config has been changed to mtp (file transfer)
// CATEGORY: SETTINGS
// OS: P
ACTION_USB_CONFIG_MTP = 1276;
// ACTION: Usb config has been changed to ptp (photo transfer)
// CATEGORY: SETTINGS
// OS: P
ACTION_USB_CONFIG_PTP = 1277;
// ACTION: Usb config has been changed to rndis (usb tethering)
// CATEGORY: SETTINGS
// OS: P
ACTION_USB_CONFIG_RNDIS = 1278;
// ACTION: Usb config has been changed to midi
// CATEGORY: SETTINGS
// OS: P
ACTION_USB_CONFIG_MIDI = 1279;
// ACTION: Usb config has been changed to accessory
// CATEGORY: SETTINGS
// OS: P
ACTION_USB_CONFIG_ACCESSORY = 1280;
3.2 代码中日志开关
adb 打开:需要重启Settings进程
adb shell setprop log.tag.UsbFunctionsCtrl D
adb shell setprop log.tag.UsbBroadcastReceiver D
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
private static final String TAG = "UsbFunctionsCtrl";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
3.3 关键日志
start u|SettingsActivity: Switching to|UsbFunctionsCtrl:|UsbDetailsFragment:|UsbBroadcastReceiver:|UsbDeviceManager:|sysui_multi_action: [757,.*,758,4]
android.hardware.usb.gadget@1.1-service-qti:|libusbconfigfs:
4、异常
symlink失败:
"Cannot create symlink %s -> %s errno:%d"
hardware/interfaces/usb/gadget/1.2/default/lib/include/UsbGadgetCommon.h
#define GADGET_PATH "/config/usb_gadget/g1/"
#define PULLUP_PATH GADGET_PATH "UDC"
#define PERSISTENT_BOOT_MODE "ro.bootmode"
#define VENDOR_ID_PATH GADGET_PATH "idVendor"
#define PRODUCT_ID_PATH GADGET_PATH "idProduct"
#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass"
#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass"
#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol"
#define DESC_USE_PATH GADGET_PATH "os_desc/use"
#define OS_DESC_PATH GADGET_PATH "os_desc/b.1"
#define CONFIG_PATH GADGET_PATH "configs/b.1/"
#define FUNCTIONS_PATH GADGET_PATH "functions/"
#define FUNCTION_NAME "function"
#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME
#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis"
hardware/interfaces/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
int linkFunction(const char* function, int index) {
char functionPath[kMaxFilePathLength];
char link[kMaxFilePathLength];
sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function);
sprintf(link, "%s%d", FUNCTION_PATH, index);
if (symlink(functionPath, link)) {
ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno);
return -1;
}
return 0;
}
Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
int* functionCount) {
if (((functions & GadgetFunction::MTP) != 0)) {
*ffsEnabled = true;
ALOGI("setCurrentUsbFunctions mtp");
if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;
if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;
// Add endpoints to be monitored.
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
} else if (((functions & GadgetFunction::PTP) != 0)) {
*ffsEnabled = true;
ALOGI("setCurrentUsbFunctions ptp");
if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;
if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;
// Add endpoints to be monitored.
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
}
if ((functions & GadgetFunction::MIDI) != 0) {
ALOGI("setCurrentUsbFunctions MIDI");
if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::ACCESSORY) != 0) {
ALOGI("setCurrentUsbFunctions Accessory");
if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
ALOGI("setCurrentUsbFunctions Audio Source");
if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::RNDIS) != 0) {
ALOGI("setCurrentUsbFunctions rndis");
if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
if (rndisFunction != "") {
if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
} else {
// link gsi.rndis for older pixel projects
if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
}
}
if ((functions & GadgetFunction::NCM) != 0) {
ALOGI("setCurrentUsbFunctions ncm");
if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;
}
return Status::SUCCESS;
}