1 /*
2 * Copyright (C) 2017 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 "AImageReaderCts"
18 //#define LOG_NDEBUG 0
19
20 #include <jni.h>
21 #include <stdint.h>
22 #include <unistd.h>
23
24 #include <algorithm>
25 #include <mutex>
26 #include <string>
27 #include <vector>
28
29 #include <android/log.h>
30 #include <android/native_window_jni.h>
31 #include <camera/NdkCameraError.h>
32 #include <camera/NdkCameraManager.h>
33 #include <camera/NdkCameraDevice.h>
34 #include <camera/NdkCameraCaptureSession.h>
35 #include <media/NdkImage.h>
36 #include <media/NdkImageReader.h>
37
38 //#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
39 //#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
40 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
41 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
42 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
43
44 namespace {
45
46 static constexpr int kDummyFenceFd = -1;
47 static constexpr int kCaptureWaitUs = 100 * 1000;
48 static constexpr int kCaptureWaitRetry = 10;
49 static constexpr int kTestImageWidth = 640;
50 static constexpr int kTestImageHeight = 480;
51 static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
52
53 struct FormatUsageCombination {
54 uint64_t format;
55 uint64_t usage;
56 };
57
58 static constexpr FormatUsageCombination supportedFormatUsage[] = {
59 {AIMAGE_FORMAT_YUV_420_888, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY},
60 {AIMAGE_FORMAT_YUV_420_888, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
61 {AIMAGE_FORMAT_JPEG, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY},
62 {AIMAGE_FORMAT_JPEG, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
63 {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY},
64 {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
65 {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE},
66 {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_VIDEO_ENCODE},
67 {AIMAGE_FORMAT_Y8, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
68 };
69
70 class CameraHelper {
71 public:
CameraHelper(ANativeWindow * imgReaderAnw)72 CameraHelper(ANativeWindow* imgReaderAnw) : mImgReaderAnw(imgReaderAnw) {}
~CameraHelper()73 ~CameraHelper() { closeCamera(); }
74
initCamera()75 int initCamera() {
76 if (mImgReaderAnw == nullptr) {
77 ALOGE("Cannot initialize camera before image reader get initialized.");
78 return -1;
79 }
80 int ret;
81
82 mCameraManager = ACameraManager_create();
83 if (mCameraManager == nullptr) {
84 ALOGE("Failed to create ACameraManager.");
85 return -1;
86 }
87
88 ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
89 if (ret != AMEDIA_OK) {
90 ALOGE("Failed to get cameraIdList: ret=%d", ret);
91 return ret;
92 }
93 if (mCameraIdList->numCameras < 1) {
94 ALOGW("Device has no camera on board.");
95 return 0;
96 }
97
98 // We always use the first camera.
99 mCameraId = mCameraIdList->cameraIds[0];
100 if (mCameraId == nullptr) {
101 ALOGE("Failed to get cameraId.");
102 return -1;
103 }
104
105 ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
106 if (ret != AMEDIA_OK || mDevice == nullptr) {
107 ALOGE("Failed to open camera, ret=%d, mDevice=%p.", ret, mDevice);
108 return -1;
109 }
110
111 ret = ACameraManager_getCameraCharacteristics(mCameraManager, mCameraId, &mCameraMetadata);
112 if (ret != ACAMERA_OK || mCameraMetadata == nullptr) {
113 ALOGE("Get camera %s characteristics failure. ret %d, metadata %p", mCameraId, ret,
114 mCameraMetadata);
115 return -1;
116 }
117
118 if (!isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) {
119 ALOGW("Camera does not support BACKWARD_COMPATIBLE.");
120 return 0;
121 }
122
123 // Create capture session
124 ret = ACaptureSessionOutputContainer_create(&mOutputs);
125 if (ret != AMEDIA_OK) {
126 ALOGE("ACaptureSessionOutputContainer_create failed, ret=%d", ret);
127 return ret;
128 }
129 ret = ACaptureSessionOutput_create(mImgReaderAnw, &mImgReaderOutput);
130 if (ret != AMEDIA_OK) {
131 ALOGE("ACaptureSessionOutput_create failed, ret=%d", ret);
132 return ret;
133 }
134 ret = ACaptureSessionOutputContainer_add(mOutputs, mImgReaderOutput);
135 if (ret != AMEDIA_OK) {
136 ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
137 return ret;
138 }
139 ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
140 if (ret != AMEDIA_OK) {
141 ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
142 return ret;
143 }
144
145 // Create capture request
146 ret = ACameraDevice_createCaptureRequest(mDevice, TEMPLATE_STILL_CAPTURE, &mStillRequest);
147 if (ret != AMEDIA_OK) {
148 ALOGE("ACameraDevice_createCaptureRequest failed, ret=%d", ret);
149 return ret;
150 }
151 ret = ACameraOutputTarget_create(mImgReaderAnw, &mReqImgReaderOutput);
152 if (ret != AMEDIA_OK) {
153 ALOGE("ACameraOutputTarget_create failed, ret=%d", ret);
154 return ret;
155 }
156 ret = ACaptureRequest_addTarget(mStillRequest, mReqImgReaderOutput);
157 if (ret != AMEDIA_OK) {
158 ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
159 return ret;
160 }
161
162 mIsCameraReady = true;
163 return 0;
164 }
165
isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap)166 bool isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap) {
167 ACameraMetadata_const_entry entry;
168 ACameraMetadata_getConstEntry(
169 mCameraMetadata, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
170 for (uint32_t i = 0; i < entry.count; i++) {
171 if (entry.data.u8[i] == cap) {
172 return true;
173 }
174 }
175 return false;
176 }
177
isCameraReady()178 bool isCameraReady() { return mIsCameraReady; }
179
closeCamera()180 void closeCamera() {
181 // Destroy capture request
182 if (mReqImgReaderOutput) {
183 ACameraOutputTarget_free(mReqImgReaderOutput);
184 mReqImgReaderOutput = nullptr;
185 }
186 if (mStillRequest) {
187 ACaptureRequest_free(mStillRequest);
188 mStillRequest = nullptr;
189 }
190 // Destroy capture session
191 if (mSession != nullptr) {
192 ACameraCaptureSession_close(mSession);
193 mSession = nullptr;
194 }
195 if (mImgReaderOutput) {
196 ACaptureSessionOutput_free(mImgReaderOutput);
197 mImgReaderOutput = nullptr;
198 }
199 if (mOutputs) {
200 ACaptureSessionOutputContainer_free(mOutputs);
201 mOutputs = nullptr;
202 }
203 // Destroy camera device
204 if (mDevice) {
205 ACameraDevice_close(mDevice);
206 mDevice = nullptr;
207 }
208 if (mCameraMetadata) {
209 ACameraMetadata_free(mCameraMetadata);
210 mCameraMetadata = nullptr;
211 }
212 // Destroy camera manager
213 if (mCameraIdList) {
214 ACameraManager_deleteCameraIdList(mCameraIdList);
215 mCameraIdList = nullptr;
216 }
217 if (mCameraManager) {
218 ACameraManager_delete(mCameraManager);
219 mCameraManager = nullptr;
220 }
221 mIsCameraReady = false;
222 }
223
takePicture()224 int takePicture() {
225 int seqId;
226 return ACameraCaptureSession_capture(mSession, nullptr, 1, &mStillRequest, &seqId);
227 }
228
onDeviceDisconnected(void *,ACameraDevice *)229 static void onDeviceDisconnected(void* /*obj*/, ACameraDevice* /*device*/) {}
230
onDeviceError(void *,ACameraDevice *,int)231 static void onDeviceError(void* /*obj*/, ACameraDevice* /*device*/, int /*errorCode*/) {}
232
onSessionClosed(void *,ACameraCaptureSession *)233 static void onSessionClosed(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
234
onSessionReady(void *,ACameraCaptureSession *)235 static void onSessionReady(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
236
onSessionActive(void *,ACameraCaptureSession *)237 static void onSessionActive(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
238
239 private:
240 ACameraDevice_StateCallbacks mDeviceCb{this, onDeviceDisconnected,
241 onDeviceError};
242 ACameraCaptureSession_stateCallbacks mSessionCb{
243 this, onSessionClosed, onSessionReady, onSessionActive};
244
245 ANativeWindow* mImgReaderAnw = nullptr; // not owned by us.
246
247 // Camera manager
248 ACameraManager* mCameraManager = nullptr;
249 ACameraIdList* mCameraIdList = nullptr;
250 // Camera device
251 ACameraMetadata* mCameraMetadata = nullptr;
252 ACameraDevice* mDevice = nullptr;
253 // Capture session
254 ACaptureSessionOutputContainer* mOutputs = nullptr;
255 ACaptureSessionOutput* mImgReaderOutput = nullptr;
256 ACameraCaptureSession* mSession = nullptr;
257 // Capture request
258 ACaptureRequest* mStillRequest = nullptr;
259 ACameraOutputTarget* mReqImgReaderOutput = nullptr;
260
261 bool mIsCameraReady = false;
262 const char* mCameraId;
263 };
264
265 class ImageReaderTestCase {
266 public:
ImageReaderTestCase(int32_t width,int32_t height,int32_t format,uint64_t usage,int32_t maxImages,bool async)267 ImageReaderTestCase(int32_t width,
268 int32_t height,
269 int32_t format,
270 uint64_t usage,
271 int32_t maxImages,
272 bool async)
273 : mWidth(width),
274 mHeight(height),
275 mFormat(format),
276 mUsage(usage),
277 mMaxImages(maxImages),
278 mAsync(async) {}
279
~ImageReaderTestCase()280 ~ImageReaderTestCase() {
281 if (mImgReaderAnw) {
282 AImageReader_delete(mImgReader);
283 // No need to call ANativeWindow_release on imageReaderAnw
284 }
285 }
286
initImageReader()287 int initImageReader() {
288 if (mImgReader != nullptr || mImgReaderAnw != nullptr) {
289 ALOGE("Cannot re-initalize image reader, mImgReader=%p, mImgReaderAnw=%p", mImgReader,
290 mImgReaderAnw);
291 return -1;
292 }
293
294 media_status_t ret = AImageReader_newWithUsage(
295 mWidth, mHeight, mFormat, mUsage, mMaxImages, &mImgReader);
296 if (ret != AMEDIA_OK || mImgReader == nullptr) {
297 ALOGE("Failed to create new AImageReader, ret=%d, mImgReader=%p", ret, mImgReader);
298 return -1;
299 }
300
301 ret = AImageReader_setImageListener(mImgReader, &mReaderAvailableCb);
302 if (ret != AMEDIA_OK) {
303 ALOGE("Failed to set image available listener, ret=%d.", ret);
304 return ret;
305 }
306
307 ret = AImageReader_setBufferRemovedListener(mImgReader, &mReaderDetachedCb);
308 if (ret != AMEDIA_OK) {
309 ALOGE("Failed to set buffer detaching listener, ret=%d.", ret);
310 return ret;
311 }
312
313 ret = AImageReader_getWindow(mImgReader, &mImgReaderAnw);
314 if (ret != AMEDIA_OK || mImgReaderAnw == nullptr) {
315 ALOGE("Failed to get ANativeWindow from AImageReader, ret=%d, mImgReaderAnw=%p.", ret,
316 mImgReaderAnw);
317 return -1;
318 }
319
320 return 0;
321 }
322
getNativeWindow()323 ANativeWindow* getNativeWindow() { return mImgReaderAnw; }
324
getAcquiredImageCount()325 int getAcquiredImageCount() {
326 std::lock_guard<std::mutex> lock(mMutex);
327 return mAcquiredImageCount;
328 }
329
HandleImageAvailable(AImageReader * reader)330 void HandleImageAvailable(AImageReader* reader) {
331 std::lock_guard<std::mutex> lock(mMutex);
332
333 AImage* outImage = nullptr;
334 media_status_t ret;
335
336 // Make sure AImage will be deleted automatically when it goes out of
337 // scope.
338 auto imageDeleter = [this](AImage* img) {
339 if (mAsync) {
340 AImage_deleteAsync(img, kDummyFenceFd);
341 } else {
342 AImage_delete(img);
343 }
344 };
345 std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
346
347 if (mAsync) {
348 int outFenceFd = 0;
349 // Verity that outFenceFd's value will be changed by
350 // AImageReader_acquireNextImageAsync.
351 ret = AImageReader_acquireNextImageAsync(reader, &outImage, &outFenceFd);
352 if (ret != AMEDIA_OK || outImage == nullptr || outFenceFd == 0) {
353 ALOGE("Failed to acquire image, ret=%d, outIamge=%p, outFenceFd=%d.", ret, outImage,
354 outFenceFd);
355 return;
356 }
357 img.reset(outImage);
358 } else {
359 ret = AImageReader_acquireNextImage(reader, &outImage);
360 if (ret != AMEDIA_OK || outImage == nullptr) {
361 ALOGE("Failed to acquire image, ret=%d, outIamge=%p.", ret, outImage);
362 return;
363 }
364 img.reset(outImage);
365 }
366
367 AHardwareBuffer* outBuffer = nullptr;
368 ret = AImage_getHardwareBuffer(img.get(), &outBuffer);
369 if (ret != AMEDIA_OK || outBuffer == nullptr) {
370 ALOGE("Faild to get hardware buffer, ret=%d, outBuffer=%p.", ret, outBuffer);
371 return;
372 }
373
374 // No need to release AHardwareBuffer, since we don't acquire additional
375 // reference to it.
376 AHardwareBuffer_Desc outDesc;
377 AHardwareBuffer_describe(outBuffer, &outDesc);
378 int32_t imageWidth = 0;
379 int32_t imageHeight = 0;
380 int32_t bufferWidth = static_cast<int32_t>(outDesc.width);
381 int32_t bufferHeight = static_cast<int32_t>(outDesc.height);
382
383 AImage_getWidth(outImage, &imageWidth);
384 AImage_getHeight(outImage, &imageHeight);
385 if (imageWidth != mWidth || imageHeight != mHeight) {
386 ALOGE("Mismatched output image dimension: expected=%dx%d, actual=%dx%d", mWidth,
387 mHeight, imageWidth, imageHeight);
388 return;
389 }
390
391 if (mFormat == AIMAGE_FORMAT_RGBA_8888 ||
392 mFormat == AIMAGE_FORMAT_RGBX_8888 ||
393 mFormat == AIMAGE_FORMAT_RGB_888 ||
394 mFormat == AIMAGE_FORMAT_RGB_565 ||
395 mFormat == AIMAGE_FORMAT_RGBA_FP16 ||
396 mFormat == AIMAGE_FORMAT_YUV_420_888 ||
397 mFormat == AIMAGE_FORMAT_Y8) {
398 // Check output buffer dimension for certain formats. Don't do this for blob based
399 // formats.
400 if (bufferWidth != mWidth || bufferHeight != mHeight) {
401 ALOGE("Mismatched output buffer dimension: expected=%dx%d, actual=%dx%d", mWidth,
402 mHeight, bufferWidth, bufferHeight);
403 return;
404 }
405 }
406
407 if ((outDesc.usage & mUsage) != mUsage) {
408 ALOGE("Mismatched output buffer usage: actual (%" PRIu64 "), expected (%" PRIu64 ")",
409 outDesc.usage, mUsage);
410 return;
411 }
412
413 uint8_t* data = nullptr;
414 int dataLength = 0;
415 ret = AImage_getPlaneData(img.get(), 0, &data, &dataLength);
416 if (mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) {
417 // When we have CPU_READ_OFTEN usage bits, we can lock the image.
418 if (ret != AMEDIA_OK || data == nullptr || dataLength < 0) {
419 ALOGE("Failed to access CPU data, ret=%d, data=%p, dataLength=%d", ret, data,
420 dataLength);
421 return;
422 }
423 } else {
424 if (ret != AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE || data != nullptr || dataLength != 0) {
425 ALOGE("Shouldn't be able to access CPU data, ret=%d, data=%p, dataLength=%d", ret,
426 data, dataLength);
427 return;
428 }
429 }
430 // Only increase mAcquiredImageCount if all checks pass.
431 mAcquiredImageCount++;
432 }
433
onImageAvailable(void * obj,AImageReader * reader)434 static void onImageAvailable(void* obj, AImageReader* reader) {
435 ImageReaderTestCase* thiz = reinterpret_cast<ImageReaderTestCase*>(obj);
436 thiz->HandleImageAvailable(reader);
437 }
438
439 static void
onBufferRemoved(void *,AImageReader *,AHardwareBuffer *)440 onBufferRemoved(void* /*obj*/, AImageReader* /*reader*/, AHardwareBuffer* /*buffer*/) {
441 // No-op, just to check the listener can be set properly.
442 }
443
444 private:
445 int32_t mWidth;
446 int32_t mHeight;
447 int32_t mFormat;
448 uint64_t mUsage;
449 int32_t mMaxImages;
450 bool mAsync;
451
452 std::mutex mMutex;
453 int mAcquiredImageCount{0};
454
455 AImageReader* mImgReader = nullptr;
456 ANativeWindow* mImgReaderAnw = nullptr;
457
458 AImageReader_ImageListener mReaderAvailableCb{this, onImageAvailable};
459 AImageReader_BufferRemovedListener mReaderDetachedCb{this, onBufferRemoved};
460 };
461
takePictures(uint64_t readerUsage,int readerMaxImages,bool readerAsync,int pictureCount)462 int takePictures(uint64_t readerUsage, int readerMaxImages, bool readerAsync, int pictureCount) {
463 int ret = 0;
464
465 ImageReaderTestCase testCase(
466 kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
467 readerAsync);
468 ret = testCase.initImageReader();
469 if (ret < 0) {
470 return ret;
471 }
472
473 CameraHelper cameraHelper(testCase.getNativeWindow());
474 ret = cameraHelper.initCamera();
475 if (ret < 0) {
476 return ret;
477 }
478
479 if (!cameraHelper.isCameraReady()) {
480 ALOGW("Camera is not ready after successful initialization. It's either due to camera on "
481 "board lacks BACKWARDS_COMPATIBLE capability or the device does not have camera on "
482 "board.");
483 return 0;
484 }
485
486 for (int i = 0; i < pictureCount; i++) {
487 ret = cameraHelper.takePicture();
488 if (ret < 0) {
489 return ret;
490 }
491 }
492
493 // Sleep until all capture finished
494 for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
495 usleep(kCaptureWaitUs);
496 if (testCase.getAcquiredImageCount() == pictureCount) {
497 ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
498 pictureCount);
499 break;
500 }
501 }
502
503 return testCase.getAcquiredImageCount() == pictureCount ? 0 : -1;
504 }
505
506 } // namespace
507
508 // Test that newWithUsage can create AImageReader correctly.
Java_android_media_cts_NativeImageReaderTest_testSucceedsWithSupportedUsageFormatNative(JNIEnv *,jclass)509 extern "C" jboolean Java_android_media_cts_NativeImageReaderTest_\
510 testSucceedsWithSupportedUsageFormatNative(JNIEnv* /*env*/, jclass /*clazz*/) {
511 static constexpr int kTestImageCount = 8;
512
513 for (auto& combination : supportedFormatUsage) {
514 AImageReader* outReader;
515 media_status_t ret = AImageReader_newWithUsage(
516 kTestImageWidth, kTestImageHeight, combination.format, combination.usage,
517 kTestImageCount, &outReader);
518 if (ret != AMEDIA_OK || outReader == nullptr) {
519 ALOGE("AImageReader_newWithUsage failed with format: %" PRId64 ", usage: %" PRId64 ".",
520 combination.format, combination.usage);
521 return false;
522 }
523 AImageReader_delete(outReader);
524 }
525
526 return true;
527 }
528
Java_android_media_cts_NativeImageReaderTest_testTakePicturesNative(JNIEnv *,jclass)529 extern "C" jboolean Java_android_media_cts_NativeImageReaderTest_\
530 testTakePicturesNative(JNIEnv* /*env*/, jclass /*clazz*/) {
531 for (auto& readerUsage :
532 {AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}) {
533 for (auto& readerMaxImages : {1, 4, 8}) {
534 for (auto& readerAsync : {true, false}) {
535 for (auto& pictureCount : {1, 8, 16}) {
536 if (takePictures(readerUsage, readerMaxImages, readerAsync, pictureCount)) {
537 ALOGE("Test takePictures failed for test case usage=%" PRIu64 ", maxImages=%d, "
538 "async=%d, pictureCount=%d",
539 readerUsage, readerMaxImages, readerAsync, pictureCount);
540 return false;
541 }
542 }
543 }
544 }
545 }
546 return true;
547 }
548
Java_android_media_cts_NativeImageReaderTest_testCreateSurfaceNative(JNIEnv * env,jclass)549 extern "C" jobject Java_android_media_cts_NativeImageReaderTest_\
550 testCreateSurfaceNative(JNIEnv* env, jclass /*clazz*/) {
551 static constexpr uint64_t kTestImageUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
552 static constexpr int kTestImageCount = 8;
553
554 ImageReaderTestCase testCase(
555 kTestImageWidth, kTestImageHeight, kTestImageFormat, kTestImageUsage, kTestImageCount,
556 false);
557 int ret = testCase.initImageReader();
558 if (ret < 0) {
559 ALOGE("Failed to get initialize image reader: ret=%d.", ret);
560 return nullptr;
561 }
562
563 // No need to release the window as AImageReader_delete takes care of it.
564 ANativeWindow* window = testCase.getNativeWindow();
565 if (window == nullptr) {
566 ALOGE("Failed to get native window for the test case.");
567 return nullptr;
568 }
569
570 return ANativeWindow_toSurface(env, window);
571 }
572