mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:23:37 +00:00
Merge "Add EvsCamera Class and Buffer Manipulation" into main
This commit is contained in:
@@ -21,45 +21,41 @@ package {
|
||||
default_applicable_licenses: ["hardware_interfaces_license"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.automotive.evs-aidl-default-service",
|
||||
cc_defaults {
|
||||
name: "android.hardware.automotive.evs-aidl-default-service-default",
|
||||
defaults: ["EvsHalDefaults"],
|
||||
vintf_fragments: ["manifest_evs-default-service.xml"],
|
||||
init_rc: ["evs-default-service.rc"],
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
cflags: [
|
||||
"-DGL_GLEXT_PROTOTYPES",
|
||||
"-DEGL_EGLEXT_PROTOTYPES",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-Wthread-safety",
|
||||
],
|
||||
srcs: [
|
||||
":libgui_frame_event_aidl",
|
||||
"src/*.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.graphics.bufferqueue@1.0",
|
||||
"android.hardware.graphics.bufferqueue@2.0",
|
||||
"android.hidl.token@1.0-utils",
|
||||
"libEGL",
|
||||
"libGLESv2",
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libbufferqueueconverter",
|
||||
"libcamera_metadata",
|
||||
"libhardware_legacy",
|
||||
"libhidlbase",
|
||||
"liblog",
|
||||
"libnativewindow",
|
||||
"libtinyxml2",
|
||||
"libui",
|
||||
"libutils",
|
||||
"libyuv",
|
||||
],
|
||||
static_libs: [
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "android.hardware.automotive.evs-aidl-default-service-lib",
|
||||
defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
|
||||
vendor: true,
|
||||
cflags: [
|
||||
"-DGL_GLEXT_PROTOTYPES",
|
||||
"-DEGL_EGLEXT_PROTOTYPES",
|
||||
],
|
||||
srcs: [
|
||||
":libgui_frame_event_aidl",
|
||||
"src/*.cpp",
|
||||
],
|
||||
exclude_srcs: ["src/service.cpp"],
|
||||
whole_static_libs: [
|
||||
"android.frameworks.automotive.display-V2-ndk",
|
||||
"android.hardware.automotive.evs-V2-ndk",
|
||||
"android.hardware.common-V2-ndk",
|
||||
@@ -71,6 +67,25 @@ cc_binary {
|
||||
],
|
||||
local_include_dirs: ["include"],
|
||||
include_dirs: ["frameworks/native/include/"],
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.automotive.evs-aidl-default-service",
|
||||
defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
|
||||
vintf_fragments: ["manifest_evs-default-service.xml"],
|
||||
init_rc: ["evs-default-service.rc"],
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
cflags: [
|
||||
"-DGL_GLEXT_PROTOTYPES",
|
||||
"-DEGL_EGLEXT_PROTOTYPES",
|
||||
],
|
||||
srcs: ["src/service.cpp"],
|
||||
static_libs: [
|
||||
"android.hardware.automotive.evs-aidl-default-service-lib",
|
||||
],
|
||||
include_dirs: ["frameworks/native/include/"],
|
||||
required: ["evs_mock_hal_configuration.xml"],
|
||||
}
|
||||
|
||||
@@ -80,3 +95,14 @@ prebuilt_etc {
|
||||
src: "resources/evs_mock_configuration.xml",
|
||||
sub_dir: "automotive/evs",
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "android.hardware.automotive.evs-aidl-default-service_cam_buffer_test",
|
||||
defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
|
||||
vendor: true,
|
||||
srcs: ["tests/EvsCameraBufferTest.cpp"],
|
||||
static_libs: [
|
||||
"android.hardware.automotive.evs-aidl-default-service-lib",
|
||||
"libgmock",
|
||||
],
|
||||
}
|
||||
|
||||
98
automotive/evs/aidl/impl/default/include/EvsCamera.h
Normal file
98
automotive/evs/aidl/impl/default/include/EvsCamera.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EvsCameraBase.h"
|
||||
|
||||
#include <cutils/native_handle.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace aidl::android::hardware::automotive::evs::implementation {
|
||||
|
||||
class EvsCamera : public EvsCameraBase {
|
||||
private:
|
||||
using Base = EvsCameraBase;
|
||||
using Self = EvsCamera;
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
|
||||
~EvsCamera() override;
|
||||
|
||||
// Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
|
||||
ndk::ScopedAStatus doneWithFrame(const std::vector<evs::BufferDesc>& buffers) override;
|
||||
|
||||
ndk::ScopedAStatus importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
|
||||
int32_t* _aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus setMaxFramesInFlight(int32_t bufferCount) override;
|
||||
|
||||
protected:
|
||||
virtual ::android::status_t allocateOneFrame(buffer_handle_t* handle) = 0;
|
||||
|
||||
virtual void freeOneFrame(const buffer_handle_t handle);
|
||||
|
||||
void shutdown() override;
|
||||
|
||||
void closeAllBuffers_unsafe();
|
||||
|
||||
// Returns (ID, handle) if succeeds. (static_cast<size_t>(-1), nullptr) otherwise.
|
||||
[[nodiscard]] std::pair<std::size_t, buffer_handle_t> useBuffer_unsafe();
|
||||
|
||||
void returnBuffer_unsafe(const std::size_t id);
|
||||
|
||||
bool increaseAvailableFrames_unsafe(const buffer_handle_t handle);
|
||||
|
||||
bool decreaseAvailableFrames_unsafe();
|
||||
|
||||
bool setAvailableFrames_unsafe(const std::size_t bufferCount);
|
||||
|
||||
void swapBufferFrames_unsafe(const std::size_t pos1, const std::size_t pos2);
|
||||
|
||||
struct BufferRecord {
|
||||
BufferRecord() = default;
|
||||
BufferRecord(const BufferRecord&) = default;
|
||||
BufferRecord(BufferRecord&&) = default;
|
||||
BufferRecord& operator=(const BufferRecord&) = default;
|
||||
BufferRecord& operator=(BufferRecord&&) = default;
|
||||
~BufferRecord() = default;
|
||||
|
||||
explicit BufferRecord(buffer_handle_t h) : handle(h) {}
|
||||
|
||||
buffer_handle_t handle{nullptr};
|
||||
bool inUse{false};
|
||||
};
|
||||
|
||||
std::mutex mMutex;
|
||||
|
||||
// Graphics buffers to transfer images, always in the order of:
|
||||
// In use buffers ... available buffers ... unavailable (unallocated) buffers.
|
||||
std::vector<BufferRecord> mBuffers;
|
||||
|
||||
// Double-mapping between buffer position and ID.
|
||||
std::vector<std::size_t> mBufferPosToId;
|
||||
std::vector<std::size_t> mBufferIdToPos;
|
||||
|
||||
std::size_t mAvailableFrames{0};
|
||||
std::size_t mFramesInUse{0};
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::automotive::evs::implementation
|
||||
266
automotive/evs/aidl/impl/default/src/EvsCamera.cpp
Normal file
266
automotive/evs/aidl/impl/default/src/EvsCamera.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 "EvsCamera.h"
|
||||
|
||||
#include <aidl/android/hardware/automotive/evs/EvsResult.h>
|
||||
#include <aidlcommonsupport/NativeHandle.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android/hardware_buffer.h>
|
||||
#include <ui/GraphicBufferAllocator.h>
|
||||
#include <ui/GraphicBufferMapper.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
|
||||
namespace aidl::android::hardware::automotive::evs::implementation {
|
||||
|
||||
// Arbitrary limit on number of graphics buffers allowed to be allocated
|
||||
// Safeguards against unreasonable resource consumption and provides a testable limit
|
||||
constexpr std::size_t kMaxBuffersInFlight = 100;
|
||||
|
||||
EvsCamera::~EvsCamera() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EvsCamera::doneWithFrame(const std::vector<evs::BufferDesc>& buffers) {
|
||||
std::lock_guard lck(mMutex);
|
||||
for (const auto& desc : buffers) {
|
||||
returnBuffer_unsafe(desc.bufferId);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EvsCamera::importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
|
||||
int32_t* _aidl_return) {
|
||||
if (buffers.empty()) {
|
||||
LOG(DEBUG) << __func__
|
||||
<< ": Ignoring a request to import external buffers with an empty list.";
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
static auto& mapper = ::android::GraphicBufferMapper::get();
|
||||
std::lock_guard lck(mMutex);
|
||||
std::size_t numBuffersToAdd = std::min(buffers.size(), kMaxBuffersInFlight - mAvailableFrames);
|
||||
if (numBuffersToAdd == 0) {
|
||||
LOG(WARNING) << __func__ << ": The number of buffers has hit the upper limit ("
|
||||
<< kMaxBuffersInFlight << "). Stop importing.";
|
||||
return ndk::ScopedAStatus::ok();
|
||||
} else if (numBuffersToAdd < buffers.size()) {
|
||||
LOG(WARNING) << "Exceeds the limit on the number of buffers. Only " << numBuffersToAdd
|
||||
<< " buffers will be imported. " << buffers.size() << " are asked.";
|
||||
}
|
||||
const size_t before = mAvailableFrames;
|
||||
for (std::size_t idx = 0; idx < numBuffersToAdd; ++idx) {
|
||||
auto& buffer = buffers[idx];
|
||||
const AHardwareBuffer_Desc* pDesc =
|
||||
reinterpret_cast<const AHardwareBuffer_Desc*>(&buffer.buffer.description);
|
||||
|
||||
buffer_handle_t handleToImport = ::android::dupFromAidl(buffer.buffer.handle);
|
||||
buffer_handle_t handleToStore = nullptr;
|
||||
if (handleToImport == nullptr) {
|
||||
LOG(WARNING) << "Failed to duplicate a memory handle. Ignoring a buffer "
|
||||
<< buffer.bufferId;
|
||||
continue;
|
||||
}
|
||||
|
||||
::android::status_t result =
|
||||
mapper.importBuffer(handleToImport, pDesc->width, pDesc->height, pDesc->layers,
|
||||
pDesc->format, pDesc->usage, pDesc->stride, &handleToStore);
|
||||
if (result != ::android::NO_ERROR || handleToStore == nullptr ||
|
||||
!increaseAvailableFrames_unsafe(handleToStore)) {
|
||||
LOG(WARNING) << "Failed to import a buffer " << buffer.bufferId;
|
||||
}
|
||||
}
|
||||
*_aidl_return = mAvailableFrames - before;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EvsCamera::setMaxFramesInFlight(int32_t bufferCount) {
|
||||
std::lock_guard lock(mMutex);
|
||||
if (bufferCount < 1) {
|
||||
LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested.";
|
||||
return ndk::ScopedAStatus::fromServiceSpecificError(
|
||||
static_cast<int>(EvsResult::INVALID_ARG));
|
||||
}
|
||||
if (!setAvailableFrames_unsafe(bufferCount)) {
|
||||
LOG(ERROR) << "Failed to adjust the maximum number of frames in flight.";
|
||||
return ndk::ScopedAStatus::fromServiceSpecificError(
|
||||
static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void EvsCamera::freeOneFrame(const buffer_handle_t handle) {
|
||||
static auto& alloc = ::android::GraphicBufferAllocator::get();
|
||||
alloc.free(handle);
|
||||
}
|
||||
|
||||
bool EvsCamera::setAvailableFrames_unsafe(const std::size_t bufferCount) {
|
||||
if (bufferCount < 1) {
|
||||
LOG(ERROR) << "Ignoring request to set buffer count to zero.";
|
||||
return false;
|
||||
}
|
||||
if (bufferCount > kMaxBuffersInFlight) {
|
||||
LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bufferCount > mAvailableFrames) {
|
||||
bool success = true;
|
||||
const std::size_t numBufferBeforeAlloc = mAvailableFrames;
|
||||
for (int numBufferToAllocate = bufferCount - mAvailableFrames;
|
||||
success && numBufferToAllocate > 0; --numBufferToAllocate) {
|
||||
buffer_handle_t handle = nullptr;
|
||||
const auto result = allocateOneFrame(&handle);
|
||||
if (result != ::android::NO_ERROR || !handle) {
|
||||
LOG(ERROR) << __func__ << ": Failed to allocate a graphics buffer. Error " << result
|
||||
<< ", handle: " << handle;
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
success &= increaseAvailableFrames_unsafe(handle);
|
||||
}
|
||||
if (!success) {
|
||||
// Rollback when failure.
|
||||
for (int numBufferToRelease = mAvailableFrames - numBufferBeforeAlloc;
|
||||
numBufferToRelease > 0; --numBufferToRelease) {
|
||||
decreaseAvailableFrames_unsafe();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
for (int numBufferToRelease = mAvailableFrames - std::max(bufferCount, mFramesInUse);
|
||||
numBufferToRelease > 0; --numBufferToRelease) {
|
||||
decreaseAvailableFrames_unsafe();
|
||||
}
|
||||
if (mAvailableFrames > bufferCount) {
|
||||
// This shouldn't happen with a properly behaving client because the client
|
||||
// should only make this call after returning sufficient outstanding buffers
|
||||
// to allow a clean resize.
|
||||
LOG(ERROR) << "Buffer queue shrink failed, asked: " << bufferCount
|
||||
<< ", actual: " << mAvailableFrames
|
||||
<< " -- too many buffers currently in use?";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EvsCamera::shutdown() {
|
||||
std::lock_guard lck(mMutex);
|
||||
closeAllBuffers_unsafe();
|
||||
}
|
||||
|
||||
void EvsCamera::closeAllBuffers_unsafe() {
|
||||
if (mFramesInUse > 0) {
|
||||
LOG(WARNING) << __func__ << ": Closing while " << mFramesInUse
|
||||
<< " frame(s) are still in use.";
|
||||
}
|
||||
for (auto& buffer : mBuffers) {
|
||||
freeOneFrame(buffer.handle);
|
||||
buffer.handle = nullptr;
|
||||
}
|
||||
mBuffers.clear();
|
||||
mBufferPosToId.clear();
|
||||
mBufferIdToPos.clear();
|
||||
}
|
||||
|
||||
std::pair<std::size_t, buffer_handle_t> EvsCamera::useBuffer_unsafe() {
|
||||
if (mFramesInUse >= mAvailableFrames) {
|
||||
DCHECK_EQ(mFramesInUse, mAvailableFrames);
|
||||
return {static_cast<std::size_t>(-1), nullptr};
|
||||
}
|
||||
const std::size_t pos = mFramesInUse++;
|
||||
auto& buffer = mBuffers[pos];
|
||||
DCHECK(!buffer.inUse);
|
||||
DCHECK(buffer.handle);
|
||||
buffer.inUse = true;
|
||||
return {mBufferPosToId[pos], buffer.handle};
|
||||
}
|
||||
|
||||
void EvsCamera::returnBuffer_unsafe(const std::size_t id) {
|
||||
if (id >= mBuffers.size()) {
|
||||
LOG(ERROR) << __func__ << ": ID out-of-bound. id: " << id
|
||||
<< " max: " << mBuffers.size() - 1;
|
||||
return;
|
||||
}
|
||||
const std::size_t pos = mBufferIdToPos[id];
|
||||
|
||||
if (!mBuffers[pos].inUse) {
|
||||
LOG(ERROR) << __func__ << ": Ignoring returning frame " << id << " which is already free.";
|
||||
return;
|
||||
}
|
||||
DCHECK_LT(pos, mFramesInUse);
|
||||
const std::size_t last_in_use_pos = --mFramesInUse;
|
||||
swapBufferFrames_unsafe(pos, last_in_use_pos);
|
||||
mBuffers[last_in_use_pos].inUse = false;
|
||||
}
|
||||
|
||||
bool EvsCamera::increaseAvailableFrames_unsafe(const buffer_handle_t handle) {
|
||||
if (mAvailableFrames >= kMaxBuffersInFlight) {
|
||||
LOG(WARNING) << __func__ << ": The number of buffers has hit the upper limit ("
|
||||
<< kMaxBuffersInFlight << "). Stop increasing.";
|
||||
return false;
|
||||
}
|
||||
const std::size_t pos = mAvailableFrames++;
|
||||
if (mAvailableFrames > mBuffers.size()) {
|
||||
const std::size_t oldBufferSize = mBuffers.size();
|
||||
mBuffers.resize(mAvailableFrames);
|
||||
mBufferPosToId.resize(mAvailableFrames);
|
||||
mBufferIdToPos.resize(mAvailableFrames);
|
||||
// Build position/ID mapping.
|
||||
for (std::size_t idx = oldBufferSize; idx < mBuffers.size(); ++idx) {
|
||||
mBufferPosToId[idx] = idx;
|
||||
mBufferIdToPos[idx] = idx;
|
||||
}
|
||||
}
|
||||
auto& buffer = mBuffers[pos];
|
||||
DCHECK(!buffer.inUse);
|
||||
DCHECK(!buffer.handle);
|
||||
buffer.handle = handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EvsCamera::decreaseAvailableFrames_unsafe() {
|
||||
if (mFramesInUse >= mAvailableFrames) {
|
||||
DCHECK_EQ(mFramesInUse, mAvailableFrames);
|
||||
return false;
|
||||
}
|
||||
const std::size_t pos = --mAvailableFrames;
|
||||
auto& buffer = mBuffers[pos];
|
||||
DCHECK(!buffer.inUse);
|
||||
DCHECK(buffer.handle);
|
||||
freeOneFrame(buffer.handle);
|
||||
buffer.handle = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void EvsCamera::swapBufferFrames_unsafe(const std::size_t pos1, const std::size_t pos2) {
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
if (pos1 >= mBuffers.size() || pos2 >= mBuffers.size()) {
|
||||
LOG(ERROR) << __func__ << ": Index out-of-bound. pos1: " << pos1 << ", pos2: " << pos2
|
||||
<< ", buffer size: " << mBuffers.size();
|
||||
return;
|
||||
}
|
||||
const std::size_t id1 = mBufferPosToId[pos1];
|
||||
const std::size_t id2 = mBufferPosToId[pos2];
|
||||
std::swap(mBufferPosToId[pos1], mBufferPosToId[pos2]);
|
||||
std::swap(mBufferIdToPos[id1], mBufferIdToPos[id2]);
|
||||
std::swap(mBuffers[pos1], mBuffers[pos2]);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::automotive::evs::implementation
|
||||
208
automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp
Normal file
208
automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 "EvsCamera.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace aidl::android::hardware::automotive::evs::implementation {
|
||||
|
||||
class EvsCameraForTest : public EvsCamera {
|
||||
public:
|
||||
using EvsCamera::increaseAvailableFrames_unsafe;
|
||||
using EvsCamera::returnBuffer_unsafe;
|
||||
using EvsCamera::useBuffer_unsafe;
|
||||
|
||||
~EvsCameraForTest() override { shutdown(); }
|
||||
|
||||
::android::status_t allocateOneFrame(buffer_handle_t* handle) override {
|
||||
static std::intptr_t handle_cnt = 0;
|
||||
*handle = reinterpret_cast<buffer_handle_t>(++handle_cnt);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
void freeOneFrame(const buffer_handle_t /* handle */) override {
|
||||
// Nothing to free because the handles are fake.
|
||||
}
|
||||
|
||||
void checkBufferOrder() {
|
||||
for (std::size_t idx = 0; idx < mBuffers.size(); ++idx) {
|
||||
const auto& buffer = mBuffers[idx];
|
||||
EXPECT_EQ(idx < mFramesInUse, buffer.inUse);
|
||||
EXPECT_EQ(idx < mAvailableFrames, buffer.handle != nullptr);
|
||||
EXPECT_LE(mFramesInUse, mAvailableFrames);
|
||||
}
|
||||
}
|
||||
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, forcePrimaryClient,
|
||||
(const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
|
||||
in_display),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, getCameraInfo,
|
||||
(::aidl::android::hardware::automotive::evs::CameraDesc * _aidl_return),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, getExtendedInfo,
|
||||
(int32_t in_opaqueIdentifier, std::vector<uint8_t>* _aidl_return), (override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, getIntParameter,
|
||||
(::aidl::android::hardware::automotive::evs::CameraParam in_id,
|
||||
std::vector<int32_t>* _aidl_return),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, getIntParameterRange,
|
||||
(::aidl::android::hardware::automotive::evs::CameraParam in_id,
|
||||
::aidl::android::hardware::automotive::evs::ParameterRange* _aidl_return),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, getParameterList,
|
||||
(std::vector<::aidl::android::hardware::automotive::evs::CameraParam> *
|
||||
_aidl_return),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, getPhysicalCameraInfo,
|
||||
(const std::string& in_deviceId,
|
||||
::aidl::android::hardware::automotive::evs::CameraDesc* _aidl_return),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, pauseVideoStream, (), (override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, resumeVideoStream, (), (override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, setExtendedInfo,
|
||||
(int32_t in_opaqueIdentifier, const std::vector<uint8_t>& in_opaqueValue),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, setIntParameter,
|
||||
(::aidl::android::hardware::automotive::evs::CameraParam in_id, int32_t in_value,
|
||||
std::vector<int32_t>* _aidl_return),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, setPrimaryClient, (), (override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, startVideoStream,
|
||||
(const std::shared_ptr<
|
||||
::aidl::android::hardware::automotive::evs::IEvsCameraStream>& in_receiver),
|
||||
(override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, stopVideoStream, (), (override));
|
||||
MOCK_METHOD(::ndk::ScopedAStatus, unsetPrimaryClient, (), (override));
|
||||
};
|
||||
|
||||
TEST(EvsCameraBufferTest, ChangeBufferPoolSize) {
|
||||
auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
|
||||
EXPECT_TRUE(evsCam->setMaxFramesInFlight(100).isOk());
|
||||
evsCam->checkBufferOrder();
|
||||
EXPECT_TRUE(evsCam->setMaxFramesInFlight(50).isOk());
|
||||
evsCam->checkBufferOrder();
|
||||
|
||||
// 2 buffers in use.
|
||||
const auto [id1, handle1] = evsCam->useBuffer_unsafe();
|
||||
const auto [id2, handle2] = evsCam->useBuffer_unsafe();
|
||||
std::ignore = evsCam->useBuffer_unsafe();
|
||||
|
||||
// It allows you to set the buffer pool size to 1, but it will keep the space for the in use
|
||||
// buffers.
|
||||
EXPECT_TRUE(evsCam->setMaxFramesInFlight(1).isOk());
|
||||
evsCam->checkBufferOrder();
|
||||
|
||||
evsCam->returnBuffer_unsafe(id1);
|
||||
evsCam->checkBufferOrder();
|
||||
evsCam->returnBuffer_unsafe(id2);
|
||||
evsCam->checkBufferOrder();
|
||||
}
|
||||
|
||||
TEST(EvsCameraForTest, UseAndReturn) {
|
||||
constexpr std::size_t kNumOfHandles = 20;
|
||||
auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
|
||||
|
||||
// Our "fake handles" of this test case is 1 to kNumOfHandles.
|
||||
for (std::size_t i = 1; i <= kNumOfHandles; ++i) {
|
||||
evsCam->increaseAvailableFrames_unsafe(reinterpret_cast<buffer_handle_t>(i));
|
||||
}
|
||||
evsCam->checkBufferOrder();
|
||||
|
||||
{
|
||||
std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
|
||||
std::unordered_set<std::size_t> inUseIDs;
|
||||
std::unordered_set<std::intptr_t> inUseHandles;
|
||||
for (std::size_t i = 0; i < kNumOfHandles; ++i) {
|
||||
const auto [id, handle] = evsCam->useBuffer_unsafe();
|
||||
const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
|
||||
EXPECT_NE(handle, nullptr);
|
||||
EXPECT_LT(id, kNumOfHandles);
|
||||
|
||||
// handleInt must be between [1, kNumOfHandles] as we "allocated" above.
|
||||
EXPECT_LT(0u, handleInt);
|
||||
EXPECT_LE(handleInt, kNumOfHandles);
|
||||
|
||||
inUseIDHandlePairs.push_back({id, handleInt});
|
||||
EXPECT_TRUE(inUseIDs.insert(id).second);
|
||||
EXPECT_TRUE(inUseHandles.insert(handleInt).second);
|
||||
evsCam->checkBufferOrder();
|
||||
}
|
||||
// Return buffers in the order of acquiring.
|
||||
for (const auto [id, handleInt] : inUseIDHandlePairs) {
|
||||
evsCam->returnBuffer_unsafe(id);
|
||||
evsCam->checkBufferOrder();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
|
||||
std::unordered_set<std::size_t> inUseIDs;
|
||||
std::unordered_set<std::intptr_t> inUseHandles;
|
||||
for (std::size_t i = 0; i < kNumOfHandles; ++i) {
|
||||
const auto [id, handle] = evsCam->useBuffer_unsafe();
|
||||
const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
|
||||
EXPECT_NE(handle, nullptr);
|
||||
EXPECT_LT(id, kNumOfHandles);
|
||||
|
||||
// handleInt must be between [1, kNumOfHandles] as we "allocated" above.
|
||||
EXPECT_LT(0u, handleInt);
|
||||
EXPECT_LE(handleInt, kNumOfHandles);
|
||||
|
||||
inUseIDHandlePairs.push_back({id, handleInt});
|
||||
EXPECT_TRUE(inUseIDs.insert(id).second);
|
||||
EXPECT_TRUE(inUseHandles.insert(handleInt).second);
|
||||
evsCam->checkBufferOrder();
|
||||
}
|
||||
// Return buffers in the reverse order of acquiring.
|
||||
std::reverse(inUseIDHandlePairs.begin(), inUseIDHandlePairs.end());
|
||||
for (const auto [id, handleInt] : inUseIDHandlePairs) {
|
||||
evsCam->returnBuffer_unsafe(id);
|
||||
evsCam->checkBufferOrder();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Making sure the handles are still in [1, kNumOfHandles] and IDs are still [0,
|
||||
// kNumOfHandles). The mapping may be different, though.
|
||||
std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
|
||||
std::unordered_set<std::size_t> inUseIDs;
|
||||
std::unordered_set<std::intptr_t> inUseHandles;
|
||||
for (std::size_t i = 0; i < kNumOfHandles; ++i) {
|
||||
const auto [id, handle] = evsCam->useBuffer_unsafe();
|
||||
const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
|
||||
EXPECT_NE(handle, nullptr);
|
||||
EXPECT_LT(id, kNumOfHandles);
|
||||
|
||||
// handleInt must be between [1, kNumOfHandles] as we "allocated" above.
|
||||
EXPECT_LT(0u, handleInt);
|
||||
EXPECT_LE(handleInt, kNumOfHandles);
|
||||
|
||||
inUseIDHandlePairs.push_back({id, handleInt});
|
||||
EXPECT_TRUE(inUseIDs.insert(id).second);
|
||||
EXPECT_TRUE(inUseHandles.insert(handleInt).second);
|
||||
evsCam->checkBufferOrder();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::automotive::evs::implementation
|
||||
Reference in New Issue
Block a user