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