blob: 6fa0864d5a2a4d4c31fcd05571c8c3009e3d57e0 [file] [log] [blame]
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -08001/*
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 "ACameraManager"
19
20#include <memory>
21#include "ACameraManager.h"
22#include "ACameraMetadata.h"
23#include "ACameraDevice.h"
24#include <utils/Vector.h>
25#include <stdlib.h>
26#include <camera/VendorTagDescriptor.h>
27
28using namespace android;
29
30//constants shared between ACameraManager and CameraManagerGlobal
31namespace {
32 const int kMaxCameraIdLen = 32;
33}
34
35namespace android {
36// Static member definitions
37const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
38const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
39const char* CameraManagerGlobal::kContextKey = "CallbackContext";
40Mutex CameraManagerGlobal::sLock;
41CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
42
43CameraManagerGlobal&
44CameraManagerGlobal::getInstance() {
45 Mutex::Autolock _l(sLock);
46 CameraManagerGlobal* instance = sInstance;
47 if (instance == nullptr) {
48 instance = new CameraManagerGlobal();
49 sInstance = instance;
50 }
51 return *instance;
52}
53
54CameraManagerGlobal::~CameraManagerGlobal() {
55 // clear sInstance so next getInstance call knows to create a new one
56 Mutex::Autolock _sl(sLock);
57 sInstance = nullptr;
58 Mutex::Autolock _l(mLock);
59 if (mCameraService != nullptr) {
60 IInterface::asBinder(mCameraService)->unlinkToDeath(mDeathNotifier);
Yin-Chia Yehead91462016-01-06 16:45:08 -080061 mCameraService->removeListener(mCameraServiceListener);
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -080062 }
63 mDeathNotifier.clear();
64 if (mCbLooper != nullptr) {
65 mCbLooper->unregisterHandler(mHandler->id());
66 mCbLooper->stop();
67 }
68 mCbLooper.clear();
69 mHandler.clear();
70 mCameraServiceListener.clear();
71 mCameraService.clear();
72}
73
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -080074sp<hardware::ICameraService> CameraManagerGlobal::getCameraService() {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -080075 Mutex::Autolock _l(mLock);
76 if (mCameraService.get() == nullptr) {
77 sp<IServiceManager> sm = defaultServiceManager();
78 sp<IBinder> binder;
79 do {
80 binder = sm->getService(String16(kCameraServiceName));
81 if (binder != nullptr) {
82 break;
83 }
84 ALOGW("CameraService not published, waiting...");
85 usleep(kCameraServicePollDelay);
86 } while(true);
87 if (mDeathNotifier == nullptr) {
88 mDeathNotifier = new DeathNotifier(this);
89 }
90 binder->linkToDeath(mDeathNotifier);
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -080091 mCameraService = interface_cast<hardware::ICameraService>(binder);
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -080092
93 // Setup looper thread to perfrom availiability callbacks
94 if (mCbLooper == nullptr) {
95 mCbLooper = new ALooper;
96 mCbLooper->setName("C2N-mgr-looper");
97 status_t ret = mCbLooper->start(
98 /*runOnCallingThread*/false,
99 /*canCallJava*/ true,
Yin-Chia Yehead91462016-01-06 16:45:08 -0800100 PRIORITY_DEFAULT);
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800101 if (mHandler == nullptr) {
102 mHandler = new CallbackHandler();
103 }
104 mCbLooper->registerHandler(mHandler);
105 }
106
107 // register ICameraServiceListener
108 if (mCameraServiceListener == nullptr) {
109 mCameraServiceListener = new CameraServiceListener(this);
110 }
111 mCameraService->addListener(mCameraServiceListener);
112
113 // setup vendor tags
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800114 sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
115 binder::Status ret = mCameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800116
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800117 if (ret.isOk()) {
118 status_t err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
119 if (err != OK) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800120 ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800121 __FUNCTION__, strerror(-err), err);
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800122 }
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800123 } else if (ret.serviceSpecificErrorCode() ==
124 hardware::ICameraService::ERROR_DEPRECATED_HAL) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800125 ALOGW("%s: Camera HAL too old; does not support vendor tags",
126 __FUNCTION__);
127 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
128 } else {
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800129 ALOGE("%s: Failed to get vendor tag descriptors: %s",
130 __FUNCTION__, ret.toString8().string());
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800131 }
132 }
133 ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
134 return mCameraService;
135}
136
137void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
138{
139 ALOGE("Camera service binderDied!");
140 sp<CameraManagerGlobal> cm = mCameraManager.promote();
141 if (cm != nullptr) {
142 AutoMutex lock(cm->mLock);
143 for (auto pair : cm->mDeviceStatusMap) {
144 int32_t cameraId = pair.first;
145 cm->onStatusChangedLocked(
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800146 CameraServiceListener::STATUS_NOT_PRESENT, cameraId);
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800147 }
148 cm->mCameraService.clear();
149 // TODO: consider adding re-connect call here?
150 }
151}
152
153void CameraManagerGlobal::registerAvailabilityCallback(
154 const ACameraManager_AvailabilityCallbacks *callback) {
155 Mutex::Autolock _l(mLock);
156 Callback cb(callback);
157 auto pair = mCallbacks.insert(cb);
158 // Send initial callbacks if callback is newly registered
159 if (pair.second) {
160 for (auto pair : mDeviceStatusMap) {
161 int32_t cameraId = pair.first;
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800162 int32_t status = pair.second;
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800163
164 sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
165 ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
166 callback->onCameraAvailable : callback->onCameraUnavailable;
167 msg->setPointer(kCallbackFpKey, (void *) cb);
168 msg->setPointer(kContextKey, callback->context);
169 msg->setInt32(kCameraIdKey, cameraId);
170 msg->post();
171 }
172 }
173}
174
175void CameraManagerGlobal::unregisterAvailabilityCallback(
176 const ACameraManager_AvailabilityCallbacks *callback) {
177 Mutex::Autolock _l(mLock);
178 Callback cb(callback);
179 mCallbacks.erase(cb);
180}
181
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800182bool CameraManagerGlobal::validStatus(int32_t status) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800183 switch (status) {
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800184 case hardware::ICameraServiceListener::STATUS_NOT_PRESENT:
185 case hardware::ICameraServiceListener::STATUS_PRESENT:
186 case hardware::ICameraServiceListener::STATUS_ENUMERATING:
187 case hardware::ICameraServiceListener::STATUS_NOT_AVAILABLE:
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800188 return true;
189 default:
190 return false;
191 }
192}
193
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800194bool CameraManagerGlobal::isStatusAvailable(int32_t status) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800195 switch (status) {
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800196 case hardware::ICameraServiceListener::STATUS_PRESENT:
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800197 return true;
198 default:
199 return false;
200 }
201}
202
203void CameraManagerGlobal::CallbackHandler::sendSingleCallback(
204 int32_t cameraId, void* context,
205 ACameraManager_AvailabilityCallback cb) const {
206 char cameraIdStr[kMaxCameraIdLen];
207 snprintf(cameraIdStr, sizeof(cameraIdStr), "%d", cameraId);
208 (*cb)(context, cameraIdStr);
209}
210
211void CameraManagerGlobal::CallbackHandler::onMessageReceived(
212 const sp<AMessage> &msg) {
213 switch (msg->what()) {
214 case kWhatSendSingleCallback:
215 {
216 ACameraManager_AvailabilityCallback cb;
217 void* context;
218 int32_t cameraId;
219 bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
220 if (!found) {
221 ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
222 return;
223 }
224 found = msg->findPointer(kContextKey, &context);
225 if (!found) {
226 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
227 return;
228 }
229 found = msg->findInt32(kCameraIdKey, &cameraId);
230 if (!found) {
231 ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
232 return;
233 }
234 sendSingleCallback(cameraId, context, cb);
235 break;
236 }
237 default:
238 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
239 break;
240 }
241}
242
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800243binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
244 int32_t status, int32_t cameraId) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800245 sp<CameraManagerGlobal> cm = mCameraManager.promote();
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800246 if (cm != nullptr) {
247 cm->onStatusChanged(status, cameraId);
248 } else {
Yin-Chia Yehead91462016-01-06 16:45:08 -0800249 ALOGE("Cannot deliver status change. Global camera manager died");
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800250 }
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800251 return binder::Status::ok();
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800252}
253
254void CameraManagerGlobal::onStatusChanged(
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800255 int32_t status, int32_t cameraId) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800256 Mutex::Autolock _l(mLock);
257 onStatusChangedLocked(status, cameraId);
258}
259
260void CameraManagerGlobal::onStatusChangedLocked(
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800261 int32_t status, int32_t cameraId) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800262 if (!validStatus(status)) {
263 ALOGE("%s: Invalid status %d", __FUNCTION__, status);
264 return;
265 }
266
267 bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800268 int32_t oldStatus = firstStatus ?
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800269 status : // first status
270 mDeviceStatusMap[cameraId];
271
272 if (!firstStatus &&
273 isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
274 // No status update. No need to send callback
275 return;
276 }
277
278 // Iterate through all registered callbacks
279 mDeviceStatusMap[cameraId] = status;
280 for (auto cb : mCallbacks) {
281 sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
282 ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
283 cb.mAvailable : cb.mUnavailable;
284 msg->setPointer(kCallbackFpKey, (void *) cbFp);
285 msg->setPointer(kContextKey, cb.mContext);
286 msg->setInt32(kCameraIdKey, cameraId);
287 msg->post();
288 }
289}
290
291} // namespace android
292
293/**
294 * ACameraManger Implementation
295 */
296camera_status_t
297ACameraManager::getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList) {
298 if (mCachedCameraIdList.numCameras == kCameraIdListNotInit) {
299 int numCameras = 0;
300 Vector<char *> cameraIds;
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800301 sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800302 if (cs == nullptr) {
303 ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
304 return ACAMERA_ERROR_CAMERA_DISCONNECTED;
305 }
306 // Get number of cameras
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800307 int numAllCameras = 0;
308 binder::Status serviceRet = cs->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_ALL,
309 &numAllCameras);
310 if (!serviceRet.isOk()) {
311 ALOGE("%s: Error getting camera count: %s", __FUNCTION__,
312 serviceRet.toString8().string());
313 numAllCameras = 0;
314 }
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800315 // Filter API2 compatible cameras and push to cameraIds
316 for (int i = 0; i < numAllCameras; i++) {
317 // TODO: Only suppot HALs that supports API2 directly now
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800318 bool camera2Support = false;
319 serviceRet = cs->supportsCameraApi(i, hardware::ICameraService::API_VERSION_2,
320 &camera2Support);
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800321 char buf[kMaxCameraIdLen];
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800322 if (camera2Support) {
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800323 numCameras++;
324 mCameraIds.insert(i);
325 snprintf(buf, sizeof(buf), "%d", i);
326 size_t cameraIdSize = strlen(buf) + 1;
327 char *cameraId = new char[cameraIdSize];
328 if (!cameraId) {
329 ALOGE("Allocate memory for ACameraIdList failed!");
330 return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
331 }
332 strlcpy(cameraId, buf, cameraIdSize);
333 cameraIds.push(cameraId);
334 }
335 }
336 mCachedCameraIdList.numCameras = numCameras;
337 mCachedCameraIdList.cameraIds = new const char*[numCameras];
338 if (!mCachedCameraIdList.cameraIds) {
339 ALOGE("Allocate memory for ACameraIdList failed!");
340 return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
341 }
342 for (int i = 0; i < numCameras; i++) {
343 mCachedCameraIdList.cameraIds[i] = cameraIds[i];
344 }
345 }
346 *cameraIdList = &mCachedCameraIdList;
347 return ACAMERA_OK;
348}
349
350camera_status_t
351ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
352 Mutex::Autolock _l(mLock);
353 ACameraIdList* cachedList;
354 camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
355 if (ret != ACAMERA_OK) {
356 ALOGE("Get camera ID list failed! err: %d", ret);
357 return ret;
358 }
359
360 int numCameras = cachedList->numCameras;
361 ACameraIdList *out = new ACameraIdList;
362 if (!out) {
363 ALOGE("Allocate memory for ACameraIdList failed!");
364 return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
365 }
366 out->numCameras = numCameras;
367 out->cameraIds = new const char*[numCameras];
368 if (!out->cameraIds) {
369 ALOGE("Allocate memory for ACameraIdList failed!");
370 return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
371 }
372 for (int i = 0; i < numCameras; i++) {
373 const char* src = cachedList->cameraIds[i];
374 size_t dstSize = strlen(src) + 1;
375 char* dst = new char[dstSize];
376 if (!dst) {
377 ALOGE("Allocate memory for ACameraIdList failed!");
378 return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
379 }
380 strlcpy(dst, src, dstSize);
381 out->cameraIds[i] = dst;
382 }
383 *cameraIdList = out;
384 return ACAMERA_OK;
385}
386
387void
388ACameraManager::deleteCameraIdList(ACameraIdList* cameraIdList) {
389 if (cameraIdList != nullptr) {
390 if (cameraIdList->cameraIds != nullptr) {
391 for (int i = 0; i < cameraIdList->numCameras; i ++) {
392 delete[] cameraIdList->cameraIds[i];
393 }
394 delete[] cameraIdList->cameraIds;
395 }
396 delete cameraIdList;
397 }
398}
399
400camera_status_t ACameraManager::getCameraCharacteristics(
401 const char *cameraIdStr, ACameraMetadata **characteristics) {
402 Mutex::Autolock _l(mLock);
403 ACameraIdList* cachedList;
404 // Make sure mCameraIds is initialized
405 camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
406 if (ret != ACAMERA_OK) {
407 ALOGE("%s: Get camera ID list failed! err: %d", __FUNCTION__, ret);
408 return ret;
409 }
410 int cameraId = atoi(cameraIdStr);
411 if (mCameraIds.count(cameraId) == 0) {
412 ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, cameraIdStr);
413 return ACAMERA_ERROR_INVALID_PARAMETER;
414 }
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800415 sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800416 if (cs == nullptr) {
417 ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
418 return ACAMERA_ERROR_CAMERA_DISCONNECTED;
419 }
420 CameraMetadata rawMetadata;
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800421 binder::Status serviceRet = cs->getCameraCharacteristics(cameraId, &rawMetadata);
422 if (!serviceRet.isOk()) {
423 ALOGE("Get camera characteristics from camera service failed: %s",
424 serviceRet.toString8().string());
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800425 return ACAMERA_ERROR_UNKNOWN; // should not reach here
426 }
427
428 *characteristics = new ACameraMetadata(
429 rawMetadata.release(), ACameraMetadata::ACM_CHARACTERISTICS);
430 return ACAMERA_OK;
431}
432
433camera_status_t
434ACameraManager::openCamera(
435 const char* cameraId,
436 ACameraDevice_StateCallbacks* callback,
437 /*out*/ACameraDevice** outDevice) {
438 ACameraMetadata* rawChars;
439 camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
440 Mutex::Autolock _l(mLock);
441 if (ret != ACAMERA_OK) {
442 ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
443 __FUNCTION__, cameraId, ret);
444 return ACAMERA_ERROR_INVALID_PARAMETER;
445 }
446 std::unique_ptr<ACameraMetadata> chars(rawChars);
447 rawChars = nullptr;
448
449 ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(chars));
450
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800451 sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800452 if (cs == nullptr) {
453 ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
454 return ACAMERA_ERROR_CAMERA_DISCONNECTED;
455 }
456
457 int id = atoi(cameraId);
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800458 sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
459 sp<hardware::camera2::ICameraDeviceUser> deviceRemote;
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800460 // No way to get package name from native.
461 // Send a zero length package name and let camera service figure it out from UID
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800462 binder::Status serviceRet = cs->connectDevice(
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800463 callbacks, id, String16(""),
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800464 hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800465
Eino-Ville Talvalad56db1d2015-12-17 16:50:35 -0800466 if (!serviceRet.isOk()) {
467 ALOGE("%s: connect camera device failed: %s", __FUNCTION__, serviceRet.toString8().string());
Yin-Chia Yeh0dea57f2015-12-09 16:46:07 -0800468 delete device;
469 return ACAMERA_ERROR_CAMERA_DISCONNECTED;
470 }
471 if (deviceRemote == nullptr) {
472 ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
473 delete device;
474 return ACAMERA_ERROR_CAMERA_DISCONNECTED;
475 }
476 device->setRemoteDevice(deviceRemote);
477 *outDevice = device;
478 return ACAMERA_OK;
479}
480
481ACameraManager::~ACameraManager() {
482 Mutex::Autolock _l(mLock);
483 if (mCachedCameraIdList.numCameras != kCameraIdListNotInit) {
484 for (int i = 0; i < mCachedCameraIdList.numCameras; i++) {
485 delete[] mCachedCameraIdList.cameraIds[i];
486 }
487 delete[] mCachedCameraIdList.cameraIds;
488 }
489}