Gralloc region
Adds the layout and the region view implementation
Test: Builds
Bug: 64158954
Change-Id: I6f6cab5545ea920f9e3d3347ff2f13c3b3c93ed5
diff --git a/common/vsoc/lib/gralloc_layout.cpp b/common/vsoc/lib/gralloc_layout.cpp
new file mode 100644
index 0000000..9be790a
--- /dev/null
+++ b/common/vsoc/lib/gralloc_layout.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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 some of the string constants associated with the region layout.
+#include "common/vsoc/shm/gralloc_layout.h"
+
+namespace vsoc {
+namespace layout {
+
+namespace gralloc {
+
+const char* GrallocManagerLayout::region_name = "gralloc_manager";
+const char* GrallocBufferLayout::region_name = "gralloc_memory";
+
+} // gralloc
+} // layout
+} // vsoc
diff --git a/common/vsoc/shm/BUILD b/common/vsoc/shm/BUILD
index 78772b8..6d5d0b6 100644
--- a/common/vsoc/shm/BUILD
+++ b/common/vsoc/shm/BUILD
@@ -4,6 +4,7 @@
"base.h",
"circqueue.h",
"e2e_test_region_layout.h",
+ "gralloc_layout.h",
"graphics.h",
"lock.h",
"version.h",
diff --git a/common/vsoc/shm/gralloc_layout.h b/common/vsoc/shm/gralloc_layout.h
new file mode 100644
index 0000000..37e5f8a
--- /dev/null
+++ b/common/vsoc/shm/gralloc_layout.h
@@ -0,0 +1,69 @@
+#pragma once
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Base macros for all layout structures.
+
+#include "common/vsoc/shm/base.h"
+#include "common/vsoc/shm/graphics.h"
+#include "common/vsoc/shm/lock.h"
+#include "common/vsoc/shm/version.h"
+#include "uapi/vsoc_shm.h"
+
+// Memory layout for the gralloc manager region.
+
+namespace vsoc {
+namespace layout {
+
+namespace gralloc {
+
+struct BufferEntry : public Base {
+ uint32_t owned_by;
+ vsoc_reg_off_t buffer_begin;
+ vsoc_reg_off_t buffer_end;
+
+ PixelFormatRegister pixel_format;
+ uint32_t stride;
+ uint32_t width;
+ uint32_t height;
+
+ uint32_t buffer_size() {
+ return buffer_end - buffer_begin;
+ }
+};
+ASSERT_SHM_COMPATIBLE(BufferEntry, gralloc);
+
+struct GrallocBufferLayout : public RegionLayout {
+ static const char* region_name;
+};
+ASSERT_SHM_COMPATIBLE(GrallocBufferLayout, gralloc);
+
+struct GrallocManagerLayout : public RegionLayout {
+ static const char* region_name;
+ typedef GrallocBufferLayout ManagedRegion;
+
+ uint32_t allocated_buffer_memory;
+ uint32_t buffer_count;
+ // Make sure this isn't the first field
+ GuestLock new_buffer_lock;
+ // Needs to be last entry
+ BufferEntry buffers_table[1];
+};
+ASSERT_SHM_COMPATIBLE(GrallocManagerLayout, gralloc);
+
+} // namespace gralloc
+} // namespace layout
+} // namespace vsoc
diff --git a/common/vsoc/shm/version.h b/common/vsoc/shm/version.h
index c4c3a5c..e9c081b 100644
--- a/common/vsoc/shm/version.h
+++ b/common/vsoc/shm/version.h
@@ -47,6 +47,8 @@
// #ifdef, etc is absolutely forbidden in this file and highly discouraged
// in the other vsoc/shm files.
+#include <cstdint>
+
namespace vsoc {
namespace layout {
namespace version_info {
@@ -90,6 +92,17 @@
} // namespace constant_values
} // namespace multi_region
+// Versioning information for gralloc.h
+// Changes to these structures will affect only the gralloc region
+namespace gralloc {
+namespace {
+const uint32_t version = 0;
+}
+static const std::size_t BufferEntry_size = 28;
+static const std::size_t GrallocManagerLayout_size = 76;
+static const std::size_t GrallocBufferLayout_size = 1;
+} // namespace gralloc
+
// Versioning information for e2e_test_region.h
// Changes to these structures will affect only the e2e_test_region
namespace e2e_test {
diff --git a/guest/vsoc/gralloc/Android.mk b/guest/vsoc/gralloc/Android.mk
new file mode 100644
index 0000000..0d4ffbe
--- /dev/null
+++ b/guest/vsoc/gralloc/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libvsoc_gralloc
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ ../../../common/vsoc/lib/gralloc_layout.cpp \
+ gralloc_region.cpp
+
+LOCAL_C_INCLUDES += \
+ device/google/cuttlefish_common/guest/vsoc/gralloc \
+ device/google/cuttlefish_common \
+ device/google/cuttlefish_kernel \
+ system/core/base/include
+
+LOCAL_CFLAGS := \
+ -DLOG_TAG=\"libvsoc_gralloc\" \
+ -Wno-missing-field-initializers \
+ -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcuttlefish_auto_resources \
+ libcuttlefish_fs \
+ liblog \
+ libvsoc
+
+LOCAL_VENDOR_MODULE := true
+include $(BUILD_SHARED_LIBRARY)
diff --git a/guest/vsoc/gralloc/gralloc_region.cpp b/guest/vsoc/gralloc/gralloc_region.cpp
new file mode 100644
index 0000000..5c5fcb0
--- /dev/null
+++ b/guest/vsoc/gralloc/gralloc_region.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 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 "gralloc_region.h"
+
+#include <atomic>
+#include <common/vsoc/lib/lock_guard.h>
+#include <log/log.h>
+#include <sys/types.h>
+#include <uapi/vsoc_shm.h>
+
+using vsoc::gralloc::GrallocRegion;
+using vsoc::layout::gralloc::BufferEntry;
+using vsoc::layout::gralloc::GrallocBufferLayout;
+using vsoc::layout::gralloc::GrallocManagerLayout;
+
+namespace {
+template <typename T>
+inline T gralloc_align(T val) {
+ return (val + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+}
+
+// Use the thread id to identify the original creator of a buffer.
+inline uint32_t gralloc_owned_value() {
+ return gettid();
+}
+
+} // namespace
+
+GrallocRegion::GrallocRegion() {
+ // The construction in the singleton is thread safe, so we call Open here to
+ // make sure it opens thread safe too. The singleton will return null if the
+ // region failed to open.
+ Open();
+}
+
+bool GrallocRegion::Open(const char* domain) {
+ if (is_open_) {
+ return true;
+ }
+ if (!vsoc::ManagerRegionView<GrallocManagerLayout>::Open()) {
+ return false;
+ }
+ std::shared_ptr<vsoc::RegionControl> managed_region =
+ vsoc::RegionControl::Open(
+ GrallocManagerLayout::ManagedRegion::region_name, domain);
+ if (!managed_region) {
+ LOG_FATAL("Unable to open managed region");
+ return false;
+ }
+ offset_of_buffer_memory_ = gralloc_align<vsoc_reg_off_t>(
+ managed_region->region_desc().offset_of_region_data);
+ total_buffer_memory_ =
+ managed_region->region_size() - offset_of_buffer_memory_;
+
+ // TODO(jemoreira): Handle the case of unexpected values in the region.
+ is_open_ = true;
+ return true;
+}
+
+int GrallocRegion::AllocateBuffer(size_t size, uint32_t* begin_offset) {
+ size = gralloc_align<size_t>(size);
+ // Cache the value of buffer_count in shared memory.
+ uint32_t buffer_count_local = 0;
+ {
+ vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock);
+ buffer_count_local = data()->buffer_count;
+ }
+ // Find a free buffer entry of the appropriate size.
+ for (uint32_t idx = 0; idx < buffer_count_local; ++idx) {
+ BufferEntry& entry = data()->buffers_table[idx];
+ if (entry.owned_by == VSOC_REGION_FREE && entry.buffer_size() == size) {
+ int fd = control_->CreateFdScopedPermission(
+ GrallocManagerLayout::ManagedRegion::region_name,
+ pointer_to_region_offset(&entry.owned_by),
+ gralloc_owned_value(),
+ entry.buffer_begin,
+ entry.buffer_end);
+ if (fd >= 0) {
+ if (begin_offset) {
+ *begin_offset = entry.buffer_begin;
+ }
+ return fd;
+ }
+ }
+ }
+
+ // We couldn't find any suitable buffer, create one
+ {
+ vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock);
+ // don't use the cached value here!!!
+ uint32_t idx = data()->buffer_count;
+ if (pointer_to_region_offset(&data()->buffers_table[idx + 1]) >
+ control_->region_size()) {
+ ALOGE(
+ "Out of memory in gralloc_manager (total: %d, used: %d, "
+ "requested: %d)",
+ control_->region_size(),
+ pointer_to_region_offset(&data()->buffers_table[idx]),
+ sizeof(data()->buffers_table[idx]));
+ return -ENOMEM;
+ }
+ if (total_buffer_memory_ - data()->allocated_buffer_memory < size) {
+ ALOGE(
+ "Out of memory in gralloc_memory (total: %d, used: %d, requested: %d)",
+ total_buffer_memory_,
+ data()->allocated_buffer_memory,
+ size);
+ return -ENOMEM;
+ }
+ // Initialize the buffer entry and acquire ownership
+ // Do it before increasing buffer_count so that another thread looking for
+ // free entries doesn't find this one
+ BufferEntry& new_entry = data()->buffers_table[idx];
+ new_entry.buffer_begin =
+ offset_of_buffer_memory_ + data()->allocated_buffer_memory;
+ data()->allocated_buffer_memory += size;
+ new_entry.buffer_end = new_entry.buffer_begin + size;
+ int fd = control_->CreateFdScopedPermission(
+ GrallocManagerLayout::ManagedRegion::region_name,
+ pointer_to_region_offset(&new_entry.owned_by),
+ gralloc_owned_value(),
+ new_entry.buffer_begin,
+ new_entry.buffer_end);
+ if (fd < 0) {
+ LOG_FATAL(
+ "Unexpected error while creating fd scoped permission over "
+ "uncontested memory: %s",
+ strerror(-fd));
+ return fd;
+ }
+ // Increment buffer_count now that the entry can't be taken from us
+ data()->buffer_count++;
+ if (begin_offset) {
+ *begin_offset = new_entry.buffer_begin;
+ }
+ return fd;
+ }
+}
+
+/* static */
+// The C++03 standard does not guarantee this singleton implemention to be
+// thread safe, however magic statics are part of the gcc compiler since
+// version 4.3.
+GrallocRegion* GrallocRegion::GetInstance() {
+ static GrallocRegion singleton;
+ if (!singleton.is_open_) {
+ return NULL;
+ }
+ return &singleton;
+}
diff --git a/guest/vsoc/gralloc/gralloc_region.h b/guest/vsoc/gralloc/gralloc_region.h
new file mode 100644
index 0000000..f8098db
--- /dev/null
+++ b/guest/vsoc/gralloc/gralloc_region.h
@@ -0,0 +1,50 @@
+#pragma once
+
+/*
+ * Copyright (C) 2017 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 <common/vsoc/shm/gralloc_layout.h>
+#include <guest/vsoc/lib/manager_region_view.h>
+#include <stdlib.h>
+
+namespace vsoc {
+namespace gralloc {
+
+class GrallocRegion : public vsoc::ManagerRegionView<
+ vsoc::layout::gralloc::GrallocManagerLayout> {
+ public:
+ // Allocates a gralloc buffer of (at least) the specified size. Returns a file
+ // descriptor that exposes the buffer when mmapped from 0 to (the page
+ // aligned) size (and fails to mmap anything outside of that range) or a
+ // negative number in case of error (e.g not enough free memory left).
+ // TODO(jemoreira): Include debug info like stride, width, height, etc
+ int AllocateBuffer(size_t size, uint32_t* begin_offset = nullptr);
+
+ static GrallocRegion* GetInstance();
+ protected:
+ GrallocRegion();
+ GrallocRegion(const GrallocRegion&);
+ GrallocRegion& operator=(const GrallocRegion&);
+
+ bool Open(const char* domain = nullptr);
+
+ vsoc_reg_off_t offset_of_buffer_memory_{};
+ uint32_t total_buffer_memory_{};
+ bool is_open_{false};
+};
+
+} // namespace gralloc
+} // namespace vsoc
diff --git a/guest/vsoc/lib/region_control.cpp b/guest/vsoc/lib/region_control.cpp
index d4e2555..cf48218 100644
--- a/guest/vsoc/lib/region_control.cpp
+++ b/guest/vsoc/lib/region_control.cpp
@@ -99,9 +99,9 @@
if (retval) {
int errno_ = errno;
close(managed_region_fd);
- if (errno != EBUSY) {
- LOG(FATAL) << "Unable to create fd scoped permission (" << strerror(errno)
- << ")";
+ if (errno_ != EBUSY) {
+ LOG(FATAL) << "Unable to create fd scoped permission ("
+ << strerror(errno_) << ")";
}
return -errno_;
}