• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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