xref: /aosp_15_r20/frameworks/av/media/mtp/MtpFfsHandle.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #include <android-base/logging.h>
18*ec779b8eSAndroid Build Coastguard Worker #include <android-base/properties.h>
19*ec779b8eSAndroid Build Coastguard Worker #include <asyncio/AsyncIO.h>
20*ec779b8eSAndroid Build Coastguard Worker #include <dirent.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <errno.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <fcntl.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <stdio.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <stdlib.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <string.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <sys/eventfd.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <sys/ioctl.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <sys/mman.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <sys/poll.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <sys/stat.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <sys/types.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <unistd.h>
33*ec779b8eSAndroid Build Coastguard Worker 
34*ec779b8eSAndroid Build Coastguard Worker #include "PosixAsyncIO.h"
35*ec779b8eSAndroid Build Coastguard Worker #include "MtpDescriptors.h"
36*ec779b8eSAndroid Build Coastguard Worker #include "MtpFfsHandle.h"
37*ec779b8eSAndroid Build Coastguard Worker #include "mtp.h"
38*ec779b8eSAndroid Build Coastguard Worker 
39*ec779b8eSAndroid Build Coastguard Worker namespace {
40*ec779b8eSAndroid Build Coastguard Worker 
41*ec779b8eSAndroid Build Coastguard Worker constexpr unsigned AIO_BUFS_MAX = 128;
42*ec779b8eSAndroid Build Coastguard Worker constexpr unsigned AIO_BUF_LEN = 16384;
43*ec779b8eSAndroid Build Coastguard Worker 
44*ec779b8eSAndroid Build Coastguard Worker constexpr unsigned FFS_NUM_EVENTS = 5;
45*ec779b8eSAndroid Build Coastguard Worker 
46*ec779b8eSAndroid Build Coastguard Worker constexpr unsigned MAX_FILE_CHUNK_SIZE = AIO_BUFS_MAX * AIO_BUF_LEN;
47*ec779b8eSAndroid Build Coastguard Worker 
48*ec779b8eSAndroid Build Coastguard Worker constexpr uint32_t MAX_MTP_FILE_SIZE = 0xFFFFFFFF;
49*ec779b8eSAndroid Build Coastguard Worker // Note: POLL_TIMEOUT_MS = 0 means return immediately i.e. no sleep.
50*ec779b8eSAndroid Build Coastguard Worker // And this will cause high CPU usage.
51*ec779b8eSAndroid Build Coastguard Worker constexpr int32_t POLL_TIMEOUT_MS = 500;
52*ec779b8eSAndroid Build Coastguard Worker 
53*ec779b8eSAndroid Build Coastguard Worker struct timespec ZERO_TIMEOUT = { 0, 0 };
54*ec779b8eSAndroid Build Coastguard Worker 
55*ec779b8eSAndroid Build Coastguard Worker struct mtp_device_status {
56*ec779b8eSAndroid Build Coastguard Worker     uint16_t  wLength;
57*ec779b8eSAndroid Build Coastguard Worker     uint16_t  wCode;
58*ec779b8eSAndroid Build Coastguard Worker };
59*ec779b8eSAndroid Build Coastguard Worker 
60*ec779b8eSAndroid Build Coastguard Worker } // anonymous namespace
61*ec779b8eSAndroid Build Coastguard Worker 
62*ec779b8eSAndroid Build Coastguard Worker namespace android {
63*ec779b8eSAndroid Build Coastguard Worker 
getPacketSize(int ffs_fd)64*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::getPacketSize(int ffs_fd) {
65*ec779b8eSAndroid Build Coastguard Worker     struct usb_endpoint_descriptor desc;
66*ec779b8eSAndroid Build Coastguard Worker     if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
67*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Could not get FFS bulk-in descriptor";
68*ec779b8eSAndroid Build Coastguard Worker         return MAX_PACKET_SIZE_HS;
69*ec779b8eSAndroid Build Coastguard Worker     } else {
70*ec779b8eSAndroid Build Coastguard Worker         return desc.wMaxPacketSize;
71*ec779b8eSAndroid Build Coastguard Worker     }
72*ec779b8eSAndroid Build Coastguard Worker }
73*ec779b8eSAndroid Build Coastguard Worker 
MtpFfsHandle(int controlFd)74*ec779b8eSAndroid Build Coastguard Worker MtpFfsHandle::MtpFfsHandle(int controlFd) {
75*ec779b8eSAndroid Build Coastguard Worker     mControl.reset(controlFd);
76*ec779b8eSAndroid Build Coastguard Worker     mBatchCancel = android::base::GetBoolProperty("sys.usb.mtp.batchcancel", false);
77*ec779b8eSAndroid Build Coastguard Worker }
78*ec779b8eSAndroid Build Coastguard Worker 
~MtpFfsHandle()79*ec779b8eSAndroid Build Coastguard Worker MtpFfsHandle::~MtpFfsHandle() {}
80*ec779b8eSAndroid Build Coastguard Worker 
closeEndpoints()81*ec779b8eSAndroid Build Coastguard Worker void MtpFfsHandle::closeEndpoints() {
82*ec779b8eSAndroid Build Coastguard Worker     mIntr.reset();
83*ec779b8eSAndroid Build Coastguard Worker     mBulkIn.reset();
84*ec779b8eSAndroid Build Coastguard Worker     mBulkOut.reset();
85*ec779b8eSAndroid Build Coastguard Worker }
86*ec779b8eSAndroid Build Coastguard Worker 
openEndpoints(bool ptp)87*ec779b8eSAndroid Build Coastguard Worker bool MtpFfsHandle::openEndpoints(bool ptp) {
88*ec779b8eSAndroid Build Coastguard Worker     if (mBulkIn < 0) {
89*ec779b8eSAndroid Build Coastguard Worker         mBulkIn.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN, O_RDWR)));
90*ec779b8eSAndroid Build Coastguard Worker         if (mBulkIn < 0) {
91*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << (ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN) << ": cannot open bulk in ep";
92*ec779b8eSAndroid Build Coastguard Worker             return false;
93*ec779b8eSAndroid Build Coastguard Worker         }
94*ec779b8eSAndroid Build Coastguard Worker     }
95*ec779b8eSAndroid Build Coastguard Worker 
96*ec779b8eSAndroid Build Coastguard Worker     if (mBulkOut < 0) {
97*ec779b8eSAndroid Build Coastguard Worker         mBulkOut.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT, O_RDWR)));
98*ec779b8eSAndroid Build Coastguard Worker         if (mBulkOut < 0) {
99*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << (ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT) << ": cannot open bulk out ep";
100*ec779b8eSAndroid Build Coastguard Worker             return false;
101*ec779b8eSAndroid Build Coastguard Worker         }
102*ec779b8eSAndroid Build Coastguard Worker     }
103*ec779b8eSAndroid Build Coastguard Worker 
104*ec779b8eSAndroid Build Coastguard Worker     if (mIntr < 0) {
105*ec779b8eSAndroid Build Coastguard Worker         mIntr.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR, O_RDWR)));
106*ec779b8eSAndroid Build Coastguard Worker         if (mIntr < 0) {
107*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << (ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR) << ": cannot open intr ep";
108*ec779b8eSAndroid Build Coastguard Worker             return false;
109*ec779b8eSAndroid Build Coastguard Worker         }
110*ec779b8eSAndroid Build Coastguard Worker     }
111*ec779b8eSAndroid Build Coastguard Worker     return true;
112*ec779b8eSAndroid Build Coastguard Worker }
113*ec779b8eSAndroid Build Coastguard Worker 
advise(int fd)114*ec779b8eSAndroid Build Coastguard Worker void MtpFfsHandle::advise(int fd) {
115*ec779b8eSAndroid Build Coastguard Worker     for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
116*ec779b8eSAndroid Build Coastguard Worker         if (posix_madvise(mIobuf[i].bufs.data(), MAX_FILE_CHUNK_SIZE,
117*ec779b8eSAndroid Build Coastguard Worker                 POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) != 0)
118*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << "Failed to madvise";
119*ec779b8eSAndroid Build Coastguard Worker     }
120*ec779b8eSAndroid Build Coastguard Worker     if (posix_fadvise(fd, 0, 0,
121*ec779b8eSAndroid Build Coastguard Worker                 POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED) != 0)
122*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to fadvise";
123*ec779b8eSAndroid Build Coastguard Worker }
124*ec779b8eSAndroid Build Coastguard Worker 
writeDescriptors(bool ptp)125*ec779b8eSAndroid Build Coastguard Worker bool MtpFfsHandle::writeDescriptors(bool ptp) {
126*ec779b8eSAndroid Build Coastguard Worker     return ::android::writeDescriptors(mControl, ptp);
127*ec779b8eSAndroid Build Coastguard Worker }
128*ec779b8eSAndroid Build Coastguard Worker 
closeConfig()129*ec779b8eSAndroid Build Coastguard Worker void MtpFfsHandle::closeConfig() {
130*ec779b8eSAndroid Build Coastguard Worker     mControl.reset();
131*ec779b8eSAndroid Build Coastguard Worker }
132*ec779b8eSAndroid Build Coastguard Worker 
doAsync(void * data,size_t len,bool read,bool zero_packet)133*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::doAsync(void* data, size_t len, bool read, bool zero_packet) {
134*ec779b8eSAndroid Build Coastguard Worker     struct io_event ioevs[AIO_BUFS_MAX];
135*ec779b8eSAndroid Build Coastguard Worker     size_t total = 0;
136*ec779b8eSAndroid Build Coastguard Worker 
137*ec779b8eSAndroid Build Coastguard Worker     while (total < len) {
138*ec779b8eSAndroid Build Coastguard Worker         size_t this_len = std::min(len - total, static_cast<size_t>(AIO_BUF_LEN * AIO_BUFS_MAX));
139*ec779b8eSAndroid Build Coastguard Worker         int num_bufs = this_len / AIO_BUF_LEN + (this_len % AIO_BUF_LEN == 0 ? 0 : 1);
140*ec779b8eSAndroid Build Coastguard Worker         for (int i = 0; i < num_bufs; i++) {
141*ec779b8eSAndroid Build Coastguard Worker             mIobuf[0].buf[i] = reinterpret_cast<unsigned char*>(data) + total + i * AIO_BUF_LEN;
142*ec779b8eSAndroid Build Coastguard Worker         }
143*ec779b8eSAndroid Build Coastguard Worker         int ret = iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, this_len, read);
144*ec779b8eSAndroid Build Coastguard Worker         if (ret < 0) return -1;
145*ec779b8eSAndroid Build Coastguard Worker         ret = waitEvents(&mIobuf[0], ret, ioevs, nullptr);
146*ec779b8eSAndroid Build Coastguard Worker         if (ret < 0) return -1;
147*ec779b8eSAndroid Build Coastguard Worker         total += ret;
148*ec779b8eSAndroid Build Coastguard Worker         if (static_cast<size_t>(ret) < this_len) break;
149*ec779b8eSAndroid Build Coastguard Worker     }
150*ec779b8eSAndroid Build Coastguard Worker 
151*ec779b8eSAndroid Build Coastguard Worker     int packet_size = getPacketSize(read ? mBulkOut : mBulkIn);
152*ec779b8eSAndroid Build Coastguard Worker     if (len % packet_size == 0 && zero_packet) {
153*ec779b8eSAndroid Build Coastguard Worker         int ret = iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, 0, read);
154*ec779b8eSAndroid Build Coastguard Worker         if (ret < 0) return -1;
155*ec779b8eSAndroid Build Coastguard Worker         ret = waitEvents(&mIobuf[0], ret, ioevs, nullptr);
156*ec779b8eSAndroid Build Coastguard Worker         if (ret < 0) return -1;
157*ec779b8eSAndroid Build Coastguard Worker     }
158*ec779b8eSAndroid Build Coastguard Worker 
159*ec779b8eSAndroid Build Coastguard Worker     for (unsigned i = 0; i < AIO_BUFS_MAX; i++) {
160*ec779b8eSAndroid Build Coastguard Worker         mIobuf[0].buf[i] = mIobuf[0].bufs.data() + i * AIO_BUF_LEN;
161*ec779b8eSAndroid Build Coastguard Worker     }
162*ec779b8eSAndroid Build Coastguard Worker     return total;
163*ec779b8eSAndroid Build Coastguard Worker }
164*ec779b8eSAndroid Build Coastguard Worker 
read(void * data,size_t len)165*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::read(void* data, size_t len) {
166*ec779b8eSAndroid Build Coastguard Worker     // Zero packets are handled by receiveFile()
167*ec779b8eSAndroid Build Coastguard Worker     return doAsync(data, len, true, false);
168*ec779b8eSAndroid Build Coastguard Worker }
169*ec779b8eSAndroid Build Coastguard Worker 
write(const void * data,size_t len)170*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::write(const void* data, size_t len) {
171*ec779b8eSAndroid Build Coastguard Worker     return doAsync(const_cast<void*>(data), len, false, true);
172*ec779b8eSAndroid Build Coastguard Worker }
173*ec779b8eSAndroid Build Coastguard Worker 
handleEvent()174*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::handleEvent() {
175*ec779b8eSAndroid Build Coastguard Worker 
176*ec779b8eSAndroid Build Coastguard Worker     std::vector<usb_functionfs_event> events(FFS_NUM_EVENTS);
177*ec779b8eSAndroid Build Coastguard Worker     usb_functionfs_event *event = events.data();
178*ec779b8eSAndroid Build Coastguard Worker     int nbytes = TEMP_FAILURE_RETRY(::read(mControl, event,
179*ec779b8eSAndroid Build Coastguard Worker                 events.size() * sizeof(usb_functionfs_event)));
180*ec779b8eSAndroid Build Coastguard Worker     if (nbytes == -1) {
181*ec779b8eSAndroid Build Coastguard Worker         return -1;
182*ec779b8eSAndroid Build Coastguard Worker     }
183*ec779b8eSAndroid Build Coastguard Worker     int ret = 0;
184*ec779b8eSAndroid Build Coastguard Worker     for (size_t n = nbytes / sizeof *event; n; --n, ++event) {
185*ec779b8eSAndroid Build Coastguard Worker         switch (event->type) {
186*ec779b8eSAndroid Build Coastguard Worker         case FUNCTIONFS_BIND:
187*ec779b8eSAndroid Build Coastguard Worker         case FUNCTIONFS_ENABLE:
188*ec779b8eSAndroid Build Coastguard Worker             ret = 0;
189*ec779b8eSAndroid Build Coastguard Worker             errno = 0;
190*ec779b8eSAndroid Build Coastguard Worker             break;
191*ec779b8eSAndroid Build Coastguard Worker         case FUNCTIONFS_UNBIND:
192*ec779b8eSAndroid Build Coastguard Worker         case FUNCTIONFS_DISABLE:
193*ec779b8eSAndroid Build Coastguard Worker             errno = ESHUTDOWN;
194*ec779b8eSAndroid Build Coastguard Worker             ret = -1;
195*ec779b8eSAndroid Build Coastguard Worker             break;
196*ec779b8eSAndroid Build Coastguard Worker         case FUNCTIONFS_SETUP:
197*ec779b8eSAndroid Build Coastguard Worker             if (handleControlRequest(&event->u.setup) == -1)
198*ec779b8eSAndroid Build Coastguard Worker                 ret = -1;
199*ec779b8eSAndroid Build Coastguard Worker             break;
200*ec779b8eSAndroid Build Coastguard Worker         case FUNCTIONFS_SUSPEND:
201*ec779b8eSAndroid Build Coastguard Worker         case FUNCTIONFS_RESUME:
202*ec779b8eSAndroid Build Coastguard Worker             break;
203*ec779b8eSAndroid Build Coastguard Worker         default:
204*ec779b8eSAndroid Build Coastguard Worker             LOG(ERROR) << "Mtp Event " << event->type << " (unknown)";
205*ec779b8eSAndroid Build Coastguard Worker         }
206*ec779b8eSAndroid Build Coastguard Worker     }
207*ec779b8eSAndroid Build Coastguard Worker     return ret;
208*ec779b8eSAndroid Build Coastguard Worker }
209*ec779b8eSAndroid Build Coastguard Worker 
handleControlRequest(const struct usb_ctrlrequest * setup)210*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::handleControlRequest(const struct usb_ctrlrequest *setup) {
211*ec779b8eSAndroid Build Coastguard Worker     uint8_t type = setup->bRequestType;
212*ec779b8eSAndroid Build Coastguard Worker     uint8_t code = setup->bRequest;
213*ec779b8eSAndroid Build Coastguard Worker     uint16_t length = setup->wLength;
214*ec779b8eSAndroid Build Coastguard Worker     uint16_t index = setup->wIndex;
215*ec779b8eSAndroid Build Coastguard Worker     uint16_t value = setup->wValue;
216*ec779b8eSAndroid Build Coastguard Worker     std::vector<char> buf;
217*ec779b8eSAndroid Build Coastguard Worker     buf.resize(length);
218*ec779b8eSAndroid Build Coastguard Worker 
219*ec779b8eSAndroid Build Coastguard Worker     if (!(type & USB_DIR_IN)) {
220*ec779b8eSAndroid Build Coastguard Worker         if (::read(mControl, buf.data(), length) != length) {
221*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << "Mtp error ctrlreq read data";
222*ec779b8eSAndroid Build Coastguard Worker         }
223*ec779b8eSAndroid Build Coastguard Worker     }
224*ec779b8eSAndroid Build Coastguard Worker 
225*ec779b8eSAndroid Build Coastguard Worker     if ((type & USB_TYPE_MASK) == USB_TYPE_CLASS && index == 0 && value == 0) {
226*ec779b8eSAndroid Build Coastguard Worker         switch(code) {
227*ec779b8eSAndroid Build Coastguard Worker         case MTP_REQ_RESET:
228*ec779b8eSAndroid Build Coastguard Worker         case MTP_REQ_CANCEL:
229*ec779b8eSAndroid Build Coastguard Worker             errno = ECANCELED;
230*ec779b8eSAndroid Build Coastguard Worker             return -1;
231*ec779b8eSAndroid Build Coastguard Worker         //    break;
232*ec779b8eSAndroid Build Coastguard Worker         case MTP_REQ_GET_DEVICE_STATUS:
233*ec779b8eSAndroid Build Coastguard Worker         {
234*ec779b8eSAndroid Build Coastguard Worker             if (length < sizeof(struct mtp_device_status) + 4) {
235*ec779b8eSAndroid Build Coastguard Worker                 errno = EINVAL;
236*ec779b8eSAndroid Build Coastguard Worker                 return -1;
237*ec779b8eSAndroid Build Coastguard Worker             }
238*ec779b8eSAndroid Build Coastguard Worker             struct mtp_device_status *st = reinterpret_cast<struct mtp_device_status*>(buf.data());
239*ec779b8eSAndroid Build Coastguard Worker             st->wLength = htole16(sizeof(st));
240*ec779b8eSAndroid Build Coastguard Worker             if (mCanceled) {
241*ec779b8eSAndroid Build Coastguard Worker                 st->wLength += 4;
242*ec779b8eSAndroid Build Coastguard Worker                 st->wCode = MTP_RESPONSE_TRANSACTION_CANCELLED;
243*ec779b8eSAndroid Build Coastguard Worker                 uint16_t *endpoints = reinterpret_cast<uint16_t*>(st + 1);
244*ec779b8eSAndroid Build Coastguard Worker                 endpoints[0] = ioctl(mBulkIn, FUNCTIONFS_ENDPOINT_REVMAP);
245*ec779b8eSAndroid Build Coastguard Worker                 endpoints[1] = ioctl(mBulkOut, FUNCTIONFS_ENDPOINT_REVMAP);
246*ec779b8eSAndroid Build Coastguard Worker                 mCanceled = false;
247*ec779b8eSAndroid Build Coastguard Worker             } else {
248*ec779b8eSAndroid Build Coastguard Worker                 st->wCode = MTP_RESPONSE_OK;
249*ec779b8eSAndroid Build Coastguard Worker             }
250*ec779b8eSAndroid Build Coastguard Worker             length = st->wLength;
251*ec779b8eSAndroid Build Coastguard Worker             break;
252*ec779b8eSAndroid Build Coastguard Worker         }
253*ec779b8eSAndroid Build Coastguard Worker         default:
254*ec779b8eSAndroid Build Coastguard Worker             LOG(ERROR) << "Unrecognized Mtp class request! " << code;
255*ec779b8eSAndroid Build Coastguard Worker         }
256*ec779b8eSAndroid Build Coastguard Worker     } else {
257*ec779b8eSAndroid Build Coastguard Worker         LOG(ERROR) << "Unrecognized request type " << type;
258*ec779b8eSAndroid Build Coastguard Worker     }
259*ec779b8eSAndroid Build Coastguard Worker 
260*ec779b8eSAndroid Build Coastguard Worker     if (type & USB_DIR_IN) {
261*ec779b8eSAndroid Build Coastguard Worker         if (::write(mControl, buf.data(), length) != length) {
262*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << "Mtp error ctrlreq write data";
263*ec779b8eSAndroid Build Coastguard Worker         }
264*ec779b8eSAndroid Build Coastguard Worker     }
265*ec779b8eSAndroid Build Coastguard Worker     return 0;
266*ec779b8eSAndroid Build Coastguard Worker }
267*ec779b8eSAndroid Build Coastguard Worker 
start(bool ptp)268*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::start(bool ptp) {
269*ec779b8eSAndroid Build Coastguard Worker     if (!openEndpoints(ptp))
270*ec779b8eSAndroid Build Coastguard Worker         return -1;
271*ec779b8eSAndroid Build Coastguard Worker 
272*ec779b8eSAndroid Build Coastguard Worker     for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
273*ec779b8eSAndroid Build Coastguard Worker         mIobuf[i].bufs.resize(MAX_FILE_CHUNK_SIZE);
274*ec779b8eSAndroid Build Coastguard Worker         mIobuf[i].iocb.resize(AIO_BUFS_MAX);
275*ec779b8eSAndroid Build Coastguard Worker         mIobuf[i].iocbs.resize(AIO_BUFS_MAX);
276*ec779b8eSAndroid Build Coastguard Worker         mIobuf[i].buf.resize(AIO_BUFS_MAX);
277*ec779b8eSAndroid Build Coastguard Worker         for (unsigned j = 0; j < AIO_BUFS_MAX; j++) {
278*ec779b8eSAndroid Build Coastguard Worker             mIobuf[i].buf[j] = mIobuf[i].bufs.data() + j * AIO_BUF_LEN;
279*ec779b8eSAndroid Build Coastguard Worker             mIobuf[i].iocb[j] = &mIobuf[i].iocbs[j];
280*ec779b8eSAndroid Build Coastguard Worker         }
281*ec779b8eSAndroid Build Coastguard Worker     }
282*ec779b8eSAndroid Build Coastguard Worker 
283*ec779b8eSAndroid Build Coastguard Worker     memset(&mCtx, 0, sizeof(mCtx));
284*ec779b8eSAndroid Build Coastguard Worker     if (io_setup(AIO_BUFS_MAX, &mCtx) < 0) {
285*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "unable to setup aio";
286*ec779b8eSAndroid Build Coastguard Worker         return -1;
287*ec779b8eSAndroid Build Coastguard Worker     }
288*ec779b8eSAndroid Build Coastguard Worker     mEventFd.reset(eventfd(0, EFD_NONBLOCK));
289*ec779b8eSAndroid Build Coastguard Worker     mPollFds[0].fd = mControl;
290*ec779b8eSAndroid Build Coastguard Worker     mPollFds[0].events = POLLIN;
291*ec779b8eSAndroid Build Coastguard Worker     mPollFds[1].fd = mEventFd;
292*ec779b8eSAndroid Build Coastguard Worker     mPollFds[1].events = POLLIN;
293*ec779b8eSAndroid Build Coastguard Worker 
294*ec779b8eSAndroid Build Coastguard Worker     mCanceled = false;
295*ec779b8eSAndroid Build Coastguard Worker     return 0;
296*ec779b8eSAndroid Build Coastguard Worker }
297*ec779b8eSAndroid Build Coastguard Worker 
close()298*ec779b8eSAndroid Build Coastguard Worker void MtpFfsHandle::close() {
299*ec779b8eSAndroid Build Coastguard Worker     // Join all child threads before destruction
300*ec779b8eSAndroid Build Coastguard Worker     int count = mChildThreads.size();
301*ec779b8eSAndroid Build Coastguard Worker     for (int i = 0; i < count; i++) {
302*ec779b8eSAndroid Build Coastguard Worker         mChildThreads[i].join();
303*ec779b8eSAndroid Build Coastguard Worker     }
304*ec779b8eSAndroid Build Coastguard Worker     mChildThreads.clear();
305*ec779b8eSAndroid Build Coastguard Worker 
306*ec779b8eSAndroid Build Coastguard Worker     io_destroy(mCtx);
307*ec779b8eSAndroid Build Coastguard Worker     closeEndpoints();
308*ec779b8eSAndroid Build Coastguard Worker     closeConfig();
309*ec779b8eSAndroid Build Coastguard Worker }
310*ec779b8eSAndroid Build Coastguard Worker 
waitEvents(struct io_buffer * buf,int min_events,struct io_event * events,int * counter)311*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::waitEvents(struct io_buffer *buf, int min_events, struct io_event *events,
312*ec779b8eSAndroid Build Coastguard Worker         int *counter) {
313*ec779b8eSAndroid Build Coastguard Worker     int num_events = 0;
314*ec779b8eSAndroid Build Coastguard Worker     int ret = 0;
315*ec779b8eSAndroid Build Coastguard Worker     int error = 0;
316*ec779b8eSAndroid Build Coastguard Worker 
317*ec779b8eSAndroid Build Coastguard Worker     while (num_events < min_events) {
318*ec779b8eSAndroid Build Coastguard Worker         if (poll(mPollFds, 2, POLL_TIMEOUT_MS) == -1) {
319*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << "Mtp error during poll()";
320*ec779b8eSAndroid Build Coastguard Worker             return -1;
321*ec779b8eSAndroid Build Coastguard Worker         }
322*ec779b8eSAndroid Build Coastguard Worker         if (mPollFds[0].revents & POLLIN) {
323*ec779b8eSAndroid Build Coastguard Worker             mPollFds[0].revents = 0;
324*ec779b8eSAndroid Build Coastguard Worker             if (handleEvent() == -1) {
325*ec779b8eSAndroid Build Coastguard Worker                 error = errno;
326*ec779b8eSAndroid Build Coastguard Worker             }
327*ec779b8eSAndroid Build Coastguard Worker         }
328*ec779b8eSAndroid Build Coastguard Worker         if (mPollFds[1].revents & POLLIN) {
329*ec779b8eSAndroid Build Coastguard Worker             mPollFds[1].revents = 0;
330*ec779b8eSAndroid Build Coastguard Worker             uint64_t ev_cnt = 0;
331*ec779b8eSAndroid Build Coastguard Worker 
332*ec779b8eSAndroid Build Coastguard Worker             if (::read(mEventFd, &ev_cnt, sizeof(ev_cnt)) == -1) {
333*ec779b8eSAndroid Build Coastguard Worker                 PLOG(ERROR) << "Mtp unable to read eventfd";
334*ec779b8eSAndroid Build Coastguard Worker                 error = errno;
335*ec779b8eSAndroid Build Coastguard Worker                 continue;
336*ec779b8eSAndroid Build Coastguard Worker             }
337*ec779b8eSAndroid Build Coastguard Worker 
338*ec779b8eSAndroid Build Coastguard Worker             // It's possible that io_getevents will return more events than the eventFd reported,
339*ec779b8eSAndroid Build Coastguard Worker             // since events may appear in the time between the calls. In this case, the eventFd will
340*ec779b8eSAndroid Build Coastguard Worker             // show up as readable next iteration, but there will be fewer or no events to actually
341*ec779b8eSAndroid Build Coastguard Worker             // wait for. Thus we never want io_getevents to block.
342*ec779b8eSAndroid Build Coastguard Worker             int this_events = TEMP_FAILURE_RETRY(io_getevents(mCtx, 0, AIO_BUFS_MAX, events, &ZERO_TIMEOUT));
343*ec779b8eSAndroid Build Coastguard Worker             if (this_events == -1) {
344*ec779b8eSAndroid Build Coastguard Worker                 PLOG(ERROR) << "Mtp error getting events";
345*ec779b8eSAndroid Build Coastguard Worker                 error = errno;
346*ec779b8eSAndroid Build Coastguard Worker             }
347*ec779b8eSAndroid Build Coastguard Worker             // Add up the total amount of data and find errors on the way.
348*ec779b8eSAndroid Build Coastguard Worker             for (unsigned j = 0; j < static_cast<unsigned>(this_events); j++) {
349*ec779b8eSAndroid Build Coastguard Worker                 if (events[j].res < 0) {
350*ec779b8eSAndroid Build Coastguard Worker                     errno = -events[j].res;
351*ec779b8eSAndroid Build Coastguard Worker                     PLOG(ERROR) << "Mtp got error event at " << j << " and " << buf->actual << " total";
352*ec779b8eSAndroid Build Coastguard Worker                     error = errno;
353*ec779b8eSAndroid Build Coastguard Worker                 }
354*ec779b8eSAndroid Build Coastguard Worker                 ret += events[j].res;
355*ec779b8eSAndroid Build Coastguard Worker             }
356*ec779b8eSAndroid Build Coastguard Worker             num_events += this_events;
357*ec779b8eSAndroid Build Coastguard Worker             if (counter)
358*ec779b8eSAndroid Build Coastguard Worker                 *counter += this_events;
359*ec779b8eSAndroid Build Coastguard Worker         }
360*ec779b8eSAndroid Build Coastguard Worker         if (error) {
361*ec779b8eSAndroid Build Coastguard Worker             errno = error;
362*ec779b8eSAndroid Build Coastguard Worker             ret = -1;
363*ec779b8eSAndroid Build Coastguard Worker             break;
364*ec779b8eSAndroid Build Coastguard Worker         }
365*ec779b8eSAndroid Build Coastguard Worker     }
366*ec779b8eSAndroid Build Coastguard Worker     return ret;
367*ec779b8eSAndroid Build Coastguard Worker }
368*ec779b8eSAndroid Build Coastguard Worker 
cancelTransaction()369*ec779b8eSAndroid Build Coastguard Worker void MtpFfsHandle::cancelTransaction() {
370*ec779b8eSAndroid Build Coastguard Worker     // Device cancels by stalling both bulk endpoints.
371*ec779b8eSAndroid Build Coastguard Worker     if (::read(mBulkIn, nullptr, 0) != -1 || errno != EBADMSG)
372*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Mtp stall failed on bulk in";
373*ec779b8eSAndroid Build Coastguard Worker     if (::write(mBulkOut, nullptr, 0) != -1 || errno != EBADMSG)
374*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Mtp stall failed on bulk out";
375*ec779b8eSAndroid Build Coastguard Worker     mCanceled = true;
376*ec779b8eSAndroid Build Coastguard Worker     errno = ECANCELED;
377*ec779b8eSAndroid Build Coastguard Worker }
378*ec779b8eSAndroid Build Coastguard Worker 
cancelEvents(struct iocb ** iocb,struct io_event * events,unsigned start,unsigned end,bool is_batch_cancel)379*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::cancelEvents(struct iocb **iocb, struct io_event *events, unsigned start,
380*ec779b8eSAndroid Build Coastguard Worker         unsigned end, bool is_batch_cancel) {
381*ec779b8eSAndroid Build Coastguard Worker     // Some manpages for io_cancel are out of date and incorrect.
382*ec779b8eSAndroid Build Coastguard Worker     // io_cancel will return -EINPROGRESS on success and does
383*ec779b8eSAndroid Build Coastguard Worker     // not place the event in the given memory. We have to use
384*ec779b8eSAndroid Build Coastguard Worker     // io_getevents to wait for all the events we cancelled.
385*ec779b8eSAndroid Build Coastguard Worker     int ret = 0;
386*ec779b8eSAndroid Build Coastguard Worker     unsigned num_events = 0;
387*ec779b8eSAndroid Build Coastguard Worker     int save_errno = errno;
388*ec779b8eSAndroid Build Coastguard Worker     errno = 0;
389*ec779b8eSAndroid Build Coastguard Worker 
390*ec779b8eSAndroid Build Coastguard Worker     for (unsigned j = start; j < end; j++) {
391*ec779b8eSAndroid Build Coastguard Worker         if (io_cancel(mCtx, iocb[j], nullptr) != -1 || errno != EINPROGRESS) {
392*ec779b8eSAndroid Build Coastguard Worker             PLOG(ERROR) << "Mtp couldn't cancel request " << j;
393*ec779b8eSAndroid Build Coastguard Worker         } else {
394*ec779b8eSAndroid Build Coastguard Worker             num_events++;
395*ec779b8eSAndroid Build Coastguard Worker         }
396*ec779b8eSAndroid Build Coastguard Worker         if (is_batch_cancel && num_events == 1) {
397*ec779b8eSAndroid Build Coastguard Worker             num_events = end - start;
398*ec779b8eSAndroid Build Coastguard Worker             break;
399*ec779b8eSAndroid Build Coastguard Worker         }
400*ec779b8eSAndroid Build Coastguard Worker     }
401*ec779b8eSAndroid Build Coastguard Worker     if (num_events != end - start) {
402*ec779b8eSAndroid Build Coastguard Worker         ret = -1;
403*ec779b8eSAndroid Build Coastguard Worker         errno = EIO;
404*ec779b8eSAndroid Build Coastguard Worker     }
405*ec779b8eSAndroid Build Coastguard Worker     int evs = TEMP_FAILURE_RETRY(io_getevents(mCtx, num_events, AIO_BUFS_MAX, events, nullptr));
406*ec779b8eSAndroid Build Coastguard Worker     if (static_cast<unsigned>(evs) != num_events) {
407*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Mtp couldn't cancel all requests, got " << evs;
408*ec779b8eSAndroid Build Coastguard Worker         ret = -1;
409*ec779b8eSAndroid Build Coastguard Worker     }
410*ec779b8eSAndroid Build Coastguard Worker 
411*ec779b8eSAndroid Build Coastguard Worker     uint64_t ev_cnt = 0;
412*ec779b8eSAndroid Build Coastguard Worker     if (num_events && ::read(mEventFd, &ev_cnt, sizeof(ev_cnt)) == -1)
413*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Mtp Unable to read event fd";
414*ec779b8eSAndroid Build Coastguard Worker 
415*ec779b8eSAndroid Build Coastguard Worker     if (ret == 0) {
416*ec779b8eSAndroid Build Coastguard Worker         // Restore errno since it probably got overriden with EINPROGRESS.
417*ec779b8eSAndroid Build Coastguard Worker         errno = save_errno;
418*ec779b8eSAndroid Build Coastguard Worker     }
419*ec779b8eSAndroid Build Coastguard Worker     return ret;
420*ec779b8eSAndroid Build Coastguard Worker }
421*ec779b8eSAndroid Build Coastguard Worker 
iobufSubmit(struct io_buffer * buf,int fd,unsigned length,bool read)422*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::iobufSubmit(struct io_buffer *buf, int fd, unsigned length, bool read) {
423*ec779b8eSAndroid Build Coastguard Worker     int ret = 0;
424*ec779b8eSAndroid Build Coastguard Worker     buf->actual = AIO_BUFS_MAX;
425*ec779b8eSAndroid Build Coastguard Worker     for (unsigned j = 0; j < AIO_BUFS_MAX; j++) {
426*ec779b8eSAndroid Build Coastguard Worker         unsigned rq_length = std::min(AIO_BUF_LEN, length - AIO_BUF_LEN * j);
427*ec779b8eSAndroid Build Coastguard Worker         io_prep(buf->iocb[j], fd, buf->buf[j], rq_length, 0, read);
428*ec779b8eSAndroid Build Coastguard Worker         buf->iocb[j]->aio_flags |= IOCB_FLAG_RESFD;
429*ec779b8eSAndroid Build Coastguard Worker         buf->iocb[j]->aio_resfd = mEventFd;
430*ec779b8eSAndroid Build Coastguard Worker 
431*ec779b8eSAndroid Build Coastguard Worker         // Not enough data, so table is truncated.
432*ec779b8eSAndroid Build Coastguard Worker         if (rq_length < AIO_BUF_LEN || length == AIO_BUF_LEN * (j + 1)) {
433*ec779b8eSAndroid Build Coastguard Worker             buf->actual = j + 1;
434*ec779b8eSAndroid Build Coastguard Worker             break;
435*ec779b8eSAndroid Build Coastguard Worker         }
436*ec779b8eSAndroid Build Coastguard Worker     }
437*ec779b8eSAndroid Build Coastguard Worker 
438*ec779b8eSAndroid Build Coastguard Worker     ret = io_submit(mCtx, buf->actual, buf->iocb.data());
439*ec779b8eSAndroid Build Coastguard Worker     if (ret != static_cast<int>(buf->actual)) {
440*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Mtp io_submit got " << ret << " expected " << buf->actual;
441*ec779b8eSAndroid Build Coastguard Worker         if (ret != -1) {
442*ec779b8eSAndroid Build Coastguard Worker             errno = EIO;
443*ec779b8eSAndroid Build Coastguard Worker         }
444*ec779b8eSAndroid Build Coastguard Worker         ret = -1;
445*ec779b8eSAndroid Build Coastguard Worker     }
446*ec779b8eSAndroid Build Coastguard Worker     return ret;
447*ec779b8eSAndroid Build Coastguard Worker }
448*ec779b8eSAndroid Build Coastguard Worker 
receiveFile(mtp_file_range mfr,bool zero_packet)449*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::receiveFile(mtp_file_range mfr, bool zero_packet) {
450*ec779b8eSAndroid Build Coastguard Worker     // When receiving files, the incoming length is given in 32 bits.
451*ec779b8eSAndroid Build Coastguard Worker     // A >=4G file is given as 0xFFFFFFFF
452*ec779b8eSAndroid Build Coastguard Worker     uint32_t file_length = mfr.length;
453*ec779b8eSAndroid Build Coastguard Worker     uint64_t offset = mfr.offset;
454*ec779b8eSAndroid Build Coastguard Worker 
455*ec779b8eSAndroid Build Coastguard Worker     struct aiocb aio;
456*ec779b8eSAndroid Build Coastguard Worker     aio.aio_fildes = mfr.fd;
457*ec779b8eSAndroid Build Coastguard Worker     aio.aio_buf = nullptr;
458*ec779b8eSAndroid Build Coastguard Worker     struct aiocb *aiol[] = {&aio};
459*ec779b8eSAndroid Build Coastguard Worker 
460*ec779b8eSAndroid Build Coastguard Worker     int ret = -1;
461*ec779b8eSAndroid Build Coastguard Worker     unsigned i = 0;
462*ec779b8eSAndroid Build Coastguard Worker     size_t length;
463*ec779b8eSAndroid Build Coastguard Worker     struct io_event ioevs[AIO_BUFS_MAX];
464*ec779b8eSAndroid Build Coastguard Worker     bool has_write = false;
465*ec779b8eSAndroid Build Coastguard Worker     bool error = false;
466*ec779b8eSAndroid Build Coastguard Worker     bool write_error = false;
467*ec779b8eSAndroid Build Coastguard Worker     int packet_size = getPacketSize(mBulkOut);
468*ec779b8eSAndroid Build Coastguard Worker     bool short_packet = false;
469*ec779b8eSAndroid Build Coastguard Worker     advise(mfr.fd);
470*ec779b8eSAndroid Build Coastguard Worker 
471*ec779b8eSAndroid Build Coastguard Worker     // Break down the file into pieces that fit in buffers
472*ec779b8eSAndroid Build Coastguard Worker     while (file_length > 0 || has_write) {
473*ec779b8eSAndroid Build Coastguard Worker         // Queue an asynchronous read from USB.
474*ec779b8eSAndroid Build Coastguard Worker         if (file_length > 0) {
475*ec779b8eSAndroid Build Coastguard Worker             length = std::min(static_cast<uint32_t>(MAX_FILE_CHUNK_SIZE), file_length);
476*ec779b8eSAndroid Build Coastguard Worker             if (iobufSubmit(&mIobuf[i], mBulkOut, length, true) == -1)
477*ec779b8eSAndroid Build Coastguard Worker                 error = true;
478*ec779b8eSAndroid Build Coastguard Worker         }
479*ec779b8eSAndroid Build Coastguard Worker 
480*ec779b8eSAndroid Build Coastguard Worker         // Get the return status of the last write request.
481*ec779b8eSAndroid Build Coastguard Worker         if (has_write) {
482*ec779b8eSAndroid Build Coastguard Worker             aio_suspend(aiol, 1, nullptr);
483*ec779b8eSAndroid Build Coastguard Worker             int written = aio_return(&aio);
484*ec779b8eSAndroid Build Coastguard Worker             if (static_cast<size_t>(written) < aio.aio_nbytes) {
485*ec779b8eSAndroid Build Coastguard Worker                 errno = written == -1 ? aio_error(&aio) : EIO;
486*ec779b8eSAndroid Build Coastguard Worker                 PLOG(ERROR) << "Mtp error writing to disk";
487*ec779b8eSAndroid Build Coastguard Worker                 write_error = true;
488*ec779b8eSAndroid Build Coastguard Worker             }
489*ec779b8eSAndroid Build Coastguard Worker             has_write = false;
490*ec779b8eSAndroid Build Coastguard Worker         }
491*ec779b8eSAndroid Build Coastguard Worker 
492*ec779b8eSAndroid Build Coastguard Worker         if (error) {
493*ec779b8eSAndroid Build Coastguard Worker             return -1;
494*ec779b8eSAndroid Build Coastguard Worker         }
495*ec779b8eSAndroid Build Coastguard Worker 
496*ec779b8eSAndroid Build Coastguard Worker         // Get the result of the read request, and queue a write to disk.
497*ec779b8eSAndroid Build Coastguard Worker         if (file_length > 0) {
498*ec779b8eSAndroid Build Coastguard Worker             unsigned num_events = 0;
499*ec779b8eSAndroid Build Coastguard Worker             ret = 0;
500*ec779b8eSAndroid Build Coastguard Worker             unsigned short_i = mIobuf[i].actual;
501*ec779b8eSAndroid Build Coastguard Worker             while (num_events < short_i) {
502*ec779b8eSAndroid Build Coastguard Worker                 // Get all events up to the short read, if there is one.
503*ec779b8eSAndroid Build Coastguard Worker                 // We must wait for each event since data transfer could end at any time.
504*ec779b8eSAndroid Build Coastguard Worker                 int this_events = 0;
505*ec779b8eSAndroid Build Coastguard Worker                 int event_ret = waitEvents(&mIobuf[i], 1, ioevs, &this_events);
506*ec779b8eSAndroid Build Coastguard Worker                 num_events += this_events;
507*ec779b8eSAndroid Build Coastguard Worker 
508*ec779b8eSAndroid Build Coastguard Worker                 if (event_ret == -1) {
509*ec779b8eSAndroid Build Coastguard Worker                     cancelEvents(mIobuf[i].iocb.data(), ioevs, num_events, mIobuf[i].actual,
510*ec779b8eSAndroid Build Coastguard Worker                             mBatchCancel);
511*ec779b8eSAndroid Build Coastguard Worker                     return -1;
512*ec779b8eSAndroid Build Coastguard Worker                 }
513*ec779b8eSAndroid Build Coastguard Worker                 ret += event_ret;
514*ec779b8eSAndroid Build Coastguard Worker                 for (int j = 0; j < this_events; j++) {
515*ec779b8eSAndroid Build Coastguard Worker                     // struct io_event contains a pointer to the associated struct iocb as a __u64.
516*ec779b8eSAndroid Build Coastguard Worker                     if (static_cast<__u64>(ioevs[j].res) <
517*ec779b8eSAndroid Build Coastguard Worker                             reinterpret_cast<struct iocb*>(ioevs[j].obj)->aio_nbytes) {
518*ec779b8eSAndroid Build Coastguard Worker                         // We've found a short event. Store the index since
519*ec779b8eSAndroid Build Coastguard Worker                         // events won't necessarily arrive in the order they are queued.
520*ec779b8eSAndroid Build Coastguard Worker                         short_i = (ioevs[j].obj - reinterpret_cast<uint64_t>(mIobuf[i].iocbs.data()))
521*ec779b8eSAndroid Build Coastguard Worker                             / sizeof(struct iocb) + 1;
522*ec779b8eSAndroid Build Coastguard Worker                         short_packet = true;
523*ec779b8eSAndroid Build Coastguard Worker                     }
524*ec779b8eSAndroid Build Coastguard Worker                 }
525*ec779b8eSAndroid Build Coastguard Worker             }
526*ec779b8eSAndroid Build Coastguard Worker             if (short_packet) {
527*ec779b8eSAndroid Build Coastguard Worker                 if (cancelEvents(mIobuf[i].iocb.data(), ioevs, short_i, mIobuf[i].actual,
528*ec779b8eSAndroid Build Coastguard Worker                         mBatchCancel)) {
529*ec779b8eSAndroid Build Coastguard Worker                     write_error = true;
530*ec779b8eSAndroid Build Coastguard Worker                 }
531*ec779b8eSAndroid Build Coastguard Worker             }
532*ec779b8eSAndroid Build Coastguard Worker             if (file_length == MAX_MTP_FILE_SIZE) {
533*ec779b8eSAndroid Build Coastguard Worker                 // For larger files, receive until a short packet is received.
534*ec779b8eSAndroid Build Coastguard Worker                 if (static_cast<size_t>(ret) < length) {
535*ec779b8eSAndroid Build Coastguard Worker                     file_length = 0;
536*ec779b8eSAndroid Build Coastguard Worker                 }
537*ec779b8eSAndroid Build Coastguard Worker             } else if (ret < static_cast<int>(length)) {
538*ec779b8eSAndroid Build Coastguard Worker                 // If file is less than 4G and we get a short packet, it's an error.
539*ec779b8eSAndroid Build Coastguard Worker                 errno = EIO;
540*ec779b8eSAndroid Build Coastguard Worker                 LOG(ERROR) << "Mtp got unexpected short packet";
541*ec779b8eSAndroid Build Coastguard Worker                 return -1;
542*ec779b8eSAndroid Build Coastguard Worker             } else {
543*ec779b8eSAndroid Build Coastguard Worker                 file_length -= ret;
544*ec779b8eSAndroid Build Coastguard Worker             }
545*ec779b8eSAndroid Build Coastguard Worker 
546*ec779b8eSAndroid Build Coastguard Worker             if (write_error) {
547*ec779b8eSAndroid Build Coastguard Worker                 cancelTransaction();
548*ec779b8eSAndroid Build Coastguard Worker                 return -1;
549*ec779b8eSAndroid Build Coastguard Worker             }
550*ec779b8eSAndroid Build Coastguard Worker 
551*ec779b8eSAndroid Build Coastguard Worker             // Enqueue a new write request
552*ec779b8eSAndroid Build Coastguard Worker             aio_prepare(&aio, mIobuf[i].bufs.data(), ret, offset);
553*ec779b8eSAndroid Build Coastguard Worker             aio_write(&aio);
554*ec779b8eSAndroid Build Coastguard Worker 
555*ec779b8eSAndroid Build Coastguard Worker             offset += ret;
556*ec779b8eSAndroid Build Coastguard Worker             i = (i + 1) % NUM_IO_BUFS;
557*ec779b8eSAndroid Build Coastguard Worker             has_write = true;
558*ec779b8eSAndroid Build Coastguard Worker         }
559*ec779b8eSAndroid Build Coastguard Worker     }
560*ec779b8eSAndroid Build Coastguard Worker     if ((ret % packet_size == 0 && !short_packet) || zero_packet) {
561*ec779b8eSAndroid Build Coastguard Worker         // Receive an empty packet if size is a multiple of the endpoint size
562*ec779b8eSAndroid Build Coastguard Worker         // and we didn't already get an empty packet from the header or large file.
563*ec779b8eSAndroid Build Coastguard Worker         if (read(mIobuf[0].bufs.data(), packet_size) != 0) {
564*ec779b8eSAndroid Build Coastguard Worker             return -1;
565*ec779b8eSAndroid Build Coastguard Worker         }
566*ec779b8eSAndroid Build Coastguard Worker     }
567*ec779b8eSAndroid Build Coastguard Worker     return 0;
568*ec779b8eSAndroid Build Coastguard Worker }
569*ec779b8eSAndroid Build Coastguard Worker 
sendFile(mtp_file_range mfr)570*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::sendFile(mtp_file_range mfr) {
571*ec779b8eSAndroid Build Coastguard Worker     uint64_t file_length = mfr.length;
572*ec779b8eSAndroid Build Coastguard Worker     uint32_t given_length = std::min(static_cast<uint64_t>(MAX_MTP_FILE_SIZE),
573*ec779b8eSAndroid Build Coastguard Worker             file_length + sizeof(mtp_data_header));
574*ec779b8eSAndroid Build Coastguard Worker     uint64_t offset = mfr.offset;
575*ec779b8eSAndroid Build Coastguard Worker     int packet_size = getPacketSize(mBulkIn);
576*ec779b8eSAndroid Build Coastguard Worker 
577*ec779b8eSAndroid Build Coastguard Worker     // If file_length is larger than a size_t, truncating would produce the wrong comparison.
578*ec779b8eSAndroid Build Coastguard Worker     // Instead, promote the left side to 64 bits, then truncate the small result.
579*ec779b8eSAndroid Build Coastguard Worker     int init_read_len = std::min(
580*ec779b8eSAndroid Build Coastguard Worker             static_cast<uint64_t>(packet_size - sizeof(mtp_data_header)), file_length);
581*ec779b8eSAndroid Build Coastguard Worker 
582*ec779b8eSAndroid Build Coastguard Worker     advise(mfr.fd);
583*ec779b8eSAndroid Build Coastguard Worker 
584*ec779b8eSAndroid Build Coastguard Worker     struct aiocb aio;
585*ec779b8eSAndroid Build Coastguard Worker     aio.aio_fildes = mfr.fd;
586*ec779b8eSAndroid Build Coastguard Worker     struct aiocb *aiol[] = {&aio};
587*ec779b8eSAndroid Build Coastguard Worker     int ret = 0;
588*ec779b8eSAndroid Build Coastguard Worker     int length, num_read;
589*ec779b8eSAndroid Build Coastguard Worker     unsigned i = 0;
590*ec779b8eSAndroid Build Coastguard Worker     struct io_event ioevs[AIO_BUFS_MAX];
591*ec779b8eSAndroid Build Coastguard Worker     bool error = false;
592*ec779b8eSAndroid Build Coastguard Worker     bool has_write = false;
593*ec779b8eSAndroid Build Coastguard Worker 
594*ec779b8eSAndroid Build Coastguard Worker     // Send the header data
595*ec779b8eSAndroid Build Coastguard Worker     mtp_data_header *header = reinterpret_cast<mtp_data_header*>(mIobuf[0].bufs.data());
596*ec779b8eSAndroid Build Coastguard Worker     if (header == NULL) {
597*ec779b8eSAndroid Build Coastguard Worker         return -1;
598*ec779b8eSAndroid Build Coastguard Worker     }
599*ec779b8eSAndroid Build Coastguard Worker     header->length = htole32(given_length);
600*ec779b8eSAndroid Build Coastguard Worker     header->type = htole16(2); // data packet
601*ec779b8eSAndroid Build Coastguard Worker     header->command = htole16(mfr.command);
602*ec779b8eSAndroid Build Coastguard Worker     header->transaction_id = htole32(mfr.transaction_id);
603*ec779b8eSAndroid Build Coastguard Worker 
604*ec779b8eSAndroid Build Coastguard Worker     // Some hosts don't support header/data separation even though MTP allows it
605*ec779b8eSAndroid Build Coastguard Worker     // Handle by filling first packet with initial file data
606*ec779b8eSAndroid Build Coastguard Worker     if (TEMP_FAILURE_RETRY(pread(mfr.fd, mIobuf[0].bufs.data() +
607*ec779b8eSAndroid Build Coastguard Worker                     sizeof(mtp_data_header), init_read_len, offset))
608*ec779b8eSAndroid Build Coastguard Worker             != init_read_len) return -1;
609*ec779b8eSAndroid Build Coastguard Worker     if (doAsync(mIobuf[0].bufs.data(), sizeof(mtp_data_header) + init_read_len,
610*ec779b8eSAndroid Build Coastguard Worker                 false, false /* zlps are handled below */) == -1)
611*ec779b8eSAndroid Build Coastguard Worker         return -1;
612*ec779b8eSAndroid Build Coastguard Worker     file_length -= init_read_len;
613*ec779b8eSAndroid Build Coastguard Worker     offset += init_read_len;
614*ec779b8eSAndroid Build Coastguard Worker     ret = init_read_len + sizeof(mtp_data_header);
615*ec779b8eSAndroid Build Coastguard Worker 
616*ec779b8eSAndroid Build Coastguard Worker     // Break down the file into pieces that fit in buffers
617*ec779b8eSAndroid Build Coastguard Worker     while(file_length > 0 || has_write) {
618*ec779b8eSAndroid Build Coastguard Worker         if (file_length > 0) {
619*ec779b8eSAndroid Build Coastguard Worker             // Queue up a read from disk.
620*ec779b8eSAndroid Build Coastguard Worker             length = std::min(static_cast<uint64_t>(MAX_FILE_CHUNK_SIZE), file_length);
621*ec779b8eSAndroid Build Coastguard Worker             aio_prepare(&aio, mIobuf[i].bufs.data(), length, offset);
622*ec779b8eSAndroid Build Coastguard Worker             aio_read(&aio);
623*ec779b8eSAndroid Build Coastguard Worker         }
624*ec779b8eSAndroid Build Coastguard Worker 
625*ec779b8eSAndroid Build Coastguard Worker         if (has_write) {
626*ec779b8eSAndroid Build Coastguard Worker             // Wait for usb write. Cancel unwritten portion if there's an error.
627*ec779b8eSAndroid Build Coastguard Worker             int num_events = 0;
628*ec779b8eSAndroid Build Coastguard Worker             if (waitEvents(&mIobuf[(i-1)%NUM_IO_BUFS], mIobuf[(i-1)%NUM_IO_BUFS].actual, ioevs,
629*ec779b8eSAndroid Build Coastguard Worker                         &num_events) != ret) {
630*ec779b8eSAndroid Build Coastguard Worker                 error = true;
631*ec779b8eSAndroid Build Coastguard Worker                 cancelEvents(mIobuf[(i-1)%NUM_IO_BUFS].iocb.data(), ioevs, num_events,
632*ec779b8eSAndroid Build Coastguard Worker                         mIobuf[(i-1)%NUM_IO_BUFS].actual, false);
633*ec779b8eSAndroid Build Coastguard Worker             }
634*ec779b8eSAndroid Build Coastguard Worker             has_write = false;
635*ec779b8eSAndroid Build Coastguard Worker         }
636*ec779b8eSAndroid Build Coastguard Worker 
637*ec779b8eSAndroid Build Coastguard Worker         if (file_length > 0) {
638*ec779b8eSAndroid Build Coastguard Worker             // Wait for the previous read to finish
639*ec779b8eSAndroid Build Coastguard Worker             aio_suspend(aiol, 1, nullptr);
640*ec779b8eSAndroid Build Coastguard Worker             num_read = aio_return(&aio);
641*ec779b8eSAndroid Build Coastguard Worker             if (static_cast<size_t>(num_read) < aio.aio_nbytes) {
642*ec779b8eSAndroid Build Coastguard Worker                 errno = num_read == -1 ? aio_error(&aio) : EIO;
643*ec779b8eSAndroid Build Coastguard Worker                 PLOG(ERROR) << "Mtp error reading from disk";
644*ec779b8eSAndroid Build Coastguard Worker                 cancelTransaction();
645*ec779b8eSAndroid Build Coastguard Worker                 return -1;
646*ec779b8eSAndroid Build Coastguard Worker             }
647*ec779b8eSAndroid Build Coastguard Worker 
648*ec779b8eSAndroid Build Coastguard Worker             file_length -= num_read;
649*ec779b8eSAndroid Build Coastguard Worker             offset += num_read;
650*ec779b8eSAndroid Build Coastguard Worker 
651*ec779b8eSAndroid Build Coastguard Worker             if (error) {
652*ec779b8eSAndroid Build Coastguard Worker                 return -1;
653*ec779b8eSAndroid Build Coastguard Worker             }
654*ec779b8eSAndroid Build Coastguard Worker 
655*ec779b8eSAndroid Build Coastguard Worker             // Queue up a write to usb.
656*ec779b8eSAndroid Build Coastguard Worker             if (iobufSubmit(&mIobuf[i], mBulkIn, num_read, false) == -1) {
657*ec779b8eSAndroid Build Coastguard Worker                 return -1;
658*ec779b8eSAndroid Build Coastguard Worker             }
659*ec779b8eSAndroid Build Coastguard Worker             has_write = true;
660*ec779b8eSAndroid Build Coastguard Worker             ret = num_read;
661*ec779b8eSAndroid Build Coastguard Worker         }
662*ec779b8eSAndroid Build Coastguard Worker 
663*ec779b8eSAndroid Build Coastguard Worker         i = (i + 1) % NUM_IO_BUFS;
664*ec779b8eSAndroid Build Coastguard Worker     }
665*ec779b8eSAndroid Build Coastguard Worker 
666*ec779b8eSAndroid Build Coastguard Worker     if (ret % packet_size == 0) {
667*ec779b8eSAndroid Build Coastguard Worker         // If the last packet wasn't short, send a final empty packet
668*ec779b8eSAndroid Build Coastguard Worker         if (write(mIobuf[0].bufs.data(), 0) != 0) {
669*ec779b8eSAndroid Build Coastguard Worker             return -1;
670*ec779b8eSAndroid Build Coastguard Worker         }
671*ec779b8eSAndroid Build Coastguard Worker     }
672*ec779b8eSAndroid Build Coastguard Worker     return 0;
673*ec779b8eSAndroid Build Coastguard Worker }
674*ec779b8eSAndroid Build Coastguard Worker 
sendEvent(mtp_event me)675*ec779b8eSAndroid Build Coastguard Worker int MtpFfsHandle::sendEvent(mtp_event me) {
676*ec779b8eSAndroid Build Coastguard Worker     // Mimic the behavior of f_mtp by sending the event async.
677*ec779b8eSAndroid Build Coastguard Worker     // Events aren't critical to the connection, so we don't need to check the return value.
678*ec779b8eSAndroid Build Coastguard Worker     char *temp = new char[me.length];
679*ec779b8eSAndroid Build Coastguard Worker     memcpy(temp, me.data, me.length);
680*ec779b8eSAndroid Build Coastguard Worker     me.data = temp;
681*ec779b8eSAndroid Build Coastguard Worker 
682*ec779b8eSAndroid Build Coastguard Worker     std::thread t([this, me]() { return this->doSendEvent(me); });
683*ec779b8eSAndroid Build Coastguard Worker 
684*ec779b8eSAndroid Build Coastguard Worker     // Store the thread object for later joining
685*ec779b8eSAndroid Build Coastguard Worker     mChildThreads.emplace_back(std::move(t));
686*ec779b8eSAndroid Build Coastguard Worker     return 0;
687*ec779b8eSAndroid Build Coastguard Worker }
688*ec779b8eSAndroid Build Coastguard Worker 
doSendEvent(mtp_event me)689*ec779b8eSAndroid Build Coastguard Worker void MtpFfsHandle::doSendEvent(mtp_event me) {
690*ec779b8eSAndroid Build Coastguard Worker     unsigned length = me.length;
691*ec779b8eSAndroid Build Coastguard Worker     int ret = ::write(mIntr, me.data, length);
692*ec779b8eSAndroid Build Coastguard Worker     if (static_cast<unsigned>(ret) != length)
693*ec779b8eSAndroid Build Coastguard Worker         PLOG(ERROR) << "Mtp error sending event thread!";
694*ec779b8eSAndroid Build Coastguard Worker     delete[] reinterpret_cast<char*>(me.data);
695*ec779b8eSAndroid Build Coastguard Worker }
696*ec779b8eSAndroid Build Coastguard Worker 
697*ec779b8eSAndroid Build Coastguard Worker } // namespace android
698*ec779b8eSAndroid Build Coastguard Worker 
699