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