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