MtpDevice.cpp revision b9ff444a7eaf7ffd43970c0477110c6808bd4a7c
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "MtpDevice" 18 19#include "MtpDebug.h" 20#include "MtpDevice.h" 21#include "MtpDeviceInfo.h" 22#include "MtpObjectInfo.h" 23#include "MtpProperty.h" 24#include "MtpStorageInfo.h" 25#include "MtpStringBuffer.h" 26#include "MtpUtils.h" 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <sys/types.h> 31#include <sys/ioctl.h> 32#include <sys/stat.h> 33#include <fcntl.h> 34#include <errno.h> 35#include <endian.h> 36 37#include <usbhost/usbhost.h> 38 39namespace android { 40 41MtpDevice::MtpDevice(struct usb_device* device, int interface, 42 struct usb_endpoint *ep_in, struct usb_endpoint *ep_out, 43 struct usb_endpoint *ep_intr) 44 : mDevice(device), 45 mInterface(interface), 46 mEndpointIn(ep_in), 47 mEndpointOut(ep_out), 48 mEndpointIntr(ep_intr), 49 mDeviceInfo(NULL), 50 mID(usb_device_get_unique_id(device)), 51 mSessionID(0), 52 mTransactionID(0) 53{ 54} 55 56MtpDevice::~MtpDevice() { 57 close(); 58 for (int i = 0; i < mDeviceProperties.size(); i++) 59 delete mDeviceProperties[i]; 60} 61 62void MtpDevice::initialize() { 63 openSession(); 64 mDeviceInfo = getDeviceInfo(); 65 if (mDeviceInfo) { 66 mDeviceInfo->print(); 67 68 if (mDeviceInfo->mDeviceProperties) { 69 int count = mDeviceInfo->mDeviceProperties->size(); 70 for (int i = 0; i < count; i++) { 71 MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; 72 MtpProperty* property = getDevicePropDesc(propCode); 73 if (property) { 74 property->print(); 75 mDeviceProperties.push(property); 76 } 77 } 78 } 79 } 80} 81 82void MtpDevice::close() { 83 if (mDevice) { 84 usb_device_release_interface(mDevice, mInterface); 85 usb_device_close(mDevice); 86 mDevice = NULL; 87 } 88} 89 90const char* MtpDevice::getDeviceName() { 91 if (mDevice) 92 return usb_device_get_name(mDevice); 93 else 94 return "???"; 95} 96 97bool MtpDevice::openSession() { 98 Mutex::Autolock autoLock(mMutex); 99 100 mSessionID = 0; 101 mTransactionID = 0; 102 MtpSessionID newSession = 1; 103 mRequest.reset(); 104 mRequest.setParameter(1, newSession); 105 if (!sendRequest(MTP_OPERATION_OPEN_SESSION)) 106 return false; 107 MtpResponseCode ret = readResponse(); 108 if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN) 109 newSession = mResponse.getParameter(1); 110 else if (ret != MTP_RESPONSE_OK) 111 return false; 112 113 mSessionID = newSession; 114 mTransactionID = 1; 115 return true; 116} 117 118bool MtpDevice::closeSession() { 119 // FIXME 120 return true; 121} 122 123MtpDeviceInfo* MtpDevice::getDeviceInfo() { 124 Mutex::Autolock autoLock(mMutex); 125 126 mRequest.reset(); 127 if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) 128 return NULL; 129 if (!readData()) 130 return NULL; 131 MtpResponseCode ret = readResponse(); 132 if (ret == MTP_RESPONSE_OK) { 133 MtpDeviceInfo* info = new MtpDeviceInfo; 134 info->read(mData); 135 return info; 136 } 137 return NULL; 138} 139 140MtpStorageIDList* MtpDevice::getStorageIDs() { 141 Mutex::Autolock autoLock(mMutex); 142 143 mRequest.reset(); 144 if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) 145 return NULL; 146 if (!readData()) 147 return NULL; 148 MtpResponseCode ret = readResponse(); 149 if (ret == MTP_RESPONSE_OK) { 150 return mData.getAUInt32(); 151 } 152 return NULL; 153} 154 155MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { 156 Mutex::Autolock autoLock(mMutex); 157 158 mRequest.reset(); 159 mRequest.setParameter(1, storageID); 160 if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) 161 return NULL; 162 if (!readData()) 163 return NULL; 164 MtpResponseCode ret = readResponse(); 165 if (ret == MTP_RESPONSE_OK) { 166 MtpStorageInfo* info = new MtpStorageInfo(storageID); 167 info->read(mData); 168 return info; 169 } 170 return NULL; 171} 172 173MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, 174 MtpObjectFormat format, MtpObjectHandle parent) { 175 Mutex::Autolock autoLock(mMutex); 176 177 mRequest.reset(); 178 mRequest.setParameter(1, storageID); 179 mRequest.setParameter(2, format); 180 mRequest.setParameter(3, parent); 181 if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES)) 182 return NULL; 183 if (!readData()) 184 return NULL; 185 MtpResponseCode ret = readResponse(); 186 if (ret == MTP_RESPONSE_OK) { 187 return mData.getAUInt32(); 188 } 189 return NULL; 190} 191 192MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { 193 Mutex::Autolock autoLock(mMutex); 194 195 // FIXME - we might want to add some caching here 196 197 mRequest.reset(); 198 mRequest.setParameter(1, handle); 199 if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO)) 200 return NULL; 201 if (!readData()) 202 return NULL; 203 MtpResponseCode ret = readResponse(); 204 if (ret == MTP_RESPONSE_OK) { 205 MtpObjectInfo* info = new MtpObjectInfo(handle); 206 info->read(mData); 207 return info; 208 } 209 return NULL; 210} 211 212void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { 213 Mutex::Autolock autoLock(mMutex); 214 215 mRequest.reset(); 216 mRequest.setParameter(1, handle); 217 if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) { 218 MtpResponseCode ret = readResponse(); 219 if (ret == MTP_RESPONSE_OK) { 220 return mData.getData(outLength); 221 } 222 } 223 outLength = 0; 224 return NULL; 225} 226 227MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) { 228 Mutex::Autolock autoLock(mMutex); 229 230 mRequest.reset(); 231 MtpObjectHandle parent = info->mParent; 232 if (parent == 0) 233 parent = MTP_PARENT_ROOT; 234 235 mRequest.setParameter(1, info->mStorageID); 236 mRequest.setParameter(2, info->mParent); 237 238 mData.putUInt32(info->mStorageID); 239 mData.putUInt16(info->mFormat); 240 mData.putUInt16(info->mProtectionStatus); 241 mData.putUInt32(info->mCompressedSize); 242 mData.putUInt16(info->mThumbFormat); 243 mData.putUInt32(info->mThumbCompressedSize); 244 mData.putUInt32(info->mThumbPixWidth); 245 mData.putUInt32(info->mThumbPixHeight); 246 mData.putUInt32(info->mImagePixWidth); 247 mData.putUInt32(info->mImagePixHeight); 248 mData.putUInt32(info->mImagePixDepth); 249 mData.putUInt32(info->mParent); 250 mData.putUInt16(info->mAssociationType); 251 mData.putUInt32(info->mAssociationDesc); 252 mData.putUInt32(info->mSequenceNumber); 253 mData.putString(info->mName); 254 255 char created[100], modified[100]; 256 formatDateTime(info->mDateCreated, created, sizeof(created)); 257 formatDateTime(info->mDateModified, modified, sizeof(modified)); 258 259 mData.putString(created); 260 mData.putString(modified); 261 if (info->mKeywords) 262 mData.putString(info->mKeywords); 263 else 264 mData.putEmptyString(); 265 266 if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) { 267 MtpResponseCode ret = readResponse(); 268 if (ret == MTP_RESPONSE_OK) { 269 info->mStorageID = mResponse.getParameter(1); 270 info->mParent = mResponse.getParameter(2); 271 info->mHandle = mResponse.getParameter(3); 272 return info->mHandle; 273 } 274 } 275 return (MtpObjectHandle)-1; 276} 277 278bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) { 279 Mutex::Autolock autoLock(mMutex); 280 281 int remaining = info->mCompressedSize; 282 mRequest.reset(); 283 mRequest.setParameter(1, info->mHandle); 284 if (sendRequest(MTP_OPERATION_SEND_OBJECT)) { 285 // send data header 286 writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining); 287 288 char buffer[65536]; 289 while (remaining > 0) { 290 int count = read(srcFD, buffer, sizeof(buffer)); 291 if (count > 0) { 292 int written = mData.write(mEndpointOut, buffer, count); 293 // FIXME check error 294 remaining -= count; 295 } else { 296 break; 297 } 298 } 299 } 300 MtpResponseCode ret = readResponse(); 301 return (remaining == 0 && ret == MTP_RESPONSE_OK); 302} 303 304bool MtpDevice::deleteObject(MtpObjectHandle handle) { 305 Mutex::Autolock autoLock(mMutex); 306 307 mRequest.reset(); 308 mRequest.setParameter(1, handle); 309 if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) { 310 MtpResponseCode ret = readResponse(); 311 if (ret == MTP_RESPONSE_OK) 312 return true; 313 } 314 return false; 315} 316 317MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) { 318 MtpObjectInfo* info = getObjectInfo(handle); 319 if (info) 320 return info->mParent; 321 else 322 return -1; 323} 324 325MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) { 326 MtpObjectInfo* info = getObjectInfo(handle); 327 if (info) 328 return info->mStorageID; 329 else 330 return -1; 331} 332 333MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { 334 Mutex::Autolock autoLock(mMutex); 335 336 mRequest.reset(); 337 mRequest.setParameter(1, code); 338 if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC)) 339 return NULL; 340 if (!readData()) 341 return NULL; 342 MtpResponseCode ret = readResponse(); 343 if (ret == MTP_RESPONSE_OK) { 344 MtpProperty* property = new MtpProperty; 345 property->read(mData); 346 return property; 347 } 348 return NULL; 349} 350 351// reads the object's data and writes it to the specified file path 352bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath) { 353 LOGD("readObject: %s", destPath); 354 int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC); 355 if (fd < 0) { 356 LOGE("open failed for %s", destPath); 357 return false; 358 } 359 360 Mutex::Autolock autoLock(mMutex); 361 bool result = false; 362 363 mRequest.reset(); 364 mRequest.setParameter(1, handle); 365 if (sendRequest(MTP_OPERATION_GET_OBJECT) 366 && mData.readDataHeader(mEndpointIn)) { 367 uint32_t length = mData.getContainerLength(); 368 if (length < MTP_CONTAINER_HEADER_SIZE) 369 goto fail; 370 length -= MTP_CONTAINER_HEADER_SIZE; 371 uint32_t remaining = length; 372 373 int initialDataLength = 0; 374 void* initialData = mData.getData(initialDataLength); 375 if (initialData) { 376 if (initialDataLength > 0) { 377 if (write(fd, initialData, initialDataLength) != initialDataLength) 378 goto fail; 379 remaining -= initialDataLength; 380 } 381 free(initialData); 382 } 383 384 // USB reads greater than 16K don't work 385 char buffer1[16384], buffer2[16384]; 386 char* readBuffer = buffer1; 387 char* writeBuffer = NULL; 388 int writeLength = 0; 389 390 while (remaining > 0 || writeBuffer) { 391 if (remaining > 0) { 392 // queue up a read request 393 int readSize = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining); 394 if (mData.readDataAsync(mEndpointIn, readBuffer, readSize)) { 395 LOGE("readDataAsync failed"); 396 goto fail; 397 } 398 } else { 399 readBuffer = NULL; 400 } 401 402 if (writeBuffer) { 403 // write previous buffer 404 if (write(fd, writeBuffer, writeLength) != writeLength) { 405 LOGE("write failed"); 406 // wait for pending read before failing 407 if (readBuffer) 408 mData.readDataWait(mEndpointIn); 409 goto fail; 410 } 411 writeBuffer = NULL; 412 } 413 414 // wait for read to complete 415 if (readBuffer) { 416 int read = mData.readDataWait(mEndpointIn); 417 if (read < 0) 418 goto fail; 419 420 writeBuffer = readBuffer; 421 writeLength = read; 422 remaining -= read; 423 readBuffer = (readBuffer == buffer1 ? buffer2 : buffer1); 424 } 425 } 426 427 MtpResponseCode response = readResponse(); 428 if (response == MTP_RESPONSE_OK) 429 result = true; 430 } 431 432fail: 433 ::close(fd); 434 return result; 435} 436 437bool MtpDevice::sendRequest(MtpOperationCode operation) { 438 LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); 439 mRequest.setOperationCode(operation); 440 if (mTransactionID > 0) 441 mRequest.setTransactionID(mTransactionID++); 442 int ret = mRequest.write(mEndpointOut); 443 mRequest.dump(); 444 return (ret > 0); 445} 446 447bool MtpDevice::sendData() { 448 LOGV("sendData\n"); 449 mData.setOperationCode(mRequest.getOperationCode()); 450 mData.setTransactionID(mRequest.getTransactionID()); 451 int ret = mData.write(mEndpointOut); 452 mData.dump(); 453 return (ret > 0); 454} 455 456bool MtpDevice::readData() { 457 mData.reset(); 458 int ret = mData.read(mEndpointIn); 459 LOGV("readData returned %d\n", ret); 460 if (ret >= MTP_CONTAINER_HEADER_SIZE) { 461 mData.dump(); 462 return true; 463 } 464 else { 465 LOGV("readResponse failed\n"); 466 return false; 467 } 468} 469 470bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) { 471 mData.setOperationCode(operation); 472 mData.setTransactionID(mRequest.getTransactionID()); 473 return (!mData.writeDataHeader(mEndpointOut, dataLength)); 474} 475 476MtpResponseCode MtpDevice::readResponse() { 477 LOGV("readResponse\n"); 478 int ret = mResponse.read(mEndpointIn); 479 if (ret >= MTP_CONTAINER_HEADER_SIZE) { 480 mResponse.dump(); 481 return mResponse.getResponseCode(); 482 } 483 else { 484 LOGD("readResponse failed\n"); 485 return -1; 486 } 487} 488 489} // namespace android 490