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