• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <JNIHelp.h>
26 #include <android_runtime/AndroidRuntime.h>
27 #include <hidl/Status.h>
28 #include <nativehelper/ScopedLocalRef.h>
29 
30 #include "core_jni_helpers.h"
31 
32 using android::AndroidRuntime;
33 using 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 
39 namespace android {
40 
41 static struct fields_t {
42     jfieldID contextID;
43     jmethodID constructID;
44 
45 } gFields;
46 
47 // static
InitClass(JNIEnv * env)48 void 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
SetNativeContext(JNIEnv * env,jobject thiz,const sp<JHwBlob> & context)59 sp<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
GetNativeContext(JNIEnv * env,jobject thiz)77 sp<JHwBlob> JHwBlob::GetNativeContext(JNIEnv *env, jobject thiz) {
78     return (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
79 }
80 
JHwBlob(JNIEnv * env,jobject thiz,size_t size)81 JHwBlob::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 
~JHwBlob()97 JHwBlob::~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 
setTo(const void * ptr,size_t handle)112 void 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 
getHandle(size_t * handle) const122 status_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 
read(size_t offset,void * data,size_t size) const132 status_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 
write(size_t offset,const void * data,size_t size)142 status_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 
getString(size_t offset,const hidl_string ** s) const152 status_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 
data() const163 const void *JHwBlob::data() const {
164     return mBuffer;
165 }
166 
size() const167 size_t JHwBlob::size() const {
168     return mSize;
169 }
170 
putBlob(size_t offset,const sp<JHwBlob> & blob)171 status_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 
writeToParcel(hardware::Parcel * parcel) const183 status_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 
writeEmbeddedToParcel(hardware::Parcel * parcel,size_t parentHandle,size_t parentOffset) const204 status_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
NewObject(JNIEnv * env,const void * ptr,size_t handle)230 jobject 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
NewObject(JNIEnv * env,size_t size)238 jobject 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 
254 using namespace android;
255 
releaseNativeContext(void * nativeContext)256 static void releaseNativeContext(void *nativeContext) {
257     sp<JHwBlob> parcel = (JHwBlob *)nativeContext;
258 
259     if (parcel != NULL) {
260         parcel->decStrong(NULL /* id */);
261     }
262 }
263 
JHwBlob_native_init(JNIEnv * env)264 static jlong JHwBlob_native_init(JNIEnv *env) {
265     JHwBlob::InitClass(env);
266 
267     return reinterpret_cast<jlong>(&releaseNativeContext);
268 }
269 
JHwBlob_native_setup(JNIEnv * env,jobject thiz,jint size)270 static 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)                                        \
278 static 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 
DEFINE_BLOB_GETTER(Int8,jbyte)293 DEFINE_BLOB_GETTER(Int8,jbyte)
294 DEFINE_BLOB_GETTER(Int16,jshort)
295 DEFINE_BLOB_GETTER(Int32,jint)
296 DEFINE_BLOB_GETTER(Int64,jlong)
297 DEFINE_BLOB_GETTER(Float,jfloat)
298 DEFINE_BLOB_GETTER(Double,jdouble)
299 
300 static 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 
JHwBlob_native_getString(JNIEnv * env,jobject thiz,jlong offset)315 static 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)                                        \
331 static 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 
DEFINE_BLOB_PUTTER(Int8,jbyte)343 DEFINE_BLOB_PUTTER(Int8,jbyte)
344 DEFINE_BLOB_PUTTER(Int16,jshort)
345 DEFINE_BLOB_PUTTER(Int32,jint)
346 DEFINE_BLOB_PUTTER(Int64,jlong)
347 DEFINE_BLOB_PUTTER(Float,jfloat)
348 DEFINE_BLOB_PUTTER(Double,jdouble)
349 
350 static 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 
JHwBlob_native_putString(JNIEnv * env,jobject thiz,jlong offset,jstring stringObj)363 static 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 - 1);
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 
JHwBlob_native_putBlob(JNIEnv * env,jobject thiz,jlong offset,jobject blobObj)392 static 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 
JHwBlob_native_handle(JNIEnv * env,jobject thiz)405 static 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 
417 static 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 
445 namespace android {
446 
register_android_os_HwBlob(JNIEnv * env)447 int register_android_os_HwBlob(JNIEnv *env) {
448     return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
449 }
450 
451 }  // namespace android
452 
453