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