首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[021]MTP架构解析

[021]MTP架构解析

作者头像
王小二
发布2020-06-08 10:50:01
1.9K0
发布2020-06-08 10:50:01
举报

前言

这两天正好在研究一个通过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整体架构图

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1.MTP传输原理
  • 2.MediaProvider中MTP功能整体架构图
    • 2.1 Java层
      • 2.2 JNI层
        • 2.3 Native层
          • 2.4 驱动层
          • 3 从PC端通过MTP拷贝1.txt文件到手机中的流程
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档