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