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 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 65 NativeInputChannel::NativeInputChannel(std::unique_ptr<InputChannel> inputChannel) 66 : mInputChannel(std::move(inputChannel)), mDisposeCallback(nullptr) {} 67 68 NativeInputChannel::~NativeInputChannel() { 69 } 70 71 void NativeInputChannel::setDisposeCallback(InputChannelObjDisposeCallback callback, void* data) { 72 mDisposeCallback = callback; 73 mDisposeData = data; 74 } 75 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 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 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 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 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 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 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 179 static void InputChannel_nativeDestroy(void *rawInputChannel) { 180 NativeInputChannel* nativeInputChannel = 181 reinterpret_cast<NativeInputChannel *>(rawInputChannel); 182 if (nativeInputChannel) { 183 delete nativeInputChannel; 184 } 185 } 186 187 static jlong android_view_InputChannel_getNativeFinalizer(JNIEnv* env, jobject obj) { 188 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&InputChannel_nativeDestroy)); 189 } 190 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 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 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 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 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 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 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