1 /*
2  * Copyright 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 #include "EvsUltrasonicsArray.h"
18 
19 #include <android-base/logging.h>
20 #include <hidlmemory/mapping.h>
21 #include <log/log.h>
22 #include <time.h>
23 #include <utils/SystemClock.h>
24 #include <utils/Timers.h>
25 
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace evs {
30 namespace V1_1 {
31 namespace implementation {
32 
33 // Arbitrary limit on number of data frames allowed to be allocated
34 // Safeguards against unreasonable resource consumption and provides a testable limit
35 const unsigned int kMaximumDataFramesInFlight = 100;
36 
37 const uint32_t kMaxReadingsPerSensor = 5;
38 const uint32_t kMaxReceiversCount = 3;
39 
40 const unsigned int kSharedMemoryMaxSize =
41         kMaxReadingsPerSensor * kMaxReceiversCount * 2 * sizeof(float);
42 
43 // Target frame rate in frames per second.
44 const int kTargetFrameRate = 10;
45 
46 namespace {
47 
fillMockArrayDesc(UltrasonicsArrayDesc & arrayDesc)48 void fillMockArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
49     arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor;
50     arrayDesc.maxReceiversCount = kMaxReceiversCount;
51 
52     const int kSensorCount = 3;
53     const float kMaxRange = 4000;                // 4 metres.
54     const float kAngleOfMeasurement = 0.261799;  // 15 degrees.
55 
56     std::vector<UltrasonicSensor> sensors(kSensorCount);
57 
58     // Sensor pointing forward on left side of front bumper.
59     sensors[0].maxRange = kMaxRange;
60     sensors[0].angleOfMeasurement = kAngleOfMeasurement;
61     sensors[0].pose = {{1, 0, 0, 0}, {-1000, 2000, 200}};
62 
63     // Sensor pointing forward on center of front bumper.
64     sensors[1].maxRange = kMaxRange;
65     sensors[1].angleOfMeasurement = kAngleOfMeasurement;
66     sensors[1].pose = {{1, 0, 0, 0}, {0, 2000, 200}};
67 
68     // Sensor pointing forward on right side of front bumper.
69     sensors[2].maxRange = kMaxRange;
70     sensors[2].angleOfMeasurement = kAngleOfMeasurement;
71     sensors[2].pose = {{1, 0, 0, 0}, {1000, 2000, 200}};
72 
73     arrayDesc.sensors = sensors;
74 }
75 
76 // Struct used by SerializeWaveformData().
77 struct WaveformData {
78     uint8_t receiverId;
79     std::vector<std::pair<float, float>> readings;
80 };
81 
82 // Serializes data provided in waveformDataList to a shared memory data pointer.
83 // TODO(b/149950362): Add a common library for serialiazing and deserializing waveform data.
SerializeWaveformData(const std::vector<WaveformData> & waveformDataList,uint8_t * pData)84 void SerializeWaveformData(const std::vector<WaveformData>& waveformDataList, uint8_t* pData) {
85     for (auto& waveformData : waveformDataList) {
86         // Set Id
87         memcpy(pData, &waveformData.receiverId, sizeof(uint8_t));
88         pData += sizeof(uint8_t);
89 
90         for (auto& reading : waveformData.readings) {
91             // Set the time of flight.
92             memcpy(pData, &reading.first, sizeof(float));
93             pData += sizeof(float);
94 
95             // Set the resonance.
96             memcpy(pData, &reading.second, sizeof(float));
97             pData += sizeof(float);
98         }
99     }
100 }
101 
102 // Fills dataFrameDesc with mock data.
fillMockDataFrame(UltrasonicsDataFrameDesc & dataFrameDesc,sp<IMemory> pIMemory)103 bool fillMockDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
104     dataFrameDesc.timestampNs = elapsedRealtimeNano();
105 
106     const std::vector<uint8_t> transmittersIdList = {0};
107     dataFrameDesc.transmittersIdList = transmittersIdList;
108 
109     const std::vector<uint8_t> recvIdList = {0, 1, 2};
110     dataFrameDesc.receiversIdList = recvIdList;
111 
112     const std::vector<uint32_t> receiversReadingsCountList = {2, 2, 4};
113     dataFrameDesc.receiversReadingsCountList = receiversReadingsCountList;
114 
115     const std::vector<WaveformData> waveformDataList = {
116             {recvIdList[0], {{1000, 0.1f}, {2000, 0.8f}}},
117             {recvIdList[1], {{1000, 0.1f}, {2000, 1.0f}}},
118             {recvIdList[2], {{1000, 0.1f}, {2000, 0.2f}, {4000, 0.2f}, {5000, 0.1f}}}};
119 
120     if (pIMemory.get() == nullptr) {
121         return false;
122     }
123 
124     uint8_t* pData = (uint8_t*)((void*)pIMemory->getPointer());
125 
126     pIMemory->update();
127     SerializeWaveformData(waveformDataList, pData);
128     pIMemory->commit();
129 
130     return true;
131 }
132 
133 }  // namespace
134 
EvsUltrasonicsArray(const char * deviceName)135 EvsUltrasonicsArray::EvsUltrasonicsArray(const char* deviceName)
136     : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) {
137     LOG(DEBUG) << "EvsUltrasonicsArray instantiated";
138 
139     // Set up mock data for description.
140     mArrayDesc.ultrasonicsArrayId = deviceName;
141     fillMockArrayDesc(mArrayDesc);
142 
143     // Assign allocator.
144     mShmemAllocator = IAllocator::getService("ashmem");
145     if (mShmemAllocator.get() == nullptr) {
146         LOG(ERROR) << "SurroundViewHidlTest getService ashmem failed";
147     }
148 }
149 
Create(const char * deviceName)150 sp<EvsUltrasonicsArray> EvsUltrasonicsArray::Create(const char* deviceName) {
151     return sp<EvsUltrasonicsArray>(new EvsUltrasonicsArray(deviceName));
152 }
153 
~EvsUltrasonicsArray()154 EvsUltrasonicsArray::~EvsUltrasonicsArray() {
155     LOG(DEBUG) << "EvsUltrasonicsArray being destroyed";
156     forceShutdown();
157 }
158 
159 // This gets called if another caller "steals" ownership of the ultrasonic array.
forceShutdown()160 void EvsUltrasonicsArray::forceShutdown() {
161     LOG(DEBUG) << "EvsUltrasonicsArray forceShutdown";
162 
163     // Make sure our output stream is cleaned up
164     // (It really should be already)
165     stopStream();
166 
167     // Claim the lock while we work on internal state
168     std::lock_guard<std::mutex> lock(mAccessLock);
169 
170     // Drop all the data frames we've been using
171     for (auto&& dataFrame : mDataFrames) {
172         if (dataFrame.inUse) {
173             LOG(ERROR) << "Error - releasing data frame despite remote ownership";
174         }
175         dataFrame.sharedMemory.clear();
176     }
177     mDataFrames.clear();
178 
179     // Put this object into an unrecoverable error state since somebody else
180     // is going to own the underlying ultrasonic array now
181     mStreamState = DEAD;
182 }
183 
GetMockArrayDesc(const char * deviceName)184 UltrasonicsArrayDesc EvsUltrasonicsArray::GetMockArrayDesc(const char* deviceName) {
185     UltrasonicsArrayDesc ultrasonicsArrayDesc;
186     ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName;
187     fillMockArrayDesc(ultrasonicsArrayDesc);
188     return ultrasonicsArrayDesc;
189 }
190 
getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb)191 Return<void> EvsUltrasonicsArray::getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb) {
192     LOG(DEBUG) << "EvsUltrasonicsArray getUltrasonicsArrayInfo";
193 
194     // Return the description for the get info callback.
195     _get_info_cb(mArrayDesc);
196 
197     return Void();
198 }
199 
setMaxFramesInFlight(uint32_t bufferCount)200 Return<EvsResult> EvsUltrasonicsArray::setMaxFramesInFlight(uint32_t bufferCount) {
201     LOG(DEBUG) << "EvsUltrasonicsArray setMaxFramesInFlight";
202 
203     // Lock mutex for performing changes to available frames.
204     std::lock_guard<std::mutex> lock(mAccessLock);
205 
206     // We cannot function without at least one buffer to send data.
207     if (bufferCount < 1) {
208         LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested";
209         return EvsResult::INVALID_ARG;
210     }
211 
212     // Update our internal state of buffer count.
213     if (setAvailableFrames_Locked(bufferCount)) {
214         return EvsResult::OK;
215     } else {
216         return EvsResult::BUFFER_NOT_AVAILABLE;
217     }
218 
219     return EvsResult::OK;
220 }
221 
doneWithDataFrame(const UltrasonicsDataFrameDesc & dataFrameDesc)222 Return<void> EvsUltrasonicsArray::doneWithDataFrame(const UltrasonicsDataFrameDesc& dataFrameDesc) {
223     LOG(DEBUG) << "EvsUltrasonicsArray doneWithFrame";
224 
225     std::lock_guard<std::mutex> lock(mAccessLock);
226 
227     if (dataFrameDesc.dataFrameId >= mDataFrames.size()) {
228         LOG(ERROR) << "ignoring doneWithFrame called with invalid dataFrameId "
229                    << dataFrameDesc.dataFrameId << "(max is " << mDataFrames.size() - 1 << ")";
230         return Void();
231     }
232 
233     if (!mDataFrames[dataFrameDesc.dataFrameId].inUse) {
234         LOG(ERROR) << "ignoring doneWithFrame called on frame " << dataFrameDesc.dataFrameId
235                    << "which is already free";
236         return Void();
237     }
238 
239     // Mark the frame as available
240     mDataFrames[dataFrameDesc.dataFrameId].inUse = false;
241     mFramesInUse--;
242 
243     // If this frame's index is high in the array, try to move it down
244     // to improve locality after mFramesAllowed has been reduced.
245     if (dataFrameDesc.dataFrameId >= mFramesAllowed) {
246         // Find an empty slot lower in the array (which should always exist in this case)
247         for (auto&& dataFrame : mDataFrames) {
248             if (!dataFrame.sharedMemory.IsValid()) {
249                 dataFrame.sharedMemory = mDataFrames[dataFrameDesc.dataFrameId].sharedMemory;
250                 mDataFrames[dataFrameDesc.dataFrameId].sharedMemory.clear();
251                 return Void();
252             }
253         }
254     }
255 
256     return Void();
257 }
258 
startStream(const::android::sp<IEvsUltrasonicsArrayStream> & stream)259 Return<EvsResult> EvsUltrasonicsArray::startStream(
260         const ::android::sp<IEvsUltrasonicsArrayStream>& stream) {
261     LOG(DEBUG) << "EvsUltrasonicsArray startStream";
262 
263     std::lock_guard<std::mutex> lock(mAccessLock);
264 
265     if (mStreamState != STOPPED) {
266         LOG(ERROR) << "ignoring startStream call when a stream is already running.";
267         return EvsResult::STREAM_ALREADY_RUNNING;
268     }
269 
270     // If the client never indicated otherwise, configure ourselves for a single streaming buffer
271     if (mFramesAllowed < 1) {
272         if (!setAvailableFrames_Locked(1)) {
273             LOG(ERROR)
274                     << "Failed to start stream because we couldn't get shared memory data buffer";
275             return EvsResult::BUFFER_NOT_AVAILABLE;
276         }
277     }
278 
279     // Record the user's callback for use when we have a frame ready
280     mStream = stream;
281 
282     // Start the frame generation thread
283     mStreamState = RUNNING;
284     mCaptureThread = std::thread([this]() { generateDataFrames(); });
285 
286     return EvsResult::OK;
287 }
288 
stopStream()289 Return<void> EvsUltrasonicsArray::stopStream() {
290     LOG(DEBUG) << "EvsUltrasonicsArray stopStream";
291 
292     bool streamStateStopping = false;
293     {
294         std::lock_guard<std::mutex> lock(mAccessLock);
295         if (mStreamState == RUNNING) {
296             // Tell the GenerateFrames loop we want it to stop
297             mStreamState = STOPPING;
298             streamStateStopping = true;
299         }
300     }
301 
302     if (streamStateStopping) {
303         // Block outside the mutex until the "stop" flag has been acknowledged
304         // We won't send any more frames, but the client might still get some already in flight
305         LOG(DEBUG) << "Waiting for stream thread to end...";
306         mCaptureThread.join();
307     }
308 
309     {
310         std::lock_guard<std::mutex> lock(mAccessLock);
311         mStreamState = STOPPED;
312         mStream = nullptr;
313         LOG(DEBUG) << "Stream marked STOPPED.";
314     }
315 
316     return Void();
317 }
318 
setAvailableFrames_Locked(unsigned bufferCount)319 bool EvsUltrasonicsArray::setAvailableFrames_Locked(unsigned bufferCount) {
320     if (bufferCount < 1) {
321         LOG(ERROR) << "Ignoring request to set buffer count to zero";
322         return false;
323     }
324     if (bufferCount > kMaximumDataFramesInFlight) {
325         LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
326         return false;
327     }
328 
329     // Is an increase required?
330     if (mFramesAllowed < bufferCount) {
331         // An increase is required
332         unsigned needed = bufferCount - mFramesAllowed;
333         LOG(INFO) << "Number of data frame buffers to add: " << needed;
334 
335         unsigned added = increaseAvailableFrames_Locked(needed);
336         if (added != needed) {
337             // If we didn't add all the frames we needed, then roll back to the previous state
338             LOG(ERROR) << "Rolling back to previous frame queue size";
339             decreaseAvailableFrames_Locked(added);
340             return false;
341         }
342     } else if (mFramesAllowed > bufferCount) {
343         // A decrease is required
344         unsigned framesToRelease = mFramesAllowed - bufferCount;
345         LOG(INFO) << "Number of data frame buffers to reduce: " << framesToRelease;
346 
347         unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
348         if (released != framesToRelease) {
349             // This shouldn't happen with a properly behaving client because the client
350             // should only make this call after returning sufficient outstanding buffers
351             // to allow a clean resize.
352             LOG(ERROR) << "Buffer queue shrink failed -- too many buffers currently in use?";
353         }
354     }
355 
356     return true;
357 }
358 
allocateAndMapSharedMemory()359 EvsUltrasonicsArray::SharedMemory EvsUltrasonicsArray::allocateAndMapSharedMemory() {
360     SharedMemory sharedMemory;
361 
362     // Check shared memory allocator is valid.
363     if (mShmemAllocator.get() == nullptr) {
364         LOG(ERROR) << "Shared memory allocator not initialized.";
365         return SharedMemory();
366     }
367 
368     // Allocate memory.
369     bool allocateSuccess = false;
370     Return<void> result = mShmemAllocator->allocate(kSharedMemoryMaxSize,
371                                                     [&](bool success, const hidl_memory& hidlMem) {
372                                                         if (!success) {
373                                                             return;
374                                                         }
375                                                         allocateSuccess = success;
376                                                         sharedMemory.hidlMemory = hidlMem;
377                                                     });
378 
379     // Check result of allocated memory.
380     if (!result.isOk() || !allocateSuccess) {
381         LOG(ERROR) << "Shared memory allocation failed.";
382         return SharedMemory();
383     }
384 
385     // Map shared memory.
386     sharedMemory.pIMemory = mapMemory(sharedMemory.hidlMemory);
387     if (sharedMemory.pIMemory.get() == nullptr) {
388         LOG(ERROR) << "Shared memory mapping failed.";
389         return SharedMemory();
390     }
391 
392     // Return success.
393     return sharedMemory;
394 }
395 
increaseAvailableFrames_Locked(unsigned numToAdd)396 unsigned EvsUltrasonicsArray::increaseAvailableFrames_Locked(unsigned numToAdd) {
397     unsigned added = 0;
398 
399     while (added < numToAdd) {
400         SharedMemory sharedMemory = allocateAndMapSharedMemory();
401 
402         // If allocate and map fails, break.
403         if (!sharedMemory.IsValid()) {
404             break;
405         }
406 
407         // Find a place to store the new buffer
408         bool stored = false;
409         for (auto&& dataFrame : mDataFrames) {
410             if (!dataFrame.sharedMemory.IsValid()) {
411                 // Use this existing entry
412                 dataFrame.sharedMemory = sharedMemory;
413                 dataFrame.inUse = false;
414                 stored = true;
415                 break;
416             }
417         }
418 
419         if (!stored) {
420             // Add a BufferRecord wrapping this handle to our set of available buffers
421             mDataFrames.emplace_back(sharedMemory);
422         }
423 
424         mFramesAllowed++;
425         added++;
426     }
427 
428     return added;
429 }
430 
decreaseAvailableFrames_Locked(unsigned numToRemove)431 unsigned EvsUltrasonicsArray::decreaseAvailableFrames_Locked(unsigned numToRemove) {
432     unsigned removed = 0;
433 
434     for (auto&& dataFrame : mDataFrames) {
435         // Is this record not in use, but holding a buffer that we can free?
436         if (!dataFrame.inUse && dataFrame.sharedMemory.IsValid()) {
437             // Release buffer and update the record so we can recognize it as "empty"
438             dataFrame.sharedMemory.clear();
439 
440             mFramesAllowed--;
441             removed++;
442 
443             if (removed == numToRemove) {
444                 break;
445             }
446         }
447     }
448 
449     return removed;
450 }
451 
452 // This is the asynchronous data frame generation thread that runs in parallel with the
453 // main serving thread. There is one for each active ultrasonic array instance.
generateDataFrames()454 void EvsUltrasonicsArray::generateDataFrames() {
455     LOG(DEBUG) << "Data frame generation loop started";
456 
457     unsigned idx = 0;
458 
459     while (true) {
460         bool timeForFrame = false;
461 
462         nsecs_t startTime = elapsedRealtimeNano();
463 
464         // Lock scope for updating shared state
465         {
466             std::lock_guard<std::mutex> lock(mAccessLock);
467 
468             if (mStreamState != RUNNING) {
469                 // Break out of our main thread loop
470                 break;
471             }
472 
473             // Are we allowed to issue another buffer?
474             if (mFramesInUse >= mFramesAllowed) {
475                 // Can't do anything right now -- skip this frame
476                 LOG(WARNING) << "Skipped a frame because too many are in flight";
477             } else {
478                 // Identify an available buffer to fill
479                 for (idx = 0; idx < mDataFrames.size(); idx++) {
480                     if (!mDataFrames[idx].inUse && mDataFrames[idx].sharedMemory.IsValid()) {
481                         // Found an available record, so stop looking
482                         break;
483                     }
484                 }
485                 if (idx >= mDataFrames.size()) {
486                     // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
487                     LOG(ERROR) << "Failed to find an available buffer slot";
488                 } else {
489                     // We're going to make the frame busy
490                     mDataFrames[idx].inUse = true;
491                     mFramesInUse++;
492                     timeForFrame = true;
493                 }
494             }
495         }
496 
497         if (timeForFrame) {
498             // Assemble the buffer description we'll transmit below
499             UltrasonicsDataFrameDesc mockDataFrameDesc;
500             mockDataFrameDesc.dataFrameId = idx;
501             mockDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
502 
503             // Fill mock waveform data.
504             fillMockDataFrame(mockDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
505 
506             // Issue the (asynchronous) callback to the client -- can't be holding the lock
507             auto result = mStream->deliverDataFrame(mockDataFrameDesc);
508             if (result.isOk()) {
509                 LOG(DEBUG) << "Delivered data frame id: " << mockDataFrameDesc.dataFrameId;
510             } else {
511                 // This can happen if the client dies and is likely unrecoverable.
512                 // To avoid consuming resources generating failing calls, we stop sending
513                 // frames.  Note, however, that the stream remains in the "STREAMING" state
514                 // until cleaned up on the main thread.
515                 LOG(ERROR) << "Frame delivery call failed in the transport layer.";
516 
517                 // Since we didn't actually deliver it, mark the frame as available
518                 std::lock_guard<std::mutex> lock(mAccessLock);
519                 mDataFrames[idx].inUse = false;
520                 mFramesInUse--;
521 
522                 break;
523             }
524         }
525 
526         // Sleep to generate frames at kTargetFrameRate.
527         static const nsecs_t kTargetFrameTimeUs = 1000 * 1000 / kTargetFrameRate;
528         const nsecs_t now = elapsedRealtimeNano();
529         const nsecs_t workTimeUs = (now - startTime) / 1000;
530         const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
531         if (sleepDurationUs > 0) {
532             usleep(sleepDurationUs);
533         }
534     }
535 
536     // If we've been asked to stop, send an event to signal the actual end of stream
537     EvsEventDesc event;
538     event.aType = EvsEventType::STREAM_STOPPED;
539     auto result = mStream->notify(event);
540     if (!result.isOk()) {
541         LOG(ERROR) << "Error delivering end of stream marker";
542     }
543 }
544 
545 }  // namespace implementation
546 }  // namespace V1_1
547 }  // namespace evs
548 }  // namespace automotive
549 }  // namespace hardware
550 }  // namespace android
551