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