1 /*
2 * Copyright (C) 2022 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 "direct_channel_buffer_reader.h"
18
19 #include <android-base/logging.h>
20 #include <hardware/sensors.h>
21
22 namespace {
23
24 // DirectChannelBufferReader::Read() keeps reading until it catches up with the
25 // write head. To avoid infinite reads in case of corrupted buffer, put an upper
26 // bound on number of reads. Read() would read at most
27 // <kMaxReadRounds * buffer_size_samples> samples.
28 constexpr int kMaxReadRounds = 2;
29
30 } // namespace
31
DirectChannelBufferReader(const sensors_event_t * direct_channel_buffer,int buffer_size_samples)32 DirectChannelBufferReader::DirectChannelBufferReader(const sensors_event_t* direct_channel_buffer,
33 int buffer_size_samples)
34 : direct_channel_buffer_(direct_channel_buffer), buffer_size_samples_(buffer_size_samples) {}
35
Read(int * num_samples_skipped)36 int DirectChannelBufferReader::Read(int* num_samples_skipped) {
37 int num_samples_read = 0;
38 int64_t last_atomic_counter_before_read = last_atomic_counter_;
39 // Keep reading samples until reaching the write head.
40 // Example: 1 2 3 4 0
41 // ^
42 // head
43 //
44 // Example: 11 12 13 14 5 6 7 8 9 10
45 // ^
46 // head
47 //
48 // Example: UINT32_MAX-1 UINT32_MAX 1 UINT32_MAX-3 UINT32_MAX-2
49 // ^
50 // head
51 //
52 // Here is a more interesting corner case:
53 // 1 2 <- samples obtained in previous calls to Read()
54 // 1 2 3
55 // ^
56 // Got a new sample. Keep reading.
57 //
58 // 1 2 3 14 15 16 7
59 // -------- ^
60 // Reached the head but only got 3 samples with
61 // consecutive counter values. Sample 3 may be
62 // corrupted so it should be discarded. Also we
63 // are still missing sample 8-13. Keep reading.
64 //
65 // 1 2 3 14 15 16 7 8 9 10 (Got 8-10. Keep reading)
66 //
67 // 11 12 13 14 15 16 7 8 9 10
68 // ^
69 // Reached the head and got all 10 consecutive
70 // samples. Stop reading. Sample 3 was discarded
71 // when buffer_ was truncated.
72 while (true) {
73 buffer_.push_back(ReadOneSample(index_));
74 num_samples_read++;
75 int64_t atomic_counter = static_cast<uint32_t>(buffer_.back().reserved0);
76 bool reached_zero_counter_head = atomic_counter == 0;
77 bool reached_regular_head =
78 atomic_counter ==
79 ((last_atomic_counter_ + UINT32_MAX - buffer_size_samples_) % UINT32_MAX) + 1;
80 bool has_enough_consecutive_samples = streak_ >= buffer_size_samples_;
81 if (reached_zero_counter_head || (reached_regular_head && has_enough_consecutive_samples)) {
82 buffer_.pop_back();
83 num_samples_read--;
84 // At this point the samples in <buffer_> are guaranteed to be free
85 // of corruption from data race. Here's the proof.
86 // Case 1: reached_zero_counter_head = true. The writer has not
87 // started overwriting any samples so all samples that have been
88 // read so far are valid.
89 // Case 2: reached_regular_head = true. E.g. suppose
90 // last_atomic_counter_ = 15 and buffer_size_samples_ = 10, now
91 // buffer_ would be [7, 8, 9, 10, 11, 12, 13, 14, 15]. The fact that we just
92 // saw a counter value of 6 means the writer has not start
93 // overwriting samples 7-15 yet. Therefore these samples are all
94 // valid.
95 break;
96 }
97 if (atomic_counter != (last_atomic_counter_ % UINT32_MAX) + 1) {
98 streak_ = 0;
99 }
100 streak_++;
101 last_atomic_counter_ = atomic_counter;
102 index_ = (index_ + 1) % buffer_size_samples_;
103 TruncateBuffer();
104 if (num_samples_read > kMaxReadRounds * buffer_size_samples_) {
105 buffer_.clear();
106 return kErrorHeadOfBufferNotFound;
107 }
108 }
109 num_samples_read = std::min(num_samples_read, buffer_size_samples_ - 1);
110 if (num_samples_skipped != nullptr) {
111 *num_samples_skipped =
112 last_atomic_counter_ - last_atomic_counter_before_read - num_samples_read;
113 }
114 return num_samples_read;
115 }
116
ReadOneSample(int index)117 const sensors_event_t DirectChannelBufferReader::ReadOneSample(int index) {
118 sensors_event_t event;
119 // reserved0 is the atomic counter and should be read first.
120 event.reserved0 = direct_channel_buffer_[index].reserved0;
121 event.version = direct_channel_buffer_[index].version;
122 event.sensor = direct_channel_buffer_[index].sensor;
123 event.type = direct_channel_buffer_[index].type;
124 event.timestamp = direct_channel_buffer_[index].timestamp;
125 event.u64.data[0] = direct_channel_buffer_[index].u64.data[0];
126 event.u64.data[1] = direct_channel_buffer_[index].u64.data[1];
127 event.u64.data[2] = direct_channel_buffer_[index].u64.data[2];
128 event.u64.data[3] = direct_channel_buffer_[index].u64.data[3];
129 event.u64.data[4] = direct_channel_buffer_[index].u64.data[4];
130 event.u64.data[5] = direct_channel_buffer_[index].u64.data[5];
131 event.u64.data[6] = direct_channel_buffer_[index].u64.data[6];
132 event.u64.data[7] = direct_channel_buffer_[index].u64.data[7];
133 return event;
134 }
135
TruncateBuffer()136 void DirectChannelBufferReader::TruncateBuffer() {
137 while (buffer_.size() > buffer_size_samples_ - 1) {
138 buffer_.pop_front();
139 }
140 }
141