Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2015 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_NDEBUG 0
     18 #define LOG_TAG "CameraBinderTests"
     19 
     20 #include <binder/IInterface.h>
     21 #include <binder/IServiceManager.h>
     22 #include <binder/Parcel.h>
     23 #include <binder/ProcessState.h>
     24 #include <utils/Errors.h>
     25 #include <utils/Log.h>
     26 #include <utils/List.h>
     27 #include <utils/String8.h>
     28 #include <utils/String16.h>
     29 #include <utils/Condition.h>
     30 #include <utils/Mutex.h>
     31 #include <system/graphics.h>
     32 #include <hardware/gralloc.h>
     33 
     34 #include <camera/CameraMetadata.h>
     35 #include <android/hardware/ICameraService.h>
     36 #include <android/hardware/ICameraServiceListener.h>
     37 #include <android/hardware/BnCameraServiceListener.h>
     38 #include <android/hardware/camera2/ICameraDeviceUser.h>
     39 #include <android/hardware/camera2/ICameraDeviceCallbacks.h>
     40 #include <android/hardware/camera2/BnCameraDeviceCallbacks.h>
     41 #include <camera/camera2/CaptureRequest.h>
     42 #include <camera/camera2/OutputConfiguration.h>
     43 #include <camera/camera2/SubmitInfo.h>
     44 
     45 #include <gui/BufferItemConsumer.h>
     46 #include <gui/IGraphicBufferProducer.h>
     47 #include <gui/Surface.h>
     48 
     49 #include <gtest/gtest.h>
     50 #include <unistd.h>
     51 #include <stdint.h>
     52 #include <utility>
     53 #include <vector>
     54 #include <map>
     55 #include <algorithm>
     56 
     57 using namespace android;
     58 
     59 #define ASSERT_NOT_NULL(x) \
     60     ASSERT_TRUE((x) != nullptr)
     61 
     62 #define SETUP_TIMEOUT 2000000000 // ns
     63 #define IDLE_TIMEOUT 2000000000 // ns
     64 
     65 // Stub listener implementation
     66 class TestCameraServiceListener : public hardware::BnCameraServiceListener {
     67     std::map<String16, int32_t> mCameraTorchStatuses;
     68     std::map<int32_t, int32_t> mCameraStatuses;
     69     mutable Mutex mLock;
     70     mutable Condition mCondition;
     71     mutable Condition mTorchCondition;
     72 public:
     73     virtual ~TestCameraServiceListener() {};
     74 
     75     virtual binder::Status onStatusChanged(int32_t status, int32_t cameraId) {
     76         Mutex::Autolock l(mLock);
     77         mCameraStatuses[cameraId] = status;
     78         mCondition.broadcast();
     79         return binder::Status::ok();
     80     };
     81 
     82     virtual binder::Status onTorchStatusChanged(int32_t status, const String16& cameraId) {
     83         Mutex::Autolock l(mLock);
     84         mCameraTorchStatuses[cameraId] = status;
     85         mTorchCondition.broadcast();
     86         return binder::Status::ok();
     87     };
     88 
     89     bool waitForNumCameras(size_t num) const {
     90         Mutex::Autolock l(mLock);
     91 
     92         if (mCameraStatuses.size() == num) {
     93             return true;
     94         }
     95 
     96         while (mCameraStatuses.size() < num) {
     97             if (mCondition.waitRelative(mLock, SETUP_TIMEOUT) != OK) {
     98                 return false;
     99             }
    100         }
    101         return true;
    102     };
    103 
    104     bool waitForTorchState(int32_t status, int32_t cameraId) const {
    105         Mutex::Autolock l(mLock);
    106 
    107         const auto& iter = mCameraTorchStatuses.find(String16(String8::format("%d", cameraId)));
    108         if (iter != mCameraTorchStatuses.end() && iter->second == status) {
    109             return true;
    110         }
    111 
    112         bool foundStatus = false;
    113         while (!foundStatus) {
    114             if (mTorchCondition.waitRelative(mLock, SETUP_TIMEOUT) != OK) {
    115                 return false;
    116             }
    117             const auto& iter =
    118                     mCameraTorchStatuses.find(String16(String8::format("%d", cameraId)));
    119             foundStatus = (iter != mCameraTorchStatuses.end() && iter->second == status);
    120         }
    121         return true;
    122     };
    123 
    124     int32_t getTorchStatus(int32_t cameraId) const {
    125         Mutex::Autolock l(mLock);
    126         const auto& iter = mCameraTorchStatuses.find(String16(String8::format("%d", cameraId)));
    127         if (iter == mCameraTorchStatuses.end()) {
    128             return hardware::ICameraServiceListener::TORCH_STATUS_UNKNOWN;
    129         }
    130         return iter->second;
    131     };
    132 
    133     int32_t getStatus(int32_t cameraId) const {
    134         Mutex::Autolock l(mLock);
    135         const auto& iter = mCameraStatuses.find(cameraId);
    136         if (iter == mCameraStatuses.end()) {
    137             return hardware::ICameraServiceListener::STATUS_UNKNOWN;
    138         }
    139         return iter->second;
    140     };
    141 };
    142 
    143 // Callback implementation
    144 class TestCameraDeviceCallbacks : public hardware::camera2::BnCameraDeviceCallbacks {
    145 public:
    146     enum Status {
    147         IDLE,
    148         ERROR,
    149         PREPARED,
    150         RUNNING,
    151         SENT_RESULT,
    152         UNINITIALIZED,
    153         REPEATING_REQUEST_ERROR,
    154     };
    155 
    156 protected:
    157     bool mError;
    158     int32_t mLastStatus;
    159     mutable std::vector<int32_t> mStatusesHit;
    160     mutable Mutex mLock;
    161     mutable Condition mStatusCondition;
    162 public:
    163     TestCameraDeviceCallbacks() : mError(false), mLastStatus(UNINITIALIZED) {}
    164 
    165     virtual ~TestCameraDeviceCallbacks() {}
    166 
    167     virtual binder::Status onDeviceError(int errorCode,
    168             const CaptureResultExtras& resultExtras) {
    169         (void) resultExtras;
    170         ALOGE("%s: onDeviceError occurred with: %d", __FUNCTION__, static_cast<int>(errorCode));
    171         Mutex::Autolock l(mLock);
    172         mError = true;
    173         mLastStatus = ERROR;
    174         mStatusesHit.push_back(mLastStatus);
    175         mStatusCondition.broadcast();
    176         return binder::Status::ok();
    177     }
    178 
    179     virtual binder::Status onDeviceIdle() {
    180         Mutex::Autolock l(mLock);
    181         mLastStatus = IDLE;
    182         mStatusesHit.push_back(mLastStatus);
    183         mStatusCondition.broadcast();
    184         return binder::Status::ok();
    185     }
    186 
    187     virtual binder::Status onCaptureStarted(const CaptureResultExtras& resultExtras,
    188             int64_t timestamp) {
    189         (void) resultExtras;
    190         (void) timestamp;
    191         Mutex::Autolock l(mLock);
    192         mLastStatus = RUNNING;
    193         mStatusesHit.push_back(mLastStatus);
    194         mStatusCondition.broadcast();
    195         return binder::Status::ok();
    196     }
    197 
    198 
    199     virtual binder::Status onResultReceived(const CameraMetadata& metadata,
    200             const CaptureResultExtras& resultExtras) {
    201         (void) metadata;
    202         (void) resultExtras;
    203         Mutex::Autolock l(mLock);
    204         mLastStatus = SENT_RESULT;
    205         mStatusesHit.push_back(mLastStatus);
    206         mStatusCondition.broadcast();
    207         return binder::Status::ok();
    208     }
    209 
    210     virtual binder::Status onPrepared(int streamId) {
    211         (void) streamId;
    212         Mutex::Autolock l(mLock);
    213         mLastStatus = PREPARED;
    214         mStatusesHit.push_back(mLastStatus);
    215         mStatusCondition.broadcast();
    216         return binder::Status::ok();
    217     }
    218 
    219     virtual binder::Status onRepeatingRequestError(int64_t lastFrameNumber) {
    220         (void) lastFrameNumber;
    221         Mutex::Autolock l(mLock);
    222         mLastStatus = REPEATING_REQUEST_ERROR;
    223         mStatusesHit.push_back(mLastStatus);
    224         mStatusCondition.broadcast();
    225         return binder::Status::ok();
    226     }
    227 
    228     // Test helper functions:
    229 
    230     bool hadError() const {
    231         Mutex::Autolock l(mLock);
    232         return mError;
    233     }
    234 
    235     bool waitForStatus(Status status) const {
    236         Mutex::Autolock l(mLock);
    237         if (mLastStatus == status) {
    238             return true;
    239         }
    240 
    241         while (std::find(mStatusesHit.begin(), mStatusesHit.end(), status)
    242                 == mStatusesHit.end()) {
    243 
    244             if (mStatusCondition.waitRelative(mLock, IDLE_TIMEOUT) != OK) {
    245                 mStatusesHit.clear();
    246                 return false;
    247             }
    248         }
    249         mStatusesHit.clear();
    250 
    251         return true;
    252 
    253     }
    254 
    255     void clearStatus() const {
    256         Mutex::Autolock l(mLock);
    257         mStatusesHit.clear();
    258     }
    259 
    260     bool waitForIdle() const {
    261         return waitForStatus(IDLE);
    262     }
    263 
    264 };
    265 
    266 namespace {
    267     Mutex                     gLock;
    268     class DeathNotifier : public IBinder::DeathRecipient
    269     {
    270     public:
    271         DeathNotifier() {}
    272 
    273         virtual void binderDied(const wp<IBinder>& /*who*/) {
    274             ALOGV("binderDied");
    275             Mutex::Autolock _l(gLock);
    276             ALOGW("Camera service died!");
    277         }
    278     };
    279     sp<DeathNotifier>         gDeathNotifier;
    280 }; // anonymous namespace
    281 
    282 // Exercise basic binder calls for the camera service
    283 TEST(CameraServiceBinderTest, CheckBinderCameraService) {
    284     ProcessState::self()->startThreadPool();
    285     sp<IServiceManager> sm = defaultServiceManager();
    286     sp<IBinder> binder = sm->getService(String16("media.camera"));
    287     ASSERT_NOT_NULL(binder);
    288     if (gDeathNotifier == NULL) {
    289         gDeathNotifier = new DeathNotifier();
    290     }
    291     binder->linkToDeath(gDeathNotifier);
    292     sp<hardware::ICameraService> service =
    293             interface_cast<hardware::ICameraService>(binder);
    294 
    295     binder::Status res;
    296 
    297     int32_t numCameras = 0;
    298     res = service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
    299     EXPECT_TRUE(res.isOk()) << res;
    300     EXPECT_LE(0, numCameras);
    301 
    302     // Check listener binder calls
    303     sp<TestCameraServiceListener> listener(new TestCameraServiceListener());
    304     res = service->addListener(listener);
    305     EXPECT_TRUE(res.isOk()) << res;
    306 
    307     EXPECT_TRUE(listener->waitForNumCameras(numCameras));
    308 
    309     for (int32_t i = 0; i < numCameras; i++) {
    310         bool isSupported = false;
    311         res = service->supportsCameraApi(i,
    312                 hardware::ICameraService::API_VERSION_2, &isSupported);
    313         EXPECT_TRUE(res.isOk()) << res;
    314 
    315         // We only care about binder calls for the Camera2 API.  Camera1 is deprecated.
    316         if (!isSupported) {
    317             continue;
    318         }
    319 
    320         // Check metadata binder call
    321         CameraMetadata metadata;
    322         res = service->getCameraCharacteristics(i, &metadata);
    323         EXPECT_TRUE(res.isOk()) << res;
    324         EXPECT_FALSE(metadata.isEmpty());
    325 
    326         // Make sure we're available, or skip device tests otherwise
    327         int32_t s = listener->getStatus(i);
    328         EXPECT_EQ(::android::hardware::ICameraServiceListener::STATUS_PRESENT, s);
    329         if (s != ::android::hardware::ICameraServiceListener::STATUS_PRESENT) {
    330             continue;
    331         }
    332 
    333         // Check connect binder calls
    334         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
    335         sp<hardware::camera2::ICameraDeviceUser> device;
    336         res = service->connectDevice(callbacks, i, String16("meeeeeeeee!"),
    337                 hardware::ICameraService::USE_CALLING_UID, /*out*/&device);
    338         EXPECT_TRUE(res.isOk()) << res;
    339         ASSERT_NE(nullptr, device.get());
    340         device->disconnect();
    341         EXPECT_FALSE(callbacks->hadError());
    342 
    343         int32_t torchStatus = listener->getTorchStatus(i);
    344         if (torchStatus == hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF) {
    345             // Check torch calls
    346             res = service->setTorchMode(String16(String8::format("%d", i)),
    347                     /*enabled*/true, callbacks);
    348             EXPECT_TRUE(res.isOk()) << res;
    349             EXPECT_TRUE(listener->waitForTorchState(
    350                     hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON, i));
    351             res = service->setTorchMode(String16(String8::format("%d", i)),
    352                     /*enabled*/false, callbacks);
    353             EXPECT_TRUE(res.isOk()) << res;
    354             EXPECT_TRUE(listener->waitForTorchState(
    355                     hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF, i));
    356         }
    357     }
    358 
    359     res = service->removeListener(listener);
    360     EXPECT_TRUE(res.isOk()) << res;
    361 }
    362 
    363 // Test fixture for client focused binder tests
    364 class CameraClientBinderTest : public testing::Test {
    365 protected:
    366     sp<hardware::ICameraService> service;
    367     int32_t numCameras;
    368     std::vector<std::pair<sp<TestCameraDeviceCallbacks>, sp<hardware::camera2::ICameraDeviceUser>>>
    369             openDeviceList;
    370     sp<TestCameraServiceListener> serviceListener;
    371 
    372     std::pair<sp<TestCameraDeviceCallbacks>, sp<hardware::camera2::ICameraDeviceUser>>
    373             openNewDevice(int deviceId) {
    374         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
    375         sp<hardware::camera2::ICameraDeviceUser> device;
    376         {
    377             SCOPED_TRACE("openNewDevice");
    378             binder::Status res = service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"),
    379                     hardware::ICameraService::USE_CALLING_UID, /*out*/&device);
    380             EXPECT_TRUE(res.isOk()) << res;
    381         }
    382         auto p = std::make_pair(callbacks, device);
    383         openDeviceList.push_back(p);
    384         return p;
    385     }
    386 
    387     void closeDevice(std::pair<sp<TestCameraDeviceCallbacks>,
    388             sp<hardware::camera2::ICameraDeviceUser>>& p) {
    389         if (p.second.get() != nullptr) {
    390             binder::Status res = p.second->disconnect();
    391             EXPECT_TRUE(res.isOk()) << res;
    392             {
    393                 SCOPED_TRACE("closeDevice");
    394                 EXPECT_FALSE(p.first->hadError());
    395             }
    396         }
    397         auto iter = std::find(openDeviceList.begin(), openDeviceList.end(), p);
    398         if (iter != openDeviceList.end()) {
    399             openDeviceList.erase(iter);
    400         }
    401     }
    402 
    403     virtual void SetUp() {
    404         ProcessState::self()->startThreadPool();
    405         sp<IServiceManager> sm = defaultServiceManager();
    406         sp<IBinder> binder = sm->getService(String16("media.camera"));
    407         service = interface_cast<hardware::ICameraService>(binder);
    408         serviceListener = new TestCameraServiceListener();
    409         service->addListener(serviceListener);
    410         service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE,
    411                 &numCameras);
    412     }
    413 
    414     virtual void TearDown() {
    415         service = nullptr;
    416         numCameras = 0;
    417         for (auto& p : openDeviceList) {
    418             closeDevice(p);
    419         }
    420     }
    421 
    422 };
    423 
    424 TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
    425     ASSERT_NOT_NULL(service);
    426     EXPECT_TRUE(serviceListener->waitForNumCameras(numCameras));
    427     for (int32_t i = 0; i < numCameras; i++) {
    428         // Make sure we're available, or skip device tests otherwise
    429         int32_t s = serviceListener->getStatus(i);
    430         EXPECT_EQ(hardware::ICameraServiceListener::STATUS_PRESENT, s);
    431         if (s != hardware::ICameraServiceListener::STATUS_PRESENT) {
    432             continue;
    433         }
    434         binder::Status res;
    435 
    436         auto p = openNewDevice(i);
    437         sp<TestCameraDeviceCallbacks> callbacks = p.first;
    438         sp<hardware::camera2::ICameraDeviceUser> device = p.second;
    439 
    440         // Setup a buffer queue; I'm just using the vendor opaque format here as that is
    441         // guaranteed to be present
    442         sp<IGraphicBufferProducer> gbProducer;
    443         sp<IGraphicBufferConsumer> gbConsumer;
    444         BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
    445         sp<BufferItemConsumer> opaqueConsumer = new BufferItemConsumer(gbConsumer,
    446                 GRALLOC_USAGE_SW_READ_NEVER, /*maxImages*/2, /*controlledByApp*/true);
    447         EXPECT_TRUE(opaqueConsumer.get() != nullptr);
    448         opaqueConsumer->setName(String8("nom nom nom"));
    449 
    450         // Set to VGA dimens for default, as that is guaranteed to be present
    451         EXPECT_EQ(OK, gbConsumer->setDefaultBufferSize(640, 480));
    452         EXPECT_EQ(OK, gbConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED));
    453 
    454         sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false));
    455 
    456         OutputConfiguration output(gbProducer, /*rotation*/0);
    457 
    458         // Can we configure?
    459         res = device->beginConfigure();
    460         EXPECT_TRUE(res.isOk()) << res;
    461         status_t streamId;
    462         res = device->createStream(output, &streamId);
    463         EXPECT_TRUE(res.isOk()) << res;
    464         EXPECT_LE(0, streamId);
    465         res = device->endConfigure(/*isConstrainedHighSpeed*/ false);
    466         EXPECT_TRUE(res.isOk()) << res;
    467         EXPECT_FALSE(callbacks->hadError());
    468 
    469         // Can we make requests?
    470         CameraMetadata requestTemplate;
    471         res = device->createDefaultRequest(/*preview template*/1,
    472                 /*out*/&requestTemplate);
    473         EXPECT_TRUE(res.isOk()) << res;
    474 
    475         hardware::camera2::CaptureRequest request;
    476         request.mMetadata = requestTemplate;
    477         request.mSurfaceList.add(surface);
    478         request.mIsReprocess = false;
    479         int64_t lastFrameNumber = 0;
    480         int64_t lastFrameNumberPrev = 0;
    481         callbacks->clearStatus();
    482 
    483         hardware::camera2::utils::SubmitInfo info;
    484         res = device->submitRequest(request, /*streaming*/true, /*out*/&info);
    485         EXPECT_TRUE(res.isOk()) << res;
    486         EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT));
    487         EXPECT_LE(0, info.mRequestId);
    488 
    489         // Can we stop requests?
    490         res = device->cancelRequest(info.mRequestId, /*out*/&lastFrameNumber);
    491         EXPECT_TRUE(res.isOk()) << res;
    492         EXPECT_TRUE(callbacks->waitForIdle());
    493         EXPECT_FALSE(callbacks->hadError());
    494 
    495         // Can we do it again?
    496         lastFrameNumberPrev = info.mLastFrameNumber;
    497         lastFrameNumber = 0;
    498         requestTemplate.clear();
    499         res = device->createDefaultRequest(hardware::camera2::ICameraDeviceUser::TEMPLATE_PREVIEW,
    500                 /*out*/&requestTemplate);
    501         EXPECT_TRUE(res.isOk()) << res;
    502         hardware::camera2::CaptureRequest request2;
    503         request2.mMetadata = requestTemplate;
    504         request2.mSurfaceList.add(surface);
    505         request2.mIsReprocess = false;
    506         callbacks->clearStatus();
    507         hardware::camera2::utils::SubmitInfo info2;
    508         res = device->submitRequest(request2, /*streaming*/true,
    509                 /*out*/&info2);
    510         EXPECT_TRUE(res.isOk()) << res;
    511         EXPECT_EQ(hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES,
    512                 info2.mLastFrameNumber);
    513         lastFrameNumber = 0;
    514         EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT));
    515         EXPECT_LE(0, info2.mRequestId);
    516         res = device->cancelRequest(info2.mRequestId, /*out*/&lastFrameNumber);
    517         EXPECT_TRUE(res.isOk()) << res;
    518         EXPECT_TRUE(callbacks->waitForIdle());
    519         EXPECT_LE(lastFrameNumberPrev, lastFrameNumber);
    520         sleep(/*second*/1); // allow some time for errors to show up, if any
    521         EXPECT_FALSE(callbacks->hadError());
    522 
    523         // Can we do it with a request list?
    524         lastFrameNumberPrev = lastFrameNumber;
    525         lastFrameNumber = 0;
    526         requestTemplate.clear();
    527         CameraMetadata requestTemplate2;
    528         res = device->createDefaultRequest(hardware::camera2::ICameraDeviceUser::TEMPLATE_PREVIEW,
    529                 /*out*/&requestTemplate);
    530         EXPECT_TRUE(res.isOk()) << res;
    531         res = device->createDefaultRequest(hardware::camera2::ICameraDeviceUser::TEMPLATE_PREVIEW,
    532                 /*out*/&requestTemplate2);
    533         EXPECT_TRUE(res.isOk()) << res;
    534         android::hardware::camera2::CaptureRequest request3;
    535         android::hardware::camera2::CaptureRequest request4;
    536         request3.mMetadata = requestTemplate;
    537         request3.mSurfaceList.add(surface);
    538         request3.mIsReprocess = false;
    539         request4.mMetadata = requestTemplate2;
    540         request4.mSurfaceList.add(surface);
    541         request4.mIsReprocess = false;
    542         std::vector<hardware::camera2::CaptureRequest> requestList;
    543         requestList.push_back(request3);
    544         requestList.push_back(request4);
    545 
    546         callbacks->clearStatus();
    547         hardware::camera2::utils::SubmitInfo info3;
    548         res = device->submitRequestList(requestList, /*streaming*/false,
    549                 /*out*/&info3);
    550         EXPECT_TRUE(res.isOk()) << res;
    551         EXPECT_LE(0, info3.mRequestId);
    552         EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT));
    553         EXPECT_TRUE(callbacks->waitForIdle());
    554         EXPECT_LE(lastFrameNumberPrev, info3.mLastFrameNumber);
    555         sleep(/*second*/1); // allow some time for errors to show up, if any
    556         EXPECT_FALSE(callbacks->hadError());
    557 
    558         // Can we unconfigure?
    559         res = device->beginConfigure();
    560         EXPECT_TRUE(res.isOk()) << res;
    561         res = device->deleteStream(streamId);
    562         EXPECT_TRUE(res.isOk()) << res;
    563         res = device->endConfigure(/*isConstrainedHighSpeed*/ false);
    564         EXPECT_TRUE(res.isOk()) << res;
    565 
    566         sleep(/*second*/1); // allow some time for errors to show up, if any
    567         EXPECT_FALSE(callbacks->hadError());
    568 
    569         closeDevice(p);
    570     }
    571 
    572 };
    573