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