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