1 // Copyright (c) 2012 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 #include "chrome/browser/importer/external_process_importer_host.h" 6 7 #include "base/bind.h" 8 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 9 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/importer/external_process_importer_client.h" 11 #include "chrome/browser/importer/firefox_profile_lock.h" 12 #include "chrome/browser/importer/importer_lock_dialog.h" 13 #include "chrome/browser/importer/importer_progress_observer.h" 14 #include "chrome/browser/importer/in_process_importer_bridge.h" 15 #include "chrome/browser/search_engines/template_url_service_factory.h" 16 #include "components/bookmarks/browser/bookmark_model.h" 17 #include "components/search_engines/template_url_service.h" 18 #include "content/public/browser/browser_thread.h" 19 20 using content::BrowserThread; 21 22 ExternalProcessImporterHost::ExternalProcessImporterHost() 23 : headless_(false), 24 parent_window_(NULL), 25 observer_(NULL), 26 profile_(NULL), 27 waiting_for_bookmarkbar_model_(false), 28 installed_bookmark_observer_(false), 29 is_source_readable_(true), 30 client_(NULL), 31 items_(0), 32 cancelled_(false), 33 weak_ptr_factory_(this) { 34 } 35 36 void ExternalProcessImporterHost::Cancel() { 37 cancelled_ = true; 38 // There is only a |client_| if the import was started. 39 if (client_) 40 client_->Cancel(); 41 NotifyImportEnded(); // Tells the observer that we're done, and deletes us. 42 } 43 44 void ExternalProcessImporterHost::StartImportSettings( 45 const importer::SourceProfile& source_profile, 46 Profile* target_profile, 47 uint16 items, 48 ProfileWriter* writer) { 49 // We really only support importing from one host at a time. 50 DCHECK(!profile_); 51 DCHECK(target_profile); 52 53 profile_ = target_profile; 54 writer_ = writer; 55 source_profile_ = source_profile; 56 items_ = items; 57 58 if (!CheckForFirefoxLock(source_profile)) { 59 Cancel(); 60 return; 61 } 62 63 CheckForLoadedModels(items); 64 65 LaunchImportIfReady(); 66 } 67 68 void ExternalProcessImporterHost::NotifyImportStarted() { 69 if (observer_) 70 observer_->ImportStarted(); 71 } 72 73 void ExternalProcessImporterHost::NotifyImportItemStarted( 74 importer::ImportItem item) { 75 if (observer_) 76 observer_->ImportItemStarted(item); 77 } 78 79 void ExternalProcessImporterHost::NotifyImportItemEnded( 80 importer::ImportItem item) { 81 if (observer_) 82 observer_->ImportItemEnded(item); 83 } 84 85 void ExternalProcessImporterHost::NotifyImportEnded() { 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 87 firefox_lock_.reset(); 88 if (observer_) 89 observer_->ImportEnded(); 90 delete this; 91 } 92 93 ExternalProcessImporterHost::~ExternalProcessImporterHost() { 94 if (installed_bookmark_observer_) { 95 DCHECK(profile_); 96 BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); 97 } 98 } 99 100 void ExternalProcessImporterHost::LaunchImportIfReady() { 101 if (waiting_for_bookmarkbar_model_ || template_service_subscription_.get() || 102 !is_source_readable_ || cancelled_) 103 return; 104 105 // This is the in-process half of the bridge, which catches data from the IPC 106 // pipe and feeds it to the ProfileWriter. The external process half of the 107 // bridge lives in the external process (see ProfileImportThread). 108 // The ExternalProcessImporterClient created in the next line owns the bridge, 109 // and will delete it. 110 InProcessImporterBridge* bridge = 111 new InProcessImporterBridge(writer_.get(), 112 weak_ptr_factory_.GetWeakPtr()); 113 client_ = new ExternalProcessImporterClient( 114 weak_ptr_factory_.GetWeakPtr(), source_profile_, items_, bridge); 115 client_->Start(); 116 } 117 118 void ExternalProcessImporterHost::BookmarkModelLoaded(BookmarkModel* model, 119 bool ids_reassigned) { 120 DCHECK(model->loaded()); 121 model->RemoveObserver(this); 122 waiting_for_bookmarkbar_model_ = false; 123 installed_bookmark_observer_ = false; 124 125 LaunchImportIfReady(); 126 } 127 128 void ExternalProcessImporterHost::BookmarkModelBeingDeleted( 129 BookmarkModel* model) { 130 installed_bookmark_observer_ = false; 131 } 132 133 void ExternalProcessImporterHost::BookmarkModelChanged() { 134 } 135 136 void ExternalProcessImporterHost::OnTemplateURLServiceLoaded() { 137 template_service_subscription_.reset(); 138 LaunchImportIfReady(); 139 } 140 141 void ExternalProcessImporterHost::ShowWarningDialog() { 142 DCHECK(!headless_); 143 importer::ShowImportLockDialog( 144 parent_window_, 145 base::Bind(&ExternalProcessImporterHost::OnImportLockDialogEnd, 146 weak_ptr_factory_.GetWeakPtr())); 147 } 148 149 void ExternalProcessImporterHost::OnImportLockDialogEnd(bool is_continue) { 150 if (is_continue) { 151 // User chose to continue, then we check the lock again to make 152 // sure that Firefox has been closed. Try to import the settings 153 // if successful. Otherwise, show a warning dialog. 154 firefox_lock_->Lock(); 155 if (firefox_lock_->HasAcquired()) { 156 is_source_readable_ = true; 157 LaunchImportIfReady(); 158 } else { 159 ShowWarningDialog(); 160 } 161 } else { 162 NotifyImportEnded(); 163 } 164 } 165 166 bool ExternalProcessImporterHost::CheckForFirefoxLock( 167 const importer::SourceProfile& source_profile) { 168 if (source_profile.importer_type != importer::TYPE_FIREFOX) 169 return true; 170 171 DCHECK(!firefox_lock_.get()); 172 firefox_lock_.reset(new FirefoxProfileLock(source_profile.source_path)); 173 if (firefox_lock_->HasAcquired()) 174 return true; 175 176 // If fail to acquire the lock, we set the source unreadable and 177 // show a warning dialog, unless running without UI (in which case the import 178 // must be aborted). 179 is_source_readable_ = false; 180 if (headless_) 181 return false; 182 183 ShowWarningDialog(); 184 return true; 185 } 186 187 void ExternalProcessImporterHost::CheckForLoadedModels(uint16 items) { 188 // A target profile must be loaded by StartImportSettings(). 189 DCHECK(profile_); 190 191 // BookmarkModel should be loaded before adding IE favorites. So we observe 192 // the BookmarkModel if needed, and start the task after it has been loaded. 193 if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) { 194 BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); 195 waiting_for_bookmarkbar_model_ = true; 196 installed_bookmark_observer_ = true; 197 } 198 199 // Observes the TemplateURLService if needed to import search engines from the 200 // other browser. We also check to see if we're importing bookmarks because 201 // we can import bookmark keywords from Firefox as search engines. 202 if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) { 203 if (!writer_->TemplateURLServiceIsLoaded()) { 204 TemplateURLService* model = 205 TemplateURLServiceFactory::GetForProfile(profile_); 206 template_service_subscription_ = model->RegisterOnLoadedCallback( 207 base::Bind(&ExternalProcessImporterHost::OnTemplateURLServiceLoaded, 208 weak_ptr_factory_.GetWeakPtr())); 209 model->Load(); 210 } 211 } 212 } 213