blob: b2dee0689ee0c78ec5289ee4293c34dcc16fdb78 [file] [log] [blame]
Andreas Huber50546a92016-08-25 11:21:21 -07001/*
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 <JNIHelp.h>
26#include <android_runtime/AndroidRuntime.h>
Martijn Coenen22fbcb42016-09-01 01:37:05 +020027#include <hidl/Status.h>
Andreas Huber50546a92016-08-25 11:21:21 -070028#include <nativehelper/ScopedLocalRef.h>
29
30#include "core_jni_helpers.h"
31
32using android::AndroidRuntime;
33using android::hardware::hidl_string;
34
35#define PACKAGE_PATH "android/os"
36#define CLASS_NAME "HwBlob"
37#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
38
39namespace android {
40
41static struct fields_t {
42 jfieldID contextID;
43 jmethodID constructID;
44
45} gFields;
46
47// static
48void JHwBlob::InitClass(JNIEnv *env) {
49 ScopedLocalRef<jclass> clazz(
50 env, FindClassOrDie(env, CLASS_PATH));
51
52 gFields.contextID =
53 GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
54
55 gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
56}
57
58// static
59sp<JHwBlob> JHwBlob::SetNativeContext(
60 JNIEnv *env, jobject thiz, const sp<JHwBlob> &context) {
61 sp<JHwBlob> old = (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
62
63 if (context != NULL) {
64 context->incStrong(NULL /* id */);
65 }
66
67 if (old != NULL) {
68 old->decStrong(NULL /* id */);
69 }
70
71 env->SetLongField(thiz, gFields.contextID, (long)context.get());
72
73 return old;
74}
75
76// static
77sp<JHwBlob> JHwBlob::GetNativeContext(JNIEnv *env, jobject thiz) {
78 return (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
79}
80
81JHwBlob::JHwBlob(JNIEnv *env, jobject thiz, size_t size)
82 : mBuffer(nullptr),
83 mSize(size),
84 mOwnsBuffer(true),
85 mHandle(0) {
86 jclass clazz = env->GetObjectClass(thiz);
87 CHECK(clazz != NULL);
88
89 mClass = (jclass)env->NewGlobalRef(clazz);
90 mObject = env->NewWeakGlobalRef(thiz);
91
92 if (size > 0) {
93 mBuffer = malloc(size);
94 }
95}
96
97JHwBlob::~JHwBlob() {
98 if (mOwnsBuffer) {
99 free(mBuffer);
100 mBuffer = nullptr;
101 }
102
103 JNIEnv *env = AndroidRuntime::getJNIEnv();
104
105 env->DeleteWeakGlobalRef(mObject);
106 mObject = NULL;
107
108 env->DeleteGlobalRef(mClass);
109 mClass = NULL;
110}
111
112void JHwBlob::setTo(const void *ptr, size_t handle) {
113 CHECK_EQ(mSize, 0u);
114 CHECK(mBuffer == nullptr);
115
116 mBuffer = const_cast<void *>(ptr);
117 mSize = SIZE_MAX; // XXX
118 mOwnsBuffer = false;
119 mHandle = handle;
120}
121
122status_t JHwBlob::getHandle(size_t *handle) const {
123 if (mOwnsBuffer) {
124 return INVALID_OPERATION;
125 }
126
127 *handle = mHandle;
128
129 return OK;
130}
131
132status_t JHwBlob::read(size_t offset, void *data, size_t size) const {
133 if (offset + size > mSize) {
134 return -ERANGE;
135 }
136
137 memcpy(data, (const uint8_t *)mBuffer + offset, size);
138
139 return OK;
140}
141
142status_t JHwBlob::write(size_t offset, const void *data, size_t size) {
143 if (offset + size > mSize) {
144 return -ERANGE;
145 }
146
147 memcpy((uint8_t *)mBuffer + offset, data, size);
148
149 return OK;
150}
151
152status_t JHwBlob::getString(size_t offset, const hidl_string **s) const {
153 if ((offset + sizeof(hidl_string)) > mSize) {
154 return -ERANGE;
155 }
156
157 *s = reinterpret_cast<const hidl_string *>(
158 (const uint8_t *)mBuffer + offset);
159
160 return OK;
161}
162
163const void *JHwBlob::data() const {
164 return mBuffer;
165}
166
167size_t JHwBlob::size() const {
168 return mSize;
169}
170
171status_t JHwBlob::putBlob(size_t offset, const sp<JHwBlob> &blob) {
172 size_t index = mSubBlobs.add();
173 BlobInfo *info = &mSubBlobs.editItemAt(index);
174
175 info->mOffset = offset;
176 info->mBlob = blob;
177
178 const void *data = blob->data();
179
180 return write(offset, &data, sizeof(data));
181}
182
183status_t JHwBlob::writeToParcel(hardware::Parcel *parcel) const {
184 size_t handle;
185 status_t err = parcel->writeBuffer(data(), size(), &handle);
186
187 if (err != OK) {
188 return err;
189 }
190
191 for (size_t i = 0; i < mSubBlobs.size(); ++i) {
192 const BlobInfo &info = mSubBlobs[i];
193
194 err = info.mBlob->writeEmbeddedToParcel(parcel, handle, info.mOffset);
195
196 if (err != OK) {
197 return err;
198 }
199 }
200
201 return OK;
202}
203
204status_t JHwBlob::writeEmbeddedToParcel(
205 hardware::Parcel *parcel,
206 size_t parentHandle,
207 size_t parentOffset) const {
208 size_t handle;
209 status_t err = parcel->writeEmbeddedBuffer(
210 data(), size(), &handle, parentHandle, parentOffset);
211
212 if (err != OK) {
213 return err;
214 }
215
216 for (size_t i = 0; i < mSubBlobs.size(); ++i) {
217 const BlobInfo &info = mSubBlobs[i];
218
219 err = info.mBlob->writeEmbeddedToParcel(parcel, handle, info.mOffset);
220
221 if (err != OK) {
222 return err;
223 }
224 }
225
226 return OK;
227}
228
229// static
230jobject JHwBlob::NewObject(JNIEnv *env, const void *ptr, size_t handle) {
231 jobject obj = JHwBlob::NewObject(env, 0 /* size */);
232 JHwBlob::GetNativeContext(env, obj)->setTo(ptr, handle);
233
234 return obj;
235}
236
237// static
238jobject JHwBlob::NewObject(JNIEnv *env, size_t size) {
239 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
240
241 jmethodID constructID =
242 GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
243
244 // XXX Again cannot refer to gFields.constructID because InitClass may
245 // not have been called yet.
246
247 return env->NewObject(clazz.get(), constructID, size);
248}
249
250} // namespace android
251
252////////////////////////////////////////////////////////////////////////////////
253
254using namespace android;
255
256static void releaseNativeContext(void *nativeContext) {
257 sp<JHwBlob> parcel = (JHwBlob *)nativeContext;
258
259 if (parcel != NULL) {
260 parcel->decStrong(NULL /* id */);
261 }
262}
263
264static jlong JHwBlob_native_init(JNIEnv *env) {
265 JHwBlob::InitClass(env);
266
267 return reinterpret_cast<jlong>(&releaseNativeContext);
268}
269
270static void JHwBlob_native_setup(
271 JNIEnv *env, jobject thiz, jint size) {
272 sp<JHwBlob> context = new JHwBlob(env, thiz, size);
273
274 JHwBlob::SetNativeContext(env, thiz, context);
275}
276
277#define DEFINE_BLOB_GETTER(Suffix,Type) \
278static Type JHwBlob_native_get ## Suffix( \
279 JNIEnv *env, jobject thiz, jlong offset) { \
280 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
281 \
282 Type x; \
283 status_t err = blob->read(offset, &x, sizeof(x)); \
284 \
285 if (err != OK) { \
286 signalExceptionForError(env, err); \
287 return 0; \
288 } \
289 \
290 return x; \
291}
292
293DEFINE_BLOB_GETTER(Int8,jbyte)
294DEFINE_BLOB_GETTER(Int16,jshort)
295DEFINE_BLOB_GETTER(Int32,jint)
296DEFINE_BLOB_GETTER(Int64,jlong)
297DEFINE_BLOB_GETTER(Float,jfloat)
298DEFINE_BLOB_GETTER(Double,jdouble)
299
300static jboolean JHwBlob_native_getBool(
301 JNIEnv *env, jobject thiz, jlong offset) {
302 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
303
304 bool x;
305 status_t err = blob->read(offset, &x, sizeof(x));
306
307 if (err != OK) {
308 signalExceptionForError(env, err);
309 return 0;
310 }
311
312 return (jboolean)x;
313}
314
315static jstring JHwBlob_native_getString(
316 JNIEnv *env, jobject thiz, jlong offset) {
317 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
318
319 const hidl_string *s;
320 status_t err = blob->getString(offset, &s);
321
322 if (err != OK) {
323 signalExceptionForError(env, err);
324 return nullptr;
325 }
326
327 return env->NewStringUTF(s->c_str());
328}
329
330#define DEFINE_BLOB_PUTTER(Suffix,Type) \
331static void JHwBlob_native_put ## Suffix( \
332 JNIEnv *env, jobject thiz, jlong offset, Type x) { \
333 \
334 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
335 \
336 status_t err = blob->write(offset, &x, sizeof(x)); \
337 \
338 if (err != OK) { \
339 signalExceptionForError(env, err); \
340 } \
341}
342
343DEFINE_BLOB_PUTTER(Int8,jbyte)
344DEFINE_BLOB_PUTTER(Int16,jshort)
345DEFINE_BLOB_PUTTER(Int32,jint)
346DEFINE_BLOB_PUTTER(Int64,jlong)
347DEFINE_BLOB_PUTTER(Float,jfloat)
348DEFINE_BLOB_PUTTER(Double,jdouble)
349
350static void JHwBlob_native_putBool(
351 JNIEnv *env, jobject thiz, jlong offset, jboolean x) {
352
353 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
354
355 bool b = (bool)x;
356 status_t err = blob->write(offset, &b, sizeof(b));
357
358 if (err != OK) {
359 signalExceptionForError(env, err);
360 }
361}
362
363static void JHwBlob_native_putString(
364 JNIEnv *env, jobject thiz, jlong offset, jstring stringObj) {
365 if (stringObj == nullptr) {
366 jniThrowException(env, "java/lang/NullPointerException", nullptr);
367 return;
368 }
369
370 const char *s = env->GetStringUTFChars(stringObj, nullptr);
371
372 if (s == nullptr) {
373 return;
374 }
375
376 size_t size = strlen(s) + 1;
377 ScopedLocalRef<jobject> subBlobObj(env, JHwBlob::NewObject(env, size));
378 sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, subBlobObj.get());
379 subBlob->write(0 /* offset */, s, size);
380
381 env->ReleaseStringUTFChars(stringObj, s);
382 s = nullptr;
383
384 hidl_string tmp;
385 tmp.setToExternal(static_cast<const char *>(subBlob->data()), size);
386
387 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
388 blob->write(offset, &tmp, sizeof(tmp));
389 blob->putBlob(offset + hidl_string::kOffsetOfBuffer, subBlob);
390}
391
392static void JHwBlob_native_putBlob(
393 JNIEnv *env, jobject thiz, jlong offset, jobject blobObj) {
394 if (blobObj == nullptr) {
395 jniThrowException(env, "java/lang/NullPointerException", nullptr);
396 return;
397 }
398
399 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
400 sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, blobObj);
401
402 blob->putBlob(offset, subBlob);
403}
404
405static jlong JHwBlob_native_handle(JNIEnv *env, jobject thiz) {
406 size_t handle;
407 status_t err = JHwBlob::GetNativeContext(env, thiz)->getHandle(&handle);
408
409 if (err != OK) {
410 signalExceptionForError(env, err);
411 return 0;
412 }
413
414 return handle;
415}
416
417static JNINativeMethod gMethods[] = {
418 { "native_init", "()J", (void *)JHwBlob_native_init },
419 { "native_setup", "(I)V", (void *)JHwBlob_native_setup },
420
421 { "getBool", "(J)Z", (void *)JHwBlob_native_getBool },
422 { "getInt8", "(J)B", (void *)JHwBlob_native_getInt8 },
423 { "getInt16", "(J)S", (void *)JHwBlob_native_getInt16 },
424 { "getInt32", "(J)I", (void *)JHwBlob_native_getInt32 },
425 { "getInt64", "(J)J", (void *)JHwBlob_native_getInt64 },
426 { "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
427 { "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
428 { "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
429
430 { "putBool", "(JZ)V", (void *)JHwBlob_native_putBool },
431 { "putInt8", "(JB)V", (void *)JHwBlob_native_putInt8 },
432 { "putInt16", "(JS)V", (void *)JHwBlob_native_putInt16 },
433 { "putInt32", "(JI)V", (void *)JHwBlob_native_putInt32 },
434 { "putInt64", "(JJ)V", (void *)JHwBlob_native_putInt64 },
435 { "putFloat", "(JF)V", (void *)JHwBlob_native_putFloat },
436 { "putDouble", "(JD)V", (void *)JHwBlob_native_putDouble },
437 { "putString", "(JLjava/lang/String;)V", (void *)JHwBlob_native_putString },
438
439 { "putBlob", "(JL" PACKAGE_PATH "/HwBlob;)V",
440 (void *)JHwBlob_native_putBlob },
441
442 { "handle", "()J", (void *)JHwBlob_native_handle },
443};
444
445namespace android {
446
447int register_android_os_HwBlob(JNIEnv *env) {
448 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
449}
450
451} // namespace android
452