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