blob: 0e5fce0c465ebff43ddf326f8136f11f373fe7d6 [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 {
25namespace dvr {
26
27namespace {
28
29static const int kAshmemProt = PROT_READ | PROT_WRITE;
30
31} // namespace
32
33using BufferHubDefs::kMetadataHeaderSize;
34using BufferHubDefs::MetadataHeader;
35
36/* static */
37BufferHubMetadata BufferHubMetadata::Create(size_t user_metadata_size) {
38 // The size the of metadata buffer is used as the "width" parameter during
39 // allocation. Thus it cannot overflow uint32_t.
40 if (user_metadata_size >=
41 (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
42 ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.",
43 user_metadata_size);
44 return {};
45 }
46
47 const size_t metadata_size = user_metadata_size + kMetadataHeaderSize;
48 int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadata_size);
49 if (fd < 0) {
50 ALOGE("BufferHubMetadata::Create: failed to create ashmem region.");
51 return {};
52 }
53
54 // Hand over the ownership of the fd to a pdx::LocalHandle immediately after
55 // the successful return of ashmem_create_region. The ashmem_handle is going
56 // to own the fd and to prevent fd leaks during error handling.
57 pdx::LocalHandle ashmem_handle{fd};
58
59 if (ashmem_set_prot_region(ashmem_handle.Get(), kAshmemProt) != 0) {
60 ALOGE("BufferHubMetadata::Create: failed to set protect region.");
61 return {};
62 }
63
64 return BufferHubMetadata::Import(std::move(ashmem_handle));
65}
66
67/* static */
68BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmem_handle) {
69 if (!ashmem_valid(ashmem_handle.Get())) {
70 ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
71 return {};
72 }
73
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -070074 size_t metadata_size = static_cast<size_t>(ashmem_get_size_region(ashmem_handle.Get()));
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070075 size_t user_metadata_size = metadata_size - kMetadataHeaderSize;
76
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -070077 // Note that here the buffer state is mapped from shared memory as an atomic
78 // object. The std::atomic's constructor will not be called so that the
79 // original value stored in the memory region can be preserved.
Jiwen 'Steve' Cai4e566ed2018-09-19 22:41:42 -070080 auto metadata_header = static_cast<MetadataHeader*>(
81 mmap(nullptr, metadata_size, kAshmemProt, MAP_SHARED, ashmem_handle.Get(),
82 /*offset=*/0));
83 if (metadata_header == nullptr) {
84 ALOGE("BufferHubMetadata::Import: failed to map region.");
85 return {};
86 }
87
88 return BufferHubMetadata(user_metadata_size, std::move(ashmem_handle),
89 metadata_header);
90}
91
92BufferHubMetadata::BufferHubMetadata(size_t user_metadata_size,
93 pdx::LocalHandle ashmem_handle,
94 MetadataHeader* metadata_header)
95 : user_metadata_size_(user_metadata_size),
96 ashmem_handle_(std::move(ashmem_handle)),
97 metadata_header_(metadata_header) {}
98
99BufferHubMetadata::~BufferHubMetadata() {
100 if (metadata_header_ != nullptr) {
101 int ret = munmap(metadata_header_, metadata_size());
102 ALOGE_IF(ret != 0,
103 "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, "
104 "error=%d.",
105 errno);
106 metadata_header_ = nullptr;
107 }
108}
109
110} // namespace dvr
111} // namespace android