美文网首页
[021]MTP架构解析

[021]MTP架构解析

作者: 王小二的技术栈 | 来源:发表于2020-01-10 21:10 被阅读0次

    前言

    这两天正好在研究一个通过MTP模式拷贝文件到手机速度慢的问题,顺便把整个MTP架构学了一遍,所以写一篇文章记录并分享一下。

    1.MTP传输原理

    主要分为三部分
    1.手机端的MediaProvider进程
    2.USB线
    3.PC端的MTP客户端
    简单的描述就是:

    手机端的MediaProvider进程不断的监听USB端口根据MTP协议读写数据
    PC端的MTP客户端也是不断的监听USB端口根据MTP协议读写数据

    PC端的MTP客户端代码是微软写的,我们只需要研究手机端MediaProvider进程中MTP相关的代码即可。

    2.MediaProvider中MTP功能整体架构图

    整体架构比较清晰,如果你看过Binder驱动,你会发现结构非常类似,Java->JNI->Native->设备节点->驱动程序。

    2.1 Java层

    /frameworks/base/media/java/android/mtp/MtpServer.java

    public class MtpServer implements Runnable {
    
          public void start() {
              Thread thread = new Thread(this, "MtpServer");
              thread.start();
          }
      
          @Override
          public void run() {
              native_run();
              native_cleanup();
              mDatabase.close();
              mOnTerminate.run();
          }
    }
    

    MtpServer的代码很简单,本身就是实现了Runnable接口,然后新启一个“MtpServer”的线程运行MtpServer,调用native_run。

    2.2 JNI层

    /frameworks/base/media/jni/android_mtp_MtpServer.cpp

    android_mtp_MtpServer_run(JNIEnv *env, jobject thiz)
    {
        MtpServer* server = getMtpServer(env, thiz);
        if (server)
            server->run();
        else
            ALOGE("server is null in run");
    }
    

    JNI没有太多的逻辑,调用MtpServer->run(),更多是实现在Native层的MtpServer.cpp

    2.3 Native层

    /frameworks/av/media/mtp/MtpServer.cpp

    MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
                        const char *deviceInfoManufacturer,
                        const char *deviceInfoModel,
                        const char *deviceInfoDeviceVersion,
                        const char *deviceInfoSerialNumber)
        {
        //我们的设备不支持FFS_MTP_EP0
        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();//默认都是走这里
        }
    }
    
    void MtpServer::run() {
        //启动MtpDevHandle
        if (mHandle->start(mPtp)) {
            ALOGE("Failed to start usb driver!");
            mHandle->close();
            return;
        }
        ...
        //请注意这里是死循环
        while (1) {
            //读取收到的MTP协议
            int ret = mRequest.read(mHandle);
            MtpOperationCode operation = mRequest.getOperationCode();
            MtpTransactionID transaction = mRequest.getTransactionID();
            ...
            //根据上面获得的MTP协议进行处理
            if (handleRequest()) {
                if (!dataIn && mData.hasData()) {
                    mData.setOperationCode(operation);
                    mData.setTransactionID(transaction);
                    ALOGV("sending data:");
                    ret = mData.write(mHandle);
                    if (ret < 0) {
                        ALOGE("request write returned %d, errno: %d", ret, errno);
                        if (errno == ECANCELED) {
                            // return to top of loop and wait for next command
                            continue;
                        }
                        break;
                    }
                }
    
                mResponse.setTransactionID(transaction);
                ALOGV("sending response %04X", mResponse.getResponseCode());
                ret = mResponse.write(mHandle);
                const int savedErrno = errno;
                if (ret < 0) {
                    ALOGE("request write returned %d, errno: %d", ret, errno);
                    if (savedErrno == ECANCELED) {
                        // return to top of loop and wait for next command
                        continue;
                    }
                    break;
                }
            } else {
                ALOGV("skipping response\n");
            }
        }
    
       ...
    }
    

    MtpServer.cpp的逻辑就相对复杂,主要是通过MtpDevHandle去和MTP驱动沟通,下面就是MtpDevHandle.cpp

    /frameworks/av/media/mtp/MtpDevHandle.cpp

    #include "MtpDevHandle.h"
    
    namespace android {
    
    constexpr char mtp_dev_path[] = "/dev/mtp_usb";
    
    MtpDevHandle::MtpDevHandle()
        : mFd(-1) {};
    
    MtpDevHandle::~MtpDevHandle() {}
    
    int MtpDevHandle::read(void *data, size_t len) {
        return ::read(mFd, data, len);
    }
    
    int MtpDevHandle::write(const void *data, size_t len) {
        return ::write(mFd, data, len);
    }
    
    int MtpDevHandle::receiveFile(mtp_file_range mfr, bool) {
        return ioctl(mFd, MTP_RECEIVE_FILE, reinterpret_cast<unsigned long>(&mfr));
    }
    
    int MtpDevHandle::sendFile(mtp_file_range mfr) {
        return ioctl(mFd, MTP_SEND_FILE_WITH_HEADER, reinterpret_cast<unsigned long>(&mfr));
    }
    
    int MtpDevHandle::sendEvent(mtp_event me) {
        return ioctl(mFd, MTP_SEND_EVENT, reinterpret_cast<unsigned long>(&me));
    }
    
    int MtpDevHandle::start(bool /* ptp */) {
        mFd.reset(TEMP_FAILURE_RETRY(open(mtp_dev_path, O_RDWR)));
        if (mFd == -1) return -1;
        return 0;
    }
    
    void MtpDevHandle::close() {
        mFd.reset();
    }
    
    } // namespace android
    

    如果看过Binder机制的人,看这个代码是不是非常熟悉,open,ioctl,close,因为mtp驱动也是一个字符型的驱动。

    2.4 驱动层

    驱动层的代码我就补贴了,我担心很多人看不懂,但是为了方便理解驱动层的做的事,我会用文字描述一下从PC端通过MTP拷贝文件到手机中过程。

    3 从PC端通过MTP拷贝1.txt文件到手机中的流程

    1.MtpServer通过MtpDevHandle从MTP驱动中获得了1.txt接受的信息,包含了1.txt文件的信息以及存储的路径信息。
    2.MtpServer根据第1步中的信息创建了一个1.txt在手机中。
    3.MtpServer通过MtpDevHandle将1.txt文件路径传给了MTP驱动
    4.MTP驱动不断读取USB驱动中的数据并写入到1.txt文件中
    MTP驱动层伪代码

    read_data = null;
    write_data = null;
    
    while(usb有数据 || write_data != null){
       read_data = read(usb);//从usb驱动中读数据
       if(write_data != null) {
           write("1.txt", write_data);
       }
       if(read_data != null) {
           write_data = read_data;
       }
    }
    

    总结

    以上就是我对MTP的架构的总结,细心的读者会说android系统层很多功能的套路都差不多啊,是的,其实你只要掌握了基础Kernel驱动知识,Native开发,JNI开发,Java开发,Android Framework,Binder机制(Binder HIDL VNDBinder),会发现看很多模块自己会学的越来越快。以下就会我画的一个简单ION架构图,从看代码到画图,也就十几分钟,后续我会详细讲一下ION架构,敬请期待。

    ION整体架构图

    相关文章

      网友评论

          本文标题:[021]MTP架构解析

          本文链接:https://www.haomeiwen.com/subject/ntbmactx.html