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