1 /*
2 * Copyright (C) 2011 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 "InputWindowHandle"
18
19 #include "android_hardware_input_InputWindowHandle.h"
20
21 #include <android/graphics/matrix.h>
22 #include <android/graphics/region.h>
23 #include <android_runtime/AndroidRuntime.h>
24 #include <android_runtime/Log.h>
25 #include <binder/IPCThreadState.h>
26 #include <ftl/flags.h>
27 #include <gui/SurfaceControl.h>
28 #include <gui/WindowInfo.h>
29 #include <nativehelper/JNIHelp.h>
30 #include <ui/Region.h>
31 #include <utils/threads.h>
32
33 #include "SkRegion.h"
34 #include "android_hardware_input_InputApplicationHandle.h"
35 #include "android_util_Binder.h"
36 #include "core_jni_helpers.h"
37 #include "jni.h"
38 #include "jni_common.h"
39
40 namespace android {
41
42 using gui::TouchOcclusionMode;
43 using gui::WindowInfo;
44
45 struct WeakRefHandleField {
46 jfieldID ctrl;
47 jmethodID get;
48 jfieldID mNativeObject;
49 };
50
51 static struct {
52 jclass clazz;
53 jmethodID ctor;
54 jfieldID ptr;
55 jfieldID inputApplicationHandle;
56 jfieldID token;
57 jfieldID name;
58 jfieldID layoutParamsFlags;
59 jfieldID layoutParamsType;
60 jfieldID dispatchingTimeoutMillis;
61 jfieldID frame;
62 jfieldID contentSize;
63 jfieldID surfaceInset;
64 jfieldID scaleFactor;
65 jfieldID touchableRegion;
66 jfieldID touchOcclusionMode;
67 jfieldID ownerPid;
68 jfieldID ownerUid;
69 jfieldID packageName;
70 jfieldID inputConfig;
71 jfieldID displayId;
72 jfieldID replaceTouchableRegionWithCrop;
73 WeakRefHandleField touchableRegionSurfaceControl;
74 jfieldID transform;
75 jfieldID windowToken;
76 jfieldID focusTransferTarget;
77 jfieldID alpha;
78 jfieldID canOccludePresentation;
79 } gInputWindowHandleClassInfo;
80
81 static struct {
82 jclass clazz;
83 jmethodID ctor;
84 } gRegionClassInfo;
85
86 static Mutex gHandleMutex;
87
88
89 // --- NativeInputWindowHandle ---
90
NativeInputWindowHandle(jweak objWeak)91 NativeInputWindowHandle::NativeInputWindowHandle(jweak objWeak) :
92 mObjWeak(objWeak) {
93 }
94
~NativeInputWindowHandle()95 NativeInputWindowHandle::~NativeInputWindowHandle() {
96 JNIEnv* env = AndroidRuntime::getJNIEnv();
97 env->DeleteWeakGlobalRef(mObjWeak);
98
99 // Clear the weak reference to the layer handle and flush any binder ref count operations so we
100 // do not hold on to any binder references.
101 // TODO(b/139697085) remove this after it can be flushed automatically
102 mInfo.touchableRegionCropHandle.clear();
103 IPCThreadState::self()->flushCommands();
104 }
105
getInputWindowHandleObjLocalRef(JNIEnv * env)106 jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) {
107 return env->NewLocalRef(mObjWeak);
108 }
109
updateInfo()110 bool NativeInputWindowHandle::updateInfo() {
111 JNIEnv* env = AndroidRuntime::getJNIEnv();
112 jobject obj = env->NewLocalRef(mObjWeak);
113 if (!obj) {
114 releaseChannel();
115 return false;
116 }
117
118 mInfo.touchableRegion.clear();
119
120 jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
121 if (tokenObj) {
122 mInfo.token = ibinderForJavaObject(env, tokenObj);
123 env->DeleteLocalRef(tokenObj);
124 } else {
125 mInfo.token.clear();
126 }
127
128 mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
129
130 mInfo.dispatchingTimeout = std::chrono::milliseconds(
131 env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
132
133 ScopedLocalRef<jobject> frameObj(env,
134 env->GetObjectField(obj, gInputWindowHandleClassInfo.frame));
135 mInfo.frame = JNICommon::rectFromObj(env, frameObj.get());
136
137 mInfo.surfaceInset = env->GetIntField(obj,
138 gInputWindowHandleClassInfo.surfaceInset);
139 mInfo.globalScaleFactor = env->GetFloatField(obj,
140 gInputWindowHandleClassInfo.scaleFactor);
141
142 jobject regionObj = env->GetObjectField(obj,
143 gInputWindowHandleClassInfo.touchableRegion);
144 if (regionObj) {
145 for (graphics::RegionIterator it(env, regionObj); !it.isDone(); it.next()) {
146 ARect rect = it.getRect();
147 mInfo.addTouchableRegion(Rect(rect.left, rect.top, rect.right, rect.bottom));
148 }
149 env->DeleteLocalRef(regionObj);
150 }
151
152 const auto flags = ftl::Flags<WindowInfo::Flag>(
153 env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
154 const auto type = static_cast<WindowInfo::Type>(
155 env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
156 mInfo.layoutParamsFlags = flags;
157 mInfo.layoutParamsType = type;
158
159 mInfo.inputConfig = static_cast<gui::WindowInfo::InputConfig>(
160 env->GetIntField(obj, gInputWindowHandleClassInfo.inputConfig));
161
162 mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
163 env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
164 mInfo.ownerPid = gui::Pid{env->GetIntField(obj, gInputWindowHandleClassInfo.ownerPid)};
165 mInfo.ownerUid = gui::Uid{
166 static_cast<uid_t>(env->GetIntField(obj, gInputWindowHandleClassInfo.ownerUid))};
167 mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, "<null>");
168 mInfo.displayId =
169 ui::LogicalDisplayId{env->GetIntField(obj, gInputWindowHandleClassInfo.displayId)};
170
171 jobject inputApplicationHandleObj = env->GetObjectField(obj,
172 gInputWindowHandleClassInfo.inputApplicationHandle);
173 if (inputApplicationHandleObj) {
174 std::shared_ptr<InputApplicationHandle> inputApplicationHandle =
175 android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
176 if (inputApplicationHandle != nullptr) {
177 inputApplicationHandle->updateInfo();
178 mInfo.applicationInfo = *(inputApplicationHandle->getInfo());
179 }
180 env->DeleteLocalRef(inputApplicationHandleObj);
181 }
182
183 mInfo.replaceTouchableRegionWithCrop = env->GetBooleanField(obj,
184 gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop);
185
186 jobject weakSurfaceCtrl = env->GetObjectField(obj,
187 gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl);
188 bool touchableRegionCropHandleSet = false;
189 if (weakSurfaceCtrl) {
190 // Promote java weak reference.
191 jobject strongSurfaceCtrl = env->CallObjectMethod(weakSurfaceCtrl,
192 gInputWindowHandleClassInfo.touchableRegionSurfaceControl.get);
193 if (strongSurfaceCtrl) {
194 jlong mNativeObject = env->GetLongField(strongSurfaceCtrl,
195 gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject);
196 if (mNativeObject) {
197 auto ctrl = reinterpret_cast<SurfaceControl *>(mNativeObject);
198 mInfo.touchableRegionCropHandle = ctrl->getHandle();
199 touchableRegionCropHandleSet = true;
200 }
201 env->DeleteLocalRef(strongSurfaceCtrl);
202 }
203 env->DeleteLocalRef(weakSurfaceCtrl);
204 }
205 if (!touchableRegionCropHandleSet) {
206 mInfo.touchableRegionCropHandle.clear();
207 }
208
209 jobject windowTokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.windowToken);
210 if (windowTokenObj) {
211 mInfo.windowToken = ibinderForJavaObject(env, windowTokenObj);
212 env->DeleteLocalRef(windowTokenObj);
213 } else {
214 mInfo.windowToken.clear();
215 }
216
217 ScopedLocalRef<jobject>
218 focusTransferTargetObj(env,
219 env->GetObjectField(obj,
220 gInputWindowHandleClassInfo
221 .focusTransferTarget));
222 if (focusTransferTargetObj.get()) {
223 mInfo.focusTransferTarget = ibinderForJavaObject(env, focusTransferTargetObj.get());
224 } else {
225 mInfo.focusTransferTarget.clear();
226 }
227
228 env->DeleteLocalRef(obj);
229 return true;
230 }
231
232
233 // --- Global functions ---
234
android_view_InputWindowHandle_getHandle(JNIEnv * env,jobject inputWindowHandleObj)235 sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
236 JNIEnv* env, jobject inputWindowHandleObj) {
237 if (!inputWindowHandleObj) {
238 return NULL;
239 }
240
241 AutoMutex _l(gHandleMutex);
242
243 jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
244 NativeInputWindowHandle* handle;
245 if (ptr) {
246 handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
247 } else {
248 jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
249 handle = new NativeInputWindowHandle(objWeak);
250 handle->incStrong((void*)android_view_InputWindowHandle_getHandle);
251 env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
252 reinterpret_cast<jlong>(handle));
253 }
254 return handle;
255 }
256
android_view_InputWindowHandle_fromWindowInfo(JNIEnv * env,gui::WindowInfo windowInfo)257 jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowInfo windowInfo) {
258 ScopedLocalRef<jobject>
259 applicationHandle(env,
260 android_view_InputApplicationHandle_fromInputApplicationInfo(
261 env, windowInfo.applicationInfo));
262
263 jobject inputWindowHandle =
264 env->NewObject(gInputWindowHandleClassInfo.clazz, gInputWindowHandleClassInfo.ctor,
265 applicationHandle.get(), windowInfo.displayId);
266 if (env->ExceptionCheck()) {
267 LOGE_EX(env);
268 env->ExceptionClear();
269 }
270 LOG_ALWAYS_FATAL_IF(inputWindowHandle == nullptr,
271 "Failed to create new InputWindowHandle object.");
272 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token,
273 javaObjectForIBinder(env, windowInfo.token));
274 ScopedLocalRef<jstring> name(env, env->NewStringUTF(windowInfo.name.data()));
275 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name, name.get());
276 env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags,
277 static_cast<uint32_t>(windowInfo.layoutParamsFlags.get()));
278 env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType,
279 static_cast<int32_t>(windowInfo.layoutParamsType));
280 env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis,
281 std::chrono::duration_cast<std::chrono::milliseconds>(
282 windowInfo.dispatchingTimeout)
283 .count());
284 ScopedLocalRef<jobject> rectObj(env, JNICommon::objFromRect(env, windowInfo.frame));
285 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.frame, rectObj.get());
286
287 ScopedLocalRef<jobject> sizeObj(env, JNICommon::objFromSize(env, windowInfo.contentSize));
288 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.contentSize, sizeObj.get());
289
290 env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.surfaceInset,
291 windowInfo.surfaceInset);
292 env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.scaleFactor,
293 windowInfo.globalScaleFactor);
294
295 SkRegion* region = new SkRegion();
296 for (const auto& r : windowInfo.touchableRegion) {
297 region->op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op);
298 }
299 ScopedLocalRef<jobject> regionObj(env,
300 env->NewObject(gRegionClassInfo.clazz, gRegionClassInfo.ctor,
301 reinterpret_cast<jlong>(region)));
302 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion,
303 regionObj.get());
304
305 env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
306 static_cast<int32_t>(windowInfo.touchOcclusionMode));
307 env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid,
308 windowInfo.ownerPid.val());
309 env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerUid,
310 windowInfo.ownerUid.val());
311 ScopedLocalRef<jstring> packageName(env, env->NewStringUTF(windowInfo.packageName.data()));
312 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName,
313 packageName.get());
314
315 const auto inputConfig = windowInfo.inputConfig.get();
316 static_assert(sizeof(inputConfig) == sizeof(int32_t));
317 env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputConfig,
318 static_cast<int32_t>(inputConfig));
319
320 float transformVals[9];
321 for (int i = 0; i < 9; i++) {
322 transformVals[i] = windowInfo.transform[i % 3][i / 3];
323 }
324 ScopedLocalRef<jobject> matrixObj(env, AMatrix_newInstance(env, transformVals));
325 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.transform, matrixObj.get());
326
327 env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.windowToken,
328 javaObjectForIBinder(env, windowInfo.windowToken));
329
330 env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.alpha, windowInfo.alpha);
331 env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.canOccludePresentation,
332 windowInfo.canOccludePresentation);
333
334 return inputWindowHandle;
335 }
336
337 // --- JNI ---
338
android_view_InputWindowHandle_nativeDispose(JNIEnv * env,jobject obj)339 static void android_view_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) {
340 AutoMutex _l(gHandleMutex);
341
342 jlong ptr = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr);
343 if (ptr) {
344 env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0);
345
346 NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
347 handle->decStrong((void*)android_view_InputWindowHandle_getHandle);
348 }
349 }
350
351
352 static const JNINativeMethod gInputWindowHandleMethods[] = {
353 /* name, signature, funcPtr */
354 { "nativeDispose", "()V",
355 (void*) android_view_InputWindowHandle_nativeDispose },
356 };
357
358 #define FIND_CLASS(var, className) \
359 var = env->FindClass(className); \
360 LOG_FATAL_IF(! (var), "Unable to find class " className);
361
362 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
363 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
364 LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
365
366 #define GET_METHOD_ID(var, clazz, methodName, methodSignature) \
367 var = env->GetMethodID(clazz, methodName, methodSignature); \
368 LOG_FATAL_IF(! (var), "Unable to find method " methodName);
369
register_android_view_InputWindowHandle(JNIEnv * env)370 int register_android_view_InputWindowHandle(JNIEnv* env) {
371 int res = jniRegisterNativeMethods(env, "android/view/InputWindowHandle",
372 gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
373 (void) res; // Faked use when LOG_NDEBUG.
374 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
375
376 jclass clazz;
377 FIND_CLASS(clazz, "android/view/InputWindowHandle");
378 gInputWindowHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
379
380 GET_METHOD_ID(gInputWindowHandleClassInfo.ctor, clazz, "<init>",
381 "(Landroid/view/InputApplicationHandle;I)V");
382
383 GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
384 "ptr", "J");
385
386 GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, clazz,
387 "inputApplicationHandle", "Landroid/view/InputApplicationHandle;");
388
389 GET_FIELD_ID(gInputWindowHandleClassInfo.token, clazz,
390 "token", "Landroid/os/IBinder;");
391
392 GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
393 "name", "Ljava/lang/String;");
394
395 GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
396 "layoutParamsFlags", "I");
397
398 GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
399 "layoutParamsType", "I");
400
401 GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutMillis, clazz,
402 "dispatchingTimeoutMillis", "J");
403
404 GET_FIELD_ID(gInputWindowHandleClassInfo.frame, clazz, "frame", "Landroid/graphics/Rect;");
405
406 GET_FIELD_ID(gInputWindowHandleClassInfo.contentSize, clazz, "contentSize",
407 "Landroid/util/Size;");
408
409 GET_FIELD_ID(gInputWindowHandleClassInfo.surfaceInset, clazz,
410 "surfaceInset", "I");
411
412 GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz,
413 "scaleFactor", "F");
414
415 GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
416 "touchableRegion", "Landroid/graphics/Region;");
417
418 GET_FIELD_ID(gInputWindowHandleClassInfo.touchOcclusionMode, clazz, "touchOcclusionMode", "I");
419
420 GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
421 "ownerPid", "I");
422
423 GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz,
424 "ownerUid", "I");
425
426 GET_FIELD_ID(gInputWindowHandleClassInfo.packageName, clazz, "packageName",
427 "Ljava/lang/String;");
428
429 GET_FIELD_ID(gInputWindowHandleClassInfo.inputConfig, clazz, "inputConfig", "I");
430
431 GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
432 "displayId", "I");
433
434 GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz,
435 "replaceTouchableRegionWithCrop", "Z");
436
437 GET_FIELD_ID(gInputWindowHandleClassInfo.transform, clazz, "transform",
438 "Landroid/graphics/Matrix;");
439
440 GET_FIELD_ID(gInputWindowHandleClassInfo.windowToken, clazz, "windowToken",
441 "Landroid/os/IBinder;");
442
443 GET_FIELD_ID(gInputWindowHandleClassInfo.focusTransferTarget, clazz, "focusTransferTarget",
444 "Landroid/os/IBinder;");
445
446 jclass weakRefClazz;
447 FIND_CLASS(weakRefClazz, "java/lang/ref/Reference");
448
449 GET_METHOD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.get, weakRefClazz,
450 "get", "()Ljava/lang/Object;")
451
452 GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl, clazz,
453 "touchableRegionSurfaceControl", "Ljava/lang/ref/WeakReference;");
454
455 GET_FIELD_ID(gInputWindowHandleClassInfo.alpha, clazz, "alpha", "F");
456
457 GET_FIELD_ID(gInputWindowHandleClassInfo.canOccludePresentation, clazz,
458 "canOccludePresentation", "Z");
459
460 jclass surfaceControlClazz;
461 FIND_CLASS(surfaceControlClazz, "android/view/SurfaceControl");
462 GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject,
463 surfaceControlClazz, "mNativeObject", "J");
464
465 jclass regionClazz;
466 FIND_CLASS(regionClazz, "android/graphics/Region");
467 gRegionClassInfo.clazz = MakeGlobalRefOrDie(env, regionClazz);
468 GET_METHOD_ID(gRegionClassInfo.ctor, gRegionClassInfo.clazz, "<init>", "(J)V");
469 return 0;
470 }
471
472 } /* namespace android */
473