MTP手机端实现过程

上一篇基本把pc端连接mtp协议走的内核路径过了一遍,还有部分细节不完善,但整体流程还是走的usb驱动逻辑。这是后话。简而言之,pc在内核平没有专门为MTP设计什么东西。解析MTP协议的逻辑还是放在了用户态。通过D-bus连通usb驱动,对数据进行mtp协议解析。为了详细了解mtp具体做了什么,我从手机端研究了MTP在内核中的实现。

一、/dev/mtp_usb

真正意义上的MTP驱动位于手机一侧。注册了 /dev/mtp_usb字符设备。
在这里插入图片描述
read write 接口实现了控制命令的传输和写入。也就是说当有远端的文件请求是,手机端是通过这里发送给手机测用户态服务的。

void MtpServer::run() {
   
   
// 将mFD赋值给fd,fd就是“/dev/mtp_usb”的句柄
int fd = mFD;

while (1) {
   
   
// 读取“/dev/mtp_usb”
int ret = mRequest.read(fd);

 ...
// 获取“MTP操作码”
 MtpOperationCode operation = mRequest.getOperationCode();
 MtpTransactionID transaction = mRequest.getTransactionID();

 ...

// 在handleRequest()中,根据读取的指令作出相应的处理
if (handleRequest()) {
   
   
 ...
 }
 }
 ...
}

二、文件数据的读取

为了在得到请求后顺利吧数据发送到远端PC上。手机端利用了启动的Mtp_server。

bool MtpServer::handleRequest() {
   
   
    undefined
    Mutex::Autolock autoLock(mMutex);
    MtpOperationCode operation = mRequest.getOperationCode();
    MtpResponseCode response;

    mResponse.reset();

    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
   
   undefined
    mSendObjectHandle = kInvalidObjectHandle;
    }

    switch (operation) {
   
   undefined
        case MTP_OPERATION_GET_DEVICE_INFO:
        response = doGetDeviceInfo();
        break;
        case MTP_OPERATION_OPEN_SESSION:
        response = doOpenSession();
        break;
        case MTP_OPERATION_CLOSE_SESSION:
        response = doCloseSession();
        break;
        ...
        case MTP_OPERATION_GET_OBJECT:    //read
        response = doGetObject();-------------------------------
        break;
        case MTP_OPERATION_SEND_OBJECT:
        response = doSendObject();------------------------------
        break;
        ...
    }

    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
        return false;
    mResponse.setResponseCode(response);
    return true;
 }

如上,请求指令会进入MTP_OPERATION_GET_OBJECT。进行文件数据发送。用户态不会打开文件,而是通过句柄传递,/dev/mtp_usb ioctl传递指令, 内核直接读取文件数据,加入usb设备的数据队列。

MtpResponseCode MtpServer::doGetObject() {
   
   undefined
...
    // 根据handle获取文件的路径(pathBuf)、大小(fileLength)和“格式”。
    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
    if (result != MTP_RESPONSE_OK)
        return result;

    // 将文件路径转换为const char*类型。
    const char* filePath = (const char *)pathBuf;
    // 将文件的信息传递给mfr,mfr是kernel的一个结构体;最终将mfr传递给kernel。
    mtp_file_range mfr;
    mfr.fd = open(filePath, O_RDONLY); // 设置“文件句柄”。
    if (mfr.fd < 0) {
   
   undefined
        return MTP_RESPONSE_GENERAL_ERROR;
    }
    mfr.offset = 0; // 设置“文件偏移”
    mfr.length = fileLength;
    mfr.command = mRequest.getOperationCode(); // 设置“command”
    mfr.transaction_id = mRequest.getTransactionID(); // 设置“transaction ID”

    // 通过ioctl将文件传给kernel。
    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);--------
    // 关闭文件
        close(mfr.fd);

 ...
}
static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value)
{
   
   
        if (code == MTP_SEND_FILE_WITH_HEADER) {
   
   
            work = &dev->send_file_work;
            dev->xfer_send_header = 1;
            dev->xfer_command = mfr.command;
            dev->xfer_transaction_id = mfr.transaction_id;
        } else if (code == MTP_SEND_FILE) {
   
   
            work = &dev->send_file_work;-------------------------------
            dev->xfer_send_header = 0;
        } else {
   
   
            work = &dev->receive_file_work;
        }
static void send_file_work(struct work_struct *data)
{
   
   
    // 获取dev结构体
    struct mtp_dev *dev = container_of(data, struct mtp_dev,
    send_file_work);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值