blob: 1e08ed13882517f78d960cf4b95c6b1e231f97e0 [file] [log] [blame]
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <sys/mman.h>
19
20#include <cutils/ashmem.h>
21#include <log/log.h>
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -070022#include <ui/BufferHubMetadata.h>
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070023
24namespace android {
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070025
26namespace {
27
28static const int kAshmemProt = PROT_READ | PROT_WRITE;
29
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070030} // namespace
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070031
Jiwen 'Steve' Cai1850da22018-10-15 21:29:14 -070032using dvr::BufferHubDefs::kMetadataHeaderSize;
33using dvr::BufferHubDefs::MetadataHeader;
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070034
35/* static */
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070036BufferHubMetadata BufferHubMetadata::Create(size_t userMetadataSize) {
37 // The size the of metadata buffer is used as the "width" parameter during allocation. Thus it
38 // cannot overflow uint32_t.
39 if (userMetadataSize >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
40 ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", userMetadataSize);
41 return {};
42 }
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070043
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070044 const size_t metadataSize = userMetadataSize + kMetadataHeaderSize;
45 int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadataSize);
46 if (fd < 0) {
47 ALOGE("BufferHubMetadata::Create: failed to create ashmem region.");
48 return {};
49 }
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070050
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070051 // Hand over the ownership of the fd to a pdx::LocalHandle immediately after the successful
52 // return of ashmem_create_region. The ashmemHandle is going to own the fd and to prevent fd
53 // leaks during error handling.
54 pdx::LocalHandle ashmemHandle{fd};
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070055
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070056 if (ashmem_set_prot_region(ashmemHandle.Get(), kAshmemProt) != 0) {
57 ALOGE("BufferHubMetadata::Create: failed to set protect region.");
58 return {};
59 }
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070060
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070061 return BufferHubMetadata::Import(std::move(ashmemHandle));
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070062}
63
64/* static */
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070065BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmemHandle) {
66 if (!ashmem_valid(ashmemHandle.Get())) {
67 ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
68 return {};
69 }
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070070
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070071 size_t metadataSize = static_cast<size_t>(ashmem_get_size_region(ashmemHandle.Get()));
72 size_t userMetadataSize = metadataSize - kMetadataHeaderSize;
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070073
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070074 // Note that here the buffer state is mapped from shared memory as an atomic object. The
75 // std::atomic's constructor will not be called so that the original value stored in the memory
76 // region can be preserved.
77 auto metadataHeader = static_cast<MetadataHeader*>(mmap(nullptr, metadataSize, kAshmemProt,
78 MAP_SHARED, ashmemHandle.Get(),
79 /*offset=*/0));
80 if (metadataHeader == nullptr) {
81 ALOGE("BufferHubMetadata::Import: failed to map region.");
82 return {};
83 }
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070084
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070085 return BufferHubMetadata(userMetadataSize, std::move(ashmemHandle), metadataHeader);
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070086}
87
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070088BufferHubMetadata::BufferHubMetadata(size_t userMetadataSize, pdx::LocalHandle ashmemHandle,
89 MetadataHeader* metadataHeader)
90 : mUserMetadataSize(userMetadataSize),
91 mAshmemHandle(std::move(ashmemHandle)),
92 mMetadataHeader(metadataHeader) {}
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070093
94BufferHubMetadata::~BufferHubMetadata() {
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070095 if (mMetadataHeader != nullptr) {
96 int ret = munmap(mMetadataHeader, metadata_size());
97 ALOGE_IF(ret != 0,
98 "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, error=%d.", errno);
99 mMetadataHeader = nullptr;
100 }
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -0700101}
102
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700103} // namespace android