• 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-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