C++程序  |  587行  |  19.37 KB

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Contains implementation of a class EmulatedCameraFactory that manages cameras
 * available for emulation.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_Factory"

#include "EmulatedCameraFactory.h"
#include "EmulatedCameraHotplugThread.h"
#include "EmulatedFakeCamera.h"
#include "EmulatedFakeCamera2.h"
#include "EmulatedFakeCamera3.h"
#include "EmulatedQemuCamera.h"
#include "EmulatedQemuCamera3.h"

#include <log/log.h>
#include <cutils/properties.h>

extern camera_module_t HAL_MODULE_INFO_SYM;

/*
 * A global instance of EmulatedCameraFactory is statically instantiated and
 * initialized when camera emulation HAL is loaded.
 */
android::EmulatedCameraFactory gEmulatedCameraFactory;

namespace android {

EmulatedCameraFactory::EmulatedCameraFactory() :
        mQemuClient(),
        mEmulatedCameras(nullptr),
        mEmulatedCameraNum(0),
        mFakeCameraNum(0),
        mConstructedOK(false),
        mCallbacks(nullptr) {

    /*
     * Figure out how many cameras need to be created, so we can allocate the
     * array of emulated cameras before populating it.
     */
    int emulatedCamerasSize = 0;

    // QEMU Cameras
    std::vector<QemuCameraInfo> qemuCameras;
    if (mQemuClient.connectClient(nullptr) == NO_ERROR) {
        findQemuCameras(&qemuCameras);
        emulatedCamerasSize += qemuCameras.size();
    }

    waitForQemuSfFakeCameraPropertyAvailable();
    // Fake Cameras
    if (isFakeCameraEmulationOn(/* backCamera */ true)) {
        mFakeCameraNum++;
    }
    if (isFakeCameraEmulationOn(/* backCamera */ false)) {
        mFakeCameraNum++;
    }
    emulatedCamerasSize += mFakeCameraNum;

    /*
     * We have the number of cameras we need to create, now allocate space for
     * them.
     */
    mEmulatedCameras = new EmulatedBaseCamera*[emulatedCamerasSize];
    if (mEmulatedCameras == nullptr) {
        ALOGE("%s: Unable to allocate emulated camera array for %d entries",
                __FUNCTION__, mEmulatedCameraNum);
        return;
    }

    createQemuCameras(qemuCameras);

    // Create fake cameras, if enabled.
    if (isFakeCameraEmulationOn(/* backCamera */ true)) {
        createFakeCamera(/* backCamera */ true);
    }
    if (isFakeCameraEmulationOn(/* backCamera */ false)) {
        createFakeCamera(/* backCamera */ false);
    }

    ALOGE("%d cameras are being emulated. %d of them are fake cameras.",
            mEmulatedCameraNum, mFakeCameraNum);

    // Create hotplug thread.
    {
        Vector<int> cameraIdVector;
        for (int i = 0; i < mEmulatedCameraNum; ++i) {
            cameraIdVector.push_back(i);
        }
        mHotplugThread = new EmulatedCameraHotplugThread(&cameraIdVector[0],
                                                         mEmulatedCameraNum);
        mHotplugThread->run("EmulatedCameraHotplugThread");
    }

    mConstructedOK = true;
}

EmulatedCameraFactory::~EmulatedCameraFactory() {
    if (mEmulatedCameras != nullptr) {
        for (int n = 0; n < mEmulatedCameraNum; n++) {
            if (mEmulatedCameras[n] != nullptr) {
                delete mEmulatedCameras[n];
            }
        }
        delete[] mEmulatedCameras;
    }

    if (mHotplugThread != nullptr) {
        mHotplugThread->requestExit();
        mHotplugThread->join();
    }
}

/******************************************************************************
 * Camera HAL API handlers.
 *
 * Each handler simply verifies existence of an appropriate EmulatedBaseCamera
 * instance, and dispatches the call to that instance.
 *
 *****************************************************************************/

int EmulatedCameraFactory::cameraDeviceOpen(int cameraId,
                                            hw_device_t **device) {
    ALOGV("%s: id = %d", __FUNCTION__, cameraId);

    *device = nullptr;

    if (!isConstructedOK()) {
        ALOGE("%s: EmulatedCameraFactory has failed to initialize",
                __FUNCTION__);
        return -EINVAL;
    }

    if (cameraId < 0 || cameraId >= getEmulatedCameraNum()) {
        ALOGE("%s: Camera id %d is out of bounds (%d)",
                __FUNCTION__, cameraId, getEmulatedCameraNum());
        return -ENODEV;
    }

    return mEmulatedCameras[cameraId]->connectCamera(device);
}

int EmulatedCameraFactory::getCameraInfo(int cameraId,
                                         struct camera_info *info) {
    ALOGV("%s: id = %d", __FUNCTION__, cameraId);

    if (!isConstructedOK()) {
        ALOGE("%s: EmulatedCameraFactory has failed to initialize",
                __FUNCTION__);
        return -EINVAL;
    }

    if (cameraId < 0 || cameraId >= getEmulatedCameraNum()) {
        ALOGE("%s: Camera id %d is out of bounds (%d)",
                __FUNCTION__, cameraId, getEmulatedCameraNum());
        return -ENODEV;
    }

    return mEmulatedCameras[cameraId]->getCameraInfo(info);
}

int EmulatedCameraFactory::setCallbacks(
        const camera_module_callbacks_t *callbacks) {
    ALOGV("%s: callbacks = %p", __FUNCTION__, callbacks);

    mCallbacks = callbacks;

    return OK;
}

void EmulatedCameraFactory::getVendorTagOps(vendor_tag_ops_t* ops) {
    ALOGV("%s: ops = %p", __FUNCTION__, ops);
    // No vendor tags defined for emulator yet, so not touching ops.
}

/****************************************************************************
 * Camera HAL API callbacks.
 ***************************************************************************/

int EmulatedCameraFactory::device_open(const hw_module_t *module, const char
        *name, hw_device_t **device) {
    /*
     * Simply verify the parameters, and dispatch the call inside the
     * EmulatedCameraFactory instance.
     */

    if (module != &HAL_MODULE_INFO_SYM.common) {
        ALOGE("%s: Invalid module %p expected %p",
                __FUNCTION__, module, &HAL_MODULE_INFO_SYM.common);
        return -EINVAL;
    }
    if (name == nullptr) {
        ALOGE("%s: NULL name is not expected here", __FUNCTION__);
        return -EINVAL;
    }

    return gEmulatedCameraFactory.cameraDeviceOpen(atoi(name), device);
}

int EmulatedCameraFactory::get_number_of_cameras() {
    return gEmulatedCameraFactory.getEmulatedCameraNum();
}

int EmulatedCameraFactory::get_camera_info(int camera_id,
                        struct camera_info *info) {
    return gEmulatedCameraFactory.getCameraInfo(camera_id, info);
}

int EmulatedCameraFactory::set_callbacks(
        const camera_module_callbacks_t *callbacks) {
    return gEmulatedCameraFactory.setCallbacks(callbacks);
}

void EmulatedCameraFactory::get_vendor_tag_ops(vendor_tag_ops_t *ops) {
    gEmulatedCameraFactory.getVendorTagOps(ops);
}

int EmulatedCameraFactory::open_legacy(const struct hw_module_t *module,
        const char *id, uint32_t halVersion, struct hw_device_t **device) {
    // Not supporting legacy open.
    return -ENOSYS;
}

/********************************************************************************
 * Internal API
 *******************************************************************************/

/*
 * Camera information tokens passed in response to the "list" factory query.
 */

// Device name token.
static const char *kListNameToken = "name=";
// Frame dimensions token.
static const char *kListDimsToken = "framedims=";
// Facing direction token.
static const char *kListDirToken = "dir=";


bool EmulatedCameraFactory::getTokenValue(const char *token,
        const std::string &s, char **value) {
    // Find the start of the token.
    size_t tokenStart = s.find(token);
    if (tokenStart == std::string::npos) {
        return false;
    }

    // Advance to the beginning of the token value.
    size_t valueStart = tokenStart + strlen(token);

    // Find the length of the token value.
    size_t valueLength = s.find(' ', valueStart) - valueStart;

    // Extract the value substring.
    std::string valueStr = s.substr(valueStart, valueLength);

    // Convert to char*.
    *value = new char[valueStr.length() + 1];
    if (*value == nullptr) {
        return false;
    }
    strcpy(*value, valueStr.c_str());

    ALOGV("%s: Parsed value is \"%s\"", __FUNCTION__, *value);

    return true;
}

void EmulatedCameraFactory::findQemuCameras(
        std::vector<QemuCameraInfo> *qemuCameras) {
    // Obtain camera list.
    char *cameraList = nullptr;
    status_t res = mQemuClient.listCameras(&cameraList);

    /*
     * Empty list, or list containing just an EOL means that there were no
     * connected cameras found.
     */
    if (res != NO_ERROR || cameraList == nullptr || *cameraList == '\0' ||
        *cameraList == '\n') {
        if (cameraList != nullptr) {
            free(cameraList);
        }
        return;
    }

    /*
     * Calculate number of connected cameras. Number of EOLs in the camera list
     * is the number of the connected cameras.
     */

    std::string cameraListStr(cameraList);
    free(cameraList);

    size_t lineBegin = 0;
    size_t lineEnd = cameraListStr.find('\n');
    while (lineEnd != std::string::npos) {
        std::string cameraStr = cameraListStr.substr(lineBegin, lineEnd - lineBegin);
        // Parse the 'name', 'framedims', and 'dir' tokens.
        char *name, *frameDims, *dir;
        if (getTokenValue(kListNameToken, cameraStr, &name) &&
                getTokenValue(kListDimsToken, cameraStr, &frameDims) &&
                getTokenValue(kListDirToken, cameraStr, &dir)) {
            // Push the camera info if it was all successfully parsed.
            qemuCameras->push_back(QemuCameraInfo{
                .name = name,
                .frameDims = frameDims,
                .dir = dir,
            });
        } else {
            ALOGW("%s: Bad camera information: %s", __FUNCTION__,
                    cameraStr.c_str());
        }
        // Skip over the newline for the beginning of the next line.
        lineBegin = lineEnd + 1;
        lineEnd = cameraListStr.find('\n', lineBegin);
    }
}

void EmulatedCameraFactory::createQemuCameras(
        const std::vector<QemuCameraInfo> &qemuCameras) {
    /*
     * Iterate the list, creating, and initializing emulated QEMU cameras for each
     * entry in the list.
     */

    /*
     * We use this index only for determining which direction the webcam should
     * face. Otherwise, mEmulatedCameraNum represents the camera ID and the
     * index into mEmulatedCameras.
     */
    int qemuIndex = 0;
    for (const auto &cameraInfo : qemuCameras) {
        /*
         * Here, we're assuming the first webcam is intended to be the back
         * camera and any other webcams are front cameras.
         */
        int halVersion = 0;
        if (qemuIndex == 0) {
            halVersion = getCameraHalVersion(/* backCamera */ true);
        } else {
            halVersion = getCameraHalVersion(/* backCamera */ false);
        }

        // Create and initialize QEMU camera.
        EmulatedBaseCamera *qemuCam = nullptr;
        status_t res;
        switch (halVersion) {
            case 1:
                EmulatedQemuCamera *qemuCamOne;
                qemuCamOne = new EmulatedQemuCamera(
                        mEmulatedCameraNum, &HAL_MODULE_INFO_SYM.common);
                if (qemuCamOne == nullptr) {
                    ALOGE("%s: Unable to instantiate EmulatedQemuCamera",
                            __FUNCTION__);
                } else {
                    /*
                     * We have to initialize in each switch case, because
                     * EmulatedBaseCamera::Initialize has a different method
                     * signature.
                     *
                     * TODO: Having an EmulatedBaseQemuCamera class
                     * could fix this issue.
                     */
                    res = qemuCamOne->Initialize(
                            cameraInfo.name,
                            cameraInfo.frameDims,
                            cameraInfo.dir);
                }
                qemuCam = qemuCamOne;
                break;
            case 2:
                ALOGE("%s: QEMU support for camera hal version %d is not "
                        "implemented", __FUNCTION__, halVersion);
                break;
            case 3:
                EmulatedQemuCamera3 *qemuCamThree;
                qemuCamThree = new EmulatedQemuCamera3(
                        mEmulatedCameraNum, &HAL_MODULE_INFO_SYM.common);
                if (qemuCamThree == nullptr) {
                    ALOGE("%s: Unable to instantiate EmulatedQemuCamera3",
                            __FUNCTION__);
                } else {
                    res = qemuCamThree->Initialize(
                            cameraInfo.name,
                            cameraInfo.frameDims,
                            cameraInfo.dir);
                }
                qemuCam = qemuCamThree;
                break;
            default:
                ALOGE("%s: Unknown camera hal version requested: %d",
                        __FUNCTION__, halVersion);
        }

        if (qemuCam == nullptr) {
            ALOGE("%s: Unable to instantiate EmulatedQemuCamera",
                    __FUNCTION__);
        } else {
            if (res == NO_ERROR) {
                mEmulatedCameras[mEmulatedCameraNum] = qemuCam;
                qemuIndex++;
                mEmulatedCameraNum++;
            } else {
                delete qemuCam;
            }
        }
    }
}

void EmulatedCameraFactory::createFakeCamera(bool backCamera) {
    int halVersion = getCameraHalVersion(backCamera);

    /*
     * Create and initialize the fake camera, using the index into
     * mEmulatedCameras as the camera ID.
     */
    switch (halVersion) {
        case 1:
            mEmulatedCameras[mEmulatedCameraNum] =
                    new EmulatedFakeCamera(mEmulatedCameraNum, backCamera,
                            &HAL_MODULE_INFO_SYM.common);
            break;
        case 2:
            mEmulatedCameras[mEmulatedCameraNum] =
                    new EmulatedFakeCamera2(mEmulatedCameraNum, backCamera,
                            &HAL_MODULE_INFO_SYM.common);
            break;
        case 3:
            {
                const char *key = "ro.kernel.qemu.camera.fake.rotating";
                char prop[PROPERTY_VALUE_MAX];
                if (property_get(key, prop, nullptr) > 0) {
                    mEmulatedCameras[mEmulatedCameraNum] =
                        new EmulatedFakeCamera(mEmulatedCameraNum, backCamera,
                                &HAL_MODULE_INFO_SYM.common);
                } else {
                    mEmulatedCameras[mEmulatedCameraNum] =
                        new EmulatedFakeCamera3(mEmulatedCameraNum, backCamera,
                                &HAL_MODULE_INFO_SYM.common);
                }
            }
            break;
        default:
            ALOGE("%s: Unknown %s camera hal version requested: %d",
                    __FUNCTION__, backCamera ? "back" : "front", halVersion);
    }

    if (mEmulatedCameras[mEmulatedCameraNum] == nullptr) {
        ALOGE("%s: Unable to instantiate fake camera class", __FUNCTION__);
    } else {
        ALOGV("%s: %s camera device version is %d", __FUNCTION__,
                backCamera ? "Back" : "Front", halVersion);
        status_t res = mEmulatedCameras[mEmulatedCameraNum]->Initialize();
        if (res == NO_ERROR) {
            // Camera creation and initialization was successful.
            mEmulatedCameraNum++;
        } else {
            ALOGE("%s: Unable to initialize %s camera %d: %s (%d)",
                    __FUNCTION__, backCamera ? "back" : "front",
                    mEmulatedCameraNum, strerror(-res), res);
            delete mEmulatedCameras[mEmulatedCameraNum];
        }
    }
}

void EmulatedCameraFactory::waitForQemuSfFakeCameraPropertyAvailable() {
    /*
     * Camera service may start running before qemu-props sets
     * qemu.sf.fake_camera to any of the follwing four values:
     * "none,front,back,both"; so we need to wait.
     *
     * android/camera/camera-service.c
     * bug: 30768229
     */
    int numAttempts = 100;
    char prop[PROPERTY_VALUE_MAX];
    bool timeout = true;
    for (int i = 0; i < numAttempts; ++i) {
        if (property_get("qemu.sf.fake_camera", prop, nullptr) != 0 ) {
            timeout = false;
            break;
        }
        usleep(5000);
    }
    if (timeout) {
        ALOGE("timeout (%dms) waiting for property qemu.sf.fake_camera to be set\n", 5 * numAttempts);
    }
}

bool EmulatedCameraFactory::isFakeCameraEmulationOn(bool backCamera) {
    /*
     * Defined by 'qemu.sf.fake_camera' boot property. If the property exists,
     * and if it's set to 'both', then fake cameras are used to emulate both
     * sides. If it's set to 'back' or 'front', then a fake camera is used only
     * to emulate the back or front camera, respectively.
     */
    char prop[PROPERTY_VALUE_MAX];
    if ((property_get("qemu.sf.fake_camera", prop, nullptr) > 0) &&
        (!strcmp(prop, "both") ||
         !strcmp(prop, backCamera ? "back" : "front"))) {
        return true;
    } else {
        return false;
    }
}

int EmulatedCameraFactory::getCameraHalVersion(bool backCamera) {
    /*
     * Defined by 'qemu.sf.front_camera_hal_version' and
     * 'qemu.sf.back_camera_hal_version' boot properties. If the property
     * doesn't exist, it is assumed we are working with HAL v1.
     */
    char prop[PROPERTY_VALUE_MAX];
    const char *propQuery = backCamera ?
            "qemu.sf.back_camera_hal" :
            "qemu.sf.front_camera_hal";
    if (property_get(propQuery, prop, nullptr) > 0) {
        char *propEnd = prop;
        int val = strtol(prop, &propEnd, 10);
        if (*propEnd == '\0') {
            return val;
        }
        // Badly formatted property. It should just be a number.
        ALOGE("qemu.sf.back_camera_hal is not a number: %s", prop);
    }
    return 3;
}

void EmulatedCameraFactory::onStatusChanged(int cameraId, int newStatus) {

    EmulatedBaseCamera *cam = mEmulatedCameras[cameraId];
    if (!cam) {
        ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
        return;
    }

    /*
     * (Order is important)
     * Send the callback first to framework, THEN close the camera.
     */

    if (newStatus == cam->getHotplugStatus()) {
        ALOGW("%s: Ignoring transition to the same status", __FUNCTION__);
        return;
    }

    const camera_module_callbacks_t* cb = mCallbacks;
    if (cb != nullptr && cb->camera_device_status_change != nullptr) {
        cb->camera_device_status_change(cb, cameraId, newStatus);
    }

    if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
        cam->unplugCamera();
    } else if (newStatus == CAMERA_DEVICE_STATUS_PRESENT) {
        cam->plugCamera();
    }
}

/********************************************************************************
 * Initializer for the static member structure.
 *******************************************************************************/

// Entry point for camera HAL API.
struct hw_module_methods_t EmulatedCameraFactory::mCameraModuleMethods = {
    .open = EmulatedCameraFactory::device_open
};

}; // end of namespace android