| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_COORDINATOR_H_ | |
| 6 #define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_COORDINATOR_H_ | |
| 7 | |
| 8 #include <memory> | |
| 9 #include <set> | |
| 10 #include <string> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "base/callback.h" | |
| 14 #include "base/macros.h" | |
| 15 #include "base/memory/weak_ptr.h" | |
| 16 #include "base/observer_list.h" | |
| 17 #include "base/supports_user_data.h" | |
| 18 #include "base/time/time.h" | |
| 19 #include "base/timer/timer.h" | |
| 20 #include "components/keyed_service/core/keyed_service.h" | |
| 21 #include "components/offline_pages/background/connection_notifier.h" | |
| 22 #include "components/offline_pages/background/device_conditions.h" | |
| 23 #include "components/offline_pages/background/offliner.h" | |
| 24 #include "components/offline_pages/background/request_coordinator_event_logger.h
" | |
| 25 #include "components/offline_pages/background/request_notifier.h" | |
| 26 #include "components/offline_pages/background/request_queue.h" | |
| 27 #include "components/offline_pages/background/scheduler.h" | |
| 28 #include "net/nqe/network_quality_estimator.h" | |
| 29 #include "url/gurl.h" | |
| 30 | |
| 31 namespace offline_pages { | |
| 32 | |
| 33 struct ClientId; | |
| 34 class OfflinerPolicy; | |
| 35 class OfflinerFactory; | |
| 36 class Offliner; | |
| 37 class RequestQueue; | |
| 38 class SavePageRequest; | |
| 39 class Scheduler; | |
| 40 class ClientPolicyController; | |
| 41 | |
| 42 // Coordinates queueing and processing save page later requests. | |
| 43 class RequestCoordinator : public KeyedService, | |
| 44 public RequestNotifier, | |
| 45 public base::SupportsUserData { | |
| 46 public: | |
| 47 // Nested observer class. To make sure that no events are missed, the client | |
| 48 // code should first register for notifications, then |GetAllRequests|, and | |
| 49 // ignore all events before the return from |GetAllRequests|, and consume | |
| 50 // events after the return callback from |GetAllRequests|. | |
| 51 class Observer { | |
| 52 public: | |
| 53 virtual ~Observer() = default; | |
| 54 | |
| 55 virtual void OnAdded(const SavePageRequest& request) = 0; | |
| 56 virtual void OnCompleted( | |
| 57 const SavePageRequest& request, | |
| 58 RequestNotifier::BackgroundSavePageResult status) = 0; | |
| 59 virtual void OnChanged(const SavePageRequest& request) = 0; | |
| 60 }; | |
| 61 | |
| 62 enum class RequestAvailability { | |
| 63 ENABLED_FOR_OFFLINER, | |
| 64 DISABLED_FOR_OFFLINER, | |
| 65 }; | |
| 66 | |
| 67 // Callback specifying which request IDs were actually removed. | |
| 68 typedef base::Callback<void(const MultipleItemStatuses&)> | |
| 69 RemoveRequestsCallback; | |
| 70 | |
| 71 // Callback that receives the response for GetAllRequests. | |
| 72 typedef base::Callback<void(std::vector<std::unique_ptr<SavePageRequest>>)> | |
| 73 GetRequestsCallback; | |
| 74 | |
| 75 RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy, | |
| 76 std::unique_ptr<OfflinerFactory> factory, | |
| 77 std::unique_ptr<RequestQueue> queue, | |
| 78 std::unique_ptr<Scheduler> scheduler, | |
| 79 net::NetworkQualityEstimator::NetworkQualityProvider* | |
| 80 network_quality_estimator); | |
| 81 | |
| 82 ~RequestCoordinator() override; | |
| 83 | |
| 84 // Queues |request| to later load and save when system conditions allow. | |
| 85 // Returns an id if the page could be queued successfully, 0L otherwise. | |
| 86 int64_t SavePageLater(const GURL& url, | |
| 87 const ClientId& client_id, | |
| 88 bool user_requested, | |
| 89 RequestAvailability availability); | |
| 90 | |
| 91 // Remove a list of requests by |request_id|. This removes requests from the | |
| 92 // request queue, and cancels an in-progress prerender. | |
| 93 void RemoveRequests(const std::vector<int64_t>& request_ids, | |
| 94 const RemoveRequestsCallback& callback); | |
| 95 | |
| 96 // Pause a list of requests by |request_id|. This will change the state | |
| 97 // in the request queue so the request cannot be started. | |
| 98 void PauseRequests(const std::vector<int64_t>& request_ids); | |
| 99 | |
| 100 // Resume a list of previously paused requests, making them available. | |
| 101 void ResumeRequests(const std::vector<int64_t>& request_ids); | |
| 102 | |
| 103 // Get all save page request items in the callback. | |
| 104 void GetAllRequests(const GetRequestsCallback& callback); | |
| 105 | |
| 106 // Starts processing of one or more queued save page later requests. | |
| 107 // Returns whether processing was started and that caller should expect | |
| 108 // a callback. If processing was already active, returns false. | |
| 109 bool StartProcessing(const DeviceConditions& device_conditions, | |
| 110 const base::Callback<void(bool)>& callback); | |
| 111 | |
| 112 // Stops the current request processing if active. This is a way for | |
| 113 // caller to abort processing; otherwise, processing will complete on | |
| 114 // its own. In either case, the callback will be called when processing | |
| 115 // is stopped or complete. | |
| 116 void StopProcessing(Offliner::RequestStatus stop_status); | |
| 117 | |
| 118 // Used to denote that the foreground thread is ready for the offliner | |
| 119 // to start work on a previously entered, but unavailable request. | |
| 120 void EnableForOffliner(int64_t request_id, const ClientId& client_id); | |
| 121 | |
| 122 // If a request that is unavailable to the offliner is finished elsewhere, | |
| 123 // (by the tab helper synchronous download), send a notificaiton that it | |
| 124 // succeeded through our notificaiton system. | |
| 125 void MarkRequestCompleted(int64_t request_id); | |
| 126 | |
| 127 const Scheduler::TriggerConditions GetTriggerConditions( | |
| 128 const bool user_requested); | |
| 129 | |
| 130 // A way for tests to set the callback in use when an operation is over. | |
| 131 void SetProcessingCallbackForTest(const base::Callback<void(bool)> callback) { | |
| 132 scheduler_callback_ = callback; | |
| 133 } | |
| 134 | |
| 135 // A way to set the callback which would be called if the request will be | |
| 136 // scheduled immediately. Used by testing harness to determine if a request | |
| 137 // has been processed. | |
| 138 void SetImmediateScheduleCallbackForTest( | |
| 139 const base::Callback<void(bool)> callback) { | |
| 140 immediate_schedule_callback_ = callback; | |
| 141 } | |
| 142 | |
| 143 void StartImmediatelyForTest() { StartImmediatelyIfConnected(); } | |
| 144 | |
| 145 // Observers implementing the RequestCoordinator::Observer interface can | |
| 146 // register here to get notifications of changes to request state. This | |
| 147 // pointer is not owned, and it is the callers responsibility to remove the | |
| 148 // observer before the observer is deleted. | |
| 149 void AddObserver(RequestCoordinator::Observer* observer); | |
| 150 | |
| 151 void RemoveObserver(RequestCoordinator::Observer* observer); | |
| 152 | |
| 153 // Implement RequestNotifier | |
| 154 void NotifyAdded(const SavePageRequest& request) override; | |
| 155 void NotifyCompleted( | |
| 156 const SavePageRequest& request, | |
| 157 RequestNotifier::BackgroundSavePageResult status) override; | |
| 158 void NotifyChanged(const SavePageRequest& request) override; | |
| 159 | |
| 160 // Returns the request queue used for requests. Coordinator keeps ownership. | |
| 161 RequestQueue* queue() { return queue_.get(); } | |
| 162 | |
| 163 // Return an unowned pointer to the Scheduler. | |
| 164 Scheduler* scheduler() { return scheduler_.get(); } | |
| 165 | |
| 166 OfflinerPolicy* policy() { return policy_.get(); } | |
| 167 | |
| 168 ClientPolicyController* GetPolicyController(); | |
| 169 | |
| 170 // Returns the status of the most recent offlining. | |
| 171 Offliner::RequestStatus last_offlining_status() { | |
| 172 return last_offlining_status_; | |
| 173 } | |
| 174 | |
| 175 bool is_busy() { | |
| 176 return is_busy_; | |
| 177 } | |
| 178 | |
| 179 // Returns whether processing is starting (before it is decided to actually | |
| 180 // process a request (is_busy()) at this time or not. | |
| 181 bool is_starting() { return is_starting_; } | |
| 182 | |
| 183 // Tracks whether the last offlining attempt got canceled. This is reset by | |
| 184 // the next StartProcessing() call. | |
| 185 bool is_canceled() { | |
| 186 return processing_state_ == ProcessingWindowState::STOPPED; | |
| 187 } | |
| 188 | |
| 189 RequestCoordinatorEventLogger* GetLogger() { return &event_logger_; } | |
| 190 | |
| 191 private: | |
| 192 // Immediate start attempt status code for UMA. | |
| 193 // These values are written to logs. New enum values can be added, but | |
| 194 // existing enums must never be renumbered or deleted and reused. | |
| 195 // For any additions, also update corresponding histogram in histograms.xml. | |
| 196 enum OfflinerImmediateStartStatus { | |
| 197 // Did start processing request. | |
| 198 STARTED = 0, | |
| 199 // Already busy processing a request. | |
| 200 BUSY = 1, | |
| 201 // The Offliner did not accept processing the request. | |
| 202 NOT_ACCEPTED = 2, | |
| 203 // No current network connection. | |
| 204 NO_CONNECTION = 3, | |
| 205 // Weak network connection (worse than 2G speed) | |
| 206 // according to network quality estimator. | |
| 207 WEAK_CONNECTION = 4, | |
| 208 // Did not start because this is svelte device. | |
| 209 NOT_STARTED_ON_SVELTE = 5, | |
| 210 // NOTE: insert new values above this line and update histogram enum too. | |
| 211 STATUS_COUNT = 6, | |
| 212 }; | |
| 213 | |
| 214 enum class ProcessingWindowState { | |
| 215 STOPPED, | |
| 216 SCHEDULED_WINDOW, | |
| 217 IMMEDIATE_WINDOW, | |
| 218 }; | |
| 219 | |
| 220 // Receives the results of a get from the request queue, and turns that into | |
| 221 // SavePageRequest objects for the caller of GetQueuedRequests. | |
| 222 void GetQueuedRequestsCallback( | |
| 223 const GetRequestsCallback& callback, | |
| 224 GetRequestsResult result, | |
| 225 std::vector<std::unique_ptr<SavePageRequest>> requests); | |
| 226 | |
| 227 // Receives the results of a get from the request queue, and turns that into | |
| 228 // SavePageRequest objects for the caller of GetQueuedRequests. | |
| 229 void GetRequestsForSchedulingCallback( | |
| 230 GetRequestsResult result, | |
| 231 std::vector<std::unique_ptr<SavePageRequest>> requests); | |
| 232 | |
| 233 // Receives the result of add requests to the request queue. | |
| 234 void AddRequestResultCallback(RequestAvailability availability, | |
| 235 AddRequestResult result, | |
| 236 const SavePageRequest& request); | |
| 237 | |
| 238 void UpdateMultipleRequestsCallback( | |
| 239 std::unique_ptr<UpdateRequestsResult> result); | |
| 240 | |
| 241 void HandleRemovedRequestsAndCallback( | |
| 242 const RemoveRequestsCallback& callback, | |
| 243 RequestNotifier::BackgroundSavePageResult status, | |
| 244 std::unique_ptr<UpdateRequestsResult> result); | |
| 245 | |
| 246 void HandleRemovedRequests(RequestNotifier::BackgroundSavePageResult status, | |
| 247 std::unique_ptr<UpdateRequestsResult> result); | |
| 248 | |
| 249 bool StartProcessingInternal(const ProcessingWindowState processing_state, | |
| 250 const DeviceConditions& device_conditions, | |
| 251 const base::Callback<void(bool)>& callback); | |
| 252 | |
| 253 // Start processing now if connected (but with conservative assumption | |
| 254 // as to other device conditions). | |
| 255 void StartImmediatelyIfConnected(); | |
| 256 | |
| 257 OfflinerImmediateStartStatus TryImmediateStart(); | |
| 258 | |
| 259 // Requests a callback upon the next network connection to start processing. | |
| 260 void RequestConnectedEventForStarting(); | |
| 261 | |
| 262 // Clears the request for connected event if it was set. | |
| 263 void ClearConnectedEventRequest(); | |
| 264 | |
| 265 // Handles receiving a connection event. Will start immediate processing. | |
| 266 void HandleConnectedEventForStarting(); | |
| 267 | |
| 268 // Check the request queue, and schedule a task corresponding | |
| 269 // to the least restrictive type of request in the queue. | |
| 270 void ScheduleAsNeeded(); | |
| 271 | |
| 272 // Callback from the request picker when it has chosen our next request. | |
| 273 void RequestPicked(const SavePageRequest& request, bool cleanup_needed); | |
| 274 | |
| 275 // Callback from the request picker when no more requests are in the queue. | |
| 276 // The parameter is a signal for what (if any) conditions to schedule future | |
| 277 // processing for. | |
| 278 void RequestNotPicked(bool non_user_requested_tasks_remaining, | |
| 279 bool cleanup_needed); | |
| 280 | |
| 281 // Callback from request picker that receives the current available queued | |
| 282 // request count as well as the total queued request count (which may be | |
| 283 // different if unavailable requests are queued such as paused requests). | |
| 284 // It also receives a flag as to whether this request picking is due to the | |
| 285 // start of a request processing window. | |
| 286 void RequestCounts(bool is_start_of_processing, | |
| 287 size_t total_requests, | |
| 288 size_t available_requests); | |
| 289 | |
| 290 void HandleWatchdogTimeout(); | |
| 291 | |
| 292 // Cancels an in progress pre-rendering, and updates state appropriately. | |
| 293 void StopPrerendering(Offliner::RequestStatus stop_status); | |
| 294 | |
| 295 // Marks attempt on the request and sends it to offliner in continuation. | |
| 296 void SendRequestToOffliner(const SavePageRequest& request); | |
| 297 | |
| 298 // Continuation of |SendRequestToOffliner| after the request is marked as | |
| 299 // started. | |
| 300 void StartOffliner(int64_t request_id, | |
| 301 const std::string& client_namespace, | |
| 302 std::unique_ptr<UpdateRequestsResult> update_result); | |
| 303 | |
| 304 // Called by the offliner when an offlining request is completed. (and by | |
| 305 // tests). | |
| 306 void OfflinerDoneCallback(const SavePageRequest& request, | |
| 307 Offliner::RequestStatus status); | |
| 308 | |
| 309 // Records a completed attempt for the request and update it in the queue | |
| 310 // (possibly removing it). | |
| 311 void UpdateRequestForCompletedAttempt(const SavePageRequest& request, | |
| 312 Offliner::RequestStatus status); | |
| 313 | |
| 314 // Returns whether we should try another request based on the outcome | |
| 315 // of the previous one. | |
| 316 bool ShouldTryNextRequest(Offliner::RequestStatus previous_request_status); | |
| 317 | |
| 318 // Try to find and start offlining an available request. | |
| 319 // |is_start_of_processing| identifies if this is the beginning of a | |
| 320 // processing window (vs. continuing within a current processing window). | |
| 321 void TryNextRequest(bool is_start_of_processing); | |
| 322 | |
| 323 // If there is an active request in the list, cancel that request. | |
| 324 bool CancelActiveRequestIfItMatches(const std::vector<int64_t>& request_ids); | |
| 325 | |
| 326 // Records an aborted attempt for the request and update it in the queue | |
| 327 // (possibly removing it). | |
| 328 void UpdateRequestForAbortedAttempt(const SavePageRequest& request); | |
| 329 | |
| 330 // Remove the attempted request from the queue with status to pass through to | |
| 331 // any observers and UMA histogram. | |
| 332 void RemoveAttemptedRequest(const SavePageRequest& request, | |
| 333 BackgroundSavePageResult status); | |
| 334 | |
| 335 // Marks the attempt as aborted. This makes the request available again | |
| 336 // for offlining. | |
| 337 void MarkAttemptAborted(int64_t request_id, const std::string& name_space); | |
| 338 | |
| 339 // Reports change from marking request, reports an error if it fails. | |
| 340 void MarkAttemptDone(int64_t request_id, | |
| 341 const std::string& name_space, | |
| 342 std::unique_ptr<UpdateRequestsResult> result); | |
| 343 | |
| 344 // Returns the appropriate offliner to use, getting a new one from the factory | |
| 345 // if needed. | |
| 346 void GetOffliner(); | |
| 347 | |
| 348 // Method to wrap calls to getting the connection type so it can be | |
| 349 // changed for tests. | |
| 350 net::NetworkChangeNotifier::ConnectionType GetConnectionType(); | |
| 351 | |
| 352 void SetNetworkConditionsForTest( | |
| 353 net::NetworkChangeNotifier::ConnectionType connection) { | |
| 354 use_test_connection_type_ = true; | |
| 355 test_connection_type_ = connection; | |
| 356 } | |
| 357 | |
| 358 void SetDeviceConditionsForTest(const DeviceConditions& current_conditions) { | |
| 359 current_conditions_.reset(new DeviceConditions(current_conditions)); | |
| 360 } | |
| 361 | |
| 362 // KeyedService implementation: | |
| 363 void Shutdown() override; | |
| 364 | |
| 365 friend class RequestCoordinatorTest; | |
| 366 | |
| 367 // Cached value of whether low end device. Overwritable for testing. | |
| 368 bool is_low_end_device_; | |
| 369 | |
| 370 // The offliner can only handle one request at a time - if the offliner is | |
| 371 // busy, prevent other requests. This flag marks whether the offliner is in | |
| 372 // use. | |
| 373 bool is_busy_; | |
| 374 // There is more than one path to start processing so this flag is used | |
| 375 // to avoid race conditions before is_busy_ is established. | |
| 376 bool is_starting_; | |
| 377 // Identifies the type of current processing window or if processing stopped. | |
| 378 ProcessingWindowState processing_state_; | |
| 379 // True if we should use the test connection type instead of the actual type. | |
| 380 bool use_test_connection_type_; | |
| 381 // For use by tests, a fake network connection type | |
| 382 net::NetworkChangeNotifier::ConnectionType test_connection_type_; | |
| 383 // Unowned pointer to the current offliner, if any. | |
| 384 Offliner* offliner_; | |
| 385 base::Time operation_start_time_; | |
| 386 // The observers. | |
| 387 base::ObserverList<Observer> observers_; | |
| 388 // Last known conditions for network, battery | |
| 389 std::unique_ptr<DeviceConditions> current_conditions_; | |
| 390 // RequestCoordinator takes over ownership of the policy | |
| 391 std::unique_ptr<OfflinerPolicy> policy_; | |
| 392 // OfflinerFactory. Used to create offline pages. Owned. | |
| 393 std::unique_ptr<OfflinerFactory> factory_; | |
| 394 // RequestQueue. Used to store incoming requests. Owned. | |
| 395 std::unique_ptr<RequestQueue> queue_; | |
| 396 // Scheduler. Used to request a callback when network is available. Owned. | |
| 397 std::unique_ptr<Scheduler> scheduler_; | |
| 398 // Controller of client policies. Owned. | |
| 399 std::unique_ptr<ClientPolicyController> policy_controller_; | |
| 400 // Unowned pointer to the Network Quality Estimator. | |
| 401 net::NetworkQualityEstimator::NetworkQualityProvider* | |
| 402 network_quality_estimator_; | |
| 403 // Holds copy of the active request, if any. | |
| 404 std::unique_ptr<SavePageRequest> active_request_; | |
| 405 // Status of the most recent offlining. | |
| 406 Offliner::RequestStatus last_offlining_status_; | |
| 407 // A set of request_ids that we are holding off until the download manager is | |
| 408 // done with them. | |
| 409 std::set<int64_t> disabled_requests_; | |
| 410 // Calling this returns to the scheduler across the JNI bridge. | |
| 411 base::Callback<void(bool)> scheduler_callback_; | |
| 412 // Logger to record events. | |
| 413 RequestCoordinatorEventLogger event_logger_; | |
| 414 // Timer to watch for pre-render attempts running too long. | |
| 415 base::OneShotTimer watchdog_timer_; | |
| 416 // Callback invoked when an immediate request is done (default empty). | |
| 417 base::Callback<void(bool)> immediate_schedule_callback_; | |
| 418 // Used for potential immediate processing when we get network connection. | |
| 419 std::unique_ptr<ConnectionNotifier> connection_notifier_; | |
| 420 // Allows us to pass a weak pointer to callbacks. | |
| 421 base::WeakPtrFactory<RequestCoordinator> weak_ptr_factory_; | |
| 422 | |
| 423 DISALLOW_COPY_AND_ASSIGN(RequestCoordinator); | |
| 424 }; | |
| 425 | |
| 426 } // namespace offline_pages | |
| 427 | |
| 428 #endif // COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_COORDINATOR_H_ | |
| OLD | NEW |