1 /*
2  * Copyright (C) 2020 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 "Camera-SurfaceUtils-JNI"
18 // #define LOG_NDEBUG 0
19 #include <camera/CameraUtils.h>
20 #include <utils/Errors.h>
21 #include <utils/Log.h>
22 #include <utils/Trace.h>
23 
24 #include <nativehelper/JNIHelp.h>
25 #include "android_runtime/android_graphics_SurfaceTexture.h"
26 #include "android_runtime/android_view_Surface.h"
27 #include "core_jni_helpers.h"
28 #include "jni.h"
29 
30 #include <gui/IGraphicBufferProducer.h>
31 #include <gui/IProducerListener.h>
32 #include <gui/Surface.h>
33 #include <system/window.h>
34 #include <ui/GraphicBuffer.h>
35 
36 #include <inttypes.h>
37 #include <stdint.h>
38 
39 using namespace android;
40 
41 // fully-qualified class name
42 #define CAMERA_UTILS_CLASS_NAME "android/hardware/camera2/utils/SurfaceUtils"
43 
44 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
45 
46 #define OVERRIDE_SURFACE_ERROR(err) \
47     do {                            \
48         if (err == -ENODEV) {       \
49             err = BAD_VALUE;        \
50         }                           \
51     } while (0)
52 
getNativeWindow(JNIEnv * env,jobject surface)53 static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
54     sp<ANativeWindow> anw;
55     if (surface) {
56         anw = android_view_Surface_getNativeWindow(env, surface);
57         if (env->ExceptionCheck()) {
58             return NULL;
59         }
60     } else {
61         jniThrowNullPointerException(env, "surface");
62         return NULL;
63     }
64     if (anw == NULL) {
65         ALOGE("%s: Surface had no valid native window.", __FUNCTION__);
66         return NULL;
67     }
68     return anw;
69 }
70 
getSurface(JNIEnv * env,jobject surface)71 static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
72     sp<Surface> s;
73     if (surface) {
74         s = android_view_Surface_getSurface(env, surface);
75         if (env->ExceptionCheck()) {
76             return NULL;
77         }
78     } else {
79         jniThrowNullPointerException(env, "surface");
80         return NULL;
81     }
82     if (s == NULL) {
83         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
84                              "Surface had no valid native Surface.");
85         return NULL;
86     }
87     return s;
88 }
89 
90 extern "C" {
91 
SurfaceUtils_nativeDetectSurfaceType(JNIEnv * env,jobject thiz,jobject surface)92 static jint SurfaceUtils_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
93     ALOGV("nativeDetectSurfaceType");
94     sp<ANativeWindow> anw;
95     if ((anw = getNativeWindow(env, surface)) == NULL) {
96         ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
97         return BAD_VALUE;
98     }
99     int32_t fmt = 0;
100     status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
101     if (err != NO_ERROR) {
102         ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
103               strerror(-err), err);
104         OVERRIDE_SURFACE_ERROR(err);
105         return err;
106     }
107     return fmt;
108 }
109 
SurfaceUtils_nativeDetectSurfaceDataspace(JNIEnv * env,jobject thiz,jobject surface)110 static jint SurfaceUtils_nativeDetectSurfaceDataspace(JNIEnv* env, jobject thiz, jobject surface) {
111     ALOGV("nativeDetectSurfaceDataspace");
112     sp<ANativeWindow> anw;
113     if ((anw = getNativeWindow(env, surface)) == NULL) {
114         ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
115         return BAD_VALUE;
116     }
117     int32_t fmt = 0;
118     status_t err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &fmt);
119     if (err != NO_ERROR) {
120         ALOGE("%s: Error while querying surface dataspace  %s (%d).", __FUNCTION__, strerror(-err),
121               err);
122         OVERRIDE_SURFACE_ERROR(err);
123         return err;
124     }
125     return fmt;
126 }
127 
SurfaceUtils_nativeDetectSurfaceDimens(JNIEnv * env,jobject thiz,jobject surface,jintArray dimens)128 static jint SurfaceUtils_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
129                                                    jintArray dimens) {
130     ALOGV("nativeGetSurfaceDimens");
131 
132     if (dimens == NULL) {
133         ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
134         return BAD_VALUE;
135     }
136 
137     if (env->GetArrayLength(dimens) < 2) {
138         ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
139         return BAD_VALUE;
140     }
141 
142     sp<ANativeWindow> anw;
143     if ((anw = getNativeWindow(env, surface)) == NULL) {
144         ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
145         return BAD_VALUE;
146     }
147     int32_t dimenBuf[2];
148     status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
149     if (err != NO_ERROR) {
150         ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err), err);
151         OVERRIDE_SURFACE_ERROR(err);
152         return err;
153     }
154     err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
155     if (err != NO_ERROR) {
156         ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
157               err);
158         OVERRIDE_SURFACE_ERROR(err);
159         return err;
160     }
161     env->SetIntArrayRegion(dimens, /*start*/ 0, /*length*/ ARRAY_SIZE(dimenBuf), dimenBuf);
162     return NO_ERROR;
163 }
164 
SurfaceUtils_nativeDetectSurfaceUsageFlags(JNIEnv * env,jobject thiz,jobject surface)165 static jlong SurfaceUtils_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz,
166                                                         jobject surface) {
167     ALOGV("nativeDetectSurfaceUsageFlags");
168 
169     sp<ANativeWindow> anw;
170     if ((anw = getNativeWindow(env, surface)) == NULL) {
171         jniThrowException(env, "java/lang/UnsupportedOperationException",
172                           "Could not retrieve native window from surface.");
173         return BAD_VALUE;
174     }
175     uint64_t usage = 0;
176     status_t err = native_window_get_consumer_usage(anw.get(), &usage);
177     if (err != NO_ERROR) {
178         jniThrowException(env, "java/lang/UnsupportedOperationException",
179                           "Error while querying surface usage bits");
180         OVERRIDE_SURFACE_ERROR(err);
181         return err;
182     }
183     return usage;
184 }
185 
SurfaceUtils_nativeGetSurfaceId(JNIEnv * env,jobject thiz,jobject surface)186 static jlong SurfaceUtils_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
187     ALOGV("nativeGetSurfaceId");
188     sp<Surface> s;
189     if ((s = getSurface(env, surface)) == NULL) {
190         ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
191         return 0;
192     }
193     sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
194     if (gbp == NULL) {
195         ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
196         return 0;
197     }
198     sp<IBinder> b = IInterface::asBinder(gbp);
199     if (b == NULL) {
200         ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
201         return 0;
202     }
203     /*
204      * FIXME: Use better unique ID for surfaces than native IBinder pointer.  Fix also in the camera
205      * service (CameraDeviceClient.h).
206      */
207     return reinterpret_cast<jlong>(b.get());
208 }
209 
210 } // extern "C"
211 
212 static const JNINativeMethod gCameraSurfaceUtilsMethods[] = {
213         {"nativeDetectSurfaceType", "(Landroid/view/Surface;)I",
214          (void*)SurfaceUtils_nativeDetectSurfaceType},
215         {"nativeDetectSurfaceDataspace", "(Landroid/view/Surface;)I",
216          (void*)SurfaceUtils_nativeDetectSurfaceDataspace},
217         {"nativeDetectSurfaceDimens", "(Landroid/view/Surface;[I)I",
218          (void*)SurfaceUtils_nativeDetectSurfaceDimens},
219         {"nativeDetectSurfaceUsageFlags", "(Landroid/view/Surface;)J",
220          (void*)SurfaceUtils_nativeDetectSurfaceUsageFlags},
221         {"nativeGetSurfaceId", "(Landroid/view/Surface;)J", (void*)SurfaceUtils_nativeGetSurfaceId},
222 };
223 
224 // Get all the required offsets in java class and register native functions
register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv * env)225 int register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv* env) {
226     // Register native functions
227     return RegisterMethodsOrDie(env, CAMERA_UTILS_CLASS_NAME, gCameraSurfaceUtilsMethods,
228                                 NELEM(gCameraSurfaceUtilsMethods));
229 }
230