MtpDevice.cpp revision 29357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47
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
41d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#if 0
4223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodstatic bool isMtpDevice(uint16_t vendor, uint16_t product) {
4323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Sandisk Sansa Fuze
4423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x0781 && product == 0x74c2)
4523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
4623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Samsung YP-Z5
4723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x04e8 && product == 0x503c)
4823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
4923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return false;
5023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
51d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#endif
5223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
5323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike LockwoodMtpDevice* MtpDevice::open(const char* deviceName, int fd) {
5423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_device *device = usb_device_new(deviceName, fd);
5523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (!device) {
5629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("usb_device_new failed for %s", deviceName);
5723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return NULL;
5823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
5923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_header* desc;
6123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_iter iter;
6223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_descriptor_iter_init(device, &iter);
6423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
6623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (desc->bDescriptorType == USB_DT_INTERFACE) {
6723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
6823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
7023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceSubClass == 1 && // Still Image Capture
7123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
7223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            {
7331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
7431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
75b8a805261bf0282e992d3608035e47d05a898710Steve Block                ALOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName);
7631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
7731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
7823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else if (interface->bInterfaceClass == 0xFF &&
7923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceSubClass == 0xFF &&
8023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceProtocol == 0) {
8123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char* interfaceName = usb_device_get_string(device, interface->iInterface);
8231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (!interfaceName) {
8323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
8431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                } else if (strcmp(interfaceName, "MTP")) {
8531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(interfaceName);
8631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    continue;
8731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
8831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(interfaceName);
8931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root
9023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // Looks like an android style MTP device
9131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
9231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
93b8a805261bf0282e992d3608035e47d05a898710Steve Block                ALOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName);
9431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
9531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
96d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood            }
97d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#if 0
98d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood             else {
9923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // look for special cased devices based on vendor/product ID
10023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // we are doing this mainly for testing purposes
10123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t vendor = usb_device_get_vendor_id(device);
10223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t product = usb_device_get_product_id(device);
10323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!isMtpDevice(vendor, product)) {
10423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // not an MTP or PTP device
10523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
10623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
10723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // request MTP OS string and descriptor
10823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // some music players need to see this before entering MTP mode.
10923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char buffer[256];
11023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                memset(buffer, 0, sizeof(buffer));
111f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                int ret = usb_device_control_transfer(device,
11223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
11323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
114f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                        0, buffer, sizeof(buffer), 0);
115f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
11623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ret > 0) {
11723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("got MTP string %s\n", buffer);
118f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                    ret = usb_device_control_transfer(device,
11923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
120f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                            0, 4, buffer, sizeof(buffer), 0);
12123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("OS descriptor got %d\n", ret);
12223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
12323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("no MTP string\n");
12423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
12523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
126d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#endif
12723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // if we got here, then we have a likely MTP or PTP device
12823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
12923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // interface should be followed by three endpoints
13023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep;
13123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_in_desc = NULL;
13223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_out_desc = NULL;
13323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
13423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            for (int i = 0; i < 3; i++) {
13523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
13623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
13729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("endpoints not found\n");
13831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    usb_device_close(device);
13923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    return NULL;
14023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
14123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
14223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
14323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc = ep;
14423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    else
14523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_out_desc = ep;
14623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
14723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
14823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep_intr_desc = ep;
14923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
15023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
15123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
15229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("endpoints not found\n");
15331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
15423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
15523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
15623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
15723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
15829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
15931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
16023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
16123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
16223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
16323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
16423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc, ep_out_desc, ep_intr_desc);
16523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            mtpDevice->initialize();
16623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            return mtpDevice;
16723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
16823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
16923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
17023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_device_close(device);
17129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    ALOGE("device not found");
17223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return NULL;
17323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
17423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface,
17642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_in,
17742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_out,
17842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_intr)
1795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
1805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
18142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1(NULL),
18242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2(NULL),
18342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestOut(NULL),
18442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIntr(NULL),
1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
1865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
187f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mTransactionID(0),
188f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse(false)
1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
19042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn1 = usb_request_new(device, ep_in);
19142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn2 = usb_request_new(device, ep_in);
19242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestOut = usb_request_new(device, ep_out);
19342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIntr = usb_request_new(device, ep_intr);
1945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1965ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
1975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
198a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++)
199a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
20042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn1);
20142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn2);
20242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestOut);
20342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIntr);
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
2075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
2095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
210a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
211a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
212a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
213a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
214a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2150c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
216a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
217a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
218a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
2195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
2235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
2245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
2255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
2265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
2275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2300c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
2310c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
2320c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
2330c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2340c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
235df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("***** DEVICE PROPERTIES *****\n");
2360c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
2370c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
2380c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
2390c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2400c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
2410c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
24231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    delete property;
2430c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2440c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2450c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2460c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2470c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2480c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
249df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("***** OBJECT PROPERTIES *****\n");
2500c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
2510c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
2520c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
253df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
2540c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
2550c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
2560c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                for (int j = 0; j < props->size(); j++) {
2570c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
25899e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
25931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    if (property) {
2600c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
26131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                        delete property;
26231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    } else {
26329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                        ALOGE("could not fetch property: %s",
2640c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
26531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    }
2660c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2670c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2680c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2690c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2700c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
2710c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
2735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
2745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
2755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
2765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
2775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
2800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
2835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
2845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
2855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
2875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
2885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
2895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
2915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
2925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
2935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
2945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
2965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
2975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
2985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
3015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
3025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
3035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3055ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
3060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
3105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
3165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3225ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
3230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
3275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
3380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
3435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
3495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3555ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
3565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
3570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
3625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
3635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
3645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3745ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
3750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3776afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
3786afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
3815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
3825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
3885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3943e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
3950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3973e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
3983e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
3993e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
4003e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
4013e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4023e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
4033e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
4043e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
4053e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
4063e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
4076afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4086afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
4100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
4140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
4150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
4160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
4180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
4190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
4210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
4220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
4230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
4250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
4260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
4270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
4280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
4320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
4330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
4340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
4350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
4360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
4430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
4440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
4450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
4460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
4470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
4490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
4520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
4640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
4670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
4680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
4690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
4720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
4730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
47442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int written = mData.write(mRequestOut, buffer, count);
4750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
4770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
4790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
4830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
4840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
4870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4896afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
4906afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
4916afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
4926afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
4936afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
4946afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
4956afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
4966afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
4976afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4986afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4996afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
5006afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
50131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
50231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle parent = info->mParent;
50331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
50431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return parent;
50531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5066afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
50731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5086afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5093e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
5106afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
5116afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
51231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
51331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle storageId = info->mStorageID;
51431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
51531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return storageId;
51631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5176afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
51831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5193e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
5203e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
52198693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
52298693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
52398693f674125484de8873d969c209276a6dd604bMike Lockwood
52498693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
52598693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
52698693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
52798693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
52898693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
52998693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
53098693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
53198693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
53298693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
53398693f674125484de8873d969c209276a6dd604bMike Lockwood    }
53498693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
53598693f674125484de8873d969c209276a6dd604bMike Lockwood
53698693f674125484de8873d969c209276a6dd604bMike Lockwood}
53798693f674125484de8873d969c209276a6dd604bMike Lockwood
538a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
5390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
541a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
542a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
543a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
544a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
545a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
546a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
547a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
548a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
549a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
550e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
551a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
552a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
553a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
554a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
555a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
55699e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
55798693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
55898693f674125484de8873d969c209276a6dd604bMike Lockwood
55998693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
56098693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
56199e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
56298693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
56398693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
56498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
56598693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
56698693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
56798693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
56898693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
56998693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
57098693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
57198693f674125484de8873d969c209276a6dd604bMike Lockwood    }
57298693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
57398693f674125484de8873d969c209276a6dd604bMike Lockwood}
57498693f674125484de8873d969c209276a6dd604bMike Lockwood
57523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle,
57623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        bool (* callback)(void* data, int offset, int length, void* clientData),
57723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int objectSize, void* clientData) {
57823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    Mutex::Autolock autoLock(mMutex);
57923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    bool result = false;
58023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
58123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.reset();
58223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.setParameter(1, handle);
58323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
58423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            && mData.readDataHeader(mRequestIn1)) {
58523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t length = mData.getContainerLength();
58623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
58729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("readObject error objectSize: %d, length: %d",
58823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    objectSize, length);
58923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            goto fail;
59023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
59123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
59223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t remaining = length;
59323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int offset = 0;
59423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
59523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int initialDataLength = 0;
59623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* initialData = mData.getData(initialDataLength);
59723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (initialData) {
59823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (initialDataLength > 0) {
59923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(initialData, 0, initialDataLength, clientData))
60023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
60123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                remaining -= initialDataLength;
60223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += initialDataLength;
60323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
60423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            free(initialData);
60523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
60623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
60723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        // USB reads greater than 16K don't work
60823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        char buffer1[16384], buffer2[16384];
60923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn1->buffer = buffer1;
61023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn2->buffer = buffer2;
61123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        struct usb_request* req = mRequestIn1;
61223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* writeBuffer = NULL;
61323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int writeLength = 0;
61423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
61523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        while (remaining > 0 || writeBuffer) {
61623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (remaining > 0) {
61723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // queue up a read request
61823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
61923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (mData.readDataAsync(req)) {
62029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("readDataAsync failed");
62123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
62223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
62323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else {
62423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req = NULL;
62523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
62623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
62723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (writeBuffer) {
62823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // write previous buffer
62923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(writeBuffer, offset, writeLength, clientData)) {
63029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("write failed");
63123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // wait for pending read before failing
63223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (req)
63323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        mData.readDataWait(mDevice);
63423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
63523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
63623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += writeLength;
63723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                writeBuffer = NULL;
63823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
63923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
64023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // wait for read to complete
64123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (req) {
64223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                int read = mData.readDataWait(mDevice);
64323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read < 0)
64423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
64523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
64623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
64723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
64823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
64923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
65023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
65123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
65223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
65323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
65423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
65523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
65623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
65723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        MtpResponseCode response = readResponse();
65823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (response == MTP_RESPONSE_OK)
65923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            result = true;
66023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
66123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
66223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodfail:
66323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return result;
66423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
66523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
66623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
667b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
66827afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
669b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("readObject: %s", destPath);
670b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
671b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
67229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("open failed for %s", destPath);
673b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
6740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
6750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
67627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
67727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
67827afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
67927afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
68027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
68127afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
682b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
683b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
6840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
685b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
686b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
687b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
68842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            && mData.readDataHeader(mRequestIn1)) {
689b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
690b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
691b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
693b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
694b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
695b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
696b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
697b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
698b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
69931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (write(fd, initialData, initialDataLength) != initialDataLength) {
70031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(initialData);
701b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
70231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
703b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
7040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
705b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
7060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
7070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
708b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
709b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
71042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1->buffer = buffer1;
71142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2->buffer = buffer2;
71242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        struct usb_request* req = mRequestIn1;
71342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        void* writeBuffer = NULL;
714b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
715b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
716b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
717b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
718b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
71942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
72042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                if (mData.readDataAsync(req)) {
72129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("readDataAsync failed");
722b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
723b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
7240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
72542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req = NULL;
7260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
7270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
728b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
729b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
730b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
73129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("write failed");
732b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
73342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                    if (req)
73442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                        mData.readDataWait(mDevice);
735b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
736b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
737b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
738b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
7390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
740b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
74142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            if (req) {
74242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int read = mData.readDataWait(mDevice);
743b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
744b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
7450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
74623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
74723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
74823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
74923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
75023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
75123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
75223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
75323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
754b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
755b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
756b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
757b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
758b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
759b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
7600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
761b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
762b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
763b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
764b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
7650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
766a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
7675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
7683856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
769f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    mReceivedResponse = false;
7705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
7715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
7725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
77342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mRequest.write(mRequestOut);
7745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
7755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
7793856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendData\n");
7805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
7815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
78242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.write(mRequestOut);
7835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
7845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
7885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
78942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.read(mRequestIn1);
7903856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("readData returned %d\n", ret);
7915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
792f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
793b8a805261bf0282e992d3608035e47d05a898710Steve Block            ALOGD("got response packet instead of data packet");
794f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // we got a response packet rather than data
795f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // copy it to mResponse
796f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mResponse.copyFrom(mData);
797f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mReceivedResponse = true;
798f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            return false;
799f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        }
8005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
8015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
8025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
8043856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("readResponse failed\n");
8055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
8065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
8100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
8110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
81242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    return (!mData.writeDataHeader(mRequestOut, dataLength));
8130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
8140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
8155ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
8163856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("readResponse\n");
817f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    if (mReceivedResponse) {
818f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse = false;
819f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        return mResponse.getResponseCode();
820f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    }
82142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mResponse.read(mRequestIn1);
8223d74457b66533b170606347e60628e55a2af255eMike Lockwood    // handle zero length packets, which might occur if the data transfer
8233d74457b66533b170606347e60628e55a2af255eMike Lockwood    // ends on a packet boundary
8243d74457b66533b170606347e60628e55a2af255eMike Lockwood    if (ret == 0)
8253d74457b66533b170606347e60628e55a2af255eMike Lockwood        ret = mResponse.read(mRequestIn1);
8265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
8275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
8285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
829f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    } else {
830b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("readResponse failed\n");
8315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
8325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
836