1 /*
2 * Copyright (C) 2019 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 #include "android_os_HidlMemory.h"
18 #include "core_jni_helpers.h"
19 #include "android_os_NativeHandle.h"
20
21 #define PACKAGE_PATH "android/os"
22 #define CLASS_NAME "HidlMemory"
23 #define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
24
25 namespace android {
26
27 namespace {
28
29 static struct {
30 jclass clazz;
31 jfieldID nativeContext; // long
32 jmethodID constructor; // HidlMemory(String, long, NativeHandle)
33 jmethodID getName; // String HidlMemory.getName()
34 jmethodID getSize; // int HidlMemory.getSize()
35 jmethodID getHandle; // NativeHandle HidlMemory.getHandle()
36 } gFields;
37
stringFromJava(JNIEnv * env,jstring jstr)38 std::string stringFromJava(JNIEnv* env, jstring jstr) {
39 ScopedUtfChars s(env, jstr);
40 return s.c_str();
41 }
42
stringToJava(JNIEnv * env,const std::string & cstr)43 jstring stringToJava(JNIEnv* env, const std::string& cstr) {
44 return env->NewStringUTF(cstr.c_str());
45 }
46
nativeFinalize(JNIEnv * env,jobject jobj)47 static void nativeFinalize(JNIEnv* env, jobject jobj) {
48 jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
49 JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
50 delete native;
51 }
52
53 static JNINativeMethod gMethods[] = {
54 {"nativeFinalize", "()V", (void*) nativeFinalize},
55 };
56
57 } // namespace
58
~JHidlMemory()59 JHidlMemory::~JHidlMemory() {
60 if (mObj) {
61 // Must manually delete the underlying handle - hidl_memory doesn't own
62 // it.
63 native_handle_delete(const_cast<native_handle_t*>(mObj->handle()));
64 }
65 }
66
fromJava(JNIEnv * env,jobject jobj)67 /* static */ const hardware::hidl_memory* JHidlMemory::fromJava(JNIEnv* env,
68 jobject jobj) {
69 // Try to get the result from cache.
70 env->MonitorEnter(jobj);
71 JHidlMemory* obj = getNativeContext(env, jobj);
72 if (!obj->mObj) {
73 // Create and cache.
74 obj->mObj = javaToNative(env, jobj);
75 }
76 env->MonitorExit(jobj);
77 return obj->mObj.get();
78 }
79
toJava(JNIEnv * env,const hardware::hidl_memory & cobj)80 /* static */ jobject JHidlMemory::toJava(JNIEnv* env,
81 const hardware::hidl_memory& cobj) {
82 if (cobj.size() > std::numeric_limits<jlong>::max()) {
83 return nullptr;
84 }
85 jstring jname = stringToJava(env, cobj.name());
86 jlong jsize = static_cast<jlong>(cobj.size());
87 jobject jhandle =
88 JNativeHandle::MakeJavaNativeHandleObj(env, cobj.handle());
89
90 // We're sharing the handle of cobj, so the Java instance doesn't own it.
91 return env->NewObject(gFields.clazz,
92 gFields.constructor,
93 jname,
94 jsize,
95 jhandle,
96 false);
97 }
98
javaToNative(JNIEnv * env,jobject jobj)99 /* static */ std::unique_ptr<hardware::hidl_memory> JHidlMemory::javaToNative(
100 JNIEnv* env,
101 jobject jobj) {
102 jstring jname =
103 static_cast<jstring>(env->CallObjectMethod(jobj, gFields.getName));
104 jlong jsize = env->CallLongMethod(jobj, gFields.getSize);
105 jobject jhandle = env->CallObjectMethod(jobj, gFields.getHandle);
106
107 if (jsize > std::numeric_limits<size_t>::max()) {
108 return nullptr;
109 }
110
111 std::string cname = stringFromJava(env, jname);
112 size_t csize = jsize;
113 // We created the handle here, we're responsible to call
114 // native_handle_delete() on it. However, we don't assume ownership of the
115 // underlying fd, so we shouldn't call native_handle_close() on it.
116 native_handle_t* chandle = JNativeHandle::MakeCppNativeHandle(env, jhandle,
117 nullptr);
118 // hidl_memory doesn't take ownership of the handle here, so won't delete
119 // or close it.
120 return std::make_unique<hardware::hidl_memory>(cname, chandle, csize);
121 }
122
getNativeContext(JNIEnv * env,jobject jobj)123 /* static */ JHidlMemory* JHidlMemory::getNativeContext(JNIEnv* env,
124 jobject jobj) {
125 env->MonitorEnter(jobj);
126 jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
127 JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
128 if (!native) {
129 native = new JHidlMemory();
130 env->SetLongField(jobj,
131 gFields.nativeContext,
132 reinterpret_cast<jlong>(native));
133 }
134 env->MonitorExit(jobj);
135 return native;
136 }
137
register_android_os_HidlMemory(JNIEnv * env)138 int register_android_os_HidlMemory(JNIEnv* env) {
139 jclass clazz = FindClassOrDie(env, CLASS_PATH);
140 gFields.clazz = MakeGlobalRefOrDie(env, clazz);
141
142 gFields.nativeContext = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
143
144 gFields.constructor = GetMethodIDOrDie(env,
145 clazz,
146 "<init>",
147 "(Ljava/lang/String;JL" PACKAGE_PATH "/NativeHandle;)V");
148 gFields.getName =
149 GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
150 gFields.getSize = GetMethodIDOrDie(env, clazz, "getSize", "()J");
151 gFields.getHandle = GetMethodIDOrDie(env,
152 clazz,
153 "getHandle",
154 "()L" PACKAGE_PATH "/NativeHandle;");
155
156 RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
157
158 return 0;
159 }
160
161 } // namespace android
162
163