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 "thermal_predictions_helper.h"
18 
19 #include <android-base/logging.h>
20 #include <android/binder_manager.h>
21 
22 #include <algorithm>
23 #include <numeric>
24 #include <string_view>
25 
26 namespace aidl {
27 namespace android {
28 namespace hardware {
29 namespace thermal {
30 namespace implementation {
31 
registerPredictorSensor(std::string_view sensor_name,int sample_duration,int num_out_samples)32 bool ThermalPredictionsHelper::registerPredictorSensor(std::string_view sensor_name,
33                                                        int sample_duration, int num_out_samples) {
34     if (sample_duration <= 0 || num_out_samples <= 0) {
35         LOG(ERROR) << "Invalid sample_duration: " << sample_duration
36                    << " or num_out_samples: " << num_out_samples << " for sensor: " << sensor_name;
37         return false;
38     }
39 
40     if (predictor_sensors_.count(sensor_name.data())) {
41         LOG(ERROR) << "sensor_name " << sensor_name << " is already registered as predictor";
42         return false;
43     }
44 
45     predictor_sensors_[sensor_name.data()] = PredictorSensorInfo(
46             {std::string(sensor_name), sample_duration, num_out_samples,
47              std::vector<PredictionSample>(num_out_samples, PredictionSample(num_out_samples)), 0});
48     return true;
49 }
50 
registerPredictedSensor(std::string_view sensor_name,std::string_view linked_sensor,int duration)51 bool ThermalPredictionsHelper::registerPredictedSensor(std::string_view sensor_name,
52                                                        std::string_view linked_sensor,
53                                                        int duration) {
54     if (duration < 0) {
55         LOG(ERROR) << "Invalid duration: " << duration << " for sensor: " << sensor_name;
56         return false;
57     }
58 
59     if (predicted_sensors_.count(sensor_name.data())) {
60         LOG(ERROR) << "sensor_name " << sensor_name << " is already registered as predicted sensor";
61         return false;
62     }
63 
64     if (predictor_sensors_.count(linked_sensor.data()) == 0) {
65         LOG(ERROR) << "linked_sensor_name " << linked_sensor << " is not registered as predictor";
66         return false;
67     }
68 
69     PredictorSensorInfo &predictor_sensor_info = predictor_sensors_[linked_sensor.data()];
70     const int max_prediction_duration =
71             (predictor_sensor_info.num_out_samples - 1) * predictor_sensor_info.sample_duration;
72 
73     if (duration > max_prediction_duration) {
74         LOG(ERROR) << "Predicted sensor " << sensor_name
75                    << " duration is greater than max prediction duration of predictor "
76                    << linked_sensor << " which is " << max_prediction_duration;
77         return false;
78     }
79 
80     // round up to nearest lower index
81     const int prediction_index = duration / predictor_sensor_info.sample_duration;
82     if (duration % predictor_sensor_info.sample_duration != 0) {
83         LOG(INFO) << "Predicted sensor " << sensor_name << " duration " << duration
84                   << " is not a multiple of " << linked_sensor << " sample duration "
85                   << predictor_sensor_info.sample_duration << " and hence updated to "
86                   << prediction_index * predictor_sensor_info.sample_duration;
87     }
88 
89     predicted_sensors_[sensor_name.data()] = PredictedSensorInfo(
90             {std::string(sensor_name), std::string(linked_sensor), duration, prediction_index});
91     return true;
92 }
93 
updateSensor(std::string_view sensor_name,std::vector<float> & values)94 bool ThermalPredictionsHelper::updateSensor(std::string_view sensor_name,
95                                             std::vector<float> &values) {
96     std::unique_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
97     const auto sensor_itr = predictor_sensors_.find(sensor_name.data());
98     if (sensor_itr == predictor_sensors_.end()) {
99         LOG(ERROR) << "sensor_name " << sensor_name << " is not registered as predictor";
100         return false;
101     }
102 
103     PredictorSensorInfo &predictor_sensor_info = predictor_sensors_[sensor_name.data()];
104     if (values.size() != static_cast<size_t>(predictor_sensor_info.num_out_samples)) {
105         LOG(ERROR) << "Invalid number of values: " << values.size()
106                    << " for sensor: " << sensor_name
107                    << ", expected: " << predictor_sensor_info.num_out_samples;
108         return false;
109     }
110 
111     predictor_sensor_info.samples[predictor_sensor_info.cur_index].timestamp = boot_clock::now();
112     predictor_sensor_info.samples[predictor_sensor_info.cur_index].values = values;
113     predictor_sensor_info.cur_index++;
114     predictor_sensor_info.cur_index %= predictor_sensor_info.num_out_samples;
115 
116     return true;
117 }
118 
readSensor(std::string_view sensor_name,float * temp)119 SensorReadStatus ThermalPredictionsHelper::readSensor(std::string_view sensor_name, float *temp) {
120     std::shared_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
121     const auto sensor_itr = predicted_sensors_.find(sensor_name.data());
122     if (sensor_itr == predicted_sensors_.end()) {
123         LOG(ERROR) << "sensor_name " << sensor_name << " is not registered as predicted sensor";
124         return SensorReadStatus::ERROR;
125     }
126 
127     PredictedSensorInfo &predicted_sensor_info = predicted_sensors_[sensor_name.data()];
128     const int prediction_index = predicted_sensor_info.prediction_index;
129 
130     const auto linked_sensor_itr = predictor_sensors_.find(predicted_sensor_info.linked_sensor);
131     if (linked_sensor_itr == predictor_sensors_.end()) {
132         LOG(ERROR) << "linked_sensor_name " << predicted_sensor_info.linked_sensor
133                    << " is not registered as predictor for sensor" << sensor_name;
134         return SensorReadStatus::ERROR;
135     }
136 
137     PredictorSensorInfo predictor_sensor_info = linked_sensor_itr->second;
138     boot_clock::time_point now = boot_clock::now();
139     const auto min_time_elapsed_ms = predicted_sensor_info.duration - kToleranceIntervalMs;
140     const auto max_time_elapsed_ms = predicted_sensor_info.duration + kToleranceIntervalMs;
141     int loop_count = 0;
142     do {
143         int index = predictor_sensor_info.cur_index - loop_count - 1;
144         if (index < 0) {
145             index += predictor_sensor_info.num_out_samples;
146         }
147 
148         const auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
149                 now - predictor_sensor_info.samples[index].timestamp);
150         if (time_elapsed.count() <= max_time_elapsed_ms &&
151             time_elapsed.count() >= min_time_elapsed_ms) {
152             *temp = predictor_sensor_info.samples[index].values[prediction_index];
153             return SensorReadStatus::OKAY;
154         }
155 
156         loop_count++;
157     } while (loop_count < predictor_sensor_info.num_out_samples);
158 
159     LOG(INFO) << "sensor_name: " << sensor_name << " no valid prediction samples found";
160     return SensorReadStatus::UNDER_COLLECTING;
161 }
162 
initializePredictionSensors(const std::unordered_map<std::string,SensorInfo> & sensor_info_map)163 bool ThermalPredictionsHelper::initializePredictionSensors(
164         const std::unordered_map<std::string, SensorInfo> &sensor_info_map) {
165     std::unique_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
166 
167     for (auto it = sensor_info_map.begin(); it != sensor_info_map.end(); ++it) {
168         const std::string_view sensor_name = it->first;
169         const SensorInfo &sensor_info = it->second;
170 
171         if (!sensor_info.predictor_info || !sensor_info.virtual_sensor_info ||
172             (!sensor_info.predictor_info->supports_predictions)) {
173             continue;
174         }
175 
176         if (!registerPredictorSensor(sensor_name,
177                                      sensor_info.predictor_info->prediction_sample_interval,
178                                      sensor_info.predictor_info->num_prediction_samples)) {
179             LOG(ERROR) << "Failed to register predictor sensor: " << sensor_name;
180             return false;
181         }
182     }
183 
184     for (auto it = sensor_info_map.begin(); it != sensor_info_map.end(); ++it) {
185         const std::string_view sensor_name = it->first;
186         const SensorInfo &sensor_info = it->second;
187 
188         if (!sensor_info.predictor_info || !sensor_info.virtual_sensor_info ||
189             (sensor_info.virtual_sensor_info->formula != FormulaOption::PREVIOUSLY_PREDICTED)) {
190             continue;
191         }
192 
193         if (sensor_info.virtual_sensor_info->linked_sensors.size() != 1) {
194             LOG(ERROR) << "Invalid number of linked sensors: "
195                        << sensor_info.virtual_sensor_info->linked_sensors.size()
196                        << " for sensor: " << sensor_name;
197             return false;
198         }
199 
200         if (!registerPredictedSensor(sensor_name,
201                                      sensor_info.virtual_sensor_info->linked_sensors[0],
202                                      sensor_info.predictor_info->prediction_duration)) {
203             LOG(ERROR) << "Failed to register predicted sensor: " << sensor_name;
204             return false;
205         }
206     }
207 
208     return true;
209 }
210 
211 }  // namespace implementation
212 }  // namespace thermal
213 }  // namespace hardware
214 }  // namespace android
215 }  // namespace aidl
216