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