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