| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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> | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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> | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 41 | #include <camera/camera2/CaptureRequest.h> | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 42 | #include <camera/camera2/OutputConfiguration.h> | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 43 | #include <camera/camera2/SubmitInfo.h> | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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 | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 66 | class TestCameraServiceListener : public hardware::BnCameraServiceListener { | 
|  | 67 | std::map<String16, int32_t> mCameraTorchStatuses; | 
|  | 68 | std::map<int32_t, int32_t> mCameraStatuses; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 69 | mutable Mutex mLock; | 
|  | 70 | mutable Condition mCondition; | 
|  | 71 | mutable Condition mTorchCondition; | 
|  | 72 | public: | 
|  | 73 | virtual ~TestCameraServiceListener() {}; | 
|  | 74 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 75 | virtual binder::Status onStatusChanged(int32_t status, int32_t cameraId) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 76 | Mutex::Autolock l(mLock); | 
|  | 77 | mCameraStatuses[cameraId] = status; | 
|  | 78 | mCondition.broadcast(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 79 | return binder::Status::ok(); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 80 | }; | 
|  | 81 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 82 | virtual binder::Status onTorchStatusChanged(int32_t status, const String16& cameraId) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 83 | Mutex::Autolock l(mLock); | 
|  | 84 | mCameraTorchStatuses[cameraId] = status; | 
|  | 85 | mTorchCondition.broadcast(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 86 | return binder::Status::ok(); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 104 | bool waitForTorchState(int32_t status, int32_t cameraId) const { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 124 | int32_t getTorchStatus(int32_t cameraId) const { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 125 | Mutex::Autolock l(mLock); | 
|  | 126 | const auto& iter = mCameraTorchStatuses.find(String16(String8::format("%d", cameraId))); | 
|  | 127 | if (iter == mCameraTorchStatuses.end()) { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 128 | return hardware::ICameraServiceListener::TORCH_STATUS_UNKNOWN; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 129 | } | 
|  | 130 | return iter->second; | 
|  | 131 | }; | 
|  | 132 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 133 | int32_t getStatus(int32_t cameraId) const { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 134 | Mutex::Autolock l(mLock); | 
|  | 135 | const auto& iter = mCameraStatuses.find(cameraId); | 
|  | 136 | if (iter == mCameraStatuses.end()) { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 137 | return hardware::ICameraServiceListener::STATUS_UNKNOWN; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 138 | } | 
|  | 139 | return iter->second; | 
|  | 140 | }; | 
|  | 141 | }; | 
|  | 142 |  | 
|  | 143 | // Callback implementation | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 144 | class TestCameraDeviceCallbacks : public hardware::camera2::BnCameraDeviceCallbacks { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 145 | public: | 
|  | 146 | enum Status { | 
|  | 147 | IDLE, | 
|  | 148 | ERROR, | 
|  | 149 | PREPARED, | 
|  | 150 | RUNNING, | 
|  | 151 | SENT_RESULT, | 
| Chien-Yu Chen | e8c535e | 2016-04-14 12:18:26 -0700 | [diff] [blame] | 152 | UNINITIALIZED, | 
|  | 153 | REPEATING_REQUEST_ERROR, | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 154 | }; | 
|  | 155 |  | 
|  | 156 | protected: | 
|  | 157 | bool mError; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 158 | int32_t mLastStatus; | 
|  | 159 | mutable std::vector<int32_t> mStatusesHit; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 160 | mutable Mutex mLock; | 
|  | 161 | mutable Condition mStatusCondition; | 
|  | 162 | public: | 
|  | 163 | TestCameraDeviceCallbacks() : mError(false), mLastStatus(UNINITIALIZED) {} | 
|  | 164 |  | 
|  | 165 | virtual ~TestCameraDeviceCallbacks() {} | 
|  | 166 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 167 | virtual binder::Status onDeviceError(int errorCode, | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 168 | const CaptureResultExtras& resultExtras) { | 
| Eino-Ville Talvala | d309fb9 | 2015-11-25 12:12:45 -0800 | [diff] [blame] | 169 | (void) resultExtras; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 176 | return binder::Status::ok(); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 177 | } | 
|  | 178 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 179 | virtual binder::Status onDeviceIdle() { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 180 | Mutex::Autolock l(mLock); | 
|  | 181 | mLastStatus = IDLE; | 
|  | 182 | mStatusesHit.push_back(mLastStatus); | 
|  | 183 | mStatusCondition.broadcast(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 184 | return binder::Status::ok(); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 185 | } | 
|  | 186 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 187 | virtual binder::Status onCaptureStarted(const CaptureResultExtras& resultExtras, | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 188 | int64_t timestamp) { | 
| Eino-Ville Talvala | d309fb9 | 2015-11-25 12:12:45 -0800 | [diff] [blame] | 189 | (void) resultExtras; | 
|  | 190 | (void) timestamp; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 191 | Mutex::Autolock l(mLock); | 
|  | 192 | mLastStatus = RUNNING; | 
|  | 193 | mStatusesHit.push_back(mLastStatus); | 
|  | 194 | mStatusCondition.broadcast(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 195 | return binder::Status::ok(); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 196 | } | 
|  | 197 |  | 
|  | 198 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 199 | virtual binder::Status onResultReceived(const CameraMetadata& metadata, | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 200 | const CaptureResultExtras& resultExtras) { | 
| Eino-Ville Talvala | d309fb9 | 2015-11-25 12:12:45 -0800 | [diff] [blame] | 201 | (void) metadata; | 
|  | 202 | (void) resultExtras; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 203 | Mutex::Autolock l(mLock); | 
|  | 204 | mLastStatus = SENT_RESULT; | 
|  | 205 | mStatusesHit.push_back(mLastStatus); | 
|  | 206 | mStatusCondition.broadcast(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 207 | return binder::Status::ok(); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 208 | } | 
|  | 209 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 210 | virtual binder::Status onPrepared(int streamId) { | 
| Eino-Ville Talvala | d309fb9 | 2015-11-25 12:12:45 -0800 | [diff] [blame] | 211 | (void) streamId; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 212 | Mutex::Autolock l(mLock); | 
|  | 213 | mLastStatus = PREPARED; | 
|  | 214 | mStatusesHit.push_back(mLastStatus); | 
|  | 215 | mStatusCondition.broadcast(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 216 | return binder::Status::ok(); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 217 | } | 
|  | 218 |  | 
| Chien-Yu Chen | e8c535e | 2016-04-14 12:18:26 -0700 | [diff] [blame] | 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 |  | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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 |  | 
| Yin-Chia Yeh | 0dea57f | 2015-12-09 16:46:07 -0800 | [diff] [blame] | 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 |  | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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); | 
| Yin-Chia Yeh | 0dea57f | 2015-12-09 16:46:07 -0800 | [diff] [blame] | 288 | if (gDeathNotifier == NULL) { | 
|  | 289 | gDeathNotifier = new DeathNotifier(); | 
|  | 290 | } | 
|  | 291 | binder->linkToDeath(gDeathNotifier); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 292 | sp<hardware::ICameraService> service = | 
|  | 293 | interface_cast<hardware::ICameraService>(binder); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 294 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 295 | binder::Status res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 296 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 297 | int32_t numCameras = 0; | 
|  | 298 | res = service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras); | 
|  | 299 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 300 | EXPECT_LE(0, numCameras); | 
|  | 301 |  | 
|  | 302 | // Check listener binder calls | 
|  | 303 | sp<TestCameraServiceListener> listener(new TestCameraServiceListener()); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 304 | res = service->addListener(listener); | 
|  | 305 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 306 |  | 
|  | 307 | EXPECT_TRUE(listener->waitForNumCameras(numCameras)); | 
|  | 308 |  | 
|  | 309 | for (int32_t i = 0; i < numCameras; i++) { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 310 | bool isSupported = false; | 
|  | 311 | res = service->supportsCameraApi(i, | 
|  | 312 | hardware::ICameraService::API_VERSION_2, &isSupported); | 
|  | 313 | EXPECT_TRUE(res.isOk()) << res; | 
|  | 314 |  | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 315 | // We only care about binder calls for the Camera2 API.  Camera1 is deprecated. | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 316 | if (!isSupported) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 317 | continue; | 
|  | 318 | } | 
|  | 319 |  | 
|  | 320 | // Check metadata binder call | 
|  | 321 | CameraMetadata metadata; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 322 | res = service->getCameraCharacteristics(i, &metadata); | 
|  | 323 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 324 | EXPECT_FALSE(metadata.isEmpty()); | 
|  | 325 |  | 
|  | 326 | // Make sure we're available, or skip device tests otherwise | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 327 | int32_t s = listener->getStatus(i); | 
|  | 328 | EXPECT_EQ(::android::hardware::ICameraServiceListener::STATUS_PRESENT, s); | 
|  | 329 | if (s != ::android::hardware::ICameraServiceListener::STATUS_PRESENT) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 330 | continue; | 
|  | 331 | } | 
|  | 332 |  | 
|  | 333 | // Check connect binder calls | 
|  | 334 | sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks()); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 339 | ASSERT_NE(nullptr, device.get()); | 
|  | 340 | device->disconnect(); | 
|  | 341 | EXPECT_FALSE(callbacks->hadError()); | 
|  | 342 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 343 | int32_t torchStatus = listener->getTorchStatus(i); | 
|  | 344 | if (torchStatus == hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 345 | // Check torch calls | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 346 | res = service->setTorchMode(String16(String8::format("%d", i)), | 
|  | 347 | /*enabled*/true, callbacks); | 
|  | 348 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 349 | EXPECT_TRUE(listener->waitForTorchState( | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 354 | EXPECT_TRUE(listener->waitForTorchState( | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 355 | hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF, i)); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 356 | } | 
|  | 357 | } | 
|  | 358 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 359 | res = service->removeListener(listener); | 
|  | 360 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 361 | } | 
|  | 362 |  | 
|  | 363 | // Test fixture for client focused binder tests | 
|  | 364 | class CameraClientBinderTest : public testing::Test { | 
|  | 365 | protected: | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 366 | sp<hardware::ICameraService> service; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 367 | int32_t numCameras; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 368 | std::vector<std::pair<sp<TestCameraDeviceCallbacks>, sp<hardware::camera2::ICameraDeviceUser>>> | 
|  | 369 | openDeviceList; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 370 | sp<TestCameraServiceListener> serviceListener; | 
|  | 371 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 372 | std::pair<sp<TestCameraDeviceCallbacks>, sp<hardware::camera2::ICameraDeviceUser>> | 
|  | 373 | openNewDevice(int deviceId) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 374 | sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks()); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 375 | sp<hardware::camera2::ICameraDeviceUser> device; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 376 | { | 
|  | 377 | SCOPED_TRACE("openNewDevice"); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 378 | binder::Status res = service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"), | 
|  | 379 | hardware::ICameraService::USE_CALLING_UID, /*out*/&device); | 
|  | 380 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 381 | } | 
|  | 382 | auto p = std::make_pair(callbacks, device); | 
|  | 383 | openDeviceList.push_back(p); | 
|  | 384 | return p; | 
|  | 385 | } | 
|  | 386 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 387 | void closeDevice(std::pair<sp<TestCameraDeviceCallbacks>, | 
|  | 388 | sp<hardware::camera2::ICameraDeviceUser>>& p) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 389 | if (p.second.get() != nullptr) { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 390 | binder::Status res = p.second->disconnect(); | 
|  | 391 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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")); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 407 | service = interface_cast<hardware::ICameraService>(binder); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 408 | serviceListener = new TestCameraServiceListener(); | 
|  | 409 | service->addListener(serviceListener); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 410 | service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE, | 
|  | 411 | &numCameras); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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 | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 429 | int32_t s = serviceListener->getStatus(i); | 
|  | 430 | EXPECT_EQ(hardware::ICameraServiceListener::STATUS_PRESENT, s); | 
|  | 431 | if (s != hardware::ICameraServiceListener::STATUS_PRESENT) { | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 432 | continue; | 
|  | 433 | } | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 434 | binder::Status res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 435 |  | 
|  | 436 | auto p = openNewDevice(i); | 
|  | 437 | sp<TestCameraDeviceCallbacks> callbacks = p.first; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 438 | sp<hardware::camera2::ICameraDeviceUser> device = p.second; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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? | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 464 | EXPECT_LE(0, streamId); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 465 | res = device->endConfigure(/*isConstrainedHighSpeed*/ false); | 
|  | 466 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 467 | EXPECT_FALSE(callbacks->hadError()); | 
|  | 468 |  | 
|  | 469 | // Can we make requests? | 
|  | 470 | CameraMetadata requestTemplate; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 479 | int64_t lastFrameNumber = 0; | 
|  | 480 | int64_t lastFrameNumberPrev = 0; | 
|  | 481 | callbacks->clearStatus(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 482 |  | 
|  | 483 | hardware::camera2::utils::SubmitInfo info; | 
|  | 484 | res = device->submitRequest(request, /*streaming*/true, /*out*/&info); | 
|  | 485 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 486 | EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 487 | EXPECT_LE(0, info.mRequestId); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 488 |  | 
|  | 489 | // Can we stop requests? | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 490 | res = device->cancelRequest(info.mRequestId, /*out*/&lastFrameNumber); | 
|  | 491 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 492 | EXPECT_TRUE(callbacks->waitForIdle()); | 
|  | 493 | EXPECT_FALSE(callbacks->hadError()); | 
|  | 494 |  | 
|  | 495 | // Can we do it again? | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 496 | lastFrameNumberPrev = info.mLastFrameNumber; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 497 | lastFrameNumber = 0; | 
|  | 498 | requestTemplate.clear(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 506 | callbacks->clearStatus(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 513 | lastFrameNumber = 0; | 
|  | 514 | EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 515 | EXPECT_LE(0, info2.mRequestId); | 
|  | 516 | res = device->cancelRequest(info2.mRequestId, /*out*/&lastFrameNumber); | 
|  | 517 | EXPECT_TRUE(res.isOk()) << res; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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; | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 543 | requestList.push_back(request3); | 
|  | 544 | requestList.push_back(request4); | 
|  | 545 |  | 
|  | 546 | callbacks->clearStatus(); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 552 | EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); | 
|  | 553 | EXPECT_TRUE(callbacks->waitForIdle()); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 554 | EXPECT_LE(lastFrameNumberPrev, info3.mLastFrameNumber); | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 555 | sleep(/*second*/1); // allow some time for errors to show up, if any | 
|  | 556 | EXPECT_FALSE(callbacks->hadError()); | 
|  | 557 |  | 
|  | 558 | // Can we unconfigure? | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 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 |  | 
| Ruben Brunk | 3450ba7 | 2015-06-16 11:00:37 -0700 | [diff] [blame] | 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 | }; |