MtpDevice.cpp revision 99e393a39a31bfbdeb435462939519e2d0279433
15ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood/*
25ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
35ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *
45ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
55ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * you may not use this file except in compliance with the License.
65ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * You may obtain a copy of the License at
75ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *
85ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
95ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *
105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * Unless required by applicable law or agreed to in writing, software
115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * See the License for the specific language governing permissions and
145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * limitations under the License.
155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood */
165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
17a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood#define LOG_TAG "MtpDevice"
18b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood
19b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpDebug.h"
20b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpDevice.h"
21b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpDeviceInfo.h"
22b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpObjectInfo.h"
23b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpProperty.h"
24b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpStorageInfo.h"
25b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpStringBuffer.h"
260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood#include "MtpUtils.h"
27a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <stdio.h>
295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <stdlib.h>
305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/types.h>
315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/ioctl.h>
325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/stat.h>
335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <fcntl.h>
345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <errno.h>
350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood#include <endian.h>
365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <usbhost/usbhost.h>
385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodnamespace android {
405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
415ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface,
425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            struct usb_endpoint *ep_intr)
445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mEndpointIn(ep_in),
475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mEndpointOut(ep_out),
485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mEndpointIntr(ep_intr),
495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mID(usb_device_get_unique_id(device)),
515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mTransactionID(0)
535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
565ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
58a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++)
59a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
66a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
67a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
68a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
69a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
70a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
710c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
72a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
73a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
74a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
860c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
870c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
880c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
890c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
900c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
910c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** DEVICE PROPERTIES *****\n");
920c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
930c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
940c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
950c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
960c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
970c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
980c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
990c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
1000c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
1010c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
1020c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
1030c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
1040c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** OBJECT PROPERTIES *****\n");
1050c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
1060c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
1070c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
1080c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
1090c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
1100c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
1110c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                for (int j = 0; j < props->size(); j++) {
1120c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
11399e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
1140c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    if (property)
1150c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
1160c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    else
1170c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        LOGE("could not fetch property: %s",
1180c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
1190c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
1200c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
1210c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
1220c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
1230c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
1240c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
1255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
1265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
1275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
1285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
1295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
1305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
1330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
1365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
1375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
1385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
1405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
1415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
1445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
1455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
1465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
1495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
1505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
1545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
1555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1585ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
1590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
1635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
1695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
1705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
1715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
1760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
1805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
1865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
1910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
1955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
1965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
2025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
2095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
2100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
2145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
2155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
2165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
2175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
2235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2275ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
2280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2306afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
2316afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
2325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
2345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
2355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
2415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2473e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
2480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2503e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
2513e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
2523e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
2533e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
2543e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
2553e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
2563e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
2573e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
2583e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
2593e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
2606afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
2616afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
2620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
2630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
2660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
2670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
2680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
2690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
2710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
2720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
2740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
2750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
2760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
2770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
2780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
2790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
2800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
2810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
2820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
2830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
2840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
2850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
2860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
2870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
2880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
2890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
2910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
2920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
2930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
2950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
2960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
2970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
2980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
2990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
3000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
3030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
3040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
3050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
3060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
3070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
3080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
3090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
3110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
3120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
3140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
3170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
3180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
3190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
3200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
3210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
3220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
3240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
3250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
3260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
3270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                int written = mData.write(mEndpointOut, buffer, count);
3280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
3290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
3300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
3310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
3320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
3330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
3340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
3360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
3370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
3380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3396afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
3400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3426afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
3436afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
3446afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
3456afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
3466afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
3476afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
3486afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
3496afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
3506afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3516afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3526afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
3536afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3546afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3556afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mParent;
3566afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3576afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3586afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3593e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
3606afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
3616afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3626afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3636afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mStorageID;
3646afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3656afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3663e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
3673e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
36898693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
36998693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
37098693f674125484de8873d969c209276a6dd604bMike Lockwood
37198693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
37298693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
37398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
37498693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
37598693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
37698693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
37798693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
37898693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
37998693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
38098693f674125484de8873d969c209276a6dd604bMike Lockwood    }
38198693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
38298693f674125484de8873d969c209276a6dd604bMike Lockwood
38398693f674125484de8873d969c209276a6dd604bMike Lockwood}
38498693f674125484de8873d969c209276a6dd604bMike Lockwood
385a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
3860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
388a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
389a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
390a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
391a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
392a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
393a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
394a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
395a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
396a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
397e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
398a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
399a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
400a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
401a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
402a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
40399e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
40498693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
40598693f674125484de8873d969c209276a6dd604bMike Lockwood
40698693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
40798693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
40899e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
40998693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
41098693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
41198693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
41298693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
41398693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
41498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
41598693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
41698693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
41798693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
41898693f674125484de8873d969c209276a6dd604bMike Lockwood    }
41998693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
42098693f674125484de8873d969c209276a6dd604bMike Lockwood}
42198693f674125484de8873d969c209276a6dd604bMike Lockwood
422b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
42327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
424b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    LOGD("readObject: %s", destPath);
425b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
426b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
427b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        LOGE("open failed for %s", destPath);
428b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
43127afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
43227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
43327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
43427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
43527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
43627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
437b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
438b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
440b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
441b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
442b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
443b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            && mData.readDataHeader(mEndpointIn)) {
444b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
445b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
446b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
447b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
448b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
449b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
450b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
451b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
452b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
453b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
454b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, initialData, initialDataLength) != initialDataLength)
455b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
456b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
458b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
461b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
462b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
463b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char* readBuffer = buffer1;
464b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char* writeBuffer = NULL;
465b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
466b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
467b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
468b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
469b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
470b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                int readSize = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
471b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (mData.readDataAsync(mEndpointIn, readBuffer, readSize)) {
472b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("readDataAsync failed");
473b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
474b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
4750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
476b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                readBuffer = NULL;
4770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
479b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
480b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
481b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
482b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("write failed");
483b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
484b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    if (readBuffer)
485b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                        mData.readDataWait(mEndpointIn);
486b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
487b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
488b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
489b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
4900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
491b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
492b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (readBuffer) {
493b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                int read = mData.readDataWait(mEndpointIn);
494b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
495b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
4960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
497b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = readBuffer;
498b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeLength = read;
499b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= read;
500b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                readBuffer = (readBuffer == buffer1 ? buffer2 : buffer1);
501b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
502b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
503b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
504b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
505b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
506b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
5070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
508b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
509b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
510b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
511b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
5120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
513a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
5145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
515f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
5165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
5175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
5185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
5195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mRequest.write(mEndpointOut);
5205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
5215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
5225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
525f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendData\n");
5265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
5275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
5285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mData.write(mEndpointOut);
5295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
5305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
5315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
5345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
5355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mData.read(mEndpointIn);
536f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readData returned %d\n", ret);
5375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
5385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
5395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
5405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
542f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood        LOGV("readResponse failed\n");
5435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
5445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
5480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
5490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
5500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (!mData.writeDataHeader(mEndpointOut, dataLength));
5510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
5520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5535ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
554f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readResponse\n");
5555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mResponse.read(mEndpointIn);
5565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
5575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
5585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
5595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
561a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        LOGD("readResponse failed\n");
5625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
5635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
567