• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #pragma once
18 
19 #include <BufferAllocator/dmabufheap-defs.h>
20 
21 #include <android-base/unique_fd.h>
22 #include <linux/ion_4.12.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 
28 #include <cstdint>
29 #include <shared_mutex>
30 #include <string>
31 #include <unordered_map>
32 #include <unordered_set>
33 #include <vector>
34 
35 
36 class BufferAllocator {
37   public:
38     BufferAllocator();
~BufferAllocator()39     ~BufferAllocator() {}
40 
41     /* Not copyable or movable */
42     BufferAllocator(const BufferAllocator&) = delete;
43     BufferAllocator& operator=(const BufferAllocator&) = delete;
44 
45     /**
46      * Maps a dmabuf heap to an equivalent ion heap configuration. This method is required since
47      * dmabuf heaps do not support heap flags. This means that a single ion heap may encompass the
48      * functionality of multiple dmabuf heaps by using heap flags. If the interface being used is
49      * non-legacy ion, the mapping from dmabuf heap name to non-legacy ion heap name will be created
50      * and the legacy parameters will be ignored.
51      * The method can be deprecated once all devices have
52      * migrated to dmabuf heaps from ion. Returns an error code when the
53      * interface used is non-legacy ion and the @ion_heap_name parameter is non-empty and
54      * invalid or if the interface used is legacy ion and @legacy_ion_heap_mask
55      * is invalid(0);
56      * @heap_name: dmabuf heap name.
57      * @ion_heap_name: name of the equivalent ion heap - if empty ("") legacy heap mask will be used
58      * @ion_heap_flags: flags to be passed to the ion heap @ion_heap_name for it to function
59      * equivalently to the dmabuf heap @heap_name. Ignored if ion_heap_name is empty("").
60      * @legacy_ion_heap_mask: heap mask for the equivalent legacy ion heap.
61      * @legacy_ion_heap_flags: flags to be passed to the legacy ion heap for it
62      * to function equivalently to dmabuf heap @heap_name.
63      */
64     int MapNameToIonHeap(const std::string& heap_name, const std::string& ion_heap_name,
65                          unsigned int ion_heap_flags = 0, unsigned int legacy_ion_heap_mask = 0,
66                          unsigned int legacy_ion_heap_flags = 0);
67 
68     /* *
69      * Returns a dmabuf fd if the allocation in one of the specified heaps is successful and
70      * an error code otherwise. If dmabuf heaps are supported, tries to allocate in the
71      * specified dmabuf heap. If allocation fails in the specified dmabuf heap and ion_fd is a
72      * valid fd, goes through saved heap data to find a heap ID/mask to match the specified heap
73      * names and allocates memory as per the specified parameters. For vendor defined heaps with a
74      * legacy ION interface(no heap query support), MapNameToIonMask() must be called prior to
75      * invocation of Alloc() to map a heap name to an equivalent heap mask and heap flag
76      * configuration.
77      * @heap_name: name of the heap to allocate in.
78      * @len: size of the allocation.
79      * @heap_flags: flags passed to heap.
80      * @legacy_align: alignment value used only by legacy ION
81      */
82     int Alloc(const std::string& heap_name, size_t len, unsigned int heap_flags = 0, size_t legacy_align = 0);
83 
84     /* *
85      * Returns a dmabuf fd if the allocation in system heap(cached/uncached) is successful and
86      * an error code otherwise. Allocates in the 'system' heap if CPU access of
87      * the buffer is expected and 'system-uncached' otherwise. If the 'system-uncached'
88      * heap is not supported, falls back to the 'system' heap.
89      * For vendor defined heaps with a legacy ION interface(no heap query support),
90      * MapNameToIonMask() must be called prior to invocation of AllocSystem() to
91      * map names 'system'(and optionally 'system-uncached' if applicable) to an
92      * equivalent heap mask and heap flag configuration;
93      * configuration.
94      * @cpu_access: indicates if CPU access of the buffer is expected.
95      * @len: size of the allocation.
96      * @heap_flags: flags passed to heap.
97      * @legacy_align: alignment value used only by legacy ION
98      */
99     int AllocSystem(bool cpu_access, size_t len, unsigned int heap_flags = 0,
100                     size_t legacy_align = 0);
101 
102     /**
103      * Optional custom callback for legacy ion implementation that can be specified as a
104      * parameter to CpuSyncStart() and CpuSyncEnd(). Its first argument is an fd to /dev/ion.
105      * The callback MUST NOT assume ownership of the fd.  The fd will be closed once the
106      * callback returns.  The second argument is a dma_buf fd, upon which the custom sync IOCTL
107      * should be called.  The third argument is a void pointer that can be used to pass data
108      * to be used in the IOCTL.
109      * If provided as an argument to CpuSyncStart() and CpuSyncEnd(), the callback will be used
110      * for syncing a shared dmabuf fd with memory(instead of ion_sync_fd()). It will be invoked
111      * with a dup of ion_fd_ as its first argument. Return 0 on success and error code otherwise
112      * which will become the return value for CpuSyncStart() and CpuSyncEnd().
113      */
114     typedef std::function<int(int, int, void *)> CustomCpuSyncLegacyIon;
115 
116     /**
117      * Must be invoked before CPU access of the allocated memory.
118      * For a legacy ion interface, syncs a shared dmabuf fd with memory either using
119      * ION_IOC_SYNC ioctl or using callback @legacy_ion_cpu_sync if specified. For
120      * non-legacy ION and dmabuf heap interfaces, DMA_BUF_IOCTL_SYNC is used.
121      * @fd: dmabuf fd. When the legacy version of ion is in use and a callback
122      * function is supplied, this is passed as the second argument to legacy_ion_cpu_sync.
123      * @sync_type: specifies if the sync is for read, write or read/write.
124      * @legacy_ion_cpu_sync: optional callback for legacy ion interfaces. If
125      * specified, will be invoked instead of ion_sync_fd()
126      * to sync dmabuf_fd with memory. The paremeter will be ignored if the interface being
127      * used is not legacy ion.
128      * @legacy_ion_custom_data: When the legacy version of ion is in use and a callback
129      * function is supplied, this pointer is passed as the third argument to
130      * legacy_ion_cpu_sync. It is intended to point to data for performing the callback.
131      *
132      * Returns 0  on success and an error code otherwise.
133      */
134     int CpuSyncStart(unsigned int dmabuf_fd, SyncType sync_type = kSyncRead,
135                      const CustomCpuSyncLegacyIon& legacy_ion_cpu_sync = nullptr,
136                      void *legacy_ion_custom_data = nullptr);
137 
138     /**
139      * Must be invoked once CPU is done accessing the allocated memory.
140      * For a legacy ion interface, syncs a shared dmabuf fd with memory using
141      * either ION_IOC_SYNC ioctl or using callback @legacy_ion_cpu_sync if
142      * specified. For non-legacy ION and dmabuf heap interfaces,
143      * DMA_BUF_IOCTL_SYNC is used.
144      * @dmabuf_fd: dmabuf fd. When the legacy version of ion is in use and a callback
145      * function is supplied, this is passed as the second argument to legacy_ion_cpu_sync.
146      * @sync_type: specifies if sync_type is for read, write or read/write.
147      * @legacy_ion_cpu_sync: optional callback for legacy ion interfaces. If
148      * specified, will be invoked instead of ion_sync_fd with a dup of ion_fd_ as its
149      * argument. The parameter will be ignored if the interface being used is
150      * not legacy ion.
151      * @legacy_ion_custom_data: When the legacy version of ion is in use and a callback
152      * function is supplied, this pointer is passed as the third argument to
153      * legacy_ion_cpu_sync. It is intended to point to data for performing the callback.
154      *
155      * Returns 0 on success and an error code otherwise.
156      */
157     int CpuSyncEnd(unsigned int dmabuf_fd, SyncType sync_type = kSyncRead,
158                    const CustomCpuSyncLegacyIon& legacy_ion_cpu_sync = nullptr,
159                    void* legacy_ion_custom_data = nullptr);
160 
161     /**
162      * Query supported DMA-BUF heaps.
163      *
164      * @return the list of supported DMA-BUF heap names.
165      */
166     static std::unordered_set<std::string> GetDmabufHeapList();
167 
168     /**
169      *
170      * Check if ION is supported on the device.
171      *
172      * @return true if /dev/ion is present on the device, otherwise false.
173      */
174     static bool CheckIonSupport();
175 
176   private:
177     int OpenDmabufHeap(const std::string& name);
178     void QueryIonHeaps();
179     int GetDmabufHeapFd(const std::string& name);
DmabufHeapsSupported()180     bool DmabufHeapsSupported() { return !dmabuf_heap_fds_.empty(); }
181     int GetIonHeapIdByName(const std::string& heap_name, unsigned int* heap_id);
182     int MapNameToIonMask(const std::string& heap_name, unsigned int ion_heap_mask,
183                          unsigned int ion_heap_flags = 0);
184     int MapNameToIonName(const std::string& heap_name, const std::string& ion_heap_name,
185                          unsigned int ion_heap_flags = 0);
186     void LogInterface(const std::string& interface);
187     int IonAlloc(const std::string& heap_name, size_t len, unsigned int heap_flags = 0, size_t legacy_align = 0);
188     int DmabufAlloc(const std::string& heap_name, size_t len);
189 
190     struct IonHeapConfig {
191         unsigned int mask;
192         unsigned int flags;
193     };
194     int GetIonConfig(const std::string& heap_name, IonHeapConfig& heap_config);
195     int LegacyIonCpuSync(unsigned int fd, const CustomCpuSyncLegacyIon& legacy_ion_cpu_sync_custom,
196                          void *custom_data);
197     int DoSync(unsigned int dmabuf_fd, bool start, SyncType sync_type,
198                const CustomCpuSyncLegacyIon& legacy_ion_cpu_sync_custom,
199                void *custom_data);
200 
201     /* Stores all open dmabuf_heap handles. */
202     std::unordered_map<std::string, android::base::unique_fd> dmabuf_heap_fds_;
203     /* Protects dma_buf_heap_fd_ from concurrent access */
204     std::shared_mutex dmabuf_heap_fd_mutex_;
205 
206     /* saved handle to /dev/ion. */
207     android::base::unique_fd ion_fd_;
208     /**
209      * Stores the queried ion heap data. Struct ion_heap_date is defined
210      * as part of the ION UAPI as follows.
211      * struct ion_heap_data {
212      *   char name[MAX_HEAP_NAME];
213      *    __u32 type;
214      *    __u32 heap_id;
215      *    __u32 reserved0;
216      *    __u32 reserved1;
217      *    __u32 reserved2;
218      * };
219      */
220     bool uses_legacy_ion_iface_ = false;
221     std::vector<struct ion_heap_data> ion_heap_info_;
222     inline static bool logged_interface_ = false;
223     /* stores a map of dmabuf heap names to equivalent ion heap configurations. */
224     std::unordered_map<std::string, struct IonHeapConfig> heap_name_to_config_;
225     /* protects heap_name_to_config_ from concurrent access */
226     std::shared_mutex heap_name_to_config_mutex_;
227 };
228