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