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