• 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/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_hardware_input_InputApplicationHandle.h"
30 #include "android_util_Binder.h"
31 #include "core_jni_helpers.h"
32 #include "input/InputWindow.h"
33 #include "jni.h"
34 
35 namespace android {
36 
37 struct WeakRefHandleField {
38     jfieldID ctrl;
39     jmethodID get;
40     jfieldID mNativeObject;
41 };
42 
43 static struct {
44     jfieldID ptr;
45     jfieldID inputApplicationHandle;
46     jfieldID token;
47     jfieldID name;
48     jfieldID layoutParamsFlags;
49     jfieldID layoutParamsType;
50     jfieldID dispatchingTimeoutMillis;
51     jfieldID frameLeft;
52     jfieldID frameTop;
53     jfieldID frameRight;
54     jfieldID frameBottom;
55     jfieldID surfaceInset;
56     jfieldID scaleFactor;
57     jfieldID touchableRegion;
58     jfieldID visible;
59     jfieldID focusable;
60     jfieldID hasWallpaper;
61     jfieldID paused;
62     jfieldID trustedOverlay;
63     jfieldID touchOcclusionMode;
64     jfieldID ownerPid;
65     jfieldID ownerUid;
66     jfieldID packageName;
67     jfieldID inputFeatures;
68     jfieldID displayId;
69     jfieldID portalToDisplayId;
70     jfieldID replaceTouchableRegionWithCrop;
71     WeakRefHandleField touchableRegionSurfaceControl;
72 } gInputWindowHandleClassInfo;
73 
74 static Mutex gHandleMutex;
75 
76 
77 // --- NativeInputWindowHandle ---
78 
NativeInputWindowHandle(jweak objWeak)79 NativeInputWindowHandle::NativeInputWindowHandle(jweak objWeak) :
80         mObjWeak(objWeak) {
81 }
82 
~NativeInputWindowHandle()83 NativeInputWindowHandle::~NativeInputWindowHandle() {
84     JNIEnv* env = AndroidRuntime::getJNIEnv();
85     env->DeleteWeakGlobalRef(mObjWeak);
86 
87     // Clear the weak reference to the layer handle and flush any binder ref count operations so we
88     // do not hold on to any binder references.
89     // TODO(b/139697085) remove this after it can be flushed automatically
90     mInfo.touchableRegionCropHandle.clear();
91     IPCThreadState::self()->flushCommands();
92 }
93 
getInputWindowHandleObjLocalRef(JNIEnv * env)94 jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) {
95     return env->NewLocalRef(mObjWeak);
96 }
97 
updateInfo()98 bool NativeInputWindowHandle::updateInfo() {
99     JNIEnv* env = AndroidRuntime::getJNIEnv();
100     jobject obj = env->NewLocalRef(mObjWeak);
101     if (!obj) {
102         releaseChannel();
103         return false;
104     }
105 
106     mInfo.touchableRegion.clear();
107 
108     jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
109     if (tokenObj) {
110         mInfo.token = ibinderForJavaObject(env, tokenObj);
111         env->DeleteLocalRef(tokenObj);
112     } else {
113         mInfo.token.clear();
114     }
115 
116     mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
117 
118     mInfo.flags = Flags<InputWindowInfo::Flag>(
119             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
120     mInfo.type = static_cast<InputWindowInfo::Type>(
121             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
122     mInfo.dispatchingTimeout = std::chrono::milliseconds(
123             env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
124     mInfo.frameLeft = env->GetIntField(obj,
125             gInputWindowHandleClassInfo.frameLeft);
126     mInfo.frameTop = env->GetIntField(obj,
127             gInputWindowHandleClassInfo.frameTop);
128     mInfo.frameRight = env->GetIntField(obj,
129             gInputWindowHandleClassInfo.frameRight);
130     mInfo.frameBottom = env->GetIntField(obj,
131             gInputWindowHandleClassInfo.frameBottom);
132     mInfo.surfaceInset = env->GetIntField(obj,
133             gInputWindowHandleClassInfo.surfaceInset);
134     mInfo.globalScaleFactor = env->GetFloatField(obj,
135             gInputWindowHandleClassInfo.scaleFactor);
136 
137     jobject regionObj = env->GetObjectField(obj,
138             gInputWindowHandleClassInfo.touchableRegion);
139     if (regionObj) {
140         for (graphics::RegionIterator it(env, regionObj); !it.isDone(); it.next()) {
141             ARect rect = it.getRect();
142             mInfo.addTouchableRegion(Rect(rect.left, rect.top, rect.right, rect.bottom));
143         }
144         env->DeleteLocalRef(regionObj);
145     }
146 
147     mInfo.visible = env->GetBooleanField(obj,
148             gInputWindowHandleClassInfo.visible);
149     mInfo.focusable = env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable);
150     mInfo.hasWallpaper = env->GetBooleanField(obj,
151             gInputWindowHandleClassInfo.hasWallpaper);
152     mInfo.paused = env->GetBooleanField(obj,
153             gInputWindowHandleClassInfo.paused);
154     mInfo.trustedOverlay = env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay);
155     mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
156             env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
157     mInfo.ownerPid = env->GetIntField(obj,
158             gInputWindowHandleClassInfo.ownerPid);
159     mInfo.ownerUid = env->GetIntField(obj,
160             gInputWindowHandleClassInfo.ownerUid);
161     mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, "<null>");
162     mInfo.inputFeatures = static_cast<InputWindowInfo::Feature>(
163             env->GetIntField(obj, gInputWindowHandleClassInfo.inputFeatures));
164     mInfo.displayId = env->GetIntField(obj,
165             gInputWindowHandleClassInfo.displayId);
166     mInfo.portalToDisplayId = env->GetIntField(obj,
167             gInputWindowHandleClassInfo.portalToDisplayId);
168 
169     jobject inputApplicationHandleObj = env->GetObjectField(obj,
170             gInputWindowHandleClassInfo.inputApplicationHandle);
171     if (inputApplicationHandleObj) {
172         std::shared_ptr<InputApplicationHandle> inputApplicationHandle =
173                 android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
174         if (inputApplicationHandle != nullptr) {
175             inputApplicationHandle->updateInfo();
176             mInfo.applicationInfo = *(inputApplicationHandle->getInfo());
177         }
178         env->DeleteLocalRef(inputApplicationHandleObj);
179     }
180 
181     mInfo.replaceTouchableRegionWithCrop = env->GetBooleanField(obj,
182             gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop);
183 
184     jobject weakSurfaceCtrl = env->GetObjectField(obj,
185             gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl);
186     bool touchableRegionCropHandleSet = false;
187     if (weakSurfaceCtrl) {
188         // Promote java weak reference.
189         jobject strongSurfaceCtrl = env->CallObjectMethod(weakSurfaceCtrl,
190                 gInputWindowHandleClassInfo.touchableRegionSurfaceControl.get);
191         if (strongSurfaceCtrl) {
192             jlong mNativeObject = env->GetLongField(strongSurfaceCtrl,
193                     gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject);
194             if (mNativeObject) {
195                 auto ctrl = reinterpret_cast<SurfaceControl *>(mNativeObject);
196                 mInfo.touchableRegionCropHandle = ctrl->getHandle();
197                 touchableRegionCropHandleSet = true;
198             }
199             env->DeleteLocalRef(strongSurfaceCtrl);
200         }
201         env->DeleteLocalRef(weakSurfaceCtrl);
202     }
203     if (!touchableRegionCropHandleSet) {
204         mInfo.touchableRegionCropHandle.clear();
205     }
206 
207     env->DeleteLocalRef(obj);
208     return true;
209 }
210 
211 
212 // --- Global functions ---
213 
android_view_InputWindowHandle_getHandle(JNIEnv * env,jobject inputWindowHandleObj)214 sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
215         JNIEnv* env, jobject inputWindowHandleObj) {
216     if (!inputWindowHandleObj) {
217         return NULL;
218     }
219 
220     AutoMutex _l(gHandleMutex);
221 
222     jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
223     NativeInputWindowHandle* handle;
224     if (ptr) {
225         handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
226     } else {
227         jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
228         handle = new NativeInputWindowHandle(objWeak);
229         handle->incStrong((void*)android_view_InputWindowHandle_getHandle);
230         env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
231                 reinterpret_cast<jlong>(handle));
232     }
233     return handle;
234 }
235 
236 
237 // --- JNI ---
238 
android_view_InputWindowHandle_nativeDispose(JNIEnv * env,jobject obj)239 static void android_view_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) {
240     AutoMutex _l(gHandleMutex);
241 
242     jlong ptr = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr);
243     if (ptr) {
244         env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0);
245 
246         NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
247         handle->decStrong((void*)android_view_InputWindowHandle_getHandle);
248     }
249 }
250 
251 
252 static const JNINativeMethod gInputWindowHandleMethods[] = {
253     /* name, signature, funcPtr */
254     { "nativeDispose", "()V",
255             (void*) android_view_InputWindowHandle_nativeDispose },
256 };
257 
258 #define FIND_CLASS(var, className) \
259         var = env->FindClass(className); \
260         LOG_FATAL_IF(! (var), "Unable to find class " className);
261 
262 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
263         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
264         LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
265 
266 #define GET_METHOD_ID(var, clazz, methodName, methodSignature) \
267         var = env->GetMethodID(clazz, methodName, methodSignature); \
268         LOG_FATAL_IF(! (var), "Unable to find method " methodName);
269 
register_android_view_InputWindowHandle(JNIEnv * env)270 int register_android_view_InputWindowHandle(JNIEnv* env) {
271     int res = jniRegisterNativeMethods(env, "android/view/InputWindowHandle",
272             gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
273     (void) res;  // Faked use when LOG_NDEBUG.
274     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
275 
276     jclass clazz;
277     FIND_CLASS(clazz, "android/view/InputWindowHandle");
278 
279     GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
280             "ptr", "J");
281 
282     GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, clazz,
283             "inputApplicationHandle", "Landroid/view/InputApplicationHandle;");
284 
285     GET_FIELD_ID(gInputWindowHandleClassInfo.token, clazz,
286             "token", "Landroid/os/IBinder;");
287 
288     GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
289             "name", "Ljava/lang/String;");
290 
291     GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
292             "layoutParamsFlags", "I");
293 
294     GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
295             "layoutParamsType", "I");
296 
297     GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutMillis, clazz,
298                  "dispatchingTimeoutMillis", "J");
299 
300     GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
301             "frameLeft", "I");
302 
303     GET_FIELD_ID(gInputWindowHandleClassInfo.frameTop, clazz,
304             "frameTop", "I");
305 
306     GET_FIELD_ID(gInputWindowHandleClassInfo.frameRight, clazz,
307             "frameRight", "I");
308 
309     GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz,
310             "frameBottom", "I");
311 
312     GET_FIELD_ID(gInputWindowHandleClassInfo.surfaceInset, clazz,
313             "surfaceInset", "I");
314 
315     GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz,
316             "scaleFactor", "F");
317 
318     GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
319             "touchableRegion", "Landroid/graphics/Region;");
320 
321     GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
322             "visible", "Z");
323 
324     GET_FIELD_ID(gInputWindowHandleClassInfo.focusable, clazz, "focusable", "Z");
325 
326     GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
327             "hasWallpaper", "Z");
328 
329     GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
330             "paused", "Z");
331 
332     GET_FIELD_ID(gInputWindowHandleClassInfo.trustedOverlay, clazz, "trustedOverlay", "Z");
333 
334     GET_FIELD_ID(gInputWindowHandleClassInfo.touchOcclusionMode, clazz, "touchOcclusionMode", "I");
335 
336     GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
337             "ownerPid", "I");
338 
339     GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz,
340             "ownerUid", "I");
341 
342     GET_FIELD_ID(gInputWindowHandleClassInfo.packageName, clazz, "packageName",
343                  "Ljava/lang/String;");
344 
345     GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz,
346             "inputFeatures", "I");
347 
348     GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
349             "displayId", "I");
350 
351     GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz,
352             "portalToDisplayId", "I");
353 
354     GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz,
355             "replaceTouchableRegionWithCrop", "Z");
356 
357     jclass weakRefClazz;
358     FIND_CLASS(weakRefClazz, "java/lang/ref/Reference");
359 
360     GET_METHOD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.get, weakRefClazz,
361              "get", "()Ljava/lang/Object;")
362 
363     GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl, clazz,
364             "touchableRegionSurfaceControl", "Ljava/lang/ref/WeakReference;");
365 
366     jclass surfaceControlClazz;
367     FIND_CLASS(surfaceControlClazz, "android/view/SurfaceControl");
368     GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject,
369         surfaceControlClazz, "mNativeObject", "J");
370 
371     return 0;
372 }
373 
374 } /* namespace android */
375