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_client.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/importer/external_process_importer_host.h" 11 #include "chrome/browser/importer/in_process_importer_bridge.h" 12 #include "chrome/common/importer/firefox_importer_utils.h" 13 #include "chrome/common/importer/imported_bookmark_entry.h" 14 #include "chrome/common/importer/profile_import_process_messages.h" 15 #include "chrome/grit/generated_resources.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/browser/utility_process_host.h" 18 #include "grit/components_strings.h" 19 #include "ui/base/l10n/l10n_util.h" 20 21 using content::BrowserThread; 22 using content::UtilityProcessHost; 23 24 ExternalProcessImporterClient::ExternalProcessImporterClient( 25 base::WeakPtr<ExternalProcessImporterHost> importer_host, 26 const importer::SourceProfile& source_profile, 27 uint16 items, 28 InProcessImporterBridge* bridge) 29 : total_bookmarks_count_(0), 30 total_history_rows_count_(0), 31 total_favicons_count_(0), 32 process_importer_host_(importer_host), 33 source_profile_(source_profile), 34 items_(items), 35 bridge_(bridge), 36 cancelled_(false) { 37 process_importer_host_->NotifyImportStarted(); 38 } 39 40 void ExternalProcessImporterClient::Start() { 41 AddRef(); // balanced in Cleanup. 42 BrowserThread::ID thread_id; 43 CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id)); 44 BrowserThread::PostTask( 45 BrowserThread::IO, FROM_HERE, 46 base::Bind(&ExternalProcessImporterClient::StartProcessOnIOThread, 47 this, 48 thread_id)); 49 } 50 51 void ExternalProcessImporterClient::Cancel() { 52 if (cancelled_) 53 return; 54 55 cancelled_ = true; 56 BrowserThread::PostTask( 57 BrowserThread::IO, FROM_HERE, 58 base::Bind( 59 &ExternalProcessImporterClient::CancelImportProcessOnIOThread, 60 this)); 61 Release(); 62 } 63 64 void ExternalProcessImporterClient::OnProcessCrashed(int exit_code) { 65 DLOG(ERROR) << __FUNCTION__; 66 if (cancelled_) 67 return; 68 69 // If the host is still around, cancel the import; otherwise it means the 70 // import was already cancelled or completed and this message can be dropped. 71 if (process_importer_host_.get()) 72 process_importer_host_->Cancel(); 73 } 74 75 bool ExternalProcessImporterClient::OnMessageReceived( 76 const IPC::Message& message) { 77 bool handled = true; 78 IPC_BEGIN_MESSAGE_MAP(ExternalProcessImporterClient, message) 79 // Notification messages about the state of the import process. 80 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_Import_Started, 81 OnImportStart) 82 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_Import_Finished, 83 OnImportFinished) 84 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_ImportItem_Started, 85 OnImportItemStart) 86 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_ImportItem_Finished, 87 OnImportItemFinished) 88 // Data messages containing items to be written to the user profile. 89 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHistoryImportStart, 90 OnHistoryImportStart) 91 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHistoryImportGroup, 92 OnHistoryImportGroup) 93 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHomePageImportReady, 94 OnHomePageImportReady) 95 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyBookmarksImportStart, 96 OnBookmarksImportStart) 97 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyBookmarksImportGroup, 98 OnBookmarksImportGroup) 99 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFaviconsImportStart, 100 OnFaviconsImportStart) 101 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFaviconsImportGroup, 102 OnFaviconsImportGroup) 103 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyPasswordFormReady, 104 OnPasswordFormImportReady) 105 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyKeywordsReady, 106 OnKeywordsImportReady) 107 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFirefoxSearchEngData, 108 OnFirefoxSearchEngineDataReceived) 109 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_AutofillFormDataImportStart, 110 OnAutofillFormDataImportStart) 111 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_AutofillFormDataImportGroup, 112 OnAutofillFormDataImportGroup) 113 #if defined(OS_WIN) 114 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyIE7PasswordInfo, 115 OnIE7PasswordReceived) 116 #endif 117 IPC_MESSAGE_UNHANDLED(handled = false) 118 IPC_END_MESSAGE_MAP() 119 return handled; 120 } 121 122 void ExternalProcessImporterClient::OnImportStart() { 123 if (cancelled_) 124 return; 125 126 bridge_->NotifyStarted(); 127 } 128 129 void ExternalProcessImporterClient::OnImportFinished( 130 bool succeeded, const std::string& error_msg) { 131 if (cancelled_) 132 return; 133 134 if (!succeeded) 135 LOG(WARNING) << "Import failed. Error: " << error_msg; 136 Cleanup(); 137 } 138 139 void ExternalProcessImporterClient::OnImportItemStart(int item_data) { 140 if (cancelled_) 141 return; 142 143 bridge_->NotifyItemStarted(static_cast<importer::ImportItem>(item_data)); 144 } 145 146 void ExternalProcessImporterClient::OnImportItemFinished(int item_data) { 147 if (cancelled_) 148 return; 149 150 importer::ImportItem import_item = 151 static_cast<importer::ImportItem>(item_data); 152 bridge_->NotifyItemEnded(import_item); 153 BrowserThread::PostTask( 154 BrowserThread::IO, FROM_HERE, 155 base::Bind(&ExternalProcessImporterClient::NotifyItemFinishedOnIOThread, 156 this, 157 import_item)); 158 } 159 160 void ExternalProcessImporterClient::OnHistoryImportStart( 161 size_t total_history_rows_count) { 162 if (cancelled_) 163 return; 164 165 total_history_rows_count_ = total_history_rows_count; 166 history_rows_.reserve(total_history_rows_count); 167 } 168 169 void ExternalProcessImporterClient::OnHistoryImportGroup( 170 const std::vector<ImporterURLRow>& history_rows_group, 171 int visit_source) { 172 if (cancelled_) 173 return; 174 175 history_rows_.insert(history_rows_.end(), history_rows_group.begin(), 176 history_rows_group.end()); 177 if (history_rows_.size() == total_history_rows_count_) 178 bridge_->SetHistoryItems(history_rows_, 179 static_cast<importer::VisitSource>(visit_source)); 180 } 181 182 void ExternalProcessImporterClient::OnHomePageImportReady( 183 const GURL& home_page) { 184 if (cancelled_) 185 return; 186 187 bridge_->AddHomePage(home_page); 188 } 189 190 void ExternalProcessImporterClient::OnBookmarksImportStart( 191 const base::string16& first_folder_name, 192 size_t total_bookmarks_count) { 193 if (cancelled_) 194 return; 195 196 bookmarks_first_folder_name_ = first_folder_name; 197 total_bookmarks_count_ = total_bookmarks_count; 198 bookmarks_.reserve(total_bookmarks_count); 199 } 200 201 void ExternalProcessImporterClient::OnBookmarksImportGroup( 202 const std::vector<ImportedBookmarkEntry>& bookmarks_group) { 203 if (cancelled_) 204 return; 205 206 // Collect sets of bookmarks from importer process until we have reached 207 // total_bookmarks_count_: 208 bookmarks_.insert(bookmarks_.end(), bookmarks_group.begin(), 209 bookmarks_group.end()); 210 if (bookmarks_.size() == total_bookmarks_count_) 211 bridge_->AddBookmarks(bookmarks_, bookmarks_first_folder_name_); 212 } 213 214 void ExternalProcessImporterClient::OnFaviconsImportStart( 215 size_t total_favicons_count) { 216 if (cancelled_) 217 return; 218 219 total_favicons_count_ = total_favicons_count; 220 favicons_.reserve(total_favicons_count); 221 } 222 223 void ExternalProcessImporterClient::OnFaviconsImportGroup( 224 const std::vector<ImportedFaviconUsage>& favicons_group) { 225 if (cancelled_) 226 return; 227 228 favicons_.insert(favicons_.end(), favicons_group.begin(), 229 favicons_group.end()); 230 if (favicons_.size() == total_favicons_count_) 231 bridge_->SetFavicons(favicons_); 232 } 233 234 void ExternalProcessImporterClient::OnPasswordFormImportReady( 235 const autofill::PasswordForm& form) { 236 if (cancelled_) 237 return; 238 239 bridge_->SetPasswordForm(form); 240 } 241 242 void ExternalProcessImporterClient::OnKeywordsImportReady( 243 const std::vector<importer::URLKeywordInfo>& url_keywords, 244 bool unique_on_host_and_path) { 245 if (cancelled_) 246 return; 247 bridge_->SetKeywords(url_keywords, unique_on_host_and_path); 248 } 249 250 void ExternalProcessImporterClient::OnFirefoxSearchEngineDataReceived( 251 const std::vector<std::string> search_engine_data) { 252 if (cancelled_) 253 return; 254 bridge_->SetFirefoxSearchEnginesXMLData(search_engine_data); 255 } 256 257 void ExternalProcessImporterClient::OnAutofillFormDataImportStart( 258 size_t total_autofill_form_data_entry_count) { 259 if (cancelled_) 260 return; 261 262 total_autofill_form_data_entry_count_ = total_autofill_form_data_entry_count; 263 autofill_form_data_.reserve(total_autofill_form_data_entry_count); 264 } 265 266 void ExternalProcessImporterClient::OnAutofillFormDataImportGroup( 267 const std::vector<ImporterAutofillFormDataEntry>& 268 autofill_form_data_entry_group) { 269 if (cancelled_) 270 return; 271 272 autofill_form_data_.insert(autofill_form_data_.end(), 273 autofill_form_data_entry_group.begin(), 274 autofill_form_data_entry_group.end()); 275 if (autofill_form_data_.size() == total_autofill_form_data_entry_count_) 276 bridge_->SetAutofillFormData(autofill_form_data_); 277 } 278 279 #if defined(OS_WIN) 280 void ExternalProcessImporterClient::OnIE7PasswordReceived( 281 const importer::ImporterIE7PasswordInfo& importer_password_info) { 282 if (cancelled_) 283 return; 284 bridge_->AddIE7PasswordInfo(importer_password_info); 285 } 286 #endif 287 288 ExternalProcessImporterClient::~ExternalProcessImporterClient() {} 289 290 void ExternalProcessImporterClient::Cleanup() { 291 if (cancelled_) 292 return; 293 294 if (process_importer_host_.get()) 295 process_importer_host_->NotifyImportEnded(); 296 Release(); 297 } 298 299 void ExternalProcessImporterClient::CancelImportProcessOnIOThread() { 300 if (utility_process_host_.get()) 301 utility_process_host_->Send(new ProfileImportProcessMsg_CancelImport()); 302 } 303 304 void ExternalProcessImporterClient::NotifyItemFinishedOnIOThread( 305 importer::ImportItem import_item) { 306 utility_process_host_->Send( 307 new ProfileImportProcessMsg_ReportImportItemFinished(import_item)); 308 } 309 310 void ExternalProcessImporterClient::StartProcessOnIOThread( 311 BrowserThread::ID thread_id) { 312 utility_process_host_ = UtilityProcessHost::Create( 313 this, BrowserThread::GetMessageLoopProxyForThread(thread_id).get()) 314 ->AsWeakPtr(); 315 utility_process_host_->DisableSandbox(); 316 317 #if defined(OS_MACOSX) 318 base::EnvironmentMap env; 319 std::string dylib_path = GetFirefoxDylibPath().value(); 320 if (!dylib_path.empty()) 321 env["DYLD_FALLBACK_LIBRARY_PATH"] = dylib_path; 322 utility_process_host_->SetEnv(env); 323 #endif 324 325 // Dictionary of all localized strings that could be needed by the importer 326 // in the external process. 327 base::DictionaryValue localized_strings; 328 localized_strings.SetString( 329 base::IntToString(IDS_BOOKMARK_GROUP), 330 l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP)); 331 localized_strings.SetString( 332 base::IntToString(IDS_BOOKMARK_GROUP_FROM_FIREFOX), 333 l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP_FROM_FIREFOX)); 334 localized_strings.SetString( 335 base::IntToString(IDS_BOOKMARK_GROUP_FROM_SAFARI), 336 l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP_FROM_SAFARI)); 337 localized_strings.SetString( 338 base::IntToString(IDS_IMPORT_FROM_FIREFOX), 339 l10n_util::GetStringUTF8(IDS_IMPORT_FROM_FIREFOX)); 340 localized_strings.SetString( 341 base::IntToString(IDS_IMPORT_FROM_ICEWEASEL), 342 l10n_util::GetStringUTF8(IDS_IMPORT_FROM_ICEWEASEL)); 343 localized_strings.SetString( 344 base::IntToString(IDS_IMPORT_FROM_SAFARI), 345 l10n_util::GetStringUTF8(IDS_IMPORT_FROM_SAFARI)); 346 localized_strings.SetString( 347 base::IntToString(IDS_BOOKMARK_BAR_FOLDER_NAME), 348 l10n_util::GetStringUTF8(IDS_BOOKMARK_BAR_FOLDER_NAME)); 349 350 utility_process_host_->Send(new ProfileImportProcessMsg_StartImport( 351 source_profile_, items_, localized_strings)); 352 } 353