Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc34eed5 authored by Mike Lockwood's avatar Mike Lockwood Committed by Android (Google) Code Review
Browse files

Merge "PTP: Improve performance and reliability of file importing"

parents 9803d7f8 954c2677
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -112,6 +112,25 @@ public final class Mtp
                    + "/storage/" + storageID + "/child");
        }

        /**
         * Used for copying files from device to host.
         * Constructs a Uri based on the ID of the device and object for the source file,
         * and the path for the destination file.
         * When passed to the ContentProvider.insert() method, the file will be transferred
         * to the specified destination directory and insert() will return a content Uri
         * for the new file in the MediaProvider.
         * ContentProvider.insert() will throw IllegalArgumentException if the destination
         * path is not in the external storage or internal media directory.
         */
        public static Uri getContentUriForImport(int deviceID, long objectID, String destPath) {
            if (destPath.length() == 0 || destPath.charAt(0) != '/') {
                throw new IllegalArgumentException(
                        "destPath must be a full path in getContentUriForImport");
            }
            return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID
                    + "/import/" + objectID + "?" +  destPath);
        }

        /**
         * The following columns correspond to the fields in the ObjectInfo dataset
         * as described in the MTP specification.
+5 −5
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package android.media;

import android.os.ParcelFileDescriptor;
import android.util.Log;

/**
@@ -69,9 +68,10 @@ public class MtpClient {
        return native_get_storage_id(deviceID, objectID);
    }

    // create a file descriptor for reading the contents of an object over MTP
    public ParcelFileDescriptor openFile(int deviceID, long objectID) {
        return native_open_file(deviceID, objectID);
    // Reads a file from device to host to the specified destination.
    // Returns true if the transfer succeeds.
    public boolean importFile(int deviceID, long objectID, String destPath) {
        return native_import_file(deviceID, objectID, destPath);
    }

    public interface Listener {
@@ -104,5 +104,5 @@ public class MtpClient {
    private native boolean native_delete_object(int deviceID, long objectID);
    private native long native_get_parent(int deviceID, long objectID);
    private native long native_get_storage_id(int deviceID, long objectID);
    private native ParcelFileDescriptor native_open_file(int deviceID, long objectID);
    private native boolean native_import_file(int deviceID, long objectID, String destPath);
}
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ public final class MtpCursor extends AbstractWindowedCursor {
    public static final int OBJECT_ID           = 6;
    public static final int STORAGE_CHILDREN    = 7;
    public static final int OBJECT_CHILDREN     = 8;
    public static final int OBJECT_IMPORT       = 9;

    /** The names of the columns in the projection */
    private String[] mColumns;
+10 −53
Original line number Diff line number Diff line
@@ -39,19 +39,6 @@ static jmethodID method_deviceAdded;
static jmethodID method_deviceRemoved;
static jfieldID field_context;

static struct file_descriptor_offsets_t
{
    jclass mClass;
    jmethodID mConstructor;
    jfieldID mDescriptor;
} gFileDescriptorOffsets;

static struct parcel_file_descriptor_offsets_t
{
    jclass mClass;
    jmethodID mConstructor;
} gParcelFileDescriptorOffsets;

#ifdef HAVE_ANDROID_OS

static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -201,34 +188,19 @@ android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz,
        return -1;
}

static jobject
android_media_MtpClient_open_file(JNIEnv *env, jobject thiz,
        jint device_id, jlong object_id)
static jboolean
android_media_MtpClient_import_file(JNIEnv *env, jobject thiz,
        jint device_id, jlong object_id, jstring dest_path)
{
#ifdef HAVE_ANDROID_OS
    MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
    MtpDevice* device = client->getDevice(device_id);
    if (!device)
        return NULL;

    MtpObjectInfo* info = device->getObjectInfo(object_id);
    if (!info)
        return NULL;
    int object_size = info->mCompressedSize;
    delete info;
    int fd = device->readObject(object_id, object_size);
    if (fd < 0)
        return NULL;

    jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass,
        gFileDescriptorOffsets.mConstructor);
    if (fileDescriptor != NULL) {
        env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd);
    } else {
        return NULL;
    if (device) {
        const char *destPathStr = env->GetStringUTFChars(dest_path, NULL);
        bool result = device->readObject(object_id, destPathStr);
        env->ReleaseStringUTFChars(dest_path, destPathStr);
        return result;
    }
    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
        gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
#endif
    return NULL;
}
@@ -243,8 +215,8 @@ static JNINativeMethod gMethods[] = {
    {"native_delete_object",   "(IJ)Z", (void *)android_media_MtpClient_delete_object},
    {"native_get_parent",      "(IJ)J", (void *)android_media_MtpClient_get_parent},
    {"native_get_storage_id",  "(IJ)J", (void *)android_media_MtpClient_get_storage_id},
    {"native_open_file",       "(IJ)Landroid/os/ParcelFileDescriptor;",
                                        (void *)android_media_MtpClient_open_file},
    {"native_import_file",     "(IJLjava/lang/String;)Z",
                                        (void *)android_media_MtpClient_import_file},
};

static const char* const kClassPathName = "android/media/MtpClient";
@@ -276,21 +248,6 @@ int register_android_media_MtpClient(JNIEnv *env)
        return -1;
    }

   clazz = env->FindClass("java/io/FileDescriptor");
    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
    gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
    gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
    gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
    LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
                 "Unable to find descriptor field in java.io.FileDescriptor");

   clazz = env->FindClass("android/os/ParcelFileDescriptor");
    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
    gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
    gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
    LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
                 "Unable to find constructor for android.os.ParcelFileDescriptor");

    return AndroidRuntime::registerNativeMethods(env,
                "android/media/MtpClient", gMethods, NELEM(gMethods));
}
+17 −13
Original line number Diff line number Diff line
@@ -413,20 +413,32 @@ int MtpDataPacket::read(struct usb_endpoint *ep) {
}

int MtpDataPacket::readData(struct usb_endpoint *ep, void* buffer, int length) {
    int packetSize = usb_endpoint_max_packet(ep);
    int read = 0;
    while (read < length) {
        int ret = transfer(ep, (char *)buffer + read, packetSize);
        int ret = transfer(ep, (char *)buffer + read, length - read);
        if (ret < 0) {
printf("MtpDataPacket::readData returning %d\n", ret);
            return ret;
        }
        read += ret;
    }
printf("MtpDataPacket::readData returning %d\n", read);
    return read;
}

// Queue a read request.  Call readDataWait to wait for result
int MtpDataPacket::readDataAsync(struct usb_endpoint *ep, void* buffer, int length) {
    if (usb_endpoint_queue(ep, buffer, length)) {
        LOGE("usb_endpoint_queue failed, errno: %d", errno);
        return -1;
    }
    return 0;
}

// Wait for result of readDataAsync
int MtpDataPacket::readDataWait(struct usb_endpoint *ep) {
    int ep_num;
    return usb_endpoint_wait(usb_endpoint_get_device(ep), &ep_num);
}

int MtpDataPacket::readDataHeader(struct usb_endpoint *ep) {
    int length = transfer(ep, mBuffer, usb_endpoint_max_packet(ep));
    if (length >= 0)
@@ -454,15 +466,7 @@ int MtpDataPacket::write(struct usb_endpoint *ep) {
}

int MtpDataPacket::write(struct usb_endpoint *ep, void* buffer, uint32_t length) {
    int ret = 0;
    int packetSize = usb_endpoint_max_packet(ep);
    while (length > 0) {
        int write = (length > packetSize ? packetSize : length);
        int ret = transfer(ep, buffer, write);
        if (ret < 0)
            break;
        length -= ret;
    }
    int ret = transfer(ep, buffer, length);
    return (ret < 0 ? ret : 0);
}

Loading