// Copyright (c) 2010 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/profile_import/profile_import_thread.h" #include #include "base/values.h" #include "chrome/browser/importer/importer.h" #include "chrome/browser/importer/importer_bridge.h" #include "chrome/browser/importer/importer_data_types.h" #include "chrome/browser/importer/importer_list.h" #include "chrome/browser/importer/importer_messages.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/common/child_process.h" namespace { // Rather than sending all import items over IPC at once we chunk them into // separate requests. This avoids the case of a large import causing // oversized IPC messages. const int kNumBookmarksToSend = 100; const int kNumHistoryRowsToSend = 100; const int kNumFavIconsToSend = 100; } ProfileImportThread::ProfileImportThread() : bridge_(NULL), browser_type_(0), items_to_import_(0), importer_(NULL) { ChildProcess::current()->AddRefProcess(); // Balanced in Cleanup(). } ProfileImportThread::~ProfileImportThread() {} bool ProfileImportThread::OnControlMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ProfileImportThread, msg) IPC_MESSAGE_HANDLER(ProfileImportProcessMsg_StartImport, OnImportStart) IPC_MESSAGE_HANDLER(ProfileImportProcessMsg_CancelImport, OnImportCancel) IPC_MESSAGE_HANDLER(ProfileImportProcessMsg_ReportImportItemFinished, OnImportItemFinished) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void ProfileImportThread::OnImportStart( const ProfileInfo& profile_info, int items, const DictionaryValue& localized_strings, bool import_to_bookmark_bar) { bridge_ = new ExternalProcessImporterBridge(this, localized_strings); scoped_refptr importer_list(new ImporterList); importer_ = importer_list->CreateImporterByType(profile_info.browser_type); if (!importer_) { Send(new ProfileImportProcessHostMsg_Import_Finished(false, "Importer could not be created.")); return; } importer_->set_import_to_bookmark_bar(import_to_bookmark_bar); items_to_import_ = items; // Create worker thread in which importer runs. import_thread_.reset(new base::Thread("import_thread")); base::Thread::Options options; options.message_loop_type = MessageLoop::TYPE_IO; if (!import_thread_->StartWithOptions(options)) { NOTREACHED(); Cleanup(); } import_thread_->message_loop()->PostTask( FROM_HERE, NewRunnableMethod( importer_.get(), &Importer::StartImport, profile_info, items, bridge_)); } void ProfileImportThread::OnImportCancel() { Cleanup(); } void ProfileImportThread::OnImportItemFinished(uint16 item) { items_to_import_ ^= item; // Remove finished item from mask. // If we've finished with all items, notify the browser process. if (items_to_import_ == 0) NotifyEnded(); } void ProfileImportThread::NotifyItemStarted(ImportItem item) { Send(new ProfileImportProcessHostMsg_ImportItem_Started(item)); } void ProfileImportThread::NotifyItemEnded(ImportItem item) { Send(new ProfileImportProcessHostMsg_ImportItem_Finished(item)); } void ProfileImportThread::NotifyStarted() { Send(new ProfileImportProcessHostMsg_Import_Started()); } void ProfileImportThread::NotifyEnded() { Send(new ProfileImportProcessHostMsg_Import_Finished(true, "")); Cleanup(); } void ProfileImportThread::NotifyHistoryImportReady( const std::vector &rows, history::VisitSource visit_source) { Send(new ProfileImportProcessHostMsg_NotifyHistoryImportStart(rows.size())); std::vector::const_iterator it; for (it = rows.begin(); it < rows.end(); it = it + kNumHistoryRowsToSend) { std::vector row_group; std::vector::const_iterator end_group = it + kNumHistoryRowsToSend < rows.end() ? it + kNumHistoryRowsToSend : rows.end(); row_group.assign(it, end_group); Send(new ProfileImportProcessHostMsg_NotifyHistoryImportGroup(row_group, visit_source)); } } void ProfileImportThread::NotifyHomePageImportReady( const GURL& home_page) { NOTIMPLEMENTED(); } void ProfileImportThread::NotifyBookmarksImportReady( const std::vector& bookmarks, const std::wstring& first_folder_name, int options) { Send(new ProfileImportProcessHostMsg_NotifyBookmarksImportStart( first_folder_name, options, bookmarks.size())); std::vector::const_iterator it; for (it = bookmarks.begin(); it < bookmarks.end(); it = it + kNumBookmarksToSend) { std::vector bookmark_group; std::vector::const_iterator end_group = it + kNumBookmarksToSend < bookmarks.end() ? it + kNumBookmarksToSend : bookmarks.end(); bookmark_group.assign(it, end_group); Send(new ProfileImportProcessHostMsg_NotifyBookmarksImportGroup( bookmark_group)); } } void ProfileImportThread::NotifyFavIconsImportReady( const std::vector& fav_icons) { Send(new ProfileImportProcessHostMsg_NotifyFavIconsImportStart( fav_icons.size())); std::vector::const_iterator it; for (it = fav_icons.begin(); it < fav_icons.end(); it = it + kNumFavIconsToSend) { std::vector fav_icons_group; std::vector::const_iterator end_group = std::min(it + kNumFavIconsToSend, fav_icons.end()); fav_icons_group.assign(it, end_group); Send(new ProfileImportProcessHostMsg_NotifyFavIconsImportGroup( fav_icons_group)); } } void ProfileImportThread::NotifyPasswordFormReady( const webkit_glue::PasswordForm& form) { Send(new ProfileImportProcessHostMsg_NotifyPasswordFormReady(form)); } void ProfileImportThread::NotifyKeywordsReady( const std::vector& template_urls, int default_keyword_index, bool unique_on_host_and_path) { std::vector urls; for (size_t i = 0; i < template_urls.size(); ++i) { urls.push_back(*template_urls[i]); } Send(new ProfileImportProcessHostMsg_NotifyKeywordsReady(urls, default_keyword_index, unique_on_host_and_path)); } void ProfileImportThread::Cleanup() { importer_->Cancel(); importer_ = NULL; bridge_ = NULL; ChildProcess::current()->ReleaseProcess(); }