xref: /aosp_15_r20/system/libhidl/libhidlmemory/mapping.cpp (revision 8222fbe171c3d6fadfe95119c180cf3010c392a8)
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