1 /*
2 * Copyright (C) 2016 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 #define LOG_TAG "android_os_HwBlob"
19 #include <android-base/logging.h>
20
21 #include "android_os_HwBlob.h"
22
23 #include "android_os_HwParcel.h"
24 #include "android_os_NativeHandle.h"
25
26 #include <nativehelper/JNIHelp.h>
27 #include <android_runtime/AndroidRuntime.h>
28 #include <hidl/Status.h>
29 #include <nativehelper/ScopedLocalRef.h>
30 #include <nativehelper/ScopedPrimitiveArray.h>
31
32 #include "core_jni_helpers.h"
33
34 using android::AndroidRuntime;
35 using android::hardware::hidl_handle;
36 using android::hardware::hidl_string;
37
38 #define PACKAGE_PATH "android/os"
39 #define CLASS_NAME "HwBlob"
40 #define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
41
42 namespace android {
43
44 static struct fields_t {
45 jfieldID contextID;
46 jmethodID constructID;
47
48 } gFields;
49
50 // static
InitClass(JNIEnv * env)51 void JHwBlob::InitClass(JNIEnv *env) {
52 ScopedLocalRef<jclass> clazz(
53 env, FindClassOrDie(env, CLASS_PATH));
54
55 gFields.contextID =
56 GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
57
58 gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
59 }
60
61 // static
SetNativeContext(JNIEnv * env,jobject thiz,const sp<JHwBlob> & context)62 sp<JHwBlob> JHwBlob::SetNativeContext(
63 JNIEnv *env, jobject thiz, const sp<JHwBlob> &context) {
64 sp<JHwBlob> old = (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
65
66 if (context != nullptr) {
67 context->incStrong(nullptr /* id */);
68 }
69
70 if (old != nullptr) {
71 old->decStrong(nullptr /* id */);
72 }
73
74 env->SetLongField(thiz, gFields.contextID, (long)context.get());
75
76 return old;
77 }
78
79 // static
GetNativeContext(JNIEnv * env,jobject thiz)80 sp<JHwBlob> JHwBlob::GetNativeContext(JNIEnv *env, jobject thiz) {
81 return (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
82 }
83
JHwBlob(JNIEnv * env,jobject thiz,size_t size)84 JHwBlob::JHwBlob(JNIEnv *env, jobject thiz, size_t size)
85 : mBuffer(nullptr),
86 mSize(size),
87 mType(BlobType::GENERIC),
88 mOwnsBuffer(true),
89 mHandle(0) {
90 if (size > 0) {
91 mBuffer = calloc(size, 1);
92 }
93 }
94
~JHwBlob()95 JHwBlob::~JHwBlob() {
96 if (mOwnsBuffer) {
97 free(mBuffer);
98 mBuffer = nullptr;
99 }
100 }
101
setTo(const void * ptr,size_t handle)102 void JHwBlob::setTo(const void *ptr, size_t handle) {
103 CHECK_EQ(mSize, 0u);
104 CHECK(mBuffer == nullptr);
105
106 mBuffer = const_cast<void *>(ptr);
107 mSize = SIZE_MAX; // XXX
108 mOwnsBuffer = false;
109 mHandle = handle;
110 }
111
getHandle(size_t * handle) const112 status_t JHwBlob::getHandle(size_t *handle) const {
113 if (mOwnsBuffer) {
114 return INVALID_OPERATION;
115 }
116
117 *handle = mHandle;
118
119 return OK;
120 }
121
read(size_t offset,void * data,size_t size) const122 status_t JHwBlob::read(size_t offset, void *data, size_t size) const {
123 if (offset + size > mSize) {
124 return -ERANGE;
125 }
126
127 memcpy(data, (const uint8_t *)mBuffer + offset, size);
128
129 return OK;
130 }
131
write(size_t offset,const void * data,size_t size)132 status_t JHwBlob::write(size_t offset, const void *data, size_t size) {
133 if (offset + size > mSize) {
134 return -ERANGE;
135 }
136
137 memcpy((uint8_t *)mBuffer + offset, data, size);
138
139 return OK;
140 }
141
getString(size_t offset,const hidl_string ** s) const142 status_t JHwBlob::getString(size_t offset, const hidl_string **s) const {
143 if ((offset + sizeof(hidl_string)) > mSize) {
144 return -ERANGE;
145 }
146
147 *s = reinterpret_cast<const hidl_string *>(
148 (const uint8_t *)mBuffer + offset);
149
150 return OK;
151 }
152
data() const153 const void *JHwBlob::data() const {
154 return mBuffer;
155 }
156
data()157 void *JHwBlob::data() {
158 return mBuffer;
159 }
160
size() const161 size_t JHwBlob::size() const {
162 return mSize;
163 }
164
specializeBlobTo(BlobType type)165 void JHwBlob::specializeBlobTo(BlobType type) {
166 CHECK_EQ(static_cast<int>(mType), static_cast<int>(BlobType::GENERIC));
167 mType = type;
168 }
169
type() const170 JHwBlob::BlobType JHwBlob::type() const {
171 return mType;
172 }
173
putBlob(size_t offset,const sp<JHwBlob> & blob)174 status_t JHwBlob::putBlob(size_t offset, const sp<JHwBlob> &blob) {
175 size_t index = mSubBlobs.add();
176 BlobInfo *info = &mSubBlobs.editItemAt(index);
177
178 info->mOffset = offset;
179 info->mBlob = blob;
180
181 const void *data = blob->data();
182
183 return write(offset, &data, sizeof(data));
184 }
185
writeToParcel(hardware::Parcel * parcel) const186 status_t JHwBlob::writeToParcel(hardware::Parcel *parcel) const {
187 CHECK_EQ(static_cast<int>(mType), static_cast<int>(BlobType::GENERIC));
188
189 size_t handle = 0;
190 status_t err = parcel->writeBuffer(data(), size(), &handle);
191
192 if (err != OK) {
193 return err;
194 }
195
196 return writeSubBlobsToParcel(parcel, handle);
197 }
198
writeEmbeddedToParcel(hardware::Parcel * parcel,size_t parentHandle,size_t parentOffset) const199 status_t JHwBlob::writeEmbeddedToParcel(
200 hardware::Parcel *parcel,
201 size_t parentHandle,
202 size_t parentOffset) const {
203 size_t handle = 0;
204 status_t err = OK;
205
206 switch (mType) {
207 case BlobType::GENERIC: {
208 err = parcel->writeEmbeddedBuffer(data(), size(), &handle, parentHandle, parentOffset);
209 break;
210 }
211 case BlobType::NATIVE_HANDLE: {
212 err = parcel->writeEmbeddedNativeHandle(
213 static_cast<const native_handle *>(data()), parentHandle, parentOffset);
214
215 CHECK(mSubBlobs.empty());
216 break;
217 }
218 default: { err = INVALID_OPERATION; }
219 }
220
221 if (err != OK) {
222 return err;
223 }
224
225 return writeSubBlobsToParcel(parcel, handle);
226 }
227
writeSubBlobsToParcel(hardware::Parcel * parcel,size_t parentHandle) const228 status_t JHwBlob::writeSubBlobsToParcel(hardware::Parcel *parcel,
229 size_t parentHandle) const {
230 for (size_t i = 0; i < mSubBlobs.size(); ++i) {
231 const BlobInfo &info = mSubBlobs[i];
232 status_t err = info.mBlob->writeEmbeddedToParcel(parcel, parentHandle, info.mOffset);
233
234 if (err != OK) {
235 return err;
236 }
237 }
238
239 return OK;
240 }
241
242 // static
NewObject(JNIEnv * env,const void * ptr,size_t handle)243 jobject JHwBlob::NewObject(JNIEnv *env, const void *ptr, size_t handle) {
244 jobject obj = JHwBlob::NewObject(env, 0 /* size */);
245 JHwBlob::GetNativeContext(env, obj)->setTo(ptr, handle);
246
247 return obj;
248 }
249
250 // static
NewObject(JNIEnv * env,size_t size)251 jobject JHwBlob::NewObject(JNIEnv *env, size_t size) {
252 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
253
254 jmethodID constructID =
255 GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
256
257 // XXX Again cannot refer to gFields.constructID because InitClass may
258 // not have been called yet.
259
260 // Cases:
261 // - this originates from another process (something so large should not fit
262 // in the binder buffer, and it should be rejected by the binder driver)
263 // - if this is used in process, this code makes too many heap copies (in
264 // order to retrofit HIDL's scatter-gather format to java types) to
265 // justify passing such a large amount of data over this path. So the
266 // alternative (updating the constructor and other code to accept other
267 // types, should also probably not be taken in this case).
268 CHECK_LE(size, static_cast<size_t>(std::numeric_limits<jint>::max()));
269
270 return env->NewObject(clazz.get(), constructID, static_cast<jint>(size));
271 }
272
273 } // namespace android
274
275 ////////////////////////////////////////////////////////////////////////////////
276
277 using namespace android;
278
releaseNativeContext(void * nativeContext)279 static void releaseNativeContext(void *nativeContext) {
280 sp<JHwBlob> parcel = (JHwBlob *)nativeContext;
281
282 if (parcel != nullptr) {
283 parcel->decStrong(nullptr /* id */);
284 }
285 }
286
JHwBlob_native_init(JNIEnv * env,jclass)287 static jlong JHwBlob_native_init(JNIEnv *env, jclass /*clazz*/) {
288 JHwBlob::InitClass(env);
289
290 return reinterpret_cast<jlong>(&releaseNativeContext);
291 }
292
JHwBlob_native_setup(JNIEnv * env,jobject thiz,jint size)293 static void JHwBlob_native_setup(
294 JNIEnv *env, jobject thiz, jint size) {
295 sp<JHwBlob> context = new JHwBlob(env, thiz, size);
296
297 JHwBlob::SetNativeContext(env, thiz, context);
298 }
299
300 #define DEFINE_BLOB_GETTER(Suffix,Type) \
301 static Type JHwBlob_native_get ## Suffix( \
302 JNIEnv *env, jobject thiz, jlong offset) { \
303 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
304 \
305 Type x; \
306 status_t err = blob->read(offset, &x, sizeof(x)); \
307 \
308 if (err != OK) { \
309 signalExceptionForError(env, err); \
310 return 0; \
311 } \
312 \
313 return x; \
314 }
315
DEFINE_BLOB_GETTER(Int8,jbyte)316 DEFINE_BLOB_GETTER(Int8,jbyte)
317 DEFINE_BLOB_GETTER(Int16,jshort)
318 DEFINE_BLOB_GETTER(Int32,jint)
319 DEFINE_BLOB_GETTER(Int64,jlong)
320 DEFINE_BLOB_GETTER(Float,jfloat)
321 DEFINE_BLOB_GETTER(Double,jdouble)
322
323 static jboolean JHwBlob_native_getBool(
324 JNIEnv *env, jobject thiz, jlong offset) {
325 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
326
327 bool x;
328 status_t err = blob->read(offset, &x, sizeof(x));
329
330 if (err != OK) {
331 signalExceptionForError(env, err);
332 return 0;
333 }
334
335 return (jboolean)x;
336 }
337
JHwBlob_native_getString(JNIEnv * env,jobject thiz,jlong offset)338 static jstring JHwBlob_native_getString(
339 JNIEnv *env, jobject thiz, jlong offset) {
340 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
341
342 const hidl_string *s;
343 status_t err = blob->getString(offset, &s);
344
345 if (err != OK) {
346 signalExceptionForError(env, err);
347 return nullptr;
348 }
349
350 return env->NewStringUTF(s->c_str());
351 }
352
JHwBlob_native_getFieldHandle(JNIEnv * env,jobject thiz,jlong offset)353 static jlong JHwBlob_native_getFieldHandle(JNIEnv* env,
354 jobject thiz,
355 jlong offset) {
356 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
357
358 return reinterpret_cast<jlong>(blob->data()) + offset;
359 }
360
361 #define DEFINE_BLOB_ARRAY_COPIER(Suffix,Type,NewType) \
362 static void JHwBlob_native_copyTo ## Suffix ## Array( \
363 JNIEnv *env, \
364 jobject thiz, \
365 jlong offset, \
366 Type ## Array array, \
367 jint size) { \
368 if (array == nullptr) { \
369 jniThrowException(env, "java/lang/NullPointerException", nullptr); \
370 return; \
371 } \
372 \
373 if (env->GetArrayLength(array) < size) { \
374 signalExceptionForError(env, BAD_VALUE); \
375 return; \
376 } \
377 \
378 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
379 \
380 if ((offset + size * sizeof(Type)) > blob->size()) { \
381 signalExceptionForError(env, -ERANGE); \
382 return; \
383 } \
384 \
385 env->Set ## NewType ## ArrayRegion( \
386 array, \
387 0 /* start */, \
388 size, \
389 reinterpret_cast<const Type *>( \
390 static_cast<const uint8_t *>(blob->data()) + offset)); \
391 }
392
DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)393 DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
394 DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
395 DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
396 DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
397 DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
398 DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
399
400 static void JHwBlob_native_copyToBoolArray(
401 JNIEnv *env,
402 jobject thiz,
403 jlong offset,
404 jbooleanArray array,
405 jint size) {
406 if (array == nullptr) {
407 jniThrowException(env, "java/lang/NullPointerException", nullptr);
408 return;
409 }
410
411 if (env->GetArrayLength(array) < size) {
412 signalExceptionForError(env, BAD_VALUE);
413 return;
414 }
415
416 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
417
418 if ((offset + size * sizeof(bool)) > blob->size()) {
419 signalExceptionForError(env, -ERANGE);
420 return;
421 }
422
423 const bool *src =
424 reinterpret_cast<const bool *>(
425 static_cast<const uint8_t *>(blob->data()) + offset);
426
427 jboolean *dst = env->GetBooleanArrayElements(array, nullptr /* isCopy */);
428
429 for (jint i = 0; i < size; ++i) {
430 dst[i] = src[i];
431 }
432
433 env->ReleaseBooleanArrayElements(array, dst, 0 /* mode */);
434 dst = nullptr;
435 }
436
437 #define DEFINE_BLOB_PUTTER(Suffix,Type) \
438 static void JHwBlob_native_put ## Suffix( \
439 JNIEnv *env, jobject thiz, jlong offset, Type x) { \
440 \
441 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
442 \
443 status_t err = blob->write(offset, &x, sizeof(x)); \
444 \
445 if (err != OK) { \
446 signalExceptionForError(env, err); \
447 } \
448 }
449
DEFINE_BLOB_PUTTER(Int8,jbyte)450 DEFINE_BLOB_PUTTER(Int8,jbyte)
451 DEFINE_BLOB_PUTTER(Int16,jshort)
452 DEFINE_BLOB_PUTTER(Int32,jint)
453 DEFINE_BLOB_PUTTER(Int64,jlong)
454 DEFINE_BLOB_PUTTER(Float,jfloat)
455 DEFINE_BLOB_PUTTER(Double,jdouble)
456
457 static void JHwBlob_native_putBool(
458 JNIEnv *env, jobject thiz, jlong offset, jboolean x) {
459
460 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
461
462 bool b = (bool)x;
463 status_t err = blob->write(offset, &b, sizeof(b));
464
465 if (err != OK) {
466 signalExceptionForError(env, err);
467 }
468 }
469
JHwBlob_native_putString(JNIEnv * env,jobject thiz,jlong offset,jstring stringObj)470 static void JHwBlob_native_putString(
471 JNIEnv *env, jobject thiz, jlong offset, jstring stringObj) {
472 if (stringObj == nullptr) {
473 jniThrowException(env, "java/lang/NullPointerException", nullptr);
474 return;
475 }
476
477 const char *s = env->GetStringUTFChars(stringObj, nullptr);
478
479 if (s == nullptr) {
480 return;
481 }
482
483 size_t size = strlen(s) + 1;
484 ScopedLocalRef<jobject> subBlobObj(env, JHwBlob::NewObject(env, size));
485 sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, subBlobObj.get());
486 subBlob->write(0 /* offset */, s, size);
487
488 env->ReleaseStringUTFChars(stringObj, s);
489 s = nullptr;
490
491 hidl_string tmp;
492 tmp.setToExternal(static_cast<const char *>(subBlob->data()), size - 1);
493
494 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
495 blob->write(offset, &tmp, sizeof(tmp));
496 blob->putBlob(offset + hidl_string::kOffsetOfBuffer, subBlob);
497 }
498
JHwBlob_native_putNativeHandle(JNIEnv * env,jobject thiz,jlong offset,jobject jHandle)499 static void JHwBlob_native_putNativeHandle(JNIEnv *env, jobject thiz,
500 jlong offset, jobject jHandle) {
501 std::unique_ptr<native_handle_t, int(*)(native_handle_t*)> nativeHandle(
502 JNativeHandle::MakeCppNativeHandle(env, jHandle, nullptr /* storage */),
503 native_handle_delete);
504
505 size_t size = 0;
506 if (nativeHandle != nullptr) {
507 size = sizeof(native_handle_t) + nativeHandle->numFds * sizeof(int)
508 + nativeHandle->numInts * sizeof(int);
509 }
510
511 ScopedLocalRef<jobject> subBlobObj(env, JHwBlob::NewObject(env, size));
512 sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, subBlobObj.get());
513 subBlob->specializeBlobTo(JHwBlob::BlobType::NATIVE_HANDLE);
514 subBlob->write(0 /* offset */, nativeHandle.get(), size);
515
516 hidl_handle cppHandle;
517 cppHandle.setTo(static_cast<native_handle_t *>(subBlob->data()), false /* shouldOwn */);
518
519 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
520 blob->write(offset, &cppHandle, sizeof(cppHandle));
521 blob->putBlob(offset + hidl_handle::kOffsetOfNativeHandle, subBlob);
522 }
523
524 #define DEFINE_BLOB_ARRAY_PUTTER(Suffix,Type,NewType) \
525 static void JHwBlob_native_put ## Suffix ## Array( \
526 JNIEnv *env, jobject thiz, jlong offset, Type ## Array array) { \
527 Scoped ## NewType ## ArrayRO autoArray(env, array); \
528 \
529 if (array == nullptr) { \
530 /* NullpointerException already pending */ \
531 return; \
532 } \
533 \
534 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
535 \
536 status_t err = blob->write( \
537 offset, autoArray.get(), autoArray.size() * sizeof(Type)); \
538 \
539 if (err != OK) { \
540 signalExceptionForError(env, err); \
541 } \
542 }
543
DEFINE_BLOB_ARRAY_PUTTER(Int8,jbyte,Byte)544 DEFINE_BLOB_ARRAY_PUTTER(Int8,jbyte,Byte)
545 DEFINE_BLOB_ARRAY_PUTTER(Int16,jshort,Short)
546 DEFINE_BLOB_ARRAY_PUTTER(Int32,jint,Int)
547 DEFINE_BLOB_ARRAY_PUTTER(Int64,jlong,Long)
548 DEFINE_BLOB_ARRAY_PUTTER(Float,jfloat,Float)
549 DEFINE_BLOB_ARRAY_PUTTER(Double,jdouble,Double)
550
551 static void JHwBlob_native_putBoolArray(
552 JNIEnv *env, jobject thiz, jlong offset, jbooleanArray array) {
553 ScopedBooleanArrayRO autoArray(env, array);
554
555 if (array == nullptr) {
556 /* NullpointerException already pending */
557 return;
558 }
559
560 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
561
562 if ((offset + autoArray.size() * sizeof(bool)) > blob->size()) {
563 signalExceptionForError(env, -ERANGE);
564 return;
565 }
566
567 const jboolean *src = autoArray.get();
568
569 bool *dst = reinterpret_cast<bool *>(
570 static_cast<uint8_t *>(blob->data()) + offset);
571
572 for (size_t i = 0; i < autoArray.size(); ++i) {
573 dst[i] = src[i];
574 }
575 }
576
JHwBlob_native_putBlob(JNIEnv * env,jobject thiz,jlong offset,jobject blobObj)577 static void JHwBlob_native_putBlob(
578 JNIEnv *env, jobject thiz, jlong offset, jobject blobObj) {
579 if (blobObj == nullptr) {
580 jniThrowException(env, "java/lang/NullPointerException", nullptr);
581 return;
582 }
583
584 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
585 sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, blobObj);
586
587 blob->putBlob(offset, subBlob);
588 }
589
JHwBlob_native_handle(JNIEnv * env,jobject thiz)590 static jlong JHwBlob_native_handle(JNIEnv *env, jobject thiz) {
591 size_t handle;
592 status_t err = JHwBlob::GetNativeContext(env, thiz)->getHandle(&handle);
593
594 if (err != OK) {
595 signalExceptionForError(env, err);
596 return 0;
597 }
598
599 return handle;
600 }
601
602 static JNINativeMethod gMethods[] = {
603 { "native_init", "()J", (void *)JHwBlob_native_init },
604 { "native_setup", "(I)V", (void *)JHwBlob_native_setup },
605
606 { "getBool", "(J)Z", (void *)JHwBlob_native_getBool },
607 { "getInt8", "(J)B", (void *)JHwBlob_native_getInt8 },
608 { "getInt16", "(J)S", (void *)JHwBlob_native_getInt16 },
609 { "getInt32", "(J)I", (void *)JHwBlob_native_getInt32 },
610 { "getInt64", "(J)J", (void *)JHwBlob_native_getInt64 },
611 { "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
612 { "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
613 { "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
614 { "getFieldHandle", "(J)J", (void*) JHwBlob_native_getFieldHandle},
615
616 { "copyToBoolArray", "(J[ZI)V", (void *)JHwBlob_native_copyToBoolArray },
617 { "copyToInt8Array", "(J[BI)V", (void *)JHwBlob_native_copyToInt8Array },
618 { "copyToInt16Array", "(J[SI)V", (void *)JHwBlob_native_copyToInt16Array },
619 { "copyToInt32Array", "(J[II)V", (void *)JHwBlob_native_copyToInt32Array },
620 { "copyToInt64Array", "(J[JI)V", (void *)JHwBlob_native_copyToInt64Array },
621 { "copyToFloatArray", "(J[FI)V", (void *)JHwBlob_native_copyToFloatArray },
622 { "copyToDoubleArray", "(J[DI)V", (void *)JHwBlob_native_copyToDoubleArray },
623
624 { "putBool", "(JZ)V", (void *)JHwBlob_native_putBool },
625 { "putInt8", "(JB)V", (void *)JHwBlob_native_putInt8 },
626 { "putInt16", "(JS)V", (void *)JHwBlob_native_putInt16 },
627 { "putInt32", "(JI)V", (void *)JHwBlob_native_putInt32 },
628 { "putInt64", "(JJ)V", (void *)JHwBlob_native_putInt64 },
629 { "putFloat", "(JF)V", (void *)JHwBlob_native_putFloat },
630 { "putDouble", "(JD)V", (void *)JHwBlob_native_putDouble },
631 { "putString", "(JLjava/lang/String;)V", (void *)JHwBlob_native_putString },
632 { "putNativeHandle", "(JL" PACKAGE_PATH "/NativeHandle;)V",
633 (void*)JHwBlob_native_putNativeHandle },
634
635 { "putBoolArray", "(J[Z)V", (void *)JHwBlob_native_putBoolArray },
636 { "putInt8Array", "(J[B)V", (void *)JHwBlob_native_putInt8Array },
637 { "putInt16Array", "(J[S)V", (void *)JHwBlob_native_putInt16Array },
638 { "putInt32Array", "(J[I)V", (void *)JHwBlob_native_putInt32Array },
639 { "putInt64Array", "(J[J)V", (void *)JHwBlob_native_putInt64Array },
640 { "putFloatArray", "(J[F)V", (void *)JHwBlob_native_putFloatArray },
641 { "putDoubleArray", "(J[D)V", (void *)JHwBlob_native_putDoubleArray },
642
643 { "putBlob", "(JL" PACKAGE_PATH "/HwBlob;)V",
644 (void *)JHwBlob_native_putBlob },
645
646 { "handle", "()J", (void *)JHwBlob_native_handle },
647 };
648
649 namespace android {
650
register_android_os_HwBlob(JNIEnv * env)651 int register_android_os_HwBlob(JNIEnv *env) {
652 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
653 }
654
655 } // namespace android
656
657