USB Preferences
- 1. USB preference setting interface and entrance
- 2. USB function settings
-
- 2.1 USB function corresponding mode
- 2.2 Click Settings
- 2.3 Broadcast monitoring refresh
- 3. Log switch
-
- 3.1 Evet log
- 3.2 Log switch in code
- 3.3 Key logs
- 4. Abnormal
1. USB preference interface and entrance
Settings>Connected devices>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 function settings
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
2.1 USB function corresponding mode
FWK mode | Corresponding value | String display | Node |
---|---|---|---|
FUNCTION_NONE = 0 | NONE = 0 | ||
FUNCTION_MTP = GadgetFunction.MTP | MTP = 1 << 2 | “File Transfer ” | |
FUNCTION_PTP = GadgetFunction.PTP | PTP = 1 << 4 | “PTP” | |
FUNCTION_RNDIS = GadgetFunction.RNDIS | RNDIS = 1 << 5 | “USB tethering” | |
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 | “Not used for data transmission” |
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 Click Settings
mUsbBackend
Set via 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 & amp; & amp; !Utils.isMonkeyRunning() & amp; & amp; !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() & amp; & amp; !mCurrentFunctionsStr.equals(functions)) {<!-- --> setSystemProperty(getPersistProp(true), functions); } if ((!functions.equals(oemFunctions) & amp; & amp; !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 & amp; & amp; (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> & amp; callback, uint64_t timeout) {<!-- --> bool ffsEnabled = false; int i = 0; if (addGenericAndroidFunctions( & amp;monitorFfs, functions, & amp;ffsEnabled, & amp;i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR; if ((functions & amp; V1_2::GadgetFunction::ADB) != 0) {<!-- --> ffsEnabled = true; if (addAdb( & amp;monitorFfs, & amp;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( & amp;currentFunctionsAppliedCallback, 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> & amp; 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 & amp; 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 & amp; 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 & amp; GadgetFunction::MIDI) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions MIDI"); if (linkFunction("midi.gs5", (*functionCount) + + )) return Status::ERROR; } if ((functions & amp; GadgetFunction::ACCESSORY) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions Accessory"); if (linkFunction("accessory.gs2", (*functionCount) + + )) return Status::ERROR; } if ((functions & amp; GadgetFunction::AUDIO_SOURCE) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions Audio Source"); if (linkFunction("audio_source.gs3", (*functionCount) + + )) return Status::ERROR; } if ((functions & amp; 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 & amp; GadgetFunction::NCM) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions ncm"); if (linkFunction("ncm.gs6", (*functionCount) + + )) return Status::ERROR; } return Status::SUCCESS; }
Understand the USB Gadget HAL API architecture
2.3 Broadcast monitoring refresh
Broadcast listening refresh
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. Log switch
3.1 Evet Log
For example:
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 Log switch in code
Adb opening: Need to restart the Settings process
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 Key log
start u|SettingsActivity: Switching to|UsbFunctionsCtrl:|UsbDetailsFragment:|UsbBroadcastReceiver:|UsbDeviceManager:|sysui_multi_action: [757,.*,758,4]
[email protected]:|libusbconfigfs:
4. Abnormal
Symlink failed:
"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 & amp; 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 & amp; 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 & amp; GadgetFunction::MIDI) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions MIDI"); if (linkFunction("midi.gs5", (*functionCount) + + )) return Status::ERROR; } if ((functions & amp; GadgetFunction::ACCESSORY) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions Accessory"); if (linkFunction("accessory.gs2", (*functionCount) + + )) return Status::ERROR; } if ((functions & amp; GadgetFunction::AUDIO_SOURCE) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions Audio Source"); if (linkFunction("audio_source.gs3", (*functionCount) + + )) return Status::ERROR; } if ((functions & amp; 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 & amp; GadgetFunction::NCM) != 0) {<!-- --> ALOGI("setCurrentUsbFunctions ncm"); if (linkFunction("ncm.gs6", (*functionCount) + + )) return Status::ERROR; } return Status::SUCCESS; }