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