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