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