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