android_mtp_MtpDevice.cpp 38 KB

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