Android USB/MTP相關實現
前面轉發了篇部落格介紹了MTP, 偏重於上層,已經很清楚了。這篇側重於底層,按照一定的流程講。
1. 程式碼位置
packages/providers/MediaProvider/src/com/android/providers/media/MtpReceiver.java
packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java
packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
frameworks/base/media/java/android/mtp/MtpServer.java
frameworks/base/media/java/android/mtp/MtpDatabase.java
frameworks/base/media/java/android/mtp/MtpStorage.java
frameworks/base/media/java/android/mtp/MtpPropertyGroup.java
frameworks/base/media/java/android/mtp/MtpPropertyList.java
frameworks/base/media/java/android/mtp/MtpConstants.java
frameworks/base/media/jni/android_mtp_MtpServer.cpp
frameworks/base/media/jni/android_mtp_MtpDatabase.cpp
frameworks/av/media/mtp/MtpServer.h
frameworks/av/media/mtp/MtpServer.cpp
frameworks/av/media/mtp/MtpDatabase.h
frameworks/base/services/java/com/android/server/usb/UsbDeviceManager.java (UsbManager, UsbService)
kernel/drivers/usb/* (主要是android.c, f_mtp.c)
2. 在Settings設定mtp後,程式碼執行
Usbanager.SetCurrentFunction()
->UsbService.SetCurrentFunction()
->UsbDeviceManager.setCurrentFunctions()
-> mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS)
->setEnabledFunctions(functions, makeDefault);
->SystemProperties.set("persist.sys.usb.config", functions);
此時會呼叫到init.usb.rc執行相應的程式碼
如果直接開機,開機時會在設定persist.sys.usb.config/sys.usb.config時執行init.usb.rc中程式碼(沒有經過framework及以上程式碼)。
write /sys/class/android_usb/android0/enable 0/1
以上程式碼對應執行enable_store (android.c)
enable_store
1)enabled
f->enable(f_holder->f);
adb_android_function_enable
android_disable
usb_ep_dequeue
usb_remove_config
android_enable(dev);
usb_add_config
usb_gadget_connect
2)disabled
android_disable(dev);
usb_ep_dequeue
usb_remove_config
f->disable(f_holder->f)
adb_android_function_disable
usb_add_config(android_bind_config) composite.c
bind()
android_bind_config()
android_bind_enabled_functions()
f->bind_config()
mtp_function_bind_config(mtp)
adb_function_bind_config(adb)
-> usb_add_function()
usb_remove_config()
reset_config(cdev);
unbind_config(cdev, config);
f->unbind(config, f);
****_function_unbind_config()
config->unbind(config);
write /sys/class/android_usb/android0/functions mtp
以上程式碼對應執行functions_store (android.c)
functions_store()
-> android_enable_function()
-> list_add_tail
3. 如果開機後,連上USB線,首先執行chargr檢測,然後是列舉過程 (以高通某晶片為例),這小節講充電器檢測
kernel\drivers\power\qpnp-charger.c
rc = devm_request_irq(chip->dev, chip->usbin_valid.irq,
qpnp_chg_usb_usbin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"usbin-valid", chip);
qpnp_chg_usb_usbin_valid_irq_handler()中斷處理函式,檢測USB插入拔出
在連USB開機的情況下,這個處理函式會在qpnp_charger_probe()呼叫。
首先是電源恢復工作,
power_supply_set_present()
->msm_otg_set_vbus_state(POWER_SUPPLY_PROP_PRESENT)
->msm_otg_sm_work()
->pm_runtime_resume()
->msm_otg_runtime_resume()
->msm_otg_resume()
此時會看到log "USB exited from low power mode"
開始充電器檢測工作
主要函式式msm_chg_detect_work() in msm_otg.c
通常USB線的檢測狀態變化
USB_CHG_STATE_UNDEFINED->USB_CHG_STATE_WAIT_FOR_DCD(迴圈幾次)->USB_CHG_STATE_DCD_DONE
USB線的檢測結果是USB_SDP_CHARGER,
此時會設定otg->phy->state=b_peripheral, 並設定current=100mA
4. 列舉過程
4.1 中斷
ci13xxx_msm.c
ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "usb resume", NULL);
ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
msm_udc_irq()直接呼叫udc_irq(),處理PM and tr complete
isr_reset_handler/isr_suspend_handler/isr_resume_handler/isr_tr_complete_handler
msm_otg.c
Vbus檢測中斷
ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
"msm_otg", motg);
msm_otg_irq()->queue_work(system_nrt_wq, &motg->sm_work);->msm_otg_sm_work()
插OTG 線後中斷
msm_pmic_id_irq(), ID pin
4.2 呼叫過程
ci13xxx_udc.c
isr_reset_handler/isr_suspend_handler/isr_resume_handler/isr_tr_complete_handler
msm_otg_sm_work() in msm_otg.c
msm_chg_detect_work(b_idle b_sess_vld USB_SDP_CHARGER)
msm_otg_start_peripheral(otg, 1); "gadget on"
setup_gpio (.setup_gpio = isp1763_setup_gpio)
usb_gadget_vbus_connect
ci13xxx_vbus_session "vbus online" ci13xxx_udc.c
hw_device_reset
notify_event(CI13XXX_CONTROLLER_RESET_EVENT)
hw_device_state
notify_event(CI13XXX_CONTROLLER_CONNECT_EVENT);
msm_udc_irq kernel/drivers/usb/gadget/ci13xxx_msm.c ( request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name...)
udc_irq
isr_suspend_handler ci13xxx_udc.c
udc->driver->suspend(&udc->gadget);
notify_event(CI13XXX_CONTROLLER_SUSPEND_EVENT);
usb_phy_set_suspend(1)
suspended=1
isr_reset_handler ci13xxx_udc.c
notify_event(CI13XXX_CONTROLLER_RESUME_EVENT);
usb_phy_set_suspend(0)
udc->driver->resume(&udc->gadget);
suspended=0
usb_phy_set_power(udc->transceiver, 100);
set_power() otg.h
msm_otg_set_power msm_otg.c
msm_otg_notify_charger(motg, mA); msm_otg.c
msm_otg_notify_chg_type msm_otg.c
power_supply_set_supply_type power/power_supply_core.c
set_property(POWER_SUPPLY_PROP_TYPE)
otg_power_set_property_usb(POWER_SUPPLY_PROP_TYPE)
msm_otg_notify_power_supply msm_otg.c
power_supply_set_online(psy, true))
power_supply_set_current_limit(100mA)
_gadget_stop_activity ci13xxx_udc.c
android_disconnect
composite_disconnect
schedule_work()->android_work "android_work: did not send uevent (0 0 (null))"
hw_usb_reset();
isr_resume_handler
notify_event(CI13XXX_CONTROLLER_RESUME_EVENT)
usb_phy_set_suspend(0);
udc->driver->resume(&udc->gadget);
isr_tr_complete_handler ci13xxx_udc.c
driver->setup
android_setup android.c
f->ctrlrequest(f, cdev, c);
mtp_function_ctrlrequest()
composite_setup(USB_REQ_GET_DESCRIPTOR USB_DT_DEVICE) composite.c
schedule_work() ->android_work "android_work: sent uevent USB_STATE=CONNECTED"
isr_reset_handler
...
_gadget_stop_activity
android_disconnect
composite_disconnect
schedule_work()->android_work "android_work: sent uevent USB_STATE=DISCONNECTED"
isr_resume_handler
...
isr_tr_complete_handler USB_REQ_SET_ADDRESS 1
isr_tr_complete_handler driver->setup
android_setup android.c
composite_setup(USB_REQ_GET_DESCRIPTOR USB_DT_DEVICE) composite.c
schedule_work()->android_work "android_work: sent uevent USB_STATE=CONNECTED"
isr_tr_complete_handler driver->setup
android_setup
composite_setup USB_REQ_GET_DESCRIPTOR USB_DT_CONFIG
isr_tr_complete_handler driver->setup (USB_DT_STRING 3 times, vary)
android_setup
composite_setup USB_REQ_GET_DESCRIPTOR USB_DT_STRING
isr_tr_complete_handler driver->setup
android_setup android.c
composite_setup(USB_REQ_GET_DESCRIPTOR USB_DT_DEVICE) composite.c
isr_tr_complete_handler driver->setup
android_setup
composite_setup USB_REQ_GET_DESCRIPTOR USB_DT_CONFIG
isr_tr_complete_handler USB_REQ_SET_CONFIGURATION 1
isr_tr_complete_handler driver->setup
android_setup
composite_setup USB_REQ_SET_CONFIGURATION composite.c
set_config
set_alt
mtp_function_set_alt
adb_function_set_alt
usb_gadget_vbus_draw()
vbus_draw()
ci13xxx_vbus_draw ci13xxx_udc.c
usb_phy_set_power
set_power
msm_otg_set_power
msm_otg_notify_charger(motg, mA); "usb: Avail curr from USB = 500"
msm_otg_notify_chg_type
power_supply_set_supply_type
msm_otg_notify_power_supply
...
isr_tr_complete_handler driver->setup
android_setup
composite_setup USB_REQ_GET_DESCRIPTOR USB_DT_STRING
schedule_work()->android_work "android_work: sent uevent USB_STATE=CONFIGURED"
4.3 判讀HS, FS
ci13xxx_udc.c
udc_probe()
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.max_speed = USB_SPEED_HIGH; //最大速度
isr_resume_handler()
udc->gadget.speed = hw_port_is_high_speed() ? USB_SPEED_HIGH : USB_SPEED_FULL;
HS/FS是通過函式hw_port_is_high_speed()得到
4.4 判斷Host/Device
msm_otg_start_peripheral(on=1)
這裡通過判斷是SDP_CHARGER,然後設成peripheral(device).
qpnp_chg_usb_usbin_valid_irq_handler: qpnp_chg_usb_usbin_valid_irq_handler usbin-valid triggered: 1 host_mode: 0
上面就可以打印出host_mode, 是通過下面函式得到
host_mode = qpnp_chg_is_otg_en_set(chip);
接OTG線後,可以通過如下中斷處理函式看出
msm_pmic_id_irq(), 主要處理函式msm_pmic_id_status_w()
也可以通過函式得到msm_otg_read_pmic_id_state()
PMIC: ID clear host
PMIC: ID set device
5. 下面才是MTP的單獨部分
5.1 start MTP server
android_work()傳送uevent(USB_STATE=CONFIGURED)給上層
packages/providers/MediaProvider/src/com/android/providers/media/MtpReceiver.java
handleUsbState()
intent = new Intent(context, MtpService.class);
context.startService(intent);
packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java
onStartCommand
manageServiceLocked() MtpService.java "starting MTP server in MTP mode"
mServer = new MtpServer(mDatabase, mPtpMode);
MtpServer(MtpDatabase database, boolean usePtp) frameworks/base/media/java/android/mtp/MtpServer.java
mServer.start();
frameworks/base/media/jni/android_mtp_MtpServer.cpp
native_setup
android_mtp_MtpServer_setup
int fd = open("/dev/mtp_usb", O_RDWR);
mtp_open() f_mtp.c
MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase),..)
packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java
mServer.start();
run() frameworks/base/media/java/android/mtp/MtpServer.java
native_run frameworks/base/media/jni/android_mtp_MtpServer.cpp
android_mtp_MtpServer_run
server->run();
MtpServer::run() frameworks/av/media/mtp/MtpServer.cpp
5.2 主要處理函式
frameworks/av/media/mtp/MtpServer.cpp
MtpServer::run()
infinite loop; read request; send data/response (write)
Read part
mRequest.read(fd);
MtpRequestPacket::read() (MtpRequestPacket mRequest;)
::read(fd, mBuffer, mBufferSize);
mtp_read() f_mtp.c
Write data/response
mData.write
MtpDataPacket::write(int fd)
::write(fd, mBuffer, mPacketSize);
mtp_write() f_mtp.c
mResponse.write
MtpResponsePacket::write
::write(fd, mBuffer, mPacketSize);
mtp_write() f_mtp.c
Event
MtpServer::doGetObject()
ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
mtp_ioctl() in f_mtp.c
MtpServer::doSendObject()
ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
mtp_ioctl() in f_mtp.c
MtpServer::sendObjectAdded/sendObjectRemoved/sendStoreAdded/sendStoreRemoved/sendDevicePropertyChanged
MtpServer::sendEvent(MtpEventCode code, uint32_t param1)
MtpEventPacket::write(int fd)
::ioctl(fd, MTP_SEND_EVENT, (unsigned long)&event);
mtp_ioctl() in f_mtp.c
mtp_send_event()
開始的幾個操作
MTP_OPERATION_OPEN_SESSION (1002)
MTP_OPERATION_GET_DEVICE_INFO (1001)
MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED (9801)
MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED (9801)
MTP_OPERATION_GET_DEVICE_PROP_DESC (1014)
MTP_OPERATION_GET_OBJECT_PROP_LIST (9805)
6. Debug方法
首先看看是哪部分出問題了
a. 檢查main log, UsbDeviceManager, setEnabledFunctions()是否正常
b. 檢查property, persist.sys.usb.config, sys.usb.config, sys.usb.state
c. 檢查sysfs, functions and state, vid, pid
d. 檢查kernel log, 能否看到sent uevent(USB_STATE=CONFIGURED), 同時看看main log, UsbDeviceManager
e. 檢查main log/kernel, MTP server啟動是否正常
f. 如果正常看看命令接收和response是否正常
針對不同出錯地方,仔細看相應部分程式碼
除錯工具
USB sniffer 方便看到所有資料,從協議上看看出錯地方,尤其是可能是PC問題時
對比方法
換PC, 換手機的方法來對比測試
7. 正常log
mtp_bind_config
msm_otg : USB exited from low power mode
msm_otg : chg_type = USB_SDP_CHARGER
msm_hsusb msm_hsusb: vbus online
msm_hsusb msm_hsusb: CI13XXX_CONTROLLER_RESET_EVENT received
msm_hsusb msm_hsusb: CI13XXX_CONTROLLER_CONNECT_EVENT received
msm_hsusb msm_hsusb: reset
msm_otg : Avail curr from USB = 100
android_work: android_work: did not send uevent (0 0 (null))
android_work: android_work: sent uevent USB_STATE=CONNECTED
msm_hsusb msm_hsusb: reset
android_work: android_work: sent uevent USB_STATE=DISCONNECTED
android_work: android_work: sent uevent USB_STATE=CONNECTED
msm_otg : Avail curr from USB = 500
android_work: android_work: sent uevent USB_STATE=CONFIGURED
MtpService: starting MTP server in MTP mode
mtp_open