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