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