1/*
2 * Copyright (C) 2016 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 "CamDev@3.2-impl"
18#include <log/log.h>
19
20#include <utils/Vector.h>
21#include <utils/Trace.h>
22#include "CameraDevice_3_2.h"
23#include <include/convert.h>
24
25namespace android {
26namespace hardware {
27namespace camera {
28namespace device {
29namespace V3_2 {
30namespace implementation {
31
32using ::android::hardware::camera::common::V1_0::Status;
33
34CameraDevice::CameraDevice(
35    sp<CameraModule> module, const std::string& cameraId,
36    const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
37        mModule(module),
38        mCameraId(cameraId),
39        mDisconnected(false),
40        mCameraDeviceNames(cameraDeviceNames) {
41    mCameraIdInt = atoi(mCameraId.c_str());
42    // Should not reach here as provider also validate ID
43    if (mCameraIdInt < 0) {
44        ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str());
45        mInitFail = true;
46    } else if (mCameraIdInt >= mModule->getNumberOfCameras()) {
47        ALOGI("%s: Adding a new camera id: %s", __FUNCTION__, mCameraId.c_str());
48    }
49
50    mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt);
51    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
52        ALOGE("%s: Camera id %s does not support HAL3.2+",
53                __FUNCTION__, mCameraId.c_str());
54        mInitFail = true;
55    }
56}
57
58CameraDevice::~CameraDevice() {}
59
60Status CameraDevice::initStatus() const {
61    Mutex::Autolock _l(mLock);
62    Status status = Status::OK;
63    if (mInitFail) {
64        status = Status::INTERNAL_ERROR;
65    } else if (mDisconnected) {
66        status = Status::CAMERA_DISCONNECTED;
67    }
68    return status;
69}
70
71void CameraDevice::setConnectionStatus(bool connected) {
72    Mutex::Autolock _l(mLock);
73    mDisconnected = !connected;
74    if (mSession == nullptr) {
75        return;
76    }
77    sp<CameraDeviceSession> session = mSession.promote();
78    if (session == nullptr) {
79        return;
80    }
81    // Only notify active session disconnect events.
82    // Users will need to re-open camera after disconnect event
83    if (!connected) {
84        session->disconnect();
85    }
86    return;
87}
88
89Status CameraDevice::getHidlStatus(int status) {
90    switch (status) {
91        case 0: return Status::OK;
92        case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED;
93        case -EBUSY : return Status::CAMERA_IN_USE;
94        case -EUSERS: return Status::MAX_CAMERAS_IN_USE;
95        case -ENODEV: return Status::INTERNAL_ERROR;
96        case -EINVAL: return Status::ILLEGAL_ARGUMENT;
97        default:
98            ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
99            return Status::INTERNAL_ERROR;
100    }
101}
102
103// Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow.
104Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb)  {
105    Status status = initStatus();
106    CameraResourceCost resCost;
107    if (status == Status::OK) {
108        int cost = 100;
109        std::vector<std::string> conflicting_devices;
110        struct camera_info info;
111
112        // If using post-2.4 module version, query the cost + conflicting devices from the HAL
113        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
114            int ret = mModule->getCameraInfo(mCameraIdInt, &info);
115            if (ret == OK) {
116                cost = info.resource_cost;
117                for (size_t i = 0; i < info.conflicting_devices_length; i++) {
118                    std::string cameraId(info.conflicting_devices[i]);
119                    for (const auto& pair : mCameraDeviceNames) {
120                        if (cameraId == pair.first) {
121                            conflicting_devices.push_back(pair.second);
122                        }
123                    }
124                }
125            } else {
126                status = Status::INTERNAL_ERROR;
127            }
128        }
129
130        if (status == Status::OK) {
131            resCost.resourceCost = cost;
132            resCost.conflictingDevices.resize(conflicting_devices.size());
133            for (size_t i = 0; i < conflicting_devices.size(); i++) {
134                resCost.conflictingDevices[i] = conflicting_devices[i];
135                ALOGV("CamDevice %s is conflicting with camDevice %s",
136                        mCameraId.c_str(), resCost.conflictingDevices[i].c_str());
137            }
138        }
139    }
140    _hidl_cb(status, resCost);
141    return Void();
142}
143
144Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb)  {
145    Status status = initStatus();
146    CameraMetadata cameraCharacteristics;
147    if (status == Status::OK) {
148        //Module 2.1+ codepath.
149        struct camera_info info;
150        int ret = mModule->getCameraInfo(mCameraIdInt, &info);
151        if (ret == OK) {
152            convertToHidl(info.static_camera_characteristics, &cameraCharacteristics);
153        } else {
154            ALOGE("%s: get camera info failed!", __FUNCTION__);
155            status = Status::INTERNAL_ERROR;
156        }
157    }
158    _hidl_cb(status, cameraCharacteristics);
159    return Void();
160}
161
162Return<Status> CameraDevice::setTorchMode(TorchMode mode)  {
163    if (!mModule->isSetTorchModeSupported()) {
164        return Status::METHOD_NOT_SUPPORTED;
165    }
166
167    Status status = initStatus();
168    if (status == Status::OK) {
169        bool enable = (mode == TorchMode::ON) ? true : false;
170        status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable));
171    }
172    return status;
173}
174
175Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb)  {
176    Status status = initStatus();
177    sp<CameraDeviceSession> session = nullptr;
178
179    if (callback == nullptr) {
180        ALOGE("%s: cannot open camera %s. callback is null!",
181                __FUNCTION__, mCameraId.c_str());
182        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
183        return Void();
184    }
185
186    if (status != Status::OK) {
187        // Provider will never pass initFailed device to client, so
188        // this must be a disconnected camera
189        ALOGE("%s: cannot open camera %s. camera is disconnected!",
190                __FUNCTION__, mCameraId.c_str());
191        _hidl_cb(Status::CAMERA_DISCONNECTED, nullptr);
192        return Void();
193    } else {
194        mLock.lock();
195
196        ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mCameraIdInt);
197        session = mSession.promote();
198        if (session != nullptr && !session->isClosed()) {
199            ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
200            mLock.unlock();
201            _hidl_cb(Status::CAMERA_IN_USE, nullptr);
202            return Void();
203        }
204
205        /** Open HAL device */
206        status_t res;
207        camera3_device_t *device;
208
209        ATRACE_BEGIN("camera3->open");
210        res = mModule->open(mCameraId.c_str(),
211                reinterpret_cast<hw_device_t**>(&device));
212        ATRACE_END();
213
214        if (res != OK) {
215            ALOGE("%s: cannot open camera %s!", __FUNCTION__, mCameraId.c_str());
216            mLock.unlock();
217            _hidl_cb(getHidlStatus(res), nullptr);
218            return Void();
219        }
220
221        /** Cross-check device version */
222        if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) {
223            ALOGE("%s: Could not open camera: "
224                    "Camera device should be at least %x, reports %x instead",
225                    __FUNCTION__,
226                    CAMERA_DEVICE_API_VERSION_3_2,
227                    device->common.version);
228            device->common.close(&device->common);
229            mLock.unlock();
230            _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
231            return Void();
232        }
233
234        struct camera_info info;
235        res = mModule->getCameraInfo(mCameraIdInt, &info);
236        if (res != OK) {
237            ALOGE("%s: Could not open camera: getCameraInfo failed", __FUNCTION__);
238            device->common.close(&device->common);
239            mLock.unlock();
240            _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
241            return Void();
242        }
243
244        session = createSession(
245                device, info.static_camera_characteristics, callback);
246        if (session == nullptr) {
247            ALOGE("%s: camera device session allocation failed", __FUNCTION__);
248            mLock.unlock();
249            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
250            return Void();
251        }
252        if (session->isInitFailed()) {
253            ALOGE("%s: camera device session init failed", __FUNCTION__);
254            session = nullptr;
255            mLock.unlock();
256            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
257            return Void();
258        }
259        mSession = session;
260
261        IF_ALOGV() {
262            session->getInterface()->interfaceChain([](
263                ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
264                    ALOGV("Session interface chain:");
265                    for (auto iface : interfaceChain) {
266                        ALOGV("  %s", iface.c_str());
267                    }
268                });
269        }
270        mLock.unlock();
271    }
272    _hidl_cb(status, session->getInterface());
273    return Void();
274}
275
276Return<void> CameraDevice::dumpState(const ::android::hardware::hidl_handle& handle)  {
277    Mutex::Autolock _l(mLock);
278    if (handle.getNativeHandle() == nullptr) {
279        ALOGE("%s: handle must not be null", __FUNCTION__);
280        return Void();
281    }
282    if (handle->numFds != 1 || handle->numInts != 0) {
283        ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
284                __FUNCTION__, handle->numFds, handle->numInts);
285        return Void();
286    }
287    int fd = handle->data[0];
288    if (mSession == nullptr) {
289        dprintf(fd, "No active camera device session instance\n");
290        return Void();
291    }
292    sp<CameraDeviceSession> session = mSession.promote();
293    if (session == nullptr) {
294        dprintf(fd, "No active camera device session instance\n");
295        return Void();
296    }
297    // Call into active session to dump states
298    session->dumpState(handle);
299    return Void();
300}
301
302sp<CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device,
303        const camera_metadata_t* deviceInfo,
304        const sp<ICameraDeviceCallback>& callback) {
305    return new CameraDeviceSession(device, deviceInfo, callback);
306}
307
308// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
309
310} // namespace implementation
311}  // namespace V3_2
312}  // namespace device
313}  // namespace camera
314}  // namespace hardware
315}  // namespace android
316