ExternalCameraProvider.cpp revision 1903059507815cc89e9cf268f73d86b2bb3feef7
1/*
2 * Copyright (C) 2018 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 "CamPvdr@2.4-external"
18//#define LOG_NDEBUG 0
19#include <log/log.h>
20
21#include <regex>
22#include <sys/inotify.h>
23#include <errno.h>
24#include <linux/videodev2.h>
25#include "ExternalCameraProvider.h"
26#include "ExternalCameraDevice_3_4.h"
27
28namespace android {
29namespace hardware {
30namespace camera {
31namespace provider {
32namespace V2_4 {
33namespace implementation {
34
35namespace {
36// "device@<version>/external/<id>"
37const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
38const int kMaxDevicePathLen = 256;
39const char* kDevicePath = "/dev/";
40
41bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
42                     std::string* cameraId) {
43    std::string deviceNameStd(deviceName.c_str());
44    std::smatch sm;
45    if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
46        if (deviceVersion != nullptr) {
47            *deviceVersion = sm[1];
48        }
49        if (cameraId != nullptr) {
50            *cameraId = sm[2];
51        }
52        return true;
53    }
54    return false;
55}
56
57} // anonymous namespace
58
59ExternalCameraProvider::ExternalCameraProvider() : mHotPlugThread(this) {
60    mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND);
61}
62
63ExternalCameraProvider::~ExternalCameraProvider() {
64    mHotPlugThread.requestExit();
65}
66
67
68Return<Status> ExternalCameraProvider::setCallback(
69        const sp<ICameraProviderCallback>& callback) {
70    Mutex::Autolock _l(mLock);
71    mCallbacks = callback;
72    return Status::OK;
73}
74
75Return<void> ExternalCameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) {
76    // No vendor tag support for USB camera
77    hidl_vec<VendorTagSection> zeroSections;
78    _hidl_cb(Status::OK, zeroSections);
79    return Void();
80}
81
82Return<void> ExternalCameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) {
83    std::vector<hidl_string> deviceNameList;
84    for (auto const& kvPair : mCameraStatusMap) {
85        if (kvPair.second == CameraDeviceStatus::PRESENT) {
86            deviceNameList.push_back(kvPair.first);
87        }
88    }
89    hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
90    ALOGV("ExtCam: number of cameras is %zu", deviceNameList.size());
91    _hidl_cb(Status::OK, hidlDeviceNameList);
92    return Void();
93}
94
95Return<void> ExternalCameraProvider::isSetTorchModeSupported(
96        isSetTorchModeSupported_cb _hidl_cb) {
97    // No torch mode support for USB camera
98    _hidl_cb (Status::OK, false);
99    return Void();
100}
101
102Return<void> ExternalCameraProvider::getCameraDeviceInterface_V1_x(
103        const hidl_string&,
104        getCameraDeviceInterface_V1_x_cb _hidl_cb) {
105    // External Camera HAL does not support HAL1
106    _hidl_cb(Status::OPERATION_NOT_SUPPORTED, nullptr);
107    return Void();
108}
109
110Return<void> ExternalCameraProvider::getCameraDeviceInterface_V3_x(
111        const hidl_string& cameraDeviceName,
112        getCameraDeviceInterface_V3_x_cb _hidl_cb) {
113
114    std::string cameraId, deviceVersion;
115    bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
116    if (!match) {
117        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
118        return Void();
119    }
120
121    if (mCameraStatusMap.count(cameraDeviceName) == 0 ||
122            mCameraStatusMap[cameraDeviceName] != CameraDeviceStatus::PRESENT) {
123        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
124        return Void();
125    }
126
127    ALOGV("Constructing v3.4 external camera device");
128    sp<device::V3_2::ICameraDevice> device;
129    sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
130            new device::V3_4::implementation::ExternalCameraDevice(
131                    cameraId);
132    if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
133        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
134        device = nullptr;
135        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
136        return Void();
137    }
138    device = deviceImpl;
139
140    _hidl_cb (Status::OK, device);
141
142    return Void();
143}
144
145void ExternalCameraProvider::addExternalCamera(const char* devName) {
146    ALOGE("ExtCam: adding %s to External Camera HAL!", devName);
147    Mutex::Autolock _l(mLock);
148    std::string deviceName = std::string("device@3.4/external/") + devName;
149    mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
150    if (mCallbacks != nullptr) {
151        mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
152    }
153}
154
155void ExternalCameraProvider::deviceAdded(const char* devName) {
156    int fd = -1;
157    if ((fd = ::open(devName, O_RDWR)) < 0) {
158        ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
159        return;
160    }
161
162    do {
163        struct v4l2_capability capability;
164        int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability);
165        if (ret < 0) {
166            ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
167            break;
168        }
169
170        if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
171            ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
172            break;
173        }
174
175        addExternalCamera(devName);
176    } while (0);
177
178    close(fd);
179    return;
180}
181
182void ExternalCameraProvider::deviceRemoved(const char* devName) {
183    Mutex::Autolock _l(mLock);
184    std::string deviceName = std::string("device@3.4/external/") + devName;
185    if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
186        mCameraStatusMap.erase(deviceName);
187        if (mCallbacks != nullptr) {
188            mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::NOT_PRESENT);
189        }
190    } else {
191        ALOGE("%s: cannot find camera device %s", __FUNCTION__, devName);
192    }
193}
194
195ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent) :
196        Thread(/*canCallJava*/false), mParent(parent) {}
197
198ExternalCameraProvider::HotplugThread::~HotplugThread() {}
199
200bool ExternalCameraProvider::HotplugThread::threadLoop() {
201    // Find existing /dev/video* devices
202    DIR* devdir = opendir(kDevicePath);
203    if(devdir == 0) {
204        ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath);
205        return false;
206    }
207
208    struct dirent* de;
209    // This list is device dependent. TODO: b/72261897 allow setting it from setprop/device boot
210    std::string internalDevices = "0,1";
211    while ((de = readdir(devdir)) != 0) {
212        // Find external v4l devices that's existing before we start watching and add them
213        if (!strncmp("video", de->d_name, 5)) {
214            // TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
215            //       is added.
216            if (internalDevices.find(de->d_name + 5) == std::string::npos) {
217                ALOGV("Non-internal v4l device %s found", de->d_name);
218                char v4l2DevicePath[kMaxDevicePathLen];
219                snprintf(v4l2DevicePath, kMaxDevicePathLen,
220                        "%s%s", kDevicePath, de->d_name);
221                mParent->deviceAdded(v4l2DevicePath);
222            }
223        }
224    }
225    closedir(devdir);
226
227    // Watch new video devices
228    mINotifyFD = inotify_init();
229    if (mINotifyFD < 0) {
230        ALOGE("%s: inotify init failed! Exiting threadloop", __FUNCTION__);
231        return true;
232    }
233
234    mWd = inotify_add_watch(mINotifyFD, kDevicePath, IN_CREATE | IN_DELETE);
235    if (mWd < 0) {
236        ALOGE("%s: inotify add watch failed! Exiting threadloop", __FUNCTION__);
237        return true;
238    }
239
240    ALOGI("%s start monitoring new V4L2 devices", __FUNCTION__);
241
242    bool done = false;
243    char eventBuf[512];
244    while (!done) {
245        int offset = 0;
246        int ret = read(mINotifyFD, eventBuf, sizeof(eventBuf));
247        if (ret >= (int)sizeof(struct inotify_event)) {
248            while (offset < ret) {
249                struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
250                if (event->wd == mWd) {
251                    if (!strncmp("video", event->name, 5)) {
252                        char v4l2DevicePath[kMaxDevicePathLen];
253                        snprintf(v4l2DevicePath, kMaxDevicePathLen,
254                                "%s%s", kDevicePath, event->name);
255                        if (event->mask & IN_CREATE) {
256                            mParent->deviceAdded(v4l2DevicePath);
257                        }
258                        if (event->mask & IN_DELETE) {
259                            mParent->deviceRemoved(v4l2DevicePath);
260                        }
261                    }
262                }
263                offset += sizeof(struct inotify_event) + event->len;
264            }
265        }
266    }
267
268    return true;
269}
270
271}  // namespace implementation
272}  // namespace V2_4
273}  // namespace provider
274}  // namespace camera
275}  // namespace hardware
276}  // namespace android
277