Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // #define LOG_NDEBUG 0
     18 
     19 #define LOG_TAG "MtpDeviceJNI"
     20 #include "utils/Log.h"
     21 
     22 #include <stdio.h>
     23 #include <assert.h>
     24 #include <limits.h>
     25 #include <unistd.h>
     26 #include <fcntl.h>
     27 
     28 #include <memory>
     29 #include <string>
     30 
     31 #include "jni.h"
     32 #include "JNIHelp.h"
     33 #include "ScopedPrimitiveArray.h"
     34 
     35 #include "android_runtime/AndroidRuntime.h"
     36 #include "android_runtime/Log.h"
     37 #include "nativehelper/ScopedLocalRef.h"
     38 #include "private/android_filesystem_config.h"
     39 
     40 #include "MtpTypes.h"
     41 #include "MtpDevice.h"
     42 #include "MtpDeviceInfo.h"
     43 #include "MtpStorageInfo.h"
     44 #include "MtpObjectInfo.h"
     45 #include "MtpProperty.h"
     46 
     47 using namespace android;
     48 
     49 // ----------------------------------------------------------------------------
     50 
     51 namespace {
     52 
     53 static jfieldID field_context;
     54 
     55 jclass clazz_deviceInfo;
     56 jclass clazz_storageInfo;
     57 jclass clazz_objectInfo;
     58 jclass clazz_event;
     59 jclass clazz_io_exception;
     60 jclass clazz_operation_canceled_exception;
     61 
     62 jmethodID constructor_deviceInfo;
     63 jmethodID constructor_storageInfo;
     64 jmethodID constructor_objectInfo;
     65 jmethodID constructor_event;
     66 
     67 // MtpDeviceInfo fields
     68 static jfieldID field_deviceInfo_manufacturer;
     69 static jfieldID field_deviceInfo_model;
     70 static jfieldID field_deviceInfo_version;
     71 static jfieldID field_deviceInfo_serialNumber;
     72 static jfieldID field_deviceInfo_operationsSupported;
     73 static jfieldID field_deviceInfo_eventsSupported;
     74 
     75 // MtpStorageInfo fields
     76 static jfieldID field_storageInfo_storageId;
     77 static jfieldID field_storageInfo_maxCapacity;
     78 static jfieldID field_storageInfo_freeSpace;
     79 static jfieldID field_storageInfo_description;
     80 static jfieldID field_storageInfo_volumeIdentifier;
     81 
     82 // MtpObjectInfo fields
     83 static jfieldID field_objectInfo_handle;
     84 static jfieldID field_objectInfo_storageId;
     85 static jfieldID field_objectInfo_format;
     86 static jfieldID field_objectInfo_protectionStatus;
     87 static jfieldID field_objectInfo_compressedSize;
     88 static jfieldID field_objectInfo_thumbFormat;
     89 static jfieldID field_objectInfo_thumbCompressedSize;
     90 static jfieldID field_objectInfo_thumbPixWidth;
     91 static jfieldID field_objectInfo_thumbPixHeight;
     92 static jfieldID field_objectInfo_imagePixWidth;
     93 static jfieldID field_objectInfo_imagePixHeight;
     94 static jfieldID field_objectInfo_imagePixDepth;
     95 static jfieldID field_objectInfo_parent;
     96 static jfieldID field_objectInfo_associationType;
     97 static jfieldID field_objectInfo_associationDesc;
     98 static jfieldID field_objectInfo_sequenceNumber;
     99 static jfieldID field_objectInfo_name;
    100 static jfieldID field_objectInfo_dateCreated;
    101 static jfieldID field_objectInfo_dateModified;
    102 static jfieldID field_objectInfo_keywords;
    103 
    104 // MtpEvent fields
    105 static jfieldID field_event_eventCode;
    106 static jfieldID field_event_parameter1;
    107 static jfieldID field_event_parameter2;
    108 static jfieldID field_event_parameter3;
    109 
    110 class JavaArrayWriter {
    111 public:
    112     JavaArrayWriter(JNIEnv* env, jbyteArray array) :
    113         mEnv(env), mArray(array), mSize(mEnv->GetArrayLength(mArray)) {}
    114     bool write(void* data, uint32_t offset, uint32_t length) {
    115         if (static_cast<uint32_t>(mSize) < offset + length) {
    116             return false;
    117         }
    118         mEnv->SetByteArrayRegion(mArray, offset, length, static_cast<jbyte*>(data));
    119         return true;
    120     }
    121     static bool writeTo(void* data, uint32_t offset, uint32_t length, void* clientData) {
    122         return static_cast<JavaArrayWriter*>(clientData)->write(data, offset, length);
    123     }
    124 
    125 private:
    126     JNIEnv* mEnv;
    127     jbyteArray mArray;
    128     jsize mSize;
    129 };
    130 
    131 }
    132 
    133 MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
    134 {
    135     return (MtpDevice*)env->GetLongField(javaDevice, field_context);
    136 }
    137 
    138 void fill_jobject_from_object_info(JNIEnv* env, jobject object, MtpObjectInfo* objectInfo) {
    139     if (objectInfo->mHandle)
    140         env->SetIntField(object, field_objectInfo_handle, objectInfo->mHandle);
    141     if (objectInfo->mStorageID)
    142         env->SetIntField(object, field_objectInfo_storageId, objectInfo->mStorageID);
    143     if (objectInfo->mFormat)
    144         env->SetIntField(object, field_objectInfo_format, objectInfo->mFormat);
    145     if (objectInfo->mProtectionStatus)
    146         env->SetIntField(object, field_objectInfo_protectionStatus, objectInfo->mProtectionStatus);
    147     if (objectInfo->mCompressedSize)
    148         env->SetIntField(object, field_objectInfo_compressedSize, objectInfo->mCompressedSize);
    149     if (objectInfo->mThumbFormat)
    150         env->SetIntField(object, field_objectInfo_thumbFormat, objectInfo->mThumbFormat);
    151     if (objectInfo->mThumbCompressedSize) {
    152         env->SetIntField(object, field_objectInfo_thumbCompressedSize,
    153                 objectInfo->mThumbCompressedSize);
    154     }
    155     if (objectInfo->mThumbPixWidth)
    156         env->SetIntField(object, field_objectInfo_thumbPixWidth, objectInfo->mThumbPixWidth);
    157     if (objectInfo->mThumbPixHeight)
    158         env->SetIntField(object, field_objectInfo_thumbPixHeight, objectInfo->mThumbPixHeight);
    159     if (objectInfo->mImagePixWidth)
    160         env->SetIntField(object, field_objectInfo_imagePixWidth, objectInfo->mImagePixWidth);
    161     if (objectInfo->mImagePixHeight)
    162         env->SetIntField(object, field_objectInfo_imagePixHeight, objectInfo->mImagePixHeight);
    163     if (objectInfo->mImagePixDepth)
    164         env->SetIntField(object, field_objectInfo_imagePixDepth, objectInfo->mImagePixDepth);
    165     if (objectInfo->mParent)
    166         env->SetIntField(object, field_objectInfo_parent, objectInfo->mParent);
    167     if (objectInfo->mAssociationType)
    168         env->SetIntField(object, field_objectInfo_associationType, objectInfo->mAssociationType);
    169     if (objectInfo->mAssociationDesc)
    170         env->SetIntField(object, field_objectInfo_associationDesc, objectInfo->mAssociationDesc);
    171     if (objectInfo->mSequenceNumber)
    172         env->SetIntField(object, field_objectInfo_sequenceNumber, objectInfo->mSequenceNumber);
    173     if (objectInfo->mName)
    174         env->SetObjectField(object, field_objectInfo_name, env->NewStringUTF(objectInfo->mName));
    175     if (objectInfo->mDateCreated)
    176         env->SetLongField(object, field_objectInfo_dateCreated, objectInfo->mDateCreated * 1000LL);
    177     if (objectInfo->mDateModified) {
    178         env->SetLongField(object, field_objectInfo_dateModified,
    179                 objectInfo->mDateModified * 1000LL);
    180     }
    181     if (objectInfo->mKeywords) {
    182         env->SetObjectField(object, field_objectInfo_keywords,
    183             env->NewStringUTF(objectInfo->mKeywords));
    184     }
    185 }
    186 
    187 // ----------------------------------------------------------------------------
    188 
    189 static jboolean
    190 android_mtp_MtpDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, jint fd)
    191 {
    192     const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
    193     if (deviceNameStr == NULL) {
    194         return JNI_FALSE;
    195     }
    196 
    197     MtpDevice* device = MtpDevice::open(deviceNameStr, fd);
    198     env->ReleaseStringUTFChars(deviceName, deviceNameStr);
    199 
    200     if (device)
    201         env->SetLongField(thiz, field_context,  (jlong)device);
    202     return (jboolean)(device != NULL);
    203 }
    204 
    205 static void
    206 android_mtp_MtpDevice_close(JNIEnv *env, jobject thiz)
    207 {
    208     MtpDevice* device = get_device_from_object(env, thiz);
    209     if (device) {
    210         device->close();
    211         delete device;
    212         env->SetLongField(thiz, field_context, 0);
    213     }
    214 }
    215 
    216 static jobject
    217 android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz)
    218 {
    219     MtpDevice* device = get_device_from_object(env, thiz);
    220     if (!device) {
    221         ALOGD("android_mtp_MtpDevice_get_device_info device is null");
    222         return NULL;
    223     }
    224     std::unique_ptr<MtpDeviceInfo> deviceInfo(device->getDeviceInfo());
    225     if (!deviceInfo) {
    226         ALOGD("android_mtp_MtpDevice_get_device_info deviceInfo is null");
    227         return NULL;
    228     }
    229     jobject info = env->NewObject(clazz_deviceInfo, constructor_deviceInfo);
    230     if (info == NULL) {
    231         ALOGE("Could not create a MtpDeviceInfo object");
    232         return NULL;
    233     }
    234 
    235     if (deviceInfo->mManufacturer)
    236         env->SetObjectField(info, field_deviceInfo_manufacturer,
    237             env->NewStringUTF(deviceInfo->mManufacturer));
    238     if (deviceInfo->mModel)
    239         env->SetObjectField(info, field_deviceInfo_model,
    240             env->NewStringUTF(deviceInfo->mModel));
    241     if (deviceInfo->mVersion)
    242         env->SetObjectField(info, field_deviceInfo_version,
    243             env->NewStringUTF(deviceInfo->mVersion));
    244     if (deviceInfo->mSerial)
    245         env->SetObjectField(info, field_deviceInfo_serialNumber,
    246             env->NewStringUTF(deviceInfo->mSerial));
    247     assert(deviceInfo->mOperations);
    248     {
    249         const size_t size = deviceInfo->mOperations->size();
    250         ScopedLocalRef<jintArray> operations(env, static_cast<jintArray>(env->NewIntArray(size)));
    251         {
    252             ScopedIntArrayRW elements(env, operations.get());
    253             if (elements.get() == NULL) {
    254                 ALOGE("Could not create operationsSupported element.");
    255                 return NULL;
    256             }
    257             for (size_t i = 0; i < size; ++i) {
    258                 elements[i] = deviceInfo->mOperations->itemAt(i);
    259             }
    260             env->SetObjectField(info, field_deviceInfo_operationsSupported, operations.get());
    261         }
    262     }
    263     assert(deviceInfo->mEvents);
    264     {
    265         const size_t size = deviceInfo->mEvents->size();
    266         ScopedLocalRef<jintArray> events(env, static_cast<jintArray>(env->NewIntArray(size)));
    267         {
    268             ScopedIntArrayRW elements(env, events.get());
    269             if (elements.get() == NULL) {
    270                 ALOGE("Could not create eventsSupported element.");
    271                 return NULL;
    272             }
    273             for (size_t i = 0; i < size; ++i) {
    274                 elements[i] = deviceInfo->mEvents->itemAt(i);
    275             }
    276             env->SetObjectField(info, field_deviceInfo_eventsSupported, events.get());
    277         }
    278     }
    279 
    280     return info;
    281 }
    282 
    283 static jintArray
    284 android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz)
    285 {
    286     MtpDevice* device = get_device_from_object(env, thiz);
    287     if (!device)
    288         return NULL;
    289     MtpStorageIDList* storageIDs = device->getStorageIDs();
    290     if (!storageIDs)
    291         return NULL;
    292 
    293     int length = storageIDs->size();
    294     jintArray array = env->NewIntArray(length);
    295     // FIXME is this cast safe?
    296     env->SetIntArrayRegion(array, 0, length, (const jint *)storageIDs->array());
    297 
    298     delete storageIDs;
    299     return array;
    300 }
    301 
    302 static jobject
    303 android_mtp_MtpDevice_get_storage_info(JNIEnv *env, jobject thiz, jint storageID)
    304 {
    305     MtpDevice* device = get_device_from_object(env, thiz);
    306     if (!device)
    307         return NULL;
    308     MtpStorageInfo* storageInfo = device->getStorageInfo(storageID);
    309     if (!storageInfo)
    310         return NULL;
    311 
    312     jobject info = env->NewObject(clazz_storageInfo, constructor_storageInfo);
    313     if (info == NULL) {
    314         ALOGE("Could not create a MtpStorageInfo object");
    315         delete storageInfo;
    316         return NULL;
    317     }
    318 
    319     if (storageInfo->mStorageID)
    320         env->SetIntField(info, field_storageInfo_storageId, storageInfo->mStorageID);
    321     if (storageInfo->mMaxCapacity)
    322         env->SetLongField(info, field_storageInfo_maxCapacity, storageInfo->mMaxCapacity);
    323     if (storageInfo->mFreeSpaceBytes)
    324         env->SetLongField(info, field_storageInfo_freeSpace, storageInfo->mFreeSpaceBytes);
    325     if (storageInfo->mStorageDescription)
    326         env->SetObjectField(info, field_storageInfo_description,
    327             env->NewStringUTF(storageInfo->mStorageDescription));
    328     if (storageInfo->mVolumeIdentifier)
    329         env->SetObjectField(info, field_storageInfo_volumeIdentifier,
    330             env->NewStringUTF(storageInfo->mVolumeIdentifier));
    331 
    332     delete storageInfo;
    333     return info;
    334 }
    335 
    336 static jintArray
    337 android_mtp_MtpDevice_get_object_handles(JNIEnv *env, jobject thiz,
    338         jint storageID, jint format, jint objectID)
    339 {
    340     MtpDevice* device = get_device_from_object(env, thiz);
    341     if (!device)
    342         return NULL;
    343     MtpObjectHandleList* handles = device->getObjectHandles(storageID, format, objectID);
    344     if (!handles)
    345         return NULL;
    346 
    347     int length = handles->size();
    348     jintArray array = env->NewIntArray(length);
    349     // FIXME is this cast safe?
    350     env->SetIntArrayRegion(array, 0, length, (const jint *)handles->array());
    351 
    352     delete handles;
    353     return array;
    354 }
    355 
    356 static jobject
    357 android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID)
    358 {
    359     MtpDevice* device = get_device_from_object(env, thiz);
    360     if (!device)
    361         return NULL;
    362     MtpObjectInfo* objectInfo = device->getObjectInfo(objectID);
    363     if (!objectInfo)
    364         return NULL;
    365     jobject info = env->NewObject(clazz_objectInfo, constructor_objectInfo);
    366     if (info == NULL) {
    367         ALOGE("Could not create a MtpObjectInfo object");
    368         delete objectInfo;
    369         return NULL;
    370     }
    371 
    372     fill_jobject_from_object_info(env, info, objectInfo);
    373     delete objectInfo;
    374     return info;
    375 }
    376 
    377 bool check_uint32_arg(JNIEnv *env, const char* name, jlong value, uint32_t* out) {
    378     if (value < 0 || 0xffffffff < value) {
    379         jniThrowException(
    380                 env,
    381                 "java/lang/IllegalArgumentException",
    382                 (std::string("argument must be a 32-bit unsigned integer: ") + name).c_str());
    383         return false;
    384     }
    385     *out = static_cast<uint32_t>(value);
    386     return true;
    387 }
    388 
    389 static jbyteArray
    390 android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jlong objectSizeLong)
    391 {
    392     uint32_t objectSize;
    393     if (!check_uint32_arg(env, "objectSize", objectSizeLong, &objectSize)) {
    394         return nullptr;
    395     }
    396 
    397     MtpDevice* device = get_device_from_object(env, thiz);
    398     if (!device) {
    399         return nullptr;
    400     }
    401 
    402     ScopedLocalRef<jbyteArray> array(env, env->NewByteArray(objectSize));
    403     if (!array.get()) {
    404         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
    405         return nullptr;
    406     }
    407 
    408     JavaArrayWriter writer(env, array.get());
    409 
    410     if (device->readObject(objectID, JavaArrayWriter::writeTo, objectSize, &writer)) {
    411         return array.release();
    412     }
    413     return nullptr;
    414 }
    415 
    416 static jlong
    417 android_mtp_MtpDevice_get_partial_object(JNIEnv *env,
    418                                          jobject thiz,
    419                                          jint objectID,
    420                                          jlong offsetLong,
    421                                          jlong sizeLong,
    422                                          jbyteArray array)
    423 {
    424     if (!array) {
    425         jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null.");
    426         return -1;
    427     }
    428 
    429     uint32_t offset;
    430     uint32_t size;
    431     if (!check_uint32_arg(env, "offset", offsetLong, &offset) ||
    432             !check_uint32_arg(env, "size", sizeLong, &size)) {
    433         return -1;
    434     }
    435 
    436     MtpDevice* const device = get_device_from_object(env, thiz);
    437     if (!device) {
    438         jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
    439         return -1;
    440     }
    441 
    442     JavaArrayWriter writer(env, array);
    443     uint32_t written_size;
    444     const bool success = device->readPartialObject(
    445             objectID, offset, size, &written_size, JavaArrayWriter::writeTo, &writer);
    446     if (!success) {
    447         jniThrowException(env, "java/io/IOException", "Failed to read data.");
    448         return -1;
    449     }
    450     return static_cast<jlong>(written_size);
    451 }
    452 
    453 static jint
    454 android_mtp_MtpDevice_get_partial_object_64(JNIEnv *env,
    455                                             jobject thiz,
    456                                             jint objectID,
    457                                             jlong offset,
    458                                             jlong size,
    459                                             jbyteArray array) {
    460     if (!array) {
    461         jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null.");
    462         return -1;
    463     }
    464 
    465     if (offset < 0) {
    466         jniThrowException(
    467                 env,
    468                 "java/lang/IllegalArgumentException",
    469                 "Offset argument must not be a negative value.");
    470         return -1;
    471     }
    472 
    473     if (size < 0 || 0xffffffffL < size) {
    474         jniThrowException(
    475                 env,
    476                 "java/lang/IllegalArgumentException",
    477                 "Size argument must be a 32-bit unsigned integer.");
    478         return -1;
    479     }
    480 
    481     MtpDevice* const device = get_device_from_object(env, thiz);
    482     if (!device) {
    483         jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
    484         return -1;
    485     }
    486 
    487     const uint32_t native_object_handle = static_cast<uint32_t>(objectID);
    488     const uint64_t native_offset = static_cast<uint64_t>(offset);
    489     const uint32_t native_size = static_cast<uint32_t>(size);
    490 
    491     JavaArrayWriter writer(env, array);
    492     uint32_t written_size;
    493     const bool success = device->readPartialObject64(
    494             native_object_handle,
    495             native_offset,
    496             native_size,
    497             &written_size,
    498             JavaArrayWriter::writeTo,
    499             &writer);
    500     if (!success) {
    501         jniThrowException(env, "java/io/IOException", "Failed to read data.");
    502         return -1;
    503     }
    504     return static_cast<jint>(written_size);
    505 }
    506 
    507 static jbyteArray
    508 android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID)
    509 {
    510     MtpDevice* device = get_device_from_object(env, thiz);
    511     if (!device)
    512         return NULL;
    513 
    514     int length;
    515     void* thumbnail = device->getThumbnail(objectID, length);
    516     if (! thumbnail)
    517         return NULL;
    518     jbyteArray array = env->NewByteArray(length);
    519     env->SetByteArrayRegion(array, 0, length, (const jbyte *)thumbnail);
    520 
    521     free(thumbnail);
    522     return array;
    523 }
    524 
    525 static jboolean
    526 android_mtp_MtpDevice_delete_object(JNIEnv *env, jobject thiz, jint object_id)
    527 {
    528     MtpDevice* device = get_device_from_object(env, thiz);
    529     if (device && device->deleteObject(object_id)) {
    530         return JNI_TRUE;
    531     } else {
    532         return JNI_FALSE;
    533     }
    534 }
    535 
    536 static jint
    537 android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id)
    538 {
    539     MtpDevice* device = get_device_from_object(env, thiz);
    540     if (device)
    541         return static_cast<jint>(device->getParent(object_id));
    542     else
    543         return -1;
    544 }
    545 
    546 static jint
    547 android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id)
    548 {
    549     MtpDevice* device = get_device_from_object(env, thiz);
    550     if (device)
    551         return static_cast<jint>(device->getStorageID(object_id));
    552     else
    553         return -1;
    554 }
    555 
    556 static jboolean
    557 android_mtp_MtpDevice_import_file(JNIEnv *env, jobject thiz, jint object_id, jstring dest_path)
    558 {
    559     MtpDevice* device = get_device_from_object(env, thiz);
    560     if (device) {
    561         const char *destPathStr = env->GetStringUTFChars(dest_path, NULL);
    562         if (destPathStr == NULL) {
    563             return JNI_FALSE;
    564         }
    565 
    566         jboolean result = device->readObject(object_id, destPathStr, AID_SDCARD_RW, 0664);
    567         env->ReleaseStringUTFChars(dest_path, destPathStr);
    568         return result;
    569     }
    570 
    571     return JNI_FALSE;
    572 }
    573 
    574 static jboolean
    575 android_mtp_MtpDevice_import_file_to_fd(JNIEnv *env, jobject thiz, jint object_id, jint fd)
    576 {
    577     MtpDevice* device = get_device_from_object(env, thiz);
    578     if (device)
    579         return device->readObject(object_id, fd);
    580     else
    581         return JNI_FALSE;
    582 }
    583 
    584 static jboolean
    585 android_mtp_MtpDevice_send_object(
    586         JNIEnv *env, jobject thiz, jint object_id, jlong sizeLong, jint fd)
    587 {
    588     uint32_t size;
    589     if (!check_uint32_arg(env, "size", sizeLong, &size))
    590         return JNI_FALSE;
    591 
    592     MtpDevice* device = get_device_from_object(env, thiz);
    593     if (!device)
    594         return JNI_FALSE;
    595 
    596     return device->sendObject(object_id, size, fd);
    597 }
    598 
    599 static jobject
    600 android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
    601 {
    602     MtpDevice* device = get_device_from_object(env, thiz);
    603     if (!device) {
    604         return JNI_FALSE;
    605     }
    606 
    607     // Updating existing objects is not supported.
    608     if (env->GetIntField(info, field_objectInfo_handle) != -1) {
    609         return JNI_FALSE;
    610     }
    611 
    612     MtpObjectInfo* object_info = new MtpObjectInfo(-1);
    613     object_info->mStorageID = env->GetIntField(info, field_objectInfo_storageId);
    614     object_info->mFormat = env->GetIntField(info, field_objectInfo_format);
    615     object_info->mProtectionStatus = env->GetIntField(info, field_objectInfo_protectionStatus);
    616     object_info->mCompressedSize = env->GetIntField(info, field_objectInfo_compressedSize);
    617     object_info->mThumbFormat = env->GetIntField(info, field_objectInfo_thumbFormat);
    618     object_info->mThumbCompressedSize =
    619             env->GetIntField(info, field_objectInfo_thumbCompressedSize);
    620     object_info->mThumbPixWidth = env->GetIntField(info, field_objectInfo_thumbPixWidth);
    621     object_info->mThumbPixHeight = env->GetIntField(info, field_objectInfo_thumbPixHeight);
    622     object_info->mImagePixWidth = env->GetIntField(info, field_objectInfo_imagePixWidth);
    623     object_info->mImagePixHeight = env->GetIntField(info, field_objectInfo_imagePixHeight);
    624     object_info->mImagePixDepth = env->GetIntField(info, field_objectInfo_imagePixDepth);
    625     object_info->mParent = env->GetIntField(info, field_objectInfo_parent);
    626     object_info->mAssociationType = env->GetIntField(info, field_objectInfo_associationType);
    627     object_info->mAssociationDesc = env->GetIntField(info, field_objectInfo_associationDesc);
    628     object_info->mSequenceNumber = env->GetIntField(info, field_objectInfo_sequenceNumber);
    629 
    630     jstring name_jstring = (jstring) env->GetObjectField(info, field_objectInfo_name);
    631     if (name_jstring != NULL) {
    632         const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
    633         object_info->mName = strdup(name_string);
    634         env->ReleaseStringUTFChars(name_jstring, name_string);
    635     }
    636 
    637     object_info->mDateCreated = env->GetLongField(info, field_objectInfo_dateCreated) / 1000LL;
    638     object_info->mDateModified = env->GetLongField(info, field_objectInfo_dateModified) / 1000LL;
    639 
    640     jstring keywords_jstring = (jstring) env->GetObjectField(info, field_objectInfo_keywords);
    641     if (keywords_jstring != NULL) {
    642         const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
    643         object_info->mKeywords = strdup(keywords_string);
    644         env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
    645     }
    646 
    647     int object_handle = device->sendObjectInfo(object_info);
    648     if (object_handle == -1) {
    649         delete object_info;
    650         return NULL;
    651     }
    652 
    653     object_info->mHandle = object_handle;
    654     jobject result = env->NewObject(clazz_objectInfo, constructor_objectInfo);
    655     if (result == NULL) {
    656         ALOGE("Could not create a MtpObjectInfo object");
    657         delete object_info;
    658         return NULL;
    659     }
    660 
    661     fill_jobject_from_object_info(env, result, object_info);
    662     delete object_info;
    663     return result;
    664 }
    665 
    666 static jint android_mtp_MtpDevice_submit_event_request(JNIEnv *env, jobject thiz)
    667 {
    668     MtpDevice* const device = get_device_from_object(env, thiz);
    669     if (!device) {
    670         env->ThrowNew(clazz_io_exception, "");
    671         return -1;
    672     }
    673     return device->submitEventRequest();
    674 }
    675 
    676 static jobject android_mtp_MtpDevice_reap_event_request(JNIEnv *env, jobject thiz, jint seq)
    677 {
    678     MtpDevice* const device = get_device_from_object(env, thiz);
    679     if (!device) {
    680         env->ThrowNew(clazz_io_exception, "");
    681         return NULL;
    682     }
    683     uint32_t parameters[3];
    684     const int eventCode = device->reapEventRequest(seq, &parameters);
    685     if (eventCode <= 0) {
    686         env->ThrowNew(clazz_operation_canceled_exception, "");
    687         return NULL;
    688     }
    689     jobject result = env->NewObject(clazz_event, constructor_event);
    690     env->SetIntField(result, field_event_eventCode, eventCode);
    691     env->SetIntField(result, field_event_parameter1, static_cast<jint>(parameters[0]));
    692     env->SetIntField(result, field_event_parameter2, static_cast<jint>(parameters[1]));
    693     env->SetIntField(result, field_event_parameter3, static_cast<jint>(parameters[2]));
    694     return result;
    695 }
    696 
    697 static void android_mtp_MtpDevice_discard_event_request(JNIEnv *env, jobject thiz, jint seq)
    698 {
    699     MtpDevice* const device = get_device_from_object(env, thiz);
    700     if (!device) {
    701         return;
    702     }
    703     device->discardEventRequest(seq);
    704 }
    705 
    706 // Returns object size in 64-bit integer. If the MTP device does not support the property, it
    707 // throws IOException.
    708 static jlong android_mtp_MtpDevice_get_object_size_long(
    709         JNIEnv *env, jobject thiz, jint handle, jint format) {
    710     MtpDevice* const device = get_device_from_object(env, thiz);
    711     if (!device) {
    712         env->ThrowNew(clazz_io_exception, "Failed to obtain MtpDevice.");
    713         return 0;
    714     }
    715 
    716     std::unique_ptr<MtpProperty> property(
    717             device->getObjectPropDesc(MTP_PROPERTY_OBJECT_SIZE, format));
    718     if (!property) {
    719         env->ThrowNew(clazz_io_exception, "Failed to obtain property desc.");
    720         return 0;
    721     }
    722 
    723     if (property->getDataType() != MTP_TYPE_UINT64) {
    724         env->ThrowNew(clazz_io_exception, "Unexpected property data type.");
    725         return 0;
    726     }
    727 
    728     if (!device->getObjectPropValue(handle, property.get())) {
    729         env->ThrowNew(clazz_io_exception, "Failed to obtain property value.");
    730         return 0;
    731     }
    732 
    733     const jlong object_size = static_cast<jlong>(property->getCurrentValue().u.u64);
    734     if (object_size < 0) {
    735         env->ThrowNew(clazz_io_exception, "Object size is too large to express as jlong.");
    736         return 0;
    737     }
    738 
    739     return object_size;
    740 }
    741 
    742 // ----------------------------------------------------------------------------
    743 
    744 static const JNINativeMethod gMethods[] = {
    745     {"native_open",             "(Ljava/lang/String;I)Z",
    746                                         (void *)android_mtp_MtpDevice_open},
    747     {"native_close",            "()V",  (void *)android_mtp_MtpDevice_close},
    748     {"native_get_device_info",  "()Landroid/mtp/MtpDeviceInfo;",
    749                                         (void *)android_mtp_MtpDevice_get_device_info},
    750     {"native_get_storage_ids",  "()[I", (void *)android_mtp_MtpDevice_get_storage_ids},
    751     {"native_get_storage_info", "(I)Landroid/mtp/MtpStorageInfo;",
    752                                         (void *)android_mtp_MtpDevice_get_storage_info},
    753     {"native_get_object_handles","(III)[I",
    754                                         (void *)android_mtp_MtpDevice_get_object_handles},
    755     {"native_get_object_info",  "(I)Landroid/mtp/MtpObjectInfo;",
    756                                         (void *)android_mtp_MtpDevice_get_object_info},
    757     {"native_get_object",       "(IJ)[B",(void *)android_mtp_MtpDevice_get_object},
    758     {"native_get_partial_object", "(IJJ[B)J", (void *)android_mtp_MtpDevice_get_partial_object},
    759     {"native_get_partial_object_64", "(IJJ[B)I",
    760                                         (void *)android_mtp_MtpDevice_get_partial_object_64},
    761     {"native_get_thumbnail",    "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail},
    762     {"native_delete_object",    "(I)Z", (void *)android_mtp_MtpDevice_delete_object},
    763     {"native_get_parent",       "(I)I", (void *)android_mtp_MtpDevice_get_parent},
    764     {"native_get_storage_id",   "(I)I", (void *)android_mtp_MtpDevice_get_storage_id},
    765     {"native_import_file",      "(ILjava/lang/String;)Z",
    766                                         (void *)android_mtp_MtpDevice_import_file},
    767     {"native_import_file",      "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
    768     {"native_send_object",      "(IJI)Z",(void *)android_mtp_MtpDevice_send_object},
    769     {"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
    770                                         (void *)android_mtp_MtpDevice_send_object_info},
    771     {"native_submit_event_request",  "()I", (void *)android_mtp_MtpDevice_submit_event_request},
    772     {"native_reap_event_request",   "(I)Landroid/mtp/MtpEvent;",
    773                                             (void *)android_mtp_MtpDevice_reap_event_request},
    774     {"native_discard_event_request", "(I)V", (void *)android_mtp_MtpDevice_discard_event_request},
    775 
    776     {"native_get_object_size_long", "(II)J", (void *)android_mtp_MtpDevice_get_object_size_long},
    777 };
    778 
    779 int register_android_mtp_MtpDevice(JNIEnv *env)
    780 {
    781     jclass clazz;
    782 
    783     ALOGD("register_android_mtp_MtpDevice\n");
    784 
    785     clazz = env->FindClass("android/mtp/MtpDeviceInfo");
    786     if (clazz == NULL) {
    787         ALOGE("Can't find android/mtp/MtpDeviceInfo");
    788         return -1;
    789     }
    790     constructor_deviceInfo = env->GetMethodID(clazz, "<init>", "()V");
    791     if (constructor_deviceInfo == NULL) {
    792         ALOGE("Can't find android/mtp/MtpDeviceInfo constructor");
    793         return -1;
    794     }
    795     field_deviceInfo_manufacturer = env->GetFieldID(clazz, "mManufacturer", "Ljava/lang/String;");
    796     if (field_deviceInfo_manufacturer == NULL) {
    797         ALOGE("Can't find MtpDeviceInfo.mManufacturer");
    798         return -1;
    799     }
    800     field_deviceInfo_model = env->GetFieldID(clazz, "mModel", "Ljava/lang/String;");
    801     if (field_deviceInfo_model == NULL) {
    802         ALOGE("Can't find MtpDeviceInfo.mModel");
    803         return -1;
    804     }
    805     field_deviceInfo_version = env->GetFieldID(clazz, "mVersion", "Ljava/lang/String;");
    806     if (field_deviceInfo_version == NULL) {
    807         ALOGE("Can't find MtpDeviceInfo.mVersion");
    808         return -1;
    809     }
    810     field_deviceInfo_serialNumber = env->GetFieldID(clazz, "mSerialNumber", "Ljava/lang/String;");
    811     if (field_deviceInfo_serialNumber == NULL) {
    812         ALOGE("Can't find MtpDeviceInfo.mSerialNumber");
    813         return -1;
    814     }
    815     field_deviceInfo_operationsSupported = env->GetFieldID(clazz, "mOperationsSupported", "[I");
    816     if (field_deviceInfo_operationsSupported == NULL) {
    817         ALOGE("Can't find MtpDeviceInfo.mOperationsSupported");
    818         return -1;
    819     }
    820     field_deviceInfo_eventsSupported = env->GetFieldID(clazz, "mEventsSupported", "[I");
    821     if (field_deviceInfo_eventsSupported == NULL) {
    822         ALOGE("Can't find MtpDeviceInfo.mEventsSupported");
    823         return -1;
    824     }
    825     clazz_deviceInfo = (jclass)env->NewGlobalRef(clazz);
    826 
    827     clazz = env->FindClass("android/mtp/MtpStorageInfo");
    828     if (clazz == NULL) {
    829         ALOGE("Can't find android/mtp/MtpStorageInfo");
    830         return -1;
    831     }
    832     constructor_storageInfo = env->GetMethodID(clazz, "<init>", "()V");
    833     if (constructor_storageInfo == NULL) {
    834         ALOGE("Can't find android/mtp/MtpStorageInfo constructor");
    835         return -1;
    836     }
    837     field_storageInfo_storageId = env->GetFieldID(clazz, "mStorageId", "I");
    838     if (field_storageInfo_storageId == NULL) {
    839         ALOGE("Can't find MtpStorageInfo.mStorageId");
    840         return -1;
    841     }
    842     field_storageInfo_maxCapacity = env->GetFieldID(clazz, "mMaxCapacity", "J");
    843     if (field_storageInfo_maxCapacity == NULL) {
    844         ALOGE("Can't find MtpStorageInfo.mMaxCapacity");
    845         return -1;
    846     }
    847     field_storageInfo_freeSpace = env->GetFieldID(clazz, "mFreeSpace", "J");
    848     if (field_storageInfo_freeSpace == NULL) {
    849         ALOGE("Can't find MtpStorageInfo.mFreeSpace");
    850         return -1;
    851     }
    852     field_storageInfo_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;");
    853     if (field_storageInfo_description == NULL) {
    854         ALOGE("Can't find MtpStorageInfo.mDescription");
    855         return -1;
    856     }
    857     field_storageInfo_volumeIdentifier = env->GetFieldID(clazz, "mVolumeIdentifier", "Ljava/lang/String;");
    858     if (field_storageInfo_volumeIdentifier == NULL) {
    859         ALOGE("Can't find MtpStorageInfo.mVolumeIdentifier");
    860         return -1;
    861     }
    862     clazz_storageInfo = (jclass)env->NewGlobalRef(clazz);
    863 
    864     clazz = env->FindClass("android/mtp/MtpObjectInfo");
    865     if (clazz == NULL) {
    866         ALOGE("Can't find android/mtp/MtpObjectInfo");
    867         return -1;
    868     }
    869     constructor_objectInfo = env->GetMethodID(clazz, "<init>", "()V");
    870     if (constructor_objectInfo == NULL) {
    871         ALOGE("Can't find android/mtp/MtpObjectInfo constructor");
    872         return -1;
    873     }
    874     field_objectInfo_handle = env->GetFieldID(clazz, "mHandle", "I");
    875     if (field_objectInfo_handle == NULL) {
    876         ALOGE("Can't find MtpObjectInfo.mHandle");
    877         return -1;
    878     }
    879     field_objectInfo_storageId = env->GetFieldID(clazz, "mStorageId", "I");
    880     if (field_objectInfo_storageId == NULL) {
    881         ALOGE("Can't find MtpObjectInfo.mStorageId");
    882         return -1;
    883     }
    884     field_objectInfo_format = env->GetFieldID(clazz, "mFormat", "I");
    885     if (field_objectInfo_format == NULL) {
    886         ALOGE("Can't find MtpObjectInfo.mFormat");
    887         return -1;
    888     }
    889     field_objectInfo_protectionStatus = env->GetFieldID(clazz, "mProtectionStatus", "I");
    890     if (field_objectInfo_protectionStatus == NULL) {
    891         ALOGE("Can't find MtpObjectInfo.mProtectionStatus");
    892         return -1;
    893     }
    894     field_objectInfo_compressedSize = env->GetFieldID(clazz, "mCompressedSize", "I");
    895     if (field_objectInfo_compressedSize == NULL) {
    896         ALOGE("Can't find MtpObjectInfo.mCompressedSize");
    897         return -1;
    898     }
    899     field_objectInfo_thumbFormat = env->GetFieldID(clazz, "mThumbFormat", "I");
    900     if (field_objectInfo_thumbFormat == NULL) {
    901         ALOGE("Can't find MtpObjectInfo.mThumbFormat");
    902         return -1;
    903     }
    904     field_objectInfo_thumbCompressedSize = env->GetFieldID(clazz, "mThumbCompressedSize", "I");
    905     if (field_objectInfo_thumbCompressedSize == NULL) {
    906         ALOGE("Can't find MtpObjectInfo.mThumbCompressedSize");
    907         return -1;
    908     }
    909     field_objectInfo_thumbPixWidth = env->GetFieldID(clazz, "mThumbPixWidth", "I");
    910     if (field_objectInfo_thumbPixWidth == NULL) {
    911         ALOGE("Can't find MtpObjectInfo.mThumbPixWidth");
    912         return -1;
    913     }
    914     field_objectInfo_thumbPixHeight = env->GetFieldID(clazz, "mThumbPixHeight", "I");
    915     if (field_objectInfo_thumbPixHeight == NULL) {
    916         ALOGE("Can't find MtpObjectInfo.mThumbPixHeight");
    917         return -1;
    918     }
    919     field_objectInfo_imagePixWidth = env->GetFieldID(clazz, "mImagePixWidth", "I");
    920     if (field_objectInfo_imagePixWidth == NULL) {
    921         ALOGE("Can't find MtpObjectInfo.mImagePixWidth");
    922         return -1;
    923     }
    924     field_objectInfo_imagePixHeight = env->GetFieldID(clazz, "mImagePixHeight", "I");
    925     if (field_objectInfo_imagePixHeight == NULL) {
    926         ALOGE("Can't find MtpObjectInfo.mImagePixHeight");
    927         return -1;
    928     }
    929     field_objectInfo_imagePixDepth = env->GetFieldID(clazz, "mImagePixDepth", "I");
    930     if (field_objectInfo_imagePixDepth == NULL) {
    931         ALOGE("Can't find MtpObjectInfo.mImagePixDepth");
    932         return -1;
    933     }
    934     field_objectInfo_parent = env->GetFieldID(clazz, "mParent", "I");
    935     if (field_objectInfo_parent == NULL) {
    936         ALOGE("Can't find MtpObjectInfo.mParent");
    937         return -1;
    938     }
    939     field_objectInfo_associationType = env->GetFieldID(clazz, "mAssociationType", "I");
    940     if (field_objectInfo_associationType == NULL) {
    941         ALOGE("Can't find MtpObjectInfo.mAssociationType");
    942         return -1;
    943     }
    944     field_objectInfo_associationDesc = env->GetFieldID(clazz, "mAssociationDesc", "I");
    945     if (field_objectInfo_associationDesc == NULL) {
    946         ALOGE("Can't find MtpObjectInfo.mAssociationDesc");
    947         return -1;
    948     }
    949     field_objectInfo_sequenceNumber = env->GetFieldID(clazz, "mSequenceNumber", "I");
    950     if (field_objectInfo_sequenceNumber == NULL) {
    951         ALOGE("Can't find MtpObjectInfo.mSequenceNumber");
    952         return -1;
    953     }
    954     field_objectInfo_name = env->GetFieldID(clazz, "mName", "Ljava/lang/String;");
    955     if (field_objectInfo_name == NULL) {
    956         ALOGE("Can't find MtpObjectInfo.mName");
    957         return -1;
    958     }
    959     field_objectInfo_dateCreated = env->GetFieldID(clazz, "mDateCreated", "J");
    960     if (field_objectInfo_dateCreated == NULL) {
    961         ALOGE("Can't find MtpObjectInfo.mDateCreated");
    962         return -1;
    963     }
    964     field_objectInfo_dateModified = env->GetFieldID(clazz, "mDateModified", "J");
    965     if (field_objectInfo_dateModified == NULL) {
    966         ALOGE("Can't find MtpObjectInfo.mDateModified");
    967         return -1;
    968     }
    969     field_objectInfo_keywords = env->GetFieldID(clazz, "mKeywords", "Ljava/lang/String;");
    970     if (field_objectInfo_keywords == NULL) {
    971         ALOGE("Can't find MtpObjectInfo.mKeywords");
    972         return -1;
    973     }
    974     clazz_objectInfo = (jclass)env->NewGlobalRef(clazz);
    975 
    976     clazz = env->FindClass("android/mtp/MtpEvent");
    977     if (clazz == NULL) {
    978         ALOGE("Can't find android/mtp/MtpEvent");
    979         return -1;
    980     }
    981     constructor_event = env->GetMethodID(clazz, "<init>", "()V");
    982     if (constructor_event == NULL) {
    983         ALOGE("Can't find android/mtp/MtpEvent constructor");
    984         return -1;
    985     }
    986     field_event_eventCode = env->GetFieldID(clazz, "mEventCode", "I");
    987     if (field_event_eventCode == NULL) {
    988         ALOGE("Can't find MtpObjectInfo.mEventCode");
    989         return -1;
    990     }
    991     field_event_parameter1 = env->GetFieldID(clazz, "mParameter1", "I");
    992     if (field_event_parameter1 == NULL) {
    993         ALOGE("Can't find MtpObjectInfo.mParameter1");
    994         return -1;
    995     }
    996     field_event_parameter2 = env->GetFieldID(clazz, "mParameter2", "I");
    997     if (field_event_parameter2 == NULL) {
    998         ALOGE("Can't find MtpObjectInfo.mParameter2");
    999         return -1;
   1000     }
   1001     field_event_parameter3 = env->GetFieldID(clazz, "mParameter3", "I");
   1002     if (field_event_parameter3 == NULL) {
   1003         ALOGE("Can't find MtpObjectInfo.mParameter3");
   1004         return -1;
   1005     }
   1006     clazz_event = (jclass)env->NewGlobalRef(clazz);
   1007 
   1008     clazz = env->FindClass("android/mtp/MtpDevice");
   1009     if (clazz == NULL) {
   1010         ALOGE("Can't find android/mtp/MtpDevice");
   1011         return -1;
   1012     }
   1013     field_context = env->GetFieldID(clazz, "mNativeContext", "J");
   1014     if (field_context == NULL) {
   1015         ALOGE("Can't find MtpDevice.mNativeContext");
   1016         return -1;
   1017     }
   1018     clazz = env->FindClass("java/io/IOException");
   1019     if (clazz == NULL) {
   1020         ALOGE("Can't find java.io.IOException");
   1021         return -1;
   1022     }
   1023     clazz_io_exception = (jclass)env->NewGlobalRef(clazz);
   1024     clazz = env->FindClass("android/os/OperationCanceledException");
   1025     if (clazz == NULL) {
   1026         ALOGE("Can't find android.os.OperationCanceledException");
   1027         return -1;
   1028     }
   1029     clazz_operation_canceled_exception = (jclass)env->NewGlobalRef(clazz);
   1030 
   1031     return AndroidRuntime::registerNativeMethods(env,
   1032                 "android/mtp/MtpDevice", gMethods, NELEM(gMethods));
   1033 }
   1034