Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4baf7261 authored by Avichal Rakesh's avatar Avichal Rakesh
Browse files

cameraservice: Copy camera characteristics from session characteristics

The getSessionCharacteristics call is meant to replace the output of
getCameraCharacteristics. The current implementation however passed
the output of HAL directly to the application, which could be missing
quite a few keys.

This CL uses the camera device's characteristics as the base
and copies over any updated values from the HAL instead. This will
ensure the output of getSessionCharacteristics matches the constraints
of getCameraCharacteristics.

Similarly, this CL also filters out any sensitive keys if
getSessionCharactersitics is called from a process that does not have
camera permission granted.

Bug: 303645857
Test: atest android.hardware.camera2.cts.CameraDeviceSetupTest passes
Test: atest android.hardware.camera2.cts.StaticMetadataTest passes
Change-Id: I589c80fc6152ae3cb14c72963953feb94a7f745a
parent ad8248a7
Loading
Loading
Loading
Loading
+93 −57
Original line number Diff line number Diff line
@@ -991,12 +991,6 @@ Status CameraService::getSessionCharacteristics(const std::string& unresolvedCam
        /*out*/ CameraMetadata* outMetadata) {
    ATRACE_CALL();

    if (!mInitialized) {
        ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
        logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
        return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
    }

    if (outMetadata == nullptr) {
        std::string msg =
                fmt::sprintf("Camera %s: Invalid 'outMetadata' input!", unresolvedCameraId.c_str());
@@ -1004,6 +998,12 @@ Status CameraService::getSessionCharacteristics(const std::string& unresolvedCam
        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
    }

    if (!mInitialized) {
        ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
        logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
        return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
    }

    std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
                                                                  devicePolicy, getCallingUid());
    if (!cameraIdOptional.has_value()) {
@@ -1014,16 +1014,19 @@ Status CameraService::getSessionCharacteristics(const std::string& unresolvedCam
    }
    std::string cameraId = cameraIdOptional.value();

    if (shouldRejectSystemCameraConnection(cameraId)) {
        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                                "Unable to retrieve camera"
                                "characteristics for system only device %s: ",
                                cameraId.c_str());
    }

    bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
            mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);

    status_t ret = mCameraProviderManager->getSessionCharacteristics(
            cameraId, sessionConfiguration, overrideForPerfClass, overrideToPortrait, outMetadata);

    // TODO(b/303645857): Remove fingerprintable metadata if the caller process does not have
    //                    camera access permission.

    Status res = Status::ok();
    switch (ret) {
        case OK:
            // Expected, no handling needed.
@@ -1033,18 +1036,90 @@ Status CameraService::getSessionCharacteristics(const std::string& unresolvedCam
                        "Camera %s: Session characteristics query not supported!",
                        cameraId.c_str());
                ALOGD("%s: %s", __FUNCTION__, msg.c_str());
                res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
                logServiceError(msg, CameraService::ERROR_INVALID_OPERATION);
                outMetadata->clear();
                return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
            }
            break;
        case NAME_NOT_FOUND: {
                std::string msg = fmt::sprintf(
                        "Camera %s: Unknown camera ID.",
                        cameraId.c_str());
                ALOGD("%s: %s", __FUNCTION__, msg.c_str());
                logServiceError(msg, CameraService::ERROR_ILLEGAL_ARGUMENT);
                outMetadata->clear();
                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
            }
            break;
        default: {
                std::string msg = fmt::sprintf("Camera %s: Error: %s (%d)", cameraId.c_str(),
                                               strerror(-ret), ret);
                std::string msg = fmt::sprintf(
                        "Unable to retrieve session characteristics for camera device %s: "
                        "Error: %s (%d)",
                        cameraId.c_str(), strerror(-ret), ret);
                ALOGE("%s: %s", __FUNCTION__, msg.c_str());
                res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
                logServiceError(msg, CameraService::ERROR_INVALID_OPERATION);
                outMetadata->clear();
                return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
            }
    }

    return res;
    return filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
}

Status CameraService::filterSensitiveMetadataIfNeeded(
        const std::string& cameraId, CameraMetadata* metadata) {
    int callingPid = getCallingPid();
    int callingUid = getCallingUid();

    if (callingPid == getpid()) {
        // Caller is cameraserver; no need to remove keys
        return Status::ok();
    }

    SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
    if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
        ALOGE("%s: Couldn't get camera kind for camera id %s", __FUNCTION__, cameraId.c_str());
        metadata->clear();
        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                                "Unable to retrieve camera kind for device %s", cameraId.c_str());
    }
    if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
        // Attempting to query system only camera without system camera permission would have
        // failed the shouldRejectSystemCameraConnection in the caller. So if we get here
        // for a system only camera, then the caller has the required permission.
        // No need to remove keys
        return Status::ok();
    }

    std::vector<int32_t> tagsRemoved;
    bool hasCameraPermission = hasPermissionsForCamera(cameraId, callingPid, callingUid);
    if (hasCameraPermission) {
        // Caller has camera permission; no need to remove keys
        return Status::ok();
    }

    status_t ret = metadata->removePermissionEntries(
            mCameraProviderManager->getProviderTagIdLocked(cameraId), &tagsRemoved);
    if (ret != OK) {
        metadata->clear();
        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                                "Failed to remove camera characteristics needing camera permission "
                                "for device %s:%s (%d)",
                                cameraId.c_str(), strerror(-ret), ret);
    }

    if (!tagsRemoved.empty()) {
        ret = metadata->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION,
                                  tagsRemoved.data(), tagsRemoved.size());
        if (ret != OK) {
            metadata->clear();
            return STATUS_ERROR_FMT(
                    ERROR_INVALID_OPERATION,
                    "Failed to insert camera keys needing permission for device %s: %s (%d)",
                    cameraId.c_str(), strerror(-ret), ret);
        }
    }
    return Status::ok();
}

Status CameraService::parseCameraIdRemapping(
@@ -1381,8 +1456,6 @@ Status CameraService::getCameraCharacteristics(const std::string& unresolvedCame
                "characteristics for system only device %s: ", cameraId.c_str());
    }

    Status ret{};

    bool overrideForPerfClass =
            SessionConfigurationUtils::targetPerfClassPrimaryCamera(mPerfClassPrimaryCameraIds,
                    cameraId, targetSdkVersion);
@@ -1401,45 +1474,8 @@ Status CameraService::getCameraCharacteristics(const std::string& unresolvedCame
                    strerror(-res), res);
        }
    }
    SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
    if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
        ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.c_str());
        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera kind "
                "for device %s", cameraId.c_str());
    }
    int callingPid = getCallingPid();
    int callingUid = getCallingUid();
    std::vector<int32_t> tagsRemoved;
    // If it's not calling from cameraserver, check the permission only if
    // android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
    // it would've already been checked in shouldRejectSystemCameraConnection.
    bool checkPermissionForCamera = hasPermissionsForCamera(cameraId, callingPid, callingUid);
    if ((callingPid != getpid()) &&
            (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
            !checkPermissionForCamera) {
        res = cameraInfo->removePermissionEntries(
                mCameraProviderManager->getProviderTagIdLocked(cameraId),
                &tagsRemoved);
        if (res != OK) {
            cameraInfo->clear();
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to remove camera"
                    " characteristics needing camera permission for device %s: %s (%d)",
                    cameraId.c_str(), strerror(-res), res);
        }
    }

    if (!tagsRemoved.empty()) {
        res = cameraInfo->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION,
                tagsRemoved.data(), tagsRemoved.size());
        if (res != OK) {
            cameraInfo->clear();
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to insert camera "
                    "keys needing permission for device %s: %s (%d)", cameraId.c_str(),
                    strerror(-res), res);
        }
    }

    return ret;
    return filterSensitiveMetadataIfNeeded(cameraId, cameraInfo);
}

Status CameraService::getTorchStrengthLevel(const std::string& unresolvedCameraId, int32_t deviceId,
+6 −0
Original line number Diff line number Diff line
@@ -1529,6 +1529,12 @@ private:
    // responsibility to acquire mLogLock before calling this functions.
    bool isClientWatchedLocked(const BasicClient *client);

    // Filters out fingerprintable keys if the calling process does not have CAMERA permission.
    // Note: function caller should ensure that shouldRejectSystemCameraConnection is checked
    // for the calling process before calling this function.
    binder::Status filterSensitiveMetadataIfNeeded(const std::string& cameraId,
                                                   CameraMetadata* metadata);

    /**
     * Get the current system time as a formatted string.
     */
+44 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <aidl/AidlUtils.h>
#include <aidl/ExtensionMetadataTags.h>
#include <aidl/SessionCharacteristicsTags.h>
#include <aidl/VndkVersionMetadataTags.h>
#include <aidlcommonsupport/NativeHandle.h>
#include <camera/StringUtils.h>
@@ -334,6 +335,49 @@ status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic
    return OK;
}

status_t copySessionCharacteristics(const CameraMetadata& from, CameraMetadata* to,
                                    int queryVersion) {
    // Ensure the vendor ID are the same before attempting
    // anything else. If vendor IDs differ we cannot safely copy the characteristics.
    if (from.getVendorId() != to->getVendorId()) {
        ALOGE("%s: Incompatible CameraMetadata objects. Vendor IDs differ. From: %lu; To: %lu",
              __FUNCTION__, from.getVendorId(), to->getVendorId());
        return BAD_VALUE;
    }

    // Allow public tags according to the queryVersion
    std::unordered_set<uint32_t> validPublicTags;
    auto last = api_level_to_session_characteristic_keys.upper_bound(queryVersion);
    for (auto it = api_level_to_session_characteristic_keys.begin(); it != last; it++) {
        validPublicTags.insert(it->second.cbegin(), it->second.cend());
    }

    const camera_metadata_t* src = from.getAndLock();
    camera_metadata_ro_entry_t entry{};
    for (size_t i = 0; i < get_camera_metadata_entry_count(src); i++) {
        int ret = get_camera_metadata_ro_entry(src, i, &entry);
        if (ret != OK) {
            ALOGE("%s: Could not fetch entry at index %lu. Error: %d", __FUNCTION__, i, ret);
            from.unlock(src);
            return BAD_VALUE;
        }

        if (entry.tag < (uint32_t)VENDOR_SECTION_START &&
                validPublicTags.find(entry.tag) == validPublicTags.end()) {
            ALOGI("%s: Session Characteristics contains tag %s but not supported by query version "
                  "(%d)",
                  __FUNCTION__, get_camera_metadata_tag_name(entry.tag), queryVersion);
            continue;
        }

        // The entry is either a vendor tag, or a valid session characteristic key.
        // Copy over the value
        to->update(entry);
    }
    from.unlock(src);
    return OK;
}

bool areExtensionKeysSupported(const CameraMetadata& metadata) {
    auto requestKeys = metadata.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
    if (requestKeys.count == 0) {
+3 −0
Original line number Diff line number Diff line
@@ -122,6 +122,9 @@ bool areBindersEqual(const ndk::SpAIBinder& b1, const ndk::SpAIBinder& b2);

status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic = true);

status_t copySessionCharacteristics(const CameraMetadata& from, CameraMetadata* to,
                                    int queryVersion);

bool areExtensionKeysSupported(const CameraMetadata& metadata);

status_t filterExtensionKeys(CameraMetadata* metadata /*out*/);
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.
 */

#include <map>
#include <vector>
#pragma once
/**
 * ! Do not edit this file directly !
 *
 * Generated automatically from session_characteristics_tags.mako. To be included in
 * libcameraservice only by aidl/AidlUtils.cpp.
 */

/**
 * Mapping of session characteristics to the INFO_SESSION_CONFIGURATION_QUERY_VERSION value
 * at which they were introduced.
 */
std::map<int, std::vector<camera_metadata_tag>> api_level_to_session_characteristic_keys {
        {35,
         {
                 ANDROID_CONTROL_ZOOM_RATIO_RANGE,
                 ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
         }},
};
Loading