Chapter 39: USB, ADB, and MTP¶
USB connectivity in Android serves three fundamentally different audiences simultaneously: the developer debugging an application over ADB, the end user transferring photos via MTP, and the accessory manufacturer hooking a game controller through USB host mode. Each audience exercises a distinct slice of a stack that stretches from user-space Java services deep into the Linux kernel's USB gadget and host controller drivers. This chapter follows every byte from the USB wire through the HAL, into the framework services, and out to the application layer, referencing real AOSP source paths throughout.
39.1 USB Framework Overview¶
39.1.1 The Big Picture¶
Android's USB subsystem is organized into four vertical tiers: the public SDK
API (UsbManager), the system service (UsbService and its sub-managers), the
Hardware Abstraction Layer (IUsb and IUsbGadget AIDL HALs), and the Linux kernel
USB subsystem (gadget driver, host controller driver, configfs, functionfs).
graph TD
subgraph "Application Layer"
APP["Application / Settings UI"]
UM["UsbManager API"]
end
subgraph "System Server (USB Service)"
US["UsbService"]
UDM["UsbDeviceManager"]
UHM["UsbHostManager"]
UPM["UsbPortManager"]
UPERM["UsbPermissionManager"]
end
subgraph "HAL Layer"
IUSB["IUsb AIDL HAL"]
IUSBG["IUsbGadget AIDL HAL"]
end
subgraph "Kernel Layer"
GADGET["USB Gadget Driver"]
HOST["USB Host Controller"]
CONFIGFS["ConfigFS / FunctionFS"]
TYPEC["USB Type-C Controller"]
end
APP --> UM
UM -->|"Binder IPC"| US
US --> UDM
US --> UHM
US --> UPM
US --> UPERM
UDM -->|"AIDL Binder"| IUSBG
UPM -->|"AIDL Binder"| IUSB
UHM -->|"JNI"| HOST
IUSBG --> GADGET
IUSBG --> CONFIGFS
IUSB --> TYPEC
HOST -->|"/dev/bus/usb"| APP
39.1.2 Key Components¶
| Component | Type | Source Path | Role |
|---|---|---|---|
UsbManager |
SDK API | frameworks/base/core/java/android/hardware/usb/UsbManager.java |
Public API for apps |
UsbService |
System Service | frameworks/base/services/usb/.../UsbService.java |
Central coordinator |
UsbDeviceManager |
Internal Manager | frameworks/base/services/usb/.../UsbDeviceManager.java |
Gadget mode state machine |
UsbHostManager |
Internal Manager | frameworks/base/services/usb/.../UsbHostManager.java |
Host mode device enumeration |
UsbPortManager |
Internal Manager | frameworks/base/services/usb/.../UsbPortManager.java |
Type-C port management |
UsbPermissionManager |
Internal Manager | frameworks/base/services/usb/.../UsbPermissionManager.java |
Per-user permission tracking |
IUsb |
AIDL HAL | hardware/interfaces/usb/aidl/.../IUsb.aidl |
Port status, role switching |
IUsbGadget |
AIDL HAL | hardware/interfaces/usb/gadget/aidl/.../IUsbGadget.aidl |
Gadget function configuration |
adbd |
Native Daemon | packages/modules/adb/daemon/main.cpp |
ADB daemon |
| MTP Native | Native Library | frameworks/av/media/mtp/ |
MTP protocol implementation |
| MTP Service | Java Service | packages/services/Mtp/ |
MTP documents provider |
39.1.3 Dual-Mode Architecture: Gadget vs. Host¶
A single USB Type-C port can operate in two fundamentally different modes, determined by the data role negotiated through the USB Power Delivery protocol:
-
Device/Gadget mode (UFP): The Android device appears as a peripheral to a host (typically a PC). This enables MTP file transfer, ADB debugging, PTP photo transfer, RNDIS tethering, MIDI, and USB accessory (AOA). The kernel's USB gadget framework (
configfs) exposes composite USB functions. -
Host mode (DFP): The Android device acts as a USB host. Connected USB peripherals (keyboards, mice, storage, audio devices) are enumerated and made available to applications through the
UsbManagerAPI.
The UsbPortManager monitors port status changes via the IUsb HAL and
coordinates mode transitions between these two modes.
39.1.4 UsbManager -- The Public API¶
UsbManager (source: frameworks/base/core/java/android/hardware/usb/UsbManager.java)
is the @SystemService-annotated entry point that applications use to interact
with USB. It provides:
Device (gadget) mode operations:
- Query and set current USB functions (MTP, PTP, etc.)
- Access USB accessory information
- Open USB accessory connections
Host mode operations:
- Enumerate connected USB devices (
getDeviceList()) - Request permission to communicate with a device
- Open device connections (
openDevice())
Function constants define the gadget configurations available:
// From UsbManager.java -- function bitmask values
public static final long FUNCTION_NONE = 0;
public static final long FUNCTION_MTP = GadgetFunction.MTP; // 1 << 2
public static final long FUNCTION_PTP = GadgetFunction.PTP; // 1 << 4
public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS; // 1 << 5
public static final long FUNCTION_MIDI = GadgetFunction.MIDI; // 1 << 3
public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY; // 1 << 1
public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE; // 1 << 6
public static final long FUNCTION_ADB = GadgetFunction.ADB; // 1
public static final long FUNCTION_NCM = GadgetFunction.NCM; // 1 << 10
public static final long FUNCTION_UVC = GadgetFunction.UVC; // 1 << 7
These constants map directly to the GadgetFunction AIDL parcelable defined at
hardware/interfaces/usb/gadget/aidl/android/hardware/usb/gadget/GadgetFunction.aidl.
39.1.5 UsbService -- The Central Coordinator¶
UsbService (source: frameworks/base/services/usb/java/com/android/server/usb/UsbService.java)
implements IUsbManager and runs within system_server. It is the Binder
endpoint for all USB operations and delegates work to specialized sub-managers:
graph LR
subgraph "UsbService Delegation"
US["UsbService<br/>(IUsbManager.Stub)"]
UDM["UsbDeviceManager<br/>gadget mode"]
UHM["UsbHostManager<br/>host mode"]
UPM["UsbPortManager<br/>Type-C ports"]
UPERM["UsbPermissionManager<br/>per-user permissions"]
U4M["Usb4Manager<br/>USB4/Thunderbolt"]
UALSA["UsbAlsaManager<br/>audio devices"]
end
US --> UDM
US --> UHM
US --> UPM
US --> UPERM
US --> U4M
US --> UALSA
The service's lifecycle follows the standard SystemService pattern:
- Construction: During
system_serverboot,UsbServiceis instantiated. systemReady(): Triggers initialization of all sub-managers. TheUsbHostManagerstarts a native thread to monitor/dev/bus/usbfor device attach/detach events. TheUsbPortManagerqueries the HAL for current port status.- Runtime: Handles Binder calls from applications, broadcasts USB state changes, manages permissions and settings per user profile.
39.1.6 System Properties and Sysfs Paths¶
UsbDeviceManager monitors and controls USB state through several kernel
interfaces and system properties:
| Interface | Path | Purpose |
|---|---|---|
| USB state sysfs | /sys/class/android_usb/android0/state |
Legacy gadget state |
| USB functions sysfs | /sys/class/android_usb/android0/functions |
Legacy function config |
| UDC controller | sys.usb.controller (sysprop) |
ConfigFS UDC name |
| USB config | persist.sys.usb.config (sysprop) |
Persistent USB config |
| RNDIS address | /sys/class/android_usb/android0/f_rndis/ethaddr |
Tethering MAC |
| MIDI ALSA | /sys/class/android_usb/android0/f_midi/alsa |
MIDI device info |
| UEvent match | DEVPATH=/devices/virtual/android_usb/android0 |
Legacy state changes |
| UEvent match | SUBSYSTEM=udc |
Modern UDC state changes |
| FunctionFS | /dev/usb-ffs/adb/ |
ADB FunctionFS endpoints |
39.2 UsbDeviceManager: The Gadget Mode State Machine¶
39.2.1 Overview¶
UsbDeviceManager (source: frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java)
is the most complex component in the USB framework. It manages the Android
device's appearance as a USB peripheral, handling function switching (MTP, PTP,
RNDIS, accessory, MIDI, ADB), state transitions triggered by cable events, and
the delicate coordination between screen lock state, user preferences, and
kernel-level USB configuration.
The class implements ActivityTaskManagerInternal.ScreenObserver to react to
keyguard state changes -- a critical detail because MTP access to user data
requires the screen to be unlocked.
39.2.2 Architecture¶
graph TD
subgraph "UsbDeviceManager"
UEVENT["UsbUEventObserver<br/>(kernel uevent listener)"]
HANDLER["UsbHandler<br/>(abstract state machine)"]
HAL_HANDLER["UsbHandlerHal<br/>(HAL-based)"]
LEGACY_HANDLER["UsbHandlerLegacy<br/>(sysfs-based)"]
GADGET_HAL["UsbGadgetHal<br/>(AIDL proxy)"]
end
subgraph "Kernel"
UEVENT_K["Kernel UEvent"]
CONFIGFS_K["ConfigFS Gadget"]
FFS_K["FunctionFS"]
end
UEVENT_K -->|"USB_STATE change"| UEVENT
UEVENT -->|"MSG_UPDATE_STATE"| HANDLER
HANDLER --> HAL_HANDLER
HANDLER --> LEGACY_HANDLER
HAL_HANDLER -->|"setCurrentUsbFunctions()"| GADGET_HAL
LEGACY_HANDLER -->|"sysfs write"| CONFIGFS_K
GADGET_HAL -->|"AIDL Binder"| CONFIGFS_K
CONFIGFS_K --> FFS_K
39.2.3 Dual Handler Strategy¶
UsbDeviceManager selects between two concrete handler implementations at
construction time:
// From UsbDeviceManager constructor
if (mUsbGadgetHal == null) {
// Initialize the legacy UsbHandler
mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(),
mContext, this, alsaManager, permissionManager);
} else {
// Initialize HAL based UsbHandler
mHandler = new UsbHandlerHal(FgThread.get().getLooper(),
mContext, this, alsaManager, permissionManager);
}
-
UsbHandlerHal: Used on modern devices where theIUsbGadgetAIDL HAL is available. CallssetCurrentUsbFunctions()on the HAL to request configuration changes. The HAL implementation handles the kernel-level ConfigFS manipulation. -
UsbHandlerLegacy: Fallback for older devices without the gadget HAL. Directly writes to sysfs files and system properties to switch USB functions.
39.2.4 Message-Based State Machine¶
The UsbHandler processes USB state transitions through Android's Handler
message queue. This serializes all state changes onto the foreground thread,
preventing race conditions:
| Message ID | Constant | Trigger |
|---|---|---|
| 0 | MSG_UPDATE_STATE |
Kernel reports connect/disconnect/configured |
| 1 | MSG_ENABLE_ADB |
ADB toggle changed in developer settings |
| 2 | MSG_SET_CURRENT_FUNCTIONS |
Application requests function change |
| 3 | MSG_SYSTEM_READY |
System server ready |
| 4 | MSG_BOOT_COMPLETED |
Boot completed broadcast |
| 5 | MSG_USER_SWITCHED |
Active user changed |
| 6 | MSG_UPDATE_USER_RESTRICTIONS |
User policy changed |
| 7 | MSG_UPDATE_PORT_STATE |
Type-C port status changed |
| 8 | MSG_ACCESSORY_MODE_ENTER_TIMEOUT |
10s timeout for accessory negotiation |
| 9 | MSG_UPDATE_CHARGING_STATE |
Battery charging state changed |
| 10 | MSG_UPDATE_HOST_STATE |
Host mode device attach/detach |
| 11 | MSG_LOCALE_CHANGED |
Language changed (notification update) |
| 12 | MSG_SET_SCREEN_UNLOCKED_FUNCTIONS |
Screen-unlock function preference |
| 13 | MSG_UPDATE_SCREEN_LOCK |
Keyguard shown/hidden |
| 14 | MSG_SET_CHARGING_FUNCTIONS |
Switch to charging-only mode |
| 15 | MSG_SET_FUNCTIONS_TIMEOUT |
Function switch timed out |
| 16 | MSG_GET_CURRENT_USB_FUNCTIONS |
Query current gadget functions |
| 17 | MSG_FUNCTION_SWITCH_TIMEOUT |
Gadget re-enumeration timeout |
| 18 | MSG_GADGET_HAL_REGISTERED |
HAL service became available |
| 19 | MSG_RESET_USB_GADGET |
Reset gadget hardware |
| 20 | MSG_ACCESSORY_HANDSHAKE_TIMEOUT |
AOA handshake timeout |
| 21 | MSG_INCREASE_SENDSTRING_COUNT |
AOA string descriptor received |
| 22 | MSG_UPDATE_USB_SPEED |
USB speed negotiation complete |
| 23 | MSG_UPDATE_HAL_VERSION |
HAL version info updated |
| 24 | MSG_USER_UNLOCKED_AFTER_BOOT |
First unlock after boot |
39.2.5 USB State Transitions¶
The kernel reports USB state changes through UEvent messages. The
UsbUEventObserver processes these and translates them into handler messages:
stateDiagram-v2
[*] --> DISCONNECTED: Cable unplugged
DISCONNECTED --> CONNECTED: Cable plugged in
CONNECTED --> CONFIGURED: Host completes enumeration
CONFIGURED --> DISCONNECTED: Cable removed
CONFIGURED --> CONNECTED: Re-enumeration on function switch
state CONFIGURED {
[*] --> CHARGING: No data function
CHARGING --> MTP: User selects MTP
CHARGING --> PTP: User selects PTP
CHARGING --> RNDIS: USB tethering enabled
CHARGING --> MIDI: User selects MIDI
MTP --> CHARGING: Screen locked
PTP --> CHARGING: Screen locked
}
The updateState() method in UsbHandler maps kernel state strings to
internal state:
// From UsbHandler.updateState()
if ("DISCONNECTED".equals(state)) {
connected = 0; configured = 0;
} else if ("CONNECTED".equals(state)) {
connected = 1; configured = 0;
} else if ("CONFIGURED".equals(state)) {
connected = 1; configured = 1;
}
39.2.6 Function Switching¶
When the user (or system) requests a USB function change, the state machine performs a multi-step process:
sequenceDiagram
participant User as User / Settings
participant UDM as UsbDeviceManager
participant Handler as UsbHandlerHal
participant HAL as IUsbGadget HAL
participant Kernel as Kernel ConfigFS
participant Host as USB Host (PC)
User->>UDM: setCurrentFunctions(MTP | ADB)
UDM->>Handler: MSG_SET_CURRENT_FUNCTIONS
Handler->>HAL: setCurrentUsbFunctions(bitmap, callback, timeout)
HAL->>Kernel: Tear down current gadget
Kernel-->>Host: USB disconnect
HAL->>Kernel: Configure new functions in ConfigFS
HAL->>Kernel: Enable UDC
Kernel-->>Host: USB connect (re-enumerate)
Host->>Kernel: SET_CONFIGURATION
Kernel-->>Handler: UEvent: CONFIGURED
Handler->>Handler: MSG_UPDATE_STATE(connected=1, configured=1)
Handler->>UDM: Broadcast USB_STATE intent
39.2.7 Debouncing and Timeouts¶
Function switching causes a transient USB disconnect. The state machine applies debouncing to prevent false disconnect events from disrupting the function switch:
// Debounce delays from UsbDeviceManager
private static final int DEVICE_STATE_UPDATE_DELAY_EXT = 3000; // 3 seconds
private static final int DEVICE_STATE_UPDATE_DELAY = 1000; // 1 second
private static final int HOST_STATE_UPDATE_DELAY = 1000; // 1 second
private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000; // 10 seconds
private static final int ACCESSORY_HANDSHAKE_TIMEOUT = 10 * 1000; // 10 seconds
After resetUsbGadget() is called, debouncing is temporarily disabled via the
mResetUsbGadgetDisableDebounce flag, ensuring the first disconnect after a
gadget reset is processed immediately.
39.2.8 Screen Lock Interaction¶
MTP requires access to user storage, which must be protected when the screen is
locked. UsbDeviceManager coordinates with the keyguard:
- When the screen locks (
onKeyguardStateChanged(true)), the handler receivesMSG_UPDATE_SCREEN_LOCK. - If MTP or PTP is active, the handler switches to charging-only functions.
- The user's preferred functions are stored in
SharedPreferencesunder the keyusb-screen-unlocked-config-<userId>. - When the screen unlocks, the previously stored functions are restored.
39.2.9 Interface Deny List¶
For security, certain USB interface classes are always denied from application access when the device acts as a host:
// From UsbDeviceManager static initializer
sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
sDenyInterfaces.add(UsbConstants.USB_CLASS_COMM);
sDenyInterfaces.add(UsbConstants.USB_CLASS_HID);
sDenyInterfaces.add(UsbConstants.USB_CLASS_PRINTER);
sDenyInterfaces.add(UsbConstants.USB_CLASS_MASS_STORAGE);
sDenyInterfaces.add(UsbConstants.USB_CLASS_HUB);
sDenyInterfaces.add(UsbConstants.USB_CLASS_CDC_DATA);
sDenyInterfaces.add(UsbConstants.USB_CLASS_CSCID);
sDenyInterfaces.add(UsbConstants.USB_CLASS_CONTENT_SEC);
sDenyInterfaces.add(UsbConstants.USB_CLASS_VIDEO);
sDenyInterfaces.add(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER);
39.2.10 MTP Service Binding¶
When MTP or PTP functions become active, the handler binds to the MTP service:
// Constants from UsbHandler
protected static final String MTP_PACKAGE_NAME = "com.android.mtp";
protected static final String MTP_SERVICE_CLASS_NAME = "com.android.mtp.MtpService";
The ServiceConnection is maintained for the duration of the MTP session and
unbound when functions change away from MTP/PTP. This binding serves a critical
purpose beyond just starting the service: it prevents the Activity Manager from
freezing the MTP process. Without the binding, the system might freeze the MTP
service's process to reclaim resources, which would break the ongoing USB
transfer session.
The binding lifecycle follows the MTP function state:
stateDiagram-v2
[*] --> Unbound: MTP not active
Unbound --> Binding: MTP function enabled
Binding --> Bound: onServiceConnected
Bound --> Unbinding: MTP function disabled
Unbinding --> Unbound: onServiceDisconnected
Bound --> Bound: Transfer in progress
39.2.11 MIDI Function Discovery¶
When the MIDI gadget function is activated, UsbDeviceManager must discover
the ALSA card and device numbers for the synthesized MIDI device. This involves
two approaches:
Modern approach (sysfs-based identification):
// Navigate the sysfs hierarchy under the UDC controller
File soundDir = new File("/sys/class/udc/" + controllerName + "/gadget/sound");
File[] cardDirs = FileUtils.listFilesOrEmpty(soundDir,
(dir, file) -> file.startsWith("card"));
File[] midis = FileUtils.listFilesOrEmpty(cardDirs[0],
(dir, file) -> file.startsWith("midi"));
// Parse card and device numbers from "midiC<card>D<device>"
Pattern pattern = Pattern.compile("midiC(\\d+)D(\\d+)");
Matcher matcher = pattern.matcher(midis[0].getName());
if (matcher.matches()) {
mMidiCard = Integer.parseInt(matcher.group(1));
mMidiDevice = Integer.parseInt(matcher.group(2));
}
Legacy approach (ALSA file):
// Read from the legacy sysfs path
Scanner scanner = new Scanner(new File(MIDI_ALSA_PATH));
mMidiCard = scanner.nextInt();
mMidiDevice = scanner.nextInt();
The discovered card/device pair is passed to UsbAlsaManager to register the
peripheral MIDI device with the Android MIDI service.
39.2.12 USB State Broadcast¶
The handler broadcasts USB state changes to all interested receivers:
protected void updateUsbStateBroadcastIfNeeded(long functions) {
Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
intent.putExtra(UsbManager.USB_DATA_UNLOCKED,
isUsbTransferAllowed() && isUsbDataTransferActive(mCurrentFunctions));
// Add active function flags
long remainingFunctions = functions;
while (remainingFunctions != 0) {
intent.putExtra(UsbManager.usbFunctionsToString(
Long.highestOneBit(remainingFunctions)), true);
remainingFunctions -= Long.highestOneBit(remainingFunctions);
}
// Only broadcast if state actually changed
if (!isUsbStateChanged(intent)) return;
sendStickyBroadcast(intent);
}
The ACTION_USB_STATE broadcast is sticky: late-registered receivers
immediately receive the last broadcast state. The intent includes boolean
extras for each active function, allowing receivers to check specific
function states.
39.2.13 User Restriction Enforcement¶
Enterprise-managed devices can restrict USB file transfer through
UserManager.DISALLOW_USB_FILE_TRANSFER:
protected boolean isUsbTransferAllowed() {
UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
return !userManager.hasUserRestriction(
UserManager.DISALLOW_USB_FILE_TRANSFER);
}
When this restriction is active:
- MTP and PTP functions are suppressed
- The USB notification shows "Charging only"
- Applications cannot switch to data transfer functions
39.2.14 Accessory Handshake Tracking¶
The handler tracks detailed timing information about the AOA handshake process for debugging and analytics:
private long mAccessoryConnectionStartTime = 0L; // When GET_PROTOCOL received
private int mSendStringCount = 0; // Number of SEND_STRING uevents
private boolean mStartAccessory = false; // Whether START received
// Broadcast handshake details for debugging
private void broadcastUsbAccessoryHandshake() {
Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_HANDSHAKE)
.putExtra(UsbManager.EXTRA_ACCESSORY_UEVENT_TIME,
mAccessoryConnectionStartTime)
.putExtra(UsbManager.EXTRA_ACCESSORY_STRING_COUNT,
mSendStringCount)
.putExtra(UsbManager.EXTRA_ACCESSORY_START,
mStartAccessory)
.putExtra(UsbManager.EXTRA_ACCESSORY_HANDSHAKE_END,
SystemClock.elapsedRealtime());
sendStickyBroadcast(intent);
}
39.2.15 RNDIS Tethering Integration¶
When RNDIS (USB tethering) is activated:
- The handler configures the
RNDISgadget function. - A locally-administered MAC address is generated from
ro.serialno:
// First byte is 0x02 to signify a locally administered address
address[0] = 0x02;
String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
// XOR the USB serial across the remaining 5 bytes
for (int i = 0; i < serialLength; i++) {
address[i % (ETH_ALEN - 1) + 1] ^= (int) serial.charAt(i);
}
- The address is written to
/sys/class/android_usb/android0/f_rndis/ethaddr. - The tethering service takes over IP configuration of the resulting
rndis0network interface.
39.3 USB HAL: IUsb and IUsbGadget¶
39.3.1 HAL Architecture Overview¶
Android's USB HAL is split into two distinct AIDL interfaces, each managing a different aspect of USB hardware:
graph TD
subgraph "Framework (system_server)"
UPM["UsbPortManager"]
UDM2["UsbDeviceManager"]
end
subgraph "IUsb HAL"
IUSB2["IUsb.aidl"]
IUSB_CB["IUsbCallback.aidl"]
PS["PortStatus.aidl"]
end
subgraph "IUsbGadget HAL"
IUSBG2["IUsbGadget.aidl"]
IUSBG_CB["IUsbGadgetCallback.aidl"]
GF["GadgetFunction.aidl"]
USPD["UsbSpeed.aidl"]
end
subgraph "Kernel"
TYPEC2["Type-C Controller Driver"]
GADGET2["USB Gadget ConfigFS"]
end
UPM -->|"Binder"| IUSB2
IUSB2 -->|"callback"| IUSB_CB
IUSB_CB --> UPM
IUSB2 --> TYPEC2
UDM2 -->|"Binder"| IUSBG2
IUSBG2 -->|"callback"| IUSBG_CB
IUSBG_CB --> UDM2
IUSBG2 --> GADGET2
39.3.2 IUsb AIDL Interface¶
Source: hardware/interfaces/usb/aidl/android/hardware/usb/IUsb.aidl
The IUsb interface manages USB Type-C port hardware. It is marked
@VintfStability (VINTF-stable) and declared oneway (asynchronous):
@VintfStability
oneway interface IUsb {
void enableContaminantPresenceDetection(in String portName,
in boolean enable, long transactionId);
void enableUsbData(in String portName, boolean enable, long transactionId);
void enableUsbDataWhileDocked(in String portName, long transactionId);
void queryPortStatus(long transactionId);
void setCallback(in IUsbCallback callback);
void switchRole(in String portName, in PortRole role, long transactionId);
void limitPowerTransfer(in String portName, boolean limit, long transactionId);
void resetUsbPort(in String portName, long transactionId);
}
Key operations:
| Method | Purpose |
|---|---|
queryPortStatus() |
Retrieve current status of all Type-C ports |
switchRole() |
Trigger DR_SWAP or PR_SWAP for role switching |
enableUsbData() |
Enable/disable USB data signaling |
enableContaminantPresenceDetection() |
Moisture/debris detection |
setCallback() |
Register for async notifications |
limitPowerTransfer() |
Control power delivery |
resetUsbPort() |
Reset a misbehaving port |
39.3.3 PortStatus: Comprehensive Port State¶
Source: hardware/interfaces/usb/aidl/android/hardware/usb/PortStatus.aidl
The PortStatus parcelable conveys the complete state of a USB Type-C port:
@VintfStability
parcelable PortStatus {
String portName;
PortDataRole currentDataRole; // HOST or DEVICE
PortPowerRole currentPowerRole; // SOURCE or SINK
PortMode currentMode; // UFP, DFP, AUDIO_ACCESSORY, DEBUG_ACCESSORY
boolean canChangeMode;
boolean canChangeDataRole; // PD DR_SWAP supported
boolean canChangePowerRole; // PD PR_SWAP supported
PortMode[] supportedModes;
ContaminantProtectionMode[] supportedContaminantProtectionModes;
boolean supportsEnableContaminantPresenceProtection;
ContaminantProtectionStatus contaminantProtectionStatus;
ContaminantDetectionStatus contaminantDetectionStatus;
UsbDataStatus[] usbDataStatus;
boolean powerTransferLimited;
PowerBrickStatus powerBrickStatus;
boolean supportsComplianceWarnings;
ComplianceWarning[] complianceWarnings;
PlugOrientation plugOrientation; // Cable orientation (CC1 vs CC2)
AltModeData[] supportedAltModes; // DisplayPort Alt Mode, etc.
}
39.3.4 IUsbGadget AIDL Interface¶
Source: hardware/interfaces/usb/gadget/aidl/android/hardware/usb/gadget/IUsbGadget.aidl
The IUsbGadget interface controls the USB gadget (device mode) configuration:
@VintfStability
oneway interface IUsbGadget {
void setCurrentUsbFunctions(in long functions,
in IUsbGadgetCallback callback,
in long timeoutMs, long transactionId);
void getCurrentUsbFunctions(in IUsbGadgetCallback callback,
long transactionId);
void getUsbSpeed(in IUsbGadgetCallback callback, long transactionId);
void reset(in IUsbGadgetCallback callback, long transactionId);
}
39.3.5 GadgetFunction Bitmask¶
Source: hardware/interfaces/usb/gadget/aidl/android/hardware/usb/gadget/GadgetFunction.aidl
Functions are combined as a bitmask:
| Constant | Value | Description |
|---|---|---|
NONE |
0 |
No function (pull down gadget) |
ADB |
1 |
Android Debug Bridge |
ACCESSORY |
1 << 1 |
Android Open Accessory |
MTP |
1 << 2 |
Media Transfer Protocol |
MIDI |
1 << 3 |
USB MIDI device |
PTP |
1 << 4 |
Picture Transfer Protocol |
RNDIS |
1 << 5 |
USB tethering (RNDIS) |
AUDIO_SOURCE |
1 << 6 |
AOAv2 audio source |
UVC |
1 << 7 |
USB Video Class |
NCM |
1 << 10 |
Network Control Model |
Multiple functions are composited. For example, MTP | ADB = 5 (binary
0b00000101) configures both MTP and ADB simultaneously.
39.3.6 HAL Version Evolution¶
The USB HAL has evolved through multiple HIDL and AIDL versions:
timeline
title USB HAL Version History
section HIDL Era
1.0 : Basic port status and role switching
1.1 : Extended port status
1.2 : Contaminant detection, USB speed
1.3 : Compliance warnings
section AIDL Era
AIDL v1 : Migration to AIDL, all HIDL features
AIDL v2 : Power brick, DisplayPort Alt Mode
AIDL v3 : Plug orientation, compliance enhancements
Source directories:
- HIDL:
hardware/interfaces/usb/1.0/,1.1/,1.2/,1.3/ - AIDL:
hardware/interfaces/usb/aidl/ - Gadget HIDL:
hardware/interfaces/usb/gadget/1.0/,1.1/,1.2/ - Gadget AIDL:
hardware/interfaces/usb/gadget/aidl/
39.3.7 Default HAL Implementation¶
Source: hardware/interfaces/usb/aidl/default/
The default HAL implementation provides a reference that vendors can use as a starting point. It typically interacts with the kernel through:
- Sysfs files under
/sys/class/typec/for port status - ConfigFS under
/config/usb_gadget/for gadget function configuration - Kernel UEvents for asynchronous status notifications
- Debugfs for testing and development
39.3.8 UsbPortManager and HAL Interaction¶
UsbPortManager (source: frameworks/base/services/usb/java/com/android/server/usb/UsbPortManager.java)
is the framework-side consumer of the IUsb HAL:
// From UsbPortManager constructor
public UsbPortManager(Context context) {
mContext = context;
mUsbPortHal = UsbPortHalInstance.getInstance(this, null);
}
public void systemReady() {
mSystemReady = true;
if (mUsbPortHal != null) {
mUsbPortHal.systemReady();
mUsbPortHal.queryPortStatus(++mTransactionId);
}
}
Port role combinations are tracked as bitmasks:
// Role combinations from UsbPortManager
private static final int COMBO_SOURCE_HOST =
UsbPort.combineRolesAsBit(POWER_ROLE_SOURCE, DATA_ROLE_HOST);
private static final int COMBO_SOURCE_DEVICE =
UsbPort.combineRolesAsBit(POWER_ROLE_SOURCE, DATA_ROLE_DEVICE);
private static final int COMBO_SINK_HOST =
UsbPort.combineRolesAsBit(POWER_ROLE_SINK, DATA_ROLE_HOST);
private static final int COMBO_SINK_DEVICE =
UsbPort.combineRolesAsBit(POWER_ROLE_SINK, DATA_ROLE_DEVICE);
39.4 ADB Architecture¶
39.4.1 Overview¶
The Android Debug Bridge (ADB) is the primary developer tool for communicating with Android devices. It enables shell access, file transfer, application installation, log collection, port forwarding, and dozens of other debugging and development operations. ADB is a Mainline module, meaning it can be updated independently of the full platform OTA through Google Play system updates.
ADB uses a client-server architecture with three components:
graph LR
subgraph "Developer Machine"
CLIENT["adb client<br/>(CLI tool)"]
SERVER["adb server<br/>(background daemon)"]
end
subgraph "Android Device"
ADBD["adbd<br/>(device daemon)"]
end
CLIENT -->|"TCP localhost:5037"| SERVER
SERVER -->|"USB or TCP/WiFi"| ADBD
Source: packages/modules/adb/
39.4.2 Three-Component Architecture¶
1. ADB Client (adb): The command-line tool that developers invoke. It
connects to the local ADB server over TCP (default port 5037). If no server is
running, the client starts one.
Source: packages/modules/adb/client/main.cpp
2. ADB Server: A background process on the developer's machine that manages connections to all devices. It:
- Discovers devices via USB scanning and mDNS
- Multiplexes connections from multiple
adbclients - Handles device authentication
- Routes commands to the appropriate device
3. ADB Daemon (adbd): Runs on the Android device. It:
- Listens for connections over USB (FunctionFS) and/or TCP
- Authenticates connections using RSA key pairs
- Spawns shell processes, handles file transfers, manages port forwarding
- Runs with reduced privileges (UID
shell) on production builds
Source: packages/modules/adb/daemon/main.cpp
39.4.3 ADB Protocol¶
The ADB protocol is a simple message-based protocol with six core message
types, defined in packages/modules/adb/adb.h:
#define A_SYNC 0x434e5953 // 'SYNC' - synchronization
#define A_CNXN 0x4e584e43 // 'CNXN' - connection
#define A_OPEN 0x4e45504f // 'OPEN' - open stream
#define A_OKAY 0x59414b4f // 'OKAY' - stream ready
#define A_CLSE 0x45534c43 // 'CLSE' - close stream
#define A_WRTE 0x45545257 // 'WRTE' - write data
#define A_AUTH 0x48545541 // 'AUTH' - authentication
#define A_STLS 0x534C5453 // 'STLS' - start TLS
Each message has a fixed 24-byte header:
// From types.h
struct amessage {
uint32_t command; // command identifier constant
uint32_t arg0; // first argument
uint32_t arg1; // second argument
uint32_t data_length; // length of payload (0 is allowed)
uint32_t data_check; // checksum of data payload
uint32_t magic; // command ^ 0xffffffff
};
39.4.4 Connection Establishment¶
sequenceDiagram
participant Server as ADB Server
participant Daemon as adbd (device)
Note over Server,Daemon: USB or TCP connection established
Server->>Daemon: A_CNXN (version, max_payload, "host::features=...")
alt Authentication Required
Daemon->>Server: A_AUTH (TOKEN, random_token)
Server->>Daemon: A_AUTH (SIGNATURE, signed_token)
alt Signature Valid
Daemon->>Server: A_CNXN (version, max_payload, "device::features=...")
else Key Not Known
Daemon->>Server: A_AUTH (TOKEN, new_random_token)
Server->>Daemon: A_AUTH (RSAPUBLICKEY, public_key)
Note over Daemon: User prompt: "Allow USB debugging?"
Daemon->>Server: A_CNXN (version, max_payload, "device::features=...")
end
else Authentication Not Required (eng build)
Daemon->>Server: A_CNXN (version, max_payload, "device::features=...")
end
The protocol version has evolved:
#define A_VERSION_MIN 0x01000000 // original
#define A_VERSION_SKIP_CHECKSUM 0x01000001 // skip checksum (Dec 2017)
#define A_VERSION 0x01000001 // current
39.4.5 Transport Types¶
ADB supports multiple transport types, defined in packages/modules/adb/adb.h:
enum TransportType {
kTransportUsb, // Physical USB connection
kTransportLocal, // TCP/IP connection (emulator or network)
kTransportAny, // Any available transport
kTransportHost, // Service in the ADB server itself
};
Connection states track the lifecycle of each transport:
enum ConnectionState {
kCsConnecting = 0, // Haven't received a response yet
kCsAuthorizing, // Authorizing with keys from ADB_VENDOR_KEYS
kCsUnauthorized, // Fell back to user prompt
kCsNoPerm, // Insufficient permissions
kCsDetached, // USB device detached from server
kCsOffline, // Peer detected but no comm started
kCsBootloader, // fastboot OS
kCsDevice, // Android OS (adbd)
kCsHost, // What device sees from its end
kCsRecovery, // Recovery mode (adbd)
kCsSideload, // Sideload mode (minadbd)
kCsRescue, // Rescue mode (minadbd)
};
39.4.6 The atransport Class¶
Source: packages/modules/adb/transport.h
The atransport class is the central abstraction for a connection to a remote
device:
classDiagram
class atransport {
+TransportId id
+TransportType type
+string serial
+string product
+string model
+string device
+bool use_tls
+FeatureSet features
+ConnectionState GetConnectionState()
+void SetConnection(Connection)
+int Write(apacket*)
+void Reset()
+void Kick()
}
class Connection {
<<abstract>>
+bool Write(unique_ptr~apacket~)
+bool Start()
+void Stop()
+bool DoTlsHandshake(RSA*)
+void Reset()
}
class BlockingConnection {
<<abstract>>
+bool Read(apacket*)
+bool Write(apacket*)
+void Close()
+void Reset()
}
class FdConnection {
-unique_fd fd_
-TlsConnection tls_
}
class BlockingConnectionAdapter {
-BlockingConnection underlying_
-thread read_thread_
-thread write_thread_
-deque write_queue_
}
atransport --> Connection
Connection <|-- BlockingConnectionAdapter
BlockingConnectionAdapter --> BlockingConnection
BlockingConnection <|-- FdConnection
39.4.7 USB Transport (Device Side)¶
Source: packages/modules/adb/daemon/usb.cpp
On the device, adbd communicates over USB using Linux FunctionFS:
// USB FunctionFS endpoints
#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
#define USB_FFS_ADB_EP0 USB_FFS_ADB_PATH "ep0" // Control endpoint
#define USB_FFS_ADB_OUT USB_FFS_ADB_PATH "ep1" // OUT (host to device)
#define USB_FFS_ADB_IN USB_FFS_ADB_PATH "ep2" // IN (device to host)
The USB transport uses asynchronous I/O (Linux AIO) for performance:
static constexpr size_t kUsbReadQueueDepth = 8;
static constexpr size_t kUsbReadSize = 16384; // 16KB per read
static constexpr size_t kUsbWriteQueueDepth = 8;
static constexpr size_t kUsbWriteSize = 16384; // 16KB per write
The 16KB limit exists because not all USB controllers support larger operations. Each submitted operation allocates a kernel buffer of that size, so the queue depth is kept shallow (8 entries) to minimize memory usage while maintaining sufficient depth to keep the USB stack saturated.
FunctionFS events drive the USB transport state machine:
// FunctionFS event types handled by adbd
FUNCTIONFS_BIND // Function bound to UDC
FUNCTIONFS_UNBIND // Function unbound from UDC
FUNCTIONFS_ENABLE // Host configured the gadget
FUNCTIONFS_DISABLE // Host deconfigured the gadget
FUNCTIONFS_SETUP // Control request from host
FUNCTIONFS_SUSPEND // USB suspend signaled
FUNCTIONFS_RESUME // USB resume signaled
The I/O subsystem uses a templated IoBlock structure for managing asynchronous
operations:
template <class Payload>
struct IoBlock {
bool pending = false;
struct iocb control = {};
Payload payload;
TransferId id() const { return TransferId::from_value(control.aio_data); }
};
using IoReadBlock = IoBlock<Block>;
using IoWriteBlock = IoBlock<std::shared_ptr<Block>>;
ADB identifies itself on the USB bus with specific class/subclass codes that the host-side ADB server uses to discover ADB-capable devices:
#define ADB_CLASS 0xff // Vendor-specific class
#define ADB_SUBCLASS 0x42 // ADB subclass
#define ADB_PROTOCOL 0x1 // ADB protocol
// USB Debug Bridge Class (USB 3.x)
#define ADB_DBC_CLASS 0xDC // Debug Device Class
#define ADB_DBC_SUBCLASS 0x2 // Debug subclass
39.4.7.1 USB Transport (Host Side)¶
Source: packages/modules/adb/client/usb_linux.cpp, packages/modules/adb/client/usb_libusb.cpp
On the host, the ADB server discovers and communicates with devices through either:
-
Direct USB I/O (
usb_linux.cpp): Scans/dev/bus/usb/and usesusbdevfsioctls for direct device communication. This is the traditional approach. -
libusb (
usb_libusb.cpp): Uses the libusb library for portable USB access. Provides hotplug notification support.
The host USB transport scans for USB interfaces matching the ADB class/subclass/protocol identifiers, then claims the interface and opens bulk endpoints for data transfer.
graph TD
subgraph "ADB Server USB Discovery"
SCAN["Scan /dev/bus/usb/ or libusb hotplug"]
PARSE["Parse USB descriptors"]
MATCH["Match ADB class/subclass/protocol"]
CLAIM["Claim USB interface"]
OPEN["Open bulk endpoints"]
TRANSPORT["Create atransport"]
end
SCAN --> PARSE
PARSE --> MATCH
MATCH --> CLAIM
CLAIM --> OPEN
OPEN --> TRANSPORT
39.4.8 Authentication¶
Source: packages/modules/adb/daemon/auth.cpp
ADB authentication uses RSA-2048 key pairs:
- The server generates a 20-byte random token.
- The daemon sends the token to the server.
- The server signs the token with its private key.
- The daemon verifies the signature against known public keys.
- If verification fails, the daemon prompts the user to accept the key.
sequenceDiagram
participant Server as ADB Server
participant Daemon as adbd
participant UI as Framework (Settings)
Daemon->>Server: A_AUTH(TOKEN, 20-byte random)
Server->>Daemon: A_AUTH(SIGNATURE, RSA-signed token)
alt Key in authorized_keys
Daemon->>Server: A_CNXN (success)
else Unknown key
Daemon->>Server: A_AUTH(TOKEN, new random)
Server->>Daemon: A_AUTH(RSAPUBLICKEY, public key)
Daemon->>UI: Show authorization dialog
UI-->>Daemon: User approves
Note over Daemon: Save key to /data/misc/adb/adb_keys
Daemon->>Server: A_CNXN (success)
end
The authentication context is managed through adbd_auth:
static AdbdAuthContext* auth_ctx;
static RSA* rsa_pkey = nullptr;
bool auth_required = true; // Set to false on eng builds
39.4.9 adbd Privilege Management¶
Source: packages/modules/adb/daemon/main.cpp
On production builds, adbd drops privileges using minijail:
// Groups added for various functionality
gid_t groups[] = {
AID_ADB, // USB driver access
AID_LOG, // System logs (logcat)
AID_INPUT, // Input diagnostics (getevent)
AID_INET, // Network diagnostics (ping)
AID_NET_BT, // Bluetooth diagnostics
AID_NET_BT_ADMIN, // Bluetooth admin
AID_SDCARD_R, // SD card read
AID_SDCARD_RW, // SD card write
AID_NET_BW_STATS, // Network bandwidth stats
AID_READPROC, // /proc cross-UID reading
AID_UHID, // HID command support
AID_EXT_DATA_RW, // External data access
AID_EXT_OBB_RW, // OBB file access
AID_READTRACEFS, // Trace filesystem
};
The decision to drop privileges depends on build type:
// ro.debuggable: 1 on eng and userdebug builds
// ro.secure: 1 on userdebug and user builds
// service.adb.root: set by "adb root" command
bool drop = ro_secure;
if (ro_debuggable && adb_root) drop = false;
if (adb_unroot) drop = true;
39.4.10 Feature Negotiation¶
ADB peers exchange feature sets during the connection handshake via the
connection banner. Key features defined in transport.h:
| Feature | Description |
|---|---|
shell_v2 |
Shell protocol version 2 (multiplexed stdin/stdout/stderr) |
cmd |
cmd command available |
stat_v2 |
Extended stat information |
ls_v2 |
Extended directory listing |
push_sync |
push --sync support |
apex |
APK/APEX installation |
abb |
Android Binder Bridge (interactive) |
abb_exec |
Android Binder Bridge (raw pipe) |
sendrecv_v2 |
File sync v2 protocol |
sendrecv_v2_brotli |
Brotli compression for sync v2 |
sendrecv_v2_lz4 |
LZ4 compression for sync v2 |
sendrecv_v2_zstd |
Zstd compression for sync v2 |
sendrecv_v2_dry_run_send |
Dry-run send mode |
delayed_ack |
Delayed acknowledgment for throughput |
dev-raw |
Raw device access service |
39.4.11 WiFi ADB¶
Starting with Android 11, ADB supports wireless connections via Wi-Fi. The
adbd daemon listens on TCP port 5555 (or a configured port) and uses mDNS
for service discovery:
// From daemon/main.cpp
if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
usb_init(); // Listen on USB
is_usb = true;
}
// Also listen on TCP if configured
std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
addrs.push_back(android::base::StringPrintf("tcp:%d", port));
addrs.push_back(android::base::StringPrintf("vsock:%d", port));
setup_adb(addrs);
}
WiFi ADB uses TLS for encrypted communication, with pairing handled through QR codes or 6-digit pairing codes.
39.5 ADB Commands Deep Dive¶
39.5.1 Command Architecture¶
ADB commands follow a consistent pattern: the client sends a service request string to the server, which either handles it locally or forwards it to the device daemon. The daemon maps service strings to handlers.
graph TD
subgraph "adb client"
CLI["adb shell ls"]
end
subgraph "adb server (host)"
PARSE["Parse command"]
ROUTE["Route to transport"]
end
subgraph "adbd (device)"
SVC["Service dispatcher"]
SHELL["shell service"]
SYNC["sync service"]
JDWP["jdwp service"]
ABB["abb service"]
FWD["forward service"]
end
CLI -->|"host:transport:serial"| PARSE
PARSE -->|"shell:ls"| ROUTE
ROUTE -->|"A_OPEN shell:ls"| SVC
SVC --> SHELL
SVC --> SYNC
SVC --> JDWP
SVC --> ABB
SVC --> FWD
39.5.2 Shell Commands (adb shell)¶
Source: packages/modules/adb/daemon/shell_service.cpp
The shell service uses the Shell Protocol v2, which multiplexes stdin, stdout, stderr, and exit status over a single stream:
// From shell_protocol.h
enum Id : uint8_t {
kIdStdin = 0, // Input to shell
kIdStdout = 1, // Standard output
kIdStderr = 2, // Standard error
kIdExit = 3, // Exit status
kIdCloseStdin = 4, // Close stdin
kIdWindowSizeChange = 5, // Terminal resize
kIdInvalid = 255,
};
Each shell protocol packet has a 5-byte header (1 byte ID + 4 bytes length):
+--------+--------+--------+--------+--------+--------...--------+
| ID | Length (32-bit LE) | Payload |
+--------+--------+--------+--------+--------+--------...--------+
Shell v2 supports:
- Separate stdout/stderr streams
- Proper exit code propagation
- PTY allocation for interactive shells
- Window size change notifications
Interactive shell vs. command execution:
When running adb shell (no arguments), an interactive PTY-based shell is
spawned. The shell process runs as the shell user (UID 2000) on production
builds, or as root if adb root has been executed on a debuggable build.
When running adb shell <command>, the command is executed in a subprocess with
stdin/stdout/stderr captured. The shell protocol ensures clean separation of
output streams:
graph LR
subgraph "Host Side"
STDIN["stdin (terminal)"]
STDOUT["stdout"]
STDERR["stderr"]
end
subgraph "Shell Protocol"
MUX["Multiplexer"]
end
subgraph "Device Side"
SH_IN["stdin"]
SH_OUT["stdout"]
SH_ERR["stderr"]
EXIT["exit code"]
end
STDIN -->|"kIdStdin"| MUX
MUX -->|"kIdStdout"| STDOUT
MUX -->|"kIdStderr"| STDERR
MUX -->|"kIdExit"| STDOUT
MUX <--> SH_IN
MUX <--> SH_OUT
MUX <--> SH_ERR
MUX <--> EXIT
Window size propagation:
When the terminal window is resized during an interactive shell session, the
client sends a kIdWindowSizeChange packet containing the new dimensions as
an ASCII string. The daemon updates the PTY's winsize structure, causing the
shell process to receive a SIGWINCH signal.
39.5.3 File Transfer (adb push / adb pull)¶
Source: packages/modules/adb/client/file_sync_client.cpp, packages/modules/adb/daemon/file_sync_service.cpp
File transfer uses the sync protocol, defined in
packages/modules/adb/file_sync_protocol.h:
// Sync protocol message IDs
#define ID_LSTAT_V1 MKID('S', 'T', 'A', 'T')
#define ID_STAT_V2 MKID('S', 'T', 'A', '2')
#define ID_LIST_V1 MKID('L', 'I', 'S', 'T')
#define ID_LIST_V2 MKID('L', 'I', 'S', '2')
#define ID_SEND_V1 MKID('S', 'E', 'N', 'D')
#define ID_SEND_V2 MKID('S', 'N', 'D', '2')
#define ID_RECV_V1 MKID('R', 'E', 'C', 'V')
#define ID_RECV_V2 MKID('R', 'C', 'V', '2')
#define ID_DONE MKID('D', 'O', 'N', 'E')
#define ID_DATA MKID('D', 'A', 'T', 'A')
#define ID_OKAY MKID('O', 'K', 'A', 'Y')
#define ID_FAIL MKID('F', 'A', 'I', 'L')
#define ID_QUIT MKID('Q', 'U', 'I', 'T')
Push operation flow:
sequenceDiagram
participant Client as adb push
participant Daemon as adbd sync service
Client->>Daemon: OPEN "sync:"
Daemon->>Client: OKAY
Client->>Daemon: SEND_V2 (path, mode, flags)
loop For each chunk
Client->>Daemon: DATA (up to 64KB)
end
Client->>Daemon: DONE (mtime)
Daemon->>Client: OKAY
Client->>Daemon: QUIT
Sync v2 features:
- Compression: Brotli, LZ4, and Zstd compression are supported
- Dry-run mode: Test a push without actually writing files
- Extended stat: Full
struct statinformation (device, inode, uid, gid, atime, mtime, ctime)
The sync_data structure limits chunks to 64KB:
#define SYNC_DATA_MAX (64 * 1024)
struct __attribute__((packed)) sync_data {
uint32_t id;
uint32_t size;
}; // followed by `size` bytes of data.
39.5.4 Package Installation (adb install)¶
Source: packages/modules/adb/client/adb_install.cpp
adb install performs these steps:
- Push the APK to a temporary location on the device
- Invoke
pm installor use the streaming install protocol - Clean up the temporary file
For streaming installs (default on modern devices):
- Open a
exec:cmd packageservice - Stream the APK directly to the Package Manager
- No intermediate file on device storage is needed
Incremental installation (adb install --incremental) uses an even more
sophisticated approach where only required blocks of the APK are transferred
on demand, dramatically reducing install times for large apps.
39.5.5 Log Collection (adb logcat)¶
adb logcat opens a shell:logcat service on the device. The output is
streamed back in real time using the shell protocol. The logcat binary on the
device reads from the kernel's log buffers via /dev/log/ or the logd socket.
39.5.6 Port Forwarding (adb forward / adb reverse)¶
Source: packages/modules/adb/adb.h, packages/modules/adb/adb_listeners.cpp
Forward (adb forward tcp:8080 tcp:8080): Creates a listener on the host
that tunnels connections to the device.
Reverse (adb reverse tcp:8080 tcp:8080): Creates a listener on the device
that tunnels connections to the host.
graph LR
subgraph "Host"
HA["Host App<br/>localhost:8080"]
HS["ADB Server"]
end
subgraph "Device"
DA["Device App<br/>localhost:8080"]
DD["adbd"]
end
HA -->|"adb forward"| HS
HS -->|"USB/TCP"| DD
DD --> DA
DA -->|"adb reverse"| DD
DD -->|"USB/TCP"| HS
HS --> HA
Forward and reverse configurations are tracked per-transport in the
reverse_forwards_ map within atransport:
// Track remote addresses against local addresses
std::unordered_map<std::string, std::string> reverse_forwards_;
39.5.7 ABB: Android Binder Bridge¶
Source: packages/modules/adb/daemon/abb.cpp, packages/modules/adb/daemon/abb_service.cpp
ABB provides a direct Binder IPC path from adb commands to system services,
bypassing the shell. Commands like adb shell cmd package list packages
internally use ABB when the feature is supported:
adb shell cmd <service> <arguments>
|
v
abb_exec:<service> <arguments>
|
v
ServiceManager.getService(<service>)
|
v
Direct Binder call
This is significantly faster than spawning a shell process and invoking the
cmd binary.
39.5.8 JDWP Service¶
Source: packages/modules/adb/daemon/jdwp_service.cpp
The JDWP (Java Debug Wire Protocol) service enables Java debugger attachment.
When a debuggable app starts, its runtime registers with adbd's JDWP service.
The adb jdwp command lists all PIDs with active JDWP connections, and
adb forward tcp:PORT jdwp:PID creates a tunnel for debugger attachment.
39.6 MTP: Media Transfer Protocol¶
39.6.1 Overview¶
MTP (Media Transfer Protocol) is the standard protocol for transferring media files between Android devices and computers. Unlike USB Mass Storage (which exposes a raw block device), MTP provides object-level file access, allowing the device to maintain filesystem control and serve files to both the host computer and local applications simultaneously.
graph TD
subgraph "Host Computer"
MTP_HOST["MTP Initiator<br/>(Windows Explorer, Android File Transfer)"]
end
subgraph "Android Device"
subgraph "Java Layer"
MTP_SVC["MtpService<br/>(packages/services/Mtp/)"]
MTP_DB["MtpDatabase<br/>(MediaStore bridge)"]
end
subgraph "Native Layer"
MTP_SERVER["MtpServer<br/>(frameworks/av/media/mtp/)"]
MTP_FFS["MtpFfsHandle<br/>(FunctionFS I/O)"]
end
subgraph "Kernel"
FFS["FunctionFS<br/>(MTP gadget function)"]
USB_GADGET["USB Gadget Composite"]
end
end
MTP_HOST <-->|"USB bulk transfers"| USB_GADGET
USB_GADGET <--> FFS
FFS <--> MTP_FFS
MTP_FFS <--> MTP_SERVER
MTP_SERVER <-->|"JNI"| MTP_DB
MTP_DB <--> MTP_SVC
39.6.2 MTP Architecture¶
The MTP implementation spans three layers:
Native MTP Library (frameworks/av/media/mtp/):
MtpServer.cpp/h: Main MTP protocol engineMtpFfsHandle.cpp/h: FunctionFS transport (modern)MtpFfsCompatHandle.cpp/h: Compatibility FunctionFS transportMtpDevHandle.cpp/h: Legacy/dev/mtp_usbtransportMtpDataPacket.cpp/h: Data container serializationMtpRequestPacket.cpp/h: Command container parsingMtpResponsePacket.cpp/h: Response container constructionMtpEventPacket.cpp/h: Event notification packetsMtpStorage.cpp/h: Storage abstraction (maps to filesystem paths)MtpObjectInfo.cpp/h: Object metadataMtpProperty.cpp/h: MTP property descriptors
MTP Service (packages/services/Mtp/):
MtpService.java: Android Service that manages the MTP server lifecycleMtpDatabase.java: Bridge between MTP operations and MediaStoreMtpDocumentsProvider.java: Storage Access Framework integrationMtpReceiver.java: Broadcast receiver for USB state changesMtpManager.java: Host-side MTP device management
Framework Integration (frameworks/base/):
UsbDeviceManagerbinds toMtpServicewhen MTP function is activeMediaProvidersupplies file metadata toMtpDatabase
39.6.3 MTP Server Initialization and Run Loop¶
Source: frameworks/av/media/mtp/MtpServer.cpp
The MtpServer constructor selects the appropriate USB transport based on
FunctionFS availability:
// Transport selection in MtpServer constructor
bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
if (ffs_ok) {
bool aio_compat = android::base::GetBoolProperty(
"sys.usb.ffs.aio_compat", false);
mHandle = aio_compat
? new MtpFfsCompatHandle(controlFd)
: new MtpFfsHandle(controlFd);
} else {
mHandle = new MtpDevHandle(); // Legacy /dev/mtp_usb
}
Three transport implementations exist:
MtpFfsHandle: Modern FunctionFS with async I/O -- highest performanceMtpFfsCompatHandle: FunctionFS with compatibility mode for devices where native AIO has issuesMtpDevHandle: Legacy kernel MTP device node (/dev/mtp_usb)
The main server loop (MtpServer::run()) processes MTP transactions:
graph TD
START["start(mPtp)"] --> READ_REQ["Read request packet"]
READ_REQ -->|"Error (ECANCELED)"| READ_REQ
READ_REQ -->|"Error (other)"| CLEANUP
READ_REQ -->|"Success"| CHECK_DATA["Check if data-in operation"]
CHECK_DATA -->|"Data expected"| READ_DATA["Read data packet"]
CHECK_DATA -->|"No data"| HANDLE["handleRequest()"]
READ_DATA --> HANDLE
HANDLE -->|"Has response data"| WRITE_DATA["Write data packet"]
HANDLE -->|"No response data"| WRITE_RESP["Write response packet"]
WRITE_DATA --> WRITE_RESP
WRITE_RESP -->|"Error (ECANCELED)"| READ_REQ
WRITE_RESP -->|"Error (other)"| CLEANUP
WRITE_RESP -->|"Success"| READ_REQ
CLEANUP["Commit open edits<br/>Close handle"]
The run loop identifies data-in operations (host sending data to device):
bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
|| operation == MTP_OPERATION_SET_OBJECT_REFERENCES
|| operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
|| operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
When the server exits (due to USB disconnect or function change), it commits all pending edits to prevent data loss:
int count = mObjectEditList.size();
for (int i = 0; i < count; i++) {
ObjectEdit* edit = mObjectEditList[i];
commitEdit(edit);
delete edit;
}
mObjectEditList.clear();
mHandle->close();
39.6.4 Storage Management¶
The MtpServer manages multiple storage locations. On a typical Android device:
- Internal Storage (storage ID
0x00010001):/storage/emulated/<user>/ - SD Card (storage ID
0x00020001):/storage/<sdcard-uuid>/
Storage add/remove operations trigger MTP events to the host:
void MtpServer::addStorage(MtpStorage* storage) {
std::lock_guard<std::mutex> lg(mMutex);
mStorages.push_back(storage);
sendStoreAdded(storage->getStorageID());
}
void MtpServer::removeStorage(MtpStorage* storage) {
std::lock_guard<std::mutex> lg(mMutex);
auto iter = std::find(mStorages.begin(), mStorages.end(), storage);
if (iter != mStorages.end()) {
sendStoreRemoved(storage->getStorageID());
mStorages.erase(iter);
}
}
When a storage is queried with ID 0 (wildcard), the first storage is
returned. When queried with 0xFFFFFFFF, any storage matches. This follows
the MTP specification for aggregate operations across all storages.
39.6.5 MTP Protocol Details¶
MTP (Media Transfer Protocol) is a session-oriented protocol originally developed by Microsoft as an extension of PTP (Picture Transfer Protocol, also known as ISO 15740). Communication happens through three USB endpoints:
- Bulk OUT (host to device): Commands and data from initiator
- Bulk IN (device to host): Responses and data to initiator
- Interrupt IN (device to host): Asynchronous event notifications
Each MTP transaction uses container packets:
Container Format (12-byte header):
+--------+--------+--------+--------+
| Container Length (32-bit LE) |
+--------+--------+--------+--------+
|Container| Operation/Response |
| Type | Code |
+--------+--------+--------+--------+
| Transaction ID (32-bit LE) |
+--------+--------+--------+--------+
| Parameters / Data (variable) |
+--------+--------+--------+--------+
Container types from frameworks/av/media/mtp/mtp.h:
#define MTP_CONTAINER_TYPE_COMMAND 1
#define MTP_CONTAINER_TYPE_DATA 2
#define MTP_CONTAINER_TYPE_RESPONSE 3
#define MTP_CONTAINER_TYPE_EVENT 4
39.6.6 Supported MTP Operations¶
The MtpServer in AOSP supports the following operation codes (from
frameworks/av/media/mtp/MtpServer.cpp):
| Operation Code | Name | Description |
|---|---|---|
0x1001 |
GET_DEVICE_INFO |
Query device capabilities |
0x1002 |
OPEN_SESSION |
Start MTP session |
0x1003 |
CLOSE_SESSION |
End MTP session |
0x1004 |
GET_STORAGE_IDS |
List available storages |
0x1005 |
GET_STORAGE_INFO |
Query storage capacity/free space |
0x1006 |
GET_NUM_OBJECTS |
Count objects in storage |
0x1007 |
GET_OBJECT_HANDLES |
List object handles |
0x1008 |
GET_OBJECT_INFO |
Query object metadata |
0x1009 |
GET_OBJECT |
Download object data |
0x100A |
GET_THUMB |
Download thumbnail |
0x100B |
DELETE_OBJECT |
Delete an object |
0x100C |
SEND_OBJECT_INFO |
Create new object (metadata) |
0x100D |
SEND_OBJECT |
Upload object data |
0x1010 |
RESET_DEVICE |
Reset MTP state |
0x1014 |
GET_DEVICE_PROP_DESC |
Device property descriptor |
0x1015 |
GET_DEVICE_PROP_VALUE |
Read device property |
0x1016 |
SET_DEVICE_PROP_VALUE |
Write device property |
0x1019 |
MOVE_OBJECT |
Move object to new parent |
0x101A |
COPY_OBJECT |
Copy object |
0x101B |
GET_PARTIAL_OBJECT |
Range read |
0x9801 |
GET_OBJECT_PROPS_SUPPORTED |
List supported properties |
0x9802 |
GET_OBJECT_PROP_DESC |
Property descriptor |
0x9803 |
GET_OBJECT_PROP_VALUE |
Read object property |
0x9804 |
SET_OBJECT_PROP_VALUE |
Write object property |
0x9805 |
GET_OBJECT_PROP_LIST |
Bulk property read |
39.6.7 Android Extensions for Direct File I/O¶
Android extends the standard MTP protocol with custom operations for efficient direct file editing:
// From mtp.h -- Android extensions
#define MTP_OPERATION_GET_PARTIAL_OBJECT_64 0x95C1 // 64-bit offset read
#define MTP_OPERATION_SEND_PARTIAL_OBJECT 0x95C2 // Host-to-device write
#define MTP_OPERATION_TRUNCATE_OBJECT 0x95C3 // Truncate to 64-bit length
#define MTP_OPERATION_BEGIN_EDIT_OBJECT 0x95C4 // Begin edit session
#define MTP_OPERATION_END_EDIT_OBJECT 0x95C5 // Commit edit changes
These extensions enable applications like document editors to modify files in place without full download-modify-upload cycles:
sequenceDiagram
participant Host as MTP Host
participant Server as MtpServer
Host->>Server: BEGIN_EDIT_OBJECT(handle)
Server->>Server: Open file, create ObjectEdit
Server-->>Host: OK
Host->>Server: GET_PARTIAL_OBJECT_64(handle, offset, size)
Server-->>Host: DATA (file region)
Host->>Server: SEND_PARTIAL_OBJECT(handle, offset, size)
Host->>Server: DATA (modified region)
Server-->>Host: OK
Host->>Server: TRUNCATE_OBJECT(handle, new_size)
Server-->>Host: OK
Host->>Server: END_EDIT_OBJECT(handle)
Server->>Server: Commit changes, close ObjectEdit
Server-->>Host: OK
39.6.8 FunctionFS Transport¶
Source: frameworks/av/media/mtp/MtpFfsHandle.h
The MtpFfsHandle class implements the USB transport using Linux FunctionFS,
providing high-performance asynchronous I/O:
class MtpFfsHandle : public IMtpHandle {
protected:
android::base::unique_fd mControl; // Control endpoint (ep0)
android::base::unique_fd mBulkIn; // Bulk IN (device to host)
android::base::unique_fd mBulkOut; // Bulk OUT (host to device)
android::base::unique_fd mIntr; // Interrupt IN (events)
aio_context_t mCtx; // Linux AIO context
struct io_buffer mIobuf[NUM_IO_BUFS]; // Double-buffered I/O
// ...
};
The data header prepended to MTP data transfers:
struct mtp_data_header {
__le32 length; // Packet length including header
__le16 type; // Container type (2 = data)
__le16 command; // MTP command code
__le32 transaction_id; // Transaction ID
};
39.6.9 MTP Event Notification¶
The MTP server sends asynchronous events to the host through the interrupt endpoint:
// Supported events from MtpServer.cpp
static const MtpEventCode kSupportedEventCodes[] = {
MTP_EVENT_OBJECT_ADDED, // 0x4002 - New file created
MTP_EVENT_OBJECT_REMOVED, // 0x4003 - File deleted
MTP_EVENT_STORE_ADDED, // 0x4004 - Storage mounted
MTP_EVENT_STORE_REMOVED, // 0x4005 - Storage unmounted
MTP_EVENT_DEVICE_PROP_CHANGED,// 0x4006 - Device property changed
MTP_EVENT_OBJECT_INFO_CHANGED,// 0x4007 - Object metadata changed
};
When a file is added or removed on the device (e.g., by a camera app), the
MtpDatabase notifies the MtpServer, which sends the appropriate event to
the host. The host can then refresh its directory listing.
39.6.10 PTP Mode¶
PTP (Picture Transfer Protocol) is a subset of MTP focused on image transfer.
When PTP mode is selected instead of MTP, the MtpServer is initialized with
the ptp flag set to true:
MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp, ...)
: mDatabase(database),
mPtp(ptp), // true for PTP mode
// ...
In PTP mode, the server restricts:
- Object formats to image types (JPEG, TIFF, PNG, etc.)
- Operations to the standard PTP subset
- Properties to photo-relevant metadata
PTP mode is useful for connecting to photo kiosks and older software that does not support the full MTP extension set.
39.6.11 MTP Documents Provider¶
Source: packages/services/Mtp/src/com/android/mtp/MtpDocumentsProvider.java
When an Android device acts as an MTP host (accessing files on another MTP
device), the MtpDocumentsProvider integrates MTP devices into the Storage
Access Framework, allowing any SAF-compatible app to browse files on connected
MTP devices.
Key classes in the host-side MTP stack:
MtpDocumentsProvider: SAF provider implementationMtpManager: Manages MTP device connectionsMtpDatabase: Caches MTP object metadata locallyDocumentLoader: Handles background loading of directory contentsPipeManager: Manages transfer pipe for large files
39.7 USB Accessory Mode (AOA)¶
39.7.1 Android Open Accessory Protocol Overview¶
The Android Open Accessory (AOA) protocol allows external USB devices (accessories) to communicate with Android applications. Unlike standard USB host mode (where Android is the host), in accessory mode the external device is the USB host and the Android device is the peripheral.
This is particularly useful for:
- Car head units (Android Auto)
- Docking stations
- Game controllers
- Industrial equipment
- Musical instruments
39.7.2 AOA Handshake Protocol¶
sequenceDiagram
participant ACC as USB Accessory (Host)
participant DEV as Android Device (Peripheral)
Note over ACC,DEV: Device initially in normal USB mode
ACC->>DEV: GET_PROTOCOL (vendor request 51)
DEV->>ACC: Protocol version (1 or 2)
ACC->>DEV: SEND_STRING(0, manufacturer)
ACC->>DEV: SEND_STRING(1, model)
ACC->>DEV: SEND_STRING(2, description)
ACC->>DEV: SEND_STRING(3, version)
ACC->>DEV: SEND_STRING(4, URI)
ACC->>DEV: SEND_STRING(5, serial)
ACC->>DEV: START_ACCESSORY (vendor request 53)
Note over DEV: Device disconnects, re-enumerates<br/>with accessory VID/PID
DEV-->>ACC: Re-enumerate as accessory<br/>(VID=0x18D1, PID=0x2D00/0x2D01)
ACC->>DEV: Open bulk endpoints
ACC->>DEV: Application data exchange
39.7.3 Accessory Detection in UsbDeviceManager¶
Source: frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
The UsbUEventObserver monitors kernel UEvents for accessory handshake
progress:
// UEvent patterns for accessory protocol
private static final String ACCESSORY_START_MATCH =
"DEVPATH=/devices/virtual/misc/usb_accessory";
// In UsbUEventObserver.onUEvent():
String accessory = event.get("ACCESSORY");
if ("GETPROTOCOL".equals(accessory)) {
// Accessory sent GET_PROTOCOL control request
mHandler.setAccessoryUEventTime(SystemClock.elapsedRealtime());
resetAccessoryHandshakeTimeoutHandler();
} else if ("SENDSTRING".equals(accessory)) {
// Accessory sent string descriptor
mHandler.sendEmptyMessage(MSG_INCREASE_SENDSTRING_COUNT);
resetAccessoryHandshakeTimeoutHandler();
} else if ("START".equals(accessory)) {
// Accessory sent START_ACCESSORY
startAccessoryMode();
}
39.7.4 Accessory Mode Activation¶
When START_ACCESSORY is received, UsbDeviceManager switches the gadget
to accessory function:
private void startAccessoryMode() {
if (!mHasUsbAccessory) return;
mAccessoryStrings = nativeGetAccessoryStrings();
// Mandatory strings must be set
boolean enableAccessory = (mAccessoryStrings != null &&
mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
long functions = UsbManager.FUNCTION_NONE;
if (enableAccessory) {
functions |= UsbManager.FUNCTION_ACCESSORY;
}
if (functions != UsbManager.FUNCTION_NONE) {
// Set timeout for host to complete configuration
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MSG_ACCESSORY_MODE_ENTER_TIMEOUT),
ACCESSORY_REQUEST_TIMEOUT);
setCurrentFunctions(functions, operationId);
}
}
39.7.5 Userspace AOA Implementation¶
Modern AOSP includes a userspace AOA implementation as an alternative to the kernel-based accessory driver:
// From UsbDeviceManager constructor
mEnableAoaUserspaceImplementation =
android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()
&& deviceEnabledUserspaceAoa
&& nativeCheckAccessoryFfsDirectories();
When userspace AOA is enabled, accessory string descriptors are read from FunctionFS rather than the kernel driver:
if (mEnableAoaUserspaceImplementation) {
mAccessoryStrings = nativeGetAccessoryStringsFromFfs();
} else {
mAccessoryStrings = nativeGetAccessoryStrings();
}
39.7.6 AOA Version 2 (Audio)¶
AOAv2 adds audio streaming support. When an accessory requests audio, the
AUDIO_SOURCE gadget function is enabled alongside ACCESSORY:
// GadgetFunction bitmask values
ACCESSORY = 1 << 1; // AOA data
AUDIO_SOURCE = 1 << 6; // AOAv2 audio
The audio is presented to the host as a standard USB Audio Class device, allowing the accessory to receive audio output from the Android device without special drivers.
39.7.7 Application Integration¶
Applications register to receive USB accessory intents through their manifest:
<activity android:name=".MyAccessoryActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter"/>
</activity>
The filter XML specifies which accessories to match:
At runtime, the application uses UsbManager to open the accessory connection:
UsbManager usbManager = getSystemService(UsbManager.class);
UsbAccessory[] accessories = usbManager.getAccessoryList();
if (accessories != null) {
ParcelFileDescriptor fd = usbManager.openAccessory(accessories[0]);
FileInputStream input = new FileInputStream(fd.getFileDescriptor());
FileOutputStream output = new FileOutputStream(fd.getFileDescriptor());
// Read/write accessory data
}
39.8 USB Host Mode¶
39.8.1 Overview¶
In USB host mode, the Android device acts as a USB host, providing power and enumerating connected USB peripherals. This enables use of:
- USB keyboards and mice
- USB storage devices (flash drives)
- USB audio devices (DACs, headsets)
- USB cameras
- USB Ethernet adapters
- USB MIDI controllers
- Custom USB devices (with application-managed protocols)
39.8.2 UsbHostManager¶
Source: frameworks/base/services/usb/java/com/android/server/usb/UsbHostManager.java
UsbHostManager manages USB devices connected to the Android device in host
mode. It runs a native thread that monitors the USB bus:
public void systemReady() {
synchronized (mLock) {
Runnable runnable = this::monitorUsbHostBus;
new Thread(null, runnable, "UsbService host thread").start();
}
}
// Native methods
private native void monitorUsbHostBus();
private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
39.8.3 Device Enumeration¶
sequenceDiagram
participant Kernel as Linux USB Core
participant JNI as UsbHostManager JNI
participant UHM as UsbHostManager
participant Settings as UsbProfileGroupSettingsManager
participant App as Application
Kernel->>JNI: USB device connected
JNI->>UHM: usbDeviceAdded(address, class, subclass, descriptors)
UHM->>UHM: Parse USB descriptors
UHM->>UHM: Check deny lists
alt Device allowed
UHM->>UHM: Build UsbDevice object
UHM->>Settings: deviceAttached(newDevice)
Settings->>App: ACTION_USB_DEVICE_ATTACHED broadcast
else Device denied
UHM->>UHM: Log and ignore
end
Note over Kernel,App: Later, device removed
Kernel->>JNI: USB device disconnected
JNI->>UHM: usbDeviceRemoved(address)
UHM->>Settings: usbDeviceRemoved(device)
Settings->>App: ACTION_USB_DEVICE_DETACHED broadcast
39.8.4 Descriptor Parsing¶
When a USB device is connected, the raw descriptors are parsed by
UsbDescriptorParser to build an android.hardware.usb.UsbDevice object:
// From UsbHostManager.usbDeviceAdded()
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
logUsbDevice(parser); // Log VID:PID, manufacturer, product, serial
UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDeviceBuilder();
UsbDevice newDevice = newDeviceBuilder.build(serialNumberReader);
mDevices.put(deviceAddress, newDevice);
The parser examines USB descriptors to classify the device:
parser.hasAudioInterface()-- USB audio deviceparser.hasHIDInterface()-- HID device (keyboard, mouse)parser.hasStorageInterface()-- Mass storage deviceparser.isInputHeadset()/parser.isOutputHeadset()-- Audio headsetparser.isDock()-- Docking station
39.8.5 Deny Lists¶
UsbHostManager maintains two levels of deny lists:
1. Bus-level deny list: Configured via the device's resource overlay:
mHostDenyList = context.getResources().getStringArray(
com.android.internal.R.array.config_usbHostDenylist);
2. Class-level deny list: Blocks certain USB classes from application access:
private boolean isDenyListed(int clazz, int subClass) {
if (clazz == UsbConstants.USB_CLASS_HUB) return true;
return clazz == UsbConstants.USB_CLASS_HID
&& subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT;
}
39.8.6 USB Permissions¶
Source: frameworks/base/services/usb/java/com/android/server/usb/UsbPermissionManager.java
Access to USB devices requires explicit permission. The permission model works as follows:
graph TD
subgraph "Permission Granting"
MANIFEST["Manifest filter match<br/>(auto-grant)"]
DIALOG["User permission dialog<br/>(manual grant)"]
PRIV["Privileged system app<br/>(pre-granted)"]
end
subgraph "UsbPermissionManager"
UPERM2["UsbPermissionManager"]
UUPM["UsbUserPermissionManager<br/>(per-user)"]
end
MANIFEST --> UPERM2
DIALOG --> UPERM2
PRIV --> UPERM2
UPERM2 --> UUPM
Applications can request permission in two ways:
1. Intent filter matching (automatic):
<activity android:name=".UsbDeviceActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter"/>
</activity>
With a device filter:
2. Runtime permission request (programmatic):
UsbManager usbManager = getSystemService(UsbManager.class);
UsbDevice device = ...;
if (!usbManager.hasPermission(device)) {
PendingIntent permissionIntent = PendingIntent.getBroadcast(
this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, permissionIntent);
}
39.8.7 Opening USB Devices¶
Once permission is granted, applications communicate with USB devices through file descriptors:
UsbDeviceConnection connection = usbManager.openDevice(device);
// Claim an interface
connection.claimInterface(usbInterface, true);
// Bulk transfer
byte[] buffer = new byte[64];
int bytesRead = connection.bulkTransfer(endpoint, buffer, buffer.length, TIMEOUT);
// Control transfer
connection.controlTransfer(
UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
REQUEST_CODE, VALUE, INDEX, buffer, buffer.length, TIMEOUT);
Under the hood, UsbHostManager.openDevice() calls nativeOpenDevice() which
returns a ParcelFileDescriptor to the USB device node (e.g.,
/dev/bus/usb/001/003).
39.8.7.1 USB Transfer Types¶
The UsbDeviceConnection class supports all four USB transfer types:
| Transfer Type | Method | Max Size | Use Case |
|---|---|---|---|
| Control | controlTransfer() |
4KB per setup | Device configuration, vendor commands |
| Bulk | bulkTransfer() |
Variable | Data-heavy transfers (storage, printers) |
| Interrupt | bulkTransfer() on interrupt EP |
64B (FS) / 1024B (HS) | HID events, status polling |
| Isochronous | UsbRequest (async) |
1023B (FS) / 1024B (HS) | Audio/video streaming |
For asynchronous transfers, applications use UsbRequest:
UsbRequest request = new UsbRequest();
request.initialize(connection, endpoint);
ByteBuffer buffer = ByteBuffer.allocate(64);
request.queue(buffer, 64);
// Wait for completion
UsbRequest completed = connection.requestWait();
if (completed == request) {
// Process data in buffer
buffer.flip();
int bytesReceived = buffer.remaining();
}
39.8.7.2 USB Device Class Model¶
The UsbDevice object provides a hierarchical view of the USB device:
graph TD
DEV["UsbDevice<br/>VID:PID, class, serial"]
CFG1["UsbConfiguration 0<br/>attributes, maxPower"]
CFG2["UsbConfiguration 1"]
IF1["UsbInterface 0<br/>class, subclass, protocol"]
IF2["UsbInterface 1"]
EP1["UsbEndpoint 0<br/>IN, BULK, 512B"]
EP2["UsbEndpoint 1<br/>OUT, BULK, 512B"]
EP3["UsbEndpoint 2<br/>IN, INTERRUPT, 8B"]
DEV --> CFG1
DEV --> CFG2
CFG1 --> IF1
CFG1 --> IF2
IF1 --> EP1
IF1 --> EP2
IF2 --> EP3
Applications iterate through this hierarchy to find the interface and endpoints they need:
for (int i = 0; i < device.getConfigurationCount(); i++) {
UsbConfiguration config = device.getConfiguration(i);
for (int j = 0; j < config.getInterfaceCount(); j++) {
UsbInterface iface = config.getInterface(j);
if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC) {
for (int k = 0; k < iface.getEndpointCount(); k++) {
UsbEndpoint ep = iface.getEndpoint(k);
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
inEndpoint = ep;
} else {
outEndpoint = ep;
}
}
}
}
}
39.8.8 USB Audio Integration¶
The UsbAlsaManager (source:
frameworks/base/services/usb/java/com/android/server/usb/UsbAlsaManager.java)
handles USB audio devices:
graph LR
USB_AUDIO["USB Audio Device"] --> UHM2["UsbHostManager"]
UHM2 --> UALSA2["UsbAlsaManager"]
UALSA2 --> ALSA["ALSA Subsystem"]
UALSA2 --> MIDI2["UsbDirectMidiDevice"]
ALSA --> AUDIO_HAL["Audio HAL"]
AUDIO_HAL --> AUDIOFLINGER["AudioFlinger"]
When a USB audio device is connected:
UsbHostManagercallsmUsbAlsaManager.usbDeviceAdded()UsbAlsaManagercreates anUsbAlsaDevicerepresenting the ALSA sound card- The Audio HAL is notified of the new output/input device
- AudioFlinger routes audio to/from the USB device
39.8.9 USB MIDI¶
For USB MIDI devices, UsbHostManager creates UsbDirectMidiDevice instances:
if (parser.containsUniversalMidiDeviceEndpoint()) {
UsbDirectMidiDevice midiDevice = UsbDirectMidiDevice.create(
mContext, newDevice, parser, true, uniqueUsbDeviceIdentifier);
midiDevices.add(midiDevice);
// If also MIDI 1.0 compatible, create legacy device
if (parser.containsLegacyMidiDeviceEndpoint()) {
midiDevice = UsbDirectMidiDevice.create(
mContext, newDevice, parser, false, uniqueUsbDeviceIdentifier);
midiDevices.add(midiDevice);
}
}
A unique 3-digit code is generated to associate related MIDI devices:
private String generateNewUsbDeviceIdentifier() {
String code;
do {
code = "";
for (int i = 0; i < 3; i++) {
code += mRandom.nextInt(10);
}
} while (mMidiUniqueCodes.contains(code));
mMidiUniqueCodes.add(code);
return code;
}
39.8.10 Connection Tracking¶
UsbHostManager maintains a rolling log of connection/disconnection events
for debugging:
static final int MAX_CONNECT_RECORDS = 32;
class ConnectionRecord {
long mTimestamp;
String mDeviceAddress;
final int mMode; // CONNECT, CONNECT_BADPARSE, CONNECT_BADDEVICE, DISCONNECT
final byte[] mDescriptors;
}
These records are accessible through dumpsys usb and include raw USB
descriptors for detailed analysis.
39.9 Try It: Hands-On Experiments¶
39.9.1 Explore USB State Machine¶
Monitor USB state changes in real time:
# Watch USB state changes via logcat
adb logcat -s UsbDeviceManager:* UsbService:*
# Check current USB configuration
adb shell getprop sys.usb.config
adb shell getprop sys.usb.state
adb shell getprop sys.usb.controller
# Check persistent USB config
adb shell getprop persist.sys.usb.config
39.9.2 Switch USB Functions¶
# Switch to MTP mode
adb shell svc usb setFunctions mtp
# Switch to PTP mode
adb shell svc usb setFunctions ptp
# Switch to RNDIS (tethering)
adb shell svc usb setFunctions rndis
# Switch to MIDI mode
adb shell svc usb setFunctions midi
# Check current functions
adb shell svc usb getFunctions
# Reset USB gadget
adb shell svc usb resetUsbGadget
39.9.3 Inspect USB HAL State¶
# Dump USB service state
adb shell dumpsys usb
# Check USB port status
adb shell dumpsys usb | grep -A 20 "USB Port State"
# Check HAL version
adb shell dumpsys usb | grep "hal version"
# List USB gadget HAL
adb shell service list | grep usb
39.9.4 ADB Protocol Exploration¶
# Check ADB version and protocol
adb version
# List connected devices with details
adb devices -l
# Check device features
adb shell getprop ro.adb.secure
adb shell getprop service.adb.root
adb shell getprop ro.debuggable
# View ADB authentication keys
adb shell ls -la /data/misc/adb/
# Enable wireless ADB
adb tcpip 5555
adb connect <device-ip>:5555
# Check ADB transport speed
adb shell cat /config/usb_gadget/g1/UDC
39.9.5 Test File Transfer Performance¶
# Create a test file
dd if=/dev/urandom of=/tmp/testfile bs=1M count=100
# Push with timing
time adb push /tmp/testfile /data/local/tmp/
# Pull with timing
time adb pull /data/local/tmp/testfile /tmp/pulled_file
# Compare transfer speeds
# USB 2.0 HS: ~35-40 MB/s
# USB 3.x: ~100+ MB/s (device dependent)
39.9.6 Explore MTP from Device Side¶
# Check MTP server status
adb shell dumpsys usb | grep -i mtp
# Monitor MTP operations
adb logcat -s MtpServer:* MtpService:*
# List MTP storage IDs
adb shell dumpsys media.mtp
# Check FunctionFS endpoints for MTP
adb shell ls -la /dev/usb-ffs/mtp/
39.9.7 USB Host Mode Exploration¶
# List connected USB devices (host mode)
adb shell cat /proc/bus/usb/devices 2>/dev/null || \
adb shell lsusb 2>/dev/null || \
adb shell "for f in /sys/bus/usb/devices/*/product; do \
echo $(dirname $f): $(cat $f 2>/dev/null); done"
# Check USB host deny list
adb shell dumpsys usb | grep -A 5 "deny"
# Monitor USB host events
adb logcat -s UsbHostManager:*
# Examine USB descriptors of connected device
adb shell "dumpsys usb -dump-raw"
39.9.8 Build and Test USB HAL Changes¶
# Build the default USB HAL
cd $AOSP_ROOT # Navigate to the AOSP source tree
source build/envsetup.sh
lunch <target>
# Build USB HAL
m android.hardware.usb-service
# Build USB Gadget HAL
m android.hardware.usb.gadget-service
# Run USB VTS tests
atest VtsHalUsbV1_0TargetTest
atest VtsHalUsbGadgetV1_0TargetTest
39.9.9 ADB Over WiFi Pairing¶
# On the device: Enable wireless debugging in Developer Options
# On the host: Pair with the device
adb pair <device-ip>:<pairing-port>
# Enter the 6-digit pairing code shown on device
# Connect after pairing
adb connect <device-ip>:<connection-port>
# Verify connection
adb devices -l
39.9.10 Port Forwarding Experiment¶
# Forward local port to device port
adb forward tcp:8080 tcp:8080
# Reverse: forward device port to host port
adb reverse tcp:3000 tcp:3000
# List all forwards
adb forward --list
adb reverse --list
# Remove forwards
adb forward --remove tcp:8080
adb reverse --remove-all
39.9.11 Investigate USB Accessory Mode¶
# Check accessory support
adb shell getprop ro.usb.ffs.ready
adb shell ls -la /dev/usb_accessory 2>/dev/null
# Monitor accessory events
adb logcat -s UsbDeviceManager:* | grep -i accessory
# Check AOA userspace implementation status
adb shell getprop ro.usb.userspace.aoa.enabled
39.9.12 Trace USB Stack with ftrace¶
# Enable USB tracing (requires root)
adb root
adb shell "echo 1 > /sys/kernel/debug/tracing/events/gadget/enable"
adb shell "echo 1 > /sys/kernel/debug/tracing/events/usb/enable"
# Plug/unplug USB cable, then read trace
adb shell cat /sys/kernel/debug/tracing/trace
# Disable tracing
adb shell "echo 0 > /sys/kernel/debug/tracing/events/gadget/enable"
adb shell "echo 0 > /sys/kernel/debug/tracing/events/usb/enable"
39.9.13 Dump ADB Protocol Traffic¶
# Set ADB trace categories
export ADB_TRACE=all # or: usb, transport, adb, packets
# Run adb with tracing enabled
ADB_TRACE=packets adb shell echo hello
# On device, enable adbd tracing
adb shell setprop persist.adb.trace_mask 0xffff
adb shell stop adbd && adb shell start adbd
39.9.14 Explore ConfigFS Gadget Configuration¶
On devices with configfs gadget support, you can inspect the USB gadget configuration directly:
# View the gadget configuration tree
adb shell ls -la /config/usb_gadget/
# Examine the primary gadget
adb shell ls -la /config/usb_gadget/g1/
# View gadget strings (manufacturer, product, serial)
adb shell cat /config/usb_gadget/g1/strings/0x409/manufacturer
adb shell cat /config/usb_gadget/g1/strings/0x409/product
adb shell cat /config/usb_gadget/g1/strings/0x409/serialnumber
# View VID/PID
adb shell cat /config/usb_gadget/g1/idVendor
adb shell cat /config/usb_gadget/g1/idProduct
# View active configuration
adb shell ls /config/usb_gadget/g1/configs/b.1/
adb shell cat /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration
# View active functions (symlinks)
adb shell ls -la /config/usb_gadget/g1/configs/b.1/ | grep "^l"
# View available functions
adb shell ls /config/usb_gadget/g1/functions/
# View the UDC (USB Device Controller)
adb shell cat /config/usb_gadget/g1/UDC
39.9.15 Monitor USB Type-C Port Status¶
# View Type-C port information
adb shell dumpsys usb | grep -A 30 "USB Port State"
# Monitor Type-C sysfs
adb shell ls /sys/class/typec/
adb shell cat /sys/class/typec/port0/data_role 2>/dev/null
adb shell cat /sys/class/typec/port0/power_role 2>/dev/null
adb shell cat /sys/class/typec/port0/port_type 2>/dev/null
# Check USB Power Delivery status
adb shell cat /sys/class/typec/port0/power_operation_mode 2>/dev/null
# Watch for UEvents (requires root)
adb root
adb shell udevadm monitor --kernel --subsystem-match=typec 2>/dev/null || \
adb shell "cat /dev/uevent_monitor 2>/dev/null" || \
echo "Use logcat to monitor UEvents"
39.9.16 Benchmark USB Data Throughput¶
# Test raw ADB transfer speed
dd if=/dev/zero bs=1M count=256 > /tmp/zero_256m
# Push benchmark
echo "Push benchmark:"
time adb push /tmp/zero_256m /data/local/tmp/benchmark
# Pull benchmark
echo "Pull benchmark:"
time adb pull /data/local/tmp/benchmark /tmp/benchmark_pull
# Clean up
adb shell rm /data/local/tmp/benchmark
rm /tmp/zero_256m /tmp/benchmark_pull
# Check USB speed from device perspective
adb shell dumpsys usb | grep -i speed
adb shell cat /sys/class/udc/*/current_speed 2>/dev/null
39.9.17 Explore ADB Key Management¶
# View authorized keys on device
adb shell cat /data/misc/adb/adb_keys
# View your ADB public key on host
cat ~/.android/adbkey.pub
# View the RSA key fingerprint
openssl rsa -in ~/.android/adbkey -pubout 2>/dev/null | \
openssl md5 -c
# Revoke all USB debugging authorizations (on device)
adb shell settings put global development_settings_enabled 0
# Or via Settings > Developer Options > Revoke USB debugging authorizations
39.9.18 Write a Simple USB Host Application¶
Create a minimal application that enumerates USB devices:
// USB enumeration activity
public class UsbEnumerator extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UsbManager usbManager = getSystemService(UsbManager.class);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
for (UsbDevice device : deviceList.values()) {
Log.i("USB", String.format("Device: %s", device.getDeviceName()));
Log.i("USB", String.format(" VID:PID = %04x:%04x",
device.getVendorId(), device.getProductId()));
Log.i("USB", String.format(" Manufacturer: %s",
device.getManufacturerName()));
Log.i("USB", String.format(" Product: %s",
device.getProductName()));
Log.i("USB", String.format(" Class: 0x%02x Subclass: 0x%02x",
device.getDeviceClass(), device.getDeviceSubclass()));
for (int i = 0; i < device.getConfigurationCount(); i++) {
UsbConfiguration config = device.getConfiguration(i);
Log.i("USB", String.format(" Config %d: %d interfaces",
i, config.getInterfaceCount()));
for (int j = 0; j < config.getInterfaceCount(); j++) {
UsbInterface iface = config.getInterface(j);
Log.i("USB", String.format(
" Interface %d: class=0x%02x endpoints=%d",
j, iface.getInterfaceClass(),
iface.getEndpointCount()));
}
}
}
}
}
39.9.19 Debug USB Connection Issues¶
Common USB debugging techniques:
# Check if USB is properly initialized
adb shell getprop sys.usb.state
adb shell getprop sys.usb.config
adb shell getprop init.svc.adbd
# Verify FunctionFS is available
adb shell ls -la /dev/usb-ffs/
# Check kernel USB messages
adb shell dmesg | grep -i usb | tail -30
# View USB controller information
adb shell cat /sys/class/udc/*/state 2>/dev/null
adb shell cat /sys/class/udc/*/device/uevent 2>/dev/null
# Reset USB gadget (if functions are stuck)
adb shell svc usb resetUsbGadget
# Force ADB restart
adb kill-server
adb start-server
adb devices
39.9.20 Inspect MTP Object Tree¶
# Use Android's mtp-send/receive tools (if available)
# Or monitor MTP operations via logcat:
adb logcat -s MtpServer:V MtpDatabase:V MtpService:V
# In another terminal, connect the device as MTP to a computer
# and browse files -- watch the MTP operations in logcat
# Common MTP operation codes to watch for:
# 0x1001 = GET_DEVICE_INFO
# 0x1002 = OPEN_SESSION
# 0x1007 = GET_OBJECT_HANDLES
# 0x1008 = GET_OBJECT_INFO
# 0x1009 = GET_OBJECT (file download)
# 0x100D = SEND_OBJECT (file upload)
# 0x100B = DELETE_OBJECT
39.10 Internal Details: ConfigFS and the Linux USB Gadget Framework¶
39.10.1 ConfigFS Gadget Architecture¶
Modern Android devices use Linux's ConfigFS-based USB gadget framework to
manage composite USB device configurations. This replaces the older
android_usb driver and provides a more flexible, user-space-configurable
approach.
graph TD
subgraph "User Space"
HAL["IUsbGadget HAL"]
INIT["init (property triggers)"]
end
subgraph "ConfigFS (/config/usb_gadget/)"
G1["g1/ (gadget instance)"]
STRINGS["strings/0x409/<br/>manufacturer, product, serial"]
CONFIGS["configs/b.1/<br/>configuration"]
FUNCS["functions/<br/>ffs.adb, ffs.mtp, ...]"]
UDC["UDC (controller binding)"]
end
subgraph "FunctionFS"
FFS_ADB["/dev/usb-ffs/adb/"]
FFS_MTP["/dev/usb-ffs/mtp/"]
end
subgraph "Kernel USB Stack"
COMPOSITE["USB Composite Driver"]
UDC_DRIVER["UDC Hardware Driver"]
end
HAL --> G1
INIT --> G1
G1 --> STRINGS
G1 --> CONFIGS
G1 --> FUNCS
G1 --> UDC
FUNCS --> FFS_ADB
FUNCS --> FFS_MTP
UDC --> COMPOSITE
COMPOSITE --> UDC_DRIVER
39.10.2 Gadget Configuration Process¶
When the HAL receives a setCurrentUsbFunctions() call, the typical ConfigFS
manipulation sequence is:
1. Write "" to UDC # Unbind from controller
2. Unlink functions from configs/b.1/ # Remove current functions
3. Create/configure new functions # e.g., mkdir functions/ffs.mtp
4. Link functions to configs/b.1/ # symlink functions/ffs.mtp -> configs/b.1/f1
5. Write controller name to UDC # Bind to controller, trigger enumeration
This sequence causes a USB disconnect/reconnect cycle visible to the host.
39.10.3 FunctionFS Endpoint Architecture¶
Each FunctionFS instance creates a filesystem that user-space daemons use to implement USB functions:
/dev/usb-ffs/adb/
ep0 # Control endpoint (descriptors, events)
ep1 # Bulk OUT (host to device)
ep2 # Bulk IN (device to host)
/dev/usb-ffs/mtp/
ep0 # Control endpoint
ep1 # Bulk OUT
ep2 # Bulk IN
ep3 # Interrupt IN (events)
The user-space daemon (e.g., adbd or MTP server):
- Opens
ep0and writes USB descriptors (device, configuration, interface, endpoint descriptors) - Reads
ep0for control events (BIND, UNBIND, ENABLE, DISABLE, SETUP) - Opens
ep1,ep2, etc. for data transfer - Performs read/write operations on data endpoints
39.10.4 Composite Device Descriptors¶
When multiple functions are active (e.g., MTP + ADB), the gadget presents itself as a USB composite device:
USB Device Descriptor:
idVendor: 0x18D1 (Google Inc.)
idProduct: 0x4EE2 (MTP + ADB)
USB Configuration Descriptor:
bNumInterfaces: 3
Interface 0: MTP
bInterfaceClass: 0xFF (Vendor Specific)
bInterfaceSubClass: 0xFF
bInterfaceProtocol: 0x00
Endpoint: Bulk IN
Endpoint: Bulk OUT
Endpoint: Interrupt IN
Interface 1: ADB
bInterfaceClass: 0xFF (Vendor Specific)
bInterfaceSubClass: 0x42
bInterfaceProtocol: 0x01
Endpoint: Bulk IN
Endpoint: Bulk OUT
The VID:PID pair changes based on the active function combination:
| Functions | PID | Description |
|---|---|---|
| MTP | 0x4EE1 |
MTP only |
| MTP + ADB | 0x4EE2 |
MTP with debugging |
| PTP | 0x4EE5 |
PTP only |
| PTP + ADB | 0x4EE6 |
PTP with debugging |
| RNDIS | 0x4EE3 |
USB tethering |
| RNDIS + ADB | 0x4EE4 |
Tethering with debugging |
| Accessory | 0x2D00 |
AOA accessory |
| Accessory + ADB | 0x2D01 |
AOA with debugging |
| MIDI | 0x4EE8 |
MIDI only |
| MIDI + ADB | 0x4EE9 |
MIDI with debugging |
| Charging | 0x4EE0 |
No data function |
39.10.5 USB Speed Negotiation¶
The USB connection speed is determined during physical layer negotiation and
reported through the IUsbGadget HAL:
@VintfStability
parcelable UsbSpeed {
const int UNKNOWN = -1;
const int USB20 = 0; // 480 Mbps
const int USB30 = 1; // 5 Gbps
const int USB31 = 2; // 10 Gbps
const int USB32 = 3; // 20 Gbps
const int USB40 = 4; // 40 Gbps
}
The negotiated speed affects maximum transfer sizes and throughput. ADB file transfer performance is typically:
- USB 2.0 High Speed: 30-40 MB/s effective
- USB 3.0 SuperSpeed: 100-200 MB/s effective
- USB 3.1/3.2: Limited by device storage speed
39.10.6 Contaminant Detection¶
Modern USB-C ports include contaminant (moisture/debris) detection. When contaminant is detected:
- The HAL reports
ContaminantDetectionStatus.DETECTED UsbPortManagerposts a notification warning the user- USB data may be disabled to prevent electrical damage
- The port continues charging at reduced power
- When contaminant clears, normal operation resumes
stateDiagram-v2
[*] --> Clean: No contaminant
Clean --> Detected: Moisture/debris sensed
Detected --> Clean: Contaminant cleared
Detected --> Disabled: USB data disabled
state Clean {
[*] --> Normal: Full USB operation
}
state Detected {
[*] --> Warning: Notification shown
Warning --> PowerOnly: Data disabled, charging reduced
}
Disabled --> Clean: User action / dry out
Summary¶
This chapter traced the complete USB, ADB, and MTP stack through AOSP:
USB Framework (Section 44.1): The UsbService coordinates USB
operations through specialized sub-managers. UsbManager provides the public
API, while the service delegates to UsbDeviceManager (gadget mode),
UsbHostManager (host mode), and UsbPortManager (Type-C ports).
UsbDeviceManager (Section 44.2): A sophisticated message-based state machine manages USB gadget function switching. It coordinates screen lock state, user preferences, kernel UEvents, and the gadget HAL, with careful debouncing to handle transient disconnect/reconnect events during function changes.
USB HAL (Section 44.3): Two AIDL interfaces -- IUsb (port management) and
IUsbGadget (gadget configuration) -- abstract vendor-specific USB hardware.
The HAL reports comprehensive port status including Type-C role, contaminant
detection, compliance warnings, and DisplayPort Alt Mode.
ADB Architecture (Section 44.4): The three-component ADB architecture (client, server, daemon) communicates through a simple message protocol over USB or TCP. RSA-based authentication secures connections, and feature negotiation enables protocol evolution.
ADB Commands (Section 44.5): Shell v2 protocol multiplexes stdin/stdout/ stderr. File sync v2 supports compression (Brotli, LZ4, Zstd). ABB provides fast Binder-based service access. Port forwarding enables bidirectional tunneling.
MTP Service (Section 44.6): The MTP stack spans native code
(frameworks/av/media/mtp/) and Java services (packages/services/Mtp/).
Android extends standard MTP with direct file I/O operations and uses
FunctionFS for high-performance USB transport.
USB Accessory Mode (Section 44.7): The AOA protocol enables external USB hosts to communicate with Android applications through a defined handshake sequence. AOAv2 adds audio streaming. A new userspace AOA implementation provides flexibility beyond the kernel driver.
USB Host Mode (Section 44.8): UsbHostManager monitors the USB bus via JNI
native code, parsing device descriptors and maintaining deny lists. The
permission model requires explicit user consent for application access to USB
devices.
Key Source Paths Reference¶
| Component | Path |
|---|---|
| USB public API | frameworks/base/core/java/android/hardware/usb/ |
| USB system service | frameworks/base/services/usb/java/com/android/server/usb/ |
| USB HAL (AIDL) | hardware/interfaces/usb/aidl/ |
| USB Gadget HAL | hardware/interfaces/usb/gadget/aidl/ |
| ADB module | packages/modules/adb/ |
| ADB daemon | packages/modules/adb/daemon/ |
| ADB client | packages/modules/adb/client/ |
| MTP native library | frameworks/av/media/mtp/ |
| MTP service | packages/services/Mtp/ |