1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_ 6 #define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_ 7 8 #include <memory> 9 10 #include "base/macros.h" 11 #include "base/memory/scoped_refptr.h" 12 #include "base/memory/weak_ptr.h" 13 #include "base/optional.h" 14 #include "base/scoped_observer.h" 15 #include "base/sequence_checker.h" 16 #include "base/sequenced_task_runner.h" 17 #include "base/threading/thread_checker.h" 18 #include "base/time/time.h" 19 #include "base/timer/timer.h" 20 #include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h" 21 #include "chrome/browser/chromeos/power/auto_screen_brightness/als_samples.h" 22 #include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor.h" 23 #include "chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h" 24 #include "chrome/browser/chromeos/power/auto_screen_brightness/model_config.h" 25 #include "chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader.h" 26 #include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h" 27 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h" 28 #include "chrome/browser/profiles/profile.h" 29 #include "ui/base/user_activity/user_activity_detector.h" 30 #include "ui/base/user_activity/user_activity_observer.h" 31 32 namespace chromeos { 33 namespace power { 34 namespace auto_screen_brightness { 35 36 struct Model { 37 Model(); 38 Model(const base::Optional<MonotoneCubicSpline>& global_curve, 39 const base::Optional<MonotoneCubicSpline>& personal_curve, 40 int iteration_count); 41 Model(const Model& model); 42 ~Model(); 43 base::Optional<MonotoneCubicSpline> global_curve; 44 base::Optional<MonotoneCubicSpline> personal_curve; 45 int iteration_count = 0; 46 }; 47 48 // Real implementation of Modeller. 49 // It monitors user-requested brightness changes, ambient light values and 50 // trains personal brightness curves when user remains idle for a period of 51 // time. 52 // An object of this class must be used on the same thread that created this 53 // object. 54 class ModellerImpl : public Modeller, 55 public AlsReader::Observer, 56 public BrightnessMonitor::Observer, 57 public ModelConfigLoader::Observer, 58 public ui::UserActivityObserver { 59 public: 60 static constexpr char kModelDir[] = "autobrightness"; 61 static constexpr char kGlobalCurveFileName[] = "global_curve"; 62 static constexpr char kPersonalCurveFileName[] = "personal_curve"; 63 static constexpr char kModelIterationCountFileName[] = "iteration_count"; 64 65 // Global curve, personal curve and training iteration count will be saved to 66 // the file paths below. 67 struct ModelSavingSpec { 68 base::FilePath global_curve; 69 base::FilePath personal_curve; 70 base::FilePath iteration_count; 71 }; 72 73 // ModellerImpl has weak dependencies on all parameters except |trainer|. 74 ModellerImpl(const Profile* profile, 75 AlsReader* als_reader, 76 BrightnessMonitor* brightness_monitor, 77 ModelConfigLoader* model_config_loader, 78 ui::UserActivityDetector* user_activity_detector, 79 std::unique_ptr<Trainer> trainer); 80 ~ModellerImpl() override; 81 82 // Modeller overrides: 83 void AddObserver(Modeller::Observer* observer) override; 84 void RemoveObserver(Modeller::Observer* observer) override; 85 86 // AlsReader::Observer overrides: 87 void OnAmbientLightUpdated(int lux) override; 88 void OnAlsReaderInitialized(AlsReader::AlsInitStatus status) override; 89 90 // BrightnessMonitor::Observer overrides: 91 void OnBrightnessMonitorInitialized(bool success) override; 92 void OnUserBrightnessChanged(double old_brightness_percent, 93 double new_brightness_percent) override; 94 void OnUserBrightnessChangeRequested() override; 95 96 // ModelConfigLoader::Observer overrides: 97 void OnModelConfigLoaded(base::Optional<ModelConfig> model_config) override; 98 99 // ui::UserActivityObserver overrides: 100 void OnUserActivity(const ui::Event* event) override; 101 102 // ModellerImpl has weak dependencies on all parameters except |trainer|. 103 static std::unique_ptr<ModellerImpl> CreateForTesting( 104 const Profile* profile, 105 AlsReader* als_reader, 106 BrightnessMonitor* brightness_monitor, 107 ModelConfigLoader* model_config_loader, 108 ui::UserActivityDetector* user_activity_detector, 109 std::unique_ptr<Trainer> trainer, 110 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, 111 const base::TickClock* tick_clock); 112 113 // Current average log ambient light. 114 base::Optional<double> AverageAmbientForTesting(base::TimeTicks now); 115 116 // Current number of training data points stored, which will be used for next 117 // training. 118 size_t NumberTrainingDataPointsForTesting() const; 119 120 // Returns |max_training_data_points_| for unit tests. 121 size_t GetMaxTrainingDataPointsForTesting() const; 122 123 base::TimeDelta GetTrainingDelayForTesting() const; 124 125 ModelConfig GetModelConfigForTesting() const; 126 127 // Returns ModelSavingSpec used to store models. It also creates intermediate 128 // directories if they do not exist. The returned paths will be empty on 129 // failures. 130 static ModelSavingSpec GetModelSavingSpecFromProfilePath( 131 const base::FilePath& profile_path); 132 133 private: 134 // ModellerImpl has weak dependencies on all parameters except |trainer|. 135 ModellerImpl(const Profile* profile, 136 AlsReader* als_reader, 137 BrightnessMonitor* brightness_monitor, 138 ModelConfigLoader* model_config_loader, 139 ui::UserActivityDetector* user_activity_detector, 140 std::unique_ptr<Trainer> trainer, 141 scoped_refptr<base::SequencedTaskRunner> task_runner, 142 const base::TickClock* tick_clock, 143 bool is_testing = false); 144 145 // Called after we've attempted to read model saving spec from the user 146 // profile. 147 void OnModelSavingSpecReadFromProfile(const ModelSavingSpec& spec); 148 149 // Called to handle a status change in one of the dependencies (ALS, 150 // brightness monitor, model config loader) of the modeller. If all 151 // dependencies are successfully initialized, attempts initialization of 152 // the modeller (curve loading, parameter customization) and notifies 153 // observers about the result. 154 void HandleStatusUpdate(); 155 156 // Applies customizations from model configs. Returns whether it is 157 // successful. 158 bool ApplyCustomization(); 159 160 // Called as soon as |is_modeller_enabled_| has its value set. It will notify 161 // all observers. 162 void OnInitializationComplete(); 163 164 // Notifies a given observer about the state of the modeller. Will provide 165 // either 166 // - no curves (if modeller is disabled), 167 // - just a global curve (if no personal curve is available), or 168 // - both a global and personal curve. 169 void NotifyObserverInitStatus(Modeller::Observer& observer); 170 171 // Sets the global and personal curves based on the model read from disk. If 172 // the model is invalid or not based on the current model config, instead 173 // resets the global and personal curves. 174 void OnModelLoadedFromDisk(const Model& model); 175 176 void OnModelSavedToDisk(bool is_successful); 177 178 // Called after we've set trainer's initial curves. 179 void OnSetInitialCurves(bool is_personal_curve_valid); 180 181 // Either starts training immediately or delays it for |training_delay_|. 182 // Training starts immediately if |training_delay_| is 0 or number of training 183 // points reached |max_training_data_points_|. 184 // This function is called after a user brightness change signal is received 185 // (that will be used as an example), and when a user activity is detected. 186 // It's also called after initial curves are set. 187 // Nothing will happen if model is not enabled. 188 void ScheduleTrainerStart(); 189 190 // Starts model training and runs it in non UI thread. Also clears 191 // |data_cache_|. 192 void StartTraining(); 193 194 // Called after training is complete. 195 void OnTrainingFinished(const TrainingResult& result); 196 197 // Erase all info related to the personal curve. 198 void ErasePersonalCurve(); 199 200 // If |is_testing_| is false, we check curve saving/loading and training jobs 201 // are running on non-UI thread. 202 const bool is_testing_ = false; 203 204 // If number of recorded training data has reached |max_training_data_points_| 205 // we start training immediately, without waiting for user to become idle for 206 // |training_delay_|. This can be overridden by experiment flag 207 // "max_training_data_points". 208 size_t max_training_data_points_ = 100; 209 210 // Once user remains idle for |training_delay_|, we start training the model. 211 // If this value is 0, we will not need to wait for user to remain inactive. 212 // This can be overridden by experiment flag "training_delay_in_seconds". 213 base::TimeDelta training_delay_ = base::TimeDelta::FromSeconds(0); 214 215 // If personal curve error is above this threshold, the curve will not be 216 // exported. The error is expressed in terms of percentages. 217 double curve_error_tolerance_ = 5.0; 218 219 ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_; 220 221 ScopedObserver<BrightnessMonitor, BrightnessMonitor::Observer> 222 brightness_monitor_observer_; 223 224 ScopedObserver<ModelConfigLoader, ModelConfigLoader::Observer> 225 model_config_loader_observer_; 226 227 ScopedObserver<ui::UserActivityDetector, ui::UserActivityObserver> 228 user_activity_observer_; 229 230 // Background task runner for IO work (loading a curve from disk and writing a 231 // curve to disk) and training jobs. 232 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; 233 std::unique_ptr<Trainer, base::OnTaskRunnerDeleter> trainer_; 234 235 // This will be replaced by a mock tick clock during tests. 236 const base::TickClock* const tick_clock_; 237 238 base::OneShotTimer model_timer_; 239 240 base::Optional<AlsReader::AlsInitStatus> als_init_status_; 241 base::Optional<bool> brightness_monitor_success_; 242 243 // |model_config_exists_| will remain nullopt until |OnModelConfigLoaded| is 244 // called. Its value will then be set to true if the input model config exists 245 // (not nullopt), else its value will be false. 246 base::Optional<bool> model_config_exists_; 247 ModelConfig model_config_; 248 249 // Whether this modeller has initialized successfully, including connecting 250 // to AlsReader, BrightnessMonitor and loading a Trainer. 251 // Initially has no value. Guaranteed to have a value after the completion of 252 // |OnModelLoadedFromDisk|. 253 base::Optional<bool> is_modeller_enabled_; 254 255 base::Optional<ModelSavingSpec> model_saving_spec_; 256 257 // Whether the initial global curve is reset to the one constructed from 258 // model config. It is true if there is no saved model loaded from the disk 259 // or if the saved global curve is different from the curve from model config. 260 // If this flag is true, then the global curve is saved to the disk the first 261 // time a personal curve is trained and saved to disk; it will be set to false 262 // after the first saving is done. 263 bool global_curve_reset_ = false; 264 265 // |model_| will be set after initialization is complete and updated each time 266 // training is done with a new curve. 267 Model model_; 268 269 // |initial_global_curve_| is constructed from model config. 270 base::Optional<MonotoneCubicSpline> initial_global_curve_; 271 272 // Recent log ambient values. 273 std::unique_ptr<AmbientLightSampleBuffer> log_als_values_; 274 275 std::vector<TrainingDataPoint> data_cache_; 276 277 base::ObserverList<Modeller::Observer> observers_; 278 279 // Training start time. 280 base::Optional<base::TimeTicks> training_start_; 281 282 SEQUENCE_CHECKER(sequence_checker_); 283 284 base::WeakPtrFactory<ModellerImpl> weak_ptr_factory_{this}; 285 286 DISALLOW_COPY_AND_ASSIGN(ModellerImpl); 287 }; 288 289 // Saves |model| to disk at location specified by |model_saving_spec| and 290 // returns whether it was successful. This should run in another thread to be 291 // non-blocking to the main thread (if |is_testing| is false). 292 // Not every components of |model| will be saved: 293 // 1. |global_curve| is saved only if |save_global_curve| is true. 294 // 2. |personal_curve| is saved only if |save_personal_curve| is true. 295 // 3. |iteration_count| is always saved. 296 bool SaveModelToDisk(const ModellerImpl::ModelSavingSpec& model_saving_spec, 297 const Model& model, 298 bool save_global_curve, 299 bool save_personal_curve, 300 bool is_testing); 301 302 } // namespace auto_screen_brightness 303 } // namespace power 304 } // namespace chromeos 305 306 #endif // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_ 307