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