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