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