1 /*
2  * Copyright (C) 2018 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 #ifndef ANDROID_SENSORS_TEST_SHARED_MEMORY_H
18 #define ANDROID_SENSORS_TEST_SHARED_MEMORY_H
19 
20 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
21 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
22 #include <ui/GraphicBuffer.h>
23 #include <ui/GraphicBufferAllocator.h>
24 #include <ui/GraphicBufferMapper.h>
25 
26 #include <android-base/macros.h>
27 #include <log/log.h>
28 
29 #include <sys/mman.h>
30 #include <cinttypes>
31 
32 #include <cutils/ashmem.h>
33 
34 using namespace ::android::hardware::sensors::V1_0;
35 using ::aidl::android::hardware::graphics::common::BufferUsage;
36 using ::aidl::android::hardware::graphics::common::PixelFormat;
37 
38 template <class SensorTypeVersion, class EventType>
39 class SensorsTestSharedMemory {
40   public:
create(SharedMemType type,size_t size)41     static SensorsTestSharedMemory* create(SharedMemType type, size_t size) {
42         constexpr size_t kMaxSize =
43                 128 * 1024 * 1024;  // sensor test should not need more than 128M
44         if (size == 0 || size >= kMaxSize) {
45             return nullptr;
46         }
47 
48         auto m = new SensorsTestSharedMemory<SensorTypeVersion, EventType>(type, size);
49         if (m->mSize != size || m->mBuffer == nullptr) {
50             delete m;
51             m = nullptr;
52         }
53         return m;
54     }
55 
getSharedMemInfo()56     SharedMemInfo getSharedMemInfo() const {
57         if (mType == SharedMemType::GRALLOC) {
58             SharedMemInfo mem = {.type = mType,
59                                  .format = SharedMemFormat::SENSORS_EVENT,
60                                  .size = static_cast<uint32_t>(mSize),
61                                  .memoryHandle = mBufferHandle};
62             return mem;
63 
64         } else {
65             SharedMemInfo mem = {.type = mType,
66                                  .format = SharedMemFormat::SENSORS_EVENT,
67                                  .size = static_cast<uint32_t>(mSize),
68                                  .memoryHandle = mNativeHandle};
69             return mem;
70         }
71     }
getBuffer()72     char* getBuffer() const { return mBuffer; }
getSize()73     size_t getSize() const { return mSize; }
74     std::vector<EventType> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const {
75         constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
76         constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
77         constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
78         constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
79         constexpr size_t kOffsetAtomicCounter =
80                 static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
81         constexpr size_t kOffsetTimestamp =
82                 static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
83         constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
84 
85         std::vector<EventType> events;
86         std::vector<float> data(16);
87 
88         while (offset + kEventSize <= mSize) {
89             int64_t atomicCounter =
90                     *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter);
91             if (atomicCounter <= lastCounter) {
92                 ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter,
93                       lastCounter);
94                 break;
95             }
96 
97             int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize);
98             if (size != kEventSize) {
99                 // unknown error, events parsed may be wrong, remove all
100                 events.clear();
101                 break;
102             }
103 
104             int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken);
105             int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType);
106             int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp);
107 
108             ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32
109                   ", timestamp %" PRId64,
110                   offset, atomicCounter, token, type, timestamp);
111 
112             EventType event = {
113                     .timestamp = timestamp,
114                     .sensorHandle = token,
115                     .sensorType = static_cast<SensorTypeVersion>(type),
116             };
117             event.u.data = android::hardware::hidl_array<float, 16>(
118                     reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
119 
120             events.push_back(event);
121 
122             lastCounter = atomicCounter;
123             offset += kEventSize;
124         }
125 
126         return events;
127     }
128 
~SensorsTestSharedMemory()129     virtual ~SensorsTestSharedMemory() {
130         switch (mType) {
131             case SharedMemType::ASHMEM: {
132                 if (mSize != 0) {
133                     ::munmap(mBuffer, mSize);
134                     mBuffer = nullptr;
135 
136                     ::native_handle_close(mNativeHandle);
137                     ::native_handle_delete(mNativeHandle);
138 
139                     mNativeHandle = nullptr;
140                     mSize = 0;
141                 }
142                 break;
143             }
144             case SharedMemType::GRALLOC: {
145                 if (mSize != 0) {
146                     android::status_t status =
147                             android::GraphicBufferAllocator::get().free(mBufferHandle);
148                     if (status != android::OK) {
149                         ALOGE("SensorsAidlTestSharedMemory Gralloc failed to free buffer. Status: "
150                               "%s",
151                               android::statusToString(status).c_str());
152                     }
153                     mBufferHandle = nullptr;
154                     mBuffer = nullptr;
155                     mSize = 0;
156                 }
157                 break;
158             }
159             default: {
160                 if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr ||
161                     mBufferHandle != nullptr) {
162                     ALOGE("SensorsAidlTestSharedMemory %p not properly destructed: "
163                           "type %d, native handle %p, size %zu, buffer %p, buffer handle %p",
164                           this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer,
165                           mBufferHandle);
166                 }
167                 break;
168             }
169         }
170     }
171 
172   private:
SensorsTestSharedMemory(SharedMemType type,size_t size)173     SensorsTestSharedMemory(SharedMemType type, size_t size)
174         : mType(type), mSize(0), mBuffer(nullptr) {
175         native_handle_t* handle = nullptr;
176         char* buffer = nullptr;
177         switch (type) {
178             case SharedMemType::ASHMEM: {
179                 int fd;
180                 handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/);
181                 if (handle != nullptr) {
182                     handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
183                     if (handle->data[0] > 0) {
184                         // memory is pinned by default
185                         buffer = static_cast<char*>(
186                                 ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
187                         if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
188                             break;
189                         }
190                         ::native_handle_close(handle);
191                     }
192                     ::native_handle_delete(handle);
193                     handle = nullptr;
194                 }
195                 break;
196             }
197             case SharedMemType::GRALLOC: {
198                 static constexpr uint64_t kBufferUsage =
199                         static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA) |
200                         static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN) |
201                         static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY);
202 
203                 uint32_t stride = 0;
204                 buffer_handle_t bufferHandle;
205                 android::status_t status = android::GraphicBufferAllocator::get().allocate(
206                         size, 1, static_cast<int>(PixelFormat::BLOB), 1, kBufferUsage,
207                         &bufferHandle, &stride, "SensorVts");
208                 if (status != android::OK) {
209                     ALOGE("SensorsAidlTestSharedMemory failed to allocate memory. Status: %s",
210                           android::statusToString(status).c_str());
211                     break;
212                 }
213                 // Per the HAL, all-zeros Rect means the entire buffer
214                 android::Rect rect = {0, 0, 0, 0};
215                 void* ret;
216                 status = android::GraphicBufferMapper::get().lock(bufferHandle, kBufferUsage, rect,
217                                                                   &ret);
218                 if (status != android::OK) {
219                     ALOGE("SensorsAidlTestSharedMemory failed to import buffer: Status: %s",
220                           android::statusToString(status).c_str());
221                 } else {
222                     buffer = static_cast<char*>(ret);
223                     mBufferHandle = bufferHandle;
224                 }
225                 break;
226             }
227             default:
228                 break;
229         }
230 
231         if (buffer != nullptr) {
232             mNativeHandle = handle;
233             mSize = size;
234             mBuffer = buffer;
235         }
236     }
237 
238     SharedMemType mType;
239     native_handle_t* mNativeHandle;
240     buffer_handle_t mBufferHandle;
241     size_t mSize;
242     char* mBuffer;
243 
244     DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
245 };
246 
247 #endif  // ANDROID_SENSORS_TEST_SHARED_MEMORY_H
248