Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3443)

Unified Diff: chrome/browser/android/offline_pages/background_loader_offliner.cc

Issue 2881223002: Create chrome/browser/offline_pages to host browser-related parts of offline_pages whcih (Closed)
Patch Set: modified OWNERS and added DEPS Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/android/offline_pages/background_loader_offliner.cc
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner.cc b/chrome/browser/android/offline_pages/background_loader_offliner.cc
deleted file mode 100644
index b2fc873f41f19a28d41c4e6e0346492aa7528c5c..0000000000000000000000000000000000000000
--- a/chrome/browser/android/offline_pages/background_loader_offliner.cc
+++ /dev/null
@@ -1,498 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/offline_pages/background_loader_offliner.h"
-
-#include "base/bind.h"
-#include "base/json/json_writer.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/sys_info.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
-#include "chrome/browser/android/offline_pages/offliner_helper.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/offline_pages/core/background/offliner_policy.h"
-#include "components/offline_pages/core/background/save_page_request.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/offline_page_feature.h"
-#include "components/offline_pages/core/offline_page_model.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/mhtml_extra_parts.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-namespace offline_pages {
-
-namespace {
-const char kContentType[] = "text/plain";
-const char kContentTransferEncodingBinary[] =
- "Content-Transfer-Encoding: binary";
-const char kXHeaderForSignals[] = "X-Chrome-Loading-Metrics-Data: 1";
-
-class OfflinerData : public content::WebContentsUserData<OfflinerData> {
- public:
- static void AddToWebContents(content::WebContents* webcontents,
- BackgroundLoaderOffliner* offliner) {
- DCHECK(offliner);
- webcontents->SetUserData(UserDataKey(), std::unique_ptr<OfflinerData>(
- new OfflinerData(offliner)));
- }
-
- explicit OfflinerData(BackgroundLoaderOffliner* offliner) {
- offliner_ = offliner;
- }
- BackgroundLoaderOffliner* offliner() { return offliner_; }
-
- private:
- // The offliner that the WebContents is attached to. The offliner owns the
- // Delegate which owns the WebContents that this data is attached to.
- // Therefore, its lifetime should exceed that of the WebContents, so this
- // should always be non-null.
- BackgroundLoaderOffliner* offliner_;
-};
-
-std::string AddHistogramSuffix(const ClientId& client_id,
- const char* histogram_name) {
- if (client_id.name_space.empty()) {
- NOTREACHED();
- return histogram_name;
- }
- std::string adjusted_histogram_name(histogram_name);
- adjusted_histogram_name += "." + client_id.name_space;
- return adjusted_histogram_name;
-}
-
-void RecordErrorCauseUMA(const ClientId& client_id, net::Error error_code) {
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- AddHistogramSuffix(client_id,
- "OfflinePages.Background.BackgroundLoadingFailedCode"),
- std::abs(error_code));
-}
-
-void HandleApplicationStateChangeCancel(
- const Offliner::CompletionCallback& completion_callback,
- const SavePageRequest& canceled_request) {
- completion_callback.Run(canceled_request,
- Offliner::RequestStatus::FOREGROUND_CANCELED);
-}
-
-} // namespace
-
-BackgroundLoaderOffliner::BackgroundLoaderOffliner(
- content::BrowserContext* browser_context,
- const OfflinerPolicy* policy,
- OfflinePageModel* offline_page_model)
- : browser_context_(browser_context),
- offline_page_model_(offline_page_model),
- policy_(policy),
- is_low_end_device_(base::SysInfo::IsLowEndDevice()),
- save_state_(NONE),
- page_load_state_(SUCCESS),
- network_bytes_(0LL),
- is_low_bar_met_(false),
- did_snapshot_on_last_retry_(false),
- weak_ptr_factory_(this) {
- DCHECK(offline_page_model_);
- DCHECK(browser_context_);
-}
-
-BackgroundLoaderOffliner::~BackgroundLoaderOffliner() {}
-
-// static
-BackgroundLoaderOffliner* BackgroundLoaderOffliner::FromWebContents(
- content::WebContents* contents) {
- OfflinerData* data = OfflinerData::FromWebContents(contents);
- if (data)
- return data->offliner();
- return nullptr;
-}
-
-bool BackgroundLoaderOffliner::LoadAndSave(
- const SavePageRequest& request,
- const CompletionCallback& completion_callback,
- const ProgressCallback& progress_callback) {
- DCHECK(completion_callback);
- DCHECK(progress_callback);
- DCHECK(offline_page_model_);
-
- if (pending_request_) {
- DVLOG(1) << "Already have pending request";
- return false;
- }
-
- ClientPolicyController* policy_controller =
- offline_page_model_->GetPolicyController();
- if (policy_controller->IsDisabledWhenPrefetchDisabled(
- request.client_id().name_space) &&
- (AreThirdPartyCookiesBlocked(browser_context_) ||
- IsNetworkPredictionDisabled(browser_context_))) {
- DVLOG(1) << "WARNING: Unable to load when 3rd party cookies blocked or "
- << "prediction disabled";
- // Record user metrics for third party cookies being disabled or network
- // prediction being disabled.
- if (AreThirdPartyCookiesBlocked(browser_context_)) {
- UMA_HISTOGRAM_ENUMERATION(
- "OfflinePages.Background.CctApiDisableStatus",
- static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
- THIRD_PARTY_COOKIES_DISABLED),
- static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
- NETWORK_PREDICTION_DISABLED) +
- 1);
- }
- if (IsNetworkPredictionDisabled(browser_context_)) {
- UMA_HISTOGRAM_ENUMERATION(
- "OfflinePages.Background.CctApiDisableStatus",
- static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
- NETWORK_PREDICTION_DISABLED),
- static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
- NETWORK_PREDICTION_DISABLED) +
- 1);
- }
-
- return false;
- }
-
- // Record UMA that the load was allowed to proceed.
- if (request.client_id().name_space == kCCTNamespace) {
- UMA_HISTOGRAM_ENUMERATION(
- "OfflinePages.Background.CctApiDisableStatus",
- static_cast<int>(
- OfflinePagesCctApiPrerenderAllowedStatus::PRERENDER_ALLOWED),
- static_cast<int>(OfflinePagesCctApiPrerenderAllowedStatus::
- NETWORK_PREDICTION_DISABLED) +
- 1);
- }
-
- if (!OfflinePageModel::CanSaveURL(request.url())) {
- DVLOG(1) << "Not able to save page for requested url: " << request.url();
- return false;
- }
-
- ResetLoader();
- AttachObservers();
-
- MarkLoadStartTime();
-
- // Track copy of pending request.
- pending_request_.reset(new SavePageRequest(request));
- completion_callback_ = completion_callback;
- progress_callback_ = progress_callback;
-
- // Listen for app foreground/background change.
- app_listener_.reset(new base::android::ApplicationStatusListener(
- base::Bind(&BackgroundLoaderOffliner::OnApplicationStateChange,
- weak_ptr_factory_.GetWeakPtr())));
-
- // Load page attempt.
- loader_.get()->LoadPage(request.url());
-
- snapshot_controller_ = SnapshotController::CreateForBackgroundOfflining(
- base::ThreadTaskRunnerHandle::Get(), this);
-
- return true;
-}
-
-bool BackgroundLoaderOffliner::Cancel(const CancelCallback& callback) {
- DCHECK(pending_request_);
- // We ignore the case where pending_request_ is not set, but given the checks
- // in RequestCoordinator this should not happen.
- if (!pending_request_)
- return false;
-
- // TODO(chili): We are not able to cancel a pending
- // OfflinePageModel::SaveSnapshot() operation. We will notify caller that
- // cancel completed once the SavePage operation returns.
- if (save_state_ != NONE) {
- save_state_ = DELETE_AFTER_SAVE;
- cancel_callback_ = callback;
- return true;
- }
-
- // Post the cancel callback right after this call concludes.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, *pending_request_.get()));
- ResetState();
- return true;
-}
-
-bool BackgroundLoaderOffliner::HandleTimeout(int64_t request_id) {
- if (pending_request_) {
- DCHECK(request_id == pending_request_->request_id());
- if (is_low_bar_met_ && (pending_request_->started_attempt_count() + 1 >=
- policy_->GetMaxStartedTries() ||
- pending_request_->completed_attempt_count() + 1 >=
- policy_->GetMaxCompletedTries())) {
- // If we are already in the middle of a save operation, let it finish
- // but do not return SAVED_ON_LAST_RETRY
- if (save_state_ == NONE) {
- did_snapshot_on_last_retry_ = true;
- StartSnapshot();
- }
- return true;
- }
- }
- return false;
-}
-
-void BackgroundLoaderOffliner::MarkLoadStartTime() {
- load_start_time_ = base::TimeTicks::Now();
-}
-
-void BackgroundLoaderOffliner::DocumentAvailableInMainFrame() {
- snapshot_controller_->DocumentAvailableInMainFrame();
- is_low_bar_met_ = true;
-
- // Add this signal to signal_data_.
- AddLoadingSignal("DocumentAvailableInMainFrame");
-}
-
-void BackgroundLoaderOffliner::DocumentOnLoadCompletedInMainFrame() {
- if (!pending_request_.get()) {
- DVLOG(1) << "DidStopLoading called even though no pending request.";
- return;
- }
-
- // Add this signal to signal_data_.
- AddLoadingSignal("DocumentOnLoadCompletedInMainFrame");
-
- snapshot_controller_->DocumentOnLoadCompletedInMainFrame();
-}
-
-void BackgroundLoaderOffliner::RenderProcessGone(
- base::TerminationStatus status) {
- if (pending_request_) {
- SavePageRequest request(*pending_request_.get());
- switch (status) {
- case base::TERMINATION_STATUS_OOM:
- case base::TERMINATION_STATUS_PROCESS_CRASHED:
- case base::TERMINATION_STATUS_STILL_RUNNING:
- completion_callback_.Run(
- request, Offliner::RequestStatus::LOADING_FAILED_NO_NEXT);
- break;
- case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
- default:
- completion_callback_.Run(request,
- Offliner::RequestStatus::LOADING_FAILED);
- }
- ResetState();
- }
-}
-
-void BackgroundLoaderOffliner::WebContentsDestroyed() {
- if (pending_request_) {
- SavePageRequest request(*pending_request_.get());
- completion_callback_.Run(request, Offliner::RequestStatus::LOADING_FAILED);
- ResetState();
- }
-}
-
-void BackgroundLoaderOffliner::DidFinishNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInMainFrame())
- return;
- // If there was an error of any kind (certificate, client, DNS, etc),
- // Mark as error page. Resetting here causes RecordNavigationMetrics to crash.
- if (navigation_handle->IsErrorPage()) {
- RecordErrorCauseUMA(pending_request_->client_id(),
- navigation_handle->GetNetErrorCode());
- switch (navigation_handle->GetNetErrorCode()) {
- case net::ERR_INTERNET_DISCONNECTED:
- page_load_state_ = DELAY_RETRY;
- break;
- default:
- page_load_state_ = RETRIABLE;
- }
- }
-}
-
-void BackgroundLoaderOffliner::SetSnapshotControllerForTest(
- std::unique_ptr<SnapshotController> controller) {
- snapshot_controller_ = std::move(controller);
-}
-
-void BackgroundLoaderOffliner::OnNetworkBytesChanged(int64_t bytes) {
- if (pending_request_ && save_state_ != SAVING) {
- network_bytes_ += bytes;
- progress_callback_.Run(*pending_request_, network_bytes_);
- }
-}
-
-void BackgroundLoaderOffliner::StartSnapshot() {
- if (!pending_request_.get()) {
- DVLOG(1) << "Pending request was cleared during delay.";
- return;
- }
-
- // Add this signal to signal_data_.
- AddLoadingSignal("Snapshotting");
-
- SavePageRequest request(*pending_request_.get());
- // If there was an error navigating to page, return loading failed.
- if (page_load_state_ != SUCCESS) {
- Offliner::RequestStatus status;
- switch (page_load_state_) {
- case RETRIABLE:
- status = Offliner::RequestStatus::LOADING_FAILED;
- break;
- case NONRETRIABLE:
- status = Offliner::RequestStatus::LOADING_FAILED_NO_RETRY;
- break;
- case DELAY_RETRY:
- status = Offliner::RequestStatus::LOADING_FAILED_NO_NEXT;
- break;
- default:
- // We should've already checked for Success before entering here.
- NOTREACHED();
- status = Offliner::RequestStatus::LOADING_FAILED;
- }
-
- completion_callback_.Run(request, status);
- ResetState();
- return;
- }
-
- save_state_ = SAVING;
- content::WebContents* web_contents(
- content::WebContentsObserver::web_contents());
-
- // Add loading signal into the MHTML that will be generated if the command
- // line flag is set for it.
- if (IsOfflinePagesLoadSignalCollectingEnabled()) {
- // Stash loading signals for writing when we write out the MHTML.
- std::string headers = base::StringPrintf(
- "%s\r\n%s\r\n\r\n", kContentTransferEncodingBinary, kXHeaderForSignals);
- std::string body;
- base::JSONWriter::Write(signal_data_, &body);
- std::string content_type = kContentType;
- std::string content_location = base::StringPrintf(
- "cid:signal-data-%" PRId64 "@mhtml.blink", request.request_id());
-
- content::MHTMLExtraParts* extra_parts =
- content::MHTMLExtraParts::FromWebContents(web_contents);
- DCHECK(extra_parts);
- if (extra_parts != nullptr) {
- extra_parts->AddExtraMHTMLPart(content_type, content_location, headers,
- body);
- }
- }
-
- std::unique_ptr<OfflinePageArchiver> archiver(
- new OfflinePageMHTMLArchiver(web_contents));
-
- OfflinePageModel::SavePageParams params;
- params.url = web_contents->GetLastCommittedURL();
- params.client_id = request.client_id();
- params.proposed_offline_id = request.request_id();
- params.is_background = true;
-
- // Pass in the original URL if it's different from last committed
- // when redirects occur.
- if (!request.original_url().is_empty())
- params.original_url = request.original_url();
- else if (params.url != request.url())
- params.original_url = request.url();
-
- offline_page_model_->SavePage(
- params, std::move(archiver),
- base::Bind(&BackgroundLoaderOffliner::OnPageSaved,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void BackgroundLoaderOffliner::OnPageSaved(SavePageResult save_result,
- int64_t offline_id) {
- if (!pending_request_)
- return;
-
- SavePageRequest request(*pending_request_.get());
- bool did_snapshot_on_last_retry = did_snapshot_on_last_retry_;
- ResetState();
-
- if (save_state_ == DELETE_AFTER_SAVE) {
- // Delete the saved page off disk and from the OPM.
- std::vector<int64_t> offline_ids;
- offline_ids.push_back(offline_id);
- offline_page_model_->DeletePagesByOfflineId(
- offline_ids,
- base::Bind(&BackgroundLoaderOffliner::DeleteOfflinePageCallback,
- weak_ptr_factory_.GetWeakPtr(), request));
- save_state_ = NONE;
- return;
- }
-
- save_state_ = NONE;
-
- Offliner::RequestStatus save_status;
- if (save_result == SavePageResult::ALREADY_EXISTS) {
- save_status = RequestStatus::SAVED;
- } else if (save_result == SavePageResult::SUCCESS) {
- if (did_snapshot_on_last_retry)
- save_status = RequestStatus::SAVED_ON_LAST_RETRY;
- else
- save_status = RequestStatus::SAVED;
- } else {
- save_status = RequestStatus::SAVE_FAILED;
- }
-
- completion_callback_.Run(request, save_status);
-}
-
-void BackgroundLoaderOffliner::DeleteOfflinePageCallback(
- const SavePageRequest& request,
- DeletePageResult result) {
- cancel_callback_.Run(request);
-}
-
-void BackgroundLoaderOffliner::ResetState() {
- pending_request_.reset();
- snapshot_controller_.reset();
- page_load_state_ = SUCCESS;
- network_bytes_ = 0LL;
- is_low_bar_met_ = false;
- did_snapshot_on_last_retry_ = false;
- content::WebContentsObserver::Observe(nullptr);
- loader_.reset();
-}
-
-void BackgroundLoaderOffliner::ResetLoader() {
- loader_.reset(
- new background_loader::BackgroundLoaderContents(browser_context_));
-}
-
-void BackgroundLoaderOffliner::AttachObservers() {
- content::WebContents* contents = loader_->web_contents();
- content::WebContentsObserver::Observe(contents);
- OfflinerData::AddToWebContents(contents, this);
-}
-
-void BackgroundLoaderOffliner::OnApplicationStateChange(
- base::android::ApplicationState application_state) {
- if (pending_request_ && is_low_end_device_ &&
- application_state ==
- base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
- DVLOG(1) << "App became active, canceling current offlining request";
- // No need to check the return value or complete early, as false would
- // indicate that there was no request, in which case the state change is
- // ignored.
- Cancel(
- base::Bind(HandleApplicationStateChangeCancel, completion_callback_));
- }
-}
-
-void BackgroundLoaderOffliner::AddLoadingSignal(const char* signal_name) {
- base::TimeTicks current_time = base::TimeTicks::Now();
- base::TimeDelta delay_so_far = current_time - load_start_time_;
- // We would prefer to use int64_t here, but JSON does not support that type.
- // Given the choice between int and double, we choose to implicitly convert to
- // a double since it maintains more precision (we can get a longer time in
- // milliseconds than we can with a 2 bit int, 53 bits vs 32).
- double delay = delay_so_far.InMilliseconds();
- signal_data_.SetDouble(signal_name, delay);
-}
-
-} // namespace offline_pages
-
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::OfflinerData);

Powered by Google App Engine
This is Rietveld 408576698