1 // Copyright 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "android/base/AndroidSubAllocator.h"
15
16 #include "android/base/address_space.h"
17 #include "android/base/files/Stream.h"
18
19 #include <iomanip>
20 #include <sstream>
21 #include <string>
22
23 #include <log/log.h>
24
25 namespace android {
26 namespace base {
27 namespace guest {
28
29 class SubAllocator::Impl {
30 public:
Impl(void * _buffer,uint64_t _totalSize,uint64_t _pageSize)31 Impl(
32 void* _buffer,
33 uint64_t _totalSize,
34 uint64_t _pageSize) :
35 buffer(_buffer),
36 totalSize(_totalSize),
37 pageSize(_pageSize),
38 startAddr((uintptr_t)buffer),
39 endAddr(startAddr + totalSize) {
40
41 address_space_allocator_init(
42 &addr_alloc,
43 totalSize,
44 32);
45 }
46
~Impl()47 ~Impl() {
48 address_space_allocator_destroy_nocleanup(&addr_alloc);
49 }
50
clear()51 void clear() {
52 address_space_allocator_destroy_nocleanup(&addr_alloc);
53 address_space_allocator_init(
54 &addr_alloc,
55 totalSize,
56 32);
57 }
58
save(Stream * stream)59 bool save(Stream* stream) {
60 address_space_allocator_iter_func_t allocatorSaver =
61 [](void* context, struct address_space_allocator* allocator) {
62 Stream* stream = reinterpret_cast<Stream*>(context);
63 stream->putBe32(allocator->size);
64 stream->putBe32(allocator->capacity);
65 stream->putBe64(allocator->total_bytes);
66 };
67 address_block_iter_func_t allocatorBlockSaver =
68 [](void* context, struct address_block* block) {
69 Stream* stream = reinterpret_cast<Stream*>(context);
70 stream->putBe64(block->offset);
71 stream->putBe64(block->size_available);
72 };
73 address_space_allocator_run(
74 &addr_alloc,
75 (void*)stream,
76 allocatorSaver,
77 allocatorBlockSaver);
78
79 stream->putBe64(pageSize);
80 stream->putBe64(totalSize);
81 stream->putBe32(allocCount);
82
83 return true;
84 }
85
load(Stream * stream)86 bool load(Stream* stream) {
87 clear();
88 address_space_allocator_iter_func_t allocatorLoader =
89 [](void* context, struct address_space_allocator* allocator) {
90 Stream* stream = reinterpret_cast<Stream*>(context);
91 allocator->size = stream->getBe32();
92 allocator->capacity = stream->getBe32();
93 allocator->total_bytes = stream->getBe64();
94 };
95 address_block_iter_func_t allocatorBlockLoader =
96 [](void* context, struct address_block* block) {
97 Stream* stream = reinterpret_cast<Stream*>(context);
98 block->offset = stream->getBe64();
99 block->size_available = stream->getBe64();
100 };
101 address_space_allocator_run(
102 &addr_alloc,
103 (void*)stream,
104 allocatorLoader,
105 allocatorBlockLoader);
106
107 pageSize = stream->getBe64();
108 totalSize = stream->getBe64();
109 allocCount = stream->getBe32();
110
111 return true;
112 }
113
postLoad(void * postLoadBuffer)114 bool postLoad(void* postLoadBuffer) {
115 buffer = postLoadBuffer;
116 startAddr =
117 (uint64_t)(uintptr_t)postLoadBuffer;
118 return true;
119 }
120
rangeCheck(const char * task,void * ptr)121 void rangeCheck(const char* task, void* ptr) {
122 uint64_t addr = (uintptr_t)ptr;
123 if (addr < startAddr ||
124 addr > endAddr) {
125 std::stringstream ss;
126 ss << "SubAllocator " << task << ": ";
127 ss << "Out of range: " << std::hex << addr << " ";
128 ss << "Range: " <<
129 std::hex << startAddr << " " <<
130 std::hex << endAddr;
131 std::string msg = ss.str();
132 ALOGE("Fatal: %s\n", msg.c_str());
133 }
134 }
135
getOffset(void * checkedPtr)136 uint64_t getOffset(void* checkedPtr) {
137 uint64_t addr = (uintptr_t)checkedPtr;
138 return addr - startAddr;
139 }
140
free(void * ptr)141 bool free(void* ptr) {
142 if (!ptr) return false;
143
144 rangeCheck("free", ptr);
145 if (EINVAL == address_space_allocator_deallocate(
146 &addr_alloc, getOffset(ptr))) {
147 return false;
148 }
149
150 --allocCount;
151 return true;
152 }
153
freeAll()154 void freeAll() {
155 address_space_allocator_reset(&addr_alloc);
156 allocCount = 0;
157 }
158
alloc(size_t wantedSize)159 void* alloc(size_t wantedSize) {
160 if (wantedSize == 0) return nullptr;
161
162 uint64_t wantedSize64 =
163 (uint64_t)wantedSize;
164
165 size_t toPageSize =
166 pageSize *
167 ((wantedSize + pageSize - 1) / pageSize);
168
169 uint64_t offset =
170 address_space_allocator_allocate(
171 &addr_alloc, toPageSize);
172
173 if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
174 return nullptr;
175 }
176
177 ++allocCount;
178 return (void*)(uintptr_t)(startAddr + offset);
179 }
180
empty() const181 bool empty() const {
182 return allocCount == 0;
183 }
184
185 void* buffer;
186 uint64_t totalSize;
187 uint64_t pageSize;
188 uint64_t startAddr;
189 uint64_t endAddr;
190 struct address_space_allocator addr_alloc;
191 uint32_t allocCount = 0;
192 };
193
SubAllocator(void * buffer,uint64_t totalSize,uint64_t pageSize)194 SubAllocator::SubAllocator(
195 void* buffer,
196 uint64_t totalSize,
197 uint64_t pageSize) :
198 mImpl(
199 new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
200
~SubAllocator()201 SubAllocator::~SubAllocator() {
202 delete mImpl;
203 }
204
205 // Snapshotting
save(Stream * stream)206 bool SubAllocator::save(Stream* stream) {
207 return mImpl->save(stream);
208 }
209
load(Stream * stream)210 bool SubAllocator::load(Stream* stream) {
211 return mImpl->load(stream);
212 }
213
postLoad(void * postLoadBuffer)214 bool SubAllocator::postLoad(void* postLoadBuffer) {
215 return mImpl->postLoad(postLoadBuffer);
216 }
217
alloc(size_t wantedSize)218 void* SubAllocator::alloc(size_t wantedSize) {
219 return mImpl->alloc(wantedSize);
220 }
221
free(void * ptr)222 bool SubAllocator::free(void* ptr) {
223 return mImpl->free(ptr);
224 }
225
freeAll()226 void SubAllocator::freeAll() {
227 mImpl->freeAll();
228 }
229
getOffset(void * ptr)230 uint64_t SubAllocator::getOffset(void* ptr) {
231 return mImpl->getOffset(ptr);
232 }
233
empty() const234 bool SubAllocator::empty() const {
235 return mImpl->empty();
236 }
237
238 } // namespace guest
239 } // namespace base
240 } // namespace android
241