Home | History | Annotate | Download | only in default
      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 (at) 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 
     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 
     61 ExternalCameraProvider::ExternalCameraProvider() :
     62         mCfg(ExternalCameraConfig::loadFromCfg()),
     63         mHotPlugThread(this) {
     64     mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND);
     65 }
     66 
     67 ExternalCameraProvider::~ExternalCameraProvider() {
     68     mHotPlugThread.requestExit();
     69 }
     70 
     71 
     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 
     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 
     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 
    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 
    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 
    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 
    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 (at) 3.4/external/") + devName;
    160     mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
    161     if (mCallbacks != nullptr) {
    162         mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
    163     }
    164 }
    165 
    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 
    199 void ExternalCameraProvider::deviceRemoved(const char* devName) {
    200     Mutex::Autolock _l(mLock);
    201     std::string deviceName = std::string("device (at) 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 
    212 ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent) :
    213         Thread(/*canCallJava*/false),
    214         mParent(parent),
    215         mInternalDevices(parent->mCfg.mInternalDevices) {}
    216 
    217 ExternalCameraProvider::HotplugThread::~HotplugThread() {}
    218 
    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