Change offset and size arguments of MtpDevice#getPartialObject to Java
long.

To represents full range of 32-bit unsigned integer, we should use
jlong instead of jint.

BUG=26284424

Change-Id: Id3fa9e3daa778c204ab8e38f821d454c709c317a
diff --git a/api/current.txt b/api/current.txt
index 4189409..5a85f6f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22556,7 +22556,7 @@
     method public int[] getObjectHandles(int, int, int);
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
-    method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
+    method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 35f4214..b203a92 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24103,7 +24103,7 @@
     method public int[] getObjectHandles(int, int, int);
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
-    method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
+    method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index f15ab58..335b783 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -22564,7 +22564,7 @@
     method public int[] getObjectHandles(int, int, int);
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
-    method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
+    method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index b692a18..5127408 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -218,6 +218,33 @@
     }
 
     /**
+     * Ensures that the argument long value is within the inclusive range.
+     *
+     * @param value a long value
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated long value
+     *
+     * @throws IllegalArgumentException if {@code value} was not within the range
+     */
+    public static long checkArgumentInRange(long value, long lower, long upper,
+            String valueName) {
+        if (value < lower) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
+        } else if (value > upper) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
+        }
+
+        return value;
+    }
+
+    /**
      * Ensures that the array is not {@code null}, and none of its elements are {@code null}.
      *
      * @param value an array of boxed objects
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index d24c5e8..4379a99 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -21,6 +21,8 @@
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
 
+import com.android.internal.util.Preconditions;
+
 import java.io.IOException;
 
 /**
@@ -164,12 +166,14 @@
      * of the data and speed of the devices.
      *
      * @param objectHandle handle of the object to read
-     * @param offset Start index of reading range.
-     * @param size Size of reading range.
+     * @param offset Start index of reading range. It must be a non-negative value at most
+     *     0xffffffff.
+     * @param size Size of reading range. It must be a non-negative value at most 0xffffffff. If
+     *     0xffffffff is specified, the method obtains the full bytes of object.
      * @param buffer Array to write data.
      * @return Size of bytes that are actually read.
      */
-    public int getPartialObject(int objectHandle, int offset, int size, byte[] buffer)
+    public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer)
             throws IOException {
         return native_get_partial_object(objectHandle, offset, size, buffer);
     }
@@ -340,8 +344,8 @@
     private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
     private native MtpObjectInfo native_get_object_info(int objectHandle);
     private native byte[] native_get_object(int objectHandle, int objectSize);
-    private native int native_get_partial_object(
-            int objectHandle, int offset, int objectSize, byte[] buffer) throws IOException;
+    private native long native_get_partial_object(
+            int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
     private native byte[] native_get_thumbnail(int objectHandle);
     private native boolean native_delete_object(int objectHandle);
     private native long native_get_parent(int objectHandle);
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 130dfe5..b1b3b62 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -372,12 +372,12 @@
     return nullptr;
 }
 
-static jint
+static jlong
 android_mtp_MtpDevice_get_partial_object(JNIEnv *env,
                                          jobject thiz,
                                          jint objectID,
-                                         jint offset,
-                                         jint size,
+                                         jlong offset,
+                                         jlong size,
                                          jbyteArray array)
 {
     if (!array) {
@@ -385,6 +385,22 @@
         return -1;
     }
 
+    if (offset < 0 || 0xffffffffL < offset) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                "Offset argument must be a 32-bit unsigned integer.");
+        return -1;
+    }
+
+    if (size < 0 || 0xffffffffL < size) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                "Size argument must be a 32-bit unsigned integer.");
+        return -1;
+    }
+
     MtpDevice* const device = get_device_from_object(env, thiz);
     if (!device) {
         jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
@@ -393,16 +409,13 @@
 
     JavaArrayWriter writer(env, array);
     uint32_t written_size;
-    bool success = device->readPartialObject(
+    const bool success = device->readPartialObject(
             objectID, offset, size, &written_size, JavaArrayWriter::writeTo, &writer);
     if (!success) {
         jniThrowException(env, "java/io/IOException", "Failed to read data.");
         return -1;
     }
-    // Note: assumption here is that a negative value will be treated as unsigned on the Java
-    //       level.
-    // TODO: Make sure that actually holds.
-    return static_cast<jint>(written_size);
+    return static_cast<jlong>(written_size);
 }
 
 static jbyteArray
@@ -615,7 +628,7 @@
     {"native_get_object_info",  "(I)Landroid/mtp/MtpObjectInfo;",
                                         (void *)android_mtp_MtpDevice_get_object_info},
     {"native_get_object",       "(II)[B",(void *)android_mtp_MtpDevice_get_object},
-    {"native_get_partial_object", "(III[B)I", (void *)android_mtp_MtpDevice_get_partial_object},
+    {"native_get_partial_object", "(IJJ[B)J", (void *)android_mtp_MtpDevice_get_partial_object},
     {"native_get_thumbnail",    "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail},
     {"native_delete_object",    "(I)Z", (void *)android_mtp_MtpDevice_delete_object},
     {"native_get_parent",       "(I)J", (void *)android_mtp_MtpDevice_get_parent},