1 /*
2 * Copyright (C) 2010 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_TAG "InputChannel-JNI"
18
19 #include "android-base/stringprintf.h"
20 #include <nativehelper/JNIHelp.h>
21 #include "nativehelper/scoped_utf_chars.h"
22 #include <android_runtime/AndroidRuntime.h>
23 #include <binder/Parcel.h>
24 #include <utils/Log.h>
25 #include <input/InputTransport.h>
26 #include "android_view_InputChannel.h"
27 #include "android_os_Parcel.h"
28 #include "android_util_Binder.h"
29
30 #include "core_jni_helpers.h"
31
32 namespace android {
33
34 // ----------------------------------------------------------------------------
35
36 static struct {
37 jclass clazz;
38
39 jmethodID mCtor;
40 jmethodID mSetNativeInputChannel;
41
42 jfieldID mPtr; // native object attached to the DVM InputChannel
43 } gInputChannelClassInfo;
44
45 // ----------------------------------------------------------------------------
46
47 class NativeInputChannel {
48 public:
49 explicit NativeInputChannel(std::unique_ptr<InputChannel> inputChannel);
50 ~NativeInputChannel();
51
getInputChannel()52 inline std::shared_ptr<InputChannel> getInputChannel() { return mInputChannel; }
53
54 void setDisposeCallback(InputChannelObjDisposeCallback callback, void* data);
55 void dispose(JNIEnv* env, jobject obj);
56
57 private:
58 std::shared_ptr<InputChannel> mInputChannel;
59 InputChannelObjDisposeCallback mDisposeCallback;
60 void* mDisposeData;
61 };
62
63 // ----------------------------------------------------------------------------
64
NativeInputChannel(std::unique_ptr<InputChannel> inputChannel)65 NativeInputChannel::NativeInputChannel(std::unique_ptr<InputChannel> inputChannel)
66 : mInputChannel(std::move(inputChannel)), mDisposeCallback(nullptr) {}
67
~NativeInputChannel()68 NativeInputChannel::~NativeInputChannel() {
69 }
70
setDisposeCallback(InputChannelObjDisposeCallback callback,void * data)71 void NativeInputChannel::setDisposeCallback(InputChannelObjDisposeCallback callback, void* data) {
72 mDisposeCallback = callback;
73 mDisposeData = data;
74 }
75
dispose(JNIEnv * env,jobject obj)76 void NativeInputChannel::dispose(JNIEnv* env, jobject obj) {
77 if (!mInputChannel) {
78 return;
79 }
80
81 if (mDisposeCallback) {
82 mDisposeCallback(env, obj, mInputChannel, mDisposeData);
83 mDisposeCallback = nullptr;
84 mDisposeData = nullptr;
85 }
86 mInputChannel.reset();
87 }
88
89 // ----------------------------------------------------------------------------
90
android_view_InputChannel_getNativeInputChannel(JNIEnv * env,jobject inputChannelObj)91 static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
92 jobject inputChannelObj) {
93 jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
94 return reinterpret_cast<NativeInputChannel*>(longPtr);
95 }
96
android_view_InputChannel_getInputChannel(JNIEnv * env,jobject inputChannelObj)97 std::shared_ptr<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env,
98 jobject inputChannelObj) {
99 NativeInputChannel* nativeInputChannel =
100 android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
101 return nativeInputChannel != nullptr ? nativeInputChannel->getInputChannel() : nullptr;
102 }
103
android_view_InputChannel_setDisposeCallback(JNIEnv * env,jobject inputChannelObj,InputChannelObjDisposeCallback callback,void * data)104 void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChannelObj,
105 InputChannelObjDisposeCallback callback, void* data) {
106 NativeInputChannel* nativeInputChannel =
107 android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
108 if (!nativeInputChannel || !nativeInputChannel->getInputChannel()) {
109 ALOGW("Cannot set dispose callback because input channel object has not been initialized.");
110 } else {
111 nativeInputChannel->setDisposeCallback(callback, data);
112 }
113 }
114
android_view_InputChannel_createInputChannel(JNIEnv * env,std::unique_ptr<InputChannel> inputChannel)115 static jlong android_view_InputChannel_createInputChannel(
116 JNIEnv* env, std::unique_ptr<InputChannel> inputChannel) {
117 std::unique_ptr<NativeInputChannel> nativeInputChannel =
118 std::make_unique<NativeInputChannel>(std::move(inputChannel));
119
120 return reinterpret_cast<jlong>(nativeInputChannel.release());
121 }
122
android_view_InputChannel_createJavaObject(JNIEnv * env,std::unique_ptr<InputChannel> inputChannel)123 jobject android_view_InputChannel_createJavaObject(JNIEnv* env,
124 std::unique_ptr<InputChannel> inputChannel) {
125 std::string name = inputChannel->getName();
126 jlong ptr = android_view_InputChannel_createInputChannel(env, std::move(inputChannel));
127 jobject javaInputChannel =
128 env->NewObject(gInputChannelClassInfo.clazz, gInputChannelClassInfo.mCtor);
129 if (!javaInputChannel) {
130 ALOGE("Failed to create a Java InputChannel for channel %s.", name.c_str());
131 return nullptr;
132 }
133
134 env->CallVoidMethod(javaInputChannel, gInputChannelClassInfo.mSetNativeInputChannel, ptr);
135 if (env->ExceptionOccurred()) {
136 ALOGE("Failed to set native ptr to the Java InputChannel for channel %s.",
137 inputChannel->getName().c_str());
138 return nullptr;
139 }
140 return javaInputChannel;
141 }
142
android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv * env,jclass clazz,jstring nameObj)143 static jlongArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
144 jclass clazz, jstring nameObj) {
145 ScopedUtfChars nameChars(env, nameObj);
146 std::string name = nameChars.c_str();
147
148 std::unique_ptr<InputChannel> serverChannel;
149 std::unique_ptr<InputChannel> clientChannel;
150 status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
151
152 if (result) {
153 std::string message = android::base::StringPrintf(
154 "Could not open input channel pair : %s", strerror(-result));
155 jniThrowRuntimeException(env, message.c_str());
156 return nullptr;
157 }
158
159 jlongArray channelPair = env->NewLongArray(2);
160 if (channelPair == nullptr) {
161 return nullptr;
162 }
163
164 jlong* outArray = env->GetLongArrayElements(channelPair, 0);
165 outArray[0] = android_view_InputChannel_createInputChannel(env, std::move(serverChannel));
166 if (env->ExceptionCheck()) {
167 return nullptr;
168 }
169
170 outArray[1] = android_view_InputChannel_createInputChannel(env, std::move(clientChannel));
171 if (env->ExceptionCheck()) {
172 return nullptr;
173 }
174 env->ReleaseLongArrayElements(channelPair, outArray, 0);
175
176 return channelPair;
177 }
178
InputChannel_nativeDestroy(void * rawInputChannel)179 static void InputChannel_nativeDestroy(void *rawInputChannel) {
180 NativeInputChannel* nativeInputChannel =
181 reinterpret_cast<NativeInputChannel *>(rawInputChannel);
182 if (nativeInputChannel) {
183 delete nativeInputChannel;
184 }
185 }
186
android_view_InputChannel_getNativeFinalizer(JNIEnv * env,jobject obj)187 static jlong android_view_InputChannel_getNativeFinalizer(JNIEnv* env, jobject obj) {
188 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&InputChannel_nativeDestroy));
189 }
190
android_view_InputChannel_nativeDispose(JNIEnv * env,jobject obj,jlong channel)191 static void android_view_InputChannel_nativeDispose(JNIEnv* env, jobject obj, jlong channel) {
192 NativeInputChannel* nativeInputChannel =
193 reinterpret_cast<NativeInputChannel*>(channel);
194
195 if (nativeInputChannel) {
196 nativeInputChannel->dispose(env, obj);
197 }
198 }
199
android_view_InputChannel_nativeReadFromParcel(JNIEnv * env,jobject obj,jobject parcelObj)200 static jlong android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
201 jobject parcelObj) {
202 Parcel* parcel = parcelForJavaObject(env, parcelObj);
203 if (parcel) {
204 bool isInitialized = parcel->readInt32();
205 if (isInitialized) {
206 std::unique_ptr<InputChannel> inputChannel = std::make_unique<InputChannel>();
207 inputChannel->readFromParcel(parcel);
208 NativeInputChannel* nativeInputChannel =
209 new NativeInputChannel(std::move(inputChannel));
210 return reinterpret_cast<jlong>(nativeInputChannel);
211 }
212 }
213 return 0;
214 }
215
android_view_InputChannel_nativeWriteToParcel(JNIEnv * env,jobject obj,jobject parcelObj,jlong channel)216 static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject obj,
217 jobject parcelObj, jlong channel) {
218 Parcel* parcel = parcelForJavaObject(env, parcelObj);
219 if (parcel == nullptr) {
220 ALOGE("Could not obtain parcel for Java object");
221 return;
222 }
223 NativeInputChannel* nativeInputChannel =
224 reinterpret_cast<NativeInputChannel*>(channel);
225
226 if (!nativeInputChannel || !nativeInputChannel->getInputChannel()) {
227 parcel->writeInt32(0); // not initialized
228 return;
229 }
230 parcel->writeInt32(1); // initialized
231 nativeInputChannel->getInputChannel()->writeToParcel(parcel);
232 }
233
android_view_InputChannel_nativeGetName(JNIEnv * env,jobject obj,jlong channel)234 static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj, jlong channel) {
235 NativeInputChannel* nativeInputChannel =
236 reinterpret_cast<NativeInputChannel*>(channel);
237 if (!nativeInputChannel || !nativeInputChannel->getInputChannel()) {
238 return nullptr;
239 }
240
241 jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().c_str());
242 return name;
243 }
244
android_view_InputChannel_nativeDup(JNIEnv * env,jobject obj,jlong channel)245 static jlong android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jlong channel) {
246 NativeInputChannel* nativeInputChannel =
247 reinterpret_cast<NativeInputChannel*>(channel);
248
249 if (nativeInputChannel == nullptr) {
250 jniThrowRuntimeException(env, "InputChannel has no valid NativeInputChannel");
251 return 0;
252 }
253
254 std::shared_ptr<InputChannel> inputChannel = nativeInputChannel->getInputChannel();
255 if (inputChannel == nullptr) {
256 jniThrowRuntimeException(env, "NativeInputChannel has no corresponding InputChannel");
257 return 0;
258 }
259
260 std::unique_ptr<InputChannel> dupInputChannel = inputChannel->dup();
261 if (dupInputChannel == nullptr) {
262 std::string message = android::base::StringPrintf(
263 "Could not duplicate input channel %s", inputChannel->getName().c_str());
264 jniThrowRuntimeException(env, message.c_str());
265 }
266 return reinterpret_cast<jlong>(new NativeInputChannel(std::move(dupInputChannel)));
267 }
268
android_view_InputChannel_nativeGetToken(JNIEnv * env,jobject obj,jlong channel)269 static jobject android_view_InputChannel_nativeGetToken(JNIEnv* env, jobject obj, jlong channel) {
270 NativeInputChannel* nativeInputChannel =
271 reinterpret_cast<NativeInputChannel*>(channel);
272 if (nativeInputChannel && nativeInputChannel->getInputChannel()) {
273 return javaObjectForIBinder(env,
274 nativeInputChannel->getInputChannel()->getConnectionToken());
275 }
276 return 0;
277 }
278
279 // ----------------------------------------------------------------------------
280
281 static const JNINativeMethod gInputChannelMethods[] = {
282 /* name, signature, funcPtr */
283 { "nativeOpenInputChannelPair", "(Ljava/lang/String;)[J",
284 (void*)android_view_InputChannel_nativeOpenInputChannelPair },
285 { "nativeGetFinalizer", "()J",
286 (void*)android_view_InputChannel_getNativeFinalizer },
287 { "nativeDispose", "(J)V",
288 (void*)android_view_InputChannel_nativeDispose },
289 { "nativeReadFromParcel", "(Landroid/os/Parcel;)J",
290 (void*)android_view_InputChannel_nativeReadFromParcel },
291 { "nativeWriteToParcel", "(Landroid/os/Parcel;J)V",
292 (void*)android_view_InputChannel_nativeWriteToParcel },
293 { "nativeGetName", "(J)Ljava/lang/String;",
294 (void*)android_view_InputChannel_nativeGetName },
295 { "nativeDup", "(J)J",
296 (void*)android_view_InputChannel_nativeDup },
297 { "nativeGetToken", "(J)Landroid/os/IBinder;",
298 (void*)android_view_InputChannel_nativeGetToken },
299 };
300
register_android_view_InputChannel(JNIEnv * env)301 int register_android_view_InputChannel(JNIEnv* env) {
302 int res = RegisterMethodsOrDie(env, "android/view/InputChannel", gInputChannelMethods,
303 NELEM(gInputChannelMethods));
304
305 jclass clazz = FindClassOrDie(env, "android/view/InputChannel");
306 gInputChannelClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
307
308 gInputChannelClassInfo.mCtor =
309 GetMethodIDOrDie(env, gInputChannelClassInfo.clazz, "<init>", "()V");
310 gInputChannelClassInfo.mSetNativeInputChannel =
311 GetMethodIDOrDie(env, gInputChannelClassInfo.clazz, "setNativeInputChannel", "(J)V");
312
313 gInputChannelClassInfo.mPtr = GetFieldIDOrDie(env, gInputChannelClassInfo.clazz, "mPtr", "J");
314
315 return res;
316 }
317
318 } // namespace android
319