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

Commit e20c637e authored by Emilian Peev's avatar Emilian Peev
Browse files

Camera: Filter camera characteristics

Camera characteristics for camera clients that don't
hold the camera permission must not contain any
metadata that explicitly requires this permission.
Vendor tags must be absent in this case as well.

Bug: 112160024
Test: Manual using application,
adb shell /data/nativetest64/camera_client_test/camera_client_test
--gtest_filter=CameraCharacteristicsPermission.TestCameraPermission
Camera CTS

Change-Id: I4e34c6ef7bd4315327ca78084fa3dcc175fc8098
parent 0127c1be
Loading
Loading
Loading
Loading
+73 −1
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@

#include <binder/Parcel.h>
#include <camera/CameraMetadata.h>
#include <camera/VendorTagDescriptor.h>

namespace android {

@@ -409,6 +408,79 @@ status_t CameraMetadata::erase(uint32_t tag) {
    return res;
}

status_t CameraMetadata::removePermissionEntries(metadata_vendor_id_t vendorId,
        std::vector<int32_t> *tagsRemoved) {
    uint32_t tagCount = 0;
    std::vector<uint32_t> tagsToRemove;

    if (tagsRemoved == nullptr) {
        return BAD_VALUE;
    }

    sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
    if ((nullptr == vTags.get()) || (0 >= vTags->getTagCount())) {
        sp<VendorTagDescriptorCache> cache =
            VendorTagDescriptorCache::getGlobalVendorTagCache();
        if (cache.get()) {
            cache->getVendorTagDescriptor(vendorId, &vTags);
        }
    }

    if ((nullptr != vTags.get()) && (vTags->getTagCount() > 0)) {
        tagCount = vTags->getTagCount();
        uint32_t *vendorTags = new uint32_t[tagCount];
        if (nullptr == vendorTags) {
            return NO_MEMORY;
        }
        vTags->getTagArray(vendorTags);

        tagsToRemove.reserve(tagCount);
        tagsToRemove.insert(tagsToRemove.begin(), vendorTags, vendorTags + tagCount);

        delete [] vendorTags;
        tagCount = 0;
    }

    auto tagsNeedingPermission = get_camera_metadata_permission_needed(&tagCount);
    if (tagCount > 0) {
        tagsToRemove.reserve(tagsToRemove.capacity() + tagCount);
        tagsToRemove.insert(tagsToRemove.end(), tagsNeedingPermission,
                tagsNeedingPermission + tagCount);
    }

    tagsRemoved->reserve(tagsToRemove.size());
    for (const auto &it : tagsToRemove) {
        if (exists(it)) {
            auto rc = erase(it);
            if (NO_ERROR != rc) {
                ALOGE("%s: Failed to erase tag: %x", __func__, it);
                return rc;
            }
            tagsRemoved->push_back(it);
        }
    }

    // Update the available characterstics accordingly
    if (exists(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS)) {
        std::vector<uint32_t> currentKeys;

        std::sort(tagsRemoved->begin(), tagsRemoved->end());
        auto keys = find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
        currentKeys.reserve(keys.count);
        currentKeys.insert(currentKeys.end(), keys.data.i32, keys.data.i32 + keys.count);
        std::sort(currentKeys.begin(), currentKeys.end());

        std::vector<int32_t> newKeys(keys.count);
        auto end = std::set_difference(currentKeys.begin(), currentKeys.end(), tagsRemoved->begin(),
                tagsRemoved->end(), newKeys.begin());
        newKeys.resize(end - newKeys.begin());

        update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, newKeys.data(), newKeys.size());
    }

    return NO_ERROR;
}

void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
    dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
}
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <utils/String8.h>
#include <utils/Vector.h>
#include <binder/Parcelable.h>
#include <camera/VendorTagDescriptor.h>

namespace android {

@@ -169,6 +170,12 @@ class CameraMetadata: public Parcelable {
     */
    status_t erase(uint32_t tag);

    /**
     * Remove metadata entries that need additional permissions.
     */
    status_t removePermissionEntries(metadata_vendor_id_t vendorId,
            std::vector<int32_t> *tagsRemoved /*out*/);

    /**
     * Swap the underlying camera metadata between this and the other
     * metadata object.
+2 −1
Original line number Diff line number Diff line
@@ -19,7 +19,8 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_SRC_FILES:= \
	VendorTagDescriptorTests.cpp \
	CameraBinderTests.cpp \
	CameraZSLTests.cpp
	CameraZSLTests.cpp \
	CameraCharacteristicsPermission.cpp

LOCAL_SHARED_LIBRARIES := \
	liblog \
+96 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#define LOG_NDEBUG 0
#define LOG_TAG "CameraCharacteristicsPermission"

#include <gtest/gtest.h>

#include <binder/ProcessState.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <camera/CameraMetadata.h>
#include <camera/Camera.h>
#include <android/hardware/ICameraService.h>

using namespace android;
using namespace android::hardware;

class CameraCharacteristicsPermission : public ::testing::Test {
protected:

    CameraCharacteristicsPermission() : numCameras(0){}
    //Gtest interface
    void SetUp() override;
    void TearDown() override;

    int32_t numCameras;
    sp<ICameraService> mCameraService;
};

void CameraCharacteristicsPermission::SetUp() {
    ::android::binder::Status rc;
    ProcessState::self()->startThreadPool();
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("media.camera"));
    mCameraService = interface_cast<ICameraService>(binder);
    rc = mCameraService->getNumberOfCameras(
            hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
    EXPECT_TRUE(rc.isOk());
}

void CameraCharacteristicsPermission::TearDown() {
    mCameraService.clear();
}

// Revoking and acquiring permissions automatically might not be possible.
// Test the functionality for removal of camera characteristics needing
// a camera permission.
TEST_F(CameraCharacteristicsPermission, TestCameraPermission) {
    for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) {

        String16 cameraIdStr = String16(String8::format("%d", cameraId));
        bool isSupported = false;
        auto rc = mCameraService->supportsCameraApi(cameraIdStr,
                hardware::ICameraService::API_VERSION_2, &isSupported);
        EXPECT_TRUE(rc.isOk());
        if (!isSupported) {
            continue;
        }

        CameraMetadata metadata;
        std::vector<int32_t> tagsNeedingPermission;
        rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata);
        ASSERT_TRUE(rc.isOk());
        EXPECT_FALSE(metadata.isEmpty());
        EXPECT_EQ(metadata.removePermissionEntries(CAMERA_METADATA_INVALID_VENDOR_ID,
                    &tagsNeedingPermission), NO_ERROR);
        camera_metadata_entry_t availableCharacteristics =
                metadata.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
        EXPECT_TRUE(0 < availableCharacteristics.count);

        std::vector<uint32_t> availableKeys;
        availableKeys.reserve(availableCharacteristics.count);
        availableKeys.insert(availableKeys.begin(), availableCharacteristics.data.i32,
                availableCharacteristics.data.i32 + availableCharacteristics.count);

        for (const auto &key : tagsNeedingPermission) {
            ASSERT_FALSE(metadata.exists(key));
            auto it = std::find(availableKeys.begin(), availableKeys.end(), key);
            ASSERT_TRUE(it == availableKeys.end());
        }
    }
}
+28 −0
Original line number Diff line number Diff line
@@ -491,6 +491,34 @@ Status CameraService::getCameraCharacteristics(const String16& cameraId,
                strerror(-res), res);
    }

    int callingPid = getCallingPid();
    int callingUid = getCallingUid();
    std::vector<int32_t> tagsRemoved;
    // If it's not calling from cameraserver, check the permission.
    if ((callingPid != getpid()) &&
            !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) {
        res = cameraInfo->removePermissionEntries(
                mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
                &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)",
                    String8(cameraId).string(), 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)", String8(cameraId).string(),
                    strerror(-res), res);
        }
    }

    return ret;
}