1*8222fbe1SAndroid Build Coastguard Worker /*
2*8222fbe1SAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*8222fbe1SAndroid Build Coastguard Worker *
4*8222fbe1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*8222fbe1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*8222fbe1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*8222fbe1SAndroid Build Coastguard Worker *
8*8222fbe1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*8222fbe1SAndroid Build Coastguard Worker *
10*8222fbe1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*8222fbe1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*8222fbe1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8222fbe1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*8222fbe1SAndroid Build Coastguard Worker * limitations under the License.
15*8222fbe1SAndroid Build Coastguard Worker */
16*8222fbe1SAndroid Build Coastguard Worker #define LOG_TAG "libhidlmemory"
17*8222fbe1SAndroid Build Coastguard Worker
18*8222fbe1SAndroid Build Coastguard Worker #include <map>
19*8222fbe1SAndroid Build Coastguard Worker #include <mutex>
20*8222fbe1SAndroid Build Coastguard Worker #include <string>
21*8222fbe1SAndroid Build Coastguard Worker
22*8222fbe1SAndroid Build Coastguard Worker #include <AshmemMemory.h>
23*8222fbe1SAndroid Build Coastguard Worker #include <hidlmemory/mapping.h>
24*8222fbe1SAndroid Build Coastguard Worker
25*8222fbe1SAndroid Build Coastguard Worker #include <android-base/logging.h>
26*8222fbe1SAndroid Build Coastguard Worker #include <android/hidl/memory/1.0/IMapper.h>
27*8222fbe1SAndroid Build Coastguard Worker #include <hidl/HidlSupport.h>
28*8222fbe1SAndroid Build Coastguard Worker #include <log/log.h>
29*8222fbe1SAndroid Build Coastguard Worker
30*8222fbe1SAndroid Build Coastguard Worker using android::sp;
31*8222fbe1SAndroid Build Coastguard Worker using android::hidl::memory::V1_0::IMemory;
32*8222fbe1SAndroid Build Coastguard Worker using android::hidl::memory::V1_0::IMapper;
33*8222fbe1SAndroid Build Coastguard Worker
34*8222fbe1SAndroid Build Coastguard Worker namespace android {
35*8222fbe1SAndroid Build Coastguard Worker namespace hardware {
36*8222fbe1SAndroid Build Coastguard Worker
37*8222fbe1SAndroid Build Coastguard Worker static std::map<std::string, sp<IMapper>> gMappersByName;
38*8222fbe1SAndroid Build Coastguard Worker static std::mutex gMutex;
39*8222fbe1SAndroid Build Coastguard Worker static std::once_flag gOnceFlagLog;
40*8222fbe1SAndroid Build Coastguard Worker
createAshmemMemory(const hidl_memory & mem)41*8222fbe1SAndroid Build Coastguard Worker static sp<IMemory> createAshmemMemory(const hidl_memory& mem) {
42*8222fbe1SAndroid Build Coastguard Worker if (mem.handle()->numFds == 0) {
43*8222fbe1SAndroid Build Coastguard Worker return nullptr;
44*8222fbe1SAndroid Build Coastguard Worker }
45*8222fbe1SAndroid Build Coastguard Worker
46*8222fbe1SAndroid Build Coastguard Worker // If ashmem service runs in 32-bit (size_t is uint32_t) and a 64-bit
47*8222fbe1SAndroid Build Coastguard Worker // client process requests a memory > 2^32 bytes, the size would be
48*8222fbe1SAndroid Build Coastguard Worker // converted to a 32-bit number in mmap. mmap could succeed but the
49*8222fbe1SAndroid Build Coastguard Worker // mapped memory's actual size would be smaller than the reported size.
50*8222fbe1SAndroid Build Coastguard Worker if (mem.size() > SIZE_MAX) {
51*8222fbe1SAndroid Build Coastguard Worker ALOGE("Cannot map %" PRIu64 " bytes of memory because it is too large.", mem.size());
52*8222fbe1SAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, "79376389");
53*8222fbe1SAndroid Build Coastguard Worker return nullptr;
54*8222fbe1SAndroid Build Coastguard Worker }
55*8222fbe1SAndroid Build Coastguard Worker
56*8222fbe1SAndroid Build Coastguard Worker int fd = mem.handle()->data[0];
57*8222fbe1SAndroid Build Coastguard Worker void* data = mmap(0, mem.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
58*8222fbe1SAndroid Build Coastguard Worker if (data == MAP_FAILED) {
59*8222fbe1SAndroid Build Coastguard Worker // mmap never maps at address zero without MAP_FIXED, so we can avoid
60*8222fbe1SAndroid Build Coastguard Worker // exposing clients to MAP_FAILED.
61*8222fbe1SAndroid Build Coastguard Worker return nullptr;
62*8222fbe1SAndroid Build Coastguard Worker }
63*8222fbe1SAndroid Build Coastguard Worker
64*8222fbe1SAndroid Build Coastguard Worker return new impl::AshmemMemory(mem, data);
65*8222fbe1SAndroid Build Coastguard Worker }
66*8222fbe1SAndroid Build Coastguard Worker
getMapperService(const std::string & name)67*8222fbe1SAndroid Build Coastguard Worker static inline sp<IMapper> getMapperService(const std::string& name) {
68*8222fbe1SAndroid Build Coastguard Worker std::unique_lock<std::mutex> _lock(gMutex);
69*8222fbe1SAndroid Build Coastguard Worker auto iter = gMappersByName.find(name);
70*8222fbe1SAndroid Build Coastguard Worker if (iter != gMappersByName.end()) {
71*8222fbe1SAndroid Build Coastguard Worker return iter->second;
72*8222fbe1SAndroid Build Coastguard Worker }
73*8222fbe1SAndroid Build Coastguard Worker
74*8222fbe1SAndroid Build Coastguard Worker sp<IMapper> mapper = IMapper::getService(name, true /* getStub */);
75*8222fbe1SAndroid Build Coastguard Worker if (mapper != nullptr) {
76*8222fbe1SAndroid Build Coastguard Worker gMappersByName[name] = mapper;
77*8222fbe1SAndroid Build Coastguard Worker }
78*8222fbe1SAndroid Build Coastguard Worker return mapper;
79*8222fbe1SAndroid Build Coastguard Worker }
80*8222fbe1SAndroid Build Coastguard Worker
mapMemory(const hidl_memory & memory)81*8222fbe1SAndroid Build Coastguard Worker sp<IMemory> mapMemory(const hidl_memory& memory) {
82*8222fbe1SAndroid Build Coastguard Worker
83*8222fbe1SAndroid Build Coastguard Worker sp<IMapper> mapper = getMapperService(memory.name());
84*8222fbe1SAndroid Build Coastguard Worker
85*8222fbe1SAndroid Build Coastguard Worker if (mapper == nullptr) {
86*8222fbe1SAndroid Build Coastguard Worker if (memory.name() == "ashmem") {
87*8222fbe1SAndroid Build Coastguard Worker std::call_once(gOnceFlagLog,
88*8222fbe1SAndroid Build Coastguard Worker [&]() { LOG(INFO) << "Using libhidlmemory mapper for ashmem."; });
89*8222fbe1SAndroid Build Coastguard Worker return createAshmemMemory(memory);
90*8222fbe1SAndroid Build Coastguard Worker } else {
91*8222fbe1SAndroid Build Coastguard Worker LOG(ERROR) << "Could not fetch mapper for " << memory.name() << " shared memory";
92*8222fbe1SAndroid Build Coastguard Worker return nullptr;
93*8222fbe1SAndroid Build Coastguard Worker }
94*8222fbe1SAndroid Build Coastguard Worker }
95*8222fbe1SAndroid Build Coastguard Worker
96*8222fbe1SAndroid Build Coastguard Worker if (mapper->isRemote()) {
97*8222fbe1SAndroid Build Coastguard Worker LOG(ERROR) << "IMapper must be a passthrough service.";
98*8222fbe1SAndroid Build Coastguard Worker return nullptr;
99*8222fbe1SAndroid Build Coastguard Worker }
100*8222fbe1SAndroid Build Coastguard Worker
101*8222fbe1SAndroid Build Coastguard Worker // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map
102*8222fbe1SAndroid Build Coastguard Worker // size in size_t. If size is over SIZE_MAX, mapMemory could succeed
103*8222fbe1SAndroid Build Coastguard Worker // but the mapped memory's actual size will be smaller than the reported size.
104*8222fbe1SAndroid Build Coastguard Worker if (memory.size() > SIZE_MAX) {
105*8222fbe1SAndroid Build Coastguard Worker LOG(ERROR) << "Cannot map " << memory.size() << " bytes of memory because it is too large.";
106*8222fbe1SAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, "79376389");
107*8222fbe1SAndroid Build Coastguard Worker return nullptr;
108*8222fbe1SAndroid Build Coastguard Worker }
109*8222fbe1SAndroid Build Coastguard Worker
110*8222fbe1SAndroid Build Coastguard Worker Return<sp<IMemory>> ret = mapper->mapMemory(memory);
111*8222fbe1SAndroid Build Coastguard Worker
112*8222fbe1SAndroid Build Coastguard Worker if (!ret.isOk()) {
113*8222fbe1SAndroid Build Coastguard Worker LOG(ERROR) << "hidl_memory map returned transport error.";
114*8222fbe1SAndroid Build Coastguard Worker return nullptr;
115*8222fbe1SAndroid Build Coastguard Worker }
116*8222fbe1SAndroid Build Coastguard Worker
117*8222fbe1SAndroid Build Coastguard Worker return ret;
118*8222fbe1SAndroid Build Coastguard Worker }
119*8222fbe1SAndroid Build Coastguard Worker
120*8222fbe1SAndroid Build Coastguard Worker } // namespace hardware
121*8222fbe1SAndroid Build Coastguard Worker } // namespace android
122