diff --git a/DEPS b/DEPS index 9e7cd4c..9b9bb21 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '72d17915df27ddf10d504f76be379a560820fd01', + 'v8_revision': 'c76bb271ec40c918ff43ee111dccd027397e854e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '302cd78d00c280cb212a5934a7a8293851e9650c', + 'pdfium_revision': 'ef002c85521278e3082517297cf60372d7751cb1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other.
diff --git a/ash/system/audio/volume_view.cc b/ash/system/audio/volume_view.cc index efbdd2f..c7ed0f3 100644 --- a/ash/system/audio/volume_view.cc +++ b/ash/system/audio/volume_view.cc
@@ -20,6 +20,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icon_types.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/button/custom_button.h" @@ -130,7 +131,9 @@ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VOLUME)); tri_view_->AddView(TriView::Container::CENTER, slider_); - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); + set_background(views::Background::CreateThemedSolidBackground( + this, ui::NativeTheme::kColorId_BubbleBackground)); + Update(); }
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc index 5c963cf..1857750 100644 --- a/ash/system/tray/system_tray.cc +++ b/ash/system/tray/system_tray.cc
@@ -64,6 +64,7 @@ #include "ui/gfx/skia_util.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_style.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" #include "ui/views/view.h" @@ -472,7 +473,6 @@ // This is the case where a volume control or brightness control bubble // is created. init_params.max_height = default_bubble_height_; - init_params.bg_color = kBackgroundColor; } else { init_params.bg_color = kHeaderBackgroundColor; }
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc index c3ae671b..0ce7b54 100644 --- a/ash/system/tray/tray_constants.cc +++ b/ash/system/tray/tray_constants.cc
@@ -64,7 +64,6 @@ const int kTrayToggleButtonWidth = 68; -const SkColor kBackgroundColor = SK_ColorWHITE; const SkColor kPublicAccountUserCardTextColor = SkColorSetRGB(0x66, 0x66, 0x66); const SkColor kPublicAccountUserCardNameColor = SK_ColorBLACK;
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h index f2977a34..952dd005 100644 --- a/ash/system/tray/tray_constants.h +++ b/ash/system/tray/tray_constants.h
@@ -77,7 +77,6 @@ // The width of ToggleButton views including any border padding. extern const int kTrayToggleButtonWidth; -extern const SkColor kBackgroundColor; extern const SkColor kPublicAccountUserCardTextColor; extern const SkColor kPublicAccountUserCardNameColor;
diff --git a/ash/system/tray/tray_details_view.cc b/ash/system/tray/tray_details_view.cc index fee3c72..4098c86 100644 --- a/ash/system/tray/tray_details_view.cc +++ b/ash/system/tray/tray_details_view.cc
@@ -21,6 +21,7 @@ #include "ui/compositor/paint_recorder.h" #include "ui/gfx/canvas.h" #include "ui/gfx/skia_paint_util.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" @@ -238,7 +239,8 @@ tri_view_(nullptr), back_button_(nullptr) { SetLayoutManager(box_layout_); - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); + set_background(views::Background::CreateThemedSolidBackground( + this, ui::NativeTheme::kColorId_BubbleBackground)); } TrayDetailsView::~TrayDetailsView() {} @@ -295,8 +297,8 @@ // Make the |scroller_| have a layer to clip |scroll_content_|'s children. // TODO(varkha): Make the sticky rows work with EnableViewPortLayer(). scroller_->SetPaintToLayer(); - scroller_->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); + scroller_->set_background(views::Background::CreateThemedSolidBackground( + scroller_, ui::NativeTheme::kColorId_BubbleBackground)); scroller_->layer()->SetMasksToBounds(true); AddChildView(scroller_);
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc index d5bdd0a6..39d3200 100644 --- a/ash/system/tray/tray_popup_utils.cc +++ b/ash/system/tray/tray_popup_utils.cc
@@ -21,6 +21,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" @@ -226,9 +227,8 @@ // Frequently the label will paint to a layer that's non-opaque, so subpixel // rendering won't work unless we explicitly set a background. See // crbug.com/686363 - label->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); - label->SetBackgroundColor(kBackgroundColor); + label->set_background(views::Background::CreateThemedSolidBackground( + label, ui::NativeTheme::kColorId_BubbleBackground)); return label; } @@ -287,8 +287,8 @@ void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) { view->set_id(VIEW_ID_STICKY_HEADER); - view->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); + view->set_background(views::Background::CreateThemedSolidBackground( + view, ui::NativeTheme::kColorId_BubbleBackground)); view->SetBorder( views::CreateEmptyBorder(gfx::Insets(kMenuSeparatorVerticalPadding, 0))); view->SetPaintToLayer();
diff --git a/ash/system/tray_accessibility.cc b/ash/system/tray_accessibility.cc index bf12a2d..94f2db9 100644 --- a/ash/system/tray_accessibility.cc +++ b/ash/system/tray_accessibility.cc
@@ -27,6 +27,7 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/native_theme/native_theme.h" #include "ui/resources/grit/ui_resources.h" #include "ui/views/background.h" #include "ui/views/controls/button/custom_button.h" @@ -130,7 +131,8 @@ : label_(CreateLabel(enabled_state_bits)) {} void AccessibilityPopupView::Init() { - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); + set_background(views::Background::CreateThemedSolidBackground( + this, ui::NativeTheme::kColorId_BubbleBackground)); views::GridLayout* layout = new views::GridLayout(this); SetLayoutManager(layout);
diff --git a/ash/system/user/user_card_view.cc b/ash/system/user/user_card_view.cc index 93034cb..bd77ef93 100644 --- a/ash/system/user/user_card_view.cc +++ b/ash/system/user/user_card_view.cc
@@ -293,7 +293,8 @@ layout->set_cross_axis_alignment( views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); + set_background(views::Background::CreateThemedSolidBackground( + this, ui::NativeTheme::kColorId_BubbleBackground)); Shell::Get()->media_controller()->AddObserver(this);
diff --git a/ash/system/user/user_view.cc b/ash/system/user/user_view.cc index 7bdb4782..56a7729 100644 --- a/ash/system/user/user_view.cc +++ b/ash/system/user/user_view.cc
@@ -37,6 +37,7 @@ #include "ui/gfx/color_utils.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/label.h" #include "ui/views/controls/separator.h" @@ -73,8 +74,7 @@ } // Creates the view shown in the user switcher popup ("AddUserMenuOption"). -views::View* CreateAddUserView(AddUserSessionPolicy policy, - views::ButtonListener* listener) { +views::View* CreateAddUserView(AddUserSessionPolicy policy) { auto* view = new views::View; const int icon_padding = (kMenuButtonSize - kMenuIconSize) / 2; auto* layout = @@ -82,8 +82,8 @@ kTrayPopupLabelHorizontalPadding + icon_padding); layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); view->SetLayoutManager(layout); - view->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); + view->set_background(views::Background::CreateThemedSolidBackground( + view, ui::NativeTheme::kColorId_BubbleBackground)); int message_id = 0; switch (policy) { @@ -124,13 +124,6 @@ view->SetBorder(views::CreateEmptyBorder(vertical_padding, icon_padding, vertical_padding, kTrayPopupLabelHorizontalPadding)); - if (policy == AddUserSessionPolicy::ALLOWED) { - auto* button = - new ButtonFromView(view, listener, TrayPopupInkDropStyle::INSET_BOUNDS); - button->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT)); - return button; - } return view; } @@ -228,11 +221,11 @@ } UserView::~UserView() { - RemoveAddUserMenuOption(); + HideUserDropdownWidget(); } TrayUser::TestState UserView::GetStateForTest() const { - if (add_menu_option_) + if (user_dropdown_widget_) return add_user_enabled_ ? TrayUser::ACTIVE : TrayUser::ACTIVE_BUT_DISABLED; // If the container is the user card view itself, there's no ButtonFromView @@ -257,13 +250,13 @@ void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) { if (sender == logout_button_) { ShellPort::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_SIGN_OUT); - RemoveAddUserMenuOption(); + HideUserDropdownWidget(); Shell::Get()->system_tray_controller()->SignOut(); } else if (sender == user_card_container_ && IsMultiProfileSupportedAndUserActive()) { - ToggleAddUserMenuOption(); - } else if (add_menu_option_ && - sender->GetWidget() == add_menu_option_.get()) { + ToggleUserDropdownWidget(); + } else if (user_dropdown_widget_ && + sender->GetWidget() == user_dropdown_widget_.get()) { DCHECK_EQ(Shell::Get()->session_controller()->NumberOfLoggedInUsers(), sender->parent()->child_count() - 1); const int index_in_add_menu = sender->parent()->GetIndexOf(sender); @@ -275,7 +268,7 @@ const int user_index = index_in_add_menu; SwitchUser(user_index); } - RemoveAddUserMenuOption(); + HideUserDropdownWidget(); owner_->system_tray()->CloseSystemBubble(); } else { NOTREACHED(); @@ -284,7 +277,7 @@ void UserView::OnWillChangeFocus(View* focused_before, View* focused_now) { if (focused_now) - RemoveAddUserMenuOption(); + HideUserDropdownWidget(); } void UserView::OnDidChangeFocus(View* focused_before, View* focused_now) { @@ -314,16 +307,16 @@ AddChildViewAt(user_card_container_, 0); } -void UserView::ToggleAddUserMenuOption() { - if (add_menu_option_) { - RemoveAddUserMenuOption(); +void UserView::ToggleUserDropdownWidget() { + if (user_dropdown_widget_) { + HideUserDropdownWidget(); return; } // Note: We do not need to install a global event handler to delete this // item since it will destroyed automatically before the menu / user menu item // gets destroyed.. - add_menu_option_.reset(new views::Widget); + user_dropdown_widget_.reset(new views::Widget); views::Widget::InitParams params; params.type = views::Widget::InitParams::TYPE_MENU; params.keep_on_top = true; @@ -334,9 +327,9 @@ WmWindow::Get(GetWidget()->GetNativeWindow()) ->GetRootWindowController() ->ConfigureWidgetInitParamsForContainer( - add_menu_option_.get(), kShellWindowId_DragImageAndTooltipContainer, - ¶ms); - add_menu_option_->Init(params); + user_dropdown_widget_.get(), + kShellWindowId_DragImageAndTooltipContainer, ¶ms); + user_dropdown_widget_->Init(params); const SessionController* const session_controller = Shell::Get()->session_controller(); @@ -352,48 +345,63 @@ int row_height = bounds.height(); views::View* container = new UserDropdownWidgetContents( - base::Bind(&UserView::RemoveAddUserMenuOption, base::Unretained(this))); + base::Bind(&UserView::HideUserDropdownWidget, base::Unretained(this))); + views::View* add_user_view = CreateAddUserView(add_user_policy); + const SkColor bg_color = add_user_view->background()->get_color(); container->SetBorder(views::CreatePaddedBorder( - views::CreateSolidSidedBorder(0, 0, 0, kSeparatorWidth, kBackgroundColor), + views::CreateSolidSidedBorder(0, 0, 0, kSeparatorWidth, bg_color), gfx::Insets(row_height, 0, 0, 0))); + + // Create the contents aside from the empty window through which the active + // user is seen. views::View* user_dropdown_padding = new views::View(); user_dropdown_padding->SetBorder(views::CreateSolidSidedBorder( - kMenuSeparatorVerticalPadding - kSeparatorWidth, 0, 0, 0, - kBackgroundColor)); + kMenuSeparatorVerticalPadding - kSeparatorWidth, 0, 0, 0, bg_color)); user_dropdown_padding->SetLayoutManager( new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); views::Separator* separator = new views::Separator(); separator->SetPreferredHeight(kSeparatorWidth); - separator->SetColor(color_utils::GetResultingPaintColor(kMenuSeparatorColor, - kBackgroundColor)); + separator->SetColor( + color_utils::GetResultingPaintColor(kMenuSeparatorColor, bg_color)); const int separator_horizontal_padding = (kTrayPopupItemMinStartWidth - kTrayItemSize) / 2; - separator->SetBorder(views::CreateSolidSidedBorder( - 0, separator_horizontal_padding, 0, separator_horizontal_padding, - kBackgroundColor)); + separator->SetBorder( + views::CreateSolidSidedBorder(0, separator_horizontal_padding, 0, + separator_horizontal_padding, bg_color)); user_dropdown_padding->AddChildView(separator); + // Add other logged in users. for (int i = 1; i < session_controller->NumberOfLoggedInUsers(); ++i) { user_dropdown_padding->AddChildView( new ButtonFromView(new UserCardView(LoginStatus::USER, i), this, TrayPopupInkDropStyle::INSET_BOUNDS)); } - user_dropdown_padding->AddChildView(CreateAddUserView(add_user_policy, this)); + // Add the "add user" option or the "can't add another user" message. + if (add_user_enabled_) { + auto* button = new ButtonFromView(add_user_view, this, + TrayPopupInkDropStyle::INSET_BOUNDS); + button->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT)); + user_dropdown_padding->AddChildView(button); + } else { + user_dropdown_padding->AddChildView(add_user_view); + } + container->AddChildView(user_dropdown_padding); container->SetLayoutManager(new views::FillLayout()); - add_menu_option_->SetContentsView(container); + user_dropdown_widget_->SetContentsView(container); bounds.set_height(container->GetPreferredSize().height()); - add_menu_option_->SetBounds(bounds); + user_dropdown_widget_->SetBounds(bounds); // Suppress the appearance of the collective capture icon while the dropdown // is open (the icon will appear in the specific user rows). user_card_view_->SetSuppressCaptureIcon(true); // Show the content. - add_menu_option_->SetAlwaysOnTop(true); - add_menu_option_->Show(); + user_dropdown_widget_->SetAlwaysOnTop(true); + user_dropdown_widget_->Show(); // Install a listener to focus changes so that we can remove the card when // the focus gets changed. When called through the destruction of the bubble, @@ -402,15 +410,15 @@ focus_manager_->AddFocusChangeListener(this); } -void UserView::RemoveAddUserMenuOption() { - if (!add_menu_option_) +void UserView::HideUserDropdownWidget() { + if (!user_dropdown_widget_) return; focus_manager_->RemoveFocusChangeListener(this); focus_manager_ = nullptr; if (user_card_container_->GetFocusManager()) user_card_container_->GetFocusManager()->ClearFocus(); user_card_view_->SetSuppressCaptureIcon(false); - add_menu_option_.reset(); + user_dropdown_widget_.reset(); } } // namespace tray
diff --git a/ash/system/user/user_view.h b/ash/system/user/user_view.h index 535a4b5..de498772 100644 --- a/ash/system/user/user_view.h +++ b/ash/system/user/user_view.h
@@ -62,10 +62,10 @@ // Create the menu option to add another user. If |disabled| is set the user // cannot actively click on the item. - void ToggleAddUserMenuOption(); + void ToggleUserDropdownWidget(); // Removes the add user menu option. - void RemoveAddUserMenuOption(); + void HideUserDropdownWidget(); // If |user_card_view_| is clickable, this is a ButtonFromView that wraps it. // If |user_card_view_| is not clickable, this will be equal to @@ -79,7 +79,7 @@ SystemTrayItem* owner_; views::View* logout_button_ = nullptr; - std::unique_ptr<views::Widget> add_menu_option_; + std::unique_ptr<views::Widget> user_dropdown_widget_; // False when the add user panel is visible but not activatable. bool add_user_enabled_ = true;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index e94aab1..090e98d8 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -342,7 +342,6 @@ "//components/policy:generated", "//content/app/resources", "//crypto", - "//headless:headless_shell_browser_lib", "//net:net_resources", "//ppapi/features", "//third_party/cld", @@ -433,7 +432,6 @@ "//components/browser_watcher:browser_watcher_client", "//components/crash/content/app", "//content/public/app:child", - "//headless:headless_shell_child_lib", ] ldflags = [
diff --git a/chrome/VERSION b/chrome/VERSION index fb1e6e7..8af47d7 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=60 MINOR=0 -BUILD=3080 +BUILD=3081 PATCH=0
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc index 3ac247f..2cc37702 100644 --- a/chrome/app/chrome_main.cc +++ b/chrome/app/chrome_main.cc
@@ -89,20 +89,22 @@ #else params.argc = argc; params.argv = argv; +#endif + +#if !defined(OS_WIN) base::CommandLine::Init(params.argc, params.argv); -#endif // defined(OS_WIN) - base::CommandLine::Init(0, nullptr); const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess()); ALLOW_UNUSED_LOCAL(command_line); +#endif -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +#if defined(OS_LINUX) || defined(OS_MACOSX) if (command_line->HasSwitch(switches::kHeadless)) { #if defined(OS_MACOSX) SetUpBundleOverrides(); #endif - return headless::HeadlessShellMain(params); + return headless::HeadlessShellMain(argc, argv); } -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) #if defined(OS_CHROMEOS) && BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES) version_info::Channel channel = chrome::GetChannel();
diff --git a/chrome/browser/android/offline_pages/request_coordinator_factory.cc b/chrome/browser/android/offline_pages/request_coordinator_factory.cc index 2384675..d4bdbb4 100644 --- a/chrome/browser/android/offline_pages/request_coordinator_factory.cc +++ b/chrome/browser/android/offline_pages/request_coordinator_factory.cc
@@ -9,7 +9,7 @@ #include "base/memory/ptr_util.h" #include "base/memory/singleton.h" #include "base/sequenced_task_runner.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "chrome/browser/android/offline_pages/background_loader_offliner.h" #include "chrome/browser/android/offline_pages/background_scheduler_bridge.h" #include "chrome/browser/android/offline_pages/downloads/offline_page_notification_bridge.h" @@ -29,7 +29,6 @@ #include "components/offline_pages/core/background/scheduler.h" #include "components/offline_pages/core/downloads/download_notifying_observer.h" #include "components/offline_pages/core/offline_page_feature.h" -#include "content/public/browser/browser_thread.h" #include "net/nqe/network_quality_estimator.h" namespace offline_pages { @@ -68,8 +67,9 @@ } scoped_refptr<base::SequencedTaskRunner> background_task_runner = - content::BrowserThread::GetBlockingPool()->GetSequencedTaskRunner( - content::BrowserThread::GetBlockingPool()->GetSequenceToken()); + base::CreateSequencedTaskRunnerWithTraits( + base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND)); Profile* profile = Profile::FromBrowserContext(context); base::FilePath queue_store_path = profile->GetPath().Append(chrome::kOfflinePageRequestQueueDirname);
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc index f3a95676..5bbb9309 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc +++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.cc
@@ -13,7 +13,7 @@ #include "base/strings/string_util.h" #include "base/sys_info.h" #include "base/task_runner_util.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "base/values.h" #include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h" #include "chrome/browser/chromeos/login/supervised/supervised_user_constants.h" @@ -31,7 +31,6 @@ #include "components/signin/core/account_id/account_id.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" -#include "content/public/browser/browser_thread.h" #include "crypto/random.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -348,9 +347,12 @@ creation_context_->token = token; PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool() - ->GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN) + base::CreateTaskRunnerWithTraits( + base::TaskTraits() + .MayBlock() + .WithPriority(base::TaskPriority::BACKGROUND) + .WithShutdownBehavior( + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)) .get(), FROM_HERE, base::Bind(&StoreSupervisedUserFiles, creation_context_->token,
diff --git a/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc b/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc index baf1eeb9..950731d 100644 --- a/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc
@@ -10,7 +10,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h" @@ -516,9 +516,12 @@ base::FilePath profile_dir = ProfileHelper::GetProfilePathByUserIdHash( ProfileHelper::Get()->GetUserByProfile(profile)->username_hash()); PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool() - ->GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN) + base::CreateTaskRunnerWithTraits( + base::TaskTraits() + .MayBlock() + .WithPriority(base::TaskPriority::BACKGROUND) + .WithShutdownBehavior( + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)) .get(), FROM_HERE, base::Bind(&LoadSyncToken, profile_dir), callback); }
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer.cc b/chrome/browser/component_updater/subresource_filter_component_installer.cc index 0b3ff98..a7635db 100644 --- a/chrome/browser/component_updater/subresource_filter_component_installer.cc +++ b/chrome/browser/component_updater/subresource_filter_component_installer.cc
@@ -112,8 +112,9 @@ // static std::string SubresourceFilterComponentInstallerTraits::GetInstallerTag() { - std::string ruleset_flavor = - subresource_filter::GetActiveConfiguration().ruleset_flavor; + std::string ruleset_flavor = subresource_filter::GetActiveConfigurations() + ->the_one_and_only() + .ruleset_flavor; if (ruleset_flavor.empty()) return ruleset_flavor;
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html index 4154a5c..0dc89c8 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html
@@ -20,8 +20,7 @@ <paper-button class="cancel-button" on-tap="onCancelTap_"> $i18n{cancel} </paper-button> - <paper-button id="ok" class="action-button" on-tap="onOkTap_" - disabled="[[!password_.length]]"> + <paper-button id="ok" class="action-button" on-tap="onOkTap_"> $i18n{ok} </paper-button> </div>
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html index c05c572..f19514a3 100644 --- a/chrome/browser/resources/settings/search_page/search_page.html +++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -80,7 +80,7 @@ <template is="dom-if" if="[[hotwordInfo_.allowed]]"> <!-- Hotword (OK Google) --> - <div class="settings-box two-line continuation"> + <div class="settings-box two-line continuation indented"> <settings-toggle-button id="hotwordSearchEnable" class="start" pref="{{hotwordSearchEnablePref_}}" label="$i18n{searchOkGoogleLabel}"
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html index 8e1c38e..5204d006 100644 --- a/chrome/browser/resources/settings/settings_shared_css.html +++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -334,7 +334,11 @@ align-items: center; display: flex; flex-shrink: 0; - height: var(--settings-row-min-height); + height: 36px; + } + + :-webkit-any(.settings-box, .list-item).two-line .secondary-action { + height: 46px; } /* Helper for a list frame to automatically avoid the separator line. */
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html index 5d84fea2..0564325 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.html +++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -18,11 +18,6 @@ <dom-module id="site-list"> <template> <style include="settings-shared"> - paper-icon-button { - left: 8px; - right: 8px; - } - .selectable { -webkit-user-select: text; } @@ -66,17 +61,30 @@ </div> <div class="list-frame menu-content vertical-list" id="listContainer"> <template is="dom-repeat" items="[[sites]]"> - <div class="list-item" actionable$="[[enableSiteSettings_]]" - on-tap="onOriginTap_"> - <div class="favicon-image" - style$="[[computeSiteIcon(item.origin)]]"> - </div> - <div class="middle no-min-width"> - <div class="selectable text-elide">[[item.displayName]]</div> + <div class="list-item"> + <div class="layout horizontal center flex" + actionable$="[[enableSiteSettings_]]" on-tap="onOriginTap_"> + <div class="favicon-image" + style$="[[computeSiteIcon(item.origin)]]"> + </div> + <div class="middle no-min-width"> + <div class="selectable text-elide">[[item.displayName]]</div> - <!-- This div must not contain extra whitespace. --> - <div class="selectable secondary text-elide" id="siteDescription" - >[[computeSiteDescription_(item)]]</div> + <!-- This div must not contain extra whitespace. --> + <div class="selectable secondary text-elide" + id="siteDescription">[[computeSiteDescription_(item)]]</div> + </div> + <template is="dom-if" if="[[enableSiteSettings_]]"> + <div on-tap="onOriginTap_" actionable> + <button class="subpage-arrow" is="paper-icon-button-light" + aria-label$="[[item.displayName]]" + aria-describedby="siteDescription"></button> + </div> + <!-- This div is intentionally empty. It creates a vertical grey + bar. This can be merged into the html that follows this + template after the |enableSiteSettings_| is removed. --> + <div class="secondary-action"></div> + </template> </div> <template is="dom-if" if="[[item.controlledBy]]"> <cr-policy-pref-indicator pref="[[item]]" @@ -87,19 +95,14 @@ <paper-icon-button id="resetSite" icon="cr:delete" hidden="[[isResetButtonHidden_( item.enforcement, readOnlyList)]]" - on-tap="onResetButtonTap_" alt="$i18n{siteSettingsActionReset}"> + on-tap="onResetButtonTap_" + alt="$i18n{siteSettingsActionReset}"> </paper-icon-button> <paper-icon-button id="actionMenuButton" icon="cr:more-vert" - hidden="[[isActionMenuHidden_(item.enforcement, readOnlyList)]]" + hidden= + "[[isActionMenuHidden_(item.enforcement, readOnlyList)]]" on-tap="onShowActionMenuTap_" title="$i18n{moreActions}"> </paper-icon-button> - <template is="dom-if" if="[[enableSiteSettings_]]"> - <div on-tap="onOriginTap_" actionable> - <button class="subpage-arrow" is="paper-icon-button-light" - aria-label$="[[item.displayName]]" - aria-describedby="siteDescription"></button> - </div> - </template> </div> </template> </div>
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index d21988ce..ab5ca80 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -60,7 +60,6 @@ #include "components/safe_browsing_db/v4_feature_list.h" #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h" #include "components/safe_browsing_db/v4_protocol_manager_util.h" -#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h" #include "components/subresource_filter/core/common/test_ruleset_creator.h" @@ -930,10 +929,6 @@ WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - auto* driver_factory = subresource_filter:: - ContentSubresourceFilterDriverFactory::FromWebContents(web_contents); - driver_factory->set_configuration_for_testing( - subresource_filter::GetActiveConfiguration()); // Navigation to a phishing page should trigger an interstitial. If the user // clicks through it, the page load should proceed, but with subresource @@ -2004,10 +1999,6 @@ WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - auto* driver_factory = subresource_filter:: - ContentSubresourceFilterDriverFactory::FromWebContents(web_contents); - driver_factory->set_configuration_for_testing( - subresource_filter::GetActiveConfiguration()); // Navigation to a phishing page should trigger an interstitial. If the user // clicks through it, the page load should proceed, but with subresource
diff --git a/chrome/browser/site_per_process_interactive_browsertest.cc b/chrome/browser/site_per_process_interactive_browsertest.cc index d3598fa..15a7953 100644 --- a/chrome/browser/site_per_process_interactive_browsertest.cc +++ b/chrome/browser/site_per_process_interactive_browsertest.cc
@@ -327,7 +327,7 @@ EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); } -#if (defined(OS_LINUX) && !defined(USE_OZONE)) +#if (defined(OS_LINUX) && !defined(USE_OZONE)) || defined(OS_WIN) // Ensures that renderers know to advance focus to sibling frames and parent // frames in the presence of mouse click initiated focus changes. // Verifies against regression of https://crbug.com/702330 @@ -367,6 +367,7 @@ std::string script = "function onFocus(e) {" " domAutomationController.setAutomationId(0);" + " console.log(window.name + '-focused-' + e.target.id);" " domAutomationController.send(window.name + '-focused-' + e.target.id);" "}" "" @@ -380,7 +381,13 @@ " return Math.floor(rect.left) +','+" " Math.floor(rect.top);" "}" + "function onClick(e) {" + " console.log('Click event ' + window.name + ' at: ' + e.x + ', ' + e.y " + " + ' screen: ' + e.screenX + ', ' + e.screenY);" + "}" "" + "window.addEventListener('click', onClick);" + "console.log(document.location.origin);" "document.styleSheets[0].insertRule('input {width:100%;margin:0;}', 1);" "document.styleSheets[0].insertRule('h2 {margin:0;}', 1);" "var input1 = document.createElement('input');" @@ -440,6 +447,7 @@ std::string reply; SimulateKeyPress(web_contents, ui::DomKey::TAB, ui::DomCode::TAB, ui::VKEY_TAB, false, reverse /* shift */, false, false); + LOG(INFO) << "Press tab"; EXPECT_TRUE(msg_queue.WaitForMessage(&reply)); return reply; }; @@ -454,6 +462,7 @@ ui_controls::SendMouseClick(ui_controls::LEFT); std::string reply; + LOG(INFO) << "Click element"; EXPECT_TRUE(msg_queue.WaitForMessage(&reply)); return reply; };
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc index 9aa2ddb..6b9c9ac 100644 --- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -381,9 +381,6 @@ void ToggleFeatures( std::unique_ptr<ScopedSubresourceFilterFeatureToggle> features) { scoped_feature_toggle_ = std::move(features); - ContentSubresourceFilterDriverFactory* driver_factory = - ContentSubresourceFilterDriverFactory::FromWebContents(web_contents()); - driver_factory->set_configuration_for_testing(GetActiveConfiguration()); } private:
diff --git a/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc b/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc index addc3e0e..6970f7d 100644 --- a/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc
@@ -155,9 +155,8 @@ PasswordGenerationPopupController::kHorizontalPadding)); AddChildView(help_label_); - set_background(views::Background::CreateSolidBackground( - GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_ResultsTableNormalBackground))); + set_background(views::Background::CreateThemedSolidBackground( + this, ui::NativeTheme::kColorId_ResultsTableNormalBackground)); } PasswordGenerationPopupViewViews::~PasswordGenerationPopupViewViews() {} @@ -212,12 +211,11 @@ if (controller_->password_selected()) NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); - password_view_->set_background( - views::Background::CreateSolidBackground( - GetNativeTheme()->GetSystemColor( - controller_->password_selected() ? - ui::NativeTheme::kColorId_ResultsTableHoveredBackground : - ui::NativeTheme::kColorId_ResultsTableNormalBackground))); + password_view_->set_background(views::Background::CreateThemedSolidBackground( + password_view_, + controller_->password_selected() + ? ui::NativeTheme::kColorId_ResultsTableHoveredBackground + : ui::NativeTheme::kColorId_ResultsTableNormalBackground)); } void PasswordGenerationPopupViewViews::Layout() {
diff --git a/chrome/browser/ui/views/sad_tab_view.cc b/chrome/browser/ui/views/sad_tab_view.cc index 926d73a7..aeaa2188 100644 --- a/chrome/browser/ui/views/sad_tab_view.cc +++ b/chrome/browser/ui/views/sad_tab_view.cc
@@ -36,10 +36,8 @@ SadTabView::SadTabView(content::WebContents* web_contents, chrome::SadTabKind kind) : SadTab(web_contents, kind) { - // Set the background color. - set_background( - views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_DialogBackground))); + set_background(views::Background::CreateThemedSolidBackground( + this, ui::NativeTheme::kColorId_DialogBackground)); views::GridLayout* layout = new views::GridLayout(this); SetLayoutManager(layout); @@ -61,7 +59,7 @@ layout->StartRow(0, column_set_id); layout->AddView(image, 2, 1); - title_ = CreateLabel(l10n_util::GetStringUTF16(GetTitle())); + title_ = new views::Label(l10n_util::GetStringUTF16(GetTitle())); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont)); title_->SetMultiLine(true); @@ -70,13 +68,10 @@ views::kPanelVerticalSpacing); layout->AddView(title_, 2, 1); - const SkColor text_color = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_LabelDisabledColor); - - message_ = CreateLabel(l10n_util::GetStringUTF16(GetMessage())); + message_ = new views::Label(l10n_util::GetStringUTF16(GetMessage())); message_->SetMultiLine(true); - message_->SetEnabledColor(text_color); + message_->SetEnabled(false); message_->SetHorizontalAlignment(gfx::ALIGN_LEFT); message_->SetLineHeight(views::kPanelSubVerticalSpacing); @@ -86,8 +81,8 @@ action_button_ = views::MdTextButton::CreateSecondaryUiBlueButton( this, l10n_util::GetStringUTF16(GetButtonTitle())); - help_link_ = - CreateLink(l10n_util::GetStringUTF16(GetHelpLinkTitle()), text_color); + help_link_ = new views::Link(l10n_util::GetStringUTF16(GetHelpLinkTitle())); + help_link_->set_listener(this); layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVerticalSpacing); layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING, @@ -150,21 +145,6 @@ View::OnPaint(canvas); } -views::Label* SadTabView::CreateLabel(const base::string16& text) { - views::Label* label = new views::Label(text); - label->SetBackgroundColor(background()->get_color()); - return label; -} - -views::Link* SadTabView::CreateLink(const base::string16& text, - const SkColor& color) { - views::Link* link = new views::Link(text); - link->SetBackgroundColor(background()->get_color()); - link->SetEnabledColor(color); - link->set_listener(this); - return link; -} - namespace chrome { SadTab* SadTab::Create(content::WebContents* web_contents,
diff --git a/chrome/browser/ui/views/sad_tab_view.h b/chrome/browser/ui/views/sad_tab_view.h index 2c18287..01885e8a 100644 --- a/chrome/browser/ui/views/sad_tab_view.h +++ b/chrome/browser/ui/views/sad_tab_view.h
@@ -51,10 +51,6 @@ void OnPaint(gfx::Canvas* canvas) override; private: - - views::Label* CreateLabel(const base::string16& text); - views::Link* CreateLink(const base::string16& text, const SkColor& color); - bool painted_ = false; views::Label* message_; views::Link* help_link_;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc index 17b5979..359d821 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_button.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -177,9 +177,7 @@ View::ConvertPointToScreen(this, &menu_position); -#if defined(OS_WIN) - int left_bound = GetSystemMetrics(SM_XVIRTUALSCREEN); -#elif defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) // A window won't overlap between displays on ChromeOS. // Use the left bound of the display on which // the menu button exists.
diff --git a/chrome/test/data/webui/settings/certificate_manager_page_test.js b/chrome/test/data/webui/settings/certificate_manager_page_test.js index 8002bf57..d5838951 100644 --- a/chrome/test/data/webui/settings/certificate_manager_page_test.js +++ b/chrome/test/data/webui/settings/certificate_manager_page_test.js
@@ -440,14 +440,13 @@ var passwordInputElement = Polymer.dom(dialog.$.dialog).querySelector('paper-input'); assertTrue(dialog.$.dialog.open); - assertTrue(dialog.$.ok.disabled); - // Test that the 'OK' button is disabled when the password field is + // Test that the 'OK' button is enabled even when the password field is // empty. - triggerInputEvent(passwordInputElement); - assertTrue(dialog.$.ok.disabled); + assertEquals('', passwordInputElement.value); + assertFalse(dialog.$.ok.disabled); + passwordInputElement.value = 'foopassword'; - triggerInputEvent(passwordInputElement); assertFalse(dialog.$.ok.disabled); // Simulate clicking 'OK'.
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index 8154535..596c013 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -439,6 +439,8 @@ "settings/timezone_settings.h", "settings/timezone_settings_helper.cc", "settings/timezone_settings_helper.h", + "system/cpu_temperature_reader.cc", + "system/cpu_temperature_reader.h", "system/devicemode.cc", "system/devicemode.h", "system/devicetype.cc", @@ -677,6 +679,7 @@ "process_proxy/process_output_watcher_unittest.cc", "process_proxy/process_proxy_unittest.cc", "settings/timezone_settings_unittest.cc", + "system/cpu_temperature_reader_unittest.cc", "system/name_value_pairs_parser_unittest.cc", "system/version_loader_unittest.cc", "timezone/timezone_unittest.cc",
diff --git a/chromeos/system/cpu_temperature_reader.cc b/chromeos/system/cpu_temperature_reader.cc new file mode 100644 index 0000000..8a3e5c0 --- /dev/null +++ b/chromeos/system/cpu_temperature_reader.cc
@@ -0,0 +1,117 @@ +// Copyright 2017 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 "chromeos/system/cpu_temperature_reader.h" + +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/location.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/task_scheduler/post_task.h" +#include "base/task_scheduler/task_traits.h" + +namespace chromeos { +namespace system { + +using CPUTemperatureInfo = CPUTemperatureReader::CPUTemperatureInfo; + +namespace { + +// The location we read our CPU temperature and channel label from. +constexpr char kDefaultHwmonDir[] = "/sys/class/hwmon/"; +constexpr char kDeviceDir[] = "device"; +constexpr char kHwmonDirectoryPattern[] = "hwmon*"; +constexpr char kCPUTempFilePattern[] = "temp*_input"; + +// The contents of sysfs files might contain a newline at the end. Use this +// function to read from a sysfs file and remove the newline. +bool ReadFileContentsAndTrimWhitespace(const base::FilePath& path, + std::string* contents_out) { + if (!base::ReadFileToString(path, contents_out)) + return false; + base::TrimWhitespaceASCII(*contents_out, base::TRIM_TRAILING, contents_out); + return true; +} + +// Reads the temperature as degrees Celsius from the file at |path|, which is +// expected to contain the temperature in millidegrees Celsius. Converts the +// value into degrees and then stores it in |*temp_celsius_out|. returns true if +// the value was successfully read from file, parsed as an int, and converted. +bool ReadTemperatureFromPath(const base::FilePath& path, + double* temp_celsius_out) { + std::string temperature_string; + if (!ReadFileContentsAndTrimWhitespace(path, &temperature_string)) + return false; + uint32_t temperature = 0; + if (!base::StringToUint(temperature_string, &temperature)) + return false; + *temp_celsius_out = temperature / 1000.0; + return true; +} + +// Gets the label describing this temperature. Use the file "temp*_label" if it +// is present, or fall back on the file "name" or |label_path|. +std::string GetLabelFromPath(const base::FilePath& label_path) { + std::string label; + if (base::PathExists(label_path) && + ReadFileContentsAndTrimWhitespace(base::FilePath(label_path), &label) && + !label.empty()) { + return label; + } + + base::FilePath name_path = label_path.DirName().Append("name"); + if (base::PathExists(name_path) && + ReadFileContentsAndTrimWhitespace(name_path, &label) && !label.empty()) { + return label; + } + return label_path.value(); +} + +} // namespace + +CPUTemperatureReader::CPUTemperatureInfo::CPUTemperatureInfo() {} + +CPUTemperatureReader::CPUTemperatureInfo::~CPUTemperatureInfo() = default; + +CPUTemperatureReader::CPUTemperatureReader() : hwmon_dir_(kDefaultHwmonDir) {} + +CPUTemperatureReader::~CPUTemperatureReader() = default; + +std::vector<CPUTemperatureInfo> CPUTemperatureReader::GetCPUTemperatures() { + std::vector<CPUTemperatureInfo> result; + + // Get directories /sys/class/hwmon/hwmon*. + base::FileEnumerator hwmon_enumerator(hwmon_dir_, false, + base::FileEnumerator::DIRECTORIES, + kHwmonDirectoryPattern); + for (base::FilePath hwmon_path = hwmon_enumerator.Next(); !hwmon_path.empty(); + hwmon_path = hwmon_enumerator.Next()) { + // Get temp*_input files in hwmon*/ and hwmon*/device/. + if (base::PathExists(hwmon_path.Append(kDeviceDir))) { + hwmon_path = hwmon_path.Append(kDeviceDir); + } + base::FileEnumerator enumerator( + hwmon_path, false, base::FileEnumerator::FILES, kCPUTempFilePattern); + for (base::FilePath temperature_path = enumerator.Next(); + !temperature_path.empty(); temperature_path = enumerator.Next()) { + CPUTemperatureInfo info; + if (!ReadTemperatureFromPath(temperature_path, &info.temp_celsius)) { + LOG(WARNING) << "Unable to read CPU temperature from " + << temperature_path.value(); + continue; + } + // Get appropriate temp*_label file. + std::string label_path = temperature_path.value(); + base::ReplaceSubstringsAfterOffset(&label_path, 0, "input", "label"); + info.label = GetLabelFromPath(base::FilePath(label_path)); + result.push_back(info); + } + } + return result; +} + +} // namespace system +} // namespace chromeos
diff --git a/chromeos/system/cpu_temperature_reader.h b/chromeos/system/cpu_temperature_reader.h new file mode 100644 index 0000000..45c77ed --- /dev/null +++ b/chromeos/system/cpu_temperature_reader.h
@@ -0,0 +1,60 @@ +// Copyright 2017 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. + +#ifndef CHROMEOS_SYSTEM_CPU_TEMPERATURE_READER_H_ +#define CHROMEOS_SYSTEM_CPU_TEMPERATURE_READER_H_ + +#include <string> +#include <utility> +#include <vector> + +#include "base/files/file_path.h" +#include "base/macros.h" + +namespace chromeos { +namespace system { + +// Used to read CPU temperature info from sysfs hwmon. +class CPUTemperatureReader { + public: + // Contains info from a CPU temperature sensor. + struct CPUTemperatureInfo { + CPUTemperatureInfo(); + ~CPUTemperatureInfo(); + + bool operator<(const CPUTemperatureInfo& other) const { + return std::make_pair(label, temp_celsius) < + std::make_pair(other.label, other.temp_celsius); + } + + // The temperature read by a CPU temperature sensor in degrees Celsius. + double temp_celsius; + + // The name of the CPU temperature zone monitored by this sensor. Used to + // identify the source of each temperature reading. Taken from sysfs "name" + // or "label" field, if it exists. + std::string label; + }; + + CPUTemperatureReader(); + ~CPUTemperatureReader(); + + void set_hwmon_dir_for_test(const base::FilePath& dir) { hwmon_dir_ = dir; } + + // Reads temperature from each thermal sensor of the CPU. Returns a vector + // containing a reading from each sensor. This is a blocking function that + // should be run on a thread that allows blocking operations. + std::vector<CPUTemperatureInfo> GetCPUTemperatures(); + + private: + // Sysfs hwmon directory path. + base::FilePath hwmon_dir_; + + DISALLOW_COPY_AND_ASSIGN(CPUTemperatureReader); +}; + +} // namespace system +} // namespace chromeos + +#endif // CHROMEOS_SYSTEM_CPU_TEMPERATURE_READER_H_
diff --git a/chromeos/system/cpu_temperature_reader_unittest.cc b/chromeos/system/cpu_temperature_reader_unittest.cc new file mode 100644 index 0000000..54c00881 --- /dev/null +++ b/chromeos/system/cpu_temperature_reader_unittest.cc
@@ -0,0 +1,136 @@ +// Copyright 2017 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 "chromeos/system/cpu_temperature_reader.h" + +#include <algorithm> +#include <string> + +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { +namespace system { + +class CPUTemperatureReaderTest : public ::testing::Test { + public: + CPUTemperatureReaderTest() { + CHECK(dir_.CreateUniqueTempDir()); + hwmon_path_ = dir_.GetPath(); + reader_.set_hwmon_dir_for_test(hwmon_path_); + } + + ~CPUTemperatureReaderTest() override = default; + + protected: + using CPUTemperatureInfo = CPUTemperatureReader::CPUTemperatureInfo; + + // Creates a subdirectory in |hwmon_path_| with name |name|. Returns the full + // path of the new subdirectory. + base::FilePath CreateHwmonSubdir(const std::string& name) { + base::FilePath subdir_path = hwmon_path_.Append(name); + CHECK(base::CreateDirectory(subdir_path)); + return subdir_path; + } + + // Creates a file at |path| containing data |contents|. + void CreateFileWithContents(const base::FilePath& path, + const std::string& contents) { + CHECK_EQ(WriteFile(path, contents.data(), contents.size()), + static_cast<int>(contents.size())); + } + + // Creates a temporary dir to act as the hwmon directory passed to |reader_|. + base::ScopedTempDir dir_; + + // Path of the temporary dir created by |dir_|. + base::FilePath hwmon_path_; + + // Instance of the class under test + CPUTemperatureReader reader_; +}; + +TEST_F(CPUTemperatureReaderTest, EmptyDir) { + base::FilePath subdir_empty = CreateHwmonSubdir("hwmon0"); + base::FilePath subdir_not_temp = CreateHwmonSubdir("hwmon1"); + CreateFileWithContents(subdir_not_temp.Append("not_cpu_temp"), "garbage"); + + EXPECT_EQ(0U, reader_.GetCPUTemperatures().size()); +} + +TEST_F(CPUTemperatureReaderTest, SingleDir) { + base::FilePath subdir = CreateHwmonSubdir("hwmon0"); + CreateFileWithContents(subdir.Append("temp1_input"), "10000\n"); + + std::vector<CPUTemperatureInfo> cpu_temp_readings = + reader_.GetCPUTemperatures(); + + ASSERT_EQ(1U, cpu_temp_readings.size()); + EXPECT_EQ(10.0f, cpu_temp_readings[0].temp_celsius); + EXPECT_EQ(subdir.Append("temp1_label").value(), cpu_temp_readings[0].label); +} + +TEST_F(CPUTemperatureReaderTest, SingleDirWithLabel) { + base::FilePath subdir = CreateHwmonSubdir("hwmon0"); + CreateFileWithContents(subdir.Append("temp2_input"), "20000\n"); + CreateFileWithContents(subdir.Append("temp2_label"), "t2\n"); + + std::vector<CPUTemperatureInfo> cpu_temp_readings = + reader_.GetCPUTemperatures(); + + ASSERT_EQ(1U, cpu_temp_readings.size()); + EXPECT_EQ(20.0f, cpu_temp_readings[0].temp_celsius); + EXPECT_EQ("t2", cpu_temp_readings[0].label); +} + +TEST_F(CPUTemperatureReaderTest, SingleDirWithName) { + base::FilePath subdir = CreateHwmonSubdir("hwmon0"); + CreateFileWithContents(subdir.Append("temp3_input"), "30000\n"); + CreateFileWithContents(subdir.Append("temp3_label"), "\n"); + CreateFileWithContents(subdir.Append("name"), "t3\n"); + + std::vector<CPUTemperatureInfo> cpu_temp_readings = + reader_.GetCPUTemperatures(); + + ASSERT_EQ(1U, cpu_temp_readings.size()); + EXPECT_EQ(30.0f, cpu_temp_readings[0].temp_celsius); + EXPECT_EQ("t3", cpu_temp_readings[0].label); +} + +TEST_F(CPUTemperatureReaderTest, MultipleDirs) { + base::FilePath subdir0 = CreateHwmonSubdir("hwmon0"); + CreateFileWithContents(subdir0.Append("temp1_input"), "10000\n"); + + base::FilePath subdir1 = CreateHwmonSubdir("hwmon1"); + CreateFileWithContents(subdir1.Append("temp2_input"), "20000\n"); + CreateFileWithContents(subdir1.Append("temp2_label"), "t2\n"); + + // This should not result in a CPU temperature reading. + base::FilePath subdir2 = CreateHwmonSubdir("hwmon2"); + CreateFileWithContents(subdir2.Append("not_cpu_temp"), "garbage"); + + base::FilePath subdir3 = CreateHwmonSubdir("hwmon3"); + CreateFileWithContents(subdir3.Append("temp3_input"), "30000\n"); + CreateFileWithContents(subdir3.Append("temp3_label"), "t3\n"); + + std::vector<CPUTemperatureInfo> cpu_temp_readings = + reader_.GetCPUTemperatures(); + + // The order in which these directories were read is not guaranteed. Sort them + // first. + std::sort(cpu_temp_readings.begin(), cpu_temp_readings.end()); + + ASSERT_EQ(3U, cpu_temp_readings.size()); + EXPECT_EQ(10.0f, cpu_temp_readings[0].temp_celsius); + EXPECT_EQ(subdir0.Append("temp1_label").value(), cpu_temp_readings[0].label); + EXPECT_EQ(20.0f, cpu_temp_readings[1].temp_celsius); + EXPECT_EQ("t2", cpu_temp_readings[1].label); + EXPECT_EQ(30.0f, cpu_temp_readings[2].temp_celsius); + EXPECT_EQ("t3", cpu_temp_readings[2].label); +} + +} // namespace system +} // namespace chromeos
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc index 05d70c1..df3f8c1 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -86,7 +86,6 @@ content::WebContents* web_contents, std::unique_ptr<SubresourceFilterClient> client) : content::WebContentsObserver(web_contents), - configuration_(GetActiveConfiguration()), client_(std::move(client)), throttle_manager_( base::MakeUnique<ContentSubresourceFilterThrottleManager>( @@ -115,10 +114,14 @@ ComputeActivationDecisionForMainFrameNavigation( content::NavigationHandle* navigation_handle) const { const GURL& url(navigation_handle->GetURL()); - if (configuration_.activation_level == ActivationLevel::DISABLED) + + auto configurations = GetActiveConfigurations(); + if (configurations->the_one_and_only().activation_level == + ActivationLevel::DISABLED) return ActivationDecision::ACTIVATION_DISABLED; - if (configuration_.activation_scope == ActivationScope::NO_SITES) + if (configurations->the_one_and_only().activation_scope == + ActivationScope::NO_SITES) return ActivationDecision::ACTIVATION_DISABLED; if (!url.SchemeIsHTTPOrHTTPS()) @@ -129,7 +132,7 @@ if (client_->ShouldSuppressActivation(navigation_handle)) return ActivationDecision::URL_WHITELISTED; - switch (configuration_.activation_scope) { + switch (configurations->the_one_and_only().activation_scope) { case ActivationScope::ALL_SITES: return ActivationDecision::ACTIVATED; case ActivationScope::ACTIVATION_LIST: { @@ -137,10 +140,11 @@ // AddActivationListMatch to ensure the activation list only has relevant // entries. DCHECK(url.SchemeIsHTTPOrHTTPS() || - !DidURLMatchActivationList(url, configuration_.activation_list)); - bool should_activate = - DidURLMatchActivationList(url, configuration_.activation_list); - if (configuration_.activation_list == + !DidURLMatchActivationList( + url, configurations->the_one_and_only().activation_list)); + bool should_activate = DidURLMatchActivationList( + url, configurations->the_one_and_only().activation_list); + if (configurations->the_one_and_only().activation_list == ActivationList::PHISHING_INTERSTITIAL) { // Handling special case, where activation on the phishing sites also // mean the activation on the sites with social engineering metadata. @@ -185,7 +189,8 @@ RecordRedirectChainMatchPattern(); - if (configuration_.should_whitelist_site_on_reload && + auto configurations = GetActiveConfigurations(); + if (configurations->the_one_and_only().should_whitelist_site_on_reload && NavigationIsPageReload(url, referrer, transition)) { // Whitelist this host for the current as well as subsequent navigations. client_->WhitelistInCurrentWebContents(url); @@ -199,17 +204,19 @@ return; } - activation_level_ = configuration_.activation_level; - measure_performance_ = activation_level_ != ActivationLevel::DISABLED && - ShouldMeasurePerformanceForPageLoad( - configuration_.performance_measurement_rate); + activation_level_ = configurations->the_one_and_only().activation_level; + measure_performance_ = + activation_level_ != ActivationLevel::DISABLED && + ShouldMeasurePerformanceForPageLoad( + configurations->the_one_and_only().performance_measurement_rate); ActivationState state = ActivationState(activation_level_); state.measure_performance = measure_performance_; throttle_manager_->NotifyPageActivationComputed(navigation_handle, state); } void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() { - if (configuration_.should_suppress_notifications) + auto configurations = GetActiveConfigurations(); + if (configurations->the_one_and_only().should_suppress_notifications) return; client_->ToggleNotificationVisibility(activation_level_ ==
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h index f6c4865..b7969d7 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -17,7 +17,6 @@ #include "base/time/time.h" #include "components/safe_browsing_db/util.h" #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h" -#include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "content/public/browser/web_contents_observer.h" #include "ui/base/page_transition_types.h" #include "url/gurl.h" @@ -120,14 +119,6 @@ return throttle_manager_.get(); } - // TODO(https://crbug.com/708181): Allow tests to change the configuration - // after construction (which happens at WebContents creation) but before a - // navigation start. Can be removed once the Safe Browsing navigation throttle - // handles all activation decisions. - void set_configuration_for_testing(Configuration configuration) { - configuration_ = std::move(configuration); - } - SubresourceFilterClient* client() { return client_.get(); } private: @@ -158,8 +149,6 @@ void RecordRedirectChainMatchPatternForList( ActivationList activation_list) const; - Configuration configuration_; - std::unique_ptr<SubresourceFilterClient> client_; std::unique_ptr<ContentSubresourceFilterThrottleManager> throttle_manager_;
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc index 8f75b85..592d21f5 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -469,7 +469,9 @@ private: static bool expected_measure_performance() { - const double rate = GetActiveConfiguration().performance_measurement_rate; + const double rate = GetActiveConfigurations() + ->the_one_and_only() + .performance_measurement_rate; // Note: The case when 0 < rate < 1 is not deterministic, don't test it. EXPECT_TRUE(rate == 0 || rate == 1); return rate == 1; @@ -530,7 +532,6 @@ base::FeatureList::OVERRIDE_DISABLE_FEATURE, kActivationLevelEnabled, kActivationScopeAllSites, kActivationListSocialEngineeringAdsInterstitial); - factory()->set_configuration_for_testing(GetActiveConfiguration()); const GURL url(kExampleUrlWithParams); NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT, ActivationDecision::ACTIVATION_DISABLED); @@ -545,7 +546,6 @@ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, kActivationScopeActivationList, kActivationListSocialEngineeringAdsInterstitial); - factory()->set_configuration_for_testing(GetActiveConfiguration()); NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY, ActivationDecision::ACTIVATION_LIST_NOT_MATCHED); } @@ -558,7 +558,6 @@ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, kActivationScopeAllSites); - factory()->set_configuration_for_testing(GetActiveConfiguration()); EmulateInPageNavigation({false}, EMPTY, ActivationDecision::ACTIVATED); } @@ -569,7 +568,6 @@ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, kActivationScopeActivationList, kActivationListSocialEngineeringAdsInterstitial); - factory()->set_configuration_for_testing(GetActiveConfiguration()); EmulateInPageNavigation({true}, NO_REDIRECTS_HIT, ActivationDecision::ACTIVATED); } @@ -582,7 +580,6 @@ kActivationScopeActivationList, kActivationListSocialEngineeringAdsInterstitial, "1" /* performance_measurement_rate */); - factory()->set_configuration_for_testing(GetActiveConfiguration()); EmulateInPageNavigation({true}, NO_REDIRECTS_HIT, ActivationDecision::ACTIVATED); } @@ -592,7 +589,6 @@ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, kActivationScopeAllSites); - factory()->set_configuration_for_testing(GetActiveConfiguration()); const GURL url(kExampleUrl); NavigateAndExpectActivation({false}, {url}, EMPTY, ActivationDecision::ACTIVATED); @@ -607,7 +603,6 @@ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, kActivationScopeActivationList, kActivationListSocialEngineeringAdsInterstitial); - factory()->set_configuration_for_testing(GetActiveConfiguration()); struct RedirectRedirectChainMatchPatternTestData { std::vector<bool> blacklisted_urls; std::vector<GURL> navigation_chain; @@ -701,8 +696,6 @@ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, kActivationScopeAllSites); - factory()->set_configuration_for_testing(GetActiveConfiguration()); - NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY, ActivationDecision::ACTIVATED); EXPECT_CALL(*client(), ToggleNotificationVisibility(true)).Times(1); @@ -718,8 +711,6 @@ kActivationScopeAllSites, "" /* activation_lists */, "" /* performance_measurement_rate */, "true" /* suppress_notifications */); - factory()->set_configuration_for_testing(GetActiveConfiguration()); - NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY, ActivationDecision::ACTIVATED); EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0); @@ -761,7 +752,6 @@ kActivationScopeAllSites, "" /* activation_lists */, "" /* performance_measurement_rate */, "" /* suppress_notifications */, "true" /* whitelist_site_on_reload */); - factory()->set_configuration_for_testing(GetActiveConfiguration()); NavigateAndExpectActivation( {false}, {GURL(kExampleUrl)}, @@ -784,7 +774,6 @@ base::FeatureList::OVERRIDE_ENABLE_FEATURE, test_data.activation_level, kActivationScopeActivationList, kActivationListSocialEngineeringAdsInterstitial); - factory()->set_configuration_for_testing(GetActiveConfiguration()); const GURL url(kExampleUrlWithParams); NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT, @@ -792,7 +781,8 @@ factory()->client()->WhitelistInCurrentWebContents(url); NavigateAndExpectActivation( {true}, {GURL(kExampleUrlWithParams)}, NO_REDIRECTS_HIT, - GetActiveConfiguration().activation_level == ActivationLevel::DISABLED + GetActiveConfigurations()->the_one_and_only().activation_level == + ActivationLevel::DISABLED ? ActivationDecision::ACTIVATION_DISABLED : ActivationDecision::URL_WHITELISTED); } @@ -806,7 +796,6 @@ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, kActivationScopeActivationList, test_data.activation_list); - factory()->set_configuration_for_testing(GetActiveConfiguration()); const GURL test_url("https://example.com/nonsoceng?q=engsocnon"); std::vector<GURL> navigation_chain; @@ -830,7 +819,6 @@ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, test_data.activation_scope, kActivationListSocialEngineeringAdsInterstitial); - factory()->set_configuration_for_testing(GetActiveConfiguration()); const GURL test_url(kExampleUrlWithParams); @@ -844,7 +832,8 @@ NavigateAndExpectActivation( {test_data.url_matches_activation_list}, {GURL(kExampleUrlWithParams)}, expected_pattern, - GetActiveConfiguration().activation_scope == ActivationScope::NO_SITES + GetActiveConfigurations()->the_one_and_only().activation_scope == + ActivationScope::NO_SITES ? ActivationDecision::ACTIVATION_DISABLED : ActivationDecision::URL_WHITELISTED); } @@ -860,7 +849,6 @@ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, test_data.activation_scope, kActivationListSocialEngineeringAdsInterstitial); - factory()->set_configuration_for_testing(GetActiveConfiguration()); // data URLs are also not supported, but not listed here, as it's not possible // for a page to redirect to them after https://crbug.com/594215 is fixed. @@ -874,7 +862,8 @@ RedirectChainMatchPattern expected_pattern = EMPTY; NavigateAndExpectActivation( {test_data.url_matches_activation_list}, {GURL(url)}, expected_pattern, - GetActiveConfiguration().activation_scope == ActivationScope::NO_SITES + GetActiveConfigurations()->the_one_and_only().activation_scope == + ActivationScope::NO_SITES ? ActivationDecision::ACTIVATION_DISABLED : ActivationDecision::UNSUPPORTED_SCHEME); }
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc index 2ad875ea..943c2e7 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -5,12 +5,15 @@ #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include <string> +#include <utility> +#include "base/lazy_instance.h" #include "base/metrics/field_trial_params.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/synchronization/lock.h" #include "components/variations/variations_associated_data.h" namespace subresource_filter { @@ -76,6 +79,45 @@ return base::LowerCaseEqualsASCII(value, "true"); } +Configuration ParseFieldTrialConfiguration() { + Configuration configuration; + + std::map<std::string, std::string> params; + base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, ¶ms); + + configuration.activation_level = ParseActivationLevel( + TakeVariationParamOrReturnEmpty(¶ms, kActivationLevelParameterName)); + + configuration.activation_scope = ParseActivationScope( + TakeVariationParamOrReturnEmpty(¶ms, kActivationScopeParameterName)); + + configuration.activation_list = ParseActivationList( + TakeVariationParamOrReturnEmpty(¶ms, kActivationListsParameterName)); + + configuration.performance_measurement_rate = + ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty( + ¶ms, kPerformanceMeasurementRateParameterName)); + + configuration.should_suppress_notifications = + ParseBool(TakeVariationParamOrReturnEmpty( + ¶ms, kSuppressNotificationsParameterName)); + + configuration.ruleset_flavor = + TakeVariationParamOrReturnEmpty(¶ms, kRulesetFlavorParameterName); + + configuration.should_whitelist_site_on_reload = + ParseBool(TakeVariationParamOrReturnEmpty( + ¶ms, kWhitelistSiteOnReloadParameterName)); + + return configuration; +} + +base::LazyInstance<base::Lock>::Leaky g_active_configurations_lock = + LAZY_INSTANCE_INITIALIZER; + +base::LazyInstance<scoped_refptr<ConfigurationList>>::Leaky + g_active_configurations = LAZY_INSTANCE_INITIALIZER; + } // namespace const base::Feature kSafeBrowsingSubresourceFilter{ @@ -115,37 +157,26 @@ Configuration::Configuration(Configuration&&) = default; Configuration& Configuration::operator=(Configuration&&) = default; -Configuration GetActiveConfiguration() { - Configuration active_configuration; +ConfigurationList::ConfigurationList(Configuration config) + : config_(std::move(config)) {} +ConfigurationList::~ConfigurationList() = default; - std::map<std::string, std::string> params; - base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, ¶ms); - - active_configuration.activation_level = ParseActivationLevel( - TakeVariationParamOrReturnEmpty(¶ms, kActivationLevelParameterName)); - - active_configuration.activation_scope = ParseActivationScope( - TakeVariationParamOrReturnEmpty(¶ms, kActivationScopeParameterName)); - - active_configuration.activation_list = ParseActivationList( - TakeVariationParamOrReturnEmpty(¶ms, kActivationListsParameterName)); - - active_configuration.performance_measurement_rate = - ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty( - ¶ms, kPerformanceMeasurementRateParameterName)); - - active_configuration.should_suppress_notifications = - ParseBool(TakeVariationParamOrReturnEmpty( - ¶ms, kSuppressNotificationsParameterName)); - - active_configuration.ruleset_flavor = - TakeVariationParamOrReturnEmpty(¶ms, kRulesetFlavorParameterName); - - active_configuration.should_whitelist_site_on_reload = - ParseBool(TakeVariationParamOrReturnEmpty( - ¶ms, kWhitelistSiteOnReloadParameterName)); - - return active_configuration; +scoped_refptr<ConfigurationList> GetActiveConfigurations() { + base::AutoLock lock(g_active_configurations_lock.Get()); + if (!g_active_configurations.Get()) { + g_active_configurations.Get() = + base::MakeShared<ConfigurationList>(ParseFieldTrialConfiguration()); + } + return g_active_configurations.Get(); } +namespace testing { + +void ClearCachedActiveConfigurations() { + base::AutoLock lock(g_active_configurations_lock.Get()); + g_active_configurations.Get() = nullptr; +} + +} // namespace testing + } // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h index 9ac8d317c..487d0839 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.h +++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -6,6 +6,8 @@ #define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_H_ #include "base/feature_list.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" #include "components/subresource_filter/core/common/activation_level.h" #include "components/subresource_filter/core/common/activation_list.h" #include "components/subresource_filter/core/common/activation_scope.h" @@ -53,8 +55,37 @@ bool should_whitelist_site_on_reload = false; }; -// Retrieves the subresource filtering configuration to use. Expensive to call. -Configuration GetActiveConfiguration(); +// TODO(engedy): Make this an actual list once all call sites are prepared to +// handle multiple simultaneous configurations. +class ConfigurationList : public base::RefCountedThreadSafe<ConfigurationList> { + public: + ConfigurationList(Configuration config); + + const Configuration& the_one_and_only() const { return config_; } + + private: + friend class base::RefCountedThreadSafe<ConfigurationList>; + ~ConfigurationList(); + + const Configuration config_; + + DISALLOW_COPY_AND_ASSIGN(ConfigurationList); +}; + +// Retrieves all currently enabled subresource filtering configurations. The +// configurations are parsed on first access and then the result is cached. +// +// In tests, however, the config may change in-between navigations, so callers +// should not hold on to the result for long. +scoped_refptr<ConfigurationList> GetActiveConfigurations(); + +namespace testing { + +// Clears the cached active ConfigurationList so that it will be recomputed on +// next access. Used in tests when the variation parameters are altered. +void ClearCachedActiveConfigurations(); + +} // namespace testing // Feature and variation parameter definitions -------------------------------
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc index 16b8354..5e43f17 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
@@ -65,10 +65,18 @@ } scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); + + // Force the active ConfigurationList to be reparsed on next access so that + // the variation parameters come into effect. + ClearCachedActiveConfigurations(); } ScopedSubresourceFilterFeatureToggle::~ScopedSubresourceFilterFeatureToggle() { variations::testing::ClearAllVariationParams(); + + // Force the active ConfigurationList to be reparsed on next access, so that + // the overrides from this instance are no longer in effect. + ClearCachedActiveConfigurations(); } } // namespace testing
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc index 2041868..86ba034 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -42,7 +42,9 @@ : base::FeatureList::OVERRIDE_USE_DEFAULT, test_case.activation_level_param, kActivationScopeNoSites); - Configuration actual_configuration = GetActiveConfiguration(); + auto active_configurations = GetActiveConfigurations(); + const Configuration& actual_configuration = + active_configurations->the_one_and_only(); EXPECT_EQ(test_case.expected_activation_level, actual_configuration.activation_level); EXPECT_EQ(ActivationScope::NO_SITES, actual_configuration.activation_scope); @@ -79,7 +81,9 @@ : base::FeatureList::OVERRIDE_USE_DEFAULT, kActivationLevelDisabled, test_case.activation_scope_param); - Configuration actual_configuration = GetActiveConfiguration(); + auto active_configurations = GetActiveConfigurations(); + const Configuration& actual_configuration = + active_configurations->the_one_and_only(); EXPECT_EQ(ActivationLevel::DISABLED, actual_configuration.activation_level); EXPECT_EQ(test_case.expected_activation_scope, actual_configuration.activation_scope); @@ -130,7 +134,9 @@ : base::FeatureList::OVERRIDE_USE_DEFAULT, test_case.activation_level_param, test_case.activation_scope_param); - Configuration actual_configuration = GetActiveConfiguration(); + auto active_configurations = GetActiveConfigurations(); + const Configuration& actual_configuration = + active_configurations->the_one_and_only(); EXPECT_EQ(test_case.expected_activation_level, actual_configuration.activation_level); EXPECT_EQ(test_case.expected_activation_scope, @@ -186,7 +192,9 @@ kActivationLevelDisabled, kActivationScopeNoSites, test_case.activation_list_param); - Configuration actual_configuration = GetActiveConfiguration(); + auto active_configurations = GetActiveConfigurations(); + const Configuration& actual_configuration = + active_configurations->the_one_and_only(); EXPECT_EQ(test_case.expected_activation_list, actual_configuration.activation_list); } @@ -223,7 +231,9 @@ {{kPerformanceMeasurementRateParameterName, test_case.perf_measurement_param}}); - Configuration actual_configuration = GetActiveConfiguration(); + auto active_configurations = GetActiveConfigurations(); + const Configuration& actual_configuration = + active_configurations->the_one_and_only(); EXPECT_EQ(test_case.expected_perf_measurement_rate, actual_configuration.performance_measurement_rate); } @@ -257,7 +267,9 @@ {{kSuppressNotificationsParameterName, test_case.suppress_notifications_param}}); - Configuration actual_configuration = GetActiveConfiguration(); + auto active_configurations = GetActiveConfigurations(); + const Configuration& actual_configuration = + active_configurations->the_one_and_only(); EXPECT_EQ(test_case.expected_suppress_notifications_value, actual_configuration.should_suppress_notifications); } @@ -291,7 +303,9 @@ {{kWhitelistSiteOnReloadParameterName, test_case.whitelist_site_on_reload_param}}); - Configuration actual_configuration = GetActiveConfiguration(); + auto active_configurations = GetActiveConfigurations(); + const Configuration& actual_configuration = + active_configurations->the_one_and_only(); EXPECT_EQ(test_case.expected_whitelist_site_on_reload_value, actual_configuration.should_whitelist_site_on_reload); }
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index 7500a8f..ea0b322 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -70,7 +70,6 @@ #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/interface_factory.h" #include "services/service_manager/public/cpp/interface_provider.h" -#include "services/service_manager/public/cpp/interface_registry.h" #include "services/service_manager/runner/common/client_util.h" #if defined(OS_POSIX) @@ -451,13 +450,6 @@ service_manager_connection_ = ServiceManagerConnection::Create( mojo::MakeRequest<service_manager::mojom::Service>(std::move(handle)), GetIOTaskRunner()); - - // TODO(rockot): Remove this once all child-to-browser interface connections - // are made via a Connector rather than directly through an - // InterfaceProvider, and all exposed interfaces are exposed via a - // ConnectionFilter. - service_manager_connection_->SetupInterfaceRequestProxies( - GetInterfaceRegistry(), nullptr); } sync_message_filter_ = channel_->CreateSyncMessageFilter(); @@ -637,14 +629,6 @@ return service_manager_connection_.get(); } -service_manager::InterfaceRegistry* ChildThreadImpl::GetInterfaceRegistry() { - if (!interface_registry_.get()) { - interface_registry_ = base::MakeUnique<service_manager::InterfaceRegistry>( - service_manager::mojom::kServiceManager_ConnectorSpec); - } - return interface_registry_.get(); -} - service_manager::Connector* ChildThreadImpl::GetConnector() { return service_manager_connection_->GetConnector(); }
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h index d2f57d5..af17dac 100644 --- a/content/child/child_thread_impl.h +++ b/content/child/child_thread_impl.h
@@ -92,7 +92,6 @@ void RecordAction(const base::UserMetricsAction& action) override; void RecordComputedAction(const std::string& action) override; ServiceManagerConnection* GetServiceManagerConnection() override; - service_manager::InterfaceRegistry* GetInterfaceRegistry() override; service_manager::Connector* GetConnector() override; // Returns the service_manager::ServiceInfo for the child process & the @@ -246,7 +245,6 @@ const service_manager::ServiceInfo& remote_info); std::unique_ptr<mojo::edk::ScopedIPCSupport> mojo_ipc_support_; - std::unique_ptr<service_manager::InterfaceRegistry> interface_registry_; std::unique_ptr<ServiceManagerConnection> service_manager_connection_; bool connected_to_browser_ = false;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index bf9aca2..f56c199 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -367,6 +367,7 @@ "//components/tracing:startup_tracing", "//content:resources", "//content/app/resources", + "//content/public/common:service_names", "//device/base/synchronization", "//device/bluetooth", "//gpu",
diff --git a/content/common/service_manager/service_manager_connection_impl.cc b/content/common/service_manager/service_manager_connection_impl.cc index 9e81238a..25065a4a 100644 --- a/content/common/service_manager/service_manager_connection_impl.cc +++ b/content/common/service_manager/service_manager_connection_impl.cc
@@ -19,9 +19,9 @@ #include "content/common/child.mojom.h" #include "content/common/service_manager/embedded_service_runner.h" #include "content/public/common/connection_filter.h" +#include "content/public/common/service_names.mojom.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/system/message_pipe.h" -#include "services/service_manager/public/cpp/interface_registry.h" #include "services/service_manager/public/cpp/service.h" #include "services/service_manager/public/cpp/service_context.h" #include "services/service_manager/public/interfaces/constants.mojom.h" @@ -112,15 +112,6 @@ filter_id)); } - // Safe to call any time before Start() is called. - void SetDefaultBinderForBrowserConnection( - const service_manager::InterfaceRegistry::Binder& binder) { - DCHECK(!started_); - default_browser_binder_ = base::Bind( - &IOThreadContext::CallBinderOnTaskRunner, - base::ThreadTaskRunnerHandle::Get(), binder); - } - void AddEmbeddedService(const std::string& name, const ServiceInfo& info) { io_task_runner_->PostTask( FROM_HERE, base::Bind(&ServiceManagerConnectionImpl::IOThreadContext:: @@ -232,11 +223,6 @@ connection_filters_.erase(it); } - void OnBrowserConnectionLost() { - DCHECK(io_thread_checker_.CalledOnValidThread()); - has_browser_connection_ = false; - } - void AddEmbeddedServiceRequestHandlerOnIoThread(const std::string& name, const ServiceInfo& info) { DCHECK(io_thread_checker_.CalledOnValidThread()); @@ -276,18 +262,22 @@ const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override { DCHECK(io_thread_checker_.CalledOnValidThread()); - - std::string remote_service = source_info.identity.name(); - // Only expose the ServiceFactory interface to the Service Manager. - if (remote_service == service_manager::mojom::kServiceName && + if (source_info.identity.name() == service_manager::mojom::kServiceName && interface_name == service_manager::mojom::ServiceFactory::Name_) { factory_bindings_.AddBinding( this, mojo::MakeRequest<service_manager::mojom::ServiceFactory>( std::move(interface_pipe))); - return; - } + } else if (source_info.identity.name() == mojom::kBrowserServiceName && + interface_name == mojom::Child::Name_) { + DCHECK(!child_binding_.is_bound()); + child_binding_.Bind( + mojo::MakeRequest<mojom::Child>(std::move(interface_pipe))); - { + InitializeCallback handler = + base::ResetAndReturn(&browser_info_available_callback_); + callback_task_runner_->PostTask(FROM_HERE, + base::Bind(handler, source_info)); + } else { base::AutoLock lock(lock_); for (auto& entry : connection_filters_) { entry.second->OnBindInterface(source_info, interface_name, @@ -298,32 +288,10 @@ return; } } - - if (remote_service == "content_browser") { - if (interface_name == mojom::Child::Name_ && !has_browser_connection_) { - has_browser_connection_ = true; - InitializeCallback handler = - base::ResetAndReturn(&browser_info_available_callback_); - callback_task_runner_->PostTask(FROM_HERE, - base::Bind(handler, source_info)); - - child_binding_.Bind(std::move(interface_pipe)); - child_binding_.set_connection_error_handler( - base::Bind(&IOThreadContext::OnBrowserConnectionLost, this)); - } else { - default_browser_binder_.Run(interface_name, std::move(interface_pipe)); - } - } - } - - bool OnServiceManagerConnectionLost() override { - ClearConnectionFiltersOnIOThread(); - callback_task_runner_->PostTask(FROM_HERE, stop_callback_); - return true; } ///////////////////////////////////////////////////////////////////////////// - // service_manager::mojom::ServiceFactory implementation + // service_manager::mojom::ServiceFactory: void CreateService(service_manager::mojom::ServiceRequest request, const std::string& name) override { @@ -334,15 +302,6 @@ it->second.Run(std::move(request)); } - static void CallBinderOnTaskRunner( - scoped_refptr<base::SequencedTaskRunner> task_runner, - const service_manager::InterfaceRegistry::Binder& binder, - const std::string& interface_name, - mojo::ScopedMessagePipeHandle request_handle) { - task_runner->PostTask(FROM_HERE, base::Bind(binder, interface_name, - base::Passed(&request_handle))); - } - base::ThreadChecker io_thread_checker_; bool started_ = false; @@ -364,19 +323,8 @@ // Callback to run if the service is stopped by the service manager. base::Closure stop_callback_; - // Called once a connection has been received from the browser process & the - // default binder (below) has been set up. - bool has_browser_connection_ = false; - service_manager::ServiceInfo local_info_; - // Default binder callback used for the browser connection's - // InterfaceRegistry. - // - // TODO(rockot): Remove this once all interfaces exposed to the browser are - // exposed via a ConnectionFilter. - service_manager::InterfaceRegistry::Binder default_browser_binder_; - std::unique_ptr<service_manager::ServiceContext> service_context_; mojo::BindingSet<service_manager::mojom::ServiceFactory> factory_bindings_; int next_filter_id_ = kInvalidConnectionFilterId; @@ -491,18 +439,6 @@ connection_lost_handler_ = closure; } -void ServiceManagerConnectionImpl::SetupInterfaceRequestProxies( - service_manager::InterfaceRegistry* registry, - service_manager::InterfaceProvider* provider) { - // It's safe to bind |registry| as a raw pointer because the caller must - // guarantee that it outlives |this|, and |this| is bound as a weak ptr here. - context_->SetDefaultBinderForBrowserConnection( - base::Bind(&ServiceManagerConnectionImpl::GetInterface, - weak_factory_.GetWeakPtr(), registry)); - - // TODO(beng): remove provider parameter. -} - int ServiceManagerConnectionImpl::AddConnectionFilter( std::unique_ptr<ConnectionFilter> filter) { return context_->AddConnectionFilter(std::move(filter));
diff --git a/content/common/service_manager/service_manager_connection_impl.h b/content/common/service_manager/service_manager_connection_impl.h index c950283..6ef897e 100644 --- a/content/common/service_manager/service_manager_connection_impl.h +++ b/content/common/service_manager/service_manager_connection_impl.h
@@ -40,9 +40,6 @@ const service_manager::ServiceInfo& GetLocalInfo() const override; const service_manager::ServiceInfo& GetBrowserInfo() const override; void SetConnectionLostClosure(const base::Closure& closure) override; - void SetupInterfaceRequestProxies( - service_manager::InterfaceRegistry* registry, - service_manager::InterfaceProvider* provider) override; int AddConnectionFilter(std::unique_ptr<ConnectionFilter> filter) override; void RemoveConnectionFilter(int filter_id) override; void AddEmbeddedService(const std::string& name,
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java index 0012b5b..8a8cc8e 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java +++ b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
@@ -844,7 +844,15 @@ mSelectionRect.set(left, top, right, bottom); mHasSelection = true; mUnselectAllOnDismiss = true; - if (mSelectionClient == null || !mSelectionClient.sendsSelectionPopupUpdates()) { + // When this event comes as the result of SelectAll, SelectionClient should not + // change the selection range (http://crbug.com/714106). We assume that two or + // more selected words means SelectAll. + // TODO(amaralp): Find a better way to know that SELECTION_HANDLES_SHOWN was + // caused by SelectAll. + boolean oneWordSelected = + !getSelectedText().isEmpty() && !getSelectedText().matches(".*\\s+.*"); + if (!oneWordSelected || mSelectionClient == null + || !mSelectionClient.sendsSelectionPopupUpdates()) { showActionModeOrClearOnFailure(); } else { // Rely on |mSelectionClient| sending a classification request and the request
diff --git a/content/public/child/child_thread.h b/content/public/child/child_thread.h index 9287ee8a..575ee808 100644 --- a/content/public/child/child_thread.h +++ b/content/public/child/child_thread.h
@@ -22,7 +22,6 @@ namespace service_manager { class Connector; -class InterfaceRegistry; } namespace content { @@ -71,10 +70,6 @@ // service_manager::Connector can be obtained). virtual ServiceManagerConnection* GetServiceManagerConnection() = 0; - // Returns the InterfaceRegistry that this process uses to expose interfaces - // to the browser. - virtual service_manager::InterfaceRegistry* GetInterfaceRegistry() = 0; - // Returns a connector that can be used to bind interfaces exposed by other // services. virtual service_manager::Connector* GetConnector() = 0;
diff --git a/content/public/common/service_manager_connection.h b/content/public/common/service_manager_connection.h index 5e5378cd..674cf2d 100644 --- a/content/public/common/service_manager_connection.h +++ b/content/public/common/service_manager_connection.h
@@ -15,10 +15,7 @@ #include "services/service_manager/public/interfaces/service.mojom.h" namespace service_manager { -class Connection; class Connector; -class InterfaceProvider; -class InterfaceRegistry; } namespace content { @@ -92,22 +89,6 @@ // run immediately before returning from this function. virtual void SetConnectionLostClosure(const base::Closure& closure) = 0; - // Provides an InterfaceRegistry to forward incoming interface requests to - // on the ServiceManagerConnection's own thread if they aren't bound by the - // connection's internal InterfaceRegistry on the IO thread. - // - // Also configures |interface_provider| to forward all of its outgoing - // interface requests to the connection's internal remote interface provider. - // - // Note that neither |interface_registry| or |interface_provider| is owned - // and both MUST outlive the ServiceManagerConnection. - // - // TODO(rockot): Remove this. It's a temporary solution to avoid porting all - // relevant code to ConnectionFilters at once. - virtual void SetupInterfaceRequestProxies( - service_manager::InterfaceRegistry* registry, - service_manager::InterfaceProvider* provider) = 0; - static const int kInvalidConnectionFilterId = 0; // Allows the caller to filter inbound connections and/or expose interfaces
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc index 0c02a0d3..aeb37bb6 100644 --- a/content/public/test/mock_render_thread.cc +++ b/content/public/test/mock_render_thread.cc
@@ -19,9 +19,6 @@ #include "ipc/ipc_sync_message.h" #include "ipc/message_filter.h" #include "services/service_manager/public/cpp/connector.h" -#include "services/service_manager/public/cpp/interface_provider.h" -#include "services/service_manager/public/cpp/interface_registry.h" -#include "services/service_manager/public/interfaces/interface_provider_spec.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/web/WebScriptController.h" @@ -253,14 +250,6 @@ return nullptr; } -service_manager::InterfaceRegistry* MockRenderThread::GetInterfaceRegistry() { - if (!interface_registry_) { - interface_registry_ = base::MakeUnique<service_manager::InterfaceRegistry>( - service_manager::mojom::kServiceManager_ConnectorSpec); - } - return interface_registry_.get(); -} - service_manager::Connector* MockRenderThread::GetConnector() { if (!connector_) { connector_ =
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h index f6cca73..3a00754 100644 --- a/content/public/test/mock_render_thread.h +++ b/content/public/test/mock_render_thread.h
@@ -17,7 +17,6 @@ #include "ipc/ipc_test_sink.h" #include "ipc/message_filter.h" #include "services/service_manager/public/interfaces/connector.mojom.h" -#include "services/service_manager/public/interfaces/interface_provider.mojom.h" #include "third_party/WebKit/public/web/WebPopupType.h" struct FrameHostMsg_CreateChildFrame_Params; @@ -89,7 +88,6 @@ void ReleaseCachedFonts() override; #endif ServiceManagerConnection* GetServiceManagerConnection() override; - service_manager::InterfaceRegistry* GetInterfaceRegistry() override; service_manager::Connector* GetConnector() override; void SetFieldTrialGroup(const std::string& trial_name, const std::string& group_name) override; @@ -167,7 +165,6 @@ base::ObserverList<RenderThreadObserver> observers_; cc::TestSharedBitmapManager shared_bitmap_manager_; - std::unique_ptr<service_manager::InterfaceRegistry> interface_registry_; std::unique_ptr<service_manager::Connector> connector_; service_manager::mojom::ConnectorRequest pending_connector_request_;
diff --git a/device/BUILD.gn b/device/BUILD.gn index 31a5095..b9d73b20 100644 --- a/device/BUILD.gn +++ b/device/BUILD.gn
@@ -74,8 +74,6 @@ "sensors/sensor_manager_android_unittest.cc", "sensors/sensor_manager_chromeos_unittest.cc", "test/run_all_unittests.cc", - "u2f/u2f_apdu_unittest.cc", - "u2f/u2f_message_unittest.cc", ] deps = [ @@ -134,13 +132,20 @@ "hid/test_report_descriptors.cc", "hid/test_report_descriptors.h", "serial/serial_io_handler_posix_unittest.cc", + "u2f/u2f_apdu_unittest.cc", "u2f/u2f_hid_device_unittest.cc", + "u2f/u2f_message_unittest.cc", + "u2f/u2f_register_unittest.cc", + "u2f/u2f_request_unittest.cc", + "u2f/u2f_sign_unittest.cc", ] deps += [ "//device/hid", "//device/hid:mocks", "//device/serial", "//device/serial:test_support", + "//device/u2f", + "//device/u2f:mocks", ] } @@ -170,7 +175,6 @@ deps += [ "//device/base", "//device/base:mocks", - "//device/u2f", "//device/usb", "//device/usb:test_support", "//device/usb/mojo",
diff --git a/device/u2f/BUILD.gn b/device/u2f/BUILD.gn index 91fd6a2..0fcfe4b 100644 --- a/device/u2f/BUILD.gn +++ b/device/u2f/BUILD.gn
@@ -19,6 +19,13 @@ "u2f_message.h", "u2f_packet.cc", "u2f_packet.h", + "u2f_register.cc", + "u2f_register.h", + "u2f_request.cc", + "u2f_request.h", + "u2f_return_code.h", + "u2f_sign.cc", + "u2f_sign.h", ] deps = [ @@ -30,6 +37,21 @@ ] } +source_set("mocks") { + testonly = true + + sources = [ + "mock_u2f_device.cc", + "mock_u2f_device.h", + ] + + deps = [ + ":u2f", + "//base", + "//testing/gmock", + ] +} + fuzzer_test("u2f_apdu_fuzzer") { sources = [ "u2f_apdu_fuzzer.cc",
diff --git a/device/u2f/mock_u2f_device.cc b/device/u2f/mock_u2f_device.cc new file mode 100644 index 0000000..4f8bdc4 --- /dev/null +++ b/device/u2f/mock_u2f_device.cc
@@ -0,0 +1,53 @@ +// Copyright 2017 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 "mock_u2f_device.h" + +namespace device { + +MockU2fDevice::MockU2fDevice() {} + +MockU2fDevice::~MockU2fDevice() {} + +void MockU2fDevice::DeviceTransact(std::unique_ptr<U2fApduCommand> command, + const DeviceCallback& cb) { + DeviceTransactPtr(command.get(), cb); +} + +// static +void MockU2fDevice::NotSatisfied(U2fApduCommand* cmd, + const DeviceCallback& cb) { + cb.Run(true, base::MakeUnique<U2fApduResponse>( + std::vector<uint8_t>(), + U2fApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED)); +} + +// static +void MockU2fDevice::WrongData(U2fApduCommand* cmd, const DeviceCallback& cb) { + cb.Run(true, + base::MakeUnique<U2fApduResponse>( + std::vector<uint8_t>(), U2fApduResponse::Status::SW_WRONG_DATA)); +} + +// static +void MockU2fDevice::NoErrorSign(U2fApduCommand* cmd, const DeviceCallback& cb) { + cb.Run(true, base::MakeUnique<U2fApduResponse>( + std::vector<uint8_t>({kSign}), + U2fApduResponse::Status::SW_NO_ERROR)); +} + +// static +void MockU2fDevice::NoErrorRegister(U2fApduCommand* cmd, + const DeviceCallback& cb) { + cb.Run(true, base::MakeUnique<U2fApduResponse>( + std::vector<uint8_t>({kRegister}), + U2fApduResponse::Status::SW_NO_ERROR)); +} + +// static +void MockU2fDevice::WinkDoNothing(const WinkCallback& cb) { + cb.Run(); +} + +} // namespace device
diff --git a/device/u2f/mock_u2f_device.h b/device/u2f/mock_u2f_device.h new file mode 100644 index 0000000..f4e65da --- /dev/null +++ b/device/u2f/mock_u2f_device.h
@@ -0,0 +1,43 @@ +// Copyright 2017 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. + +#ifndef DEVICE_U2F_MOCK_U2F_DEVICE_H_ +#define DEVICE_U2F_MOCK_U2F_DEVICE_H_ + +#include <vector> + +#include "base/memory/ptr_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "u2f_apdu_command.h" +#include "u2f_device.h" + +namespace device { + +class MockU2fDevice : public U2fDevice { + public: + static constexpr uint8_t kSign = 0x1; + static constexpr uint8_t kRegister = 0x5; + + MockU2fDevice(); + ~MockU2fDevice() override; + + MOCK_METHOD1(TryWink, void(const WinkCallback& cb)); + MOCK_METHOD0(GetId, std::string(void)); + // GMock cannot mock a method taking a std::unique_ptr<T> + MOCK_METHOD2(DeviceTransactPtr, + void(U2fApduCommand* command, const DeviceCallback& cb)); + void DeviceTransact(std::unique_ptr<U2fApduCommand> command, + const DeviceCallback& cb) override; + static void TransactNoError(std::unique_ptr<U2fApduCommand> command, + const DeviceCallback& cb); + static void NotSatisfied(U2fApduCommand* cmd, const DeviceCallback& cb); + static void WrongData(U2fApduCommand* cmd, const DeviceCallback& cb); + static void NoErrorSign(U2fApduCommand* cmd, const DeviceCallback& cb); + static void NoErrorRegister(U2fApduCommand* cmd, const DeviceCallback& cb); + static void WinkDoNothing(const WinkCallback& cb); +}; + +} // namespace device + +#endif // DEVICE_U2F_MOCK_U2F_DEVICE_H_
diff --git a/device/u2f/u2f_apdu_response.h b/device/u2f/u2f_apdu_response.h index 44bf7d6..2e5d74e 100644 --- a/device/u2f/u2f_apdu_response.h +++ b/device/u2f/u2f_apdu_response.h
@@ -23,6 +23,7 @@ SW_NO_ERROR = 0x9000, SW_CONDITIONS_NOT_SATISFIED = 0x6985, SW_WRONG_DATA = 0x6A80, + SW_WRONG_LENGTH = 0x6700, }; U2fApduResponse(std::vector<uint8_t> message, Status response_status);
diff --git a/device/u2f/u2f_device.cc b/device/u2f/u2f_device.cc index dc9e5ec..1b2f2b7 100644 --- a/device/u2f/u2f_device.cc +++ b/device/u2f/u2f_device.cc
@@ -10,7 +10,8 @@ namespace device { -U2fDevice::U2fDevice() : weak_factory_(this) {} +U2fDevice::U2fDevice() + : channel_id_(kBroadcastChannel), capabilities_(0), weak_factory_(this) {} U2fDevice::~U2fDevice() {} @@ -20,7 +21,7 @@ std::unique_ptr<U2fApduCommand> register_cmd = U2fApduCommand::CreateRegister(app_param, challenge_param); if (!register_cmd) { - callback.Run(ReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); + callback.Run(U2fReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); return; } DeviceTransact(std::move(register_cmd), @@ -35,7 +36,7 @@ std::unique_ptr<U2fApduCommand> sign_cmd = U2fApduCommand::CreateSign(app_param, challenge_param, key_handle); if (!sign_cmd) { - callback.Run(ReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); + callback.Run(U2fReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); return; } DeviceTransact(std::move(sign_cmd), @@ -59,22 +60,22 @@ bool success, std::unique_ptr<U2fApduResponse> register_response) { if (!success || !register_response) { - callback.Run(ReturnCode::FAILURE, std::vector<uint8_t>()); + callback.Run(U2fReturnCode::FAILURE, std::vector<uint8_t>()); return; } switch (register_response->status()) { case U2fApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED: - callback.Run(ReturnCode::CONDITIONS_NOT_SATISFIED, + callback.Run(U2fReturnCode::CONDITIONS_NOT_SATISFIED, std::vector<uint8_t>()); break; case U2fApduResponse::Status::SW_NO_ERROR: - callback.Run(ReturnCode::SUCCESS, register_response->data()); + callback.Run(U2fReturnCode::SUCCESS, register_response->data()); break; case U2fApduResponse::Status::SW_WRONG_DATA: - callback.Run(ReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); + callback.Run(U2fReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); break; default: - callback.Run(ReturnCode::FAILURE, std::vector<uint8_t>()); + callback.Run(U2fReturnCode::FAILURE, std::vector<uint8_t>()); break; } } @@ -83,22 +84,21 @@ bool success, std::unique_ptr<U2fApduResponse> sign_response) { if (!success || !sign_response) { - callback.Run(ReturnCode::FAILURE, std::vector<uint8_t>()); + callback.Run(U2fReturnCode::FAILURE, std::vector<uint8_t>()); return; } switch (sign_response->status()) { case U2fApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED: - callback.Run(ReturnCode::CONDITIONS_NOT_SATISFIED, + callback.Run(U2fReturnCode::CONDITIONS_NOT_SATISFIED, std::vector<uint8_t>()); break; case U2fApduResponse::Status::SW_NO_ERROR: - callback.Run(ReturnCode::SUCCESS, sign_response->data()); + callback.Run(U2fReturnCode::SUCCESS, sign_response->data()); break; case U2fApduResponse::Status::SW_WRONG_DATA: - callback.Run(ReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); - break; + case U2fApduResponse::Status::SW_WRONG_LENGTH: default: - callback.Run(ReturnCode::FAILURE, std::vector<uint8_t>()); + callback.Run(U2fReturnCode::INVALID_PARAMS, std::vector<uint8_t>()); break; } }
diff --git a/device/u2f/u2f_device.h b/device/u2f/u2f_device.h index 06b9d2f..77c8133 100644 --- a/device/u2f/u2f_device.h +++ b/device/u2f/u2f_device.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" #include "u2f_apdu_response.h" +#include "u2f_return_code.h" namespace device { @@ -23,15 +24,9 @@ U2F_V2, UNKNOWN, }; - enum class ReturnCode : uint8_t { - SUCCESS, - FAILURE, - INVALID_PARAMS, - CONDITIONS_NOT_SATISFIED, - }; using MessageCallback = - base::Callback<void(ReturnCode, std::vector<uint8_t>)>; + base::Callback<void(U2fReturnCode, std::vector<uint8_t>)>; using VersionCallback = base::Callback<void(bool success, ProtocolVersion version)>; using DeviceCallback =
diff --git a/device/u2f/u2f_hid_device.cc b/device/u2f/u2f_hid_device.cc index 62eda92..27e1f7b 100644 --- a/device/u2f/u2f_hid_device.cc +++ b/device/u2f/u2f_hid_device.cc
@@ -25,7 +25,6 @@ state_(State::INIT), device_info_(device_info), weak_factory_(this) { - channel_id_ = kBroadcastChannel; } U2fHidDevice::~U2fHidDevice() {
diff --git a/device/u2f/u2f_register.cc b/device/u2f/u2f_register.cc new file mode 100644 index 0000000..0f43e260 --- /dev/null +++ b/device/u2f/u2f_register.cc
@@ -0,0 +1,61 @@ +// Copyright 2017 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 "u2f_register.h" + +#include "base/memory/ptr_util.h" + +namespace device { + +U2fRegister::U2fRegister(const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb) + : U2fRequest(cb), + challenge_hash_(challenge_hash), + app_param_(app_param), + weak_factory_(this) {} + +U2fRegister::~U2fRegister() {} + +// static +std::unique_ptr<U2fRequest> U2fRegister::TryRegistration( + const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb) { + std::unique_ptr<U2fRequest> request = + base::MakeUnique<U2fRegister>(challenge_hash, app_param, cb); + request->Start(); + return request; +} + +void U2fRegister::TryDevice() { + DCHECK(current_device_); + + current_device_->Register( + app_param_, challenge_hash_, + base::Bind(&U2fRegister::OnTryDevice, weak_factory_.GetWeakPtr())); +} + +void U2fRegister::OnTryDevice(U2fReturnCode return_code, + std::vector<uint8_t> response_data) { + switch (return_code) { + case U2fReturnCode::SUCCESS: + state_ = State::COMPLETE; + cb_.Run(return_code, response_data); + break; + case U2fReturnCode::CONDITIONS_NOT_SATISFIED: + // Waiting for user touch, move on and try this device later + state_ = State::IDLE; + Transition(); + break; + default: + state_ = State::IDLE; + // An error has occured, quit trying this device + current_device_ = nullptr; + Transition(); + break; + } +} + +} // namespace device
diff --git a/device/u2f/u2f_register.h b/device/u2f/u2f_register.h new file mode 100644 index 0000000..466127ed --- /dev/null +++ b/device/u2f/u2f_register.h
@@ -0,0 +1,37 @@ +// Copyright 2017 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. + +#ifndef DEVICE_U2F_U2F_REGISTER_H_ +#define DEVICE_U2F_U2F_REGISTER_H_ + +#include <vector> + +#include "u2f_request.h" + +namespace device { + +class U2fRegister : public U2fRequest { + public: + U2fRegister(const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb); + ~U2fRegister() override; + + static std::unique_ptr<U2fRequest> TryRegistration( + const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb); + + private: + void TryDevice() override; + void OnTryDevice(U2fReturnCode, std::vector<uint8_t>); + + std::vector<uint8_t> challenge_hash_; + std::vector<uint8_t> app_param_; + base::WeakPtrFactory<U2fRegister> weak_factory_; +}; + +} // namespace device + +#endif // DEVICE_U2F_U2F_REGISTER_H_
diff --git a/device/u2f/u2f_register_unittest.cc b/device/u2f/u2f_register_unittest.cc new file mode 100644 index 0000000..2d0d2d4 --- /dev/null +++ b/device/u2f/u2f_register_unittest.cc
@@ -0,0 +1,130 @@ +// Copyright 2017 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 <list> + +#include "base/run_loop.h" +#include "base/test/test_io_thread.h" +#include "device/base/mock_device_client.h" +#include "device/hid/mock_hid_service.h" +#include "device/test/test_device_client.h" +#include "mock_u2f_device.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "u2f_register.h" + +namespace device { + +class U2fRegisterTest : public testing::Test { + public: + U2fRegisterTest() : io_thread_(base::TestIOThread::kAutoStart) {} + + void SetUp() override { + MockHidService* hid_service = device_client_.hid_service(); + hid_service->FirstEnumerationComplete(); + } + + protected: + base::MessageLoopForUI message_loop_; + base::TestIOThread io_thread_; + device::MockDeviceClient device_client_; +}; + +class TestRegisterCallback { + public: + TestRegisterCallback() + : callback_(base::Bind(&TestRegisterCallback::ReceivedCallback, + base::Unretained(this))) {} + ~TestRegisterCallback() {} + + void ReceivedCallback(U2fReturnCode status_code, + std::vector<uint8_t> response) { + response_ = std::make_pair(status_code, response); + closure_.Run(); + } + + std::pair<U2fReturnCode, std::vector<uint8_t>>& WaitForCallback() { + closure_ = run_loop_.QuitClosure(); + run_loop_.Run(); + return response_; + } + + const U2fRequest::ResponseCallback& callback() { return callback_; } + + private: + std::pair<U2fReturnCode, std::vector<uint8_t>> response_; + base::Closure closure_; + U2fRequest::ResponseCallback callback_; + base::RunLoop run_loop_; +}; + +TEST_F(U2fRegisterTest, TestRegisterSuccess) { + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice()); + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister)); + EXPECT_CALL(*device.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + TestRegisterCallback cb; + std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration( + std::vector<uint8_t>(32), std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]); +} + +TEST_F(U2fRegisterTest, TestDelayedSuccess) { + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice()); + + // Go through the state machine twice before success + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister)); + EXPECT_CALL(*device.get(), TryWink(testing::_)) + .Times(2) + .WillRepeatedly(testing::Invoke(MockU2fDevice::WinkDoNothing)); + TestRegisterCallback cb; + + std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration( + std::vector<uint8_t>(32), std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]); +} + +TEST_F(U2fRegisterTest, TestMultipleDevices) { + // Second device will have a successful touch + std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice()); + std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice()); + + EXPECT_CALL(*device0.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied)); + // One wink per device + EXPECT_CALL(*device0.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + EXPECT_CALL(*device1.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister)); + EXPECT_CALL(*device1.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + + TestRegisterCallback cb; + std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration( + std::vector<uint8_t>(32), std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device0)); + request->AddDeviceForTesting(std::move(device1)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]); +} + +} // namespace device
diff --git a/device/u2f/u2f_request.cc b/device/u2f/u2f_request.cc new file mode 100644 index 0000000..a010352 --- /dev/null +++ b/device/u2f/u2f_request.cc
@@ -0,0 +1,148 @@ +// Copyright 2017 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 "u2f_request.h" + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "base/threading/thread_task_runner_handle.h" +#include "device/base/device_client.h" +#include "u2f_hid_device.h" + +namespace device { + +U2fRequest::U2fRequest(const ResponseCallback& cb) + : state_(State::INIT), + cb_(cb), + hid_service_observer_(this), + weak_factory_(this) { + filter_.SetUsagePage(0xf1d0); +} + +void U2fRequest::Transition() { + switch (state_) { + case State::IDLE: + IterateDevice(); + if (!current_device_) { + // No devices available + state_ = State::OFF; + break; + } + state_ = State::WINK; + current_device_->TryWink( + base::Bind(&U2fRequest::Transition, weak_factory_.GetWeakPtr())); + break; + case State::WINK: + state_ = State::BUSY; + TryDevice(); + default: + break; + } +} + +void U2fRequest::Start() { + if (state_ == State::INIT) { + state_ = State::BUSY; + Enumerate(); + } +} + +void U2fRequest::Enumerate() { + HidService* hid_service = DeviceClient::Get()->GetHidService(); + DCHECK(hid_service); + hid_service_observer_.Add(hid_service); + hid_service->GetDevices( + base::Bind(&U2fRequest::OnEnumerate, weak_factory_.GetWeakPtr())); +} + +void U2fRequest::OnEnumerate( + const std::vector<scoped_refptr<HidDeviceInfo>>& devices) { + for (auto device_info : devices) { + if (filter_.Matches(device_info)) + devices_.push_back(base::MakeUnique<U2fHidDevice>(device_info)); + } + + state_ = State::IDLE; + Transition(); +} + +void U2fRequest::OnDeviceAdded(scoped_refptr<HidDeviceInfo> device_info) { + // Ignore non-U2F devices + if (!filter_.Matches(device_info)) + return; + + auto device = base::MakeUnique<U2fHidDevice>(device_info); + AddDevice(std::move(device)); +} + +void U2fRequest::OnDeviceRemoved(scoped_refptr<HidDeviceInfo> device_info) { + // Ignore non-U2F devices + if (!filter_.Matches(device_info)) + return; + + auto device = base::MakeUnique<U2fHidDevice>(device_info); + + // Check if the active device was removed + if (current_device_ && current_device_->GetId() == device->GetId()) { + current_device_ = nullptr; + state_ = State::IDLE; + Transition(); + return; + } + + // Remove the device if it exists in either device list + devices_.remove_if([&device](const std::unique_ptr<U2fDevice>& this_device) { + return this_device->GetId() == device->GetId(); + }); + attempted_devices_.remove_if( + [&device](const std::unique_ptr<U2fDevice>& this_device) { + return this_device->GetId() == device->GetId(); + }); +} + +void U2fRequest::IterateDevice() { + // Move active device to attempted device list + if (current_device_) + attempted_devices_.push_back(std::move(current_device_)); + + // If there is an additional device on device list, make it active. + // Otherwise, if all devices have been tried, move attempted devices back to + // the main device list. + if (devices_.size() > 0) { + current_device_ = std::move(devices_.front()); + devices_.pop_front(); + } else if (attempted_devices_.size() > 0) { + devices_ = std::move(attempted_devices_); + // After trying every device, wait 200ms before trying again + delay_callback_.Reset( + base::Bind(&U2fRequest::OnWaitComplete, weak_factory_.GetWeakPtr())); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, delay_callback_.callback(), + base::TimeDelta::FromMilliseconds(200)); + } +} + +void U2fRequest::OnWaitComplete() { + state_ = State::IDLE; + Transition(); +} + +void U2fRequest::AddDevice(std::unique_ptr<U2fDevice> device) { + devices_.push_back(std::move(device)); + + // Start the state machine if this is the only device + if (state_ == State::OFF) { + state_ = State::IDLE; + delay_callback_.Cancel(); + Transition(); + } +} + +void U2fRequest::AddDeviceForTesting(std::unique_ptr<U2fDevice> device) { + AddDevice(std::move(device)); +} + +U2fRequest::~U2fRequest() {} + +} // namespace device
diff --git a/device/u2f/u2f_request.h b/device/u2f/u2f_request.h new file mode 100644 index 0000000..902a2ca --- /dev/null +++ b/device/u2f/u2f_request.h
@@ -0,0 +1,65 @@ +// Copyright 2017 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. + +#ifndef DEVICE_U2F_U2F_REQUEST_H_ +#define DEVICE_U2F_U2F_REQUEST_H_ + +#include "base/cancelable_callback.h" +#include "base/scoped_observer.h" +#include "device/hid/hid_device_filter.h" +#include "device/hid/hid_service.h" +#include "u2f_device.h" + +namespace device { +class U2fRequest : HidService::Observer { + public: + using ResponseCallback = base::Callback<void(U2fReturnCode status_code, + std::vector<uint8_t> response)>; + + U2fRequest(const ResponseCallback& callback); + virtual ~U2fRequest(); + + void Start(); + void AddDeviceForTesting(std::unique_ptr<U2fDevice> device); + + protected: + enum class State { + INIT, + BUSY, + WINK, + IDLE, + OFF, + COMPLETE, + }; + + void Transition(); + virtual void TryDevice() = 0; + + std::unique_ptr<U2fDevice> current_device_; + State state_; + ResponseCallback cb_; + + private: + FRIEND_TEST_ALL_PREFIXES(U2fRequestTest, TestAddRemoveDevice); + FRIEND_TEST_ALL_PREFIXES(U2fRequestTest, TestIterateDevice); + FRIEND_TEST_ALL_PREFIXES(U2fRequestTest, TestBasicMachine); + + void Enumerate(); + void IterateDevice(); + void OnWaitComplete(); + void AddDevice(std::unique_ptr<U2fDevice> device); + void OnDeviceAdded(scoped_refptr<HidDeviceInfo> device_info) override; + void OnDeviceRemoved(scoped_refptr<HidDeviceInfo> device_info) override; + void OnEnumerate(const std::vector<scoped_refptr<HidDeviceInfo>>& devices); + + std::list<std::unique_ptr<U2fDevice>> devices_; + std::list<std::unique_ptr<U2fDevice>> attempted_devices_; + base::CancelableClosure delay_callback_; + HidDeviceFilter filter_; + ScopedObserver<HidService, HidService::Observer> hid_service_observer_; + base::WeakPtrFactory<U2fRequest> weak_factory_; +}; +} // namespace device + +#endif // DEVICE_U2F_U2F_REQUEST_H_
diff --git a/device/u2f/u2f_request_unittest.cc b/device/u2f/u2f_request_unittest.cc new file mode 100644 index 0000000..53c2130a --- /dev/null +++ b/device/u2f/u2f_request_unittest.cc
@@ -0,0 +1,159 @@ +// Copyright 2017 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 <list> + +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/test_io_thread.h" +#include "device/base/mock_device_client.h" +#include "device/hid/mock_hid_service.h" +#include "device/test/test_device_client.h" +#include "device/test/usb_test_gadget.h" +#include "device/u2f/u2f_hid_device.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "u2f_request.h" + +namespace device { +namespace { +#if defined(OS_MACOSX) +const uint64_t kTestDeviceId0 = 42; +const uint64_t kTestDeviceId1 = 43; +const uint64_t kTestDeviceId2 = 44; +#else +const char* kTestDeviceId0 = "device0"; +const char* kTestDeviceId1 = "device1"; +const char* kTestDeviceId2 = "device2"; +#endif + +class FakeU2fRequest : public U2fRequest { + public: + FakeU2fRequest(const ResponseCallback& cb) : U2fRequest(cb) {} + ~FakeU2fRequest() override {} + + void TryDevice() override { + cb_.Run(U2fReturnCode::SUCCESS, std::vector<uint8_t>()); + } +}; +} // namespace + +class TestResponseCallback { + public: + TestResponseCallback() + : callback_(base::Bind(&TestResponseCallback::ReceivedCallback, + base::Unretained(this))) {} + ~TestResponseCallback() {} + + void ReceivedCallback(U2fReturnCode status, std::vector<uint8_t> data) { + closure_.Run(); + } + + void WaitForCallback() { + closure_ = run_loop_.QuitClosure(); + run_loop_.Run(); + } + + U2fRequest::ResponseCallback& callback() { return callback_; } + + private: + base::Closure closure_; + U2fRequest::ResponseCallback callback_; + base::RunLoop run_loop_; +}; + +class U2fRequestTest : public testing::Test { + public: + U2fRequestTest() : io_thread_(base::TestIOThread::kAutoStart) {} + + protected: + base::MessageLoopForUI message_loop_; + base::TestIOThread io_thread_; + device::MockDeviceClient device_client_; +}; + +TEST_F(U2fRequestTest, TestAddRemoveDevice) { + MockHidService* hid_service = device_client_.hid_service(); + HidCollectionInfo c_info; + hid_service->FirstEnumerationComplete(); + + TestResponseCallback cb; + FakeU2fRequest request(cb.callback()); + request.Enumerate(); + EXPECT_EQ(static_cast<size_t>(0), request.devices_.size()); + + // Add one U2F device + c_info.usage = HidUsageAndPage(1, static_cast<HidUsageAndPage::Page>(0xf1d0)); + scoped_refptr<HidDeviceInfo> u2f_device = make_scoped_refptr( + new HidDeviceInfo(kTestDeviceId0, 0, 0, "Test Fido Device", "123FIDO", + kHIDBusTypeUSB, c_info, 64, 64, 0)); + hid_service->AddDevice(u2f_device); + EXPECT_EQ(static_cast<size_t>(1), request.devices_.size()); + + // Add one non-U2F device. Verify that it is not added to our device list. + scoped_refptr<HidDeviceInfo> other_device = make_scoped_refptr( + new HidDeviceInfo(kTestDeviceId2, 0, 0, "Other Device", "OtherDevice", + kHIDBusTypeUSB, std::vector<uint8_t>())); + hid_service->AddDevice(other_device); + EXPECT_EQ(static_cast<size_t>(1), request.devices_.size()); + + // Remove the non-U2F device and verify that device list was unchanged. + hid_service->RemoveDevice(kTestDeviceId2); + EXPECT_EQ(static_cast<size_t>(1), request.devices_.size()); + + // Remove the U2F device and verify that device list is empty. + hid_service->RemoveDevice(kTestDeviceId0); + EXPECT_EQ(static_cast<size_t>(0), request.devices_.size()); +} + +TEST_F(U2fRequestTest, TestIterateDevice) { + TestResponseCallback cb; + FakeU2fRequest request(cb.callback()); + HidCollectionInfo c_info; + // Add one U2F device and one non-U2f device + c_info.usage = HidUsageAndPage(1, static_cast<HidUsageAndPage::Page>(0xf1d0)); + scoped_refptr<HidDeviceInfo> device0 = make_scoped_refptr( + new HidDeviceInfo(kTestDeviceId0, 0, 0, "Test Fido Device", "123FIDO", + kHIDBusTypeUSB, c_info, 64, 64, 0)); + request.devices_.push_back(base::MakeUnique<U2fHidDevice>(device0)); + scoped_refptr<HidDeviceInfo> device1 = make_scoped_refptr( + new HidDeviceInfo(kTestDeviceId1, 0, 0, "Test Fido Device", "123FIDO", + kHIDBusTypeUSB, c_info, 64, 64, 0)); + request.devices_.push_back(base::MakeUnique<U2fHidDevice>(device1)); + + // Move first device to current + request.IterateDevice(); + ASSERT_NE(nullptr, request.current_device_); + EXPECT_EQ(static_cast<size_t>(1), request.devices_.size()); + + // Move second device to current, first to attempted + request.IterateDevice(); + ASSERT_NE(nullptr, request.current_device_); + EXPECT_EQ(static_cast<size_t>(1), request.attempted_devices_.size()); + + // Move second device from current to attempted, move attempted to devices as + // all devices have been attempted + request.IterateDevice(); + ASSERT_EQ(nullptr, request.current_device_); + EXPECT_EQ(static_cast<size_t>(2), request.devices_.size()); + EXPECT_EQ(static_cast<size_t>(0), request.attempted_devices_.size()); +} + +TEST_F(U2fRequestTest, TestBasicMachine) { + MockHidService* hid_service = device_client_.hid_service(); + hid_service->FirstEnumerationComplete(); + TestResponseCallback cb; + FakeU2fRequest request(cb.callback()); + request.Start(); + // Add one U2F device + HidCollectionInfo c_info; + c_info.usage = HidUsageAndPage(1, static_cast<HidUsageAndPage::Page>(0xf1d0)); + scoped_refptr<HidDeviceInfo> u2f_device = make_scoped_refptr( + new HidDeviceInfo(kTestDeviceId0, 0, 0, "Test Fido Device", "123FIDO", + kHIDBusTypeUSB, c_info, 64, 64, 0)); + hid_service->AddDevice(u2f_device); + cb.WaitForCallback(); + EXPECT_EQ(U2fRequest::State::BUSY, request.state_); +} + +} // namespace device
diff --git a/device/u2f/u2f_return_code.h b/device/u2f/u2f_return_code.h new file mode 100644 index 0000000..4aa0b42 --- /dev/null +++ b/device/u2f/u2f_return_code.h
@@ -0,0 +1,19 @@ +// Copyright 2017 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. + +#ifndef DEVICE_U2F_U2F_RETURN_CODE_H_ +#define DEVICE_U2F_U2F_RETURN_CODE_H_ + +namespace device { + +enum class U2fReturnCode : uint8_t { + SUCCESS, + FAILURE, + INVALID_PARAMS, + CONDITIONS_NOT_SATISFIED, +}; + +} // namespace device + +#endif // DEVICE_U2F_U2F_RETURN_CODE_H_
diff --git a/device/u2f/u2f_sign.cc b/device/u2f/u2f_sign.cc new file mode 100644 index 0000000..d537c48 --- /dev/null +++ b/device/u2f/u2f_sign.cc
@@ -0,0 +1,92 @@ +// Copyright 2017 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 "u2f_sign.h" + +#include "base/memory/ptr_util.h" + +namespace device { + +U2fSign::U2fSign(const std::vector<std::vector<uint8_t>>& registered_keys, + const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb) + : U2fRequest(cb), + registered_keys_(registered_keys), + challenge_hash_(challenge_hash), + app_param_(app_param), + weak_factory_(this) {} + +U2fSign::~U2fSign() {} + +// static +std::unique_ptr<U2fRequest> U2fSign::TrySign( + const std::vector<std::vector<uint8_t>>& registered_keys, + const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb) { + std::unique_ptr<U2fRequest> request = + base::MakeUnique<U2fSign>(registered_keys, challenge_hash, app_param, cb); + request->Start(); + return request; +} + +void U2fSign::TryDevice() { + DCHECK(current_device_); + + if (registered_keys_.size() == 0) { + // Send registration (Fake enroll) if no keys were provided + current_device_->Register( + kBogusAppParam, kBogusChallenge, + base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(), + registered_keys_.cbegin())); + return; + } + // Try signing current device with the first registered key + auto it = registered_keys_.cbegin(); + current_device_->Sign( + app_param_, challenge_hash_, *it, + base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(), it)); +} + +void U2fSign::OnTryDevice(std::vector<std::vector<uint8_t>>::const_iterator it, + U2fReturnCode return_code, + std::vector<uint8_t> response_data) { + switch (return_code) { + case U2fReturnCode::SUCCESS: + state_ = State::COMPLETE; + cb_.Run(return_code, response_data); + break; + case U2fReturnCode::CONDITIONS_NOT_SATISFIED: { + // Key handle is accepted by this device, but waiting on user touch. Move + // on and try this device again later. + state_ = State::IDLE; + Transition(); + break; + } + case U2fReturnCode::INVALID_PARAMS: + if (++it != registered_keys_.end()) { + // Key is not for this device. Try signing with the next key. + current_device_->Sign( + app_param_, challenge_hash_, *it, + base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(), it)); + } else { + // No provided key was accepted by this device. Send registration + // (Fake enroll) request to device. + current_device_->Register( + kBogusAppParam, kBogusChallenge, + base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(), + registered_keys_.cbegin())); + } + break; + default: + // Some sort of failure occured. Abandon this device and move on. + state_ = State::IDLE; + current_device_ = nullptr; + Transition(); + break; + } +} + +} // namespace device
diff --git a/device/u2f/u2f_sign.h b/device/u2f/u2f_sign.h new file mode 100644 index 0000000..e924137 --- /dev/null +++ b/device/u2f/u2f_sign.h
@@ -0,0 +1,51 @@ +// Copyright 2017 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. + +#ifndef DEVICE_U2F_U2F_SIGN_H_ +#define DEVICE_U2F_U2F_SIGN_H_ + +#include <vector> + +#include "u2f_request.h" + +namespace device { + +class U2fSign : public U2fRequest { + public: + U2fSign(const std::vector<std::vector<uint8_t>>& registered_keys, + const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb); + ~U2fSign() override; + + static std::unique_ptr<U2fRequest> TrySign( + const std::vector<std::vector<uint8_t>>& registered_keys, + const std::vector<uint8_t>& challenge_hash, + const std::vector<uint8_t>& app_param, + const ResponseCallback& cb); + + private: + void TryDevice() override; + void OnTryDevice(std::vector<std::vector<uint8_t>>::const_iterator, + U2fReturnCode, + std::vector<uint8_t>); + + const std::vector<std::vector<uint8_t>> registered_keys_; + std::vector<uint8_t> challenge_hash_; + std::vector<uint8_t> app_param_; + const std::vector<uint8_t> kBogusAppParam = { + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41}; + const std::vector<uint8_t> kBogusChallenge = { + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}; + + base::WeakPtrFactory<U2fSign> weak_factory_; +}; + +} // namespace device + +#endif // DEVICE_U2F_U2F_SIGN_H_
diff --git a/device/u2f/u2f_sign_unittest.cc b/device/u2f/u2f_sign_unittest.cc new file mode 100644 index 0000000..8c846217 --- /dev/null +++ b/device/u2f/u2f_sign_unittest.cc
@@ -0,0 +1,215 @@ +// Copyright 2017 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 <list> + +#include "base/run_loop.h" +#include "base/test/test_io_thread.h" +#include "device/base/mock_device_client.h" +#include "device/hid/mock_hid_service.h" +#include "device/test/test_device_client.h" +#include "mock_u2f_device.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "u2f_sign.h" + +namespace device { +class U2fSignTest : public testing::Test { + public: + U2fSignTest() : io_thread_(base::TestIOThread::kAutoStart) {} + + void SetUp() override { + MockHidService* hid_service = device_client_.hid_service(); + hid_service->FirstEnumerationComplete(); + } + + protected: + base::MessageLoopForUI message_loop_; + base::TestIOThread io_thread_; + device::MockDeviceClient device_client_; +}; + +class TestSignCallback { + public: + TestSignCallback() + : callback_(base::Bind(&TestSignCallback::ReceivedCallback, + base::Unretained(this))) {} + ~TestSignCallback() {} + + void ReceivedCallback(U2fReturnCode status_code, + std::vector<uint8_t> response) { + response_ = std::make_pair(status_code, response); + closure_.Run(); + } + + std::pair<U2fReturnCode, std::vector<uint8_t>>& WaitForCallback() { + closure_ = run_loop_.QuitClosure(); + run_loop_.Run(); + return response_; + } + + const U2fRequest::ResponseCallback& callback() { return callback_; } + + private: + std::pair<U2fReturnCode, std::vector<uint8_t>> response_; + base::Closure closure_; + U2fRequest::ResponseCallback callback_; + base::RunLoop run_loop_; +}; + +TEST_F(U2fSignTest, TestSignSuccess) { + std::vector<uint8_t> key(32, 0xA); + std::vector<std::vector<uint8_t>> handles = {key}; + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice()); + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign)); + EXPECT_CALL(*device.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + TestSignCallback cb; + std::unique_ptr<U2fRequest> request = + U2fSign::TrySign(handles, std::vector<uint8_t>(32), + std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + // Correct key was sent so a sign response is expected + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]); +} + +TEST_F(U2fSignTest, TestDelayedSuccess) { + std::vector<uint8_t> key(32, 0xA); + std::vector<std::vector<uint8_t>> handles = {key}; + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice()); + + // Go through the state machine twice before success + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign)); + EXPECT_CALL(*device.get(), TryWink(testing::_)) + .Times(2) + .WillRepeatedly(testing::Invoke(MockU2fDevice::WinkDoNothing)); + TestSignCallback cb; + + std::unique_ptr<U2fRequest> request = + U2fSign::TrySign(handles, std::vector<uint8_t>(32), + std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + // Correct key was sent so a sign response is expected + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]); +} + +TEST_F(U2fSignTest, TestMultipleHandles) { + std::vector<uint8_t> key(32, 0xA); + std::vector<uint8_t> wrong_key0(32, 0xB); + std::vector<uint8_t> wrong_key1(32, 0xC); + std::vector<uint8_t> wrong_key2(32, 0xD); + // Put wrong key first to ensure that it will be tested before the correct key + std::vector<std::vector<uint8_t>> handles = {wrong_key0, wrong_key1, + wrong_key2, key}; + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice()); + + // Wrong key would respond with SW_WRONG_DATA + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WrongData)) + .WillOnce(testing::Invoke(MockU2fDevice::WrongData)) + .WillOnce(testing::Invoke(MockU2fDevice::WrongData)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign)); + // Only one wink expected per device + EXPECT_CALL(*device.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + + TestSignCallback cb; + std::unique_ptr<U2fRequest> request = + U2fSign::TrySign(handles, std::vector<uint8_t>(32), + std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + // Correct key was sent so a sign response is expected + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]); +} + +TEST_F(U2fSignTest, TestMultipleDevices) { + std::vector<uint8_t> key0(32, 0xA); + std::vector<uint8_t> key1(32, 0xB); + // Second device will have a successful touch + std::vector<std::vector<uint8_t>> handles = {key0, key1}; + std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice()); + std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice()); + + EXPECT_CALL(*device0.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WrongData)) + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied)); + // One wink per device + EXPECT_CALL(*device0.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + EXPECT_CALL(*device1.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign)); + EXPECT_CALL(*device1.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + + TestSignCallback cb; + std::unique_ptr<U2fRequest> request = + U2fSign::TrySign(handles, std::vector<uint8_t>(32), + std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device0)); + request->AddDeviceForTesting(std::move(device1)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + // Correct key was sent so a sign response is expected + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]); +} + +TEST_F(U2fSignTest, TestFakeEnroll) { + std::vector<uint8_t> key0(32, 0xA); + std::vector<uint8_t> key1(32, 0xB); + // Second device will be have a successful touch + std::vector<std::vector<uint8_t>> handles = {key0, key1}; + std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice()); + std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice()); + + EXPECT_CALL(*device0.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WrongData)) + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied)); + // One wink per device + EXPECT_CALL(*device0.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + // Both keys will be tried, when both fail, register is tried on that device + EXPECT_CALL(*device1.get(), DeviceTransactPtr(testing::_, testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WrongData)) + .WillOnce(testing::Invoke(MockU2fDevice::WrongData)) + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister)); + EXPECT_CALL(*device1.get(), TryWink(testing::_)) + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing)); + + TestSignCallback cb; + std::unique_ptr<U2fRequest> request = + U2fSign::TrySign(handles, std::vector<uint8_t>(32), + std::vector<uint8_t>(32), cb.callback()); + request->Start(); + request->AddDeviceForTesting(std::move(device0)); + request->AddDeviceForTesting(std::move(device1)); + std::pair<U2fReturnCode, std::vector<uint8_t>>& response = + cb.WaitForCallback(); + EXPECT_EQ(U2fReturnCode::SUCCESS, response.first); + // Device that responded had no correct keys, so a registration response is + // expected + ASSERT_LT(static_cast<size_t>(0), response.second.size()); + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]); +} + +} // namespace device
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc index 39d5dea..9abc53e 100644 --- a/extensions/renderer/api_binding.cc +++ b/extensions/renderer/api_binding.cc
@@ -289,9 +289,9 @@ v8::Local<v8::Object> APIBinding::CreateInstance( v8::Local<v8::Context> context, - v8::Isolate* isolate, const AvailabilityCallback& is_available) { DCHECK(IsContextValid(context)); + v8::Isolate* isolate = context->GetIsolate(); if (object_template_.IsEmpty()) InitializeTemplate(isolate); DCHECK(!object_template_.IsEmpty()); @@ -498,11 +498,7 @@ // GetCurrentContext() should always be correct. v8::Local<v8::Context> context = isolate->GetCurrentContext(); - std::vector<v8::Local<v8::Value>> argument_list; - if (arguments->Length() > 0) { - // Just copying handles should never fail. - CHECK(arguments->GetRemaining(&argument_list)); - } + std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll(); bool invalid_invocation = false; v8::Local<v8::Function> custom_callback;
diff --git a/extensions/renderer/api_binding.h b/extensions/renderer/api_binding.h index 7728e3f..972df11 100644 --- a/extensions/renderer/api_binding.h +++ b/extensions/renderer/api_binding.h
@@ -72,7 +72,6 @@ // Returns a new v8::Object for the API this APIBinding represents. v8::Local<v8::Object> CreateInstance( v8::Local<v8::Context> context, - v8::Isolate* isolate, const AvailabilityCallback& is_available); APIBindingHooks* hooks() { return binding_hooks_.get(); }
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc index c589d08..d17e720 100644 --- a/extensions/renderer/api_binding_unittest.cc +++ b/extensions/renderer/api_binding_unittest.cc
@@ -313,7 +313,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); EXPECT_EQ( 0u, binding_object->GetOwnPropertyNames(context).ToLocalChecked()->Length()); @@ -329,7 +329,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); ExpectPass(binding_object, "obj.oneString('foo');", "['foo']", false); ExpectPass(binding_object, "obj.oneString('');", "['']", false); @@ -423,7 +423,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); const char kExpected[] = "{'ALPHA':'alpha','CAMEL_CASE':'camelCase','HYPHEN_ATED':'Hyphen-ated'," @@ -450,7 +450,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); EXPECT_EQ( "{\"\":\"\",\"OTHER\":\"other\"}", @@ -497,7 +497,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", "[{'prop1':'foo'}]", false); @@ -546,7 +546,7 @@ }; v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(is_available)); + binding()->CreateInstance(context, base::Bind(is_available)); auto is_defined = [&binding_object, context](const std::string& name) { v8::Local<v8::Value> val = @@ -574,7 +574,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); // Event behavior is tested in the APIEventHandler unittests as well as the // APIBindingsSystem tests, so we really only need to check that the events @@ -612,7 +612,7 @@ v8::HandleScope handle_scope(isolate()); v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); EXPECT_EQ("17", GetStringPropertyFromObject(binding_object, context, "prop1")); EXPECT_EQ(R"({"subprop1":"some value","subprop2":true})", @@ -664,7 +664,7 @@ v8::HandleScope handle_scope(isolate()); v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); EXPECT_EQ(R"({"alphaProp":"alphaVal"})", GetStringPropertyFromObject(binding_object, context, "alpha")); EXPECT_EQ( @@ -680,7 +680,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); v8::Local<v8::Function> func = FunctionFromString(context, "(function(obj) { obj.oneString('foo'); })"); @@ -700,10 +700,10 @@ SetFunctions(kFunctions); InitializeBinding(); - v8::Local<v8::Object> binding_object_a = binding()->CreateInstance( - context_a, isolate(), base::Bind(&AllowAllAPIs)); - v8::Local<v8::Object> binding_object_b = binding()->CreateInstance( - context_b, isolate(), base::Bind(&AllowAllAPIs)); + v8::Local<v8::Object> binding_object_a = + binding()->CreateInstance(context_a, base::Bind(&AllowAllAPIs)); + v8::Local<v8::Object> binding_object_b = + binding()->CreateInstance(context_b, base::Bind(&AllowAllAPIs)); ExpectPass(context_a, binding_object_a, "obj.oneString('foo');", "['foo']", false); @@ -744,7 +744,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); // First try calling the oneString() method, which has a custom hook // installed. @@ -785,7 +785,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); // First try calling with an invalid invocation. An error should be raised and // the hook should never have been called, since the arguments didn't match. @@ -837,7 +837,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); // Call the method with a hook. Since the hook updates arguments before // validation, we should be able to pass in invalid arguments and still @@ -895,7 +895,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); v8::Local<v8::Function> function = FunctionFromString(context, @@ -937,7 +937,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); v8::Local<v8::Function> function = FunctionFromString(context, @@ -998,7 +998,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); v8::Local<v8::Function> function = FunctionFromString(context, @@ -1048,7 +1048,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); { // Test an invocation that we expect to throw an exception. @@ -1104,7 +1104,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); // Try calling the method with an invalid signature. Since it's invalid, we // should never enter the hook. @@ -1152,7 +1152,7 @@ InitializeBinding(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); // Call the method with a valid signature. The hook should be entered and // manipulate the arguments. @@ -1168,7 +1168,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> binding_object = - binding()->CreateInstance(context, isolate(), base::Bind(&AllowAllAPIs)); + binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); v8::Local<v8::Function> function = FunctionFromString(context, "(function(obj) { obj.oneString('foo');})");
diff --git a/extensions/renderer/api_bindings_system.cc b/extensions/renderer/api_bindings_system.cc index 344041f..29e38c8 100644 --- a/extensions/renderer/api_bindings_system.cc +++ b/extensions/renderer/api_bindings_system.cc
@@ -31,7 +31,6 @@ v8::Local<v8::Object> APIBindingsSystem::CreateAPIInstance( const std::string& api_name, v8::Local<v8::Context> context, - v8::Isolate* isolate, const APIBinding::AvailabilityCallback& is_available, APIBindingHooks** hooks_out) { std::unique_ptr<APIBinding>& binding = api_bindings_[api_name]; @@ -39,7 +38,7 @@ binding = CreateNewAPIBinding(api_name); if (hooks_out) *hooks_out = binding->hooks(); - return binding->CreateInstance(context, isolate, is_available); + return binding->CreateInstance(context, is_available); } std::unique_ptr<APIBinding> APIBindingsSystem::CreateNewAPIBinding(
diff --git a/extensions/renderer/api_bindings_system.h b/extensions/renderer/api_bindings_system.h index 9f96dbb..138d42d9 100644 --- a/extensions/renderer/api_bindings_system.h +++ b/extensions/renderer/api_bindings_system.h
@@ -54,7 +54,6 @@ v8::Local<v8::Object> CreateAPIInstance( const std::string& api_name, v8::Local<v8::Context> context, - v8::Isolate* isolate, const APIBinding::AvailabilityCallback& is_available, APIBindingHooks** hooks_out);
diff --git a/extensions/renderer/api_bindings_system_unittest.cc b/extensions/renderer/api_bindings_system_unittest.cc index 84f7d91..b00c8465 100644 --- a/extensions/renderer/api_bindings_system_unittest.cc +++ b/extensions/renderer/api_bindings_system_unittest.cc
@@ -205,10 +205,10 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> alpha_api = bindings_system()->CreateAPIInstance( - kAlphaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); + kAlphaAPIName, context, base::Bind(&AllowAllAPIs), nullptr); ASSERT_FALSE(alpha_api.IsEmpty()); v8::Local<v8::Object> beta_api = bindings_system()->CreateAPIInstance( - kBetaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); + kBetaAPIName, context, base::Bind(&AllowAllAPIs), nullptr); ASSERT_FALSE(beta_api.IsEmpty()); { @@ -334,7 +334,7 @@ binding_hooks->SetDelegate(std::move(test_hooks)); v8::Local<v8::Object> alpha_api = bindings_system()->CreateAPIInstance( - kAlphaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); + kAlphaAPIName, context, base::Bind(&AllowAllAPIs), nullptr); ASSERT_FALSE(alpha_api.IsEmpty()); { @@ -372,7 +372,7 @@ APIBindingHooks* hooks = nullptr; v8::Local<v8::Object> alpha_api = bindings_system()->CreateAPIInstance( - kAlphaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), &hooks); + kAlphaAPIName, context, base::Bind(&AllowAllAPIs), &hooks); ASSERT_FALSE(alpha_api.IsEmpty()); ASSERT_TRUE(hooks); v8::Local<v8::Object> js_hooks = hooks->GetJSHookInterface(context); @@ -415,7 +415,7 @@ // alpha API yet, since this tests that we can lazily populate the type // information. v8::Local<v8::Object> gamma_api = bindings_system()->CreateAPIInstance( - kGammaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); + kGammaAPIName, context, base::Bind(&AllowAllAPIs), nullptr); ASSERT_FALSE(gamma_api.IsEmpty()); { @@ -449,7 +449,7 @@ binding_hooks->SetDelegate(std::move(test_hooks)); v8::Local<v8::Object> api = bindings_system()->CreateAPIInstance( - kAlphaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); + kAlphaAPIName, context, base::Bind(&AllowAllAPIs), nullptr); v8::Local<v8::Value> event = GetPropertyFromObject(api, context, "alphaEvent");
diff --git a/extensions/renderer/chrome_setting.cc b/extensions/renderer/chrome_setting.cc index 43dad58..81f1ca2 100644 --- a/extensions/renderer/chrome_setting.cc +++ b/extensions/renderer/chrome_setting.cc
@@ -133,11 +133,7 @@ v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); - std::vector<v8::Local<v8::Value>> argument_list; - if (arguments->Length() > 0) { - // Just copying handles should never fail. - CHECK(arguments->GetRemaining(&argument_list)); - } + std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll(); std::string full_name = "types.ChromeSetting." + method_name; std::unique_ptr<base::ListValue> converted_arguments;
diff --git a/extensions/renderer/declarative_event.cc b/extensions/renderer/declarative_event.cc index 4e00229..9365c8d 100644 --- a/extensions/renderer/declarative_event.cc +++ b/extensions/renderer/declarative_event.cc
@@ -174,13 +174,7 @@ v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); - // TODO(devlin): This pattern is getting common. We should probably pull it - // out somewhere. - std::vector<v8::Local<v8::Value>> argument_list; - if (arguments->Length() > 0) { - // Just copying handles should never fail. - CHECK(arguments->GetRemaining(&argument_list)); - } + std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll(); // The events API has two undocumented parameters for each function: the name // of the event, and the "webViewInstanceId". Currently, stub 0 for webview
diff --git a/extensions/renderer/declarative_event_unittest.cc b/extensions/renderer/declarative_event_unittest.cc index 4b33591d..c5771d8 100644 --- a/extensions/renderer/declarative_event_unittest.cc +++ b/extensions/renderer/declarative_event_unittest.cc
@@ -199,8 +199,7 @@ v8::Local<v8::Context> context = MainContext(); v8::Local<v8::Object> api = bindings_system()->CreateAPIInstance( - kDeclarativeAPIName, context, isolate(), base::Bind(&AllowAllAPIs), - nullptr); + kDeclarativeAPIName, context, base::Bind(&AllowAllAPIs), nullptr); ASSERT_FALSE(api.IsEmpty()); v8::Local<v8::Value> declarative_event =
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc index a2a9fa8..f4d5d5c 100644 --- a/extensions/renderer/native_extension_bindings_system.cc +++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -198,8 +198,7 @@ APIBindingsSystem* bindings_system) { APIBindingHooks* hooks = nullptr; v8::Local<v8::Object> binding_object = bindings_system->CreateAPIInstance( - name, context, context->GetIsolate(), - base::Bind(&IsAPIMethodAvailable, script_context), &hooks); + name, context, base::Bind(&IsAPIMethodAvailable, script_context), &hooks); gin::Handle<APIBindingBridge> bridge_handle = gin::CreateHandle( context->GetIsolate(),
diff --git a/extensions/renderer/storage_area.cc b/extensions/renderer/storage_area.cc index d3017399..b952460 100644 --- a/extensions/renderer/storage_area.cc +++ b/extensions/renderer/storage_area.cc
@@ -183,11 +183,7 @@ v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); - std::vector<v8::Local<v8::Value>> argument_list; - if (arguments->Length() > 0) { - // Just copying handles should never fail. - CHECK(arguments->GetRemaining(&argument_list)); - } + std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll(); std::unique_ptr<base::ListValue> converted_arguments; v8::Local<v8::Function> callback;
diff --git a/headless/BUILD.gn b/headless/BUILD.gn index b3407de0..3922634 100644 --- a/headless/BUILD.gn +++ b/headless/BUILD.gn
@@ -19,9 +19,9 @@ } } -group("headless_lib") { +group("headless") { deps = [ - "//headless:headless", + "//headless:headless_lib", ] } @@ -201,7 +201,7 @@ ] } -component("headless") { +static_library("headless_lib") { sources = generated_devtools_api + [ "app/headless_shell_switches.cc", "app/headless_shell_switches.h", @@ -243,6 +243,10 @@ "lib/headless_crash_reporter_client.h", "lib/headless_content_client.cc", "lib/headless_content_client.h", + "lib/headless_content_main_delegate.cc", + "lib/headless_content_main_delegate.h", + "lib/renderer/headless_content_renderer_client.cc", + "lib/renderer/headless_content_renderer_client.h", "public/headless_browser.cc", "public/headless_browser.h", "public/headless_browser_context.h", @@ -323,6 +327,9 @@ "//components/crash/content/browser", "//components/security_state/content", "//components/security_state/core", + "//content/public/app:both", + "//content/public/browser", + "//content/public/child:child", "//content/public/common", "//content/public/common:service_names", "//services/service_manager/public/cpp", @@ -334,28 +341,19 @@ "//url", ] - if (is_component_build) { - sources += [ - "lib/headless_content_main_delegate.cc", - "lib/headless_content_main_delegate.h", - "lib/renderer/headless_content_renderer_client.cc", - "lib/renderer/headless_content_renderer_client.h", - ] - - if (enable_basic_printing) { - deps += [ - "//components/printing/browser", - "//components/printing/renderer", - ] - } - } - if (is_mac) { deps += [ ":mac_helpers" ] } else { deps += [ "//ui/aura" ] } + if (enable_basic_printing) { + deps += [ + "//components/printing/browser", + "//components/printing/renderer", + ] + } + if (headless_use_embedded_resources) { deps += [ ":embed_resources" ] sources += [ @@ -369,32 +367,8 @@ if (use_ozone) { deps += [ "//ui/ozone" ] } - configs += [ ":headless_implementation" ] -} -# Headless renderer is a convenience source set that includes headless classes -# that depend on the reenderer. These are not added in case of a component build -# since in that case they are already included in the headless component. -source_set("headless_renderer") { - deps = [ - ":headless", - ] - if (!is_component_build) { - sources = [ - "lib/headless_content_main_delegate.cc", - "lib/headless_content_main_delegate.h", - "lib/renderer/headless_content_renderer_client.cc", - "lib/renderer/headless_content_renderer_client.h", - ] - deps += [ "//ui/base" ] - if (enable_basic_printing) { - deps += [ - "//components/printing/browser", - "//components/printing/renderer", - ] - } - configs += [ ":headless_implementation" ] - } + configs += [ ":headless_implementation" ] } group("headless_tests") { @@ -419,7 +393,7 @@ ] deps = [ - ":headless", + ":headless_lib", "//base/test:run_all_unittests", "//base/test:test_support", "//testing/gmock", @@ -513,80 +487,14 @@ deps = [ ":embedder_mojo_for_testing", ":headless_browser_tests_pak", - ":headless_renderer", "//base", "//content/test:test_support", + "//headless:headless_lib", "//testing/gmock", "//testing/gtest", ] } -# Headless library with only browser dependencies. This is used when no child -# dependencies are needed in the target (e.g. chrome:main_dll). -static_library("headless_shell_browser_lib") { - if (is_multi_dll_chrome) { - defines = [ "CHROME_MULTIPLE_DLL_BROWSER" ] - } - - sources = [ - "app/headless_shell.cc", - "app/headless_shell.h", - "app/headless_shell_switches.cc", - "app/headless_shell_switches.h", - "app/shell_navigation_request.cc", - "app/shell_navigation_request.h", - "lib/headless_content_main_delegate.cc", - "lib/headless_content_main_delegate.h", - "public/headless_shell.h", - ] - - deps = [ - ":headless", - "//content/public/browser", - "//content/public/common", - ] - - if (is_win) { - deps += [ - "//content:sandbox_helper_win", - "//sandbox", - ] - } - - configs += [ ":headless_implementation" ] -} - -# Headless library with child specific dependencies (e.g., renderer). This -# is used when no browser depencendies are needed (e.g. chrome:child_dll). -static_library("headless_shell_child_lib") { - if (is_multi_dll_chrome) { - defines = [ "CHROME_MULTIPLE_DLL_CHILD" ] - } - - sources = [ - "app/headless_shell.cc", - "app/headless_shell.h", - "app/headless_shell_switches.cc", - "app/headless_shell_switches.h", - "app/shell_navigation_request.cc", - "app/shell_navigation_request.h", - "lib/headless_content_main_delegate.cc", - "lib/headless_content_main_delegate.h", - "public/headless_shell.h", - ] - - deps = [ - ":headless_renderer", - "//content/public/child:child", - "//net", - "//ui/base", - ] - - configs += [ ":headless_implementation" ] -} - -# Headless library with all included dependencies. Use this library unless you -# have browser/child dependencies restrictions. static_library("headless_shell_lib") { sources = [ "app/headless_shell.cc", @@ -599,19 +507,10 @@ ] deps = [ - ":headless_renderer", - "//content/public/app:both", - "//content/public/browser", - "//content/public/child:child", - "//content/public/common", + "//headless:headless_lib", ] - if (is_win) { - deps += [ - "//content:sandbox_helper_win", - "//sandbox", - ] - } + configs += [ ":headless_implementation" ] } executable("headless_shell") { @@ -620,8 +519,18 @@ ] deps = [ - ":headless_shell_lib", + "//headless:headless_shell_lib", ] + + if (is_win) { + deps += [ + "//build/win:default_exe_manifest", + "//content:sandbox_helper_win", + "//sandbox", + ] + } + + configs += [ ":headless_implementation" ] } process_version("version_header") { @@ -639,6 +548,6 @@ ] deps = [ - ":headless_shell_lib", + "//headless:headless_shell_lib", ] }
diff --git a/headless/DEPS b/headless/DEPS index 70959d7..2e51ac4e 100644 --- a/headless/DEPS +++ b/headless/DEPS
@@ -3,7 +3,6 @@ "+components/crash/content/browser", "+content/public/app", "+content/public/browser", - "+content/public/renderer", "+content/public/common", "+content/public/test", "+mojo/public", @@ -17,6 +16,5 @@ "+ui/gfx/geometry", "+ui/gl", "+ui/ozone/public", - "+sandbox/win/src", "+services/service_manager/public", ]
diff --git a/headless/app/headless_example.cc b/headless/app/headless_example.cc index d344796b..56932ef 100644 --- a/headless/app/headless_example.cc +++ b/headless/app/headless_example.cc
@@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/memory/weak_ptr.h" -#include "build/build_config.h" #include "headless/public/devtools/domains/page.h" #include "headless/public/devtools/domains/runtime.h" #include "headless/public/headless_browser.h" @@ -20,11 +19,6 @@ #include "headless/public/headless_web_contents.h" #include "ui/gfx/geometry/size.h" -#if defined(OS_WIN) -#include "content/public/app/sandbox_helper_win.h" -#include "sandbox/win/src/sandbox_types.h" -#endif - // This class contains the main application logic, i.e., waiting for a page to // load and printing its DOM. Note that browser initialization happens outside // this class. @@ -164,24 +158,15 @@ } int main(int argc, const char** argv) { -#if !defined(OS_WIN) // This function must be the first thing we call to make sure child processes // such as the renderer are started properly. The headless library starts // child processes by forking and exec'ing the main application. headless::RunChildProcessIfNeeded(argc, argv); -#endif // Create a headless browser instance. There can be one of these per process // and it can only be initialized once. headless::HeadlessBrowser::Options::Builder builder(argc, argv); -#if defined(OS_WIN) - // In windows, you must initialize and set the sandbox, or pass it along - // if it has already been initialized. - sandbox::SandboxInterfaceInfo sandbox_info = {0}; - content::InitializeSandboxInfo(&sandbox_info); - builder.SetSandboxInfo(&sandbox_info); -#endif // Here you can customize browser options. As an example we set the window // size. builder.SetWindowSize(gfx::Size(800, 600));
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc index e12d12c..ff670db0 100644 --- a/headless/app/headless_shell.cc +++ b/headless/app/headless_shell.cc
@@ -18,7 +18,6 @@ #include "base/memory/weak_ptr.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" -#include "content/public/app/content_main.h" #include "headless/app/headless_shell.h" #include "headless/app/headless_shell_switches.h" #include "headless/public/headless_devtools_target.h" @@ -29,10 +28,6 @@ #include "net/http/http_util.h" #include "ui/gfx/geometry/size.h" -#if defined(OS_WIN) -#include "sandbox/win/src/sandbox_types.h" -#endif - namespace headless { namespace { // Address where to listen to incoming DevTools connections. @@ -429,10 +424,10 @@ } void HeadlessShell::OnFileWritten(const base::FilePath file_name, - const size_t length, + const int length, base::File::Error error_code, int write_result) { - if (write_result < static_cast<int>(length)) { + if (write_result < length) { // TODO(eseckler): Support recovering from partial writes. LOG(ERROR) << "Writing to file " << file_name.value() << " was unsuccessful: " @@ -502,20 +497,11 @@ return true; } -#if defined(OS_WIN) -int HeadlessShellMain(HINSTANCE instance, - sandbox::SandboxInterfaceInfo* sandbox_info) { - base::CommandLine::Init(0, nullptr); - HeadlessBrowser::Options::Builder builder(0, nullptr); - builder.SetInstance(instance); - builder.SetSandboxInfo(std::move(sandbox_info)); -#else int HeadlessShellMain(int argc, const char** argv) { base::CommandLine::Init(argc, argv); RunChildProcessIfNeeded(argc, argv); - HeadlessBrowser::Options::Builder builder(argc, argv); -#endif // defined(OS_WIN) HeadlessShell shell; + HeadlessBrowser::Options::Builder builder(argc, argv); // Enable devtools if requested. const base::CommandLine& command_line( @@ -523,7 +509,7 @@ if (!ValidateCommandLine(command_line)) return EXIT_FAILURE; - if (command_line.HasSwitch(switches::kEnableCrashReporter)) + if (command_line.HasSwitch(::switches::kEnableCrashReporter)) builder.SetCrashReporterEnabled(true); if (command_line.HasSwitch(switches::kCrashDumpsDir)) { builder.SetCrashDumpsDir( @@ -611,12 +597,4 @@ base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); } -int HeadlessShellMain(const content::ContentMainParams& params) { -#if defined(OS_WIN) - return HeadlessShellMain(params.instance, params.sandbox_info); -#else - return HeadlessShellMain(params.argc, params.argv); -#endif -} - } // namespace headless
diff --git a/headless/app/headless_shell.h b/headless/app/headless_shell.h index e38f017..91535105 100644 --- a/headless/app/headless_shell.h +++ b/headless/app/headless_shell.h
@@ -86,7 +86,7 @@ const base::FilePath file_name, base::File::Error error_code); void OnFileWritten(const base::FilePath file_name, - const size_t length, + const int length, base::File::Error error_code, int write_result); void OnFileClosed(base::File::Error error_code);
diff --git a/headless/app/headless_shell_main.cc b/headless/app/headless_shell_main.cc index 5f63fcb..3ae4553 100644 --- a/headless/app/headless_shell_main.cc +++ b/headless/app/headless_shell_main.cc
@@ -2,20 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "build/build_config.h" #include "headless/public/headless_shell.h" -#if defined(OS_WIN) -#include "content/public/app/sandbox_helper_win.h" -#include "sandbox/win/src/sandbox_types.h" -#endif - int main(int argc, const char** argv) { -#if defined(OS_WIN) - sandbox::SandboxInterfaceInfo sandbox_info = {0}; - content::InitializeSandboxInfo(&sandbox_info); - return headless::HeadlessShellMain(0, &sandbox_info); -#else return headless::HeadlessShellMain(argc, argv); -#endif // defined(OS_WIN) }
diff --git a/headless/app/headless_shell_switches.cc b/headless/app/headless_shell_switches.cc index 45e8a11..86ced81 100644 --- a/headless/app/headless_shell_switches.cc +++ b/headless/app/headless_shell_switches.cc
@@ -12,9 +12,6 @@ // transparent. const char kDefaultBackgroundColor[] = "default-background-color"; -// Enable chrash reporter for headless. -const char kEnableCrashReporter[] = "enable-crash-reporter"; - // The directory breakpad should store minidumps in. const char kCrashDumpsDir[] = "crash-dumps-dir";
diff --git a/headless/app/headless_shell_switches.h b/headless/app/headless_shell_switches.h index 69b24b61..dd22903f 100644 --- a/headless/app/headless_shell_switches.h +++ b/headless/app/headless_shell_switches.h
@@ -11,7 +11,6 @@ namespace switches { extern const char kDefaultBackgroundColor[]; -extern const char kEnableCrashReporter[]; extern const char kCrashDumpsDir[]; extern const char kDeterministicFetch[]; extern const char kDumpDom[];
diff --git a/headless/lib/browser/DEPS b/headless/lib/browser/DEPS index 25bce98..bc59dd2 100644 --- a/headless/lib/browser/DEPS +++ b/headless/lib/browser/DEPS
@@ -5,6 +5,7 @@ "+printing", "+storage/browser/quota", "+ui/aura", + "+sandbox/win/src", ] specific_include_rules = { "headless_clipboard.h": [
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc index c45408f9..747639c 100644 --- a/headless/lib/browser/headless_browser_impl.cc +++ b/headless/lib/browser/headless_browser_impl.cc
@@ -27,6 +27,11 @@ #include "ui/events/devices/device_data_manager.h" #include "ui/gfx/geometry/size.h" +#if defined(OS_WIN) +#include "content/public/app/sandbox_helper_win.h" +#include "sandbox/win/src/sandbox_types.h" +#endif + namespace headless { namespace { @@ -35,10 +40,9 @@ const base::Callback<void(HeadlessBrowser*)>& on_browser_start_callback) { content::ContentMainParams params(nullptr); #if defined(OS_WIN) - // Sandbox info has to be set and initialized. - CHECK(options.sandbox_info); - params.instance = options.instance; - params.sandbox_info = std::move(options.sandbox_info); + sandbox::SandboxInterfaceInfo sandbox_info = {0}; + content::InitializeSandboxInfo(&sandbox_info); + params.sandbox_info = &sandbox_info; #elif !defined(OS_ANDROID) params.argc = options.argc; params.argv = options.argv; @@ -196,7 +200,6 @@ return find_it->second.get(); } -#if !defined(OS_WIN) void RunChildProcessIfNeeded(int argc, const char** argv) { base::CommandLine::Init(argc, argv); const base::CommandLine& command_line( @@ -215,7 +218,6 @@ exit(RunContentMain(builder.Build(), base::Callback<void(HeadlessBrowser*)>())); } -#endif // !defined(OS_WIN) int HeadlessBrowserMain( HeadlessBrowser::Options options,
diff --git a/headless/lib/headless_browser_browsertest.cc b/headless/lib/headless_browser_browsertest.cc index b39dce3..8b6e20c7 100644 --- a/headless/lib/headless_browser_browsertest.cc +++ b/headless/lib/headless_browser_browsertest.cc
@@ -400,7 +400,7 @@ class ProtocolHandlerWithCookies : public net::URLRequestJobFactory::ProtocolHandler { public: - explicit ProtocolHandlerWithCookies(net::CookieList* sent_cookies); + ProtocolHandlerWithCookies(net::CookieList* sent_cookies); ~ProtocolHandlerWithCookies() override {} net::URLRequestJob* MaybeCreateJob( @@ -634,7 +634,11 @@ // TODO(skyostil): This test currently relies on being able to run a shell // script. #if defined(OS_POSIX) -IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, RendererCommandPrefixTest) { +#define MAYBE_RendererCommandPrefixTest RendererCommandPrefixTest +#else +#define MAYBE_RendererCommandPrefixTest DISABLED_RendererCommandPrefixTest +#endif // defined(OS_POSIX) +IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, MAYBE_RendererCommandPrefixTest) { base::ThreadRestrictions::SetIOAllowed(true); base::FilePath launcher_stamp; base::CreateTemporaryFile(&launcher_stamp); @@ -672,7 +676,6 @@ base::DeleteFile(launcher_script, false); base::DeleteFile(launcher_stamp, false); } -#endif // defined(OS_POSIX) class CrashReporterTest : public HeadlessBrowserTest, public HeadlessWebContents::Observer, @@ -683,8 +686,7 @@ void SetUp() override { base::ThreadRestrictions::SetIOAllowed(true); - base::CreateNewTempDirectory(FILE_PATH_LITERAL("CrashReporterTest"), - &crash_dumps_dir_); + base::CreateNewTempDirectory("CrashReporterTest", &crash_dumps_dir_); EXPECT_FALSE(options()->enable_crash_reporter); options()->enable_crash_reporter = true; options()->crash_dumps_dir = crash_dumps_dir_; @@ -752,7 +754,7 @@ base::FileEnumerator::FILES); base::FilePath minidump = it.Next(); EXPECT_FALSE(minidump.empty()); - EXPECT_EQ(FILE_PATH_LITERAL(".dmp"), minidump.Extension()); + EXPECT_EQ(".dmp", minidump.Extension()); EXPECT_TRUE(it.Next().empty()); }
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc index 8526274a..ee1f655 100644 --- a/headless/lib/headless_content_main_delegate.cc +++ b/headless/lib/headless_content_main_delegate.cc
@@ -22,6 +22,7 @@ #include "headless/lib/browser/headless_content_browser_client.h" #include "headless/lib/headless_crash_reporter_client.h" #include "headless/lib/headless_macros.h" +#include "headless/lib/renderer/headless_content_renderer_client.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches.h" #include "ui/gfx/switches.h" @@ -32,10 +33,6 @@ #include "headless/embedded_resource_pak.h" #endif -#if !defined(CHROME_MULTIPLE_DLL_BROWSER) -#include "headless/lib/renderer/headless_content_renderer_client.h" -#endif - #if defined(OS_MACOSX) #include "components/crash/content/app/crashpad.h" #endif @@ -189,8 +186,10 @@ #else if (command_line.HasSwitch(switches::kEnableLogging)) InitLogging(command_line); -#endif // defined(OS_WIN) +#endif +#if !defined(OS_MACOSX) InitCrashReporter(command_line); +#endif // defined(OS_WIN) InitializeResourceBundle(); } @@ -278,23 +277,15 @@ content::ContentBrowserClient* HeadlessContentMainDelegate::CreateContentBrowserClient() { -#if defined(CHROME_MULTIPLE_DLL_CHILD) - return nullptr; -#else browser_client_ = base::MakeUnique<HeadlessContentBrowserClient>(browser_.get()); return browser_client_.get(); -#endif } content::ContentRendererClient* HeadlessContentMainDelegate::CreateContentRendererClient() { -#if defined(CHROME_MULTIPLE_DLL_BROWSER) - return nullptr; -#else renderer_client_ = base::MakeUnique<HeadlessContentRendererClient>(); return renderer_client_.get(); -#endif } } // namespace headless
diff --git a/headless/lib/headless_content_main_delegate.h b/headless/lib/headless_content_main_delegate.h index eb8cd61..0aca886 100644 --- a/headless/lib/headless_content_main_delegate.h +++ b/headless/lib/headless_content_main_delegate.h
@@ -11,8 +11,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "content/public/app/content_main_delegate.h" -#include "content/public/browser/content_browser_client.h" -#include "content/public/renderer/content_renderer_client.h" #include "headless/lib/browser/headless_platform_event_source.h" #include "headless/lib/headless_content_client.h" #include "headless/public/headless_export.h" @@ -24,6 +22,8 @@ namespace headless { class HeadlessBrowserImpl; +class HeadlessContentBrowserClient; +class HeadlessContentRendererClient; // Exported for tests. class HEADLESS_EXPORT HeadlessContentMainDelegate @@ -57,8 +57,8 @@ static HeadlessContentMainDelegate* GetInstance(); - std::unique_ptr<content::ContentRendererClient> renderer_client_; - std::unique_ptr<content::ContentBrowserClient> browser_client_; + std::unique_ptr<HeadlessContentBrowserClient> browser_client_; + std::unique_ptr<HeadlessContentRendererClient> renderer_client_; HeadlessContentClient content_client_; HeadlessPlatformEventSource platform_event_source_;
diff --git a/headless/public/headless_browser.cc b/headless/public/headless_browser.cc index 58067c7..64e31a8 100644 --- a/headless/public/headless_browser.cc +++ b/headless/public/headless_browser.cc
@@ -9,10 +9,6 @@ #include "content/public/common/user_agent.h" #include "headless/public/version.h" -#if defined(OS_WIN) -#include "sandbox/win/src/sandbox_types.h" -#endif - using Options = headless::HeadlessBrowser::Options; using Builder = headless::HeadlessBrowser::Options::Builder; @@ -31,10 +27,6 @@ Options::Options(int argc, const char** argv) : argc(argc), argv(argv), -#if defined(OS_WIN) - instance(0), - sandbox_info(nullptr), -#endif message_pump(nullptr), single_process_mode(false), disable_sandbox(false), @@ -113,18 +105,6 @@ return *this; } -#if defined(OS_WIN) -Builder& Builder::SetInstance(HINSTANCE instance) { - options_.instance = instance; - return *this; -} - -Builder& Builder::SetSandboxInfo(sandbox::SandboxInterfaceInfo* sandbox_info) { - options_.sandbox_info = sandbox_info; - return *this; -} -#endif // defined(OS_WIN) - Builder& Builder::SetUserDataDir(const base::FilePath& user_data_dir) { options_.user_data_dir = user_data_dir; return *this;
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h index b57c21a..4b18f56 100644 --- a/headless/public/headless_browser.h +++ b/headless/public/headless_browser.h
@@ -22,10 +22,6 @@ #include "net/base/ip_endpoint.h" #include "ui/gfx/geometry/size.h" -#if defined(OS_WIN) -#include "sandbox/win/src/sandbox_types.h" -#endif - namespace base { class MessagePump; class SingleThreadTaskRunner; @@ -93,7 +89,7 @@ }; // Embedding API overrides for the headless browser. -struct HEADLESS_EXPORT HeadlessBrowser::Options { +struct HeadlessBrowser::Options { class Builder; Options(Options&& options); @@ -105,14 +101,6 @@ int argc; const char** argv; -#if defined(OS_WIN) - // Set hardware instance if available, otherwise it defaults to 0. - HINSTANCE instance; - - // Set with sandbox information. This has to be already initialized. - sandbox::SandboxInterfaceInfo* sandbox_info; -#endif - // Address at which DevTools should listen for connections. Disabled by // default. net::IPEndPoint devtools_endpoint; @@ -184,7 +172,7 @@ DISALLOW_COPY_AND_ASSIGN(Options); }; -class HEADLESS_EXPORT HeadlessBrowser::Options::Builder { +class HeadlessBrowser::Options::Builder { public: Builder(int argc, const char** argv); Builder(); @@ -198,10 +186,6 @@ Builder& SetDisableSandbox(bool disable_sandbox); Builder& SetGLImplementation(const std::string& gl_implementation); Builder& AddMojoServiceName(const std::string& mojo_service_name); -#if defined(OS_WIN) - Builder& SetInstance(HINSTANCE instance); - Builder& SetSandboxInfo(sandbox::SandboxInterfaceInfo* sandbox_info); -#endif // Per-context settings. @@ -245,9 +229,7 @@ // // [1] // https://chromium.googlesource.com/chromium/src/+/master/docs/linux_zygote.md -#if !defined(OS_WIN) -HEADLESS_EXPORT void RunChildProcessIfNeeded(int argc, const char** argv); -#endif +void RunChildProcessIfNeeded(int argc, const char** argv); // Main entry point for running the headless browser. This function constructs // the headless browser instance, passing it to the given @@ -255,7 +237,7 @@ // the main loop, it will only return after HeadlessBrowser::Shutdown() is // called, returning the exit code for the process. It is not possible to // initialize the browser again after it has been torn down. -HEADLESS_EXPORT int HeadlessBrowserMain( +int HeadlessBrowserMain( HeadlessBrowser::Options options, const base::Callback<void(HeadlessBrowser*)>& on_browser_start_callback);
diff --git a/headless/public/headless_shell.h b/headless/public/headless_shell.h index 3f1caca2..0fd9066 100644 --- a/headless/public/headless_shell.h +++ b/headless/public/headless_shell.h
@@ -5,27 +5,13 @@ #ifndef HEADLESS_PUBLIC_HEADLESS_SHELL_H_ #define HEADLESS_PUBLIC_HEADLESS_SHELL_H_ -#include "content/public/app/content_main.h" - -#if defined(OS_WIN) -#include "sandbox/win/src/sandbox_types.h" -#endif +#include "headless/public/headless_export.h" namespace headless { -// Start the headless shell applications from a |ContentMainParams| object. -// Note that the |ContentMainDelegate| is ignored and -// |HeadlessContentMainDelegate| is used instead. -int HeadlessShellMain(const content::ContentMainParams& params); - // Start the Headless Shell application. Intended to be called early in main(). // Returns the exit code for the process. -#if defined(OS_WIN) -int HeadlessShellMain(HINSTANCE instance, - sandbox::SandboxInterfaceInfo* sandbox_info); -#else -int HeadlessShellMain(int argc, const char** argv); -#endif // defined(OS_WIN) +HEADLESS_EXPORT int HeadlessShellMain(int argc, const char** argv); } // namespace headless #endif // HEADLESS_PUBLIC_HEADLESS_SHELL_H_
diff --git a/headless/public/util/deterministic_http_protocol_handler.cc b/headless/public/util/deterministic_http_protocol_handler.cc index db0866a3..1f61f98 100644 --- a/headless/public/util/deterministic_http_protocol_handler.cc +++ b/headless/public/util/deterministic_http_protocol_handler.cc
@@ -10,7 +10,6 @@ #include "headless/public/util/deterministic_dispatcher.h" #include "headless/public/util/generic_url_request_job.h" #include "headless/public/util/http_url_fetcher.h" -#include "net/http/http_response_headers.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_job_factory_impl.h"
diff --git a/headless/public/util/generic_url_request_job.h b/headless/public/util/generic_url_request_job.h index 679e5ca..8830934e 100644 --- a/headless/public/util/generic_url_request_job.h +++ b/headless/public/util/generic_url_request_job.h
@@ -14,7 +14,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" -#include "headless/public/headless_export.h" #include "headless/public/util/managed_dispatch_url_request_job.h" #include "headless/public/util/url_fetcher.h" #include "net/base/net_errors.h" @@ -35,7 +34,7 @@ class URLRequestDispatcher; // Wrapper around net::URLRequest with helpers to access select metadata. -class HEADLESS_EXPORT Request { +class Request { public: virtual uint64_t GetRequestId() const = 0; @@ -84,7 +83,7 @@ // Details of a pending request received by GenericURLRequestJob which must be // either Allowed, Blocked, Modified or have it's response Mocked. -class HEADLESS_EXPORT PendingRequest { +class PendingRequest { public: virtual const Request* GetRequest() const = 0; @@ -129,7 +128,7 @@ public PendingRequest, public Request { public: - class HEADLESS_EXPORT Delegate { + class Delegate { public: // Notifies the delegate of an PendingRequest which must either be // allowed, blocked, modifed or it's response mocked. Called on an arbitrary
diff --git a/headless/public/util/testing/generic_url_request_mocks.cc b/headless/public/util/testing/generic_url_request_mocks.cc index 54f1ed9..c047e051 100644 --- a/headless/public/util/testing/generic_url_request_mocks.cc +++ b/headless/public/util/testing/generic_url_request_mocks.cc
@@ -8,7 +8,6 @@ #include "base/logging.h" #include "base/threading/thread_task_runner_handle.h" -#include "net/http/http_response_headers.h" namespace net { class URLRequestJob;
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc index 1ad15d8..39c40d7 100644 --- a/headless/test/headless_browser_test.cc +++ b/headless/test/headless_browser_test.cc
@@ -211,9 +211,9 @@ if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION) return; + FAIL() << "Abnormal renderer termination"; FinishAsynchronousTest(); render_process_exited_ = true; - FAIL() << "Abnormal renderer termination"; } void HeadlessAsyncDevTooledBrowserTest::RunTest() {
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h index 069bcb28..ce34169 100644 --- a/media/base/video_frame_metadata.h +++ b/media/base/video_frame_metadata.h
@@ -42,12 +42,6 @@ // contexts. COPY_REQUIRED, - // Indicates that the frame is owned by the decoder and that destroying the - // decoder will make the frame unrenderable. TODO(sandersd): Remove once OSX - // and Windows hardware decoders support frames which outlive the decoder. - // http://crbug.com/595716 and http://crbug.com/602708. - DECODER_OWNS_FRAME, - // Indicates if the current frame is the End of its current Stream. Use // Get/SetBoolean() for this Key. END_OF_STREAM,
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index b81e151..e1f11db4 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -880,9 +880,7 @@ DCHECK(main_task_runner_->BelongsToCurrentThread()); TRACE_EVENT0("media", "WebMediaPlayerImpl:paint"); - // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when - // we have other ways to check if decoder owns video frame. - // See http://crbug.com/595716 and http://crbug.com/602708 + // We can't copy from protected frames. if (cdm_) return; @@ -958,9 +956,7 @@ DCHECK(main_task_runner_->BelongsToCurrentThread()); TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture"); - // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when - // we have other ways to check if decoder owns video frame. - // See http://crbug.com/595716 and http://crbug.com/602708 + // We can't copy from protected frames. if (cdm_) return false;
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java index c2ab234f..ef97261 100644 --- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java +++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -43,7 +43,7 @@ * and their capabilities, using android.hardware.camera2.CameraManager. **/ @JNINamespace("media") -@TargetApi(Build.VERSION_CODES.LOLLIPOP) +@TargetApi(Build.VERSION_CODES.M) public class VideoCaptureCamera2 extends VideoCapture { // Inner class to extend a CameraDevice state change listener. private class CrStateListener extends CameraDevice.StateCallback { @@ -805,7 +805,9 @@ break; } } - // TODO(mcasas): query |cameraCharacteristics| for CONTROL_AE_LOCK_AVAILABLE (API 23) + if (cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE)) { + exposureModes.add(Integer.valueOf(AndroidMeteringMode.FIXED)); + } builder.setExposureModes(integerArrayListToArray(exposureModes)); int jniExposureMode = AndroidMeteringMode.CONTINUOUS; @@ -838,7 +840,9 @@ break; } } - // TODO(mcasas): query |cameraCharacteristics| for CONTROL_AWE_LOCK_AVAILABLE (API 23) + if (cameraCharacteristics.get(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE)) { + whiteBalanceModes.add(Integer.valueOf(AndroidMeteringMode.FIXED)); + } builder.setWhiteBalanceModes(integerArrayListToArray(whiteBalanceModes)); final int whiteBalanceMode = mPreviewRequest.get(CaptureRequest.CONTROL_AWB_MODE);
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc index dde9947..e5d592ef 100644 --- a/media/filters/decoder_stream.cc +++ b/media/filters/decoder_stream.cc
@@ -56,7 +56,7 @@ decoder_selector_(new DecoderSelector<StreamType>(task_runner, std::move(decoders), media_log)), - decoded_frames_since_fallback_(0), + decoder_produced_a_frame_(false), decoding_eos_(false), pending_decode_requests_(0), duration_tracker_(8), @@ -284,8 +284,6 @@ DCHECK(decoder_); } - previous_decoder_ = std::move(decoder_); - decoded_frames_since_fallback_ = 0; decoder_ = std::move(selected_decoder); if (decrypting_demuxer_stream) { decrypting_demuxer_stream_ = std::move(decrypting_demuxer_stream); @@ -346,7 +344,7 @@ // We don't know if the decoder will error out on first decode yet. Save the // buffer to feed it to the fallback decoder later if needed. - if (!decoded_frames_since_fallback_) + if (!decoder_produced_a_frame_) pending_buffers_.push_back(buffer); // It's possible for a buffer to arrive from the demuxer right after the @@ -431,10 +429,10 @@ switch (status) { case DecodeStatus::DECODE_ERROR: - if (!decoded_frames_since_fallback_) { + if (!decoder_produced_a_frame_) { pending_decode_requests_ = 0; - // Prevent all pending decode requests and outputs form those requests + // Prevent all pending decode requests and outputs from those requests // from being called back. fallback_weak_factory_.InvalidateWeakPtrs(); @@ -500,10 +498,9 @@ if (!reset_cb_.is_null()) return; + decoder_produced_a_frame_ = true; traits_.OnDecodeDone(output); - ++decoded_frames_since_fallback_; - // |decoder_| sucessfully decoded a frame. No need to keep buffers for a // fallback decoder. // Note: |fallback_buffers_| might still have buffers, and we will keep @@ -520,13 +517,6 @@ // Store decoded output. ready_outputs_.push_back(output); - - // Destruct any previous decoder once we've decoded enough frames to ensure - // that it's no longer in use. - if (previous_decoder_ && - decoded_frames_since_fallback_ > limits::kMaxVideoFrames) { - previous_decoder_.reset(); - } } template <DemuxerStream::Type StreamType> @@ -564,9 +554,7 @@ DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(pending_demuxer_read_); - if (decoded_frames_since_fallback_) { - DCHECK(pending_demuxer_read_ || state_ == STATE_ERROR) << state_; - } else { + if (!decoder_produced_a_frame_) { DCHECK(state_ == STATE_ERROR || state_ == STATE_REINITIALIZING_DECODER || state_ == STATE_NORMAL) << state_; @@ -577,8 +565,7 @@ // If parallel decode requests are supported, multiple read requests might // have been sent to the demuxer. The buffers might arrive while the decoder // is reinitializing after falling back on first decode error. - if (state_ == STATE_REINITIALIZING_DECODER && - !decoded_frames_since_fallback_) { + if (state_ == STATE_REINITIALIZING_DECODER && !decoder_produced_a_frame_) { switch (status) { case DemuxerStream::kOk: // Save valid buffers to be consumed by the new decoder.
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h index e0f26c9..28a11eb 100644 --- a/media/filters/decoder_stream.h +++ b/media/filters/decoder_stream.h
@@ -112,10 +112,6 @@ config_change_observer_cb_ = config_change_observer; } - const Decoder* get_previous_decoder_for_testing() const { - return previous_decoder_.get(); - } - int get_pending_buffers_size_for_testing() const { return pending_buffers_.size(); } @@ -205,12 +201,8 @@ std::unique_ptr<Decoder> decoder_; - // When falling back from H/W decoding to S/W decoding, destructing the - // GpuVideoDecoder too early results in black frames being displayed. - // |previous_decoder_| is used to keep it alive. It is destroyed once we've - // decoded at least media::limits::kMaxVideoFrames frames after fallback. - int decoded_frames_since_fallback_; - std::unique_ptr<Decoder> previous_decoder_; + // Whether |decoder_| has produced a frame yet. Reset on fallback. + bool decoder_produced_a_frame_; std::unique_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream_;
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index 3207c34..c36b0e1 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc
@@ -679,9 +679,6 @@ frame->metadata()->SetBoolean(VideoFrameMetadata::WANTS_PROMOTION_HINT, true); } -#if defined(OS_WIN) - frame->metadata()->SetBoolean(VideoFrameMetadata::DECODER_OWNS_FRAME, true); -#endif if (requires_texture_copy_) frame->metadata()->SetBoolean(VideoFrameMetadata::COPY_REQUIRED, true);
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc index c82dadd2..0f6752d 100644 --- a/media/filters/video_frame_stream_unittest.cc +++ b/media/filters/video_frame_stream_unittest.cc
@@ -977,7 +977,6 @@ EXPECT_EQ(0, video_frame_stream_->get_fallback_buffers_size_for_testing()); EXPECT_EQ(demuxer_reads_satisfied, video_frame_stream_->get_pending_buffers_size_for_testing()); - EXPECT_EQ(video_frame_stream_->get_previous_decoder_for_testing(), decoder1_); EXPECT_TRUE(pending_read_); // Give the decoder one more buffer, enough to release a frame. @@ -1083,15 +1082,9 @@ TEST_P(VideoFrameStreamTest, FallbackDecoderSelectedOnFailureToReinitialize) { Initialize(); decoder1_->SimulateFailureToInit(); - // Holding decode, because large decoder delays might cause us to get rid of - // |previous_decoder_| before we are in a pending state again. - decoder2_->HoldDecode(); ReadUntilDecoderReinitialized(decoder1_); - ASSERT_TRUE(video_frame_stream_->get_previous_decoder_for_testing()); - decoder2_->SatisfyDecode(); - base::RunLoop().RunUntilIdle(); ReadAllFrames(); - ASSERT_FALSE(video_frame_stream_->get_previous_decoder_for_testing()); + ASSERT_GT(decoder2_->total_bytes_decoded(), 0); } TEST_P(VideoFrameStreamTest,
diff --git a/media/renderers/video_overlay_factory.cc b/media/renderers/video_overlay_factory.cc index 6bb1f0f..a5a935b56 100644 --- a/media/renderers/video_overlay_factory.cc +++ b/media/renderers/video_overlay_factory.cc
@@ -107,9 +107,6 @@ base::TimeDelta()); // timestamp CHECK(frame); frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); - // TODO(halliwell): this is to block idle suspend behaviour on Chromecast. - // Find a better way to do this. - frame->metadata()->SetBoolean(VideoFrameMetadata::DECODER_OWNS_FRAME, true); return frame; }
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 2fd124c..22b9400 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3448,6 +3448,9 @@ # Sheriff failures 2017-04-19 crbug.com/713094 [ Win ] virtual/sharedarraybuffer/fast/css/fontfaceset-check-platform-fonts.html [ Failure Pass ] +# Sheriff failures 2017-04-24 +crbug.com/714862 [ Android ] tables/mozilla/collapsing_borders/bug41262-3.html [ Failure ] + # Tests to be run only under virtual/experimental-canvas-features/ crbug.com/682753 fast/canvas-experimental [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fragmentation/forced-break-inside-float.html b/third_party/WebKit/LayoutTests/fragmentation/forced-break-inside-float.html new file mode 100644 index 0000000..9b1f20e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fragmentation/forced-break-inside-float.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<style> + .part { height:30px; background:blue; } +</style> +<p>There should be a blue square below.</p> +<div style="columns:3; column-fill:auto; column-gap:0; width:30px; height:80px; line-height:20px;"> + <div style="position:relative;"> + <div style="float:left; width:100%;"> + <div id="elm1" class="part"></div> + <div id="elm2" class="part" style="break-before:column; break-after:column;"></div> + <div id="elm3" class="part"></div> + </div> + </div> +</div> + +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script> +test(() => { + assert_equals(document.getElementById("elm1").offsetTop, 0); + assert_equals(document.getElementById("elm2").offsetTop, 80); + assert_equals(document.getElementById("elm3").offsetTop, 160); +}, "Forced breaks should be allowed inside floats"); +</script>
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 0774e23..d4bd0cf3 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -4552,7 +4552,8 @@ AddListenerType(listener_type); } -void Document::AddListenerTypeIfNeeded(const AtomicString& event_type) { +void Document::AddListenerTypeIfNeeded(const AtomicString& event_type, + EventTarget& event_target) { if (event_type == EventTypeNames::DOMSubtreeModified) { UseCounter::Count(*this, UseCounter::kDOMSubtreeModifiedEvent); AddMutationEventListenerTypeIfEnabled(DOMSUBTREEMODIFIED_LISTENER); @@ -4589,6 +4590,15 @@ AddListenerType(TRANSITIONEND_LISTENER); } else if (event_type == EventTypeNames::scroll) { AddListenerType(SCROLL_LISTENER); + } else if (event_type == EventTypeNames::load) { + if (Node* node = event_target.ToNode()) { + if (isHTMLStyleElement(*node)) { + AddListenerType(LOAD_LISTENER_AT_CAPTURE_PHASE_OR_AT_STYLE_ELEMENT); + return; + } + } + if (event_target.HasCapturingEventListeners(event_type)) + AddListenerType(LOAD_LISTENER_AT_CAPTURE_PHASE_OR_AT_STYLE_ELEMENT); } }
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 9da3667..14066c98 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -794,14 +794,15 @@ ANIMATIONSTART_LISTENER = 1 << 7, ANIMATIONITERATION_LISTENER = 1 << 8, TRANSITIONEND_LISTENER = 1 << 9, - SCROLL_LISTENER = 1 << 10 - // 5 bits remaining + SCROLL_LISTENER = 1 << 10, + LOAD_LISTENER_AT_CAPTURE_PHASE_OR_AT_STYLE_ELEMENT = 1 << 11 + // 4 bits remaining }; bool HasListenerType(ListenerType listener_type) const { return (listener_types_ & listener_type); } - void AddListenerTypeIfNeeded(const AtomicString& event_type); + void AddListenerTypeIfNeeded(const AtomicString& event_type, EventTarget&); bool HasMutationObserversOfType(MutationObserver::MutationType type) const { return mutation_observer_types_ & type;
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp index d70c2af2..14d5b5e 100644 --- a/third_party/WebKit/Source/core/dom/Node.cpp +++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -1867,7 +1867,7 @@ event_target_data->event_listener_map; if (!listener_map.IsEmpty()) { for (const auto& type : listener_map.EventTypes()) - GetDocument().AddListenerTypeIfNeeded(type); + GetDocument().AddListenerTypeIfNeeded(type, *this); } } @@ -1894,7 +1894,7 @@ void Node::AddedEventListener(const AtomicString& event_type, RegisteredEventListener& registered_listener) { EventTarget::AddedEventListener(event_type, registered_listener); - GetDocument().AddListenerTypeIfNeeded(event_type); + GetDocument().AddListenerTypeIfNeeded(event_type, *this); if (Page* page = GetDocument().GetPage()) page->GetEventHandlerRegistry().DidAddEventHandler( *this, event_type, registered_listener.Options());
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp index cdb98a3..0a20380 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -491,17 +491,16 @@ const Vector<String>& words) { for (auto& node_markers : markers_) { const Node& node = *node_markers.key; - if (!node.IsTextNode()) // MarkerRemoverPredicate requires a Text node. + if (!node.IsTextNode()) continue; MarkerLists* markers = node_markers.value; - for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) { + for (DocumentMarker::MarkerType type : + DocumentMarker::MisspellingMarkers()) { MarkerList* list = ListForType(markers, type); if (!list) continue; - bool removed_markers = DocumentMarkerListEditor::RemoveMarkersUnderWords( + DocumentMarkerListEditor::RemoveMarkersUnderWords( list, ToText(node).data(), words); - if (removed_markers && type == DocumentMarker::kTextMatch) - InvalidatePaintForTickmarks(node); } } }
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp index 16646d47..931f6e7 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp
@@ -324,4 +324,28 @@ EXPECT_EQ(0u, MarkerController().Markers().size()); } +TEST_F(DocumentMarkerControllerTest, RemoveSpellingMarkersUnderWords) { + SetBodyInnerHTML("<div contenteditable>foo</div>"); + GetDocument().UpdateStyleAndLayout(); + Element* div = GetDocument().QuerySelector("div"); + Node* text = div->firstChild(); + + // Add a spelling marker and a text match marker to "foo". + const EphemeralRange marker_range(Position(text, 0), Position(text, 3)); + MarkerController().AddMarker(marker_range.StartPosition(), + marker_range.EndPosition(), + DocumentMarker::kSpelling, ""); + MarkerController().AddTextMatchMarker(marker_range, + DocumentMarker::MatchStatus::kInactive); + + MarkerController().RemoveSpellingMarkersUnderWords({"foo"}); + + // RemoveSpellingMarkersUnderWords does not remove text match marker. + ASSERT_EQ(1u, MarkerController().Markers().size()); + const DocumentMarker& marker = *MarkerController().Markers()[0]; + EXPECT_EQ(0u, marker.StartOffset()); + EXPECT_EQ(3u, marker.EndOffset()); + EXPECT_EQ(DocumentMarker::kTextMatch, marker.GetType()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp index 7fdceb5..8a160dc4 100644 --- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -1442,7 +1442,7 @@ *this, event_type, registered_listener.Options()); if (Document* document = this->document()) - document->AddListenerTypeIfNeeded(event_type); + document->AddListenerTypeIfNeeded(event_type, *this); for (auto& it : event_listener_observers_) { it->DidAddEventListener(this, event_type);
diff --git a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp index 349287a..c2ca811 100644 --- a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
@@ -107,9 +107,13 @@ void HTMLStyleElement::DispatchPendingEvent( std::unique_ptr<IncrementLoadEventDelayCount> count) { - DispatchEvent(Event::Create(loaded_sheet_ ? EventTypeNames::load - : EventTypeNames::error)); - + if (loaded_sheet_) { + if (GetDocument().HasListenerType( + Document::LOAD_LISTENER_AT_CAPTURE_PHASE_OR_AT_STYLE_ELEMENT)) + DispatchEvent(Event::Create(EventTypeNames::load)); + } else { + DispatchEvent(Event::Create(EventTypeNames::error)); + } // Checks Document's load event synchronously here for performance. // This is safe because dispatchPendingEvent() is called asynchronously. count->ClearAndCheckLoadEvent();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 92f2ff0..6f2ceee 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -2272,7 +2272,7 @@ // If this is a flow thread for a multicol container, and we have a break // value for paged, we need to keep looking. } - if (curr->IsFloatingOrOutOfFlowPositioned()) + if (curr->IsOutOfFlowPositioned()) return false; curr = curr->ContainingBlock(); }
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py index a451fec..b1cf856 100644 --- a/tools/perf/benchmarks/tab_switching.py +++ b/tools/perf/benchmarks/tab_switching.py
@@ -2,11 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import os + from core import perf_benchmark from measurements import tab_switching -import page_sets +from page_sets.system_health import multi_tab_stories from telemetry import benchmark +from telemetry import story @benchmark.Owner(emails=['vovoy@chromium.org'], @@ -24,9 +27,19 @@ """ test = tab_switching.TabSwitching + @classmethod + def AddBenchmarkCommandLineArgs(cls, parser): + parser.add_option('--tabset-repeat', type='int', default=1, + help='repeat tab page set') + def CreateStorySet(self, options): - return page_sets.SystemHealthStorySet(platform='desktop', - case='multitab:misc') + story_set = story.StorySet( + archive_data_file='../page_sets/data/system_health_desktop.json', + base_dir=os.path.dirname(os.path.abspath(__file__)), + cloud_storage_bucket=story.PARTNER_BUCKET) + story_set.AddStory(multi_tab_stories.MultiTabTypical24Story( + story_set, False, options.tabset_repeat)) + return story_set @classmethod def Name(cls):
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index c37a5a9..d47f2ea 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -565,7 +565,7 @@ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY TAGS = [story_tags.EMERGING_MARKET] - ITEMS_TO_VISIT = 4 + ITEMS_TO_VISIT = 3 # 4 links causes renderer OOM crbug.com/714650. ITEM_SELECTOR = '.hui-premium__title' COMPLETE_STATE_WAIT_TIMEOUT = 150
diff --git a/tools/perf/page_sets/system_health/multi_tab_stories.py b/tools/perf/page_sets/system_health/multi_tab_stories.py index a9ab0c7..fef8486 100644 --- a/tools/perf/page_sets/system_health/multi_tab_stories.py +++ b/tools/perf/page_sets/system_health/multi_tab_stories.py
@@ -15,18 +15,23 @@ class MultiTabStory(system_health_story.SystemHealthStory): ABSTRACT_STORY = True + def __init__(self, story_set, take_memory_measurement, tabset_repeat=1): + super(MultiTabStory, self).__init__(story_set, take_memory_measurement) + self._tabset_repeat = tabset_repeat + def RunNavigateSteps(self, action_runner): tabs = action_runner.tab.browser.tabs # No need to create the first tab as there is already one # when the browser is ready, - if self.URL_LIST: - action_runner.Navigate(self.URL_LIST[0]) - for url in self.URL_LIST[1:]: + url_list = self.URL_LIST * self._tabset_repeat + if url_list: + action_runner.Navigate(url_list[0]) + for url in url_list[1:]: new_tab = tabs.New() new_tab.action_runner.Navigate(url) - for i, url in enumerate(self.URL_LIST): + for i, url in enumerate(url_list): try: tabs[i].action_runner.WaitForNetworkQuiescence() except py_utils.TimeoutException:
diff --git a/ui/message_center/views/message_bubble_base.cc b/ui/message_center/views/message_bubble_base.cc index 43915d1..4089234 100644 --- a/ui/message_center/views/message_bubble_base.cc +++ b/ui/message_center/views/message_bubble_base.cc
@@ -21,9 +21,6 @@ namespace message_center { -const SkColor MessageBubbleBase::kBackgroundColor = - SkColorSetRGB(0xfe, 0xfe, 0xfe); - MessageBubbleBase::MessageBubbleBase(MessageCenter* message_center, MessageCenterTray* tray) : message_center_(message_center),
diff --git a/ui/message_center/views/message_bubble_base.h b/ui/message_center/views/message_bubble_base.h index 65bdf5a..0c9718a 100644 --- a/ui/message_center/views/message_bubble_base.h +++ b/ui/message_center/views/message_bubble_base.h
@@ -57,8 +57,6 @@ views::TrayBubbleView* bubble_view() const { return bubble_view_; } - static const SkColor kBackgroundColor; - protected: views::TrayBubbleView::InitParams GetDefaultInitParams( views::TrayBubbleView::AnchorAlignment anchor_alignment);
diff --git a/ui/views/background.cc b/ui/views/background.cc index 190a5a6..e036490a 100644 --- a/ui/views/background.cc +++ b/ui/views/background.cc
@@ -6,11 +6,14 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/scoped_observer.h" #include "build/build_config.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/views/painter.h" #include "ui/views/view.h" +#include "ui/views/view_observer.h" #if defined(OS_WIN) #include "skia/ext/skia_utils_win.h" @@ -36,6 +39,32 @@ DISALLOW_COPY_AND_ASSIGN(SolidBackground); }; +// ThemedSolidBackground is a solid background that stays in sync with a view's +// native theme. +class ThemedSolidBackground : public SolidBackground, public ViewObserver { + public: + explicit ThemedSolidBackground(View* view, ui::NativeTheme::ColorId color_id) + : SolidBackground(gfx::kPlaceholderColor), + observer_(this), + color_id_(color_id) { + observer_.Add(view); + OnViewNativeThemeChanged(view); + } + ~ThemedSolidBackground() override {} + + // ViewObserver: + void OnViewNativeThemeChanged(View* view) override { + SetNativeControlColor(view->GetNativeTheme()->GetSystemColor(color_id_)); + view->SchedulePaint(); + } + + private: + ScopedObserver<View, ViewObserver> observer_; + ui::NativeTheme::ColorId color_id_; + + DISALLOW_COPY_AND_ASSIGN(ThemedSolidBackground); +}; + class BackgroundPainter : public Background { public: explicit BackgroundPainter(std::unique_ptr<Painter> painter) @@ -73,6 +102,13 @@ } // static +Background* Background::CreateThemedSolidBackground( + View* view, + ui::NativeTheme::ColorId color_id) { + return new ThemedSolidBackground(view, color_id); +} + +// static Background* Background::CreateStandardPanelBackground() { // TODO(beng): Should be in NativeTheme. return CreateSolidBackground(SK_ColorWHITE);
diff --git a/ui/views/background.h b/ui/views/background.h index 6648689d..81bb675 100644 --- a/ui/views/background.h +++ b/ui/views/background.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "build/build_config.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/views_export.h" #if defined(OS_WIN) @@ -47,6 +48,12 @@ // Creates a background that fills the canvas in the specified color. static Background* CreateSolidBackground(SkColor color); + // Creates a background that fills the canvas in the color specified by the + // view's NativeTheme and the given color identifier. + static Background* CreateThemedSolidBackground( + View* view, + ui::NativeTheme::ColorId color_id); + // Creates a background that fills the canvas in the specified color. static Background* CreateSolidBackground(int r, int g, int b) { return CreateSolidBackground(SkColorSetRGB(r, g, b));
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc index 3d7a93e..e1cd285 100644 --- a/ui/views/bubble/tray_bubble_view.cc +++ b/ui/views/bubble/tray_bubble_view.cc
@@ -175,8 +175,7 @@ max_width(max_width), max_height(0), can_activate(false), - close_on_deactivate(true), - bg_color(gfx::kPlaceholderColor) {} + close_on_deactivate(true) {} TrayBubbleView::InitParams::InitParams(const InitParams& other) = default; @@ -196,12 +195,14 @@ layout_(new BottomAlignedBoxLayout(this)), delegate_(delegate), preferred_width_(init_params.min_width), - bubble_border_(new BubbleBorder(arrow(), - BubbleBorder::NO_ASSETS, - init_params.bg_color)), + bubble_border_(new BubbleBorder( + arrow(), + BubbleBorder::NO_ASSETS, + init_params.bg_color.value_or(gfx::kPlaceholderColor))), owned_bubble_border_(bubble_border_), is_gesture_dragging_(false), mouse_actively_entered_(false) { + bubble_border_->set_use_theme_background_color(!init_params.bg_color); bubble_border_->set_alignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); bubble_border_->set_paint_arrow(BubbleBorder::PAINT_NONE); set_can_activate(params_.can_activate);
diff --git a/ui/views/bubble/tray_bubble_view.h b/ui/views/bubble/tray_bubble_view.h index 8de9c30..12b9bad 100644 --- a/ui/views/bubble/tray_bubble_view.h +++ b/ui/views/bubble/tray_bubble_view.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/optional.h" #include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/mouse_watcher.h" #include "ui/views/views_export.h" @@ -83,7 +84,8 @@ int max_height; bool can_activate; bool close_on_deactivate; - SkColor bg_color; + // If not provided, the bg color will be derived from the NativeTheme. + base::Optional<SkColor> bg_color; }; // Constructs and returns a TrayBubbleView. |init_params| may be modified.
diff --git a/ui/views/view.cc b/ui/views/view.cc index 27eada4..b39da49 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -2136,6 +2136,8 @@ child->PropagateNativeThemeChanged(theme); } OnNativeThemeChanged(theme); + for (ViewObserver& observer : observers_) + observer.OnViewNativeThemeChanged(this); } // Size and disposition --------------------------------------------------------
diff --git a/ui/views/view_observer.h b/ui/views/view_observer.h index c4f56791..f4285a9 100644 --- a/ui/views/view_observer.h +++ b/ui/views/view_observer.h
@@ -35,6 +35,9 @@ // View::ReorderChildView() is called on |observed_view|. virtual void OnChildViewReordered(View* observed_view, View* child) {} + // Called when the active NativeTheme has changed for |observed_view|. + virtual void OnViewNativeThemeChanged(View* observed_view) {} + // Called from ~View. virtual void OnViewIsDeleting(View* observed_view) {}