• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SubAllocator.h"
15 
16 #include "android/base/address_space.h"
17 
18 #include <log/log.h>
19 
20 #include <iomanip>
21 #include <sstream>
22 #include <string>
23 
24 namespace android {
25 namespace base {
26 
27 class SubAllocator::Impl {
28 public:
Impl(void * _buffer,uint64_t _totalSize,uint64_t _pageSize)29     Impl(
30         void* _buffer,
31         uint64_t _totalSize,
32         uint64_t _pageSize) :
33         buffer(_buffer),
34         totalSize(_totalSize),
35         pageSize(_pageSize),
36         startAddr((uintptr_t)buffer),
37         endAddr(startAddr + totalSize) {
38 
39         address_space_allocator_init(
40             &addr_alloc,
41             totalSize,
42             32);
43     }
44 
~Impl()45     ~Impl() {
46         address_space_allocator_destroy(&addr_alloc);
47     }
48 
rangeCheck(const char * task,void * ptr)49     void rangeCheck(const char* task, void* ptr) {
50         uint64_t addr = (uintptr_t)ptr;
51         if (addr < startAddr ||
52             addr > endAddr) {
53             std::stringstream ss;
54             ss << "SubAllocator " << task << ": ";
55             ss << "Out of range: " << std::hex << addr << " ";
56             ss << "Range: " <<
57                 std::hex << startAddr << " " <<
58                 std::hex << endAddr;
59             std::string msg = ss.str();
60             ALOGE("%s", msg.c_str());
61             abort();
62         }
63     }
64 
getOffset(void * checkedPtr)65     uint64_t getOffset(void* checkedPtr) {
66         uint64_t addr = (uintptr_t)checkedPtr;
67         return addr - startAddr;
68     }
69 
free(void * ptr)70     void free(void* ptr) {
71         if (!ptr) return;
72 
73         rangeCheck("free", ptr);
74         address_space_allocator_deallocate(
75             &addr_alloc, getOffset(ptr));
76     }
77 
freeAll()78     void freeAll() {
79         address_space_allocator_reset(&addr_alloc);
80     }
81 
alloc(size_t wantedSize)82     void* alloc(size_t wantedSize) {
83         if (wantedSize == 0) return nullptr;
84 
85         uint64_t wantedSize64 =
86             (uint64_t)wantedSize;
87 
88         size_t toPageSize =
89             pageSize *
90             ((wantedSize + pageSize - 1) / pageSize);
91 
92         uint64_t offset =
93             address_space_allocator_allocate(
94                 &addr_alloc, toPageSize);
95 
96         if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
97             return nullptr;
98         }
99 
100         return (void*)(uintptr_t)(startAddr + offset);
101     }
102 
103     void* buffer;
104     uint64_t totalSize;
105     uint64_t pageSize;
106     uint64_t startAddr;
107     uint64_t endAddr;
108     struct address_space_allocator addr_alloc;
109 };
110 
SubAllocator(void * buffer,uint64_t totalSize,uint64_t pageSize)111 SubAllocator::SubAllocator(
112     void* buffer,
113     uint64_t totalSize,
114     uint64_t pageSize) :
115     mImpl(
116         new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
117 
~SubAllocator()118 SubAllocator::~SubAllocator() {
119     delete mImpl;
120 }
121 
alloc(size_t wantedSize)122 void* SubAllocator::alloc(size_t wantedSize) {
123     return mImpl->alloc(wantedSize);
124 }
125 
free(void * ptr)126 void SubAllocator::free(void* ptr) {
127     mImpl->free(ptr);
128 }
129 
freeAll()130 void SubAllocator::freeAll() {
131     mImpl->freeAll();
132 }
133 
getOffset(void * ptr)134 uint64_t SubAllocator::getOffset(void* ptr) {
135     return mImpl->getOffset(ptr);
136 }
137 
138 } // namespace base
139 } // namespace android
140