• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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