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, ¶meters); 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