blob: 8a1d68e1107749f3b5110da3563f6316f70ce1be [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/importer/external_process_importer_host.h"
#include <memory>
#include "base/functional/bind.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/importer/external_process_importer_client.h"
#include "chrome/browser/importer/firefox_profile_lock.h"
#include "chrome/browser/importer/importer_lock_dialog.h"
#include "chrome/browser/importer/importer_progress_observer.h"
#include "chrome/browser/importer/in_process_importer_bridge.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/search_engines/template_url_service.h"
#include "content/public/browser/browser_thread.h"
using bookmarks::BookmarkModel;
using content::BrowserThread;
ExternalProcessImporterHost::ExternalProcessImporterHost()
: headless_(false),
parent_window_(gfx::NativeWindow()),
observer_(nullptr),
profile_(nullptr),
is_source_readable_(true),
client_(nullptr),
items_(0),
cancelled_(false) {}
void ExternalProcessImporterHost::Cancel() {
cancelled_ = true;
// There is only a |client_| if the import was started.
if (client_)
client_->Cancel();
NotifyImportEnded(); // Tells the observer that we're done, and deletes us.
}
void ExternalProcessImporterHost::StartImportSettings(
const user_data_importer::SourceProfile& source_profile,
Profile* target_profile,
uint16_t items,
ProfileWriter* writer) {
// We really only support importing from one host at a time.
DCHECK(!profile_);
DCHECK(target_profile);
profile_ = target_profile;
writer_ = writer;
source_profile_ = source_profile;
items_ = items;
if (!CheckForFirefoxLock(source_profile)) {
Cancel();
return;
}
CheckForLoadedModels(items);
LaunchImportIfReady();
}
void ExternalProcessImporterHost::NotifyImportStarted() {
if (observer_)
observer_->ImportStarted();
}
void ExternalProcessImporterHost::NotifyImportItemStarted(
user_data_importer::ImportItem item) {
if (observer_)
observer_->ImportItemStarted(item);
}
void ExternalProcessImporterHost::NotifyImportItemEnded(
user_data_importer::ImportItem item) {
if (observer_)
observer_->ImportItemEnded(item);
}
void ExternalProcessImporterHost::NotifyImportEnded() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
firefox_lock_.reset();
if (observer_)
observer_->ImportEnded();
delete this;
}
ExternalProcessImporterHost::~ExternalProcessImporterHost() = default;
void ExternalProcessImporterHost::LaunchImportIfReady() {
if (bookmark_model_observation_for_loading_.IsObserving() ||
template_service_subscription_ || !is_source_readable_ || cancelled_) {
return;
}
// This is the in-process half of the bridge, which catches data from the IPC
// pipe and feeds it to the ProfileWriter. The external process half of the
// bridge lives in the external process (see ProfileImportThread).
// The ExternalProcessImporterClient created in the next line owns the bridge,
// and will delete it.
InProcessImporterBridge* bridge =
new InProcessImporterBridge(writer_.get(),
weak_ptr_factory_.GetWeakPtr());
client_ = new ExternalProcessImporterClient(
weak_ptr_factory_.GetWeakPtr(), source_profile_, items_, bridge);
client_->Start();
}
void ExternalProcessImporterHost::BookmarkModelLoaded(bool ids_reassigned) {
bookmark_model_observation_for_loading_.Reset();
LaunchImportIfReady();
}
void ExternalProcessImporterHost::BookmarkModelBeingDeleted() {
bookmark_model_observation_for_loading_.Reset();
}
void ExternalProcessImporterHost::BookmarkModelChanged() {
}
void ExternalProcessImporterHost::OnTemplateURLServiceLoaded() {
template_service_subscription_ = {};
LaunchImportIfReady();
}
void ExternalProcessImporterHost::ShowWarningDialog() {
DCHECK(!headless_);
importer::ShowImportLockDialog(
parent_window_,
base::BindOnce(&ExternalProcessImporterHost::OnImportLockDialogEnd,
weak_ptr_factory_.GetWeakPtr()));
}
void ExternalProcessImporterHost::OnImportLockDialogEnd(bool is_continue) {
if (is_continue) {
// User chose to continue, then we check the lock again to make
// sure that Firefox has been closed. Try to import the settings
// if successful. Otherwise, show a warning dialog.
firefox_lock_->Lock();
if (firefox_lock_->HasAcquired()) {
is_source_readable_ = true;
LaunchImportIfReady();
} else {
ShowWarningDialog();
}
} else {
NotifyImportEnded();
}
}
bool ExternalProcessImporterHost::CheckForFirefoxLock(
const user_data_importer::SourceProfile& source_profile) {
if (source_profile.importer_type != user_data_importer::TYPE_FIREFOX) {
return true;
}
DCHECK(!firefox_lock_.get());
firefox_lock_ =
std::make_unique<FirefoxProfileLock>(source_profile.source_path);
if (firefox_lock_->HasAcquired())
return true;
// If fail to acquire the lock, we set the source unreadable and
// show a warning dialog, unless running without UI (in which case the import
// must be aborted).
is_source_readable_ = false;
if (headless_)
return false;
ShowWarningDialog();
return true;
}
void ExternalProcessImporterHost::CheckForLoadedModels(uint16_t items) {
// A target profile must be loaded by StartImportSettings().
DCHECK(profile_);
// BookmarkModel should be loaded before adding IE favorites. So we observe
// the BookmarkModel if needed, and start the task after it has been loaded.
if ((items & user_data_importer::FAVORITES) &&
!writer_->BookmarkModelIsLoaded()) {
bookmark_model_observation_for_loading_.Observe(
BookmarkModelFactory::GetForBrowserContext(profile_));
}
// Observes the TemplateURLService if needed to import search engines from the
// other browser. We also check to see if we're importing bookmarks because
// we can import bookmark keywords from Firefox as search engines.
if ((items & user_data_importer::SEARCH_ENGINES) ||
(items & user_data_importer::FAVORITES)) {
if (!writer_->TemplateURLServiceIsLoaded()) {
TemplateURLService* model =
TemplateURLServiceFactory::GetForProfile(profile_);
template_service_subscription_ =
model->RegisterOnLoadedCallback(base::BindOnce(
&ExternalProcessImporterHost::OnTemplateURLServiceLoaded,
weak_ptr_factory_.GetWeakPtr()));
model->Load();
}
}
}