1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "jni_helper.h"
17 #include "ipc_debug.h"
18 #include "jni_help.h"
19 #include "ohos_rpc_remote_object.h"
20 #include "log_tags.h"
21
22 namespace OHOS {
23 using namespace OHOS::HiviewDFX;
24
25 struct JFileDescriptor {
26 jclass klazz;
27 jmethodID fileDescriptorCtor;
28 jfieldID descriptorField;
29 } g_jFileDescriptor;
30
31 static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC_OTHER, "IPCJniHelper" };
32
33 JavaVM *JNIEnvHelper::javaVm_ = nullptr;
34 // The JavaVM is a representation of the virtual machine on the JNI layer,
35 // one process has only one JavaVM, and all the threads share a JavaVM.
36 // JNIEnv is in effect only on the thread that it is created,
37 // cannot be passed across threads, different threads are independent of each other.
38 // In order to implement cross-threading calls, we need to transform between JNIENV and JavaVM
JNIEnvHelper()39 JNIEnvHelper::JNIEnvHelper() : env_ { nullptr }, nativeThread_ { false }
40 {
41 if (javaVm_->GetEnv(reinterpret_cast<void **>(&env_), JNI_VERSION_1_4) == JNI_EDETACHED) {
42 javaVm_->AttachCurrentThread(reinterpret_cast<void **>(&env_), nullptr);
43 nativeThread_ = true;
44 }
45 }
46
nativeInit(JavaVM * vm)47 void JNIEnvHelper::nativeInit(JavaVM *vm)
48 {
49 if (javaVm_ != nullptr) {
50 ZLOGE(LABEL, "Failed to init vm, javaVm_ has been initialized");
51 return;
52 }
53
54 javaVm_ = vm;
55 }
56
~JNIEnvHelper()57 JNIEnvHelper::~JNIEnvHelper()
58 {
59 if (nativeThread_) {
60 javaVm_->DetachCurrentThread();
61 }
62 }
63
Get()64 JNIEnv *JNIEnvHelper::Get()
65 {
66 return env_;
67 }
68
operator ->()69 JNIEnv *JNIEnvHelper::operator->()
70 {
71 return env_;
72 }
73
JniHelperThrowException(JNIEnv * env,const char * className,const char * msg)74 void JniHelperThrowException(JNIEnv *env, const char *className, const char *msg)
75 {
76 jclass clazz = env->FindClass(className);
77 if (!clazz) {
78 ZLOGE(LABEL, "Unable to find exception class:%{public}s", className);
79 /* ClassNotFoundException now pending */
80 return;
81 }
82
83 if (env->ThrowNew(clazz, msg) != JNI_OK) {
84 ZLOGE(LABEL, "Failed throwing className:%{public}s msg:%{public}s", className, msg);
85 /* an exception, most likely OOM, will now be pending */
86 }
87
88 env->DeleteLocalRef(clazz);
89 }
90
JniHelperThrowNullPointerException(JNIEnv * env,const char * msg)91 void JniHelperThrowNullPointerException(JNIEnv *env, const char *msg)
92 {
93 JniHelperThrowException(env, "java/lang/NullPointerException", msg);
94 }
95
JniHelperThrowIllegalStateException(JNIEnv * env,const char * msg)96 void JniHelperThrowIllegalStateException(JNIEnv *env, const char *msg)
97 {
98 JniHelperThrowException(env, "java/lang/IllegalStateException", msg);
99 }
100
101 /*
102 * Get an int file descriptor from a java.io.FileDescriptor
103 */
JniHelperJavaIoGetFdFromFileDescriptor(JNIEnv * env,jobject fileDescriptor)104 int JniHelperJavaIoGetFdFromFileDescriptor(JNIEnv *env, jobject fileDescriptor)
105 {
106 return env->GetIntField(fileDescriptor, g_jFileDescriptor.descriptorField);
107 }
108
109 /*
110 * Set the descriptor of a java.io.FileDescriptor
111 */
JniHelperJavaIoSetFdToFileDescriptor(JNIEnv * env,jobject fileDescriptor,int value)112 void JniHelperJavaIoSetFdToFileDescriptor(JNIEnv *env, jobject fileDescriptor, int value)
113 {
114 env->SetIntField(fileDescriptor, g_jFileDescriptor.descriptorField, value);
115 }
116
117 /*
118 * JNI may throws exception when native code call java scenario.
119 * we should convert local exception to native status code.
120 * Check and clear local exception.
121 */
JniHelperCheckAndClearLocalException(JNIEnv * env)122 jboolean JniHelperCheckAndClearLocalException(JNIEnv *env)
123 {
124 jthrowable exception = env->ExceptionOccurred();
125 if (exception != nullptr) {
126 ZLOGE(LABEL, "clean up JNI local ref");
127 // clean up JNI local ref -- we don't return to Java code
128 env->ExceptionDescribe(); // for debug perpose.
129 env->ExceptionClear();
130 env->DeleteLocalRef(exception);
131 return JNI_TRUE;
132 }
133
134 return JNI_FALSE;
135 }
136
137 /*
138 * Create a java.io.FileDescriptor given an integer fd
139 */
JniHelperJavaIoCreateFileDescriptor(JNIEnv * env,int fd)140 jobject JniHelperJavaIoCreateFileDescriptor(JNIEnv *env, int fd)
141 {
142 jobject descriptor = env->NewObject(g_jFileDescriptor.klazz, g_jFileDescriptor.fileDescriptorCtor);
143 JniHelperJavaIoSetFdToFileDescriptor(env, descriptor, fd);
144 return descriptor;
145 }
146
JniHelperRegisterNativeMethods(JNIEnv * env)147 int JniHelperRegisterNativeMethods(JNIEnv *env)
148 {
149 if (env == nullptr) {
150 ZLOGE(LABEL, "env is null");
151 return JNI_ERR;
152 }
153 g_jFileDescriptor.klazz = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass("java/io/FileDescriptor")));
154 if (g_jFileDescriptor.klazz == nullptr) {
155 return JNI_ERR;
156 }
157
158 g_jFileDescriptor.fileDescriptorCtor = env->GetMethodID(g_jFileDescriptor.klazz, "<init>", "()V");
159 if (g_jFileDescriptor.fileDescriptorCtor == nullptr) {
160 env->DeleteGlobalRef(g_jFileDescriptor.klazz);
161 return JNI_ERR;
162 }
163
164 g_jFileDescriptor.descriptorField = env->GetFieldID(g_jFileDescriptor.klazz, "descriptor", "I");
165 if (g_jFileDescriptor.descriptorField == nullptr) {
166 env->DeleteGlobalRef(g_jFileDescriptor.klazz);
167 return JNI_ERR;
168 }
169
170 return JNI_OK;
171 }
172
JNIHelperGetJavaRemoteObject(JNIEnv * env,const sptr<IRemoteObject> & target)173 jobject JNIHelperGetJavaRemoteObject(JNIEnv *env, const sptr<IRemoteObject> &target)
174 {
175 if (env == nullptr) {
176 return nullptr;
177 }
178 return Java_ohos_rpc_getJavaRemoteObject(env, target);
179 }
180 } // namespace OHOS
181