diff --git a/DEPS b/DEPS index 93479a6..b3345a7 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '71b762f2aca1c8bda51f68ee31157d2af41aa34e', + 'skia_revision': 'dad2923b8ec9270d810c1e8e76da8e6768d8f9dd', # 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': '4e01f2a8efd8cbf3ee2142f0fbeaa221e0c6dc9c', + 'v8_revision': 'd34f038fd58bf112c755ab35b798c78f644ee24d', # 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': '8a463c5a1a2252b5fdbff3b5ab07d50273bbc391', + 'pdfium_revision': 'd7ecb5f272de6cdd88ecef4c7b4d0dbee4355610', # 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. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'da3aa694af9729a870e1837d7cbeebb38bd64063', + 'catapult_revision': '760530e4994ad2d4a6d68dceead76e588fdb9a04', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/ash/common/metrics/pointer_metrics_recorder_unittest.cc b/ash/common/metrics/pointer_metrics_recorder_unittest.cc index 5399f4ea..396cb17 100644 --- a/ash/common/metrics/pointer_metrics_recorder_unittest.cc +++ b/ash/common/metrics/pointer_metrics_recorder_unittest.cc
@@ -181,11 +181,6 @@ pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), target.get()); histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 3, 1); - - window->SetAppType(static_cast<int>(AppType::DEFAULT_NOTE_TAKING_APP)); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 4, 1); } } // namespace ash
diff --git a/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc index 38b1c0ad..b10258c 100644 --- a/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc +++ b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc
@@ -340,8 +340,6 @@ // In the material design, we will add a title item with a separator on the // top of the IME menu. if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - bubble_view->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); bubble_view->AddChildView( new ImeTitleView(!ShouldShowEmojiHandwritingVoiceButtons())); } else {
diff --git a/ash/common/system/tray/system_tray_bubble.cc b/ash/common/system/tray/system_tray_bubble.cc index 19ad267..c08e00e6 100644 --- a/ash/common/system/tray/system_tray_bubble.cc +++ b/ash/common/system/tray/system_tray_bubble.cc
@@ -45,6 +45,9 @@ // detailed view or vice versa. const int kSwipeDelayMS = 150; +// Extra bottom padding when showing the BUBBLE_TYPE_DEFAULT view. +const int kDefaultViewBottomPadding = 4; + // Implicit animation observer that deletes itself and the layer at the end of // the animation. class AnimationObserverDeleteLayer : public ui::ImplicitAnimationObserver { @@ -150,6 +153,7 @@ return; } + UpdateBottomPadding(); bubble_view_->GetWidget()->GetContentsView()->Layout(); // Make sure that the bubble is large enough for the default view. if (bubble_type_ == BUBBLE_TYPE_DEFAULT) { @@ -197,6 +201,7 @@ } bubble_view_ = TrayBubbleView::Create(anchor, tray_, init_params); + UpdateBottomPadding(); bubble_view_->set_adjust_if_offscreen(false); CreateItemViews(login_status); @@ -302,6 +307,15 @@ } } +void SystemTrayBubble::UpdateBottomPadding() { + if (bubble_type_ == BUBBLE_TYPE_DEFAULT && + MaterialDesignController::IsSystemTrayMenuMaterial()) { + bubble_view_->SetBottomPadding(kDefaultViewBottomPadding); + } else { + bubble_view_->SetBottomPadding(0); + } +} + void SystemTrayBubble::CreateItemViews(LoginStatus login_status) { tray_item_view_map_.clear();
diff --git a/ash/common/system/tray/system_tray_bubble.h b/ash/common/system/tray/system_tray_bubble.h index 1fed3521..aeb8722 100644 --- a/ash/common/system/tray/system_tray_bubble.h +++ b/ash/common/system/tray/system_tray_bubble.h
@@ -66,6 +66,9 @@ void RecordVisibleRowMetrics(); private: + // Updates the bottom padding of the |bubble_view_| based on the + // |bubble_type_|. + void UpdateBottomPadding(); void CreateItemViews(LoginStatus login_status); ash::SystemTray* tray_;
diff --git a/ash/common/system/web_notification/web_notification_tray.cc b/ash/common/system/web_notification/web_notification_tray.cc index b6bd17a..351fd441 100644 --- a/ash/common/system/web_notification/web_notification_tray.cc +++ b/ash/common/system/web_notification/web_notification_tray.cc
@@ -9,6 +9,7 @@ #include "ash/common/shelf/shelf_constants.h" #include "ash/common/shelf/wm_shelf.h" #include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/status_area_widget.h" #include "ash/common/system/tray/system_tray.h" #include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/system/tray/tray_bubble_wrapper.h" @@ -96,6 +97,7 @@ public: // Takes ownership of |bubble| and creates |bubble_wrapper_|. WebNotificationBubbleWrapper(WebNotificationTray* tray, + TrayBackgroundView* anchor_tray, message_center::MessageBubbleBase* bubble) { bubble_.reset(bubble); views::TrayBubbleView::AnchorAlignment anchor_alignment = @@ -103,8 +105,8 @@ views::TrayBubbleView::InitParams init_params = bubble->GetInitParams(anchor_alignment); views::TrayBubbleView* bubble_view = views::TrayBubbleView::Create( - tray->GetBubbleAnchor(), tray, &init_params); - bubble_view->set_anchor_view_insets(tray->GetBubbleAnchorInsets()); + anchor_tray->GetBubbleAnchor(), tray, &init_params); + bubble_view->set_anchor_view_insets(anchor_tray->GetBubbleAnchorInsets()); bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_view)); bubble->InitializeContents(bubble_view); } @@ -373,8 +375,18 @@ std::max(0, max_height - GetTrayConstant(TRAY_SPACING))); if (show_settings) message_center_bubble->SetSettingsVisible(); - message_center_bubble_.reset( - new WebNotificationBubbleWrapper(this, message_center_bubble)); + + // For vertical shelf alignments, anchor to the WebNotificationTray, but for + // horizontal (i.e. bottom) shelves, anchor to the system tray. + TrayBackgroundView* anchor_tray = this; + if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) { + anchor_tray = WmShelf::ForWindow(status_area_window_) + ->GetStatusAreaWidget() + ->system_tray(); + } + + message_center_bubble_.reset(new WebNotificationBubbleWrapper( + this, anchor_tray, message_center_bubble)); system_tray_->SetHideNotifications(true); shelf()->UpdateAutoHideState();
diff --git a/ash/common/wm/default_state.cc b/ash/common/wm/default_state.cc index 2b5a5893..d7e49d9 100644 --- a/ash/common/wm/default_state.cc +++ b/ash/common/wm/default_state.cc
@@ -682,8 +682,13 @@ bounds_in_parent = window->GetBounds(); } // Make sure that part of the window is always visible. - wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, - &bounds_in_parent); + if (!window_state->is_dragged()) { + // Avoid doing this while the window is being dragged as its root + // window hasn't been updated yet in the case of dragging to another + // display. crbug.com/666836. + wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, + &bounds_in_parent); + } break; } case WINDOW_STATE_TYPE_MAXIMIZED:
diff --git a/ash/common/wm/workspace/workspace_window_resizer.cc b/ash/common/wm/workspace/workspace_window_resizer.cc index 8dd745f..e17da97 100644 --- a/ash/common/wm/workspace/workspace_window_resizer.cc +++ b/ash/common/wm/workspace/workspace_window_resizer.cc
@@ -439,12 +439,8 @@ GetTarget()->GetBounds())) { // Set the window to WINDOW_STATE_TYPE_NORMAL but keep the // window at the bounds that the user has moved/resized the - // window to. ClearRestoreBounds() is used instead of - // SaveCurrentBoundsForRestore() because most of the restore - // logic is skipped because we are still in the middle of a - // drag. TODO(pkotwicz): Fix this and use - // SaveCurrentBoundsForRestore(). - window_state()->ClearRestoreBounds(); + // window to. + window_state()->SaveCurrentBoundsForRestore(); window_state()->Restore(); } } else if (!dock_layout_->is_dragged_window_docked()) {
diff --git a/ash/mus/accelerators/accelerator_controller_delegate_mus.cc b/ash/mus/accelerators/accelerator_controller_delegate_mus.cc index f1664b58..b92ada3b 100644 --- a/ash/mus/accelerators/accelerator_controller_delegate_mus.cc +++ b/ash/mus/accelerators/accelerator_controller_delegate_mus.cc
@@ -11,6 +11,7 @@ #include "services/ui/public/interfaces/constants.mojom.h" #include "services/ui/public/interfaces/display/display_controller.mojom.h" #include "services/ui/public/interfaces/display/test_display_controller.mojom.h" +#include "ui/display/screen.h" namespace ash { namespace mus { @@ -28,12 +29,18 @@ AcceleratorControllerDelegateMus::~AcceleratorControllerDelegateMus() {} bool AcceleratorControllerDelegateMus::HandlesAction(AcceleratorAction action) { - // This is the list of actions that are not ported from aura. The actions are - // replicated here to make sure we don't forget any. This list should - // eventually be empty. If there are any actions that don't make sense for - // mus, then they should be removed from AcceleratorAction. + // Accelerators that return true need to work differently in mash. These + // should have implementations in CanPerformAction() and PerformAction(). + // Accelerators that return false have not been ported to work with mash yet. + // If the behavior between cash and mash can be unified then the accelerator + // should be moved to accelerator_controller.cc/h. See // http://crbug.com/612331. switch (action) { + case SCALE_UI_DOWN: + case SCALE_UI_RESET: + case SCALE_UI_UP: + case ROTATE_SCREEN: + return true; case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR: case DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN: case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS: @@ -41,11 +48,7 @@ case DEBUG_TOGGLE_SHOW_PAINT_RECTS: case MAGNIFY_SCREEN_ZOOM_IN: case MAGNIFY_SCREEN_ZOOM_OUT: - case ROTATE_SCREEN: case ROTATE_WINDOW: - case SCALE_UI_DOWN: - case SCALE_UI_RESET: - case SCALE_UI_UP: case SHOW_SYSTEM_TRAY_BUBBLE: case TAKE_PARTIAL_SCREENSHOT: case TAKE_SCREENSHOT: @@ -58,13 +61,13 @@ case DEV_ADD_REMOVE_DISPLAY: case DEV_TOGGLE_UNIFIED_DESKTOP: case SWAP_PRIMARY_DISPLAY: + case TOGGLE_MIRROR_MODE: case TOUCH_HUD_PROJECTION_TOGGLE: return true; case LOCK_PRESSED: case LOCK_RELEASED: case POWER_PRESSED: case POWER_RELEASED: - case TOGGLE_MIRROR_MODE: case TOUCH_HUD_CLEAR: case TOUCH_HUD_MODE_CHANGE: NOTIMPLEMENTED(); @@ -81,25 +84,49 @@ AcceleratorAction action, const ui::Accelerator& accelerator, const ui::Accelerator& previous_accelerator) { -#if defined(OS_CHROMEOS) switch (action) { + case ROTATE_SCREEN: + case SCALE_UI_DOWN: + case SCALE_UI_RESET: + case SCALE_UI_UP: + return true; +#if defined(OS_CHROMEOS) case DEV_ADD_REMOVE_DISPLAY: case DEV_TOGGLE_UNIFIED_DESKTOP: + return true; case SWAP_PRIMARY_DISPLAY: + return display::Screen::GetScreen()->GetNumDisplays() > 1; + case TOGGLE_MIRROR_MODE: case TOUCH_HUD_PROJECTION_TOGGLE: return true; +#endif default: break; } -#endif return false; } void AcceleratorControllerDelegateMus::PerformAction( AcceleratorAction action, const ui::Accelerator& accelerator) { -#if defined(OS_CHROMEOS) switch (action) { + case ROTATE_SCREEN: { + window_manager_->GetDisplayController()->RotateCurrentDisplayCW(); + break; + } + case SCALE_UI_DOWN: { + window_manager_->GetDisplayController()->DecreaseInternalDisplayZoom(); + break; + } + case SCALE_UI_RESET: { + window_manager_->GetDisplayController()->ResetInternalDisplayZoom(); + break; + } + case SCALE_UI_UP: { + window_manager_->GetDisplayController()->IncreaseInternalDisplayZoom(); + break; + } +#if defined(OS_CHROMEOS) case DEV_ADD_REMOVE_DISPLAY: { display::mojom::TestDisplayControllerPtr test_display_controller; window_manager_->connector()->ConnectToInterface( @@ -120,6 +147,10 @@ window_manager_->GetDisplayController()->SwapPrimaryDisplay(); break; } + case TOGGLE_MIRROR_MODE: { + window_manager_->GetDisplayController()->ToggleMirrorMode(); + break; + } case TOUCH_HUD_PROJECTION_TOGGLE: { mash::mojom::LaunchablePtr launchable; window_manager_->connector()->ConnectToInterface("touch_hud", @@ -128,12 +159,10 @@ mash::mojom::LaunchMode::DEFAULT); break; } +#endif default: NOTREACHED(); } -#else - NOTREACHED(); -#endif } void AcceleratorControllerDelegateMus::ShowDeprecatedAcceleratorNotification(
diff --git a/ash/mus/accelerators/accelerator_controller_delegate_mus.h b/ash/mus/accelerators/accelerator_controller_delegate_mus.h index 4d14750..79a30fee 100644 --- a/ash/mus/accelerators/accelerator_controller_delegate_mus.h +++ b/ash/mus/accelerators/accelerator_controller_delegate_mus.h
@@ -13,6 +13,7 @@ class WindowManager; +// Controls accelerators that are specific to mash. class AcceleratorControllerDelegateMus : public AcceleratorControllerDelegate { public: explicit AcceleratorControllerDelegateMus(WindowManager* window_manager);
diff --git a/ash/shared/app_types.h b/ash/shared/app_types.h index 0cebf8d3..a1df588 100644 --- a/ash/shared/app_types.h +++ b/ash/shared/app_types.h
@@ -14,8 +14,8 @@ BROWSER, CHROME_APP, ARC_APP, - DEFAULT_NOTE_TAKING_APP, - APP_TYPE_LAST = DEFAULT_NOTE_TAKING_APP, + DEPRECATED_DEFAULT_NOTE_TAKING_APP, // Use CHROME_APP or ARC_APP instead. + APP_TYPE_LAST = DEPRECATED_DEFAULT_NOTE_TAKING_APP, }; const int kAppCount = static_cast<int>(AppType::APP_TYPE_LAST) + 1;
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc index 067e238..cfc8ebf 100644 --- a/ash/wm/toplevel_window_event_handler.cc +++ b/ash/wm/toplevel_window_event_handler.cc
@@ -14,6 +14,7 @@ #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" +#include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host.h" #include "ui/base/cursor/cursor.h" #include "ui/base/hit_test.h" @@ -94,13 +95,16 @@ wm::WindowState* window_state = wm::GetWindowState(source); const bool window_position_managed = window_state->window_position_managed(); window_state->set_window_position_managed(false); + aura::WindowTracker tracker({source}); run_loop.Run(); if (!weak_ptr) return aura::client::MOVE_CANCELED; - window_state->set_window_position_managed(window_position_managed); + // Make sure the window hasn't been deleted. + if (tracker.Contains(source)) + window_state->set_window_position_managed(window_position_managed); in_move_loop_ = false; return result == wm::WmToplevelWindowEventHandler::DragResult::SUCCESS
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc index ba89155..573686c 100644 --- a/ash/wm/toplevel_window_event_handler_unittest.cc +++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -5,6 +5,7 @@ #include "ash/wm/toplevel_window_event_handler.h" #include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm/workspace_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" @@ -24,6 +25,8 @@ #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/base/hit_test.h" +#include "ui/display/display_layout_builder.h" +#include "ui/display/manager/display_manager.h" #include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/test/event_generator.h" @@ -827,6 +830,46 @@ aura::client::WINDOW_MOVE_SOURCE_TOUCH)); } +// Tests that dragging a snapped window to another display updates the window's +// bounds correctly. +TEST_F(ToplevelWindowEventHandlerTest, DragSnappedWindowToExternalDisplay) { + if (!SupportsMultipleDisplays()) + return; + + UpdateDisplay("940x550,940x550"); + int64_t primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); + int64_t secondary_id = display_manager()->GetSecondaryDisplay().id(); + display::DisplayLayoutBuilder builder(primary_id); + builder.SetSecondaryPlacement(secondary_id, display::DisplayPlacement::TOP, + 0); + display_manager()->SetLayoutForCurrentDisplays(builder.Build()); + + const gfx::Size initial_window_size(330, 230); + std::unique_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegateAndType( + new TestWindowDelegate(HTCAPTION), ui::wm::WINDOW_TYPE_NORMAL, 0, + gfx::Rect(initial_window_size))); + + // Snap the window to the right. + wm::WindowState* window_state = wm::GetWindowState(w1.get()); + ASSERT_TRUE(window_state->CanSnap()); + const wm::WMEvent event(wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT); + window_state->OnWMEvent(&event); + ASSERT_TRUE(window_state->IsSnapped()); + + // Drag the window to the secondary display. + ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), w1.get()); + generator.DragMouseTo(472, -462); + + // Expect the window is no longer snapped and its size was restored to the + // initial size. + EXPECT_FALSE(window_state->IsSnapped()); + EXPECT_EQ(initial_window_size.ToString(), w1->bounds().size().ToString()); + + // The window is now fully contained in the secondary display. + EXPECT_TRUE(display_manager()->GetSecondaryDisplay().bounds().Contains( + w1->GetBoundsInScreen())); +} + // Showing the resize shadows when the mouse is over the window edges is tested // in resize_shadow_and_cursor_test.cc
diff --git a/base/BUILD.gn b/base/BUILD.gn index bbdf073..cd6fd2e 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -823,6 +823,8 @@ "task_scheduler/scheduler_worker_pool_params.h", "task_scheduler/scheduler_worker_stack.cc", "task_scheduler/scheduler_worker_stack.h", + "task_scheduler/scoped_set_task_priority_for_current_thread.cc", + "task_scheduler/scoped_set_task_priority_for_current_thread.h", "task_scheduler/sequence.cc", "task_scheduler/sequence.h", "task_scheduler/sequence_sort_key.cc", @@ -1984,6 +1986,7 @@ "task_scheduler/scheduler_worker_pool_impl_unittest.cc", "task_scheduler/scheduler_worker_stack_unittest.cc", "task_scheduler/scheduler_worker_unittest.cc", + "task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc", "task_scheduler/sequence_sort_key_unittest.cc", "task_scheduler/sequence_unittest.cc", "task_scheduler/task_scheduler_impl_unittest.cc",
diff --git a/base/task_scheduler/scoped_set_task_priority_for_current_thread.cc b/base/task_scheduler/scoped_set_task_priority_for_current_thread.cc new file mode 100644 index 0000000..a163863 --- /dev/null +++ b/base/task_scheduler/scoped_set_task_priority_for_current_thread.cc
@@ -0,0 +1,41 @@ +// Copyright 2016 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 "base/task_scheduler/scoped_set_task_priority_for_current_thread.h" + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/threading/thread_local.h" + +namespace base { +namespace internal { + +namespace { + +LazyInstance<ThreadLocalPointer<const TaskPriority>>::Leaky + tls_task_priority_for_current_thread = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +ScopedSetTaskPriorityForCurrentThread::ScopedSetTaskPriorityForCurrentThread( + TaskPriority priority) + : priority_(priority) { + DCHECK(!tls_task_priority_for_current_thread.Get().Get()); + tls_task_priority_for_current_thread.Get().Set(&priority_); +} + +ScopedSetTaskPriorityForCurrentThread:: + ~ScopedSetTaskPriorityForCurrentThread() { + DCHECK_EQ(&priority_, tls_task_priority_for_current_thread.Get().Get()); + tls_task_priority_for_current_thread.Get().Set(nullptr); +} + +TaskPriority GetTaskPriorityForCurrentThread() { + const TaskPriority* priority = + tls_task_priority_for_current_thread.Get().Get(); + return priority ? *priority : TaskPriority::USER_VISIBLE; +} + +} // namespace internal +} // namespace base
diff --git a/base/task_scheduler/scoped_set_task_priority_for_current_thread.h b/base/task_scheduler/scoped_set_task_priority_for_current_thread.h new file mode 100644 index 0000000..4508911d --- /dev/null +++ b/base/task_scheduler/scoped_set_task_priority_for_current_thread.h
@@ -0,0 +1,36 @@ +// Copyright 2016 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 BASE_TASK_SCHEDULER_SCOPED_SET_TASK_PRIORITY_FOR_CURRENT_THREAD_H_ +#define BASE_TASK_SCHEDULER_SCOPED_SET_TASK_PRIORITY_FOR_CURRENT_THREAD_H_ + +#include "base/base_export.h" +#include "base/macros.h" +#include "base/task_scheduler/task_traits.h" + +namespace base { +namespace internal { + +class BASE_EXPORT ScopedSetTaskPriorityForCurrentThread { + public: + // Within the scope of this object, GetTaskPriorityForCurrentThread() will + // return |priority|. + ScopedSetTaskPriorityForCurrentThread(TaskPriority priority); + ~ScopedSetTaskPriorityForCurrentThread(); + + private: + const TaskPriority priority_; + + DISALLOW_COPY_AND_ASSIGN(ScopedSetTaskPriorityForCurrentThread); +}; + +// Returns the priority of the TaskScheduler task running on the current thread, +// or TaskPriority::USER_VISIBLE if no TaskScheduler task is running on the +// current thread. +BASE_EXPORT TaskPriority GetTaskPriorityForCurrentThread(); + +} // namespace internal +} // namespace base + +#endif // BASE_TASK_SCHEDULER_SCOPED_SET_TASK_PRIORITY_FOR_CURRENT_THREAD_H_
diff --git a/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc b/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc new file mode 100644 index 0000000..c497af6 --- /dev/null +++ b/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc
@@ -0,0 +1,26 @@ +// Copyright 2016 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 "base/task_scheduler/scoped_set_task_priority_for_current_thread.h" + +#include "base/task_scheduler/task_traits.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace internal { + +TEST(TaskSchedulerScopedSetTaskPriorityForCurrentThreadTest, + ScopedSetTaskPriorityForCurrentThread) { + EXPECT_EQ(TaskPriority::USER_VISIBLE, GetTaskPriorityForCurrentThread()); + { + ScopedSetTaskPriorityForCurrentThread + scoped_set_task_priority_for_current_thread( + TaskPriority::USER_BLOCKING); + EXPECT_EQ(TaskPriority::USER_BLOCKING, GetTaskPriorityForCurrentThread()); + } + EXPECT_EQ(TaskPriority::USER_VISIBLE, GetTaskPriorityForCurrentThread()); +} + +} // namespace internal +} // namespace base
diff --git a/base/task_scheduler/task_tracker.cc b/base/task_scheduler/task_tracker.cc index 03f161e..818ded7 100644 --- a/base/task_scheduler/task_tracker.cc +++ b/base/task_scheduler/task_tracker.cc
@@ -14,6 +14,7 @@ #include "base/metrics/histogram_macros.h" #include "base/sequence_token.h" #include "base/synchronization/condition_variable.h" +#include "base/task_scheduler/scoped_set_task_priority_for_current_thread.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" @@ -230,9 +231,10 @@ ThreadRestrictions::SetWaitAllowed(task->traits.with_wait()); { - // Set up SequenceToken as expected for the scope of the task. ScopedSetSequenceTokenForCurrentThread scoped_set_sequence_token_for_current_thread(sequence_token); + ScopedSetTaskPriorityForCurrentThread + scoped_set_task_priority_for_current_thread(task->traits.priority()); // Set up TaskRunnerHandle as expected for the scope of the task. std::unique_ptr<SequencedTaskRunnerHandle> sequenced_task_runner_handle;
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index cc05f58e..67b1e06 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -315,7 +315,7 @@ <ignore regexp="blimp/client/app/android/java/res/values/dimens.xml"/> <ignore regexp="blimp/client/app/android/java/res/xml/about_blimp_preferences.xml"/> <ignore regexp="blimp/client/app/android/java/res/xml/blimp_preferences.xml"/> - <ignore regexp="blimp/client/core/resources/android/java/res/*" /> + <ignore regexp="blimp/client/core/resources/android/java/res/*" /> <!-- TODO(crbug.com/635567): Fix this properly. --> <ignore regexp="chrome/android/java/res/drawable-hdpi/*"/> <ignore regexp="chrome/android/java/res/drawable-hdpi/amex_card.png"/> @@ -460,6 +460,10 @@ <!-- TODO(crbug.com/635567): Fix this properly. --> <ignore regexp="content/shell/android/shell_apk/res/values/strings.xml"/> </issue> + <!-- TODO(crbug.com/669629): Remove this when the Chromecast dependency on old layout code is removed. --> + <issue id="UseCompoundDrawables"> + <ignore regexp="chromecast/internal/android/prebuilt/settings/res/layout-v17/setup_activity_progress.xml"/> + </issue> <issue id="UselessParent"> <ignore regexp="android_webview/tools/system_webview_shell/apk/res/layout/activity_webview_browser.xml"/> <ignore regexp="chrome/android/java/res/layout/data_reduction_promo_screen.xml"/>
diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py index d1e392f..109d553 100755 --- a/build/linux/sysroot_scripts/install-sysroot.py +++ b/build/linux/sysroot_scripts/install-sysroot.py
@@ -25,6 +25,7 @@ import shutil import subprocess import sys +import urllib SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.dirname(os.path.dirname(SCRIPT_DIR))) @@ -245,8 +246,14 @@ print 'Downloading %s' % url sys.stdout.flush() sys.stderr.flush() - subprocess.check_call( - ['wget', '--quiet', '-t', '3', '-O', tarball, url]) + for _ in range(3): + try: + urllib.urlretrieve(url, tarball) + break + except: + pass + else: + raise Error('Failed to download %s' % url) sha1sum = GetSha1(tarball) if sha1sum != tarball_sha1sum: raise Error('Tarball sha1sum is wrong.'
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn index 213109a..f35977d2 100644 --- a/build/secondary/third_party/android_tools/BUILD.gn +++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -30,7 +30,7 @@ ] } -lib_version = "24.1.1" +lib_version = "25.0.1" lib_path = "$android_sdk_root/extras/android/m2repository/com/android/support" android_java_prebuilt("android_gcm_java") { @@ -60,8 +60,39 @@ jar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.jar" } -android_aar_prebuilt("android_support_v4_java") { - _lib_name = "support-v4" +java_group("android_support_v4_java") { + deps = [ + ":android_support_compat_java", + ":android_support_core_ui_java", + ":android_support_core_utils_java", + ":android_support_fragment_java", + ":android_support_media_compat_java", + ] +} + +android_aar_prebuilt("android_support_compat_java") { + _lib_name = "support-compat" + aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar" + ignore_aidl = true # We don't appear to need these currently. +} + +android_aar_prebuilt("android_support_core_ui_java") { + _lib_name = "support-core-ui" + aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar" +} + +android_aar_prebuilt("android_support_core_utils_java") { + _lib_name = "support-core-utils" + aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar" +} + +android_aar_prebuilt("android_support_fragment_java") { + _lib_name = "support-fragment" + aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar" +} + +android_aar_prebuilt("android_support_media_compat_java") { + _lib_name = "support-media-compat" aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar" ignore_aidl = true # We don't appear to need these currently. }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 0435b84..fdb91d6d 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -211,6 +211,7 @@ "//third_party/jsr-305:jsr_305_javalib", "//third_party/leakcanary:leakcanary_java", "//ui/android:ui_java", + "//ui/gfx/geometry/mojo:mojo_java", "//url/mojo:url_mojom_gurl_java", google_play_services_library, ]
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index f1f4805f..c7223de7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1720,13 +1720,7 @@ builder.show(); } } else if (id == R.id.help_id) { - // Since reading back the compositor is asynchronous, we need to do the readback - // before starting the GoogleHelp. - String helpContextId = HelpAndFeedback.getHelpContextIdFromUrl( - this, currentTab.getUrl(), getCurrentTabModel().isIncognito()); - HelpAndFeedback.getInstance(this) - .show(this, helpContextId, currentTab.getProfile(), currentTab.getUrl()); - RecordUserAction.record("MobileMenuFeedback"); + startHelpAndFeedback(currentTab, "MobileMenuFeedback"); } else { return false; } @@ -1734,6 +1728,21 @@ } /** + * Shows HelpAndFeedback and records the user action as well. + * @param currentTab The tab that the user is currently on. + * @param recordAction The user action to record. + */ + public void startHelpAndFeedback(Tab currentTab, String recordAction) { + // Since reading back the compositor is asynchronous, we need to do the readback + // before starting the GoogleHelp. + String helpContextId = HelpAndFeedback.getHelpContextIdFromUrl( + this, currentTab.getUrl(), getCurrentTabModel().isIncognito()); + HelpAndFeedback.getInstance(this) + .show(this, helpContextId, currentTab.getProfile(), currentTab.getUrl()); + RecordUserAction.record(recordAction); + } + + /** * Tests if VR Shell (the mode displaying browser UI and tab contents in VR) is currently * enabled. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java index 7dced043e3..ffe957b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
@@ -293,12 +293,13 @@ } /** - * Sets whether navigation info should be recorded and shared for the session. + * Sets whether navigation info should be recorded and shared for the current navigation in this + * session. */ public synchronized void setSendNavigationInfoForSession( - CustomTabsSessionToken session, boolean save) { + CustomTabsSessionToken session, boolean send) { SessionParams params = mSessionParams.get(session); - if (params != null) params.mShouldSendNavigationInfo = save; + if (params != null) params.mShouldSendNavigationInfo = send; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java index b4ad78c..9313416 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
@@ -95,6 +95,7 @@ mPageLoadStartedTimestamp = SystemClock.elapsedRealtime(); } if (mCustomTabsConnection != null) { + mCustomTabsConnection.setSendNavigationInfoForSession(mSession, false); mCustomTabsConnection.notifyNavigationEvent( mSession, CustomTabsCallback.NAVIGATION_STARTED); mScreenshotTakenForCurrentNavigation = false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java index 13219d9..a9585d87 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -662,6 +662,13 @@ } /** + * See {@link ClientManager#setSendNavigationInfoForSession(CustomTabsSessionToken, boolean)}. + */ + void setSendNavigationInfoForSession(CustomTabsSessionToken session, boolean send) { + mClientManager.setSendNavigationInfoForSession(session, send); + } + + /** * Extracts the creator package name from the intent. * @param intent The intent to get the package name from. * @return the package name which can be null.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java index dec67a4a2..9eb7542 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
@@ -22,6 +22,7 @@ import java.io.File; import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; /** A View that manages the display of space used by the downloads. */ public class SpaceDisplay extends RecyclerView.AdapterDataObserver { @@ -108,6 +109,7 @@ private TextView mSpaceUsedByOtherAppsTextView; private TextView mSpaceFreeTextView; private ProgressBar mSpaceBar; + private long mFreeBytes; SpaceDisplay(final ViewGroup parent, DownloadHistoryAdapter historyAdapter) { mHistoryAdapter = historyAdapter; @@ -131,13 +133,22 @@ } // Determine how much space is free now, then update the display. - mFreeBytesTask = new StorageSizeTask(false) { - @Override - protected void onPostExecute(Long bytes) { - update(); + if (mFreeBytesTask == null) { + mFreeBytesTask = new StorageSizeTask(false) { + @Override + protected void onPostExecute(Long bytes) { + mFreeBytes = bytes.longValue(); + mFreeBytesTask = null; + update(); + } + }; + + try { + mFreeBytesTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } catch (RejectedExecutionException e) { + mFreeBytesTask = null; } - }; - mFreeBytesTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } } @VisibleForTesting @@ -147,17 +158,15 @@ private void update() { long fileSystemBytes = 0; - long freeBytes = 0; try { fileSystemBytes = mFileSystemBytesTask.get(); - freeBytes = mFreeBytesTask.get(); } catch (ExecutionException | InterruptedException e) { // Can't do anything here. } // Indicate how much space has been used by everything on the device via the progress bar. - long bytesUsedTotal = Math.max(0, fileSystemBytes - freeBytes); + long bytesUsedTotal = Math.max(0, fileSystemBytes - mFreeBytes); long bytesUsedByDownloads = Math.max(0, mHistoryAdapter.getTotalDownloadSize()); long bytesUsedByOtherApps = Math.max(0, bytesUsedTotal - bytesUsedByDownloads); @@ -166,7 +175,7 @@ getStringForBytes(USED_STRINGS, bytesUsedByDownloads)); mSpaceUsedByOtherAppsTextView.setText( getStringForBytes(OTHER_STRINGS, bytesUsedByOtherApps)); - mSpaceFreeTextView.setText(getStringForBytes(FREE_STRINGS, freeBytes)); + mSpaceFreeTextView.setText(getStringForBytes(FREE_STRINGS, mFreeBytes)); // Set a minimum size for the download size so that it shows up in the progress bar. long onePercentOfSystem = fileSystemBytes == 0 ? 0 : fileSystemBytes / 100;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java b/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java index 0442a6f..ac04f445 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java
@@ -5,7 +5,9 @@ package org.chromium.chrome.browser.mojo; import org.chromium.base.annotations.CalledByNative; +import org.chromium.blink.mojom.BarcodeDetection; import org.chromium.chrome.browser.payments.PaymentRequestFactory; +import org.chromium.chrome.browser.shapedetection.BarcodeDetectionFactory; import org.chromium.chrome.browser.webshare.ShareServiceImplementationFactory; import org.chromium.content_public.browser.InterfaceRegistrar; import org.chromium.content_public.browser.WebContents; @@ -28,5 +30,7 @@ registry.addInterface(PaymentRequest.MANAGER, new PaymentRequestFactory(webContents)); registry.addInterface( ShareService.MANAGER, new ShareServiceImplementationFactory(webContents)); + registry.addInterface( + BarcodeDetection.MANAGER, new BarcodeDetectionFactory(webContents)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionFactory.java new file mode 100644 index 0000000..c3c3e564 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionFactory.java
@@ -0,0 +1,39 @@ +// Copyright 2016 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. + +package org.chromium.chrome.browser.shapedetection; + +import android.app.Activity; + +import org.chromium.blink.mojom.BarcodeDetection; +import org.chromium.content.browser.ContentViewCore; +import org.chromium.content_public.browser.WebContents; +import org.chromium.services.service_manager.InterfaceFactory; +import org.chromium.ui.base.WindowAndroid; + +/** + * Factory class registered to create BarcodeDetections upon request. + */ +public class BarcodeDetectionFactory implements InterfaceFactory<BarcodeDetection> { + private final WebContents mWebContents; + + public BarcodeDetectionFactory(WebContents webContents) { + mWebContents = webContents; + } + + @Override + public BarcodeDetection createImpl() { + // Get android.content.Context out of |mWebContents|. + final ContentViewCore contentViewCore = ContentViewCore.fromWebContents(mWebContents); + if (contentViewCore == null) return null; + + final WindowAndroid window = contentViewCore.getWindowAndroid(); + if (window == null) return null; + + final Activity context = window.getActivity().get(); + if (context == null) return null; + + return new BarcodeDetectionImpl(context); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java new file mode 100644 index 0000000..ec9e4f5 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java
@@ -0,0 +1,118 @@ +// Copyright 2016 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. + +package org.chromium.chrome.browser.shapedetection; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.util.SparseArray; + +import com.google.android.gms.vision.Frame; +import com.google.android.gms.vision.barcode.Barcode; +import com.google.android.gms.vision.barcode.BarcodeDetector; + +import org.chromium.base.Log; +import org.chromium.blink.mojom.BarcodeDetection; +import org.chromium.blink.mojom.BarcodeDetectionResult; +import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; +import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler; +import org.chromium.gfx.mojom.RectF; +import org.chromium.mojo.system.MojoException; +import org.chromium.mojo.system.SharedBufferHandle; +import org.chromium.mojo.system.SharedBufferHandle.MapFlags; + +import java.nio.ByteBuffer; + +/** + * Implementation of mojo BarcodeDetection, using Google Play Services vision package. + */ +public class BarcodeDetectionImpl implements BarcodeDetection { + private static final String TAG = "BarcodeDetectionImpl"; + + private final Context mContext; + private BarcodeDetector mBarcodeDetector; + + public BarcodeDetectionImpl(Context context) { + Log.d(TAG, "BarcodeDetectionImpl ctor()"); + mContext = context; + mBarcodeDetector = new BarcodeDetector.Builder(mContext).build(); + } + + @Override + public void detect( + SharedBufferHandle frameData, int width, int height, DetectResponse callback) { + if (!ExternalAuthUtils.getInstance().canUseGooglePlayServices( + mContext, new UserRecoverableErrorHandler.Silent())) { + Log.e(TAG, "Google Play Services not available"); + callback.call(new BarcodeDetectionResult[0]); + return; + } + // The vision library will be downloaded the first time the API is used + // on the device; this happens "fast", but it might have not completed, + // bail in this case. Also, the API was disabled between and v.9.0 and + // v.9.2, see https://developers.google.com/android/guides/releases. + if (!mBarcodeDetector.isOperational()) { + Log.e(TAG, "BarcodeDetector is not operational"); + callback.call(new BarcodeDetectionResult[0]); + return; + } + + final long numPixels = (long) width * height; + // TODO(mcasas): https://crbug.com/670028 homogeneize overflow checking. + if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) { + callback.call(new BarcodeDetectionResult[0]); + return; + } + + // Mapping |frameData| will fail if the intended mapped size is larger + // than its actual capacity, which is limited by the appropriate + // mojo::edk::Configuration entry. + ByteBuffer imageBuffer = frameData.map(0, numPixels * 4, MapFlags.none()); + if (imageBuffer.capacity() <= 0) { + callback.call(new BarcodeDetectionResult[0]); + return; + } + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap.copyPixelsFromBuffer(imageBuffer); + + Frame frame = null; + try { + // This constructor implies a pixel format conversion to YUV. + frame = new Frame.Builder().setBitmap(bitmap).build(); + } catch (IllegalArgumentException | IllegalStateException ex) { + Log.e(TAG, "Frame.Builder().setBitmap() or build(): " + ex); + callback.call(new BarcodeDetectionResult[0]); + return; + } + + final SparseArray<Barcode> barcodes = mBarcodeDetector.detect(frame); + + BarcodeDetectionResult[] barcodeArray = new BarcodeDetectionResult[barcodes.size()]; + for (int i = 0; i < barcodes.size(); i++) { + barcodeArray[i] = new BarcodeDetectionResult(); + final Barcode barcode = barcodes.valueAt(i); + barcodeArray[i].rawValue = barcode.rawValue; + final Rect rect = barcode.getBoundingBox(); + barcodeArray[i].boundingBox = new RectF(); + barcodeArray[i].boundingBox.x = rect.left; + barcodeArray[i].boundingBox.y = rect.top; + barcodeArray[i].boundingBox.width = rect.width(); + barcodeArray[i].boundingBox.height = rect.height(); + } + callback.call(barcodeArray); + } + + @Override + public void close() { + mBarcodeDetector.release(); + } + + @Override + public void onConnectionError(MojoException e) { + close(); + } + +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTabViewFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTabViewFactory.java index 704b8e18..71204a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTabViewFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTabViewFactory.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.tab; import android.content.Context; +import android.support.annotation.StringRes; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.View; @@ -21,16 +22,18 @@ * A factory class for creating the "Sad Tab" view, which is shown in place of a crashed renderer. */ public class SadTabViewFactory { + /** * @param context Context of the resulting Sad Tab view. * @param suggestionAction Action to be executed when user clicks "try these suggestions". * @param reloadButtonAction Action to be executed when Reload button is pressed. * (e.g., refreshing the page) + * @param buttonTextId The string resource for the button text label. * @return A "Sad Tab" view instance which is used in place of a crashed renderer. */ public static View createSadTabView( Context context, final OnClickListener suggestionAction, - OnClickListener reloadButtonAction) { + OnClickListener reloadButtonAction, @StringRes int buttonTextId) { // Inflate Sad tab and initialize. LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); @@ -41,6 +44,7 @@ messageText.setMovementMethod(LinkMovementMethod.getInstance()); Button reloadButton = (Button) sadTabView.findViewById(R.id.sad_tab_reload_button); + reloadButton.setText(buttonTextId); reloadButton.setOnClickListener(reloadButtonAction); return sadTabView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java index 466a003..d1d9bcc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -365,6 +365,12 @@ */ private View mSadTabView; + /** + * Counts the number of successive refreshes on the sad tab page. The count is is reset after a + * successful page load. + */ + private int mSadTabSuccessiveRefreshCounter; + private final int mDefaultThemeColor; private int mThemeColor; @@ -1669,6 +1675,9 @@ "Navigation.IsMobileOptimized", mContentViewCore.getIsMobileOptimizedHint()); } + // Reset the succressiveRefresh counter after successfully loading a page. + mSadTabSuccessiveRefreshCounter = 0; + if (mTabUma != null) mTabUma.onPageLoadFinished(); for (TabObserver observer : mObservers) observer.onPageLoadFinished(this); @@ -1876,18 +1885,29 @@ Profile.getLastUsedProfile(), null); } }; - OnClickListener reloadButtonAction = new OnClickListener() { + + // If the tab has crashed twice in a row change the button to "Send Feedback" and + // change the onClickListener. + final boolean showSendFeedbackButton = mSadTabSuccessiveRefreshCounter >= 1; + OnClickListener buttonAction = new OnClickListener() { + @Override - public void onClick(View view) { - reload(); + public void onClick(View v) { + if (showSendFeedbackButton) { + getActivity().startHelpAndFeedback(Tab.this, "MobileSadTabFeedback"); + } else { + reload(); + } } }; // Make sure we are not adding the "Aw, snap" view over an existing one. assert mSadTabView == null; - mSadTabView = SadTabViewFactory.createSadTabView( - mThemedApplicationContext, suggestionAction, reloadButtonAction); + mSadTabView = SadTabViewFactory.createSadTabView(mThemedApplicationContext, + suggestionAction, buttonAction, showSendFeedbackButton + ? R.string.sad_tab_send_feedback_label : R.string.sad_tab_reload_label); + mSadTabSuccessiveRefreshCounter++; // Show the sad tab inside ContentView. getContentViewCore().getContainerView().addView( mSadTabView, new FrameLayout.LayoutParams( @@ -1912,6 +1932,16 @@ } /** + * Removes any existing sad tab view and shows it again. This "reloads" the tab without + * going through any formal loading logic. + */ + @VisibleForTesting + public void reloadSadTabForTesting() { + removeSadTabIfPresent(); + showSadTab(); + } + + /** * @return Whether or not the sad tab is showing. */ public boolean isShowingSadTab() {
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 1e8dc4d..29e6868 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -863,6 +863,8 @@ "java/src/org/chromium/chrome/browser/services/gcm/GcmUma.java", "java/src/org/chromium/chrome/browser/services/gcm/InvalidationGcmUpstreamSender.java", "java/src/org/chromium/chrome/browser/sessions/SessionTabHelper.java", + "java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionFactory.java", + "java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java", "java/src/org/chromium/chrome/browser/share/ShareDialogAdapter.java", "java/src/org/chromium/chrome/browser/share/ShareHelper.java", "java/src/org/chromium/chrome/browser/signin/AccountAdder.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java index 3ef355a..e4b69bd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
@@ -290,9 +290,10 @@ mAdapter.onDownloadItemCreated(item8); } }); - mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount, 2); - // This first check is a Criteria because initialization of the Adapter is asynchronous. + // The criteria is needed because an AsyncTask is fired to update the space display, which + // can result in either 1 or 2 updates. + mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount); CriteriaHelper.pollUiThread(new Criteria() { @Override public boolean isSatisfied() { @@ -367,9 +368,10 @@ mAdapter.onDownloadItemCreated(item8); } }); - mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount, 2); - // This first check is a Criteria because initialization of the Adapter is asynchronous. + // The criteria is needed because an AsyncTask is fired to update the space display, which + // can result in either 1 or 2 updates. + mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount); CriteriaHelper.pollUiThread(new Criteria() { @Override public boolean isSatisfied() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/SadTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/SadTabTest.java index 98802ab6..37b4647 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/SadTabTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/SadTabTest.java
@@ -5,10 +5,12 @@ package org.chromium.chrome.browser.tab; import android.test.suitebuilder.annotation.SmallTest; +import android.widget.Button; import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.RetryOnFailure; +import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.test.ChromeActivityTestCaseBase; @@ -36,14 +38,7 @@ final Tab tab = getActivity().getActivityTab(); assertFalse(tab.isShowingSadTab()); - - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - tab.simulateRendererKilledForTesting(true); - } - }); - + simulateRendererKilled(tab, true); assertTrue(tab.isShowingSadTab()); } @@ -57,14 +52,91 @@ final Tab tab = getActivity().getActivityTab(); assertFalse(tab.isShowingSadTab()); + simulateRendererKilled(tab, false); + assertFalse(tab.isShowingSadTab()); + } + /** + * Confirm that after a successive refresh of a failed tab that failed to load, change the + * button from "Reload" to "Send Feedback". + */ + @SmallTest + @Feature({"SadTab"}) + public void testChangeSadButtonToFeedbackAfterFailedRefresh() { + final Tab tab = getActivity().getActivityTab(); + + assertFalse(tab.isShowingSadTab()); + simulateRendererKilled(tab, true); + assertTrue(tab.isShowingSadTab()); + String actualText = getSadTabButton(tab).getText().toString(); + assertEquals("Expected the sad tab button to have the reload label", + getActivity().getString(R.string.sad_tab_reload_label), actualText); + + reloadSadTab(tab); + assertTrue(tab.isShowingSadTab()); + actualText = getSadTabButton(tab).getText().toString(); + assertEquals( + "Expected the sad tab button to have the feedback label after the tab button " + + "crashes twice in a row.", + getActivity().getString(R.string.sad_tab_send_feedback_label), actualText); + } + + /** + * Confirm after two failures, if we refresh a third time and it's successful, and then we + * crash again, we do not show the "Send Feedback" button and instead show the "Reload" tab. + */ + @SmallTest + @Feature({"SadTab"}) + public void testSadButtonRevertsBackToReloadAfterSuccessfulLoad() { + final Tab tab = getActivity().getActivityTab(); + + simulateRendererKilled(tab, true); + reloadSadTab(tab); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - tab.simulateRendererKilledForTesting(false); + tab.reload(); // Erases the sad tab page + tab.didFinishPageLoad(); // Resets the tab counter to 0 } }); - - assertFalse(tab.isShowingSadTab()); + simulateRendererKilled(tab, true); + String actualText = getSadTabButton(tab).getText().toString(); + assertEquals(getActivity().getString(R.string.sad_tab_reload_label), actualText); } + + /** + * Helper method that kills the renderer on a UI thread. + */ + private void simulateRendererKilled(final Tab tab, final boolean wasOomProtected) { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + tab.simulateRendererKilledForTesting(wasOomProtected); + } + }); + } + + /** + * Helper method that reloads a tab with a SadTabView currently displayed. + */ + private void reloadSadTab(final Tab tab) { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + tab.reloadSadTabForTesting(); + } + }); + } + + /** + * If there is a SadTabView, this method will get the button for the sad tab. + * @param tab The tab that needs to contain a SadTabView. + * @return Returns the button that is on the SadTabView, null if SadTabView. + * doesn't exist. + */ + private Button getSadTabButton(Tab tab) { + return (Button) tab.getContentViewCore().getContainerView() + .findViewById(R.id.sad_tab_reload_button); + } + }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 4779a4b..6aae3e3d 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2172,6 +2172,9 @@ "download/notification/download_notification.h", "download/notification/download_notification_manager.cc", "download/notification/download_notification_manager.h", + "memory/memory_kills_histogram.h", + "memory/memory_kills_monitor.cc", + "memory/memory_kills_monitor.h", "metrics/chromeos_metrics_provider.cc", "metrics/chromeos_metrics_provider.h", "metrics/leak_detector/leak_detector_controller.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index d3568a1..6b96566 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -107,6 +107,7 @@ "+third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h", "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h", "+third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h", + "+third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom.h", "+third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h", "+third_party/WebKit/public/public_features.h", "+third_party/WebKit/public/web/WebCache.h",
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 1c7ce3b..2cab771 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -193,6 +193,7 @@ #include "services/service_manager/public/cpp/interface_registry.h" #include "services/service_manager/public/cpp/service.h" #include "storage/browser/fileapi/external_mount_points.h" +#include "third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom.h" #include "third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -1440,7 +1441,8 @@ return true; } -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN) || \ + defined(OS_ANDROID) bool AreExperimentalWebPlatformFeaturesEnabled() { const base::CommandLine& browser_command_line = *base::CommandLine::ForCurrentProcess(); @@ -3027,6 +3029,19 @@ } } #endif + +#if defined(OS_ANDROID) + if (AreExperimentalWebPlatformFeaturesEnabled()) { + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host); + if (web_contents) { + registry->AddInterface( + web_contents->GetJavaInterfaces() + ->CreateInterfaceFactory<blink::mojom::BarcodeDetection>()); + } + } +#endif + } void ChromeContentBrowserClient::ExposeInterfacesToGpuProcess(
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json index eef80fdb..7bce362b 100644 --- a/chrome/browser/chrome_content_browser_manifest_overlay.json +++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -44,6 +44,7 @@ "renderer": [ "autofill::mojom::AutofillDriver", "autofill::mojom::PasswordManagerDriver", + "blink::mojom::BarcodeDetection", "blink::mojom::ShareService", "bluetooth::mojom::AdapterFactory", "device::usb::ChooserService",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index fc3ef093..19f18b12 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1389,6 +1389,7 @@ "../extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc", "../extensions/api/log_private/syslog_parser_unittest.cc", "../extensions/updater/local_extension_cache_unittest.cc", + "../memory/memory_kills_monitor_unittest.cc", "../metrics/chromeos_metrics_provider_unittest.cc", "../metrics/leak_detector/leak_detector_controller_unittest.cc", "../metrics/perf/cpu_identity_unittest.cc",
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.cc index 7ff06f5..7b28aa97 100644 --- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.cc +++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.cc
@@ -31,7 +31,8 @@ void ArcKioskAppLauncher::OnTaskCreated(int32_t task_id, const std::string& package_name, - const std::string& activity) { + const std::string& activity, + const std::string& intent) { std::unique_ptr<ArcAppListPrefs::AppInfo> app = prefs_->GetApp(app_id_); if (!app || app->package_name != package_name || app->activity != activity) return;
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.h b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.h index 5ea5feb..f854a70 100644 --- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.h +++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.h
@@ -28,7 +28,8 @@ // ArcAppListPrefs::Observer overrides. void OnTaskCreated(int32_t task_id, const std::string& package_name, - const std::string& activity) override; + const std::string& activity, + const std::string& intent) override; // aura::EnvObserver overrides. void OnWindowInitialized(aura::Window* window) override;
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc index b943504..59611d3a 100644 --- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc +++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
@@ -50,7 +50,8 @@ void ArcKioskAppService::OnTaskCreated(int32_t task_id, const std::string& package_name, - const std::string& activity) { + const std::string& activity, + const std::string& intent) { // Store task id of the app to stop it later when needed. if (app_info_ && package_name == app_info_->package_name && activity == app_info_->activity) {
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h index 11ea62d9..79ed66a 100644 --- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h +++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h
@@ -35,7 +35,8 @@ void OnAppReadyChanged(const std::string& id, bool ready) override; void OnTaskCreated(int32_t task_id, const std::string& package_name, - const std::string& activity) override; + const std::string& activity, + const std::string& intent) override; void OnTaskDestroyed(int32_t task_id) override; void OnPackageListInitialRefreshed() override;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index 8cd1f92..b9b4a980 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -354,6 +354,10 @@ chrome::SetChannel(channel); #endif + // Start monitoring OOM kills. + memory_kills_monitor_ = base::MakeUnique<memory::MemoryKillsMonitor::Handle>( + memory::MemoryKillsMonitor::StartMonitoring()); + ChromeBrowserMainPartsLinux::PreEarlyInitialization(); }
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h index fb33160..cea135d 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -11,6 +11,7 @@ #include "base/task/cancelable_task_tracker.h" #include "chrome/browser/chrome_browser_main_linux.h" #include "chrome/browser/chromeos/external_metrics.h" +#include "chrome/browser/memory/memory_kills_monitor.h" #include "chromeos/system/version_loader.h" namespace session_manager { @@ -95,6 +96,8 @@ std::unique_ptr<LowDiskNotification> low_disk_notification_; std::unique_ptr<ArcKioskAppManager> arc_kiosk_app_manager_; + std::unique_ptr<memory::MemoryKillsMonitor::Handle> memory_kills_monitor_; + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsChromeos); };
diff --git a/chrome/browser/chromeos/login/users/affiliation.cc b/chrome/browser/chromeos/login/users/affiliation.cc index 4330afc..6d9b38d 100644 --- a/chrome/browser/chromeos/login/users/affiliation.cc +++ b/chrome/browser/chromeos/login/users/affiliation.cc
@@ -4,7 +4,9 @@ #include "chrome/browser/chromeos/login/users/affiliation.h" +#include "base/command_line.h" #include "chrome/browser/chromeos/policy/device_local_account.h" +#include "components/policy/core/common/policy_switches.h" #include "google_apis/gaia/gaia_auth_util.h" namespace chromeos { @@ -40,6 +42,14 @@ return true; } + // Not all test servers correctly support affiliation ids so far, so + // this is a work-around. + // TODO(antrim): remove this once all test servers support affiliation ids. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(policy::switches::kUserAlwaysAffiliated)) { + return true; + } + if (!device_affiliation_ids.empty() && !user_affiliation_ids.empty()) { return HaveCommonElement(user_affiliation_ids, device_affiliation_ids); }
diff --git a/chrome/browser/chromeos/note_taking_app_utils.cc b/chrome/browser/chromeos/note_taking_app_utils.cc index d68cd41..7f12a8d 100644 --- a/chrome/browser/chromeos/note_taking_app_utils.cc +++ b/chrome/browser/chromeos/note_taking_app_utils.cc
@@ -15,7 +15,6 @@ #include "base/strings/string_split.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/chromeos_switches.h" -#include "extensions/browser/app_window/app_window.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/api/app_runtime.h" #include "extensions/common/extension.h" @@ -87,11 +86,4 @@ apps::LaunchPlatformAppWithAction(profile, app, std::move(action_data), path); } -bool IsNoteTakingAppWindow(extensions::AppWindow* app_window, - Profile* profile) { - DCHECK(app_window && profile); - const extensions::Extension* app = GetApp(profile); - return app && (app->id() == app_window->extension_id()); -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/note_taking_app_utils.h b/chrome/browser/chromeos/note_taking_app_utils.h index 8968dd8..1f32610 100644 --- a/chrome/browser/chromeos/note_taking_app_utils.h +++ b/chrome/browser/chromeos/note_taking_app_utils.h
@@ -11,10 +11,6 @@ class FilePath; } // namespace base -namespace extensions { -class AppWindow; -} // namespace extensions - namespace chromeos { // Returns true if an app that can be used to take notes is available. @@ -26,9 +22,6 @@ void LaunchNoteTakingAppForNewNote(Profile* profile, const base::FilePath& path); -// Returns true if |app_window| belongs to the default note-taking app. -bool IsNoteTakingAppWindow(extensions::AppWindow* app_window, Profile* profile); - } // namespace chromeos #endif // CHROME_BROWSER_CHROMEOS_NOTE_TAKING_APP_UTILS_H_
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc index 366e5d4..cd1785d 100644 --- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc +++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -334,8 +334,10 @@ // Add a new recorder to the render frame map to replace the deleted one. DataUseRecorderEntry entry = data_use_recorders_.emplace( data_use_recorders_.end()); - render_frame_data_use_map_.insert(std::make_pair( - RenderFrameHostID(render_process_id, render_frame_id), entry)); + std::pair<int, int> frame_key = + RenderFrameHostID(render_process_id, render_frame_id); + entry->set_main_frame_id(frame_key); + render_frame_data_use_map_.insert(std::make_pair(frame_key, entry)); } return; }
diff --git a/chrome/browser/memory/memory_kills_histogram.h b/chrome/browser/memory/memory_kills_histogram.h new file mode 100644 index 0000000..67f1641 --- /dev/null +++ b/chrome/browser/memory/memory_kills_histogram.h
@@ -0,0 +1,25 @@ +// Copyright 2016 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 CHROME_BROWSER_MEMORY_MEMORY_KILLS_HISTOGRAM_H_ +#define CHROME_BROWSER_MEMORY_MEMORY_KILLS_HISTOGRAM_H_ + +#include "base/metrics/histogram.h" +#include "base/time/time.h" + +namespace memory { + +constexpr base::TimeDelta kMaxMemoryKillTimeDelta = + base::TimeDelta::FromSeconds(30); + +} // namespace memory + +// Use this macro to report elapsed time since last Memory kill event. +// Must be a macro as the underlying HISTOGRAM macro creates static variables. +#define UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL(name, sample) \ + UMA_HISTOGRAM_CUSTOM_TIMES( \ + name, sample, base::TimeDelta::FromMilliseconds(1), \ + ::memory::kMaxMemoryKillTimeDelta, 50) + +#endif // CHROME_BROWSER_MEMORY_MEMORY_KILLS_HISTOGRAM_H_
diff --git a/chrome/browser/memory/memory_kills_monitor.cc b/chrome/browser/memory/memory_kills_monitor.cc new file mode 100644 index 0000000..9e6da116 --- /dev/null +++ b/chrome/browser/memory/memory_kills_monitor.cc
@@ -0,0 +1,218 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/memory/memory_kills_monitor.h" + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> + +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/debug/leak_annotations.h" +#include "base/files/file_util.h" +#include "base/files/scoped_file.h" +#include "base/lazy_instance.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/posix/safe_strerror.h" +#include "base/sequenced_task_runner.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/synchronization/atomic_flag.h" +#include "base/time/time.h" +#include "chrome/browser/memory/memory_kills_histogram.h" +#include "third_party/re2/src/re2/re2.h" + +namespace memory { + +using base::SequencedWorkerPool; +using base::TimeDelta; + +namespace { + +int64_t GetTimestamp(const std::string& line) { + std::vector<std::string> fields = base::SplitString( + line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + + int64_t timestamp = -1; + // Timestamp is the third field in a line of /dev/kmsg. + if (fields.size() < 3 || !base::StringToInt64(fields[2], ×tamp)) + return -1; + return timestamp; +} + +void LogEvent(const base::Time& time_stamp, const std::string& event) { + VLOG(1) << time_stamp.ToJavaTime() << ", " << event; +} + +void LogOOMKill(int64_t time_stamp, int oom_badness) { + static int64_t last_kill_time = -1; + static int oom_kills = 0; + + // Ideally the timestamp should be parsed from /dev/kmsg, but the timestamp + // there is the elapsed time since system boot. So the timestamp |now| used + // here is a bit delayed. + base::Time now = base::Time::Now(); + LogEvent(now, "OOM_KILL"); + + ++oom_kills; + // Report the cumulative count of killed process in one login session. + // For example if there are 3 processes killed, it would report 1 for the + // first kill, 2 for the second kill, then 3 for the final kill. + // It doesn't report a final count at the end of a user session because + // the code runs in a dedicated thread and never ends until browser shutdown + // (or logout on Chrome OS). And on browser shutdown the thread may be + // terminated brutally so there's no chance to execute a "final" block. + // More specifically, code outside the main loop of MemoryKillsMonitor::Run() + // are not guaranteed to be executed. + UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", oom_kills, 1, 1000, 1001); + + // In practice most process has oom_badness < 1000, but + // strictly speaking the number could be [1, 2000]. What it really + // means is the baseline, proportion of memory used (normalized to + // [0, 1000]), plus an adjustment score oom_score_adj [-1000, 1000], + // truncated to 1 if negative (0 means never kill). + // Ref: https://lwn.net/Articles/396552/ + UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Score", oom_badness, 1, 2000, 2001); + + if (time_stamp > 0) { + // Sets to |kMaxMemoryKillTimeDelta| for the first kill event. + const TimeDelta time_delta = + last_kill_time < 0 ? kMaxMemoryKillTimeDelta: + TimeDelta::FromMicroseconds(time_stamp - last_kill_time); + + last_kill_time = time_stamp; + + UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL( + "Arc.OOMKills.TimeDelta", time_delta); + } +} + +} // namespace + +MemoryKillsMonitor::Handle::Handle(MemoryKillsMonitor* outer) : outer_(outer) { + DCHECK(outer_); +} + +MemoryKillsMonitor::Handle::Handle(MemoryKillsMonitor::Handle&& other) + : outer_(nullptr) { + outer_ = other.outer_; + other.outer_ = nullptr; +} + +MemoryKillsMonitor::Handle::~Handle() { + if (outer_) { + VLOG(2) << "Chrome is shutting down" << outer_; + outer_->is_shutting_down_.Set(); + } +} + +MemoryKillsMonitor::MemoryKillsMonitor() { + base::SimpleThread::Options non_joinable_options; + non_joinable_options.joinable = false; + non_joinable_worker_thread_ = base::MakeUnique<base::DelegateSimpleThread>( + this, "memory_kills_monitor", non_joinable_options); + non_joinable_worker_thread_->Start(); +} + +MemoryKillsMonitor::~MemoryKillsMonitor() { + // The instance has to be leaked on shutdown as it is referred to by a + // non-joinable thread but ~MemoryKillsMonitor() can't be explicitly deleted + // as it overrides ~SimpleThread(), it should nevertheless never be invoked. + NOTREACHED(); +} + +// static +MemoryKillsMonitor::Handle MemoryKillsMonitor::StartMonitoring() { +#if DCHECK_IS_ON() + static volatile bool monitoring_active = false; + DCHECK(!monitoring_active); + monitoring_active = true; +#endif + + // Instantiate the MemoryKillsMonitor and its underlying thread. The + // MemoryKillsMonitor itself has to be leaked on shutdown per having a + // non-joinable thread associated to its state. The MemoryKillsMonitor::Handle + // will notify the MemoryKillsMonitor when it is destroyed so that the + // underlying thread can at a minimum not do extra work during shutdown. + MemoryKillsMonitor* instance = new MemoryKillsMonitor(); + ANNOTATE_LEAKING_OBJECT_PTR(instance); + return Handle(instance); +} + +// static +void MemoryKillsMonitor::LogLowMemoryKill( + const std::string& type, int estimated_freed_kb) { + static base::Time last_kill_time; + static int low_memory_kills = 0; + + base::Time now = base::Time::Now(); + LogEvent(now, "LOW_MEMORY_KILL_" + type); + + const TimeDelta time_delta = + last_kill_time.is_null() ? + kMaxMemoryKillTimeDelta : + (now - last_kill_time); + UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL( + "Arc.LowMemoryKiller.TimeDelta", time_delta); + last_kill_time = now; + + ++low_memory_kills; + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Arc.LowMemoryKiller.Count", low_memory_kills, 1, 1000, 1001); + + UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize", + estimated_freed_kb); +} + +// static +void MemoryKillsMonitor::TryMatchOomKillLine(const std::string& line) { + // Sample OOM log line: + // 3,1362,97646497541,-;Out of memory: Kill process 29582 (android.vending) + // score 961 or sacrifice child. + int oom_badness; + TimeDelta time_delta; + if (RE2::PartialMatch(line, + "Out of memory: Kill process .* score (\\d+)", + &oom_badness)) { + int64_t time_stamp = GetTimestamp(line); + LogOOMKill(time_stamp, oom_badness); + } +} + +void MemoryKillsMonitor::Run() { + VLOG(1) << "MemoryKillsMonitor started"; + base::ScopedFILE kmsg_handle( + base::OpenFile(base::FilePath("/dev/kmsg"), "r")); + if (!kmsg_handle) { + LOG(WARNING) << "Open /dev/kmsg failed: " << base::safe_strerror(errno); + return; + } + // Skip kernel messages prior to the instantiation of this object to avoid + // double reporting. + fseek(kmsg_handle.get(), 0, SEEK_END); + + static constexpr int kMaxBufSize = 512; + char buf[kMaxBufSize]; + + while (fgets(buf, kMaxBufSize, kmsg_handle.get())) { + if (is_shutting_down_.IsSet()) { + // Not guaranteed to execute when the process is shutting down, + // because the thread might be blocked in fgets(). + VLOG(1) << "Chrome is shutting down, MemoryKillsMonitor exits."; + break; + } + TryMatchOomKillLine(buf); + } +} + + +} // namespace memory
diff --git a/chrome/browser/memory/memory_kills_monitor.h b/chrome/browser/memory/memory_kills_monitor.h new file mode 100644 index 0000000..8594f53 --- /dev/null +++ b/chrome/browser/memory/memory_kills_monitor.h
@@ -0,0 +1,89 @@ +// Copyright 2016 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 CHROME_BROWSER_MEMORY_MEMORY_KILLS_MONITOR_H_ +#define CHROME_BROWSER_MEMORY_MEMORY_KILLS_MONITOR_H_ + +#include <memory> +#include <string> + +#include "base/files/scoped_file.h" +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/atomic_flag.h" +#include "base/synchronization/lock.h" +#include "base/threading/simple_thread.h" +#include "base/time/time.h" + +namespace memory { + +// Traces kernel OOM kill events and Low memory kill events (by Chrome +// TabManager). +// +// For OOM kill events, it listens to kernel message (/dev/kmsg) in a blocking +// manner. It runs in a non-joinable thread in order to avoid blocking shutdown. +// There should be only one MemoryKillsMonitor instance globally at any given +// time, otherwise UMA would receive duplicate events. +// +// For Low memory kills events, chrome calls the single global instance of +// MemoryKillsMonitor synchronously. Note that it would be from a browser thread +// other than the listening thread. +// +// For every events, it reports to UMA and optionally a local file specified by +// --memory-kills-log. The log file is useful if we want to analyze low memory +// kills. If the flag is not given, it won't write to any file. +class MemoryKillsMonitor : public base::DelegateSimpleThread::Delegate { + public: + // A handle representing the MemoryKillsMonitor's lifetime (the monitor itself + // can't be destroyed per being a non-joinable Thread). + class Handle { + public: + // Constructs a handle that will flag |outer| as shutting down on + // destruction. + explicit Handle(MemoryKillsMonitor* outer); + + Handle(Handle&& handle); + + ~Handle(); + + private: + MemoryKillsMonitor* outer_; + DISALLOW_COPY_AND_ASSIGN(Handle); + }; + + // Instantiates the MemoryKillsMonitor instance and starts it. This must only + // be invoked once per process. + static Handle StartMonitoring(); + + // Logs a low memory kill event. + static void LogLowMemoryKill(const std::string& type, int estimated_freed_kb); + + private: + FRIEND_TEST_ALL_PREFIXES(MemoryKillsMonitorTest, TryMatchOomKillLine); + + MemoryKillsMonitor(); + ~MemoryKillsMonitor() override; + + // Overridden from base::DelegateSimpleThread::Delegate: + void Run() override; + + // Try to match a line in kernel message which reports OOM. + static void TryMatchOomKillLine(const std::string& line); + + // A flag set when MemoryKillsMonitor is shutdown so that its thread can poll + // it and attempt to wind down from that point (to avoid unnecessary work, not + // because it blocks shutdown). + base::AtomicFlag is_shutting_down_; + + // The underlying worker thread which is non-joinable to avoid blocking + // shutdown. + std::unique_ptr<base::DelegateSimpleThread> non_joinable_worker_thread_; + + DISALLOW_COPY_AND_ASSIGN(MemoryKillsMonitor); +}; + +} // namespace memory + +#endif // CHROME_BROWSER_MEMORY_MEMORY_KILLS_MONITOR_H_
diff --git a/chrome/browser/memory/memory_kills_monitor_unittest.cc b/chrome/browser/memory/memory_kills_monitor_unittest.cc new file mode 100644 index 0000000..339030e --- /dev/null +++ b/chrome/browser/memory/memory_kills_monitor_unittest.cc
@@ -0,0 +1,99 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/memory/memory_kills_monitor.h" + +#include "base/macros.h" +#include "base/metrics/histogram_base.h" +#include "base/metrics/histogram_samples.h" +#include "base/metrics/statistics_recorder.h" +#include "base/time/time.h" +#include "chrome/browser/memory/memory_kills_histogram.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace memory { + +using MemoryKillsMonitorTest = testing::Test; + +TEST_F(MemoryKillsMonitorTest, LogLowMemoryKill) { + MemoryKillsMonitor::LogLowMemoryKill("APP", 123); + MemoryKillsMonitor::LogLowMemoryKill("APP", 100); + MemoryKillsMonitor::LogLowMemoryKill("TAB", 10000); + + auto histogram_count = + base::StatisticsRecorder::FindHistogram("Arc.LowMemoryKiller.Count"); + ASSERT_TRUE(histogram_count); + auto count_samples = histogram_count->SnapshotSamples(); + EXPECT_EQ(3, count_samples->TotalCount()); + EXPECT_EQ(1, count_samples->GetCount(1)); + EXPECT_EQ(1, count_samples->GetCount(2)); + EXPECT_EQ(1, count_samples->GetCount(3)); + + auto histogram_freed_size = + base::StatisticsRecorder::FindHistogram("Arc.LowMemoryKiller.FreedSize"); + ASSERT_TRUE(histogram_freed_size); + auto freed_size_samples = histogram_freed_size->SnapshotSamples(); + EXPECT_EQ(3, freed_size_samples->TotalCount()); + // 123 and 100 are in the same bucket. + EXPECT_EQ(2, freed_size_samples->GetCount(123)); + EXPECT_EQ(2, freed_size_samples->GetCount(100)); + EXPECT_EQ(1, freed_size_samples->GetCount(10000)); + + auto histogram_time_delta = + base::StatisticsRecorder::FindHistogram("Arc.LowMemoryKiller.TimeDelta"); + ASSERT_TRUE(histogram_time_delta); + auto time_delta_samples = histogram_time_delta->SnapshotSamples(); + EXPECT_EQ(3, time_delta_samples->TotalCount()); + // First time delta is set to kMaxMemoryKillTimeDelta. + EXPECT_EQ(1, time_delta_samples->GetCount( + kMaxMemoryKillTimeDelta.InMilliseconds())); + // Time delta for the other 2 events depends on Now() so we skip testing it + // here. +} + +TEST_F(MemoryKillsMonitorTest, TryMatchOomKillLine) { + const char* sample_lines[] = { + "3,3429,812967386,-;Out of memory: Kill process 8291 (handle-watcher-) " + "score 674 or sacrifice child", + "3,3431,812981331,-;Out of memory: Kill process 8271 (.gms.persistent) " + "score 652 or sacrifice child", + "3,3433,812993014,-;Out of memory: Kill process 9210 (lowpool[11]) " + "score 653 or sacrifice child" + }; + + for (unsigned long i = 0; i < arraysize(sample_lines); ++i) { + MemoryKillsMonitor::TryMatchOomKillLine(sample_lines[i]); + } + + auto histogram_count = + base::StatisticsRecorder::FindHistogram("Arc.OOMKills.Count"); + ASSERT_TRUE(histogram_count); + auto count_samples = histogram_count->SnapshotSamples(); + EXPECT_EQ(3, count_samples->TotalCount()); + EXPECT_EQ(1, count_samples->GetCount(1)); + EXPECT_EQ(1, count_samples->GetCount(2)); + EXPECT_EQ(1, count_samples->GetCount(3)); + + auto histogram_score = + base::StatisticsRecorder::FindHistogram("Arc.OOMKills.Score"); + ASSERT_TRUE(histogram_score); + auto score_samples = histogram_score->SnapshotSamples(); + EXPECT_EQ(3, score_samples->TotalCount()); + EXPECT_EQ(1, score_samples->GetCount(674)); + EXPECT_EQ(1, score_samples->GetCount(652)); + EXPECT_EQ(1, score_samples->GetCount(653)); + + auto histogram_time_delta = + base::StatisticsRecorder::FindHistogram("Arc.OOMKills.TimeDelta"); + ASSERT_TRUE(histogram_time_delta); + auto time_delta_samples = histogram_time_delta->SnapshotSamples(); + EXPECT_EQ(3, time_delta_samples->TotalCount()); + // First time delta is set to kMaxMemoryKillTimeDelta. + EXPECT_EQ(1, time_delta_samples->GetCount( + kMaxMemoryKillTimeDelta.InMilliseconds())); + EXPECT_EQ(1, time_delta_samples->GetCount(11)); + EXPECT_EQ(1, time_delta_samples->GetCount(13)); +} + +} // namespace memory
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.cc b/chrome/browser/memory/tab_manager_delegate_chromeos.cc index 75100d0..b9f1d3e 100644 --- a/chrome/browser/memory/tab_manager_delegate_chromeos.cc +++ b/chrome/browser/memory/tab_manager_delegate_chromeos.cc
@@ -27,6 +27,7 @@ #include "base/time/time.h" #include "chrome/browser/chromeos/arc/process/arc_process.h" #include "chrome/browser/chromeos/arc/process/arc_process_service.h" +#include "chrome/browser/memory/memory_kills_monitor.h" #include "chrome/browser/memory/tab_stats.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" @@ -36,7 +37,6 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/common/process.mojom.h" -#include "components/arc/metrics/oom_kills_histogram.h" #include "components/exo/shell_surface.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" @@ -273,36 +273,6 @@ return mem_usage.priv; } -class TabManagerDelegate::UmaReporter { - public: - UmaReporter() : total_kills_(0) {} - ~UmaReporter() {} - - void ReportKill(const int memory_freed); - - private: - base::Time last_kill_time_; - int total_kills_; -}; - -void TabManagerDelegate::UmaReporter::ReportKill(const int memory_freed) { - base::Time now = base::Time::Now(); - const TimeDelta time_delta = - last_kill_time_.is_null() ? - TimeDelta::FromSeconds(arc::kMaxOomMemoryKillTimeDeltaSecs) : - (now - last_kill_time_); - UMA_HISTOGRAM_OOM_KILL_TIME_INTERVAL( - "Arc.LowMemoryKiller.TimeDelta", time_delta); - last_kill_time_ = now; - - ++total_kills_; - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Arc.LowMemoryKiller.Count", total_kills_, 1, 1000, 1001); - - UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize", - memory_freed); -} - TabManagerDelegate::TabManagerDelegate( const base::WeakPtr<TabManager>& tab_manager) : TabManagerDelegate(tab_manager, new MemoryStat()) { @@ -314,7 +284,6 @@ : tab_manager_(tab_manager), focused_process_(new FocusedProcess()), mem_stat_(mem_stat), - uma_(new UmaReporter()), weak_ptr_factory_(this) { registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, content::NotificationService::AllBrowserContextsAndSources()); @@ -631,7 +600,7 @@ mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); if (KillArcProcess(it->app()->nspid())) { target_memory_to_free_kb -= estimated_memory_freed_kb; - uma_->ReportKill(estimated_memory_freed_kb); + MemoryKillsMonitor::LogLowMemoryKill("APP", estimated_memory_freed_kb); VLOG(2) << "Killed " << *it; } } else { @@ -643,7 +612,7 @@ mem_stat_->EstimatedMemoryFreedKB(it->tab()->renderer_handle); if (KillTab(tab_id)) { target_memory_to_free_kb -= estimated_memory_freed_kb; - uma_->ReportKill(estimated_memory_freed_kb); + MemoryKillsMonitor::LogLowMemoryKill("TAB", estimated_memory_freed_kb); VLOG(2) << "Killed " << *it; } }
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.h b/chrome/browser/memory/tab_manager_delegate_chromeos.h index 13c6c8b..af53e01 100644 --- a/chrome/browser/memory/tab_manager_delegate_chromeos.h +++ b/chrome/browser/memory/tab_manager_delegate_chromeos.h
@@ -97,7 +97,6 @@ class Candidate; class FocusedProcess; - class UmaReporter; friend std::ostream& operator<<(std::ostream& out, const Candidate& candidate); @@ -169,9 +168,6 @@ // Util for getting system memory status. std::unique_ptr<TabManagerDelegate::MemoryStat> mem_stat_; - // Reports UMA histograms. - std::unique_ptr<UmaReporter> uma_; - // Weak pointer factory used for posting tasks to other threads. base::WeakPtrFactory<TabManagerDelegate> weak_ptr_factory_;
diff --git a/chrome/browser/resources/chromeos/login/lock.js b/chrome/browser/resources/chromeos/login/lock.js index 0e2a3d18..ad5919ce 100644 --- a/chrome/browser/resources/chromeos/login/lock.js +++ b/chrome/browser/resources/chromeos/login/lock.js
@@ -29,7 +29,7 @@ // Called after polymer has been loaded. Fades the pin element in. var onPinLoaded = function(pinKeyboard) { var podRow = $('pod-row'); - podRow.togglePinTransitions(true); + podRow.toggleTransitions(true); podRow.setFocusedPodPinVisibility(true); };
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.css b/chrome/browser/resources/chromeos/login/oobe_eula.css index defff1b..390d952 100644 --- a/chrome/browser/resources/chromeos/login/oobe_eula.css +++ b/chrome/browser/resources/chromeos/login/oobe_eula.css
@@ -36,5 +36,9 @@ } .bottom-buttons { - padding: 0 24px; + padding: 0 6px; /* = 8px - 2px back button border */ +} + +#eula-accept-button { + -webkit-padding-end: 18px; }
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.html b/chrome/browser/resources/chromeos/login/oobe_eula.html index 5fc8eb3..013c863f 100644 --- a/chrome/browser/resources/chromeos/login/oobe_eula.html +++ b/chrome/browser/resources/chromeos/login/oobe_eula.html
@@ -59,8 +59,12 @@ </paper-checkbox> </div> </div> - <div class="bottom-buttons flex layout horizontal end-justified"> - <oobe-text-button inverse on-tap="eulaAccepted_" + <div class="bottom-buttons flex layout horizontal"> + <oobe-back-button on-tap="onEulaBackButtonPressed_"> + </oobe-back-button> + <div class="flex"> + </div> + <oobe-text-button id="eula-accept-button" inverse on-tap="eulaAccepted_" disabled="[[acceptButtonDisabled]]"> <div i18n-content="oobeEulaAcceptAndContinueButtonText" id="accept-button-text">
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.js b/chrome/browser/resources/chromeos/login/oobe_eula.js index 78cf7ed..8ff6cf2 100644 --- a/chrome/browser/resources/chromeos/login/oobe_eula.js +++ b/chrome/browser/resources/chromeos/login/oobe_eula.js
@@ -76,7 +76,7 @@ /** * On-change event handler for usageStats. * - * * @private + * @private */ onUsageChanged_: function() { this.screen.onUsageStatsClicked_(this.$.usageStats.checked); @@ -85,7 +85,7 @@ /** * On-tap event handler for installationSettings. * - * * @private + * @private */ onInstallationSettingsClicked_: function() { chrome.send('eulaOnInstallationSettingsPopupOpened'); @@ -96,9 +96,18 @@ /** * On-tap event handler for stats-help-link. * - * * @private + * @private */ onUsageStatsHelpLinkClicked_: function() { chrome.send('eulaOnLearnMore'); }, + + /** + * On-tap event handler for back button. + * + * @private + */ + onEulaBackButtonPressed_: function() { + chrome.send('login.EulaScreen.userActed', ['back-button']); + }, });
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc index 9a5b4f5..6d535b1 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -2350,11 +2350,6 @@ // From an HTTP top frame, navigate to good and bad HTTPS (security state should // stay unauthenticated). IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnauthenticatedFrameNavigation) { - // TODO(crbug.com/668913): Flaky with --site-per-process. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kSitePerProcess)) { - return; - } ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(https_server_.Start()); ASSERT_TRUE(https_server_expired_.Start());
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc index e2e59da..c64051c 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -859,6 +859,7 @@ package_dict->SetString(kLastBackupAndroidId, id_str); package_dict->SetString(kLastBackupTime, time_str); package_dict->SetBoolean(kSystem, package.system); + package_dict->SetBoolean(kUninstalled, false); } void ArcAppListPrefs::RemovePackageFromPrefs(PrefService* prefs, @@ -962,6 +963,7 @@ std::unordered_set<std::string> apps_to_remove = GetAppsForPackage(package_name); + default_apps_.MaybeMarkPackageUninstalled(package_name, false); for (const auto& app : apps) { apps_to_remove.erase(GetAppId(app->package_name, app->activity)); AddApp(*app); @@ -1064,10 +1066,15 @@ void ArcAppListPrefs::OnTaskCreated(int32_t task_id, const std::string& package_name, const std::string& activity, - const base::Optional<std::string>& name) { + const base::Optional<std::string>& name, + const base::Optional<std::string>& intent) { MaybeAddNonLaunchableApp(name, package_name, activity); - for (auto& observer : observer_list_) - observer.OnTaskCreated(task_id, package_name, activity); + for (auto& observer : observer_list_) { + observer.OnTaskCreated(task_id, + package_name, + activity, + intent.value_or(std::string())); + } } void ArcAppListPrefs::OnTaskDestroyed(int32_t task_id) { @@ -1193,8 +1200,14 @@ prefs_->GetDictionary(prefs::kArcPackages); for (base::DictionaryValue::Iterator package(*package_prefs); !package.IsAtEnd(); package.Advance()) { + const base::DictionaryValue* package_info; + if (!package.value().GetAsDictionary(&package_info)) { + NOTREACHED(); + continue; + } + bool uninstalled = false; - package_prefs->GetBoolean(kSystem, &uninstalled); + package_info->GetBoolean(kUninstalled, &uninstalled); if (installed != !uninstalled) continue;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h index d97686a..7c7e613 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -126,7 +126,8 @@ // initial activity. virtual void OnTaskCreated(int32_t task_id, const std::string& package_name, - const std::string& activity) {} + const std::string& activity, + const std::string& intent) {} // Notifies that task has been destroyed. virtual void OnTaskDestroyed(int32_t task_id) {} // Notifies that task has been activated and moved to the front. @@ -278,7 +279,8 @@ void OnTaskCreated(int32_t task_id, const std::string& package_name, const std::string& activity, - const base::Optional<std::string>& name) override; + const base::Optional<std::string>& name, + const base::Optional<std::string>& intent) override; void OnTaskDestroyed(int32_t task_id) override; void OnTaskSetActive(int32_t task_id) override; void OnNotificationsEnabledChanged(const std::string& package_name,
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc index c606367..58f3594d 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -372,6 +372,8 @@ // ArcAppModelBuilderTest: void OnBeforeArcTestSetup() override { ArcDefaultAppList::UseTestAppsDirectory(); + arc::ArcPackageSyncableServiceFactory::GetInstance()->SetTestingFactory( + profile_.get(), nullptr); } private: @@ -1111,7 +1113,7 @@ EXPECT_FALSE(prefs->IsRegistered(app_id)); EXPECT_FALSE(FindArcItem(app_id)); - app_instance()->SendTaskCreated(0, fake_apps()[0]); + app_instance()->SendTaskCreated(0, fake_apps()[0], std::string()); // App should not appear now in the model but should be registered. EXPECT_FALSE(FindArcItem(app_id)); EXPECT_TRUE(prefs->IsRegistered(app_id)); @@ -1181,11 +1183,13 @@ } // And now default apps are ready. + std::map<std::string, bool> oem_states; for (const auto& default_app : fake_default_apps()) { - std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp( - ArcAppTest::GetAppId(default_app)); + const std::string app_id = ArcAppTest::GetAppId(default_app); + std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(app_id); ASSERT_TRUE(app_info); EXPECT_TRUE(app_info->ready); + oem_states[app_id] = prefs->IsOem(app_id); } // Uninstall first default package. Default app should go away. @@ -1198,6 +1202,33 @@ all_apps = fake_default_apps(); all_apps.erase(all_apps.begin()); ValidateHaveApps(all_apps); + + // Sign-out and sign-in again. Removed default app should not appear. + arc_test()->TearDown(); + ResetBuilder(); + ArcAppListPrefsFactory::GetInstance()->RecreateServiceInstanceForTesting( + profile_.get()); + arc_test()->SetUp(profile_.get()); + CreateBuilder(); + + // Prefs are changed. + prefs = ArcAppListPrefs::Get(profile_.get()); + ASSERT_NE(nullptr, prefs); + + ValidateHaveApps(all_apps); + + // Install deleted default app again. + std::vector<arc::mojom::AppInfo> package_apps; + package_apps.push_back(fake_default_apps()[0]); + app_instance()->SendPackageAppListRefreshed( + fake_default_apps()[0].package_name, package_apps); + ValidateHaveApps(fake_default_apps()); + + // Validate that OEM state is preserved. + for (const auto& default_app : fake_default_apps()) { + const std::string app_id = ArcAppTest::GetAppId(default_app); + EXPECT_EQ(oem_states[app_id], prefs->IsOem(app_id)); + } } TEST_F(ArcDefaulAppForManagedUserTest, DefaultAppsForManagedUser) {
diff --git a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc index cde7f22..7aadc019 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc
@@ -382,6 +382,7 @@ EXPECT_FALSE(delegate->IsAppOpen(app_id)); // Simulate task creation so the app is marked as running/open. std::unique_ptr<ArcAppListPrefs::AppInfo> info = app_prefs()->GetApp(app_id); - app_host()->OnTaskCreated(0, info->package_name, info->activity, info->name); + app_host()->OnTaskCreated(0, info->package_name, info->activity, info->name, + info->intent_uri); EXPECT_TRUE(delegate->IsAppOpen(app_id)); }
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc index 870186d..19a6119 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -455,7 +455,8 @@ void ArcAppWindowLauncherController::OnTaskCreated( int task_id, const std::string& package_name, - const std::string& activity_name) { + const std::string& activity_name, + const std::string& intent) { DCHECK(!GetAppWindowForTask(task_id)); const std::string arc_app_id = ArcAppListPrefs::GetAppId(package_name, activity_name);
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h index a1006dd..8294402 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
@@ -75,7 +75,8 @@ void OnAppRemoved(const std::string& app_id) override; void OnTaskCreated(int task_id, const std::string& package_name, - const std::string& activity) override; + const std::string& activity, + const std::string& intent) override; void OnTaskDestroyed(int task_id) override; void OnTaskSetActive(int32_t task_id) override; void OnTaskOrientationLockRequested(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc index 1dd2b49..031e7dc2 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -867,7 +867,7 @@ int32_t task_id) { ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs(); prefs->OnTaskCreated(task_id, appinfo.package_name, appinfo.activity, - appinfo.name); + appinfo.name, std::string()); } void NotifyOnTaskOrientationLockRequested(int32_t task_id, @@ -1865,13 +1865,15 @@ std::string window_app_id1("org.chromium.arc.1"); views::Widget* arc_window1 = CreateArcWindow(window_app_id1); - arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0]); + arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id1)); std::string window_app_id2("org.chromium.arc.2"); views::Widget* arc_window2 = CreateArcWindow(window_app_id2); - arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1]); + arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id2)); @@ -1885,7 +1887,8 @@ std::string window_app_id3("org.chromium.arc.3"); views::Widget* arc_window3 = CreateArcWindow(window_app_id3); - arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[2]); + arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[2], + std::string()); EXPECT_EQ(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id3)); @@ -1920,11 +1923,13 @@ std::string window_app_id2("org.chromium.arc.2"); std::string window_app_id3("org.chromium.arc.3"); CreateArcWindow(window_app_id1); - arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0]); + arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id)); CreateArcWindow(window_app_id2); - arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[0]); + arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[0], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id)); arc_test_.app_instance()->SendTaskDestroyed(1); @@ -1936,7 +1941,8 @@ // Stopping bridge removes apps. CreateArcWindow(window_app_id3); - arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[0]); + arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[0], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id)); arc_test_.StopArcInstance(); @@ -1962,7 +1968,8 @@ EXPECT_EQ(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id1)); ASSERT_TRUE(arc_window); - arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0]); + arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id1)); arc_test_.app_instance()->SendTaskDestroyed(1); @@ -1975,7 +1982,8 @@ // Arc window created after and closed before mojom notification. std::string window_app_id2("org.chromium.arc.2"); - arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1]); + arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(arc_app_id2)); arc_window = CreateArcWindow(window_app_id2); @@ -2001,7 +2009,8 @@ std::string window_app_id("org.chromium.arc.1"); views::Widget* arc_window = CreateArcWindow(window_app_id); ASSERT_TRUE(arc_window); - arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0]); + arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0], + std::string()); const ash::ShelfID shelf_id = launcher_controller_->GetShelfIDForAppID(arc_app_id); EXPECT_NE(ash::kInvalidShelfID, shelf_id); @@ -3985,8 +3994,8 @@ std::string window_app_id("org.chromium.arc.1"); CreateArcWindow(window_app_id); - arc_test_.app_instance()->SendTaskCreated(1, - arc_test_.fake_default_apps()[0]); + arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_default_apps()[0], + std::string()); EXPECT_NE(ash::kInvalidShelfID, launcher_controller_->GetShelfIDForAppID(app_id));
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc index 1165229..caeb9e0 100644 --- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc +++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -211,7 +211,8 @@ // Arc app is running. std::string window_app_id1("org.chromium.arc.1"); CreateArcWindow(window_app_id1); - arc_test().app_instance()->SendTaskCreated(1, arc_test().fake_apps()[0]); + arc_test().app_instance()->SendTaskCreated(1, arc_test().fake_apps()[0], + std::string()); menu.reset(new ArcLauncherContextMenu(controller(), &item, wm_shelf)); EXPECT_FALSE( @@ -225,7 +226,8 @@ const std::string app_id2 = ArcAppTest::GetAppId(arc_test().fake_apps()[1]); std::string window_app_id2("org.chromium.arc.2"); CreateArcWindow(window_app_id2); - arc_test().app_instance()->SendTaskCreated(2, arc_test().fake_apps()[1]); + arc_test().app_instance()->SendTaskCreated(2, arc_test().fake_apps()[1], + std::string()); item.id = controller()->GetShelfIDForAppID(app_id2); ASSERT_TRUE(item.id); menu.reset(new ArcLauncherContextMenu(controller(), &item, wm_shelf));
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 91b0f3a31..cffc7903 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -431,6 +431,26 @@ [super dealloc]; } +// Hack to address crbug.com/667274 +// On TouchBar MacBooks, the touch bar machinery retains a reference +// to the browser window controller (which is an NSTouchBarProvider by +// default) but doesn't release it if Chrome quits before it takes the +// key window (for example, quitting from the Dock icon context menu.) +// +// If the window denies being a touch bar provider, it's never added +// to the set of providers and the reference is never taken. This +// prevents us from providing a touch bar from the window directly +// but descendant responders can still provide one. +// +// rdar://29467717 +- (BOOL)conformsToProtocol:(Protocol*)protocol { + if ([protocol isEqual:NSProtocolFromString(@"NSFunctionBarProvider")] || + [protocol isEqual:NSProtocolFromString(@"NSTouchBarProvider")]) { + return NO; + } + return [super conformsToProtocol:protocol]; +} + - (gfx::Rect)enforceMinWindowSize:(gfx::Rect)bounds { gfx::Rect checkedBounds = bounds;
diff --git a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm index dea4c912..f5f0887 100644 --- a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm +++ b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
@@ -191,44 +191,46 @@ alignment:NSLeftTextAlignment]; NSSize headingSize = [heading frame].size; + NSSize extraViewIconSize = NSZeroSize; + NSSize extraViewTextSize = NSZeroSize; + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> extra_view_info = delegate_->GetExtraViewInfo(); - gfx::VectorIconId resource_id = extra_view_info->resource_id; + if (extra_view_info) { + gfx::VectorIconId resource_id = extra_view_info->resource_id; + // The extra view icon is optional. + if (resource_id != gfx::VectorIconId::VECTOR_ICON_NONE) { + NSImage* image = gfx::Image(gfx::CreateVectorIcon(resource_id, 16, + gfx::kChromeIconGrey)) + .ToNSImage(); + NSRect frame = NSMakeRect(0, 0, image.size.width, image.size.height); + iconView_ = [[[NSImageView alloc] initWithFrame:frame] autorelease]; + [iconView_ setImage:image]; + extraViewIconSize = frame.size; - NSSize extraViewIconSize = NSZeroSize; - // The extra view icon is optional. - if (resource_id != gfx::VectorIconId::VECTOR_ICON_NONE) { - NSImage* image = - gfx::Image(gfx::CreateVectorIcon(resource_id, 16, gfx::kChromeIconGrey)) - .ToNSImage(); - NSRect frame = NSMakeRect(0, 0, image.size.width, image.size.height); - iconView_ = [[[NSImageView alloc] initWithFrame:frame] autorelease]; - [iconView_ setImage:image]; - extraViewIconSize = frame.size; - - [[[self window] contentView] addSubview:iconView_]; - } - - NSSize extraViewTextSize = NSZeroSize; - const base::string16& text = extra_view_info->text; - if (!text.empty()) { // The extra view text is optional. - if (extra_view_info->is_text_linked) { - NSAttributedString* linkString = - [self attributedStringWithString:text - fontSize:13.0 - alignment:NSLeftTextAlignment]; - link_ = [HyperlinkButtonCell buttonWithString:linkString.string]; - [link_ setTarget:self]; - [link_ setAction:@selector(onButtonClicked:)]; - [[[self window] contentView] addSubview:link_]; - [link_ sizeToFit]; - } else { - label_ = [self addTextFieldWithString:text - fontSize:13.0 - alignment:NSLeftTextAlignment]; + [[[self window] contentView] addSubview:iconView_]; } - extraViewTextSize = label_ ? [label_ frame].size : [link_ frame].size; + + const base::string16& text = extra_view_info->text; + if (!text.empty()) { // The extra view text is optional. + if (extra_view_info->is_text_linked) { + NSAttributedString* linkString = + [self attributedStringWithString:text + fontSize:13.0 + alignment:NSLeftTextAlignment]; + link_ = [HyperlinkButtonCell buttonWithString:linkString.string]; + [link_ setTarget:self]; + [link_ setAction:@selector(onButtonClicked:)]; + [[[self window] contentView] addSubview:link_]; + [link_ sizeToFit]; + } else { + label_ = [self addTextFieldWithString:text + fontSize:13.0 + alignment:NSLeftTextAlignment]; + } + extraViewTextSize = label_ ? [label_ frame].size : [link_ frame].size; + } } base::string16 cancelStr = delegate_->GetDismissButtonText(); @@ -318,27 +320,27 @@ dismissButtonSize.height)]; currentMaxWidth -= (dismissButtonSize.width + kButtonPadding); } - if (label_ || link_) { - CGFloat extraViewTextHeight = - currentHeight + (buttonStripHeight - extraViewTextSize.height) / 2.0; - NSRect frame = NSMakeRect(currentMaxWidth - extraViewTextSize.width, - extraViewTextHeight, extraViewTextSize.width, - extraViewTextSize.height); - if (link_) { - [link_ setFrame:frame]; - } else { - [label_ setFrame:frame]; - } - currentMaxWidth -= extraViewTextSize.width + kButtonPadding; - } + int leftAlignXPos = kHorizontalPadding; if (iconView_) { CGFloat extraViewIconHeight = currentHeight + (buttonStripHeight - extraViewIconSize.height) / 2.0; [iconView_ - setFrame:NSMakeRect(kHorizontalPadding, extraViewIconHeight, + setFrame:NSMakeRect(leftAlignXPos, extraViewIconHeight, extraViewIconSize.width, extraViewIconSize.height)]; - currentMaxWidth -= extraViewIconSize.width + kButtonPadding; + leftAlignXPos += extraViewIconSize.width + kButtonPadding; + } + if (label_ || link_) { + CGFloat extraViewTextHeight = + currentHeight + (buttonStripHeight - extraViewTextSize.height) / 2.0; + NSRect frame = + NSMakeRect(leftAlignXPos, extraViewTextHeight, extraViewTextSize.width, + extraViewTextSize.height); + if (link_) { + [link_ setFrame:frame]; + } else { + [label_ setFrame:frame]; + } } // Buttons have some inherit padding of their own, so we don't need quite as // much space here.
diff --git a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm index 650ec69..4b416be2 100644 --- a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm +++ b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm
@@ -6,6 +6,7 @@ #import "base/mac/foundation_util.h" #import "base/mac/scoped_nsobject.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #import "chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.h" @@ -112,10 +113,12 @@ HeadingString(), BodyString(), ActionString()); delegate.set_dismiss_button_text(DismissString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info_linked_text; - extra_view_info_linked_text.text = LearnMoreString(); - extra_view_info_linked_text.is_text_linked = true; - delegate.set_extra_view_info(extra_view_info_linked_text); + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info_linked_text = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info_linked_text->text = LearnMoreString(); + extra_view_info_linked_text->is_text_linked = true; + delegate.set_extra_view_info(std::move(extra_view_info_linked_text)); ToolbarActionsBarBubbleMac* bubble = CreateAndShowBubble(&delegate); base::scoped_nsobject<WindowObserver> windowObserver( @@ -201,10 +204,12 @@ TestToolbarActionsBarBubbleDelegate delegate( HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info_linked_text; - extra_view_info_linked_text.text = LearnMoreString(); - extra_view_info_linked_text.is_text_linked = true; - delegate.set_extra_view_info(extra_view_info_linked_text); + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info_linked_text = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info_linked_text->text = LearnMoreString(); + extra_view_info_linked_text->is_text_linked = true; + delegate.set_extra_view_info(std::move(extra_view_info_linked_text)); delegate.set_dismiss_button_text(DismissString()); ToolbarActionsBarBubbleMac* bubble = CreateAndShowBubble(&delegate); @@ -253,17 +258,35 @@ chrome::testing::NSRunLoopRunAllPending(); } + // Test with a null extra view. + { + TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), + ActionString()); + ToolbarActionsBarBubbleMac* bubble = CreateAndShowBubble(&delegate); + EXPECT_TRUE([bubble actionButton]); + EXPECT_FALSE([bubble iconView]); + EXPECT_FALSE([bubble label]); + EXPECT_FALSE([bubble link]); + EXPECT_FALSE([bubble dismissButton]); + EXPECT_FALSE([bubble itemList]); + + [bubble close]; + chrome::testing::NSRunLoopRunAllPending(); + } + // Test with an extra view of a (unlinked) text and icon and action button. { TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info; - extra_view_info.resource_id = gfx::VectorIconId::BUSINESS; - extra_view_info.text = + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info->resource_id = gfx::VectorIconId::BUSINESS; + extra_view_info->text = l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN); - extra_view_info.is_text_linked = false; - delegate.set_extra_view_info(extra_view_info); + extra_view_info->is_text_linked = false; + delegate.set_extra_view_info(std::move(extra_view_info)); ToolbarActionsBarBubbleMac* bubble = CreateAndShowBubble(&delegate); EXPECT_TRUE([bubble actionButton]); @@ -282,10 +305,12 @@ TestToolbarActionsBarBubbleDelegate delegate( HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info_linked_text; - extra_view_info_linked_text.text = LearnMoreString(); - extra_view_info_linked_text.is_text_linked = true; - delegate.set_extra_view_info(extra_view_info_linked_text); + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info_linked_text = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info_linked_text->text = LearnMoreString(); + extra_view_info_linked_text->is_text_linked = true; + delegate.set_extra_view_info(std::move(extra_view_info_linked_text)); delegate.set_dismiss_button_text(DismissString()); delegate.set_item_list_text(ItemListString());
diff --git a/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc index 4e2ea3d..69b1a442 100644 --- a/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc +++ b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc
@@ -32,7 +32,10 @@ } std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> GetExtraViewInfo() override { - return base::MakeUnique<ExtraViewInfo>(parent_->extra_view_info_); + if (parent_->info_) + return base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>( + *parent_->info_); + return nullptr; } std::string GetAnchorActionId() override { return std::string(); } void OnBubbleShown() override { @@ -57,8 +60,7 @@ heading_(heading), body_(body), action_(action), - close_on_deactivate_(true) { -} + close_on_deactivate_(true) {} TestToolbarActionsBarBubbleDelegate::~TestToolbarActionsBarBubbleDelegate() { // If the bubble didn't close, it means that it still owns the DelegateImpl,
diff --git a/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.h b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.h index 07d5f7b..463ec6f 100644 --- a/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.h +++ b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h" // A test delegate for a bubble to hang off the toolbar actions bar. @@ -33,10 +34,12 @@ void set_learn_more_button_text(const base::string16& learn_more) { learn_more_ = learn_more; - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info_linked_text; - extra_view_info_linked_text.text = learn_more; - extra_view_info_linked_text.is_text_linked = true; - set_extra_view_info(extra_view_info_linked_text); + if (!info_) { + info_ = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + } + info_->text = learn_more; + info_->is_text_linked = true; } void set_item_list_text(const base::string16& item_list) { item_list_ = item_list; @@ -45,10 +48,9 @@ close_on_deactivate_ = close_on_deactivate; } void set_extra_view_info( - const ToolbarActionsBarBubbleDelegate::ExtraViewInfo& extra_view_info) { - extra_view_info_ = extra_view_info; + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> info) { + info_ = std::move(info); } - const ToolbarActionsBarBubbleDelegate::CloseAction* close_action() const { return close_action_.get(); } @@ -75,7 +77,7 @@ bool close_on_deactivate_; // Information about the extra view to show, if any. - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info_; + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> info_; DISALLOW_COPY_AND_ASSIGN(TestToolbarActionsBarBubbleDelegate); };
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc index dac0eac..82ea9c09 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -142,12 +142,8 @@ property_util::SetIntProperty(window, ash::kShelfItemTypeKey, ash::TYPE_APP_PANEL); } else { - ash::AppType app_type = ash::AppType::CHROME_APP; - Profile* profile = - Profile::FromBrowserContext(app_window->browser_context()); - if (profile && chromeos::IsNoteTakingAppWindow(app_window, profile)) - app_type = ash::AppType::DEFAULT_NOTE_TAKING_APP; - window->SetProperty(aura::client::kAppType, static_cast<int>(app_type)); + window->SetProperty(aura::client::kAppType, + static_cast<int>(ash::AppType::CHROME_APP)); } }
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc index 33e1264..869bd7a 100644 --- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc +++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -171,11 +171,10 @@ class DragStartWaiter : public aura::client::DragDropClient { public: // Starts monitoring |web_contents| for a start of a drag-and-drop. - // While alive, prevents a real, OS-level drag-and-drop from starting - // for this particular |web_contents|. explicit DragStartWaiter(content::WebContents* web_contents) : web_contents_(web_contents), message_loop_runner_(new content::MessageLoopRunner), + suppress_passing_of_start_drag_further_(false), drag_started_(false) { DCHECK(web_contents_); @@ -193,27 +192,44 @@ aura::client::SetDragDropClient(root_window, old_client_); } - // Waits until we almost report a drag-and-drop start to the OS - // (notifying the OS will be prevented to help the test continue - // without entering a nested message loop). + // Waits until we almost report a drag-and-drop start to the OS. + // At that point + // 1) the callback from PostTaskWhenDragStarts will be posted. + // 2) the drag-start request will be forwarded to the OS + // (unless SuppressPassingStartDragFurther method was called). // - // Returns true if drag and drop has indeed started (and in this - // case populates |text|, |html| and other parameters with data - // that would have been passed to the OS). - void WaitUntilDragStartIsIntercepted( - std::string* text, - std::string* html, - int* operation, - gfx::Point* location_inside_web_contents) { + // Note that if SuppressPassingStartDragFurther was not called then + // WaitUntilDragStart can take a long time to return (it returns only after + // the OS decides that the drag-and-drop has ended). + // + // Before returning populates |text|, |html| and other parameters with data + // that would have been passed to the OS). If the caller is not interested in + // this data, then the corresponding argument can be null. + void WaitUntilDragStart(std::string* text, + std::string* html, + int* operation, + gfx::Point* location_inside_web_contents) { message_loop_runner_->Run(); // message_loop_runner_->Quit is only called from StartDragAndDrop. DCHECK(drag_started_); - *text = text_; - *html = html_; - *operation = operation_; - *location_inside_web_contents = location_inside_web_contents_; + if (text) + *text = text_; + if (html) + *html = html_; + if (operation) + *operation = operation_; + if (location_inside_web_contents) + *location_inside_web_contents = location_inside_web_contents_; + } + + void SuppressPassingStartDragFurther() { + suppress_passing_of_start_drag_further_ = true; + } + + void PostTaskWhenDragStarts(const base::Closure& callback) { + callback_to_run_inside_drag_and_drop_message_loop_ = callback; } // aura::client::DragDropClient overrides: @@ -249,12 +265,19 @@ operation_ = operation; } - // Forwarding to |old_client_| is undesirable, because test cannot control - // next steps after a nested drag-and-drop loop is entered at the OS level - // (as is the case in Windows, via DoDragDrop). Instead, in the test we - // kind of ignore renderer's request to start drag and drop and never - // forward this request to the OS-specific layers. - return 0; + if (!callback_to_run_inside_drag_and_drop_message_loop_.is_null()) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + std::move(callback_to_run_inside_drag_and_drop_message_loop_)); + callback_to_run_inside_drag_and_drop_message_loop_.Reset(); + } + + if (suppress_passing_of_start_drag_further_) + return 0; + + // Start a nested drag-and-drop loop (might not return for a long time). + return old_client_->StartDragAndDrop(data, root_window, source_window, + screen_location, operation, source); } void DragCancel() override { @@ -267,6 +290,8 @@ content::WebContents* web_contents_; scoped_refptr<content::MessageLoopRunner> message_loop_runner_; aura::client::DragDropClient* old_client_; + base::Closure callback_to_run_inside_drag_and_drop_message_loop_; + bool suppress_passing_of_start_drag_further_; // Data captured during the first intercepted StartDragAndDrop call. bool drag_started_; @@ -396,6 +421,10 @@ public: DragAndDropBrowserTest(){}; + struct DragImageBetweenFrames_TestState; + void DragImageBetweenFrames_Step2(DragImageBetweenFrames_TestState*); + void DragImageBetweenFrames_Step3(DragImageBetweenFrames_TestState*); + protected: void SetUpOnMainThread() override { host_resolver()->AddRule("*", "127.0.0.1"); @@ -468,6 +497,16 @@ return kMiddleOfLeftFrame + gfx::Vector2d(10, 10); } + bool SimulateMouseMoveToLeftFrame() { + AssertTestPageIsLoaded(); + return SimulateMouseMove(kMiddleOfLeftFrame); + } + + bool SimulateMouseMoveToRightFrame() { + AssertTestPageIsLoaded(); + return SimulateMouseMove(kMiddleOfRightFrame); + } + bool SimulateMouseUp() { return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::UP); @@ -488,6 +527,13 @@ } private: + // Constants with coordinates within content/test/data/drag_and_drop/page.html + // The precise frame center is at 200,200 and 400,200 coordinates, but slight + // differences between left and right frame hopefully make it easier to detect + // incorrect dom_drag_and_drop_event.clientX/Y values in test asserts. + const gfx::Point kMiddleOfLeftFrame = gfx::Point(155, 150); + const gfx::Point kMiddleOfRightFrame = gfx::Point(455, 250); + bool SimulateMouseDown() { return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::DOWN); @@ -569,13 +615,11 @@ std::unique_ptr<DragAndDropSimulator> drag_simulator_; - // Constants with coordinates within content/test/data/drag_and_drop/page.html - const gfx::Point kMiddleOfLeftFrame = gfx::Point(200, 200); - const gfx::Point kMiddleOfRightFrame = gfx::Point(400, 200); - DISALLOW_COPY_AND_ASSIGN(DragAndDropBrowserTest); }; +// Scenario: drag text from outside the browser and drop to the right frame. +// Test coverage: dragover, drop DOM events. IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropTextFromOutside) { std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com"; ASSERT_TRUE(NavigateToTestPage("a.com")); @@ -583,11 +627,11 @@ // Setup test expectations. DOMDragEventVerifier expected_dom_event_data; - expected_dom_event_data.set_expected_client_position("(100, 100)"); + expected_dom_event_data.set_expected_client_position("(155, 150)"); expected_dom_event_data.set_expected_drop_effect("none"); expected_dom_event_data.set_expected_effect_allowed("all"); expected_dom_event_data.set_expected_mime_types("text/plain"); - expected_dom_event_data.set_expected_page_position("(100, 100)"); + expected_dom_event_data.set_expected_page_position("(155, 150)"); // Drag text from outside the browser into/over the right frame. { @@ -610,23 +654,32 @@ } } +// Scenario: starting a drag in left frame +// Test coverage: dragstart DOM event, dragstart data passed to the OS. IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DragStartInFrame) { std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com"; ASSERT_TRUE(NavigateToTestPage("a.com")); ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html")); // Setup test expectations. - // (dragstart event handler in image_source.html is asking for "copy" only). DOMDragEventVerifier expected_dom_event_data; - expected_dom_event_data.set_expected_client_position("(100, 100)"); + expected_dom_event_data.set_expected_client_position("(55, 50)"); expected_dom_event_data.set_expected_drop_effect("none"); + // (dragstart event handler in image_source.html is asking for "copy" only). expected_dom_event_data.set_expected_effect_allowed("copy"); + expected_dom_event_data.set_expected_page_position("(55, 50)"); + + // TODO(lukasza): Figure out why the dragstart event + // - lists "Files" on the mime types list, + // - doesn't list "text/plain" on the mime types list. + // (i.e. why expectations below differ from expectations for dragenter, + // dragover, dragend and/or drop events in DragImageBetweenFrames test). expected_dom_event_data.set_expected_mime_types( "Files,text/html,text/uri-list"); - expected_dom_event_data.set_expected_page_position("(100, 100)"); // Start the drag in the left frame. DragStartWaiter drag_start_waiter(web_contents()); + drag_start_waiter.SuppressPassingStartDragFurther(); DOMDragEventWaiter dragstart_event_waiter("dragstart", left_frame()); EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame()); @@ -644,8 +697,8 @@ std::string html; int operation = 0; gfx::Point location_inside_web_contents; - drag_start_waiter.WaitUntilDragStartIsIntercepted( - &text, &html, &operation, &location_inside_web_contents); + drag_start_waiter.WaitUntilDragStart(&text, &html, &operation, + &location_inside_web_contents); EXPECT_EQ(embedded_test_server()->GetURL(frame_site, "/image_decoding/droids.jpg"), text); @@ -662,6 +715,173 @@ SimulateMouseUp(); } +// There is no known way to execute test-controlled tasks during +// a drag-and-drop loop run by Windows OS. +#if defined(OS_WIN) +#define MAYBE_DragImageBetweenFrames DISABLED_DragImageBetweenFrames +#else +#define MAYBE_DragImageBetweenFrames DragImageBetweenFrames +#endif + +// Data that needs to be shared across multiple test steps below +// (i.e. across DragImageBetweenFrames_Step2 and DragImageBetweenFrames_Step3). +struct DragAndDropBrowserTest::DragImageBetweenFrames_TestState { + DOMDragEventVerifier expected_dom_event_data; + std::unique_ptr<DOMDragEventWaiter> dragstart_event_waiter; + std::unique_ptr<DOMDragEventWaiter> drop_event_waiter; + std::unique_ptr<DOMDragEventWaiter> dragend_event_waiter; +}; + +// Scenario: drag an image from the left into the right frame. +// Test coverage: dragleave, dragenter, dragover, dragend, drop DOM events. +IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, MAYBE_DragImageBetweenFrames) { + // Note that drag and drop will not expose data across cross-site frames on + // the same page - this is why the same |frame_site| is used below both for + // the left and the right frame. See also https://crbug.com/59081. + std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com"; + ASSERT_TRUE(NavigateToTestPage("a.com")); + ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html")); + ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html")); + + // Setup test expectations. + DragAndDropBrowserTest::DragImageBetweenFrames_TestState state; + state.expected_dom_event_data.set_expected_client_position("(55, 50)"); + state.expected_dom_event_data.set_expected_drop_effect("none"); + // (dragstart event handler in image_source.html is asking for "copy" only). + state.expected_dom_event_data.set_expected_effect_allowed("copy"); + state.expected_dom_event_data.set_expected_mime_types( + "text/html,text/plain,text/uri-list"); + state.expected_dom_event_data.set_expected_page_position("(55, 50)"); + + // Start the drag in the left frame. + DragStartWaiter drag_start_waiter(web_contents()); + drag_start_waiter.PostTaskWhenDragStarts( + base::Bind(&DragAndDropBrowserTest::DragImageBetweenFrames_Step2, + base::Unretained(this), base::Unretained(&state))); + state.dragstart_event_waiter.reset( + new DOMDragEventWaiter("dragstart", left_frame())); + EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame()); + + // The next step of the test (DragImageBetweenFrames_Step2) runs inside the + // nested drag-and-drop message loop - the call below won't return until the + // drag-and-drop has already ended. + drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr); + + DragImageBetweenFrames_Step3(&state); +} + +void DragAndDropBrowserTest::DragImageBetweenFrames_Step2( + DragAndDropBrowserTest::DragImageBetweenFrames_TestState* state) { + // Verify dragstart DOM event. + { + std::string dragstart_event; + EXPECT_TRUE(state->dragstart_event_waiter->WaitForNextMatchingEvent( + &dragstart_event)); + state->dragstart_event_waiter.reset(); + } + + // While dragging, move mouse within the left frame. + // Without this extra mouse move we wouldn't get a dragleave event later on. + ASSERT_TRUE(SimulateMouseMoveToLeftFrame()); + + // While dragging, move mouse from the left into the right frame. + // This should trigger dragleave and dragenter events. + { + DOMDragEventWaiter dragleave_event_waiter("dragleave", left_frame()); + DOMDragEventWaiter dragenter_event_waiter("dragenter", right_frame()); + ASSERT_TRUE(SimulateMouseMoveToRightFrame()); + + { // Verify dragleave DOM event. + std::string dragleave_event; + + // TODO(paulmeyer): https://crbug.com/669695: Need to unify coordinates + // passed to dragend when OOPIFs are present or not. + state->expected_dom_event_data.set_expected_client_position( + "<no expectation>"); + state->expected_dom_event_data.set_expected_page_position( + "<no expectation>"); + + EXPECT_TRUE( + dragleave_event_waiter.WaitForNextMatchingEvent(&dragleave_event)); + EXPECT_THAT(dragleave_event, state->expected_dom_event_data.Matches()); + } + + { // Verify dragenter DOM event. + std::string dragenter_event; + + // Update expected event coordinates after SimulateMouseMoveToRightFrame + // (these coordinates are relative to the right frame). + state->expected_dom_event_data.set_expected_client_position("(155, 150)"); + state->expected_dom_event_data.set_expected_page_position("(155, 150)"); + + EXPECT_TRUE( + dragenter_event_waiter.WaitForNextMatchingEvent(&dragenter_event)); + EXPECT_THAT(dragenter_event, state->expected_dom_event_data.Matches()); + } + + // Note that ash (unlike aura/x11) will not fire dragover event in response + // to the same mouse event that trigerred a dragenter. Because of that, we + // postpone dragover testing until the next test step below. See + // implementation of ash::DragDropController::DragUpdate for details. + } + + // Move the mouse twice in the right frame. The 1st move will ensure that + // allowed operations communicated by the renderer will be stored in + // WebContentsViewAura::current_drag_op_. The 2nd move will ensure that this + // gets be copied into DesktopDragDropClientAuraX11::negotiated_operation_. + for (int i = 0; i < 2; i++) { + DOMDragEventWaiter dragover_event_waiter("dragover", right_frame()); + ASSERT_TRUE(SimulateMouseMoveToRightFrame()); + + { // Verify dragover DOM event. + std::string dragover_event; + EXPECT_TRUE( + dragover_event_waiter.WaitForNextMatchingEvent(&dragover_event)); + EXPECT_THAT(dragover_event, state->expected_dom_event_data.Matches()); + } + } + + // Release the mouse button to end the drag. + state->drop_event_waiter.reset(new DOMDragEventWaiter("drop", right_frame())); + state->dragend_event_waiter.reset( + new DOMDragEventWaiter("dragend", left_frame())); + SimulateMouseUp(); + // The test will continue in DragImageBetweenFrames_Step3. +} + +void DragAndDropBrowserTest::DragImageBetweenFrames_Step3( + DragAndDropBrowserTest::DragImageBetweenFrames_TestState* state) { + // Verify drop DOM event. + { + std::string drop_event; + EXPECT_TRUE( + state->drop_event_waiter->WaitForNextMatchingEvent(&drop_event)); + state->drop_event_waiter.reset(); + EXPECT_THAT(drop_event, state->expected_dom_event_data.Matches()); + } + + // Verify dragend DOM event. + { + // TODO(lukasza): Figure out why the drop event sees different values of + // DataTransfer.dropEffect and DataTransfer.types properties. + state->expected_dom_event_data.set_expected_drop_effect("copy"); + state->expected_dom_event_data.set_expected_mime_types(""); + + // TODO(paulmeyer): https://crbug.com/669695: Need to unify coordinates + // passed to dragend when OOPIFs are present or not. + state->expected_dom_event_data.set_expected_client_position( + "<no expectation>"); + state->expected_dom_event_data.set_expected_page_position( + "<no expectation>"); + + std::string dragend_event; + EXPECT_TRUE( + state->dragend_event_waiter->WaitForNextMatchingEvent(&dragend_event)); + state->dragend_event_waiter.reset(); + EXPECT_THAT(dragend_event, state->expected_dom_event_data.Matches()); + } +} + INSTANTIATE_TEST_CASE_P( SameSiteSubframe, DragAndDropBrowserTest, ::testing::Values(false));
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc index 64378065..de76808 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc
@@ -122,8 +122,10 @@ TEST_F(ToolbarActionsBarBubbleViewsTest, TestBubbleLayoutNoButtons) { TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info; - delegate.set_extra_view_info(extra_view_info); + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + delegate.set_extra_view_info(std::move(extra_view_info)); delegate.set_dismiss_button_text(base::string16()); delegate.set_action_button_text(base::string16()); ShowBubble(&delegate); @@ -161,12 +163,12 @@ TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), ActionString()); delegate.set_dismiss_button_text(DismissString()); - - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info_linked_text; - - extra_view_info_linked_text.text = LearnMoreString(); - extra_view_info_linked_text.is_text_linked = true; - delegate.set_extra_view_info(extra_view_info_linked_text); + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info_linked_text = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info_linked_text->text = LearnMoreString(); + extra_view_info_linked_text->is_text_linked = true; + delegate.set_extra_view_info(std::move(extra_view_info_linked_text)); ShowBubble(&delegate); @@ -303,13 +305,23 @@ CloseBubble(); } +TEST_F(ToolbarActionsBarBubbleViewsTest, TestNullExtraView) { + TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), + ActionString()); + ShowBubble(&delegate); + std::unique_ptr<views::View> extra_view(TestCreateExtraView()); + ASSERT_FALSE(extra_view); + CloseBubble(); +} + TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewIconOnly) { TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info; - - extra_view_info.resource_id = gfx::VectorIconId::BUSINESS; - delegate.set_extra_view_info(extra_view_info); + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info->resource_id = gfx::VectorIconId::BUSINESS; + delegate.set_extra_view_info(std::move(extra_view_info)); ShowBubble(&delegate); std::unique_ptr<views::View> extra_view(TestCreateExtraView()); ASSERT_TRUE(extra_view); @@ -324,12 +336,13 @@ TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewLinkedTextOnly) { TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info_linked_text; - - extra_view_info_linked_text.text = + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info_linked_text = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info_linked_text->text = l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN); - extra_view_info_linked_text.is_text_linked = true; - delegate.set_extra_view_info(extra_view_info_linked_text); + extra_view_info_linked_text->is_text_linked = true; + delegate.set_extra_view_info(std::move(extra_view_info_linked_text)); ShowBubble(&delegate); @@ -344,12 +357,13 @@ TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewLabelTextOnly) { TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info; - - extra_view_info.text = + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info->text = l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN); - extra_view_info.is_text_linked = false; - delegate.set_extra_view_info(extra_view_info); + extra_view_info->is_text_linked = false; + delegate.set_extra_view_info(std::move(extra_view_info)); ShowBubble(&delegate); @@ -364,12 +378,14 @@ TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewImageAndText) { TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(), ActionString()); - ToolbarActionsBarBubbleDelegate::ExtraViewInfo extra_view_info; - extra_view_info.resource_id = gfx::VectorIconId::BUSINESS; - extra_view_info.text = + std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> + extra_view_info = + base::MakeUnique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>(); + extra_view_info->resource_id = gfx::VectorIconId::BUSINESS; + extra_view_info->text = l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN); - extra_view_info.is_text_linked = false; - delegate.set_extra_view_info(extra_view_info); + extra_view_info->is_text_linked = false; + delegate.set_extra_view_info(std::move(extra_view_info)); ShowBubble(&delegate);
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc index 9134d83..c0087b2 100644 --- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -157,13 +157,6 @@ : PeopleHandler(profile) { set_web_ui(web_ui); } - ~TestingPeopleHandler() override { - // TODO(tommycli): PeopleHandler needs this call to destruct properly in the - // unit testing context. See the destructor to PeopleHandler. This is hacky. - set_web_ui(nullptr); - } - - void FocusUI() override {} using PeopleHandler::is_configuring_sync;
diff --git a/chrome/installer/linux/common/apt.include b/chrome/installer/linux/common/apt.include index 76c65a8..14f196f 100644 --- a/chrome/installer/linux/common/apt.include +++ b/chrome/installer/linux/common/apt.include
@@ -6,14 +6,6 @@ SOURCES_PREAMBLE="### THIS FILE IS AUTOMATICALLY CONFIGURED ### # You may comment out this entry, but any other modifications may be lost.\n" -# Parse apt configuration and return requested variable value. -apt_config_val() { - APTVAR="$1" - if [ -x "$APT_CONFIG" ]; then - "$APT_CONFIG" dump | sed -e "/^$APTVAR /"'!d' -e "s/^$APTVAR \"\(.*\)\".*/\1/" - fi -} - # Install the repository/package signing keys, if they aren't already. # (see also: https://www.google.com/linuxrepositories/) install_key() { @@ -141,14 +133,7 @@ # Set variables for the locations of the apt sources lists. find_apt_sources() { - # NB: These variables only *sometimes* include a trailing slash. (In - # particular, in Ubuntu 16.10 / Debian 9, the default value *stopped* - # including the trailing slash.) We have to join them with slashes, even - # though that sometimes gives a double slash. - APTDIR=$(apt_config_val Dir) - APTETC=$(apt_config_val 'Dir::Etc') - APT_SOURCES="$APTDIR/$APTETC/$(apt_config_val 'Dir::Etc::sourcelist')" - APT_SOURCESDIR="$APTDIR/$APTETC/$(apt_config_val 'Dir::Etc::sourceparts')" + eval $("$APT_CONFIG" shell APT_SOURCESDIR 'Dir::Etc::sourceparts/d') } # Update the Google repository if it's not set correctly.
diff --git a/chrome/test/data/drag_and_drop/drop_target.html b/chrome/test/data/drag_and_drop/drop_target.html index 4f1bbcce..b77ace2c 100644 --- a/chrome/test/data/drag_and_drop/drop_target.html +++ b/chrome/test/data/drag_and_drop/drop_target.html
@@ -38,7 +38,9 @@ </script> </head> <body> - <div ondragover="dragover_handler(event);" ondrop="drop_handler(event);"> - <p>Use this frame as a target of a drag-n-drop</p> + <div ondragover="dragover_handler(event);" + ondrop="drop_handler(event);" + ondragenter="window.reportDragAndDropEvent(event);" + ><p>Use this frame as a target of a drag-n-drop</p> </div> </body>
diff --git a/chrome/test/data/drag_and_drop/event_monitoring.js b/chrome/test/data/drag_and_drop/event_monitoring.js index badd6ad9..8447cdd 100644 --- a/chrome/test/data/drag_and_drop/event_monitoring.js +++ b/chrome/test/data/drag_and_drop/event_monitoring.js
@@ -8,11 +8,12 @@ try { return f(); } catch(err) { - return "exception: " + err.message; + return "Got exception: " + err.message; } } - console.log("got event: " + ev.type); + var msg = "Got a " + ev.type + " event from the " + window.name + " frame."; + console.log(msg); if (window.domAutomationController) { window.domAutomationController.setAutomationId(0);
diff --git a/chrome/test/data/drag_and_drop/image_source.html b/chrome/test/data/drag_and_drop/image_source.html index e2a68343..4c4d05c5 100644 --- a/chrome/test/data/drag_and_drop/image_source.html +++ b/chrome/test/data/drag_and_drop/image_source.html
@@ -22,14 +22,11 @@ ev.dataTransfer.effectAllowed = "copy"; window.reportDragAndDropEvent(ev); } - - function dragend_handler(ev) { - window.reportDragAndDropEvent(ev); - } </script> </head> <body> <img ondragstart="dragstart_handler(event);" - ondragend="dragend_handler(event);" + ondragend="window.reportDragAndDropEvent(event);" + ondragleave="window.reportDragAndDropEvent(event);" src="/image_decoding/droids.jpg"> </body>
diff --git a/chrome/test/data/drag_and_drop/page.html b/chrome/test/data/drag_and_drop/page.html index 2e158b7c..719eb0c 100644 --- a/chrome/test/data/drag_and_drop/page.html +++ b/chrome/test/data/drag_and_drop/page.html
@@ -19,6 +19,9 @@ #left { left: 100px; background: green; } #right { left: 300px; background: cyan; } </style> + <script> + window.name = "main"; + </script> </head> <body> <iframe id="left" name="left" srcdoc="<body>blank left frame</body>"></iframe>
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn index 99aef6c0..c09d970 100644 --- a/components/arc/BUILD.gn +++ b/components/arc/BUILD.gn
@@ -56,9 +56,6 @@ "kiosk/arc_kiosk_bridge.h", "metrics/arc_metrics_service.cc", "metrics/arc_metrics_service.h", - "metrics/oom_kills_histogram.h", - "metrics/oom_kills_monitor.cc", - "metrics/oom_kills_monitor.h", "net/arc_net_host_impl.cc", "net/arc_net_host_impl.h", "obb_mounter/arc_obb_mounter_bridge.cc",
diff --git a/components/arc/common/app.mojom b/components/arc/common/app.mojom index 7087e13..2cad0d4 100644 --- a/components/arc/common/app.mojom +++ b/components/arc/common/app.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 15 +// Next MinVersion: 16 module arc.mojom; @@ -107,11 +107,14 @@ // app. [MinVersion=1] OnPackageRemoved@3(string package_name); - // Sends information about newly created task. + // Sends information about newly created task |package_name| and |activity| + // specifies launch activity and |intent| is initial intent used to start + // new task. [MinVersion=4] OnTaskCreated@4(int32 task_id@0, string package_name@1, string activity@2, - [MinVersion=13] string? name@3); + [MinVersion=13] string? name@3, + [MinVersion=15] string? intent@4); // Notifies that task has been destroyed. [MinVersion=4] OnTaskDestroyed@5(int32 task_id);
diff --git a/components/arc/metrics/arc_metrics_service.cc b/components/arc/metrics/arc_metrics_service.cc index 9914eae..a7f663a 100644 --- a/components/arc/metrics/arc_metrics_service.cc +++ b/components/arc/metrics/arc_metrics_service.cc
@@ -29,7 +29,6 @@ : ArcService(bridge_service), binding_(this), process_observer_(this), - oom_kills_monitor_handle_(OomKillsMonitor::StartMonitoring()), weak_ptr_factory_(this) { arc_bridge_service()->metrics()->AddObserver(this); arc_bridge_service()->process()->AddObserver(&process_observer_);
diff --git a/components/arc/metrics/arc_metrics_service.h b/components/arc/metrics/arc_metrics_service.h index c3d256b4..7ad1a0be3 100644 --- a/components/arc/metrics/arc_metrics_service.h +++ b/components/arc/metrics/arc_metrics_service.h
@@ -15,7 +15,6 @@ #include "components/arc/common/metrics.mojom.h" #include "components/arc/common/process.mojom.h" #include "components/arc/instance_holder.h" -#include "components/arc/metrics/oom_kills_monitor.h" #include "mojo/public/cpp/bindings/binding.h" namespace arc { @@ -73,8 +72,6 @@ base::ThreadChecker thread_checker_; base::RepeatingTimer timer_; - OomKillsMonitor::Handle oom_kills_monitor_handle_; - base::TimeTicks arc_start_time_; // Always keep this the last member of this class to make sure it's the
diff --git a/components/arc/metrics/oom_kills_histogram.h b/components/arc/metrics/oom_kills_histogram.h deleted file mode 100644 index 2a9bf56..0000000 --- a/components/arc/metrics/oom_kills_histogram.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2016 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 COMPONENTS_ARC_METRICS_OOM_KILLS_HISTOGRAM_H_ -#define COMPONENTS_ARC_METRICS_OOM_KILLS_HISTOGRAM_H_ - -#include "base/metrics/histogram.h" - -namespace arc { - -const int kMaxOomMemoryKillTimeDeltaSecs = 30; - -} // namespace arc - -// Use this macro to report elapsed time since last OOM kill event. -// Must be a macro as the underlying HISTOGRAM macro creates static variables. -#define UMA_HISTOGRAM_OOM_KILL_TIME_INTERVAL(name, sample) \ - UMA_HISTOGRAM_CUSTOM_TIMES( \ - name, sample, base::TimeDelta::FromMilliseconds(1), \ - base::TimeDelta::FromSeconds(::arc::kMaxOomMemoryKillTimeDeltaSecs), 50) - -#endif // COMPONENTS_ARC_METRICS_OOM_KILLS_HISTOGRAM_H_
diff --git a/components/arc/metrics/oom_kills_monitor.cc b/components/arc/metrics/oom_kills_monitor.cc deleted file mode 100644 index 719b778..0000000 --- a/components/arc/metrics/oom_kills_monitor.cc +++ /dev/null
@@ -1,206 +0,0 @@ -// Copyright 2016 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 "components/arc/metrics/oom_kills_monitor.h" - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> - -#include <vector> - -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/posix/safe_strerror.h" -#include "base/sequenced_task_runner.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_split.h" -#include "base/time/time.h" -#include "components/arc/metrics/oom_kills_histogram.h" -#include "third_party/re2/src/re2/re2.h" -#include "third_party/re2/src/re2/stringpiece.h" - -namespace arc { - -using base::StringPiece; - -using base::SequencedWorkerPool; -using base::TimeDelta; - -namespace { - -int64_t GetTimestamp(const StringPiece& line) { - std::vector<StringPiece> fields = base::SplitStringPiece( - line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - - int64_t timestamp = -1; - // Timestamp is the third field in a line of /dev/kmsg. - if (fields.size() < 3 || !base::StringToInt64(fields[2], ×tamp)) - return -1; - return timestamp; -} - -bool GetTimeDelta( - const StringPiece& line, int64_t* last, TimeDelta* time_delta) { - int64_t now = GetTimestamp(line); - if (now < 0) - return false; - - // Sets to |kMaxOomMemoryKillTimeSecs| for the first kill event. - if (*last < 0) - *time_delta = TimeDelta::FromSeconds(kMaxOomMemoryKillTimeDeltaSecs); - else - *time_delta = TimeDelta::FromMicroseconds(now - *last); - - *last = now; - - return true; -} - -void LogOOMKill(const StringPiece& line) { - static int64_t last_timestamp = -1; - static int oom_kills = 0; - - // Sample log line: - // 3,1362,97646497541,-;Out of memory: Kill process 29582 (android.vending) - // score 961 or sacrifice child. - int oom_badness; - TimeDelta time_delta; - if (RE2::PartialMatch(re2::StringPiece(line.data(), line.size()), - "Out of memory: Kill process .* score (\\d+)", - &oom_badness)) { - ++oom_kills; - // Report the cumulative count of killed process in one login session. - // For example if there are 3 processes killed, it would report 1 for the - // first kill, 2 for the second kill, then 3 for the final kill. - // It doesn't report a final count at the end of a user session because - // the code runs in a dedicated thread and never ends until browser shutdown - // (or logout on Chrome OS). And on browser shutdown the thread may be - // terminated brutally so there's no chance to execute a "final" block. - // More specifically, code outside the main loop of OomKillsMonitor::Run() - // are not guaranteed to be executed. - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Arc.OOMKills.Count", oom_kills, 1, 1000, 1001); - - // In practice most process has oom_badness < 1000, but - // strictly speaking the number could be [1, 2000]. What it really - // means is the baseline, proportion of memory used (normalized to - // [0, 1000]), plus an adjustment score oom_score_adj [-1000, 1000], - // truncated to 1 if negative (0 means never kill). - // Ref: https://lwn.net/Articles/396552/ - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Arc.OOMKills.Score", oom_badness, 1, 2000, 2001); - - if (GetTimeDelta(line, &last_timestamp, &time_delta)) { - UMA_HISTOGRAM_OOM_KILL_TIME_INTERVAL( - "Arc.OOMKills.TimeDelta", time_delta); - } - } -} - -void LogLowMemoryKill(const StringPiece& line) { - static int64_t last_timestamp = -1; - static int low_memory_kills = 0; - - int freed_size; - TimeDelta time_delta; - // Sample log line: - // 6,2302,533604004,-;lowmemorykiller: Killing 'externalstorage' (21742), - // adj 1000,\x0a to free 27320kB on behalf of 'kswapd0' (47) because\x0a - // cache 181920kB is below limit 184320kB for oom_score_adj 1000\x0a - // Free memory is 1228kB above reserved - if (RE2::PartialMatch(re2::StringPiece(line.data(), line.size()), - "lowmemorykiller: .* to free (\\d+)kB", - &freed_size)) { - // Report the count for each lowmemorykill event. See comments in - // LogOOMKill(). - ++low_memory_kills; - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Arc.LowMemoryKiller.Count", low_memory_kills, 1, 1000, 1001); - - UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize", freed_size); - - if (GetTimeDelta(line, &last_timestamp, &time_delta)) { - UMA_HISTOGRAM_OOM_KILL_TIME_INTERVAL( - "Arc.LowMemoryKiller.TimeDelta", time_delta); - } - } -} - -} // namespace - -OomKillsMonitor::Handle::Handle(OomKillsMonitor* outer) : outer_(outer) { - DCHECK(outer_); -} - -OomKillsMonitor::Handle::~Handle() { - outer_->is_shutting_down_.Set(); -} - -OomKillsMonitor::OomKillsMonitor() { - base::SimpleThread::Options non_joinable_options; - non_joinable_options.joinable = false; - non_joinable_worker_thread_ = base::MakeUnique<base::DelegateSimpleThread>( - this, "oom_kills_monitor", non_joinable_options); - non_joinable_worker_thread_->Start(); -} - -OomKillsMonitor::~OomKillsMonitor() { - // The instance has to be leaked on shutdown as it is referred to by a - // non-joinable thread but ~OomKillsMonitor() can't be explicitly deleted as - // it overrides ~SimpleThread(), it should nevertheless never be invoked. - NOTREACHED(); -} - -// static -OomKillsMonitor::Handle OomKillsMonitor::StartMonitoring() { -#if DCHECK_IS_ON() - static volatile bool monitoring_active = false; - DCHECK(!monitoring_active); - monitoring_active = true; -#endif - - // Instantiate the OomKillsMonitor and its underlying thread. The - // OomKillsMonitor itself has to be leaked on shutdown per having a - // non-joinable thread associated to its state. The OomKillsMonitor::Handle - // will notify the OomKillsMonitor when it is destroyed so that the underlying - // thread can at a minimum not do extra work during shutdown. - OomKillsMonitor* instance = new OomKillsMonitor; - ANNOTATE_LEAKING_OBJECT_PTR(instance); - return Handle(instance); -} - -void OomKillsMonitor::Run() { - base::ScopedFILE kmsg_handle( - base::OpenFile(base::FilePath("/dev/kmsg"), "r")); - if (!kmsg_handle) { - LOG(WARNING) << "Open /dev/kmsg failed: " << base::safe_strerror(errno); - return; - } - // Skip kernel messages prior to the instantiation of this object to avoid - // double reporting. - fseek(kmsg_handle.get(), 0, SEEK_END); - - static const int kMaxBufSize = 512; - char buf[kMaxBufSize]; - - while (fgets(buf, kMaxBufSize, kmsg_handle.get())) { - if (is_shutting_down_.IsSet()) { - DVLOG(1) << "Chrome is shutting down, exit now."; - break; - } - const StringPiece buf_string(buf); - LogOOMKill(buf_string); - LogLowMemoryKill(buf_string); - } -} - -} // namespace arc
diff --git a/components/arc/metrics/oom_kills_monitor.h b/components/arc/metrics/oom_kills_monitor.h deleted file mode 100644 index 63e249e..0000000 --- a/components/arc/metrics/oom_kills_monitor.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2016 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 COMPONENTS_ARC_METRICS_OOM_KILLS_MONITOR_H_ -#define COMPONENTS_ARC_METRICS_OOM_KILLS_MONITOR_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/atomic_flag.h" -#include "base/threading/simple_thread.h" - -namespace arc { - -// Traces kernel OOM kill events and lowmemorykiller (if enabled) events. -// -// OomKillsMonitor listens to kernel messages for both OOM kills and -// lowmemorykiller kills, then reports to UMA. It uses a non-joinable thread -// in order to avoid blocking shutdown. -// -// Note: There should be only one OomKillsMonitor instance globally at any given -// time, otherwise UMA would receive duplicate events. -class OomKillsMonitor : public base::DelegateSimpleThread::Delegate { - public: - // A handle representing the OomKillsMonitor's lifetime (the monitor itself - // can't be destroyed per being a non-joinable Thread). - class Handle { - public: - // Constructs a handle that will flag |outer| as shutting down on - // destruction. - explicit Handle(OomKillsMonitor* outer); - - ~Handle(); - - private: - OomKillsMonitor* const outer_; - }; - - // Instantiates the OomKillsMonitor instance and starts it. This must only - // be invoked once per process. - static Handle StartMonitoring(); - - private: - OomKillsMonitor(); - ~OomKillsMonitor() override; - - // Overridden from base::DelegateSimpleThread::Delegate: - void Run() override; - - // A flag set when OomKillsMonitor is shutdown so that its thread can poll - // it and attempt to wind down from that point (to avoid unnecessary work, not - // because it blocks shutdown). - base::AtomicFlag is_shutting_down_; - - // The underlying worker thread which is non-joinable to avoid blocking - // shutdown. - std::unique_ptr<base::DelegateSimpleThread> non_joinable_worker_thread_; - - DISALLOW_COPY_AND_ASSIGN(OomKillsMonitor); -}; - -} // namespace arc - -#endif // COMPONENTS_ARC_METRICS_OOM_KILLS_MONITOR_H_
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc index 6e9cdec..7ae00a63 100644 --- a/components/arc/test/fake_app_instance.cc +++ b/components/arc/test/fake_app_instance.cc
@@ -93,8 +93,13 @@ } void FakeAppInstance::SendTaskCreated(int32_t taskId, - const mojom::AppInfo& app) { - app_host_->OnTaskCreated(taskId, app.package_name, app.activity, app.name); + const mojom::AppInfo& app, + const std::string& intent) { + app_host_->OnTaskCreated(taskId, + app.package_name, + app.activity, + app.name, + intent); } void FakeAppInstance::SendTaskDestroyed(int32_t taskId) {
diff --git a/components/arc/test/fake_app_instance.h b/components/arc/test/fake_app_instance.h index c487676..eeaac8d 100644 --- a/components/arc/test/fake_app_instance.h +++ b/components/arc/test/fake_app_instance.h
@@ -118,7 +118,9 @@ void SendAppAdded(const mojom::AppInfo& app); void SendPackageAppListRefreshed(const std::string& package_name, const std::vector<mojom::AppInfo>& apps); - void SendTaskCreated(int32_t taskId, const mojom::AppInfo& app); + void SendTaskCreated(int32_t taskId, + const mojom::AppInfo& app, + const std::string& intent); void SendTaskDestroyed(int32_t taskId); bool GenerateAndSendIcon(const mojom::AppInfo& app, mojom::ScaleFactor scale_factor,
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index 3ba8227..725024e 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -270,6 +270,7 @@ java_files = [ "api/src/org/chromium/net/BidirectionalStream.java", "api/src/org/chromium/net/CronetEngine.java", + "api/src/org/chromium/net/CallbackException.java", "api/src/org/chromium/net/CronetException.java", "api/src/org/chromium/net/ICronetEngineBuilder.java", "api/src/org/chromium/net/ImplLoader.java", @@ -277,6 +278,7 @@ "api/src/org/chromium/net/ExperimentalCronetEngine.java", "api/src/org/chromium/net/ExperimentalUrlRequest.java", "api/src/org/chromium/net/InlineExecutionProhibitedException.java", + "api/src/org/chromium/net/NetworkException.java", "api/src/org/chromium/net/NetworkQualityRttListener.java", "api/src/org/chromium/net/NetworkQualityThroughputListener.java", "api/src/org/chromium/net/QuicException.java", @@ -310,9 +312,13 @@ # by all Cronet engine implementations. android_library("cronet_impl_common_java") { java_files = [ + "java/src/org/chromium/net/impl/CallbackExceptionImpl.java", + "java/src/org/chromium/net/impl/CronetExceptionImpl.java", "java/src/org/chromium/net/impl/CronetEngineBase.java", "java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java", + "java/src/org/chromium/net/impl/NetworkExceptionImpl.java", "java/src/org/chromium/net/impl/Preconditions.java", + "java/src/org/chromium/net/impl/QuicExceptionImpl.java", "java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java", "java/src/org/chromium/net/impl/UrlRequestBase.java", "java/src/org/chromium/net/impl/UrlRequestBuilderImpl.java",
diff --git a/components/cronet/android/api/src/org/chromium/net/CallbackException.java b/components/cronet/android/api/src/org/chromium/net/CallbackException.java new file mode 100644 index 0000000..0e1fa61e --- /dev/null +++ b/components/cronet/android/api/src/org/chromium/net/CallbackException.java
@@ -0,0 +1,24 @@ +// Copyright 2016 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. + +package org.chromium.net; + +/** + * Exception passed to {@link UrlRequest.Callback#onFailed UrlRequest.Callback.onFailed()} when + * {@link UrlRequest.Callback} or {@link UploadDataProvider} method throws an exception. In this + * case {@link java.io.IOException#getCause getCause()} can be used to find the thrown + * exception. + */ +public abstract class CallbackException extends CronetException { + /** + * Constructs an exception that wraps {@code cause} thrown by a {@link UrlRequest.Callback}. + * + * @param message explanation of failure. + * @param cause exception thrown by {@link UrlRequest.Callback} that's being wrapped. It is + * saved for later retrieval by the {@link java.io.IOException#getCause getCause()}. + */ + protected CallbackException(String message, Throwable cause) { + super(message, cause); + } +}
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetException.java b/components/cronet/android/api/src/org/chromium/net/CronetException.java index 8eec778..d21a424 100644 --- a/components/cronet/android/api/src/org/chromium/net/CronetException.java +++ b/components/cronet/android/api/src/org/chromium/net/CronetException.java
@@ -4,22 +4,21 @@ package org.chromium.net; -/** - * Exception reported from UrlRequest or BidirectionalStream. - */ -// TODO(mef): Will replace UrlRequestException soon. -public class CronetException extends UrlRequestException { - /** - * @hide only used by internal implementation. - */ - public CronetException(String message, Throwable cause) { - super(message, cause); - } +import java.io.IOException; +/** + * Base exception passed to {@link UrlRequest.Callback#onFailed UrlRequest.Callback.onFailed()}. + */ +public abstract class CronetException extends IOException { /** - * @hide only used by internal implementation. + * Constructs an exception that is caused by {@code cause}. + * + * @param message explanation of failure. + * @param cause the cause (which is saved for later retrieval by the {@link + * java.io.IOException#getCause getCause()} method). A null value is permitted, and + * indicates that the cause is nonexistent or unknown. */ - public CronetException(String message, int errorCode, int cronetInternalErrorCode) { - super(message, errorCode, cronetInternalErrorCode); + protected CronetException(String message, Throwable cause) { + super(message, cause); } }
diff --git a/components/cronet/android/api/src/org/chromium/net/NetworkException.java b/components/cronet/android/api/src/org/chromium/net/NetworkException.java new file mode 100644 index 0000000..7458f0fd --- /dev/null +++ b/components/cronet/android/api/src/org/chromium/net/NetworkException.java
@@ -0,0 +1,108 @@ +// Copyright 2016 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. + +package org.chromium.net; + +/** + * Exception passed to {@link UrlRequest.Callback#onFailed UrlRequest.Callback.onFailed()} when + * Cronet fails to process a network request. In this case {@link #getErrorCode} and + * {@link #getCronetInternalErrorCode} can be used to get more information about the specific + * type of failure. If {@link #getErrorCode} returns {@link #ERROR_QUIC_PROTOCOL_FAILED}, + * this exception can be cast to a {@link QuicException} which can provide further details. + */ +public abstract class NetworkException extends CronetException { + /** + * Error code indicating the host being sent the request could not be resolved to an IP address. + */ + public static final int ERROR_HOSTNAME_NOT_RESOLVED = 1; + /** + * Error code indicating the device was not connected to any network. + */ + public static final int ERROR_INTERNET_DISCONNECTED = 2; + /** + * Error code indicating that as the request was processed the network configuration changed. + */ + public static final int ERROR_NETWORK_CHANGED = 3; + /** + * Error code indicating a timeout expired. Timeouts expiring while attempting to connect will + * be reported as the more specific {@link #ERROR_CONNECTION_TIMED_OUT}. + */ + public static final int ERROR_TIMED_OUT = 4; + /** + * Error code indicating the connection was closed unexpectedly. + */ + public static final int ERROR_CONNECTION_CLOSED = 5; + /** + * Error code indicating the connection attempt timed out. + */ + public static final int ERROR_CONNECTION_TIMED_OUT = 6; + /** + * Error code indicating the connection attempt was refused. + */ + public static final int ERROR_CONNECTION_REFUSED = 7; + /** + * Error code indicating the connection was unexpectedly reset. + */ + public static final int ERROR_CONNECTION_RESET = 8; + /** + * Error code indicating the IP address being contacted is unreachable, meaning there is no + * route to the specified host or network. + */ + public static final int ERROR_ADDRESS_UNREACHABLE = 9; + /** + * Error code indicating an error related to the <a href="https://www.chromium.org/quic"> + * QUIC</a> protocol. When {@link #getErrorCode} returns this code, this exception can be cast + * to {@link QuicException} for more information. + */ + public static final int ERROR_QUIC_PROTOCOL_FAILED = 10; + /** + * Error code indicating another type of error was encountered. + * {@link #getCronetInternalErrorCode} can be consulted to get a more specific cause. + */ + public static final int ERROR_OTHER = 11; + + /** + * Constructs an exception that is caused by a network error. + * + * @param message explanation of failure. + * @param cause the cause (which is saved for later retrieval by the {@link + * java.io.IOException#getCause getCause()} method). A null value is permitted, and + * indicates that the cause is nonexistent or unknown. + */ + protected NetworkException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Returns error code, one of {@link #ERROR_HOSTNAME_NOT_RESOLVED ERROR_*}. + * + * @return error code, one of {@link #ERROR_HOSTNAME_NOT_RESOLVED ERROR_*}. + */ + public abstract int getErrorCode(); + + /** + * Returns a Cronet internal error code. This may provide more specific error + * diagnosis than {@link #getErrorCode}, but the constant values are not exposed to Java and + * may change over time. See + * <a href=https://chromium.googlesource.com/chromium/src/+/master/net/base/net_error_list.h> + * here</a> for the lastest list of values. + * + * @return Cronet internal error code. + */ + public abstract int getCronetInternalErrorCode(); + + /** + * Returns {@code true} if retrying this request right away might succeed, {@code false} + * otherwise. For example returns {@code true} when {@link #getErrorCode} returns + * {@link #ERROR_NETWORK_CHANGED} because trying the request might succeed using the new + * network configuration, but {@code false} when {@code getErrorCode()} returns + * {@link #ERROR_INTERNET_DISCONNECTED} because retrying the request right away will + * encounter the same failure (instead retrying should be delayed until device regains + * network connectivity). + * + * @return {@code true} if retrying this request right away might succeed, {@code false} + * otherwise. + */ + public abstract boolean immediatelyRetryable(); +}
diff --git a/components/cronet/android/api/src/org/chromium/net/QuicException.java b/components/cronet/android/api/src/org/chromium/net/QuicException.java index 54f3626..b302cee 100644 --- a/components/cronet/android/api/src/org/chromium/net/QuicException.java +++ b/components/cronet/android/api/src/org/chromium/net/QuicException.java
@@ -5,31 +5,24 @@ package org.chromium.net; /** - * Subclass of {@link UrlRequestException} which contains a detailed + * Subclass of {@link NetworkException} which contains a detailed * <a href="https://www.chromium.org/quic">QUIC</a> error code from <a * href=https://cs.chromium.org/chromium/src/net/quic/quic_protocol.h?type=cs&q=%22enum+QuicErrorCode+%7B%22+file:src/net/quic/quic_protocol.h> * QuicErrorCode</a>. An instance of {@code QuicException} is passed to {@code onFailed} callbacks - * when the error code is {@link UrlRequestException#ERROR_QUIC_PROTOCOL_FAILED - * UrlRequestException.ERROR_QUIC_PROTOCOL_FAILED}. + * when the error code is {@link NetworkException#ERROR_QUIC_PROTOCOL_FAILED + * NetworkException.ERROR_QUIC_PROTOCOL_FAILED}. */ -public class QuicException extends CronetException { - private final int mQuicDetailedErrorCode; - +public abstract class QuicException extends NetworkException { /** - * Constructs an exception with a specific error. + * Constructs an exception that is caused by a QUIC protocol error. * * @param message explanation of failure. - * @param netErrorCode Error code from - * <a href=https://chromium.googlesource.com/chromium/src/+/master/net/base/net_error_list.h> - * this list</a>. - * @param quicDetailedErrorCode Detailed <a href="https://www.chromium.org/quic">QUIC</a> error - * code from <a - * href=https://cs.chromium.org/chromium/src/net/quic/quic_protocol.h?type=cs&q=%22enum+QuicErrorCode+%7B%22+file:src/net/quic/quic_protocol.h> - * QuicErrorCode</a>. + * @param cause the cause (which is saved for later retrieval by the {@link + * java.io.IOException#getCause getCause()} method). A null value is permitted, and + * indicates that the cause is nonexistent or unknown. */ - public QuicException(String message, int netErrorCode, int quicDetailedErrorCode) { - super(message, ERROR_QUIC_PROTOCOL_FAILED, netErrorCode); - mQuicDetailedErrorCode = quicDetailedErrorCode; + protected QuicException(String message, Throwable cause) { + super(message, cause); } /** @@ -38,7 +31,5 @@ * href=https://cs.chromium.org/chromium/src/net/quic/quic_protocol.h?type=cs&q=%22enum+QuicErrorCode+%7B%22+file:src/net/quic/quic_protocol.h> * QuicErrorCode</a>. */ - public int getQuicDetailedErrorCode() { - return mQuicDetailedErrorCode; - } + public abstract int getQuicDetailedErrorCode(); }
diff --git a/components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java b/components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java index 595b436..4d9ae5e 100644 --- a/components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java +++ b/components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java
@@ -294,11 +294,11 @@ public abstract UrlResponseInfo getResponseInfo(); /** - * If the request failed, returns the same {@link UrlRequestException} provided to + * If the request failed, returns the same {@link CronetException} provided to * {@link UrlRequest.Callback#onFailed}. * - * @return the request's {@link UrlRequestException}, if the request failed + * @return the request's {@link CronetException}, if the request failed */ @Nullable - public abstract UrlRequestException getException(); + public abstract CronetException getException(); }
diff --git a/components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java b/components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java index 352a45c..03edd98 100644 --- a/components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java +++ b/components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java
@@ -46,7 +46,7 @@ * @throws IOException if any IOException occurred during the process. * {@link UrlRequest.Callback#onFailed} will be called with the * thrown exception set as the cause of the - * {@link UrlRequestException}. + * {@link CallbackException}. */ public abstract void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) throws IOException; @@ -72,7 +72,7 @@ * @throws IOException if any IOException occurred during the process. * {@link UrlRequest.Callback#onFailed} will be called with the * thrown exception set as the cause of the - * {@link UrlRequestException}. + * {@link CallbackException}. */ public abstract void rewind(UploadDataSink uploadDataSink) throws IOException;
diff --git a/components/cronet/android/api/src/org/chromium/net/UrlRequest.java b/components/cronet/android/api/src/org/chromium/net/UrlRequest.java index 20ee1e9..726e10ec 100644 --- a/components/cronet/android/api/src/org/chromium/net/UrlRequest.java +++ b/components/cronet/android/api/src/org/chromium/net/UrlRequest.java
@@ -145,7 +145,7 @@ * @param newLocationUrl Location where request is redirected. * @throws Exception if an error occurs while processing a redirect. {@link #onFailed} * will be called with the thrown exception set as the cause of the - * {@link UrlRequestException}. + * {@link CallbackException}. */ public abstract void onRedirectReceived( UrlRequest request, UrlResponseInfo info, String newLocationUrl) throws Exception; @@ -165,7 +165,7 @@ * @param info Response information. * @throws Exception if an error occurs while processing response start. {@link #onFailed} * will be called with the thrown exception set as the cause of the - * {@link UrlRequestException}. + * {@link CallbackException}. */ public abstract void onResponseStarted(UrlRequest request, UrlResponseInfo info) throws Exception; @@ -190,7 +190,7 @@ * the received data. The buffer's limit is not changed. * @throws Exception if an error occurs while processing a read completion. * {@link #onFailed} will be called with the thrown exception set as the cause of - * the {@link UrlRequestException}. + * the {@link CallbackException}. */ public abstract void onReadCompleted( UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) throws Exception; @@ -214,8 +214,11 @@ * received. * @param error information about error. */ - public abstract void onFailed( - UrlRequest request, UrlResponseInfo info, UrlRequestException error); + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { + // TODO(mef): Remove fallback to legacy api and make this method abstract + // after complete transition to CronetException. + onFailed(request, info, new UrlRequestException(error)); + } /** * Invoked if request was canceled via {@link UrlRequest#cancel}. Once @@ -227,6 +230,16 @@ * received. */ public void onCanceled(UrlRequest request, UrlResponseInfo info) {} + + /** + * @deprecated Use {@code onFailed} instead. + * {@hide This method will be removed after complete transition to CronetException}. + */ + @Deprecated + // TODO(mef): Remove this after complete transition to CronetException. + public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + assert false; + } } /**
diff --git a/components/cronet/android/api/src/org/chromium/net/UrlRequestException.java b/components/cronet/android/api/src/org/chromium/net/UrlRequestException.java index 03f638b..0bca019 100644 --- a/components/cronet/android/api/src/org/chromium/net/UrlRequestException.java +++ b/components/cronet/android/api/src/org/chromium/net/UrlRequestException.java
@@ -7,18 +7,10 @@ import java.io.IOException; /** - * Exception passed to {@link UrlRequest.Callback#onFailed UrlRequest.Callback.onFailed()} when: - * <ul> - * <li>{@link UrlRequest.Callback} or {@link UploadDataProvider} method throws an exception. In this - * case {@link IOException#getCause getCause()} can be used to find the thrown exception. - * {@link #getErrorCode} will return {@link #ERROR_LISTENER_EXCEPTION_THROWN}. - * <li>Cronet fails to process a network request. In this case - * {@link #getErrorCode} and {@link #getCronetInternalErrorCode} can be used to get more - * information about the specific type of failure. If {@link #getErrorCode} - * returns {@link #ERROR_QUIC_PROTOCOL_FAILED}, this exception can be cast to a - * {@link QuicException} which can provide further details. - * </ul> + * @deprecated Use {@link CronetException} instead. + * {@hide This class will be removed after complete transition to CronetException}. */ +@Deprecated public class UrlRequestException extends IOException { /** * Error code indicating this class wraps an exception thrown by {@link UrlRequest.Callback} or @@ -81,31 +73,15 @@ // Cronet internal error code. private final int mCronetInternalErrorCode; - /** - * Constructs an exception with a specific error. - * - * @param message explanation of failure. - * @param errorCode error code, one of {@link #ERROR_LISTENER_EXCEPTION_THROWN ERROR_*}. - * @param cronetInternalErrorCode Cronet internal error code, one of - * <a href=https://chromium.googlesource.com/chromium/src/+/master/net/base/net_error_list.h> - * these</a>. - */ - public UrlRequestException(String message, int errorCode, int cronetInternalErrorCode) { - super(message, null); - mErrorCode = errorCode; - mCronetInternalErrorCode = cronetInternalErrorCode; - } - - /** - * Constructs an exception that wraps {@code cause} thrown by a {@link UrlRequest.Callback}. - * - * @param message explanation of failure. - * @param cause exception thrown by {@link UrlRequest.Callback} that's being wrapped. - */ - public UrlRequestException(String message, Throwable cause) { - super(message, cause); - mErrorCode = ERROR_LISTENER_EXCEPTION_THROWN; - mCronetInternalErrorCode = 0; + public UrlRequestException(CronetException error) { + super(error.getMessage(), error.getCause()); + if (error instanceof NetworkException) { + mErrorCode = ((NetworkException) error).getErrorCode(); + mCronetInternalErrorCode = ((NetworkException) error).getCronetInternalErrorCode(); + } else { + mErrorCode = 0; + mCronetInternalErrorCode = ERROR_LISTENER_EXCEPTION_THROWN; + } } /** @@ -161,15 +137,4 @@ return true; } } - - @Override - public String getMessage() { - StringBuilder b = new StringBuilder(super.getMessage()); - b.append(", ErrorCode=").append(mErrorCode); - if (mCronetInternalErrorCode != 0) { - b.append(", InternalErrorCode=").append(mCronetInternalErrorCode); - } - b.append(", Retryable=").append(immediatelyRetryable()); - return b.toString(); - } }
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java b/components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java new file mode 100644 index 0000000..94009eb --- /dev/null +++ b/components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java
@@ -0,0 +1,16 @@ +// Copyright 2016 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. + +package org.chromium.net.impl; + +import org.chromium.net.CallbackException; + +/** + * An implementation of {@link CallbackException}. + */ +public class CallbackExceptionImpl extends CallbackException { + public CallbackExceptionImpl(String message, Throwable cause) { + super(message, cause); + } +}
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java index cee01da2..780fbe2c7 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java
@@ -10,12 +10,12 @@ import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeClassQualifiedName; import org.chromium.net.BidirectionalStream; +import org.chromium.net.CallbackException; import org.chromium.net.CronetException; import org.chromium.net.ExperimentalBidirectionalStream; -import org.chromium.net.QuicException; +import org.chromium.net.NetworkException; import org.chromium.net.RequestFinishedInfo; import org.chromium.net.RequestPriority; -import org.chromium.net.UrlRequestException; import org.chromium.net.UrlResponseInfo; import java.nio.ByteBuffer; @@ -86,7 +86,7 @@ private final String mRequestHeaders[]; private final boolean mDelayRequestHeadersUntilFirstFlush; private final Collection<Object> mRequestAnnotations; - private UrlRequestException mException; + private CronetException mException; /* * Synchronizes access to mNativeStream, mReadState and mWriteState. @@ -496,7 +496,7 @@ mResponseInfo = prepareResponseInfoOnNetworkThread( httpStatusCode, negotiatedProtocol, headers, receivedBytesCount); } catch (Exception e) { - failWithException(new CronetException("Cannot prepare ResponseInfo", null)); + failWithException(new CronetExceptionImpl("Cannot prepare ResponseInfo", null)); return; } postTaskToExecutor(new Runnable() { @@ -525,11 +525,11 @@ mResponseInfo.setReceivedBytesCount(receivedBytesCount); if (byteBuffer.position() != initialPosition || byteBuffer.limit() != initialLimit) { failWithException( - new CronetException("ByteBuffer modified externally during read", null)); + new CronetExceptionImpl("ByteBuffer modified externally during read", null)); return; } if (bytesRead < 0 || initialPosition + bytesRead > initialLimit) { - failWithException(new CronetException("Invalid number of bytes read", null)); + failWithException(new CronetExceptionImpl("Invalid number of bytes read", null)); return; } byteBuffer.position(initialPosition + bytesRead); @@ -555,8 +555,8 @@ for (int i = 0; i < byteBuffers.length; i++) { ByteBuffer buffer = byteBuffers[i]; if (buffer.position() != initialPositions[i] || buffer.limit() != initialLimits[i]) { - failWithException( - new CronetException("ByteBuffer modified externally during write", null)); + failWithException(new CronetExceptionImpl( + "ByteBuffer modified externally during write", null)); return; } // Current implementation always writes the complete buffer. @@ -596,11 +596,12 @@ if (mResponseInfo != null) { mResponseInfo.setReceivedBytesCount(receivedBytesCount); } - if (errorCode == UrlRequestException.ERROR_QUIC_PROTOCOL_FAILED) { - failWithException(new QuicException("Exception in BidirectionalStream: " + errorString, - nativeError, nativeQuicError)); + if (errorCode == NetworkException.ERROR_QUIC_PROTOCOL_FAILED) { + failWithException( + new QuicExceptionImpl("Exception in BidirectionalStream: " + errorString, + nativeError, nativeQuicError)); } else { - failWithException(new CronetException( + failWithException(new NetworkExceptionImpl( "Exception in BidirectionalStream: " + errorString, errorCode, nativeError)); } } @@ -770,8 +771,8 @@ * Only called on the Executor. */ private void onCallbackException(Exception e) { - CronetException streamError = - new CronetException("CalledByNative method has thrown an exception", e); + CallbackException streamError = + new CallbackExceptionImpl("CalledByNative method has thrown an exception", e); Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in CalledByNative method", e); failWithExceptionOnExecutor(streamError); }
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java new file mode 100644 index 0000000..de47b14 --- /dev/null +++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java
@@ -0,0 +1,16 @@ +// Copyright 2016 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. + +package org.chromium.net.impl; + +import org.chromium.net.CronetException; + +/** + * Implements {@link CronetException}. + */ +public class CronetExceptionImpl extends CronetException { + public CronetExceptionImpl(String message, Throwable cause) { + super(message, cause); + } +}
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java index 6585fd5..56ecf16 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java
@@ -10,13 +10,14 @@ import org.chromium.base.annotations.JNIAdditionalImport; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeClassQualifiedName; +import org.chromium.net.CallbackException; +import org.chromium.net.CronetException; import org.chromium.net.InlineExecutionProhibitedException; -import org.chromium.net.QuicException; +import org.chromium.net.NetworkException; import org.chromium.net.RequestFinishedInfo; import org.chromium.net.RequestPriority; import org.chromium.net.UploadDataProvider; import org.chromium.net.UrlRequest; -import org.chromium.net.UrlRequestException; import java.nio.ByteBuffer; import java.util.AbstractMap; @@ -82,7 +83,7 @@ private final Collection<Object> mRequestAnnotations; @RequestFinishedInfoImpl.FinishedReason private int mFinishedReason; - private UrlRequestException mException; + private CronetException mException; private final boolean mDisableCache; private final boolean mDisableConnectionMigration; @@ -368,7 +369,7 @@ // request's failure, since failWithException does not enforce that onFailed() is not // executed inline. failWithException( - new UrlRequestException("Exception posting task to executor", failException)); + new CronetExceptionImpl("Exception posting task to executor", failException)); } } @@ -429,8 +430,8 @@ * Only called on the Executor. */ private void onCallbackException(Exception e) { - UrlRequestException requestError = - new UrlRequestException("Exception received from UrlRequest.Callback", e); + CallbackException requestError = + new CallbackExceptionImpl("Exception received from UrlRequest.Callback", e); Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in CalledByNative method", e); failWithException(requestError); } @@ -439,8 +440,8 @@ * Called when UploadDataProvider encounters an error. */ void onUploadException(Throwable e) { - UrlRequestException uploadError = - new UrlRequestException("Exception received from UploadDataProvider", e); + CallbackException uploadError = + new CallbackExceptionImpl("Exception received from UploadDataProvider", e); Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in upload method", e); failWithException(uploadError); } @@ -448,7 +449,7 @@ /** * Fails the request with an exception. Can be called on any thread. */ - private void failWithException(final UrlRequestException exception) { + private void failWithException(final CronetException exception) { mException = exception; synchronized (mUrlRequestAdapterLock) { if (isDoneLocked()) { @@ -579,7 +580,7 @@ mResponseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects + receivedBytesCount); if (byteBuffer.position() != initialPosition || byteBuffer.limit() != initialLimit) { failWithException( - new UrlRequestException("ByteBuffer modified externally during read", null)); + new CronetExceptionImpl("ByteBuffer modified externally during read", null)); return; } if (mOnReadCompletedTask == null) { @@ -626,8 +627,8 @@ * Called when error has occured, no callbacks will be called afterwards. * * @param errorCode Error code represented by {@code UrlRequestError} that should be mapped - * to one of {@link UrlRequestException#ERROR_LISTENER_EXCEPTION_THROWN - * UrlRequestException.ERROR_*}. + * to one of {@link NetworkException#ERROR_HOSTNAME_NOT_RESOLVED + * NetworkException.ERROR_*}. * @param nativeError native net error code. * @param errorString textual representation of the error code. * @param receivedBytesCount number of bytes received. @@ -641,12 +642,12 @@ mResponseInfo.setReceivedBytesCount( mReceivedBytesCountFromRedirects + receivedBytesCount); } - if (errorCode == UrlRequestException.ERROR_QUIC_PROTOCOL_FAILED) { - failWithException(new QuicException( + if (errorCode == NetworkException.ERROR_QUIC_PROTOCOL_FAILED) { + failWithException(new QuicExceptionImpl( "Exception in CronetUrlRequest: " + errorString, nativeError, nativeQuicError)); } else { int javaError = mapUrlRequestErrorToApiErrorCode(errorCode); - failWithException(new UrlRequestException( + failWithException(new NetworkExceptionImpl( "Exception in CronetUrlRequest: " + errorString, javaError, nativeError)); } } @@ -724,30 +725,28 @@ private int mapUrlRequestErrorToApiErrorCode(int errorCode) { switch (errorCode) { - case UrlRequestError.LISTENER_EXCEPTION_THROWN: - return UrlRequestException.ERROR_LISTENER_EXCEPTION_THROWN; case UrlRequestError.HOSTNAME_NOT_RESOLVED: - return UrlRequestException.ERROR_HOSTNAME_NOT_RESOLVED; + return NetworkException.ERROR_HOSTNAME_NOT_RESOLVED; case UrlRequestError.INTERNET_DISCONNECTED: - return UrlRequestException.ERROR_INTERNET_DISCONNECTED; + return NetworkException.ERROR_INTERNET_DISCONNECTED; case UrlRequestError.NETWORK_CHANGED: - return UrlRequestException.ERROR_NETWORK_CHANGED; + return NetworkException.ERROR_NETWORK_CHANGED; case UrlRequestError.TIMED_OUT: - return UrlRequestException.ERROR_TIMED_OUT; + return NetworkException.ERROR_TIMED_OUT; case UrlRequestError.CONNECTION_CLOSED: - return UrlRequestException.ERROR_CONNECTION_CLOSED; + return NetworkException.ERROR_CONNECTION_CLOSED; case UrlRequestError.CONNECTION_TIMED_OUT: - return UrlRequestException.ERROR_CONNECTION_TIMED_OUT; + return NetworkException.ERROR_CONNECTION_TIMED_OUT; case UrlRequestError.CONNECTION_REFUSED: - return UrlRequestException.ERROR_CONNECTION_REFUSED; + return NetworkException.ERROR_CONNECTION_REFUSED; case UrlRequestError.CONNECTION_RESET: - return UrlRequestException.ERROR_CONNECTION_RESET; + return NetworkException.ERROR_CONNECTION_RESET; case UrlRequestError.ADDRESS_UNREACHABLE: - return UrlRequestException.ERROR_ADDRESS_UNREACHABLE; + return NetworkException.ERROR_ADDRESS_UNREACHABLE; case UrlRequestError.QUIC_PROTOCOL_FAILED: - return UrlRequestException.ERROR_QUIC_PROTOCOL_FAILED; + return NetworkException.ERROR_QUIC_PROTOCOL_FAILED; case UrlRequestError.OTHER: - return UrlRequestException.ERROR_OTHER; + return NetworkException.ERROR_OTHER; default: Log.e(CronetUrlRequestContext.LOG_TAG, "Unknown error code: " + errorCode); return errorCode;
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java index 04897de..2b81e3e 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java
@@ -11,10 +11,10 @@ import android.util.Log; +import org.chromium.net.CronetException; import org.chromium.net.InlineExecutionProhibitedException; import org.chromium.net.UploadDataProvider; import org.chromium.net.UploadDataSink; -import org.chromium.net.UrlRequestException; import org.chromium.net.UrlResponseInfo; import java.io.Closeable; @@ -452,7 +452,7 @@ }); } - private void enterErrorState(final UrlRequestException error) { + private void enterErrorState(final CronetException error) { if (setTerminalState(State.ERROR)) { fireDisconnect(); fireCloseUploadDataProvider(); @@ -482,19 +482,19 @@ /** Ends the request with an error, caused by an exception thrown from user code. */ private void enterUserErrorState(final Throwable error) { enterErrorState( - new UrlRequestException("Exception received from UrlRequest.Callback", error)); + new CallbackExceptionImpl("Exception received from UrlRequest.Callback", error)); } /** Ends the request with an error, caused by an exception thrown from user code. */ private void enterUploadErrorState(final Throwable error) { enterErrorState( - new UrlRequestException("Exception received from UploadDataProvider", error)); + new CallbackExceptionImpl("Exception received from UploadDataProvider", error)); } private void enterCronetErrorState(final Throwable error) { // TODO(clm) mapping from Java exception (UnknownHostException, for example) to net error // code goes here. - enterErrorState(new UrlRequestException("System error", error)); + enterErrorState(new CronetExceptionImpl("System error", error)); } /** @@ -827,7 +827,7 @@ try { mUserExecutor.execute(userErrorSetting(runnable)); } catch (RejectedExecutionException e) { - enterErrorState(new UrlRequestException("Exception posting task to executor", e)); + enterErrorState(new CronetExceptionImpl("Exception posting task to executor", e)); } } @@ -889,7 +889,7 @@ }); } - void onFailed(final UrlResponseInfo urlResponseInfo, final UrlRequestException e) { + void onFailed(final UrlResponseInfo urlResponseInfo, final CronetException e) { closeResponseChannel(); Runnable runnable = new Runnable() { @Override
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java b/components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java new file mode 100644 index 0000000..4c328ab --- /dev/null +++ b/components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java
@@ -0,0 +1,72 @@ +// Copyright 2016 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. + +package org.chromium.net.impl; + +import org.chromium.net.NetworkException; + +/** + * Implements {@link NetworkException}. + */ +public class NetworkExceptionImpl extends NetworkException { + // Error code, one of ERROR_* + private final int mErrorCode; + // Cronet internal error code. + private final int mCronetInternalErrorCode; + + /** + * Constructs an exception with a specific error. + * + * @param message explanation of failure. + * @param errorCode error code, one of {@link #ERROR_HOSTNAME_NOT_RESOLVED ERROR_*}. + * @param cronetInternalErrorCode Cronet internal error code, one of + * <a href=https://chromium.googlesource.com/chromium/src/+/master/net/base/net_error_list.h> + * these</a>. + */ + public NetworkExceptionImpl(String message, int errorCode, int cronetInternalErrorCode) { + super(message, null); + mErrorCode = errorCode; + mCronetInternalErrorCode = cronetInternalErrorCode; + } + + @Override + public int getErrorCode() { + return mErrorCode; + } + + @Override + public int getCronetInternalErrorCode() { + return mCronetInternalErrorCode; + } + + @Override + public boolean immediatelyRetryable() { + switch (mErrorCode) { + case ERROR_HOSTNAME_NOT_RESOLVED: + case ERROR_INTERNET_DISCONNECTED: + case ERROR_CONNECTION_REFUSED: + case ERROR_ADDRESS_UNREACHABLE: + case ERROR_OTHER: + default: + return false; + case ERROR_NETWORK_CHANGED: + case ERROR_TIMED_OUT: + case ERROR_CONNECTION_CLOSED: + case ERROR_CONNECTION_TIMED_OUT: + case ERROR_CONNECTION_RESET: + return true; + } + } + + @Override + public String getMessage() { + StringBuilder b = new StringBuilder(super.getMessage()); + b.append(", ErrorCode=").append(mErrorCode); + if (mCronetInternalErrorCode != 0) { + b.append(", InternalErrorCode=").append(mCronetInternalErrorCode); + } + b.append(", Retryable=").append(immediatelyRetryable()); + return b.toString(); + } +}
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java b/components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java new file mode 100644 index 0000000..617dd52 --- /dev/null +++ b/components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java
@@ -0,0 +1,61 @@ +// Copyright 2016 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. + +package org.chromium.net.impl; + +import org.chromium.net.QuicException; + +/** + * Implements {@link QuicException}. + */ +public class QuicExceptionImpl extends QuicException { + private final int mQuicDetailedErrorCode; + private final NetworkExceptionImpl mNetworkException; + + /** + * Constructs an exception with a specific error. + * + * @param message explanation of failure. + * @param netErrorCode Error code from + * <a href=https://chromium.googlesource.com/chromium/src/+/master/net/base/net_error_list.h> + * this list</a>. + * @param quicDetailedErrorCode Detailed <a href="https://www.chromium.org/quic">QUIC</a> error + * code from <a + * href=https://cs.chromium.org/chromium/src/net/quic/quic_protocol.h?type=cs&q=%22enum+QuicErrorCode+%7B%22+file:src/net/quic/quic_protocol.h> + * QuicErrorCode</a>. + */ + public QuicExceptionImpl(String message, int netErrorCode, int quicDetailedErrorCode) { + super(message, null); + mNetworkException = + new NetworkExceptionImpl(message, ERROR_QUIC_PROTOCOL_FAILED, netErrorCode); + mQuicDetailedErrorCode = quicDetailedErrorCode; + } + + @Override + public String getMessage() { + StringBuilder b = new StringBuilder(mNetworkException.getMessage()); + b.append(", QuicDetailedErrorCode=").append(mQuicDetailedErrorCode); + return b.toString(); + } + + @Override + public int getErrorCode() { + return mNetworkException.getErrorCode(); + } + + @Override + public int getCronetInternalErrorCode() { + return mNetworkException.getCronetInternalErrorCode(); + } + + @Override + public boolean immediatelyRetryable() { + return mNetworkException.immediatelyRetryable(); + } + + @Override + public int getQuicDetailedErrorCode() { + return mQuicDetailedErrorCode; + } +}
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java b/components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java index 30fbf8c..61aaa39 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java
@@ -7,8 +7,8 @@ import android.support.annotation.IntDef; import android.support.annotation.Nullable; +import org.chromium.net.CronetException; import org.chromium.net.RequestFinishedInfo; -import org.chromium.net.UrlRequestException; import org.chromium.net.UrlResponseInfo; import java.lang.annotation.Retention; @@ -30,7 +30,7 @@ @Nullable private final UrlResponseInfo mResponseInfo; @Nullable - private final UrlRequestException mException; + private final CronetException mException; @IntDef({SUCCEEDED, FAILED, CANCELED}) @Retention(RetentionPolicy.SOURCE) @@ -38,7 +38,7 @@ public RequestFinishedInfoImpl(String url, Collection<Object> annotations, RequestFinishedInfo.Metrics metrics, @FinishedReason int finishedReason, - @Nullable UrlResponseInfo responseInfo, @Nullable UrlRequestException exception) { + @Nullable UrlResponseInfo responseInfo, @Nullable CronetException exception) { mUrl = url; mAnnotations = annotations; mMetrics = metrics; @@ -79,7 +79,7 @@ @Override @Nullable - public UrlRequestException getException() { + public CronetException getException() { return mException; } }
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java b/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java index 7b1633d9..d0c4ace9 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java
@@ -64,7 +64,7 @@ } @Override - public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { mWrappedCallback.onFailed(request, info, error); } @@ -72,6 +72,11 @@ public void onCanceled(UrlRequest request, UrlResponseInfo info) { mWrappedCallback.onCanceled(request, info); } + + @Override + public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + mWrappedCallback.onFailed(request, info, error); + } } /** @@ -289,4 +294,4 @@ mWrappedLoader.loadLibrary(libName); } } -} \ No newline at end of file +}
diff --git a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java index 2d565be..e1e6b52 100644 --- a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java +++ b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java
@@ -8,8 +8,8 @@ import org.chromium.base.Log; import org.chromium.net.CronetEngine; +import org.chromium.net.CronetException; import org.chromium.net.UrlRequest; -import org.chromium.net.UrlRequestException; import org.chromium.net.UrlResponseInfo; import java.io.FileNotFoundException; @@ -44,7 +44,7 @@ private CronetInputStream mInputStream; private CronetOutputStream mOutputStream; private UrlResponseInfo mResponseInfo; - private UrlRequestException mException; + private CronetException mException; private boolean mOnRedirectCalled = false; private boolean mHasResponse = false; private List<Map.Entry<String, String>> mResponseHeadersList; @@ -479,8 +479,7 @@ } @Override - public void onFailed( - UrlRequest request, UrlResponseInfo info, UrlRequestException exception) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException exception) { if (exception == null) { throw new IllegalStateException( "Exception cannot be null in onFailed.");
diff --git a/components/cronet/android/sample/src/org/chromium/cronet_sample_apk/CronetSampleActivity.java b/components/cronet/android/sample/src/org/chromium/cronet_sample_apk/CronetSampleActivity.java index 3512b9c..39359b4 100644 --- a/components/cronet/android/sample/src/org/chromium/cronet_sample_apk/CronetSampleActivity.java +++ b/components/cronet/android/sample/src/org/chromium/cronet_sample_apk/CronetSampleActivity.java
@@ -15,9 +15,9 @@ import org.chromium.base.Log; import org.chromium.net.CronetEngine; +import org.chromium.net.CronetException; import org.chromium.net.UploadDataProviders; import org.chromium.net.UrlRequest; -import org.chromium.net.UrlRequestException; import org.chromium.net.UrlResponseInfo; import java.io.ByteArrayOutputStream; @@ -92,7 +92,7 @@ } @Override - public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { Log.i(TAG, "****** onFailed, error is: %s", error.getMessage()); final String url = mUrl;
diff --git a/components/cronet/android/test/javaperftests/src/org/chromium/net/CronetPerfTestActivity.java b/components/cronet/android/test/javaperftests/src/org/chromium/net/CronetPerfTestActivity.java index 430c37a4..340b065 100644 --- a/components/cronet/android/test/javaperftests/src/org/chromium/net/CronetPerfTestActivity.java +++ b/components/cronet/android/test/javaperftests/src/org/chromium/net/CronetPerfTestActivity.java
@@ -451,8 +451,7 @@ } @Override - public void onFailed( - UrlRequest request, UrlResponseInfo info, UrlRequestException e) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException e) { System.out.println("Async request failed with " + e); mFailed = true; }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java index 87fa67f2..16ae9f22 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
@@ -330,8 +330,10 @@ // Server terminated on us, so the stream must fail. // QUIC reports this as ERR_QUIC_PROTOCOL_ERROR. Sometimes we get ERR_CONNECTION_REFUSED. assertNotNull(callback.mError); - assertTrue(NetError.ERR_QUIC_PROTOCOL_ERROR == callback.mError.getCronetInternalErrorCode() - || NetError.ERR_CONNECTION_REFUSED == callback.mError.getCronetInternalErrorCode()); + assertTrue(callback.mError instanceof NetworkException); + NetworkException networkError = (NetworkException) callback.mError; + assertTrue(NetError.ERR_QUIC_PROTOCOL_ERROR == networkError.getCronetInternalErrorCode() + || NetError.ERR_CONNECTION_REFUSED == networkError.getCronetInternalErrorCode()); } @SmallTest
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java index 8e7c642..fc2fd96 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
@@ -203,7 +203,7 @@ assertTrue(stream.isDone()); assertContains("Exception in BidirectionalStream: net::ERR_DISALLOWED_URL_SCHEME", callback.mError.getMessage()); - assertEquals(-301, callback.mError.getCronetInternalErrorCode()); + assertEquals(-301, ((NetworkException) callback.mError).getCronetInternalErrorCode()); } @SmallTest
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java index 9acfb99..5757a44 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -120,7 +120,7 @@ } @Override - public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { super.onFailed(request, info, error); mCronetEngine.shutdown(); mCallbackCompletionBlock.open(); @@ -785,8 +785,7 @@ } @Override - public void onFailed( - UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { throw new RuntimeException("Unexpected"); } } @@ -837,8 +836,7 @@ } @Override - public void onFailed( - UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { throw new RuntimeException("Unexpected"); } }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java index 3190230..23ce5ab5 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
@@ -314,8 +314,7 @@ } @Override - public void onFailed( - UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { failedExpectation.set(true); fail(); } @@ -621,7 +620,8 @@ FailurePhase.START, arbitraryNetError)); assertNull(callback.mResponseInfo); assertNotNull(callback.mError); - assertEquals(arbitraryNetError, callback.mError.getCronetInternalErrorCode()); + assertEquals(arbitraryNetError, + ((NetworkException) callback.mError).getCronetInternalErrorCode()); assertEquals(0, callback.mRedirectCount); assertTrue(callback.mOnErrorCalled); assertEquals(ResponseStep.ON_FAILED, callback.mResponseStep); @@ -638,7 +638,8 @@ assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); assertEquals(15, callback.mResponseInfo.getReceivedBytesCount()); assertNotNull(callback.mError); - assertEquals(arbitraryNetError, callback.mError.getCronetInternalErrorCode()); + assertEquals(arbitraryNetError, + ((NetworkException) callback.mError).getCronetInternalErrorCode()); assertEquals(0, callback.mRedirectCount); assertTrue(callback.mOnErrorCalled); assertEquals(ResponseStep.ON_FAILED, callback.mResponseStep); @@ -655,7 +656,8 @@ assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); assertEquals(15, callback.mResponseInfo.getReceivedBytesCount()); assertNotNull(callback.mError); - assertEquals(arbitraryNetError, callback.mError.getCronetInternalErrorCode()); + assertEquals(arbitraryNetError, + ((NetworkException) callback.mError).getCronetInternalErrorCode()); assertEquals(0, callback.mRedirectCount); assertTrue(callback.mOnErrorCalled); assertEquals(ResponseStep.ON_FAILED, callback.mResponseStep); @@ -690,7 +692,7 @@ assertNull(callback.mResponseInfo); assertNotNull(callback.mError); assertTrue(callback.mOnErrorCalled); - assertEquals(-201, callback.mError.getCronetInternalErrorCode()); + assertEquals(-201, ((NetworkException) callback.mError).getCronetInternalErrorCode()); assertContains("Exception in CronetUrlRequest: net::ERR_CERT_DATE_INVALID", callback.mError.getMessage()); assertEquals(ResponseStep.ON_FAILED, callback.mResponseStep); @@ -1932,23 +1934,23 @@ @OnlyRunNativeCronet // Java impl doesn't support MockUrlRequestJobFactory public void testErrorCodes() throws Exception { checkSpecificErrorCode( - -105, UrlRequestException.ERROR_HOSTNAME_NOT_RESOLVED, "NAME_NOT_RESOLVED", false); - checkSpecificErrorCode(-106, UrlRequestException.ERROR_INTERNET_DISCONNECTED, - "INTERNET_DISCONNECTED", false); + -105, NetworkException.ERROR_HOSTNAME_NOT_RESOLVED, "NAME_NOT_RESOLVED", false); checkSpecificErrorCode( - -21, UrlRequestException.ERROR_NETWORK_CHANGED, "NETWORK_CHANGED", true); + -106, NetworkException.ERROR_INTERNET_DISCONNECTED, "INTERNET_DISCONNECTED", false); checkSpecificErrorCode( - -100, UrlRequestException.ERROR_CONNECTION_CLOSED, "CONNECTION_CLOSED", true); + -21, NetworkException.ERROR_NETWORK_CHANGED, "NETWORK_CHANGED", true); checkSpecificErrorCode( - -102, UrlRequestException.ERROR_CONNECTION_REFUSED, "CONNECTION_REFUSED", false); + -100, NetworkException.ERROR_CONNECTION_CLOSED, "CONNECTION_CLOSED", true); checkSpecificErrorCode( - -101, UrlRequestException.ERROR_CONNECTION_RESET, "CONNECTION_RESET", true); + -102, NetworkException.ERROR_CONNECTION_REFUSED, "CONNECTION_REFUSED", false); checkSpecificErrorCode( - -118, UrlRequestException.ERROR_CONNECTION_TIMED_OUT, "CONNECTION_TIMED_OUT", true); - checkSpecificErrorCode(-7, UrlRequestException.ERROR_TIMED_OUT, "TIMED_OUT", true); + -101, NetworkException.ERROR_CONNECTION_RESET, "CONNECTION_RESET", true); checkSpecificErrorCode( - -109, UrlRequestException.ERROR_ADDRESS_UNREACHABLE, "ADDRESS_UNREACHABLE", false); - checkSpecificErrorCode(-2, UrlRequestException.ERROR_OTHER, "FAILED", false); + -118, NetworkException.ERROR_CONNECTION_TIMED_OUT, "CONNECTION_TIMED_OUT", true); + checkSpecificErrorCode(-7, NetworkException.ERROR_TIMED_OUT, "TIMED_OUT", true); + checkSpecificErrorCode( + -109, NetworkException.ERROR_ADDRESS_UNREACHABLE, "ADDRESS_UNREACHABLE", false); + checkSpecificErrorCode(-2, NetworkException.ERROR_OTHER, "FAILED", false); } /* @@ -1980,22 +1982,85 @@ FailurePhase.START, NetError.ERR_QUIC_PROTOCOL_ERROR)); assertNull(callback.mResponseInfo); assertNotNull(callback.mError); - assertEquals( - UrlRequestException.ERROR_QUIC_PROTOCOL_FAILED, callback.mError.getErrorCode()); + assertEquals(NetworkException.ERROR_QUIC_PROTOCOL_FAILED, + ((NetworkException) callback.mError).getErrorCode()); assertTrue(callback.mError instanceof QuicException); QuicException quicException = (QuicException) callback.mError; // 1 is QUIC_INTERNAL_ERROR assertEquals(1, quicException.getQuicDetailedErrorCode()); } + /** + * Tests that legacy onFailed callback is invoked with UrlRequestException if there + * is no onFailed callback implementation that takes CronetException. + */ + @SmallTest + @Feature({"Cronet"}) + @OnlyRunNativeCronet + public void testLegacyOnFailedCallback() throws Exception { + final int netError = -123; + final AtomicBoolean failedExpectation = new AtomicBoolean(); + final ConditionVariable done = new ConditionVariable(); + UrlRequest.Callback callback = new UrlRequest.Callback() { + @Override + public void onRedirectReceived( + UrlRequest request, UrlResponseInfo info, String newLocationUrl) { + failedExpectation.set(true); + fail(); + } + + @Override + public void onResponseStarted(UrlRequest request, UrlResponseInfo info) { + failedExpectation.set(true); + fail(); + } + + @Override + public void onReadCompleted( + UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) { + failedExpectation.set(true); + fail(); + } + + @Override + public void onSucceeded(UrlRequest request, UrlResponseInfo info) { + failedExpectation.set(true); + fail(); + } + + @Override + public void onFailed( + UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + assertEquals(netError, error.getCronetInternalErrorCode()); + failedExpectation.set(error.getCronetInternalErrorCode() != netError); + done.open(); + } + + @Override + public void onCanceled(UrlRequest request, UrlResponseInfo info) { + failedExpectation.set(true); + fail(); + } + }; + + UrlRequest.Builder builder = mTestFramework.mCronetEngine.newUrlRequestBuilder( + MockUrlRequestJobFactory.getMockUrlWithFailure(FailurePhase.START, netError), + callback, Executors.newSingleThreadExecutor()); + final UrlRequest urlRequest = builder.build(); + urlRequest.start(); + done.block(); + // Check that onFailed is called. + assertFalse(failedExpectation.get()); + } + private void checkSpecificErrorCode(int netError, int errorCode, String name, boolean immediatelyRetryable) throws Exception { TestUrlRequestCallback callback = startAndWaitForComplete( MockUrlRequestJobFactory.getMockUrlWithFailure(FailurePhase.START, netError)); assertNull(callback.mResponseInfo); assertNotNull(callback.mError); - assertEquals(netError, callback.mError.getCronetInternalErrorCode()); - assertEquals(errorCode, callback.mError.getErrorCode()); + assertEquals(netError, ((NetworkException) callback.mError).getCronetInternalErrorCode()); + assertEquals(errorCode, ((NetworkException) callback.mError).getErrorCode()); assertContains( "Exception in CronetUrlRequest: net::ERR_" + name, callback.mError.getMessage()); assertEquals(0, callback.mRedirectCount);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java index 9ace3b833..662e6d4 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
@@ -89,7 +89,8 @@ callback.blockForDone(); assertNotNull(callback.mError); assertTrue(callback.mOnErrorCalled); - assertEquals(NetError.ERR_NETWORK_CHANGED, callback.mError.getCronetInternalErrorCode()); + assertEquals(NetError.ERR_NETWORK_CHANGED, + ((NetworkException) callback.mError).getCronetInternalErrorCode()); assertContains("Exception in CronetUrlRequest: net::ERR_NETWORK_CHANGED", callback.mError.getMessage()); }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java index 16342df..fa84f746 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java
@@ -363,7 +363,7 @@ */ private void assertErrorResponse() { assertNotNull("Expected an error", mListener.mError); - int errorCode = mListener.mError.getCronetInternalErrorCode(); + int errorCode = ((NetworkException) mListener.mError).getCronetInternalErrorCode(); Set<Integer> expectedErrors = new HashSet<>(); expectedErrors.add(NetError.ERR_QUIC_PROTOCOL_ERROR); expectedErrors.add(NetError.ERR_CONNECTION_REFUSED); @@ -379,7 +379,7 @@ private void assertSuccessfulResponse() { if (mListener.mError != null) { fail("Did not expect an error but got error code " - + mListener.mError.getCronetInternalErrorCode()); + + ((NetworkException) mListener.mError).getCronetInternalErrorCode()); } assertNotNull("Expected non-null response from the server", mListener.mResponseInfo); assertEquals(200, mListener.mResponseInfo.getHttpStatusCode());
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java index 5b0f50e6..9bef689 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java
@@ -206,8 +206,8 @@ assertTrue(requestInfo.getAnnotations().isEmpty()); assertEquals(RequestFinishedInfo.FAILED, requestInfo.getFinishedReason()); assertNotNull(requestInfo.getException()); - assertEquals(UrlRequestException.ERROR_CONNECTION_REFUSED, - requestInfo.getException().getErrorCode()); + assertEquals(NetworkException.ERROR_CONNECTION_REFUSED, + ((NetworkException) requestInfo.getException()).getErrorCode()); RequestFinishedInfo.Metrics metrics = requestInfo.getMetrics(); assertNotNull("RequestFinishedInfo.getMetrics() must not be null", metrics); // The failure is occasionally fast enough that time reported is 0, so just check for null
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java b/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java index b2a0163..b088cfb 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java
@@ -15,8 +15,6 @@ import static org.chromium.net.CronetTestBase.assertContains; -import org.chromium.net.impl.UrlRequestError; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.concurrent.ExecutorService; @@ -33,7 +31,7 @@ public ArrayList<UrlResponseInfo> mRedirectResponseInfoList = new ArrayList<UrlResponseInfo>(); public ArrayList<String> mRedirectUrlList = new ArrayList<String>(); public UrlResponseInfo mResponseInfo; - public UrlRequestException mError; + public CronetException mError; public ResponseStep mResponseStep = ResponseStep.NOTHING; @@ -50,7 +48,7 @@ // that advance it. private boolean mAutoAdvance = true; // Whether an exception is thrown by maybeThrowCancelOrPause(). - private boolean mListenerExceptionThrown; + private boolean mCallbackExceptionThrown; // Whether to permit calls on the network thread. private boolean mAllowDirectExecutor = false; @@ -239,7 +237,7 @@ } @Override - public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { // If the failure is because of prohibited direct execution, the test shouldn't fail // since the request already did. if (error.getCause() instanceof InlineExecutionProhibitedException) { @@ -253,14 +251,12 @@ assertFalse(mOnErrorCalled); assertFalse(mOnCanceledCalled); assertNull(mError); - if (mListenerExceptionThrown) { - assertEquals(UrlRequestError.LISTENER_EXCEPTION_THROWN, error.getErrorCode()); - assertEquals(0, error.getCronetInternalErrorCode()); + if (mCallbackExceptionThrown) { + assertTrue(error instanceof CallbackException); assertContains("Exception received from UrlRequest.Callback", error.getMessage()); assertNotNull(error.getCause()); assertTrue(error.getCause() instanceof IllegalStateException); assertContains("Listener Exception.", error.getCause().getMessage()); - assertFalse(error.immediatelyRetryable()); } mResponseStep = ResponseStep.ON_FAILED; @@ -326,8 +322,8 @@ } if (mFailureType == FailureType.THROW_SYNC) { - assertFalse(mListenerExceptionThrown); - mListenerExceptionThrown = true; + assertFalse(mCallbackExceptionThrown); + mCallbackExceptionThrown = true; throw new IllegalStateException("Listener Exception."); } Runnable task = new Runnable() {
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java index b5a4a095..de4bc266 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/UploadDataProvidersTest.java
@@ -200,8 +200,7 @@ first.block(); callback.blockForDone(); assertFalse(callback.mOnCanceledCalled); - assertEquals(UrlRequestException.ERROR_LISTENER_EXCEPTION_THROWN, - callback.mError.getErrorCode()); + assertTrue(callback.mError instanceof CallbackException); assertContains("Exception received from UploadDataProvider", callback.mError.getMessage()); assertContains(exceptionMessage, callback.mError.getCause().getMessage()); }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java index 13603ed..476c174 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java
@@ -10,7 +10,7 @@ import org.chromium.net.CronetTestBase; import org.chromium.net.CronetTestFramework; import org.chromium.net.NativeTestServer; -import org.chromium.net.UrlRequestException; +import org.chromium.net.NetworkException; import java.io.IOException; import java.io.OutputStream; @@ -103,9 +103,9 @@ fail(); } catch (IOException e) { if (!testingSystemHttpURLConnection()) { - UrlRequestException requestException = (UrlRequestException) e; - assertEquals(UrlRequestException.ERROR_CONNECTION_REFUSED, - requestException.getErrorCode()); + NetworkException requestException = (NetworkException) e; + assertEquals( + NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode()); } } // Restarting server to run the test for a second time. @@ -133,9 +133,9 @@ fail(); } catch (IOException e) { if (!testingSystemHttpURLConnection()) { - UrlRequestException requestException = (UrlRequestException) e; - assertEquals(UrlRequestException.ERROR_CONNECTION_REFUSED, - requestException.getErrorCode()); + NetworkException requestException = (NetworkException) e; + assertEquals( + NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode()); } } // Make sure IOException is reported again when trying to read response @@ -146,9 +146,9 @@ } catch (IOException e) { // Expected. if (!testingSystemHttpURLConnection()) { - UrlRequestException requestException = (UrlRequestException) e; - assertEquals(UrlRequestException.ERROR_CONNECTION_REFUSED, - requestException.getErrorCode()); + NetworkException requestException = (NetworkException) e; + assertEquals( + NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode()); } } // Restarting server to run the test for a second time.
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java index bb481cd..7ae9ca09 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java
@@ -10,7 +10,7 @@ import org.chromium.net.CronetTestBase; import org.chromium.net.CronetTestFramework; import org.chromium.net.NativeTestServer; -import org.chromium.net.UrlRequestException; +import org.chromium.net.NetworkException; import java.io.IOException; import java.io.OutputStream; @@ -85,9 +85,9 @@ } catch (IOException e) { // Expected. if (!testingSystemHttpURLConnection()) { - UrlRequestException requestException = (UrlRequestException) e; - assertEquals(UrlRequestException.ERROR_CONNECTION_REFUSED, - requestException.getErrorCode()); + NetworkException requestException = (NetworkException) e; + assertEquals( + NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode()); } } // Restarting server to run the test for a second time. @@ -114,9 +114,9 @@ fail(); } catch (IOException e) { if (!testingSystemHttpURLConnection()) { - UrlRequestException requestException = (UrlRequestException) e; - assertEquals(UrlRequestException.ERROR_CONNECTION_REFUSED, - requestException.getErrorCode()); + NetworkException requestException = (NetworkException) e; + assertEquals( + NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode()); } } // Make sure IOException is reported again when trying to read response @@ -127,9 +127,9 @@ } catch (IOException e) { // Expected. if (!testingSystemHttpURLConnection()) { - UrlRequestException requestException = (UrlRequestException) e; - assertEquals(UrlRequestException.ERROR_CONNECTION_REFUSED, - requestException.getErrorCode()); + NetworkException requestException = (NetworkException) e; + assertEquals( + NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode()); } } // Restarting server to run the test for a second time.
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java index f55ef289..989de7d 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
@@ -10,11 +10,11 @@ import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; import org.chromium.net.CronetEngine; +import org.chromium.net.CronetException; import org.chromium.net.CronetTestBase; import org.chromium.net.CronetTestFramework; import org.chromium.net.MockUrlRequestJobFactory; import org.chromium.net.NativeTestServer; -import org.chromium.net.UrlRequestException; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; @@ -271,8 +271,7 @@ secondConnection.getResponseCode(); fail(); } catch (IOException e) { - assertTrue(e instanceof java.net.ConnectException - || e instanceof UrlRequestException); + assertTrue(e instanceof java.net.ConnectException || e instanceof CronetException); assertTrue((e.getMessage().contains("ECONNREFUSED") || (e.getMessage().contains("Connection refused")) || e.getMessage().contains("net::ERR_CONNECTION_REFUSED"))); @@ -297,8 +296,7 @@ urlConnection.getResponseCode(); fail(); } catch (IOException e) { - assertTrue(e instanceof java.net.ConnectException - || e instanceof UrlRequestException); + assertTrue(e instanceof java.net.ConnectException || e instanceof CronetException); assertTrue((e.getMessage().contains("ECONNREFUSED") || (e.getMessage().contains("Connection refused")) || e.getMessage().contains("net::ERR_CONNECTION_REFUSED"))); @@ -322,7 +320,7 @@ fail(); } catch (java.net.UnknownHostException e) { // Expected. - } catch (UrlRequestException e) { + } catch (CronetException e) { // Expected. } checkExceptionsAreThrown(urlConnection);
diff --git a/components/new_or_sad_tab_strings.grdp b/components/new_or_sad_tab_strings.grdp index b04b83d5..a88f6663 100644 --- a/components/new_or_sad_tab_strings.grdp +++ b/components/new_or_sad_tab_strings.grdp
@@ -31,6 +31,11 @@ <message name="IDS_SAD_TAB_RELOAD_LABEL" desc="Button label in the sad tab page for reloading a page." formatter_data="android_java"> Reload </message> + <if expr="is_android"> + <message name="IDS_SAD_TAB_SEND_FEEDBACK_LABEL" desc="Button label in the sad tab page for sending feedback. This label replaces the reload button after a crash happens twice in a row." formatter_data="android_java"> + Send Feedback + </message> + </if> <!-- New Tab --> <message name="IDS_NEW_TAB_TITLE"
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc index a7029482..d297b64 100644 --- a/components/omnibox/browser/url_index_private_data.cc +++ b/components/omnibox/browser/url_index_private_data.cc
@@ -253,7 +253,7 @@ for (SearchTermCacheMap::iterator cache_iter = search_term_cache_.begin(); cache_iter != search_term_cache_.end(); ) { if (!cache_iter->second.used_) - search_term_cache_.erase(cache_iter++); + cache_iter = search_term_cache_.erase(cache_iter); else ++cache_iter; } @@ -497,6 +497,7 @@ HistoryIDSet URLIndexPrivateData::HistoryIDSetFromWords( const String16Vector& unsorted_words) { + SCOPED_UMA_HISTOGRAM_TIMER("Omnibox.HistoryQuickHistoryIDSetFromWords"); // Break the terms down into individual terms (words), get the candidate // set for each term, and intersect each to get a final candidate list. // Note that a single 'term' from the user's perspective might be @@ -605,7 +606,7 @@ for (WordIDSet::iterator word_set_iter = word_id_set.begin(); word_set_iter != word_id_set.end(); ) { if (word_list_[*word_set_iter].find(term) == base::string16::npos) - word_id_set.erase(word_set_iter++); + word_set_iter = word_id_set.erase(word_set_iter); else ++word_set_iter; }
diff --git a/components/payments/payment_details_validation.cc b/components/payments/payment_details_validation.cc index 08a6fa3..a01303e 100644 --- a/components/payments/payment_details_validation.cc +++ b/components/payments/payment_details_validation.cc
@@ -108,19 +108,15 @@ return false; } - std::set<mojo::String> uniqueMethods; for (const auto& modifier : modifiers) { - if (modifier->supported_methods.empty()) { - *error_message = "Must specify at least one payment method identifier"; + if (!modifier->method_data) { + *error_message = "Method data required"; return false; } - for (const auto& method : modifier->supported_methods) { - if (uniqueMethods.find(method) != uniqueMethods.end()) { - *error_message = "Duplicate payment method identifiers are not allowed"; - return false; - } - uniqueMethods.insert(method); + if (modifier->method_data->supported_methods.empty()) { + *error_message = "Must specify at least one payment method identifier"; + return false; } if (modifier->total) {
diff --git a/components/payments/payment_request.mojom b/components/payments/payment_request.mojom index 9d95c51..bc42866 100644 --- a/components/payments/payment_request.mojom +++ b/components/payments/payment_request.mojom
@@ -58,8 +58,8 @@ // a payment app, for example Android Pay. Browser ensures that the string can // be successfully parsed into base::JSONParser. Renderer parses this string // via v8::JSON::Parse() and hands off the result to the merchant website. - // There's no one format for this object, so richer types cannot be used. A - // simple example: + // There's no one format for this object, so more specific types cannot be + // used. A simple example: // // {"nameOnCard": "Jon Doe", "pan": "4111 1111 1111 1111"} string stringified_details; @@ -106,10 +106,34 @@ bool selected; }; -struct PaymentDetailsModifier { +struct PaymentMethodData { array<string> supported_methods; + + // A JSON string built by the renderer from a JavaScript object that the + // merchant website provides. The renderer uses + // blink::JSONObject::toJSONString() to generate this string. The browser does + // not parse the string and passes it as-is directly to payment apps. There's + // no one format for this object, so more specific types cannot be used. A + // simple example: + // + // {"gateway": "stripe"} + string stringified_data; + + // Android Pay specific method data is parsed in the renderer. + // https://developers.google.com/web/fundamentals/getting-started/primers/payment-request/android-pay + // TODO(rouslan): Stop parsing Android Pay data. http://crbug.com/620173 + AndroidPayEnvironment environment; + string? merchant_name; + string? merchant_id; + array<AndroidPayCardNetwork> allowed_card_networks; + AndroidPayTokenization tokenization_type; + array<AndroidPayTokenizationParameter> parameters; +}; + +struct PaymentDetailsModifier { PaymentItem? total; array<PaymentItem> additional_display_items; + PaymentMethodData method_data; }; struct PaymentDetails { @@ -157,30 +181,6 @@ string? value; }; -struct PaymentMethodData { - array<string> supported_methods; - - // A JSON string built by the renderer from a JavaScript object that the - // merchant website provides. The renderer uses - // blink::JSONObject::toJSONString() to generate this string. The browser does - // not parse the string and passes it as-is directly to payment apps. There's - // no one format for this object, so richer types cannot be used. A simple - // example: - // - // {"gateway": "stripe"} - string stringified_data; - - // Android Pay specific method data is parsed in the renderer. - // https://developers.google.com/web/fundamentals/getting-started/primers/payment-request/android-pay - // TODO(rouslan): Stop parsing Android Pay data. http://crbug.com/620173 - AndroidPayEnvironment environment; - string? merchant_name; - string? merchant_id; - array<AndroidPayCardNetwork> allowed_card_networks; - AndroidPayTokenization tokenization_type; - array<AndroidPayTokenizationParameter> parameters; -}; - enum PaymentComplete { SUCCESS, FAIL,
diff --git a/components/policy/core/common/policy_switches.cc b/components/policy/core/common/policy_switches.cc index c9682f6..be6a8569 100644 --- a/components/policy/core/common/policy_switches.cc +++ b/components/policy/core/common/policy_switches.cc
@@ -19,5 +19,9 @@ // produce verification signatures. const char kDisablePolicyKeyVerification[] = "disable-policy-key-verification"; +// Always treat user as affiliated. +// TODO(antrim): Remove once test servers correctly produce affiliation ids. +const char kUserAlwaysAffiliated[] = "user-always-affiliated"; + } // namespace switches } // namespace policy
diff --git a/components/policy/core/common/policy_switches.h b/components/policy/core/common/policy_switches.h index 1f0426c..34db62f 100644 --- a/components/policy/core/common/policy_switches.h +++ b/components/policy/core/common/policy_switches.h
@@ -15,6 +15,7 @@ POLICY_EXPORT extern const char kDeviceManagementUrl[]; POLICY_EXPORT extern const char kDisableComponentCloudPolicy[]; POLICY_EXPORT extern const char kDisablePolicyKeyVerification[]; +POLICY_EXPORT extern const char kUserAlwaysAffiliated[]; } // namespace switches } // namespace policy
diff --git a/components/test_runner/test_interfaces.cc b/components/test_runner/test_interfaces.cc index e5f0c076..3e3e715 100644 --- a/components/test_runner/test_interfaces.cc +++ b/components/test_runner/test_interfaces.cc
@@ -96,7 +96,8 @@ if (spec.find("/inspector/") != std::string::npos || spec.find("/inspector-enabled/") != std::string::npos) test_runner_->ClearDevToolsLocalStorage(); - if (spec.find("/inspector/") != std::string::npos) { + if (spec.find("/inspector/") != std::string::npos && + spec.find("unit_test_runner.html") == std::string::npos) { // Subfolder name determines default panel to open. std::string test_path = spec.substr(spec.find("/inspector/") + 11); base::DictionaryValue settings;
diff --git a/content/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc index 8c05c07..0bf1caa 100644 --- a/content/browser/dom_storage/session_storage_database.cc +++ b/content/browser/dom_storage/session_storage_database.cc
@@ -33,7 +33,12 @@ enum SessionStorageUMA { SESSION_STORAGE_UMA_SUCCESS, SESSION_STORAGE_UMA_RECREATED, - SESSION_STORAGE_UMA_FAIL, + SESSION_STORAGE_UMA_RECREATE_FAIL, // Deprecated in M56 (issue 183679) + SESSION_STORAGE_UMA_RECREATE_NOT_FOUND, + SESSION_STORAGE_UMA_RECREATE_NOT_SUPPORTED, + SESSION_STORAGE_UMA_RECREATE_CORRUPTION, + SESSION_STORAGE_UMA_RECREATE_INVALID_ARGUMENT, + SESSION_STORAGE_UMA_RECREATE_IO_ERROR, SESSION_STORAGE_UMA_MAX }; @@ -391,9 +396,30 @@ if (!s.ok()) { LOG(WARNING) << "Failed to open leveldb in " << file_path_.value() << ", error: " << s.ToString(); - UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name, - SESSION_STORAGE_UMA_FAIL, - SESSION_STORAGE_UMA_MAX); + if (s.IsNotFound()) { + UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name, + SESSION_STORAGE_UMA_RECREATE_NOT_FOUND, + SESSION_STORAGE_UMA_MAX); + } else if (s.IsNotSupportedError()) { + UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name, + SESSION_STORAGE_UMA_RECREATE_NOT_SUPPORTED, + SESSION_STORAGE_UMA_MAX); + } else if (s.IsCorruption()) { + UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name, + SESSION_STORAGE_UMA_RECREATE_CORRUPTION, + SESSION_STORAGE_UMA_MAX); + } else if (s.IsInvalidArgument()) { + UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name, + SESSION_STORAGE_UMA_RECREATE_INVALID_ARGUMENT, + SESSION_STORAGE_UMA_MAX); + } else if (s.IsIOError()) { + UMA_HISTOGRAM_ENUMERATION(session_storage_uma_name, + SESSION_STORAGE_UMA_RECREATE_IO_ERROR, + SESSION_STORAGE_UMA_MAX); + } else { + NOTREACHED(); + } + DCHECK(db == NULL); db_error_ = true; return false;
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index 1453acb..56e95b8 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -519,7 +519,7 @@ gfx::Point RenderWidgetHostViewChildFrame::TransformPointToRootCoordSpace( const gfx::Point& point) { - if (!frame_connector_) + if (!frame_connector_ || !local_frame_id_.is_valid()) return point; return frame_connector_->TransformPointToRootCoordSpace(
diff --git a/content/browser/indexed_db/cursor_impl.cc b/content/browser/indexed_db/cursor_impl.cc index 6e4d219..e711d8dd 100644 --- a/content/browser/indexed_db/cursor_impl.cc +++ b/content/browser/indexed_db/cursor_impl.cc
@@ -12,7 +12,7 @@ class CursorImpl::IDBThreadHelper { public: - explicit IDBThreadHelper(scoped_refptr<IndexedDBCursor> cursor); + explicit IDBThreadHelper(std::unique_ptr<IndexedDBCursor> cursor); ~IDBThreadHelper(); void Advance(uint32_t count, scoped_refptr<IndexedDBCallbacks> callbacks); @@ -24,13 +24,13 @@ private: scoped_refptr<IndexedDBDispatcherHost> dispatcher_host_; - scoped_refptr<IndexedDBCursor> cursor_; + std::unique_ptr<IndexedDBCursor> cursor_; const url::Origin origin_; DISALLOW_COPY_AND_ASSIGN(IDBThreadHelper); }; -CursorImpl::CursorImpl(scoped_refptr<IndexedDBCursor> cursor, +CursorImpl::CursorImpl(std::unique_ptr<IndexedDBCursor> cursor, const url::Origin& origin, scoped_refptr<IndexedDBDispatcherHost> dispatcher_host) : helper_(new IDBThreadHelper(std::move(cursor))), @@ -88,10 +88,12 @@ } CursorImpl::IDBThreadHelper::IDBThreadHelper( - scoped_refptr<IndexedDBCursor> cursor) + std::unique_ptr<IndexedDBCursor> cursor) : cursor_(std::move(cursor)) {} -CursorImpl::IDBThreadHelper::~IDBThreadHelper() {} +CursorImpl::IDBThreadHelper::~IDBThreadHelper() { + cursor_->RemoveCursorFromTransaction(); +} void CursorImpl::IDBThreadHelper::Advance( uint32_t count,
diff --git a/content/browser/indexed_db/cursor_impl.h b/content/browser/indexed_db/cursor_impl.h index a0b66c0..69254289c 100644 --- a/content/browser/indexed_db/cursor_impl.h +++ b/content/browser/indexed_db/cursor_impl.h
@@ -5,6 +5,8 @@ #ifndef CONTENT_BROWSER_INDEXED_DB_CURSOR_IMPL_H_ #define CONTENT_BROWSER_INDEXED_DB_CURSOR_IMPL_H_ +#include <memory> + #include "base/memory/ref_counted.h" #include "content/common/indexed_db/indexed_db.mojom.h" @@ -20,7 +22,7 @@ class CursorImpl : public ::indexed_db::mojom::Cursor { public: - CursorImpl(scoped_refptr<IndexedDBCursor> cursor, + CursorImpl(std::unique_ptr<IndexedDBCursor> cursor, const url::Origin& origin, scoped_refptr<IndexedDBDispatcherHost> dispatcher_host); ~CursorImpl() override;
diff --git a/content/browser/indexed_db/database_impl.cc b/content/browser/indexed_db/database_impl.cc index fd3b190..27b331f 100644 --- a/content/browser/indexed_db/database_impl.cc +++ b/content/browser/indexed_db/database_impl.cc
@@ -9,6 +9,7 @@ #include "content/browser/indexed_db/indexed_db_connection.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/indexed_db/indexed_db_dispatcher_host.h" +#include "content/browser/indexed_db/indexed_db_transaction.h" #include "content/browser/indexed_db/indexed_db_value.h" #include "storage/browser/blob/blob_storage_context.h" #include "storage/browser/quota/quota_manager_proxy.h" @@ -453,9 +454,13 @@ if (!connection_->IsConnected()) return; - connection_->database()->CreateObjectStore( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - name, key_path, auto_increment); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->CreateObjectStore(transaction, object_store_id, name, + key_path, auto_increment); } void DatabaseImpl::IDBThreadHelper::DeleteObjectStore(int64_t transaction_id, @@ -463,8 +468,12 @@ if (!connection_->IsConnected()) return; - connection_->database()->DeleteObjectStore( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->DeleteObjectStore(transaction, object_store_id); } void DatabaseImpl::IDBThreadHelper::RenameObjectStore( @@ -474,9 +483,13 @@ if (!connection_->IsConnected()) return; - connection_->database()->RenameObjectStore( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - new_name); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->RenameObjectStore(transaction, object_store_id, + new_name); } void DatabaseImpl::IDBThreadHelper::CreateTransaction( @@ -486,15 +499,8 @@ if (!connection_->IsConnected()) return; - int64_t host_transaction_id = - dispatcher_host_->HostTransactionId(transaction_id); - if (!dispatcher_host_->RegisterTransactionId(host_transaction_id, origin_)) { - DLOG(ERROR) << "Duplicate host_transaction_id."; - return; - } - - connection_->database()->CreateTransaction( - host_transaction_id, connection_.get(), object_store_ids, mode); + connection_->database()->CreateTransaction(transaction_id, connection_.get(), + object_store_ids, mode); } void DatabaseImpl::IDBThreadHelper::Close() { @@ -520,11 +526,15 @@ if (!connection_->IsConnected()) return; + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + IndexedDBObserver::Options options(include_transaction, no_records, values, operation_types); - connection_->database()->AddPendingObserver( - dispatcher_host_->HostTransactionId(transaction_id), observer_id, - options); + connection_->database()->AddPendingObserver(transaction, observer_id, + options); } void DatabaseImpl::IDBThreadHelper::RemoveObservers( @@ -545,10 +555,14 @@ if (!connection_->IsConnected()) return; - connection_->database()->Get( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_id, base::MakeUnique<IndexedDBKeyRange>(key_range), key_only, - callbacks); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->Get(transaction, object_store_id, index_id, + base::MakeUnique<IndexedDBKeyRange>(key_range), + key_only, callbacks); } void DatabaseImpl::IDBThreadHelper::GetAll( @@ -562,10 +576,15 @@ if (!connection_->IsConnected()) return; + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + connection_->database()->GetAll( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_id, base::MakeUnique<IndexedDBKeyRange>(key_range), key_only, - max_count, std::move(callbacks)); + transaction, object_store_id, index_id, + base::MakeUnique<IndexedDBKeyRange>(key_range), key_only, max_count, + std::move(callbacks)); } void DatabaseImpl::IDBThreadHelper::Put( @@ -581,19 +600,22 @@ if (!connection_->IsConnected()) return; - int64_t host_transaction_id = - dispatcher_host_->HostTransactionId(transaction_id); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + uint64_t commit_size = mojo_value->bits.size(); IndexedDBValue value; swap(value.bits, mojo_value->bits); swap(value.blob_info, blob_info); - connection_->database()->Put(host_transaction_id, object_store_id, &value, - &handles, base::MakeUnique<IndexedDBKey>(key), - mode, std::move(callbacks), index_keys); + connection_->database()->Put(transaction, object_store_id, &value, &handles, + base::MakeUnique<IndexedDBKey>(key), mode, + std::move(callbacks), index_keys); // Size can't be big enough to overflow because it represents the // actual bytes passed through IPC. - dispatcher_host_->AddToTransaction(host_transaction_id, commit_size); + transaction->set_size(transaction->size() + commit_size); } void DatabaseImpl::IDBThreadHelper::SetIndexKeys( @@ -604,9 +626,14 @@ if (!connection_->IsConnected()) return; + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + connection_->database()->SetIndexKeys( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - base::MakeUnique<IndexedDBKey>(primary_key), index_keys); + transaction, object_store_id, base::MakeUnique<IndexedDBKey>(primary_key), + index_keys); } void DatabaseImpl::IDBThreadHelper::SetIndexesReady( @@ -616,9 +643,13 @@ if (!connection_->IsConnected()) return; - connection_->database()->SetIndexesReady( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_ids); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->SetIndexesReady(transaction, object_store_id, + index_ids); } void DatabaseImpl::IDBThreadHelper::OpenCursor( @@ -633,10 +664,15 @@ if (!connection_->IsConnected()) return; + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + connection_->database()->OpenCursor( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_id, base::MakeUnique<IndexedDBKeyRange>(key_range), direction, - key_only, task_type, std::move(callbacks)); + transaction, object_store_id, index_id, + base::MakeUnique<IndexedDBKeyRange>(key_range), direction, key_only, + task_type, std::move(callbacks)); } void DatabaseImpl::IDBThreadHelper::Count( @@ -648,10 +684,14 @@ if (!connection_->IsConnected()) return; - connection_->database()->Count( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_id, base::MakeUnique<IndexedDBKeyRange>(key_range), - std::move(callbacks)); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->Count(transaction, object_store_id, index_id, + base::MakeUnique<IndexedDBKeyRange>(key_range), + std::move(callbacks)); } void DatabaseImpl::IDBThreadHelper::DeleteRange( @@ -662,8 +702,13 @@ if (!connection_->IsConnected()) return; + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + connection_->database()->DeleteRange( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, + transaction, object_store_id, base::MakeUnique<IndexedDBKeyRange>(key_range), std::move(callbacks)); } @@ -674,9 +719,12 @@ if (!connection_->IsConnected()) return; - connection_->database()->Clear( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - callbacks); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->Clear(transaction, object_store_id, callbacks); } void DatabaseImpl::IDBThreadHelper::CreateIndex( @@ -690,9 +738,13 @@ if (!connection_->IsConnected()) return; - connection_->database()->CreateIndex( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_id, name, key_path, unique, multi_entry); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->CreateIndex(transaction, object_store_id, index_id, + name, key_path, unique, multi_entry); } void DatabaseImpl::IDBThreadHelper::DeleteIndex(int64_t transaction_id, @@ -701,9 +753,12 @@ if (!connection_->IsConnected()) return; - connection_->database()->DeleteIndex( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_id); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->DeleteIndex(transaction, object_store_id, index_id); } void DatabaseImpl::IDBThreadHelper::RenameIndex( @@ -714,34 +769,39 @@ if (!connection_->IsConnected()) return; - connection_->database()->RenameIndex( - dispatcher_host_->HostTransactionId(transaction_id), object_store_id, - index_id, new_name); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->database()->RenameIndex(transaction, object_store_id, index_id, + new_name); } void DatabaseImpl::IDBThreadHelper::Abort(int64_t transaction_id) { if (!connection_->IsConnected()) return; - connection_->database()->Abort( - dispatcher_host_->HostTransactionId(transaction_id)); + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) + return; + + connection_->AbortTransaction(transaction); } void DatabaseImpl::IDBThreadHelper::Commit(int64_t transaction_id) { if (!connection_->IsConnected()) return; - int64_t host_transaction_id = - dispatcher_host_->HostTransactionId(transaction_id); - // May have been aborted by back end before front-end could request commit. - int64_t transaction_size; - if (!dispatcher_host_->GetTransactionSize(host_transaction_id, - &transaction_size)) + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) return; // Always allow empty or delete-only transactions. - if (transaction_size == 0) { - connection_->database()->Commit(host_transaction_id); + if (transaction->size() == 0) { + connection_->database()->Commit(transaction); return; } @@ -761,19 +821,17 @@ if (!connection_->IsConnected()) return; - int64_t host_transaction_id = - dispatcher_host_->HostTransactionId(transaction_id); - // May have aborted while quota check was pending. - int64_t transaction_size; - if (!dispatcher_host_->GetTransactionSize(host_transaction_id, - &transaction_size)) + IndexedDBTransaction* transaction = + connection_->GetTransaction(transaction_id); + if (!transaction) return; - if (status == storage::kQuotaStatusOk && usage + transaction_size <= quota) { - connection_->database()->Commit(host_transaction_id); + if (status == storage::kQuotaStatusOk && + usage + transaction->size() <= quota) { + connection_->database()->Commit(transaction); } else { - connection_->database()->Abort( - host_transaction_id, + connection_->AbortTransaction( + transaction, IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError)); } }
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc index 4f80b83..a3a9115 100644 --- a/content/browser/indexed_db/indexed_db_backing_store.cc +++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -2268,7 +2268,7 @@ ++iter_; WriteNextFile(); } else { - callback_->Run(false); + callback_->Run(BlobWriteResult::FAILURE_ASYNC); } } @@ -2290,11 +2290,11 @@ } if (iter_ == blobs_.end()) { DCHECK(!self_ref_.get()); - callback_->Run(true); + callback_->Run(BlobWriteResult::SUCCESS_ASYNC); return; } else { if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { - callback_->Run(false); + callback_->Run(BlobWriteResult::FAILURE_ASYNC); return; } waiting_for_callback_ = true; @@ -2307,6 +2307,9 @@ WriteDescriptorVec::const_iterator iter_; int64_t database_id_; IndexedDBBackingStore* backing_store_; + // Callback result is useless as call stack is no longer transaction's + // operations queue. Errors are instead handled in + // IndexedDBTransaction::BlobWriteComplete. scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; std::unique_ptr<FileWriterDelegate> delegate_; bool aborted_; @@ -4045,8 +4048,10 @@ IndexedDBBackingStore::Transaction::Transaction( IndexedDBBackingStore* backing_store) - : backing_store_(backing_store), database_id_(-1), committing_(false) { -} + : backing_store_(backing_store), + database_id_(-1), + committing_(false), + ptr_factory_(this) {} IndexedDBBackingStore::Transaction::~Transaction() { DCHECK(!committing_); @@ -4215,7 +4220,7 @@ // This call will zero out new_blob_entries and new_files_to_write. WriteNewBlobs(&new_blob_entries, &new_files_to_write, callback); } else { - callback->Run(true); + return callback->Run(BlobWriteResult::SUCCESS_SYNC); } return leveldb::Status::OK(); @@ -4320,22 +4325,36 @@ class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper : public IndexedDBBackingStore::BlobWriteCallback { public: - BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction, - scoped_refptr<BlobWriteCallback> callback) - : transaction_(transaction), callback_(callback) {} - void Run(bool succeeded) override { + BlobWriteCallbackWrapper( + base::WeakPtr<IndexedDBBackingStore::Transaction> transaction, + void* tracing_end_ptr, + scoped_refptr<BlobWriteCallback> callback) + : transaction_(std::move(transaction)), + tracing_end_ptr_(tracing_end_ptr), + callback_(callback) {} + leveldb::Status Run(BlobWriteResult result) override { + DCHECK_NE(result, BlobWriteResult::SUCCESS_SYNC); IDB_ASYNC_TRACE_END("IndexedDBBackingStore::Transaction::WriteNewBlobs", - transaction_); - callback_->Run(succeeded); - if (succeeded) // Else it's already been deleted during rollback. - transaction_->chained_blob_writer_ = NULL; + tracing_end_ptr_); + leveldb::Status leveldb_result = callback_->Run(result); + switch (result) { + case BlobWriteResult::FAILURE_ASYNC: + break; + case BlobWriteResult::SUCCESS_ASYNC: + case BlobWriteResult::SUCCESS_SYNC: + if (transaction_) + transaction_->chained_blob_writer_ = nullptr; + break; + } + return leveldb_result; } private: ~BlobWriteCallbackWrapper() override {} friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>; - IndexedDBBackingStore::Transaction* transaction_; + base::WeakPtr<IndexedDBBackingStore::Transaction> transaction_; + const void* const tracing_end_ptr_; scoped_refptr<BlobWriteCallback> callback_; DISALLOW_COPY_AND_ASSIGN(BlobWriteCallbackWrapper); @@ -4358,12 +4377,11 @@ transaction_->Put(blob_entry_iter.first.Encode(), &blob_entry_iter.second); } - // Creating the writer will start it going asynchronously. - chained_blob_writer_ = - new ChainedBlobWriterImpl(database_id_, - backing_store_, - new_files_to_write, - new BlobWriteCallbackWrapper(this, callback)); + // Creating the writer will start it going asynchronously. The transaction + // can be destructed before the callback is triggered. + chained_blob_writer_ = new ChainedBlobWriterImpl( + database_id_, backing_store_, new_files_to_write, + new BlobWriteCallbackWrapper(ptr_factory_.GetWeakPtr(), this, callback)); } void IndexedDBBackingStore::Transaction::Rollback() { @@ -4378,7 +4396,7 @@ chained_blob_writer_->Abort(); chained_blob_writer_ = NULL; } - if (transaction_.get() == NULL) + if (!transaction_) return; transaction_->Rollback(); transaction_ = NULL;
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h index 00d6678f..46d8591 100644 --- a/content/browser/indexed_db/indexed_db_backing_store.h +++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -19,6 +19,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/strings/string_piece.h" #include "base/time/time.h" #include "base/timer/timer.h" @@ -90,9 +91,13 @@ DISALLOW_COPY_AND_ASSIGN(RecordIdentifier); }; + enum class BlobWriteResult { FAILURE_ASYNC, SUCCESS_ASYNC, SUCCESS_SYNC }; + class BlobWriteCallback : public base::RefCounted<BlobWriteCallback> { public: - virtual void Run(bool succeeded) = 0; + // TODO(dmurph): Make all calls to this method async after measuring + // performance. + virtual leveldb::Status Run(BlobWriteResult result) = 0; protected: friend class base::RefCounted<BlobWriteCallback>; @@ -282,6 +287,8 @@ // has been bumped, and journal cleaning should be deferred. bool committing_; + base::WeakPtrFactory<Transaction> ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(Transaction); };
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc index f9ce90c..ca6ee07 100644 --- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc +++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -375,9 +375,18 @@ class TestCallback : public IndexedDBBackingStore::BlobWriteCallback { public: TestCallback() : called(false), succeeded(false) {} - void Run(bool succeeded_in) override { + leveldb::Status Run(IndexedDBBackingStore::BlobWriteResult result) override { called = true; - succeeded = succeeded_in; + switch (result) { + case IndexedDBBackingStore::BlobWriteResult::FAILURE_ASYNC: + succeeded = false; + break; + case IndexedDBBackingStore::BlobWriteResult::SUCCESS_ASYNC: + case IndexedDBBackingStore::BlobWriteResult::SUCCESS_SYNC: + succeeded = true; + break; + } + return leveldb::Status::OK(); } bool called; bool succeeded;
diff --git a/content/browser/indexed_db/indexed_db_callbacks.cc b/content/browser/indexed_db/indexed_db_callbacks.cc index 03dd974..9ecc1ad 100644 --- a/content/browser/indexed_db/indexed_db_callbacks.cc +++ b/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -23,6 +23,7 @@ #include "content/browser/indexed_db/indexed_db_database_error.h" #include "content/browser/indexed_db/indexed_db_return_value.h" #include "content/browser/indexed_db/indexed_db_tracing.h" +#include "content/browser/indexed_db/indexed_db_transaction.h" #include "content/browser/indexed_db/indexed_db_value.h" #include "content/common/indexed_db/indexed_db_constants.h" #include "content/common/indexed_db/indexed_db_metadata.h" @@ -38,7 +39,6 @@ namespace content { namespace { -const int64_t kNoTransaction = -1; void ConvertBlobInfo( const std::vector<IndexedDBBlobInfo>& blob_info, @@ -144,7 +144,6 @@ const url::Origin& origin, ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) : dispatcher_host_(std::move(dispatcher_host)), - host_transaction_id_(kNoTransaction), origin_(origin), data_loss_(blink::WebIDBDataLossNone), sent_blocked_(false), @@ -180,7 +179,6 @@ DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_EQ(kNoTransaction, host_transaction_id_); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -221,11 +219,9 @@ DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_NE(kNoTransaction, host_transaction_id_); DCHECK(!database_sent_); data_loss_ = data_loss_info.status; - dispatcher_host_->RegisterTransactionId(host_transaction_id_, origin_); database_sent_ = true; auto database = base::MakeUnique<DatabaseImpl>(std::move(connection), origin_, dispatcher_host_); @@ -252,7 +248,6 @@ DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_NE(kNoTransaction, host_transaction_id_); DCHECK_EQ(database_sent_, !connection); scoped_refptr<IndexedDBCallbacks> self(this); @@ -278,7 +273,7 @@ } } -void IndexedDBCallbacks::OnSuccess(scoped_refptr<IndexedDBCursor> cursor, +void IndexedDBCallbacks::OnSuccess(std::unique_ptr<IndexedDBCursor> cursor, const IndexedDBKey& key, const IndexedDBKey& primary_key, IndexedDBValue* value) { @@ -286,11 +281,10 @@ DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_EQ(kNoTransaction, host_transaction_id_); DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_); - auto cursor_impl = - base::MakeUnique<CursorImpl>(cursor, origin_, dispatcher_host_); + auto cursor_impl = base::MakeUnique<CursorImpl>(std::move(cursor), origin_, + dispatcher_host_); ::indexed_db::mojom::ValuePtr mojo_value; std::vector<IndexedDBBlobInfo> blob_info; @@ -315,7 +309,6 @@ DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_EQ(kNoTransaction, host_transaction_id_); DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_); ::indexed_db::mojom::ValuePtr mojo_value; @@ -343,7 +336,6 @@ DCHECK_EQ(keys.size(), primary_keys.size()); DCHECK_EQ(keys.size(), values->size()); - DCHECK_EQ(kNoTransaction, host_transaction_id_); DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_); std::vector<::indexed_db::mojom::ValuePtr> mojo_values; @@ -363,7 +355,6 @@ DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(dispatcher_host_); - DCHECK_EQ(kNoTransaction, host_transaction_id_); DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_); ::indexed_db::mojom::ReturnValuePtr mojo_value; @@ -387,7 +378,6 @@ DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_EQ(kNoTransaction, host_transaction_id_); DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_); std::vector<::indexed_db::mojom::ReturnValuePtr> mojo_values; @@ -407,7 +397,6 @@ DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_EQ(kNoTransaction, host_transaction_id_); DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_); BrowserThread::PostTask( @@ -433,7 +422,6 @@ DCHECK(dispatcher_host_); DCHECK(io_helper_); - DCHECK_EQ(kNoTransaction, host_transaction_id_); DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_); BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
diff --git a/content/browser/indexed_db/indexed_db_callbacks.h b/content/browser/indexed_db/indexed_db_callbacks.h index bf26a1d..c3b564f 100644 --- a/content/browser/indexed_db/indexed_db_callbacks.h +++ b/content/browser/indexed_db/indexed_db_callbacks.h
@@ -59,7 +59,7 @@ const content::IndexedDBDatabaseMetadata& metadata); // IndexedDBDatabase::OpenCursor - virtual void OnSuccess(scoped_refptr<IndexedDBCursor> cursor, + virtual void OnSuccess(std::unique_ptr<IndexedDBCursor> cursor, const IndexedDBKey& key, const IndexedDBKey& primary_key, IndexedDBValue* value); @@ -99,10 +99,6 @@ void SetConnectionOpenStartTime(const base::TimeTicks& start_time); - void set_host_transaction_id(int64_t host_transaction_id) { - host_transaction_id_ = host_transaction_id; - } - protected: virtual ~IndexedDBCallbacks(); @@ -118,7 +114,6 @@ scoped_refptr<IndexedDBDispatcherHost> dispatcher_host_; // IndexedDBDatabase callbacks ------------------------ - int64_t host_transaction_id_; url::Origin origin_; bool database_sent_ = false;
diff --git a/content/browser/indexed_db/indexed_db_class_factory.cc b/content/browser/indexed_db/indexed_db_class_factory.cc index 2ef35d6..c6e2489e 100644 --- a/content/browser/indexed_db/indexed_db_class_factory.cc +++ b/content/browser/indexed_db/indexed_db_class_factory.cc
@@ -37,17 +37,15 @@ return new IndexedDBDatabase(name, backing_store, factory, unique_identifier); } -IndexedDBTransaction* IndexedDBClassFactory::CreateIndexedDBTransaction( +std::unique_ptr<IndexedDBTransaction> +IndexedDBClassFactory::CreateIndexedDBTransaction( int64_t id, - base::WeakPtr<IndexedDBConnection> connection, + IndexedDBConnection* connection, const std::set<int64_t>& scope, blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction) { - // The transaction adds itself to |connection|'s database's transaction - // coordinator, which owns the object. - IndexedDBTransaction* transaction = new IndexedDBTransaction( - id, std::move(connection), scope, mode, backing_store_transaction); - return transaction; + return std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection, scope, mode, backing_store_transaction)); } scoped_refptr<LevelDBTransaction>
diff --git a/content/browser/indexed_db/indexed_db_class_factory.h b/content/browser/indexed_db/indexed_db_class_factory.h index f9fb5fd..6f216e6 100644 --- a/content/browser/indexed_db/indexed_db_class_factory.h +++ b/content/browser/indexed_db/indexed_db_class_factory.h
@@ -47,9 +47,9 @@ scoped_refptr<IndexedDBFactory> factory, const IndexedDBDatabase::Identifier& unique_identifier); - virtual IndexedDBTransaction* CreateIndexedDBTransaction( + virtual std::unique_ptr<IndexedDBTransaction> CreateIndexedDBTransaction( int64_t id, - base::WeakPtr<IndexedDBConnection> connection, + IndexedDBConnection* connection, const std::set<int64_t>& scope, blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction);
diff --git a/content/browser/indexed_db/indexed_db_connection.cc b/content/browser/indexed_db/indexed_db_connection.cc index 0c3cb35..216786a 100644 --- a/content/browser/indexed_db/indexed_db_connection.cc +++ b/content/browser/indexed_db/indexed_db_connection.cc
@@ -5,6 +5,12 @@ #include "content/browser/indexed_db/indexed_db_connection.h" #include "base/logging.h" +#include "base/stl_util.h" +#include "content/browser/indexed_db/indexed_db_class_factory.h" +#include "content/browser/indexed_db/indexed_db_database_callbacks.h" +#include "content/browser/indexed_db/indexed_db_observer.h" +#include "content/browser/indexed_db/indexed_db_tracing.h" +#include "content/browser/indexed_db/indexed_db_transaction.h" namespace content { @@ -15,9 +21,11 @@ } // namespace IndexedDBConnection::IndexedDBConnection( + int child_process_id, scoped_refptr<IndexedDBDatabase> database, scoped_refptr<IndexedDBDatabaseCallbacks> callbacks) : id_(next_id++), + child_process_id_(child_process_id), database_(database), callbacks_(callbacks), weak_factory_(this) {} @@ -85,8 +93,69 @@ else pending_observer_ids.push_back(id_to_remove); } - if (!pending_observer_ids.empty()) - database_->RemovePendingObservers(this, pending_observer_ids); + if (pending_observer_ids.empty()) + return; + + for (const auto& it : transactions_) { + it.second->RemovePendingObservers(pending_observer_ids); + } +} + +IndexedDBTransaction* IndexedDBConnection::CreateTransaction( + int64_t id, + const std::set<int64_t>& scope, + blink::WebIDBTransactionMode mode, + IndexedDBBackingStore::Transaction* backing_store_transaction) { + DCHECK_EQ(GetTransaction(id), nullptr) << "Duplicate transaction id." << id; + std::unique_ptr<IndexedDBTransaction> transaction = + IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( + id, this, scope, mode, backing_store_transaction); + IndexedDBTransaction* transaction_ptr = transaction.get(); + transactions_[id] = std::move(transaction); + return transaction_ptr; +} + +void IndexedDBConnection::AbortTransaction(IndexedDBTransaction* transaction) { + IDB_TRACE1("IndexedDBDatabase::Abort", "txn.id", transaction->id()); + transaction->Abort(); +} + +void IndexedDBConnection::AbortTransaction( + IndexedDBTransaction* transaction, + const IndexedDBDatabaseError& error) { + IDB_TRACE1("IndexedDBDatabase::Abort(error)", "txn.id", transaction->id()); + transaction->Abort(error); +} + +void IndexedDBConnection::AbortAllTransactions( + const IndexedDBDatabaseError& error) { + std::unordered_map<int64_t, std::unique_ptr<IndexedDBTransaction>> temp_map; + std::swap(temp_map, transactions_); + for (const auto& pair : temp_map) { + IDB_TRACE1("IndexedDBDatabase::Abort(error)", "txn.id", pair.second->id()); + pair.second->Abort(error); + } +} + +IndexedDBTransaction* IndexedDBConnection::GetTransaction(int64_t id) const { + auto it = transactions_.find(id); + if (it == transactions_.end()) + return nullptr; + return it->second.get(); +} + +base::WeakPtr<IndexedDBTransaction> +IndexedDBConnection::AddTransactionForTesting( + std::unique_ptr<IndexedDBTransaction> transaction) { + DCHECK(!base::ContainsKey(transactions_, transaction->id())); + base::WeakPtr<IndexedDBTransaction> transaction_ptr = + transaction->ptr_factory_.GetWeakPtr(); + transactions_[transaction->id()] = std::move(transaction); + return transaction_ptr; +} + +void IndexedDBConnection::RemoveTransaction(int64_t id) { + transactions_.erase(id); } } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_connection.h b/content/browser/indexed_db/indexed_db_connection.h index ce60ebd..20acb7b 100644 --- a/content/browser/indexed_db/indexed_db_connection.h +++ b/content/browser/indexed_db/indexed_db_connection.h
@@ -6,20 +6,25 @@ #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_CONNECTION_H_ #include <memory> +#include <set> +#include <unordered_map> #include <vector> #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "content/browser/indexed_db/indexed_db_database.h" -#include "content/browser/indexed_db/indexed_db_database_callbacks.h" -#include "content/browser/indexed_db/indexed_db_observer.h" namespace content { +class IndexedDBDatabaseCallbacks; +class IndexedDBDatabaseError; +class IndexedDBObserver; +class IndexedDBTransaction; class CONTENT_EXPORT IndexedDBConnection { public: - IndexedDBConnection(scoped_refptr<IndexedDBDatabase> db, + IndexedDBConnection(int child_process_id, + scoped_refptr<IndexedDBDatabase> db, scoped_refptr<IndexedDBDatabaseCallbacks> callbacks); virtual ~IndexedDBConnection(); @@ -38,6 +43,7 @@ virtual void RemoveObservers(const std::vector<int32_t>& remove_observer_ids); int32_t id() const { return id_; } + int child_process_id() const { return child_process_id_; } IndexedDBDatabase* database() const { return database_.get(); } IndexedDBDatabaseCallbacks* callbacks() const { return callbacks_.get(); } @@ -49,12 +55,42 @@ return weak_factory_.GetWeakPtr(); } + // Creates a transaction for this connection. + IndexedDBTransaction* CreateTransaction( + int64_t id, + const std::set<int64_t>& scope, + blink::WebIDBTransactionMode mode, + IndexedDBBackingStore::Transaction* backing_store_transaction); + + void AbortTransaction(IndexedDBTransaction* transaction); + void AbortTransaction(IndexedDBTransaction* transaction, + const IndexedDBDatabaseError& error); + + void AbortAllTransactions(const IndexedDBDatabaseError& error); + + IndexedDBTransaction* GetTransaction(int64_t id) const; + + base::WeakPtr<IndexedDBTransaction> AddTransactionForTesting( + std::unique_ptr<IndexedDBTransaction> transaction); + + // We ignore calls where the id doesn't exist to facilitate the AbortAll call. + // TODO(dmurph): Change that so this doesn't need to ignore unknown ids. + void RemoveTransaction(int64_t id); + private: const int32_t id_; + // The process id of the child process this connection is associated with. + // Tracked for IndexedDBContextImpl::GetAllOriginsDetails and debugging. + const int child_process_id_; + // NULL in some unit tests, and after the connection is closed. scoped_refptr<IndexedDBDatabase> database_; + // The connection owns transactions created on this connection. + std::unordered_map<int64_t, std::unique_ptr<IndexedDBTransaction>> + transactions_; + // The callbacks_ member is cleared when the connection is closed. // May be NULL in unit tests. scoped_refptr<IndexedDBDatabaseCallbacks> callbacks_;
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc index 8300e147..449283c1 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.cc +++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -236,13 +236,8 @@ } transaction_info->SetDouble( - "pid", - IndexedDBDispatcherHost::TransactionIdToProcessId( - transaction->id())); - transaction_info->SetDouble( - "tid", - IndexedDBDispatcherHost::TransactionIdToRendererTransactionId( - transaction->id())); + "pid", transaction->connection()->child_process_id()); + transaction_info->SetDouble("tid", transaction->id()); transaction_info->SetDouble( "age", (base::Time::Now() - transaction->diagnostics().creation_time)
diff --git a/content/browser/indexed_db/indexed_db_cursor.cc b/content/browser/indexed_db/indexed_db_cursor.cc index f4b2c5f..005d5411 100644 --- a/content/browser/indexed_db/indexed_db_cursor.cc +++ b/content/browser/indexed_db/indexed_db_cursor.cc
@@ -18,6 +18,42 @@ #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h" namespace content { +namespace { +// This should never be script visible: the cursor should either be closed when +// it hits the end of the range (and script throws an error before the call +// could be made), if the transaction has finished (ditto), or if there's an +// incoming request from the front end but the transaction has aborted on the +// back end; in that case the tx will already have sent an abort to the request +// so this would be ignored. +IndexedDBDatabaseError CreateCursorClosedError() { + return IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, + "The cursor has been closed."); +} + +leveldb::Status InvokeOrSucceed(base::WeakPtr<IndexedDBCursor> weak_cursor, + IndexedDBTransaction::Operation operation, + IndexedDBTransaction* transaction) { + if (weak_cursor) + return operation.Run(transaction); + return leveldb::Status::OK(); +} + +// This allows us to bind a function with a return value to a weak ptr, and if +// the weak pointer is invalidated then we just return a default (success). +template <typename Functor, typename... Args> +IndexedDBTransaction::Operation BindWeakOperation( + Functor&& functor, + base::WeakPtr<IndexedDBCursor> weak_cursor, + Args&&... args) { + DCHECK(weak_cursor); + IndexedDBCursor* cursor_ptr = weak_cursor.get(); + return base::Bind( + &InvokeOrSucceed, std::move(weak_cursor), + base::Bind(std::forward<Functor>(functor), base::Unretained(cursor_ptr), + std::forward<Args>(args)...)); +} + +} // namespace IndexedDBCursor::IndexedDBCursor( std::unique_ptr<IndexedDBBackingStore::Cursor> cursor, @@ -28,13 +64,10 @@ cursor_type_(cursor_type), transaction_(transaction), cursor_(std::move(cursor)), - closed_(false) { - transaction_->RegisterOpenCursor(this); -} + closed_(false), + ptr_factory_(this) {} -IndexedDBCursor::~IndexedDBCursor() { - transaction_->UnregisterOpenCursor(this); -} +IndexedDBCursor::~IndexedDBCursor() {} void IndexedDBCursor::Continue(std::unique_ptr<IndexedDBKey> key, std::unique_ptr<IndexedDBKey> primary_key, @@ -42,19 +75,15 @@ IDB_TRACE("IndexedDBCursor::Continue"); if (closed_) { - callbacks->OnError( - IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, - "The cursor has been closed.")); + callbacks->OnError(CreateCursorClosedError()); return; } transaction_->ScheduleTask( task_type_, - base::Bind(&IndexedDBCursor::CursorIterationOperation, - this, - base::Passed(&key), - base::Passed(&primary_key), - callbacks)); + BindWeakOperation(&IndexedDBCursor::CursorIterationOperation, + ptr_factory_.GetWeakPtr(), base::Passed(&key), + base::Passed(&primary_key), callbacks)); } void IndexedDBCursor::Advance(uint32_t count, @@ -62,16 +91,19 @@ IDB_TRACE("IndexedDBCursor::Advance"); if (closed_) { - callbacks->OnError( - IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, - "The cursor has been closed.")); + callbacks->OnError(CreateCursorClosedError()); return; } transaction_->ScheduleTask( task_type_, - base::Bind( - &IndexedDBCursor::CursorAdvanceOperation, this, count, callbacks)); + BindWeakOperation(&IndexedDBCursor::CursorAdvanceOperation, + ptr_factory_.GetWeakPtr(), count, callbacks)); +} + +void IndexedDBCursor::RemoveCursorFromTransaction() { + if (transaction_) + transaction_->UnregisterOpenCursor(this); } leveldb::Status IndexedDBCursor::CursorAdvanceOperation( @@ -131,18 +163,14 @@ IDB_TRACE("IndexedDBCursor::PrefetchContinue"); if (closed_) { - callbacks->OnError( - IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, - "The cursor has been closed.")); + callbacks->OnError(CreateCursorClosedError()); return; } transaction_->ScheduleTask( task_type_, - base::Bind(&IndexedDBCursor::CursorPrefetchIterationOperation, - this, - number_to_fetch, - callbacks)); + BindWeakOperation(&IndexedDBCursor::CursorPrefetchIterationOperation, + ptr_factory_.GetWeakPtr(), number_to_fetch, callbacks)); } leveldb::Status IndexedDBCursor::CursorPrefetchIterationOperation( @@ -244,6 +272,7 @@ closed_ = true; cursor_.reset(); saved_cursor_.reset(); + transaction_ = nullptr; } } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_cursor.h b/content/browser/indexed_db/indexed_db_cursor.h index 72852f6..591f9f89 100644 --- a/content/browser/indexed_db/indexed_db_cursor.h +++ b/content/browser/indexed_db/indexed_db_cursor.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "content/browser/indexed_db/indexed_db_backing_store.h" #include "content/browser/indexed_db/indexed_db_database.h" #include "content/browser/indexed_db/indexed_db_transaction.h" @@ -20,13 +21,13 @@ namespace content { -class CONTENT_EXPORT IndexedDBCursor - : NON_EXPORTED_BASE(public base::RefCounted<IndexedDBCursor>) { +class CONTENT_EXPORT IndexedDBCursor { public: IndexedDBCursor(std::unique_ptr<IndexedDBBackingStore::Cursor> cursor, indexed_db::CursorType cursor_type, blink::WebIDBTaskType task_type, IndexedDBTransaction* transaction); + ~IndexedDBCursor(); void Advance(uint32_t count, scoped_refptr<IndexedDBCallbacks> callbacks); void Continue(std::unique_ptr<IndexedDBKey> key, @@ -42,6 +43,8 @@ return (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) ? NULL : cursor_->value(); } + + void RemoveCursorFromTransaction(); void Close(); leveldb::Status CursorIterationOperation( @@ -59,13 +62,11 @@ IndexedDBTransaction* transaction); private: - friend class base::RefCounted<IndexedDBCursor>; - - ~IndexedDBCursor(); - blink::WebIDBTaskType task_type_; indexed_db::CursorType cursor_type_; - const scoped_refptr<IndexedDBTransaction> transaction_; + + // We rely on the transaction calling Close() to clear this. + IndexedDBTransaction* transaction_; // Must be destroyed before transaction_. std::unique_ptr<IndexedDBBackingStore::Cursor> cursor_; @@ -74,6 +75,8 @@ bool closed_; + base::WeakPtrFactory<IndexedDBCursor> ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(IndexedDBCursor); };
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc index f15d312..b910f2b 100644 --- a/content/browser/indexed_db/indexed_db_database.cc +++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -70,6 +70,19 @@ return KEY_PATH_TYPE_NONE; } +// The database will be closed (IndexedDBFactory::ForceClose) during this call. +// This should NOT be used in an method scheduled as a transaction operation. +void ReportError(leveldb::Status status, + const url::Origin& origin, + IndexedDBFactory* factory, + const IndexedDBDatabaseError& error) { + DCHECK(!status.ok()); + if (status.IsCorruption()) + factory->HandleBackingStoreCorruption(origin, error); + else + factory->HandleBackingStoreFailure(origin); +} + } // namespace // This represents what script calls an 'IDBOpenDBRequest' - either a database @@ -464,7 +477,6 @@ } IndexedDBDatabase::~IndexedDBDatabase() { - DCHECK(transactions_.empty()); DCHECK(!active_request_); DCHECK(pending_requests_.empty()); } @@ -477,20 +489,13 @@ scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, int child_process_id) { std::unique_ptr<IndexedDBConnection> connection( - base::MakeUnique<IndexedDBConnection>(this, database_callbacks)); + base::MakeUnique<IndexedDBConnection>(child_process_id, this, + database_callbacks)); connections_.insert(connection.get()); backing_store_->GrantChildProcessPermissions(child_process_id); return connection; } -IndexedDBTransaction* IndexedDBDatabase::GetTransaction( - int64_t transaction_id) const { - const auto& trans_iterator = transactions_.find(transaction_id); - if (trans_iterator == transactions_.end()) - return NULL; - return trans_iterator->second; -} - bool IndexedDBDatabase::ValidateObjectStoreId(int64_t object_store_id) const { if (!base::ContainsKey(metadata_.object_stores, object_store_id)) { DLOG(ERROR) << "Invalid object_store_id"; @@ -542,15 +547,14 @@ return true; } -void IndexedDBDatabase::CreateObjectStore(int64_t transaction_id, +void IndexedDBDatabase::CreateObjectStore(IndexedDBTransaction* transaction, int64_t object_store_id, const base::string16& name, const IndexedDBKeyPath& key_path, bool auto_increment) { - IDB_TRACE1("IndexedDBDatabase::CreateObjectStore", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::CreateObjectStore", "txn.id", + transaction->id()); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); if (base::ContainsKey(metadata_.object_stores, object_store_id)) { @@ -585,9 +589,7 @@ blink::WebIDBDatabaseExceptionUnknownError, ASCIIToUTF16("Internal error creating object store '") + object_store_metadata.name + ASCIIToUTF16("'.")); - transaction->Abort(error); - if (s.IsCorruption()) - factory_->HandleBackingStoreCorruption(backing_store_->origin(), error); + ReportError(s, origin(), factory_.get(), error); return; } @@ -598,12 +600,11 @@ object_store_id)); } -void IndexedDBDatabase::DeleteObjectStore(int64_t transaction_id, +void IndexedDBDatabase::DeleteObjectStore(IndexedDBTransaction* transaction, int64_t object_store_id) { - IDB_TRACE1("IndexedDBDatabase::DeleteObjectStore", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::DeleteObjectStore", "txn.id", + transaction->id()); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); if (!ValidateObjectStoreId(object_store_id)) @@ -615,13 +616,12 @@ object_store_id)); } -void IndexedDBDatabase::RenameObjectStore(int64_t transaction_id, +void IndexedDBDatabase::RenameObjectStore(IndexedDBTransaction* transaction, int64_t object_store_id, const base::string16& new_name) { - IDB_TRACE1("IndexedDBDatabase::RenameObjectStore", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::RenameObjectStore", "txn.id", + transaction->id()); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); if (!ValidateObjectStoreId(object_store_id)) @@ -643,9 +643,7 @@ ASCIIToUTF16("Internal error renaming object store '") + object_store_metadata.name + ASCIIToUTF16("' to '") + new_name + ASCIIToUTF16("'.")); - transaction->Abort(error); - if (s.IsCorruption()) - factory_->HandleBackingStoreCorruption(backing_store_->origin(), error); + ReportError(s, origin(), factory_.get(), error); return; } @@ -657,17 +655,15 @@ SetObjectStoreName(object_store_id, new_name); } -void IndexedDBDatabase::CreateIndex(int64_t transaction_id, +void IndexedDBDatabase::CreateIndex(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, const base::string16& name, const IndexedDBKeyPath& key_path, bool unique, bool multi_entry) { - IDB_TRACE1("IndexedDBDatabase::CreateIndex", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::CreateIndex", "txn.id", transaction->id()); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id)) @@ -714,13 +710,11 @@ RemoveIndex(object_store_id, index_id); } -void IndexedDBDatabase::DeleteIndex(int64_t transaction_id, +void IndexedDBDatabase::DeleteIndex(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id) { - IDB_TRACE1("IndexedDBDatabase::DeleteIndex", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::DeleteIndex", "txn.id", transaction->id()); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id)) @@ -748,15 +742,8 @@ transaction->database()->id(), object_store_id, index_id); - if (!s.ok()) { - base::string16 error_string = - ASCIIToUTF16("Internal error deleting index '") + - index_metadata.name + ASCIIToUTF16("'."); - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - error_string); - transaction->Abort(error); + if (!s.ok()) return s; - } RemoveIndex(object_store_id, index_id); transaction->ScheduleAbortTask( @@ -774,14 +761,12 @@ AddIndex(object_store_id, index_metadata, IndexedDBIndexMetadata::kInvalidId); } -void IndexedDBDatabase::RenameIndex(int64_t transaction_id, +void IndexedDBDatabase::RenameIndex(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, const base::string16& new_name) { - IDB_TRACE1("IndexedDBDatabase::RenameIndex", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::RenameIndex", "txn.id", transaction->id()); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id)) @@ -806,11 +791,7 @@ ASCIIToUTF16("'."); IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, error_string); - transaction->Abort(error); - if (s.IsCorruption()) - factory_->HandleBackingStoreCorruption(origin(), error); - else - factory_->HandleBackingStoreFailure(origin()); + ReportError(s, origin(), factory_.get(), error); return; } @@ -831,67 +812,30 @@ SetIndexName(object_store_id, index_id, old_name); } -void IndexedDBDatabase::Commit(int64_t transaction_id) { +void IndexedDBDatabase::Commit(IndexedDBTransaction* transaction) { // The frontend suggests that we commit, but we may have previously initiated // an abort, and so have disposed of the transaction. on_abort has already // been dispatched to the frontend, so it will find out about that // asynchronously. - IndexedDBTransaction* transaction = GetTransaction(transaction_id); if (transaction) { scoped_refptr<IndexedDBFactory> factory = factory_; leveldb::Status result = transaction->Commit(); if (!result.ok()) { - if (result.IsCorruption()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - base::ASCIIToUTF16(result.ToString())); - factory->HandleBackingStoreCorruption(origin(), error); - } else { - factory->HandleBackingStoreFailure(origin()); - } + IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, + base::ASCIIToUTF16(result.ToString())); + ReportError(result, origin(), factory_.get(), error); } } } -void IndexedDBDatabase::Abort(int64_t transaction_id) { - // If the transaction is unknown, then it has already been aborted by the - // backend before this call so it is safe to ignore it. - IDB_TRACE1("IndexedDBDatabase::Abort", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (transaction) - transaction->Abort(); -} - -void IndexedDBDatabase::Abort(int64_t transaction_id, - const IndexedDBDatabaseError& error) { - IDB_TRACE1("IndexedDBDatabase::Abort(error)", "txn.id", transaction_id); - // If the transaction is unknown, then it has already been aborted by the - // backend before this call so it is safe to ignore it. - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (transaction) - transaction->Abort(error); -} - void IndexedDBDatabase::AddPendingObserver( - int64_t transaction_id, + IndexedDBTransaction* transaction, int32_t observer_id, const IndexedDBObserver::Options& options) { - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); transaction->AddPendingObserver(observer_id, options); } -void IndexedDBDatabase::RemovePendingObservers( - IndexedDBConnection* connection, - const std::vector<int32_t>& pending_observer_ids) { - for (const auto& it : transactions_) { - // Avoid call to RemovePendingObservers for transactions on other - // connections. - if (it.second->connection() == connection) - it.second->RemovePendingObservers(pending_observer_ids); - } -} - // TODO(palakj): Augment the function with IDBValue later. Issue // crbug.com/609934. void IndexedDBDatabase::FilterObservation(IndexedDBTransaction* transaction, @@ -928,17 +872,15 @@ } } -void IndexedDBDatabase::GetAll(int64_t transaction_id, +void IndexedDBDatabase::GetAll(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, bool key_only, int64_t max_count, scoped_refptr<IndexedDBCallbacks> callbacks) { - IDB_TRACE1("IndexedDBDatabase::GetAll", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::GetAll", "txn.id", transaction->id()); if (!ValidateObjectStoreId(object_store_id)) return; @@ -950,16 +892,14 @@ max_count, callbacks)); } -void IndexedDBDatabase::Get(int64_t transaction_id, +void IndexedDBDatabase::Get(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, bool key_only, scoped_refptr<IndexedDBCallbacks> callbacks) { - IDB_TRACE1("IndexedDBDatabase::Get", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::Get", "txn.id", transaction->id()); if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) return; @@ -1025,13 +965,8 @@ &s); } - if (!s.ok()) { - DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString(); - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error deleting data in range"); - callbacks->OnError(error); + if (!s.ok()) return s; - } if (!backing_store_cursor) { // This means we've run out of data. @@ -1051,12 +986,8 @@ object_store_id, *key, &value); - if (!s.ok()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error in GetRecord."); - callbacks->OnError(error); + if (!s.ok()) return s; - } if (value.empty()) { callbacks->OnSuccess(); @@ -1086,12 +1017,9 @@ index_id, *key, &primary_key); - if (!s.ok()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error in GetPrimaryKeyViaIndex."); - callbacks->OnError(error); + if (!s.ok()) return s; - } + if (!primary_key) { callbacks->OnSuccess(); return s; @@ -1109,12 +1037,8 @@ object_store_id, *primary_key, &value); - if (!s.ok()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error in GetRecord."); - callbacks->OnError(error); + if (!s.ok()) return s; - } if (value.empty()) { callbacks->OnSuccess(); @@ -1180,9 +1104,6 @@ if (!s.ok()) { DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString(); - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error in GetAllOperation"); - callbacks->OnError(error); return s; } @@ -1209,12 +1130,8 @@ cursor_valid = cursor->FirstSeek(&s); did_first_seek = true; } - if (!s.ok()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error in GetAllOperation."); - callbacks->OnError(error); + if (!s.ok()) return s; - } if (!cursor_valid) break; @@ -1310,7 +1227,7 @@ }; void IndexedDBDatabase::Put( - int64_t transaction_id, + IndexedDBTransaction* transaction, int64_t object_store_id, IndexedDBValue* value, std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles, @@ -1318,10 +1235,8 @@ blink::WebIDBPutMode put_mode, scoped_refptr<IndexedDBCallbacks> callbacks, const std::vector<IndexedDBIndexKeys>& index_keys) { - IDB_TRACE1("IndexedDBDatabase::Put", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::Put", "txn.id", transaction->id()); DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly); if (!ValidateObjectStoreId(object_store_id)) @@ -1385,12 +1300,8 @@ *key, &record_identifier, &found); - if (!s.ok()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error checking key existence."); - params->callbacks->OnError(error); + if (!s.ok()) return s; - } if (found) { params->callbacks->OnError( IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError, @@ -1429,13 +1340,9 @@ s = backing_store_->PutRecord(transaction->BackingStoreTransaction(), id(), params->object_store_id, *key, ¶ms->value, ¶ms->handles, &record_identifier); - if (!s.ok()) { - IndexedDBDatabaseError error( - blink::WebIDBDatabaseExceptionUnknownError, - "Internal error: backing store error performing put/add."); - params->callbacks->OnError(error); + if (!s.ok()) return s; - } + { IDB_TRACE1("IndexedDBDatabase::PutOperation.UpdateIndexes", "txn.id", transaction->id()); @@ -1453,12 +1360,8 @@ transaction->id()); s = UpdateKeyGenerator(backing_store_.get(), transaction, id(), params->object_store_id, *key, !key_was_generated); - if (!s.ok()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error updating key generator."); - params->callbacks->OnError(error); + if (!s.ok()) return s; - } } { IDB_TRACE1("IndexedDBDatabase::PutOperation.Callbacks", "txn.id", @@ -1474,15 +1377,12 @@ } void IndexedDBDatabase::SetIndexKeys( - int64_t transaction_id, + IndexedDBTransaction* transaction, int64_t object_store_id, std::unique_ptr<IndexedDBKey> primary_key, const std::vector<IndexedDBIndexKeys>& index_keys) { - IDB_TRACE1("IndexedDBDatabase::SetIndexKeys", "txn.id", transaction_id); - - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::SetIndexKeys", "txn.id", transaction->id()); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); // TODO(alecflett): This method could be asynchronous, but we need to @@ -1499,9 +1399,7 @@ if (!s.ok()) { IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, "Internal error setting index keys."); - transaction->Abort(error); - if (s.IsCorruption()) - factory_->HandleBackingStoreCorruption(backing_store_->origin(), error); + ReportError(s, origin(), factory_.get(), error); return; } if (!found) { @@ -1547,12 +1445,10 @@ } } -void IndexedDBDatabase::SetIndexesReady(int64_t transaction_id, +void IndexedDBDatabase::SetIndexesReady(IndexedDBTransaction* transaction, int64_t, const std::vector<int64_t>& index_ids) { - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange); transaction->ScheduleTask( @@ -1585,7 +1481,7 @@ }; void IndexedDBDatabase::OpenCursor( - int64_t transaction_id, + IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, @@ -1593,10 +1489,8 @@ bool key_only, blink::WebIDBTaskType task_type, scoped_refptr<IndexedDBCallbacks> callbacks) { - IDB_TRACE1("IndexedDBDatabase::OpenCursor", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::OpenCursor", "txn.id", transaction->id()); if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) return; @@ -1674,8 +1568,6 @@ if (!s.ok()) { DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString(); - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error opening cursor operation"); return s; } @@ -1685,23 +1577,23 @@ return s; } - scoped_refptr<IndexedDBCursor> cursor = - new IndexedDBCursor(std::move(backing_store_cursor), params->cursor_type, - params->task_type, transaction); - params->callbacks->OnSuccess( - cursor, cursor->key(), cursor->primary_key(), cursor->Value()); + std::unique_ptr<IndexedDBCursor> cursor = base::MakeUnique<IndexedDBCursor>( + std::move(backing_store_cursor), params->cursor_type, params->task_type, + transaction); + IndexedDBCursor* cursor_ptr = cursor.get(); + transaction->RegisterOpenCursor(cursor_ptr); + params->callbacks->OnSuccess(std::move(cursor), cursor_ptr->key(), + cursor_ptr->primary_key(), cursor_ptr->Value()); return s; } -void IndexedDBDatabase::Count(int64_t transaction_id, +void IndexedDBDatabase::Count(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, scoped_refptr<IndexedDBCallbacks> callbacks) { - IDB_TRACE1("IndexedDBDatabase::Count", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::Count", "txn.id", transaction->id()); if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) return; @@ -1745,8 +1637,6 @@ } if (!s.ok()) { DLOG(ERROR) << "Unable perform count operation: " << s.ToString(); - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error performing count operation"); return s; } if (!backing_store_cursor) { @@ -1765,14 +1655,12 @@ } void IndexedDBDatabase::DeleteRange( - int64_t transaction_id, + IndexedDBTransaction* transaction, int64_t object_store_id, std::unique_ptr<IndexedDBKeyRange> key_range, scoped_refptr<IndexedDBCallbacks> callbacks) { - IDB_TRACE1("IndexedDBDatabase::DeleteRange", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::DeleteRange", "txn.id", transaction->id()); DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly); if (!ValidateObjectStoreId(object_store_id)) @@ -1796,27 +1684,19 @@ leveldb::Status s = backing_store_->DeleteRange(transaction->BackingStoreTransaction(), id(), object_store_id, *key_range, &delete_count); - if (!s.ok()) { - base::string16 error_string = - ASCIIToUTF16("Internal error deleting data in range"); - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - error_string); - transaction->Abort(error); + if (!s.ok()) return s; - } callbacks->OnSuccess(); FilterObservation(transaction, object_store_id, blink::WebIDBDelete, *key_range); return s; } -void IndexedDBDatabase::Clear(int64_t transaction_id, +void IndexedDBDatabase::Clear(IndexedDBTransaction* transaction, int64_t object_store_id, scoped_refptr<IndexedDBCallbacks> callbacks) { - IDB_TRACE1("IndexedDBDatabase::Clear", "txn.id", transaction_id); - IndexedDBTransaction* transaction = GetTransaction(transaction_id); - if (!transaction) - return; + DCHECK(transaction); + IDB_TRACE1("IndexedDBDatabase::Clear", "txn.id", transaction->id()); DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly); if (!ValidateObjectStoreId(object_store_id)) @@ -1833,12 +1713,8 @@ IDB_TRACE1("IndexedDBDatabase::ClearOperation", "txn.id", transaction->id()); leveldb::Status s = backing_store_->ClearObjectStore( transaction->BackingStoreTransaction(), id(), object_store_id); - if (!s.ok()) { - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - "Internal error clearing object store"); - callbacks->OnError(error); + if (!s.ok()) return s; - } callbacks->OnSuccess(); FilterObservation(transaction, object_store_id, blink::WebIDBClear, @@ -1859,15 +1735,8 @@ backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(), transaction->database()->id(), object_store_id); - if (!s.ok()) { - base::string16 error_string = - ASCIIToUTF16("Internal error deleting object store '") + - object_store_metadata.name + ASCIIToUTF16("'."); - IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, - error_string); - transaction->Abort(error); + if (!s.ok()) return s; - } RemoveObjectStore(object_store_id); transaction->ScheduleAbortTask( @@ -1900,10 +1769,10 @@ void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction, bool committed) { - IDB_TRACE1("IndexedDBTransaction::TransactionFinished", "txn.id", id()); - DCHECK(transactions_.find(transaction->id()) != transactions_.end()); - DCHECK_EQ(transactions_[transaction->id()], transaction); - transactions_.erase(transaction->id()); + IDB_TRACE1("IndexedDBTransaction::TransactionFinished", "txn.id", + transaction->id()); + --transaction_count_; + DCHECK_GE(transaction_count_, 0); // This may be an unrelated transaction finishing while waiting for // connections to close, or the actual upgrade transaction from an active @@ -1956,27 +1825,22 @@ blink::WebIDBTransactionMode mode) { IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id); DCHECK(connections_.count(connection)); - DCHECK(transactions_.find(transaction_id) == transactions_.end()); - if (transactions_.find(transaction_id) != transactions_.end()) - return nullptr; UMA_HISTOGRAM_COUNTS_1000( "WebCore.IndexedDB.Database.OutstandingTransactionCount", - transactions_.size()); + transaction_count_); - // The transaction will add itself to this database's coordinator, which - // manages the lifetime of the object. - IndexedDBTransaction* transaction = - IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( - transaction_id, connection->GetWeakPtr(), - std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), - mode, new IndexedDBBackingStore::Transaction(backing_store_.get())); + IndexedDBTransaction* transaction = connection->CreateTransaction( + transaction_id, + std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), mode, + new IndexedDBBackingStore::Transaction(backing_store_.get())); TransactionCreated(transaction); return transaction; } void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) { - transactions_[transaction->id()] = transaction; + transaction_count_++; + transaction_coordinator_.DidCreateTransaction(transaction); } void IndexedDBDatabase::OpenConnection( @@ -2016,15 +1880,8 @@ // happen if the close is requested by the connection itself as the // front-end defers the close until all transactions are complete, but can // occur on process termination or forced close. - { - auto transactions(transactions_); - for (const auto& it : transactions) { - if (it.second->callbacks() == connection->callbacks()) - it.second->Abort( - IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, - "Connection is closing.")); - } - } + connection->AbortAllTransactions(IndexedDBDatabaseError( + blink::WebIDBDatabaseExceptionUnknownError, "Connection is closing.")); // Abort transactions before removing the connection; aborting may complete // an upgrade, and thus allow the next open/delete requests to proceed. The @@ -2041,7 +1898,6 @@ // If there are no more connections (current, active, or pending), tell the // factory to clean us up. if (connections_.empty() && !active_request_ && pending_requests_.empty()) { - DCHECK(transactions_.empty()); backing_store_ = nullptr; factory_->ReleaseDatabase(identifier_, forced); }
diff --git a/content/browser/indexed_db/indexed_db_database.h b/content/browser/indexed_db/indexed_db_database.h index 1dc57be..1a82f30 100644 --- a/content/browser/indexed_db/indexed_db_database.h +++ b/content/browser/indexed_db/indexed_db_database.h
@@ -82,13 +82,14 @@ void DeleteDatabase(scoped_refptr<IndexedDBCallbacks> callbacks); const IndexedDBDatabaseMetadata& metadata() const { return metadata_; } - void CreateObjectStore(int64_t transaction_id, + void CreateObjectStore(IndexedDBTransaction* transaction, int64_t object_store_id, const base::string16& name, const IndexedDBKeyPath& key_path, bool auto_increment); - void DeleteObjectStore(int64_t transaction_id, int64_t object_store_id); - void RenameObjectStore(int64_t transaction_id, + void DeleteObjectStore(IndexedDBTransaction* transaction, + int64_t object_store_id); + void RenameObjectStore(IndexedDBTransaction* transaction, int64_t object_store_id, const base::string16& new_name); @@ -107,21 +108,19 @@ // pending connection. void VersionChangeIgnored(); - void Commit(int64_t transaction_id); - void Abort(int64_t transaction_id); - void Abort(int64_t transaction_id, const IndexedDBDatabaseError& error); + void Commit(IndexedDBTransaction* transaction); - void CreateIndex(int64_t transaction_id, + void CreateIndex(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, const base::string16& name, const IndexedDBKeyPath& key_path, bool unique, bool multi_entry); - void DeleteIndex(int64_t transaction_id, + void DeleteIndex(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id); - void RenameIndex(int64_t transaction_id, + void RenameIndex(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, const base::string16& new_name); @@ -136,11 +135,9 @@ void TransactionCreated(IndexedDBTransaction* transaction); void TransactionFinished(IndexedDBTransaction* transaction, bool committed); - void AddPendingObserver(int64_t transaction_id, + void AddPendingObserver(IndexedDBTransaction* transaction, int32_t observer_id, const IndexedDBObserver::Options& options); - void RemovePendingObservers(IndexedDBConnection* connection, - const std::vector<int32_t>& pending_observer_ids); void FilterObservation(IndexedDBTransaction*, int64_t object_store_id, @@ -149,20 +146,20 @@ void SendObservations( std::map<int32_t, ::indexed_db::mojom::ObserverChangesPtr> change_map); - void Get(int64_t transaction_id, + void Get(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, bool key_only, scoped_refptr<IndexedDBCallbacks> callbacks); - void GetAll(int64_t transaction_id, + void GetAll(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, bool key_only, int64_t max_count, scoped_refptr<IndexedDBCallbacks> callbacks); - void Put(int64_t transaction_id, + void Put(IndexedDBTransaction* transaction, int64_t object_store_id, IndexedDBValue* value, std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles, @@ -170,14 +167,14 @@ blink::WebIDBPutMode mode, scoped_refptr<IndexedDBCallbacks> callbacks, const std::vector<IndexedDBIndexKeys>& index_keys); - void SetIndexKeys(int64_t transaction_id, + void SetIndexKeys(IndexedDBTransaction* transaction, int64_t object_store_id, std::unique_ptr<IndexedDBKey> primary_key, const std::vector<IndexedDBIndexKeys>& index_keys); - void SetIndexesReady(int64_t transaction_id, + void SetIndexesReady(IndexedDBTransaction* transaction, int64_t object_store_id, const std::vector<int64_t>& index_ids); - void OpenCursor(int64_t transaction_id, + void OpenCursor(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, @@ -185,16 +182,16 @@ bool key_only, blink::WebIDBTaskType task_type, scoped_refptr<IndexedDBCallbacks> callbacks); - void Count(int64_t transaction_id, + void Count(IndexedDBTransaction* transaction, int64_t object_store_id, int64_t index_id, std::unique_ptr<IndexedDBKeyRange> key_range, scoped_refptr<IndexedDBCallbacks> callbacks); - void DeleteRange(int64_t transaction_id, + void DeleteRange(IndexedDBTransaction* transaction, int64_t object_store_id, std::unique_ptr<IndexedDBKeyRange> key_range, scoped_refptr<IndexedDBCallbacks> callbacks); - void Clear(int64_t transaction_id, + void Clear(IndexedDBTransaction* transaction, int64_t object_store_id, scoped_refptr<IndexedDBCallbacks> callbacks); @@ -306,8 +303,6 @@ scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, int child_process_id); - IndexedDBTransaction* GetTransaction(int64_t transaction_id) const; - bool ValidateObjectStoreId(int64_t object_store_id) const; bool ValidateObjectStoreIdAndIndexId(int64_t object_store_id, int64_t index_id) const; @@ -323,8 +318,7 @@ scoped_refptr<IndexedDBFactory> factory_; IndexedDBTransactionCoordinator transaction_coordinator_; - - std::map<int64_t, IndexedDBTransaction*> transactions_; + int64_t transaction_count_ = 0; list_set<IndexedDBConnection*> connections_;
diff --git a/content/browser/indexed_db/indexed_db_database_callbacks.cc b/content/browser/indexed_db/indexed_db_database_callbacks.cc index 90daa5ff..bc7e6b9 100644 --- a/content/browser/indexed_db/indexed_db_database_callbacks.cc +++ b/content/browser/indexed_db/indexed_db_database_callbacks.cc
@@ -7,6 +7,7 @@ #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/indexed_db/indexed_db_database_error.h" #include "content/browser/indexed_db/indexed_db_dispatcher_host.h" +#include "content/browser/indexed_db/indexed_db_transaction.h" using ::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo; @@ -67,33 +68,33 @@ base::Unretained(io_helper_.get()), old_version, new_version)); } -void IndexedDBDatabaseCallbacks::OnAbort(int64_t host_transaction_id, - const IndexedDBDatabaseError& error) { +void IndexedDBDatabaseCallbacks::OnAbort( + const IndexedDBTransaction& transaction, + const IndexedDBDatabaseError& error) { DCHECK(thread_checker_.CalledOnValidThread()); if (!dispatcher_host_) return; - dispatcher_host_->FinishTransaction(host_transaction_id, false); DCHECK(io_helper_); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&IOThreadHelper::SendAbort, base::Unretained(io_helper_.get()), - dispatcher_host_->RendererTransactionId(host_transaction_id), - error)); + transaction.id(), error)); } -void IndexedDBDatabaseCallbacks::OnComplete(int64_t host_transaction_id) { +void IndexedDBDatabaseCallbacks::OnComplete( + const IndexedDBTransaction& transaction) { DCHECK(thread_checker_.CalledOnValidThread()); if (!dispatcher_host_) return; - dispatcher_host_->FinishTransaction(host_transaction_id, true); + dispatcher_host_->context()->TransactionComplete( + transaction.database()->origin()); DCHECK(io_helper_); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&IOThreadHelper::SendComplete, - base::Unretained(io_helper_.get()), - dispatcher_host_->RendererTransactionId(host_transaction_id))); + base::Unretained(io_helper_.get()), transaction.id())); } void IndexedDBDatabaseCallbacks::OnDatabaseChange(
diff --git a/content/browser/indexed_db/indexed_db_database_callbacks.h b/content/browser/indexed_db/indexed_db_database_callbacks.h index 23298cde..1978d72 100644 --- a/content/browser/indexed_db/indexed_db_database_callbacks.h +++ b/content/browser/indexed_db/indexed_db_database_callbacks.h
@@ -17,6 +17,7 @@ namespace content { class IndexedDBDatabaseError; class IndexedDBDispatcherHost; +class IndexedDBTransaction; class CONTENT_EXPORT IndexedDBDatabaseCallbacks : public base::RefCounted<IndexedDBDatabaseCallbacks> { @@ -28,9 +29,9 @@ virtual void OnForcedClose(); virtual void OnVersionChange(int64_t old_version, int64_t new_version); - virtual void OnAbort(int64_t host_transaction_id, + virtual void OnAbort(const IndexedDBTransaction& transaction, const IndexedDBDatabaseError& error); - virtual void OnComplete(int64_t host_transaction_id); + virtual void OnComplete(const IndexedDBTransaction& transaction); virtual void OnDatabaseChange( ::indexed_db::mojom::ObserverChangesPtr changes);
diff --git a/content/browser/indexed_db/indexed_db_database_unittest.cc b/content/browser/indexed_db/indexed_db_database_unittest.cc index 7b322ef..5d85503 100644 --- a/content/browser/indexed_db/indexed_db_database_unittest.cc +++ b/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -361,13 +361,13 @@ db_->OpenConnection(std::move(connection)); EXPECT_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata().version); - connection_ = base::MakeUnique<IndexedDBConnection>(db_, callbacks_); - transaction_ = IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( - transaction_id, connection_->GetWeakPtr(), - std::set<int64_t>() /*scope*/, + connection_ = base::MakeUnique<IndexedDBConnection>(kFakeChildProcessId, + db_, callbacks_); + transaction_ = connection_->CreateTransaction( + transaction_id, std::set<int64_t>() /*scope*/, blink::WebIDBTransactionModeVersionChange, new IndexedDBFakeBackingStore::FakeTransaction(commit_success_)); - db_->TransactionCreated(transaction_.get()); + db_->TransactionCreated(transaction_); // Add a dummy task which takes the place of the VersionChangeOperation // which kicks off the upgrade. This ensures that the transaction has @@ -382,7 +382,7 @@ scoped_refptr<IndexedDBDatabase> db_; scoped_refptr<MockIndexedDBCallbacks> request_; scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks_; - scoped_refptr<IndexedDBTransaction> transaction_; + IndexedDBTransaction* transaction_; std::unique_ptr<IndexedDBConnection> connection_; leveldb::Status commit_success_; @@ -397,11 +397,8 @@ TEST_F(IndexedDBDatabaseOperationTest, CreateObjectStore) { EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); const int64_t store_id = 1001; - db_->CreateObjectStore(transaction_->id(), - store_id, - ASCIIToUTF16("store"), - IndexedDBKeyPath(), - false /*auto_increment*/); + db_->CreateObjectStore(transaction_, store_id, ASCIIToUTF16("store"), + IndexedDBKeyPath(), false /*auto_increment*/); EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); RunPostedTasks(); transaction_->Commit(); @@ -411,20 +408,12 @@ TEST_F(IndexedDBDatabaseOperationTest, CreateIndex) { EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); const int64_t store_id = 1001; - db_->CreateObjectStore(transaction_->id(), - store_id, - ASCIIToUTF16("store"), - IndexedDBKeyPath(), - false /*auto_increment*/); + db_->CreateObjectStore(transaction_, store_id, ASCIIToUTF16("store"), + IndexedDBKeyPath(), false /*auto_increment*/); EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); const int64_t index_id = 2002; - db_->CreateIndex(transaction_->id(), - store_id, - index_id, - ASCIIToUTF16("index"), - IndexedDBKeyPath(), - false /*unique*/, - false /*multi_entry*/); + db_->CreateIndex(transaction_, store_id, index_id, ASCIIToUTF16("index"), + IndexedDBKeyPath(), false /*unique*/, false /*multi_entry*/); EXPECT_EQ( 1ULL, db_->metadata().object_stores.find(store_id)->second.indexes.size()); @@ -450,11 +439,8 @@ TEST_F(IndexedDBDatabaseOperationAbortTest, CreateObjectStore) { EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); const int64_t store_id = 1001; - db_->CreateObjectStore(transaction_->id(), - store_id, - ASCIIToUTF16("store"), - IndexedDBKeyPath(), - false /*auto_increment*/); + db_->CreateObjectStore(transaction_, store_id, ASCIIToUTF16("store"), + IndexedDBKeyPath(), false /*auto_increment*/); EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); RunPostedTasks(); transaction_->Commit(); @@ -464,20 +450,12 @@ TEST_F(IndexedDBDatabaseOperationAbortTest, CreateIndex) { EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); const int64_t store_id = 1001; - db_->CreateObjectStore(transaction_->id(), - store_id, - ASCIIToUTF16("store"), - IndexedDBKeyPath(), - false /*auto_increment*/); + db_->CreateObjectStore(transaction_, store_id, ASCIIToUTF16("store"), + IndexedDBKeyPath(), false /*auto_increment*/); EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); const int64_t index_id = 2002; - db_->CreateIndex(transaction_->id(), - store_id, - index_id, - ASCIIToUTF16("index"), - IndexedDBKeyPath(), - false /*unique*/, - false /*multi_entry*/); + db_->CreateIndex(transaction_, store_id, index_id, ASCIIToUTF16("index"), + IndexedDBKeyPath(), false /*unique*/, false /*multi_entry*/); EXPECT_EQ( 1ULL, db_->metadata().object_stores.find(store_id)->second.indexes.size()); @@ -491,11 +469,8 @@ const int64_t store_id = 1001; // Creation is synchronous. - db_->CreateObjectStore(transaction_->id(), - store_id, - ASCIIToUTF16("store"), - IndexedDBKeyPath(), - false /*auto_increment*/); + db_->CreateObjectStore(transaction_, store_id, ASCIIToUTF16("store"), + IndexedDBKeyPath(), false /*auto_increment*/); EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); @@ -506,12 +481,11 @@ std::vector<IndexedDBIndexKeys> index_keys; scoped_refptr<MockIndexedDBCallbacks> request( new MockIndexedDBCallbacks(false)); - db_->Put(transaction_->id(), store_id, &value, &handles, std::move(key), + db_->Put(transaction_, store_id, &value, &handles, std::move(key), blink::WebIDBPutModeAddOnly, request, index_keys); // Deletion is asynchronous. - db_->DeleteObjectStore(transaction_->id(), - store_id); + db_->DeleteObjectStore(transaction_, store_id); EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); // This will execute the Put then Delete.
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc index 7461b76e..8e5b198 100644 --- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc +++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -100,61 +100,6 @@ return false; } -bool IndexedDBDispatcherHost::RegisterTransactionId(int64_t host_transaction_id, - const url::Origin& origin) { - if (base::ContainsKey(transaction_size_map_, host_transaction_id)) - return false; - transaction_size_map_[host_transaction_id] = 0; - transaction_origin_map_[host_transaction_id] = origin; - return true; -} - -bool IndexedDBDispatcherHost::GetTransactionSize(int64_t host_transaction_id, - int64_t* transaction_size) { - const auto it = transaction_size_map_.find(host_transaction_id); - if (it == transaction_size_map_.end()) - return false; - *transaction_size = it->second; - return true; -} - -void IndexedDBDispatcherHost::AddToTransaction(int64_t host_transaction_id, - int64_t value_length) { - transaction_size_map_[host_transaction_id] += value_length; -} - -int64_t IndexedDBDispatcherHost::HostTransactionId(int64_t transaction_id) { - // Inject the renderer process id into the transaction id, to - // uniquely identify this transaction, and effectively bind it to - // the renderer that initiated it. The lower 32 bits of - // transaction_id are guaranteed to be unique within that renderer. - base::ProcessId pid = peer_pid(); - DCHECK(!(transaction_id >> 32)) << "Transaction ids can only be 32 bits"; - static_assert(sizeof(base::ProcessId) <= sizeof(int32_t), - "Process ID must fit in 32 bits"); - - return transaction_id | (static_cast<uint64_t>(pid) << 32); -} - -int64_t IndexedDBDispatcherHost::RendererTransactionId( - int64_t host_transaction_id) { - DCHECK(host_transaction_id >> 32 == peer_pid()) - << "Invalid renderer target for transaction id"; - return host_transaction_id & 0xffffffff; -} - -// static -uint32_t IndexedDBDispatcherHost::TransactionIdToRendererTransactionId( - int64_t host_transaction_id) { - return host_transaction_id & 0xffffffff; -} - -// static -uint32_t IndexedDBDispatcherHost::TransactionIdToProcessId( - int64_t host_transaction_id) { - return (host_transaction_id >> 32) & 0xffffffff; -} - std::string IndexedDBDispatcherHost::HoldBlobData( const IndexedDBBlobInfo& blob_info) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -286,15 +231,12 @@ base::TimeTicks begin_time = base::TimeTicks::Now(); base::FilePath indexed_db_path = indexed_db_context_->data_path(); - int64_t host_transaction_id = HostTransactionId(transaction_id); - // TODO(dgrogan): Don't let a non-existing database be opened (and therefore // created) if this origin is already over quota. callbacks->SetConnectionOpenStartTime(begin_time); - callbacks->set_host_transaction_id(host_transaction_id); std::unique_ptr<IndexedDBPendingConnection> connection = base::MakeUnique<IndexedDBPendingConnection>( - callbacks, database_callbacks, ipc_process_id_, host_transaction_id, + callbacks, database_callbacks, ipc_process_id_, transaction_id, version); DCHECK(request_context_getter_); context()->GetIDBFactory()->Open(name, std::move(connection), @@ -314,15 +256,4 @@ name, request_context_getter_, callbacks, origin, indexed_db_path); } -void IndexedDBDispatcherHost::FinishTransaction(int64_t host_transaction_id, - bool committed) { - DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread()); - if (committed) { - context()->TransactionComplete( - transaction_origin_map_[host_transaction_id]); - } - transaction_origin_map_.erase(host_transaction_id); - transaction_size_map_.erase(host_transaction_id); -} - } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.h b/content/browser/indexed_db/indexed_db_dispatcher_host.h index 28f1966..33a55d74 100644 --- a/content/browser/indexed_db/indexed_db_dispatcher_host.h +++ b/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -21,7 +21,6 @@ #include "content/public/browser/browser_message_filter.h" #include "net/url_request/url_request_context_getter.h" #include "storage/browser/blob/blob_data_handle.h" -#include "url/gurl.h" namespace url { class Origin; @@ -50,8 +49,6 @@ void OnDestruct() const override; bool OnMessageReceived(const IPC::Message& message) override; - void FinishTransaction(int64_t host_transaction_id, bool committed); - // A shortcut for accessing our context. IndexedDBContextImpl* context() const { return indexed_db_context_.get(); } storage::BlobStorageContext* blob_storage_context() const { @@ -59,23 +56,6 @@ } int ipc_process_id() const { return ipc_process_id_; } - bool RegisterTransactionId(int64_t host_transaction_id, - const url::Origin& origin); - bool GetTransactionSize(int64_t host_transaction_id, - int64_t* transaction_size); - void AddToTransaction(int64_t host_transaction_id, int64_t value_length); - - // These are called to map a 32-bit front-end (renderer-specific) transaction - // id to and from a back-end ("host") transaction id that encodes the process - // id in the high 32 bits. The mapping is host-specific and ids are validated. - int64_t HostTransactionId(int64_t transaction_id); - int64_t RendererTransactionId(int64_t host_transaction_id); - - // These are called to decode a host transaction ID, for diagnostic purposes. - static uint32_t TransactionIdToRendererTransactionId( - int64_t host_transaction_id); - static uint32_t TransactionIdToProcessId(int64_t host_transaction_id); - std::string HoldBlobData(const IndexedDBBlobInfo& blob_info); void DropBlobData(const std::string& uuid); @@ -88,10 +68,6 @@ friend class BrowserThread; friend class base::DeleteHelper<IndexedDBDispatcherHost>; - // Used in nested classes. - typedef std::map<int64_t, int64_t> TransactionIDToSizeMap; - typedef std::map<int64_t, url::Origin> TransactionIDToOriginMap; - ~IndexedDBDispatcherHost() override; // indexed_db::mojom::Factory implementation: @@ -138,8 +114,6 @@ // Only access on IndexedDB thread. bool is_open_ = true; - TransactionIDToSizeMap transaction_size_map_; - TransactionIDToOriginMap transaction_origin_map_; // Used to set file permissions for blob storage. int ipc_process_id_;
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc index 24c25bf..6494017 100644 --- a/content/browser/indexed_db/indexed_db_factory_unittest.cc +++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -469,7 +469,7 @@ // Open at version 2, then close. { - scoped_refptr<MockIndexedDBCallbacks> callbacks( + scoped_refptr<UpgradeNeededCallbacks> callbacks( new UpgradeNeededCallbacks()); std::unique_ptr<IndexedDBPendingConnection> connection( base::MakeUnique<IndexedDBPendingConnection>( @@ -483,7 +483,8 @@ // Pump the message loop so the upgrade transaction can run. base::RunLoop().RunUntilIdle(); EXPECT_TRUE(callbacks->connection()); - callbacks->connection()->database()->Commit(transaction_id); + callbacks->connection()->database()->Commit( + callbacks->connection()->GetTransaction(transaction_id)); callbacks->connection()->Close(); EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name));
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.cc b/content/browser/indexed_db/indexed_db_fake_backing_store.cc index cd61ebb..d89073d 100644 --- a/content/browser/indexed_db/indexed_db_fake_backing_store.cc +++ b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
@@ -218,7 +218,7 @@ void IndexedDBFakeBackingStore::FakeTransaction::Begin() {} leveldb::Status IndexedDBFakeBackingStore::FakeTransaction::CommitPhaseOne( scoped_refptr<BlobWriteCallback> callback) { - callback->Run(true); + callback->Run(IndexedDBBackingStore::BlobWriteResult::SUCCESS_SYNC); return leveldb::Status::OK(); } leveldb::Status IndexedDBFakeBackingStore::FakeTransaction::CommitPhaseTwo() {
diff --git a/content/browser/indexed_db/indexed_db_pending_connection.cc b/content/browser/indexed_db/indexed_db_pending_connection.cc index 34f49242..0f6dcea 100644 --- a/content/browser/indexed_db/indexed_db_pending_connection.cc +++ b/content/browser/indexed_db/indexed_db_pending_connection.cc
@@ -7,16 +7,16 @@ namespace content { IndexedDBPendingConnection::IndexedDBPendingConnection( - scoped_refptr<IndexedDBCallbacks> callbacks_in, - scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks_in, - int child_process_id_in, - int64_t transaction_id_in, - int64_t version_in) - : callbacks(callbacks_in), - database_callbacks(database_callbacks_in), - child_process_id(child_process_id_in), - transaction_id(transaction_id_in), - version(version_in) {} + scoped_refptr<IndexedDBCallbacks> callbacks, + scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, + int child_process_id, + int64_t transaction_id, + int64_t version) + : callbacks(callbacks), + database_callbacks(database_callbacks), + child_process_id(child_process_id), + transaction_id(transaction_id), + version(version) {} IndexedDBPendingConnection::IndexedDBPendingConnection( const IndexedDBPendingConnection& other) = default;
diff --git a/content/browser/indexed_db/indexed_db_pending_connection.h b/content/browser/indexed_db/indexed_db_pending_connection.h index 6458a7e..b434ad4 100644 --- a/content/browser/indexed_db/indexed_db_pending_connection.h +++ b/content/browser/indexed_db/indexed_db_pending_connection.h
@@ -12,6 +12,7 @@ #include "content/browser/indexed_db/indexed_db_data_loss_info.h" #include "content/browser/indexed_db/indexed_db_database_callbacks.h" #include "content/common/content_export.h" +#include "url/origin.h" namespace content { @@ -20,11 +21,11 @@ struct CONTENT_EXPORT IndexedDBPendingConnection { IndexedDBPendingConnection( - scoped_refptr<IndexedDBCallbacks> callbacks_in, - scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks_in, - int child_process_id_in, - int64_t transaction_id_in, - int64_t version_in); + scoped_refptr<IndexedDBCallbacks> callbacks, + scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, + int child_process_id, + int64_t transaction_id, + int64_t version); IndexedDBPendingConnection(const IndexedDBPendingConnection& other); ~IndexedDBPendingConnection(); scoped_refptr<IndexedDBCallbacks> callbacks;
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc index 40de131..064d5a0 100644 --- a/content/browser/indexed_db/indexed_db_transaction.cc +++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -30,7 +30,9 @@ // Helper for posting a task to call IndexedDBTransaction::Commit when we know // the transaction had no requests and therefore the commit must succeed. -void CommitUnused(scoped_refptr<IndexedDBTransaction> transaction) { +void CommitUnused(base::WeakPtr<IndexedDBTransaction> transaction) { + if (!transaction) + return; leveldb::Status status = transaction->Commit(); DCHECK(status.ok()); } @@ -85,7 +87,7 @@ IndexedDBTransaction::IndexedDBTransaction( int64_t id, - base::WeakPtr<IndexedDBConnection> connection, + IndexedDBConnection* connection, const std::set<int64_t>& object_store_ids, blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction) @@ -93,12 +95,11 @@ object_store_ids_(object_store_ids), mode_(mode), connection_(std::move(connection)), - transaction_(backing_store_transaction) { + transaction_(backing_store_transaction), + ptr_factory_(this) { callbacks_ = connection_->callbacks(); database_ = connection_->database(); - database_->transaction_coordinator().DidCreateTransaction(this); - diagnostics_.tasks_scheduled = 0; diagnostics_.tasks_completed = 0; diagnostics_.creation_time = base::Time::Now(); @@ -112,7 +113,6 @@ DCHECK_EQ(pending_preemptive_events_, 0); DCHECK(task_queue_.empty()); DCHECK(abort_task_stack_.empty()); - DCHECK(pending_observers_.empty()); DCHECK(!processing_event_queue_); } @@ -152,7 +152,8 @@ should_process_queue_ = true; base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this)); + FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, + ptr_factory_.GetWeakPtr())); } void IndexedDBTransaction::Abort() { @@ -162,14 +163,10 @@ void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) { IDB_TRACE1("IndexedDBTransaction::Abort", "txn.id", id()); + DCHECK(!processing_event_queue_); if (state_ == FINISHED) return; - // The last reference to this object may be released while performing the - // abort steps below. We therefore take a self reference to keep ourselves - // alive while executing this method. - scoped_refptr<IndexedDBTransaction> protect(this); - timeout_timer_.Stop(); state_ = FINISHED; @@ -202,13 +199,12 @@ #endif if (callbacks_.get()) - callbacks_->OnAbort(id_, error); + callbacks_->OnAbort(*this, error); database_->TransactionFinished(this, false); - database_ = NULL; - connection_ = nullptr; - pending_observers_.clear(); + // RemoveTransaction will delete |this|. + connection_->RemoveTransaction(id_); } bool IndexedDBTransaction::IsTaskQueueEmpty() const { @@ -239,7 +235,7 @@ // front-end previously requested a commit; do the commit now, but not // re-entrantly as that may renter the coordinator. base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&CommitUnused, make_scoped_refptr(this))); + FROM_HERE, base::Bind(&CommitUnused, ptr_factory_.GetWeakPtr())); } return; } @@ -250,35 +246,50 @@ class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback { public: explicit BlobWriteCallbackImpl( - scoped_refptr<IndexedDBTransaction> transaction) - : transaction_(transaction) {} - void Run(bool succeeded) override { - transaction_->BlobWriteComplete(succeeded); + base::WeakPtr<IndexedDBTransaction> transaction) + : transaction_(std::move(transaction)) {} + + leveldb::Status Run(IndexedDBBackingStore::BlobWriteResult result) override { + if (!transaction_) + return leveldb::Status::OK(); + return transaction_->BlobWriteComplete(result); } protected: ~BlobWriteCallbackImpl() override {} private: - scoped_refptr<IndexedDBTransaction> transaction_; + base::WeakPtr<IndexedDBTransaction> transaction_; }; -void IndexedDBTransaction::BlobWriteComplete(bool success) { +leveldb::Status IndexedDBTransaction::BlobWriteComplete( + IndexedDBBackingStore::BlobWriteResult result) { IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); if (state_ == FINISHED) // aborted - return; + return leveldb::Status::OK(); DCHECK_EQ(state_, COMMITTING); - if (!success) { - Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, - "Failed to write blobs.")); - return; + leveldb::Status s = leveldb::Status::OK(); + // Switch statement to protect against adding new enum values. + switch (result) { + case IndexedDBBackingStore::BlobWriteResult::FAILURE_ASYNC: + Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, + "Failed to write blobs.")); + return leveldb::Status::OK(); + case IndexedDBBackingStore::BlobWriteResult::SUCCESS_ASYNC: + case IndexedDBBackingStore::BlobWriteResult::SUCCESS_SYNC: { + // Save the database as |this| can be destroyed in the next line. We also + // make + // sure to handle the error if we're not being called synchronously. + scoped_refptr<IndexedDBDatabase> database = database_; + s = CommitPhaseTwo(); + if (!s.ok() && + result == IndexedDBBackingStore::BlobWriteResult::SUCCESS_ASYNC) + ReportError(s, database, database->factory()); + break; + } } - // Save the database as |this| can be destroyed in the next line. - scoped_refptr<IndexedDBDatabase> database = database_; - leveldb::Status s = CommitPhaseTwo(); - if (!s.ok()) - ReportError(s, database, database->factory()); + return s; } leveldb::Status IndexedDBTransaction::Commit() { @@ -315,13 +326,10 @@ s = CommitPhaseTwo(); } else { scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback( - new BlobWriteCallbackImpl(this)); + new BlobWriteCallbackImpl(ptr_factory_.GetWeakPtr())); // CommitPhaseOne will call the callback synchronously if there are no blobs // to write. s = transaction_->CommitPhaseOne(callback); - if (!s.ok()) - Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, - "Error processing blob journal.")); } return s; @@ -334,11 +342,6 @@ DCHECK_EQ(state_, COMMITTING); - // The last reference to this object may be released while performing the - // commit steps below. We therefore take a self reference to keep ourselves - // alive while executing this method. - scoped_refptr<IndexedDBTransaction> protect(this); - state_ = FINISHED; leveldb::Status s; @@ -375,7 +378,7 @@ IDB_TRACE1( "IndexedDBTransaction::CommitPhaseTwo.TransactionCompleteCallbacks", "txn.id", id()); - callbacks_->OnComplete(id_); + callbacks_->OnComplete(*this); } if (!pending_observers_.empty() && connection_) { connection_->ActivatePendingObservers(std::move(pending_observers_)); @@ -383,6 +386,9 @@ } database_->TransactionFinished(this, true); + // RemoveTransaction will delete |this|. + connection_->RemoveTransaction(id_); + return s; } else { while (!abort_task_stack_.empty()) abort_task_stack_.pop().Run(); @@ -396,12 +402,9 @@ error = IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, "Internal error committing transaction."); } - callbacks_->OnAbort(id_, error); - + callbacks_->OnAbort(*this, error); database_->TransactionFinished(this, false); } - - database_ = NULL; return s; } @@ -424,11 +427,6 @@ backing_store_transaction_begun_ = true; } - // The last reference to this object may be released while performing the - // tasks. Take take a self reference to keep this object alive so that - // the loop termination conditions can be checked. - scoped_refptr<IndexedDBTransaction> protect(this); - TaskQueue* task_queue = pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; while (!task_queue->empty() && state_ != FINISHED) { @@ -441,8 +439,7 @@ } if (!result.ok()) { processing_event_queue_ = false; - if (!result.ok()) - ReportError(result, database_, database_->factory()); + ReportError(result, database_, database_->factory()); return; } @@ -454,8 +451,9 @@ // If there are no pending tasks, we haven't already committed/aborted, // and the front-end requested a commit, it is now safe to do so. if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) { - leveldb::Status result = Commit(); processing_event_queue_ = false; + // This can delete |this|. + leveldb::Status result = Commit(); if (!result.ok()) ReportError(result, database_, database_->factory()); return; @@ -473,8 +471,9 @@ // never requests further activity. Read-only transactions don't // block other transactions, so don't time those out. if (mode_ != blink::WebIDBTransactionModeReadOnly) { - timeout_timer_.Start(FROM_HERE, GetInactivityTimeout(), - base::Bind(&IndexedDBTransaction::Timeout, this)); + timeout_timer_.Start( + FROM_HERE, GetInactivityTimeout(), + base::Bind(&IndexedDBTransaction::Timeout, ptr_factory_.GetWeakPtr())); } processing_event_queue_ = false; }
diff --git a/content/browser/indexed_db/indexed_db_transaction.h b/content/browser/indexed_db/indexed_db_transaction.h index 1d7c382..8315eb2 100644 --- a/content/browser/indexed_db/indexed_db_transaction.h +++ b/content/browser/indexed_db/indexed_db_transaction.h
@@ -15,6 +15,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "content/browser/indexed_db/indexed_db_backing_store.h" @@ -30,8 +31,7 @@ class IndexedDBCursor; class IndexedDBDatabaseCallbacks; -class CONTENT_EXPORT IndexedDBTransaction - : public NON_EXPORTED_BASE(base::RefCounted<IndexedDBTransaction>) { +class CONTENT_EXPORT IndexedDBTransaction { public: using Operation = base::Callback<leveldb::Status(IndexedDBTransaction*)>; using AbortOperation = base::Closure; @@ -44,8 +44,12 @@ FINISHED, // Either aborted or committed. }; - virtual void Abort(); + virtual ~IndexedDBTransaction(); + leveldb::Status Commit(); + + // This object is destroyed by these method calls. + virtual void Abort(); void Abort(const IndexedDBDatabaseError& error); // Called by the transaction coordinator when this transaction is unblocked. @@ -54,6 +58,7 @@ blink::WebIDBTransactionMode mode() const { return mode_; } const std::set<int64_t>& scope() const { return object_store_ids_; } + // Tasks cannot call Commit. void ScheduleTask(Operation task) { ScheduleTask(blink::WebIDBTaskTypeNormal, task); } @@ -86,7 +91,7 @@ IndexedDBDatabase* database() const { return database_.get(); } IndexedDBDatabaseCallbacks* callbacks() const { return callbacks_.get(); } - IndexedDBConnection* connection() const { return connection_.get(); } + IndexedDBConnection* connection() const { return connection_; } State state() const { return state_; } bool IsTimeoutTimerRunning() const { return timeout_timer_.IsRunning(); } @@ -100,16 +105,18 @@ const Diagnostics& diagnostics() const { return diagnostics_; } + void set_size(int64_t size) { size_ = size; } + int64_t size() const { return size_; } + protected: // Test classes may derive, but most creation should be done via // IndexedDBClassFactory. IndexedDBTransaction( int64_t id, - base::WeakPtr<IndexedDBConnection> connection, + IndexedDBConnection* connection, const std::set<int64_t>& object_store_ids, blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction); - virtual ~IndexedDBTransaction(); // May be overridden in tests. virtual base::TimeDelta GetInactivityTimeout() const; @@ -117,6 +124,7 @@ private: friend class BlobWriteCallbackImpl; friend class IndexedDBClassFactory; + friend class IndexedDBConnection; friend class base::RefCounted<IndexedDBTransaction>; FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTestMode, AbortPreemptive); @@ -135,7 +143,8 @@ bool IsTaskQueueEmpty() const; bool HasPendingTasks() const; - void BlobWriteComplete(bool success); + leveldb::Status BlobWriteComplete( + IndexedDBBackingStore::BlobWriteResult result); void ProcessTaskQueue(); void CloseOpenCursors(); leveldb::Status CommitPhaseTwo(); @@ -148,7 +157,8 @@ bool used_ = false; State state_ = CREATED; bool commit_pending_ = false; - base::WeakPtr<IndexedDBConnection> connection_; + // We are owned by the connection object. + IndexedDBConnection* connection_; scoped_refptr<IndexedDBDatabaseCallbacks> callbacks_; scoped_refptr<IndexedDBDatabase> database_; @@ -157,6 +167,9 @@ std::map<int32_t, ::indexed_db::mojom::ObserverChangesPtr> connection_changes_map_; + // Metrics for quota. + int64_t size_ = 0; + class TaskQueue { public: TaskQueue(); @@ -206,6 +219,8 @@ base::OneShotTimer timeout_timer_; Diagnostics diagnostics_; + + base::WeakPtrFactory<IndexedDBTransaction> ptr_factory_; }; } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_transaction_coordinator.cc b/content/browser/indexed_db/indexed_db_transaction_coordinator.cc index c7d171bc..68e0172 100644 --- a/content/browser/indexed_db/indexed_db_transaction_coordinator.cc +++ b/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
@@ -18,7 +18,7 @@ } void IndexedDBTransactionCoordinator::DidCreateTransaction( - scoped_refptr<IndexedDBTransaction> transaction) { + IndexedDBTransaction* transaction) { DCHECK(!queued_transactions_.count(transaction)); DCHECK(!started_transactions_.count(transaction)); DCHECK_EQ(IndexedDBTransaction::CREATED, transaction->state()); @@ -65,12 +65,11 @@ std::vector<const IndexedDBTransaction*> IndexedDBTransactionCoordinator::GetTransactions() const { std::vector<const IndexedDBTransaction*> result; - - for (const auto& transaction : started_transactions_) - result.push_back(transaction.get()); - for (const auto& transaction : queued_transactions_) - result.push_back(transaction.get()); - + result.reserve(started_transactions_.size() + queued_transactions_.size()); + result.insert(result.end(), started_transactions_.begin(), + started_transactions_.end()); + result.insert(result.end(), queued_transactions_.begin(), + queued_transactions_.end()); return result; } @@ -98,9 +97,9 @@ auto it = queued_transactions_.begin(); while (it != queued_transactions_.end()) { - scoped_refptr<IndexedDBTransaction> transaction = *it; + IndexedDBTransaction* transaction = *it; ++it; - if (CanStartTransaction(transaction.get(), locked_scope)) { + if (CanStartTransaction(transaction, locked_scope)) { DCHECK_EQ(IndexedDBTransaction::CREATED, transaction->state()); queued_transactions_.erase(transaction); started_transactions_.insert(transaction);
diff --git a/content/browser/indexed_db/indexed_db_transaction_coordinator.h b/content/browser/indexed_db/indexed_db_transaction_coordinator.h index c75d141..865ddc7c 100644 --- a/content/browser/indexed_db/indexed_db_transaction_coordinator.h +++ b/content/browser/indexed_db/indexed_db_transaction_coordinator.h
@@ -13,7 +13,6 @@ #include <vector> #include "base/macros.h" -#include "base/memory/ref_counted.h" #include "content/browser/indexed_db/list_set.h" namespace content { @@ -27,7 +26,7 @@ ~IndexedDBTransactionCoordinator(); // Called by transactions as they start and finish. - void DidCreateTransaction(scoped_refptr<IndexedDBTransaction> transaction); + void DidCreateTransaction(IndexedDBTransaction* transaction); void DidFinishTransaction(IndexedDBTransaction* transaction); bool IsRunningVersionChangeTransaction() const; @@ -47,8 +46,8 @@ // Transactions in different states are grouped below. // list_set is used to provide stable ordering; required by spec // for the queue, convenience for diagnostics for the rest. - list_set<scoped_refptr<IndexedDBTransaction>> queued_transactions_; - list_set<scoped_refptr<IndexedDBTransaction>> started_transactions_; + list_set<IndexedDBTransaction*> queued_transactions_; + list_set<IndexedDBTransaction*> started_transactions_; DISALLOW_COPY_AND_ASSIGN(IndexedDBTransactionCoordinator); };
diff --git a/content/browser/indexed_db/indexed_db_transaction_unittest.cc b/content/browser/indexed_db/indexed_db_transaction_unittest.cc index f10d5af..1233b29d 100644 --- a/content/browser/indexed_db/indexed_db_transaction_unittest.cc +++ b/content/browser/indexed_db/indexed_db_transaction_unittest.cc
@@ -5,6 +5,7 @@ #include "content/browser/indexed_db/indexed_db_transaction.h" #include <stdint.h> +#include <memory> #include "base/bind.h" #include "base/logging.h" @@ -20,6 +21,7 @@ #include "testing/gtest/include/gtest/gtest.h" namespace content { +const int kFakeProcessId = 10; class AbortObserver { public: @@ -90,11 +92,11 @@ const leveldb::Status commit_success = leveldb::Status::OK(); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, - blink::WebIDBTransactionModeReadWrite, - new IndexedDBFakeBackingStore::FakeTransaction(commit_success)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + std::unique_ptr<IndexedDBTransaction> transaction = + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, blink::WebIDBTransactionModeReadWrite, + new IndexedDBFakeBackingStore::FakeTransaction(commit_success))); db_->TransactionCreated(transaction.get()); // No conflicting transactions, so coordinator will start it immediately: @@ -136,10 +138,11 @@ const leveldb::Status commit_success = leveldb::Status::OK(); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, blink::WebIDBTransactionModeReadOnly, - new IndexedDBFakeBackingStore::FakeTransaction(commit_success)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + std::unique_ptr<IndexedDBTransaction> transaction = + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, blink::WebIDBTransactionModeReadOnly, + new IndexedDBFakeBackingStore::FakeTransaction(commit_success))); db_->TransactionCreated(transaction.get()); // No conflicting transactions, so coordinator will start it immediately: @@ -168,10 +171,11 @@ const leveldb::Status commit_success = leveldb::Status::OK(); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, GetParam(), - new IndexedDBFakeBackingStore::FakeTransaction(commit_success)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + std::unique_ptr<IndexedDBTransaction> transaction = + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, GetParam(), + new IndexedDBFakeBackingStore::FakeTransaction(commit_success))); EXPECT_FALSE(transaction->HasPendingTasks()); EXPECT_TRUE(transaction->IsTaskQueueEmpty()); @@ -229,10 +233,11 @@ const leveldb::Status commit_success = leveldb::Status::OK(); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, GetParam(), - new IndexedDBFakeBackingStore::FakeTransaction(commit_success)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + std::unique_ptr<IndexedDBTransaction> transaction = + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, GetParam(), + new IndexedDBFakeBackingStore::FakeTransaction(commit_success))); EXPECT_FALSE(transaction->HasPendingTasks()); EXPECT_TRUE(transaction->IsTaskQueueEmpty()); @@ -292,11 +297,12 @@ const leveldb::Status commit_failure = leveldb::Status::Corruption("Ouch."); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, - blink::WebIDBTransactionModeVersionChange, - new IndexedDBFakeBackingStore::FakeTransaction(commit_failure)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + std::unique_ptr<IndexedDBTransaction> transaction = + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, + blink::WebIDBTransactionModeVersionChange, + new IndexedDBFakeBackingStore::FakeTransaction(commit_failure))); EXPECT_FALSE(transaction->HasPendingTasks()); EXPECT_TRUE(transaction->IsTaskQueueEmpty()); @@ -353,10 +359,11 @@ const leveldb::Status commit_failure = leveldb::Status::Corruption("Ouch."); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, GetParam(), - new IndexedDBFakeBackingStore::FakeTransaction(commit_failure)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + std::unique_ptr<IndexedDBTransaction> transaction = + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, GetParam(), + new IndexedDBFakeBackingStore::FakeTransaction(commit_failure))); db_->TransactionCreated(transaction.get()); AbortObserver observer; @@ -382,10 +389,11 @@ const leveldb::Status commit_success = leveldb::Status::OK(); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, GetParam(), - new IndexedDBFakeBackingStore::FakeTransaction(commit_success)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + std::unique_ptr<IndexedDBTransaction> transaction = + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, GetParam(), + new IndexedDBFakeBackingStore::FakeTransaction(commit_success))); db_->TransactionCreated(transaction.get()); // No conflicting transactions, so coordinator will start it immediately: @@ -433,11 +441,15 @@ const leveldb::Status commit_success = leveldb::Status::OK(); std::unique_ptr<IndexedDBConnection> connection( base::MakeUnique<IndexedDBConnection>( - db_, new MockIndexedDBDatabaseCallbacks())); - scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( - id, connection->GetWeakPtr(), scope, - blink::WebIDBTransactionModeReadWrite, - new IndexedDBFakeBackingStore::FakeTransaction(commit_success)); + kFakeProcessId, db_, new MockIndexedDBDatabaseCallbacks())); + + base::WeakPtr<IndexedDBTransaction> transaction = + connection->AddTransactionForTesting( + std::unique_ptr<IndexedDBTransaction>(new IndexedDBTransaction( + id, connection.get(), scope, + blink::WebIDBTransactionModeReadWrite, + new IndexedDBFakeBackingStore::FakeTransaction(commit_success)))); + ASSERT_TRUE(transaction); db_->TransactionCreated(transaction.get()); EXPECT_EQ(0UL, transaction->pending_observers_.size()); @@ -459,7 +471,7 @@ // After commit, observer moved to connection's active observer. transaction->Commit(); - EXPECT_EQ(0UL, transaction->pending_observers_.size()); + EXPECT_FALSE(transaction); EXPECT_EQ(1UL, connection->active_observers().size()); // Observer does not exist, so no change to active_observers.
diff --git a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc index 2ba375f..c408494 100644 --- a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc +++ b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
@@ -66,12 +66,12 @@ public: IndexedDBTestTransaction( int64_t id, - base::WeakPtr<IndexedDBConnection> connection, + IndexedDBConnection* connection, const std::set<int64_t>& scope, blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction) : IndexedDBTransaction(id, - std::move(connection), + connection, scope, mode, backing_store_transaction) {} @@ -264,15 +264,15 @@ unique_identifier); } -IndexedDBTransaction* +std::unique_ptr<IndexedDBTransaction> MockBrowserTestIndexedDBClassFactory::CreateIndexedDBTransaction( int64_t id, - base::WeakPtr<IndexedDBConnection> connection, + IndexedDBConnection* connection, const std::set<int64_t>& scope, blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction) { - return new IndexedDBTestTransaction(id, std::move(connection), scope, mode, - backing_store_transaction); + return std::unique_ptr<IndexedDBTransaction>(new IndexedDBTestTransaction( + id, connection, scope, mode, backing_store_transaction)); } scoped_refptr<LevelDBTransaction>
diff --git a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h index 955b0435..d8db0c6 100644 --- a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h +++ b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
@@ -46,9 +46,9 @@ scoped_refptr<IndexedDBBackingStore> backing_store, scoped_refptr<IndexedDBFactory> factory, const IndexedDBDatabase::Identifier& unique_identifier) override; - IndexedDBTransaction* CreateIndexedDBTransaction( + std::unique_ptr<IndexedDBTransaction> CreateIndexedDBTransaction( int64_t id, - base::WeakPtr<IndexedDBConnection> connection, + IndexedDBConnection* connection, const std::set<int64_t>& scope, blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction) override;
diff --git a/content/browser/indexed_db/mock_indexed_db_database_callbacks.cc b/content/browser/indexed_db/mock_indexed_db_database_callbacks.cc index 51fb078a..ceabc8b5b 100644 --- a/content/browser/indexed_db/mock_indexed_db_database_callbacks.cc +++ b/content/browser/indexed_db/mock_indexed_db_database_callbacks.cc
@@ -18,7 +18,7 @@ } void MockIndexedDBDatabaseCallbacks::OnAbort( - int64_t transaction_id, + const IndexedDBTransaction& transaction, const IndexedDBDatabaseError& error) { abort_called_ = true; }
diff --git a/content/browser/indexed_db/mock_indexed_db_database_callbacks.h b/content/browser/indexed_db/mock_indexed_db_database_callbacks.h index 20ea2b5..a8e5290 100644 --- a/content/browser/indexed_db/mock_indexed_db_database_callbacks.h +++ b/content/browser/indexed_db/mock_indexed_db_database_callbacks.h
@@ -19,9 +19,9 @@ void OnVersionChange(int64_t old_version, int64_t new_version) override {} void OnForcedClose() override; - void OnAbort(int64_t transaction_id, + void OnAbort(const IndexedDBTransaction& transaction, const IndexedDBDatabaseError& error) override; - void OnComplete(int64_t transaction_id) override {} + void OnComplete(const IndexedDBTransaction& transaction) override {} bool abort_called() const { return abort_called_; } bool forced_close_called() const { return forced_close_called_; }
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index 091cb0e..709ea5d 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -550,7 +550,8 @@ rwhv->SetSize(size); } -void WebContentsViewAura::EndDrag(blink::WebDragOperationsMask ops) { +void WebContentsViewAura::EndDrag(RenderWidgetHost* source_rwh, + blink::WebDragOperationsMask ops) { if (!web_contents_) return; @@ -566,7 +567,9 @@ // the coordinates local to |drag_start_rwh_|? See crbug.com/647249. web_contents_->DragSourceEndedAt(client_loc.x(), client_loc.y(), screen_loc.x(), screen_loc.y(), ops, - drag_start_rwh_.get()); + source_rwh); + + web_contents_->SystemDragEnded(source_rwh); } void WebContentsViewAura::InstallOverscrollControllerDelegate( @@ -896,7 +899,13 @@ return; } - drag_start_rwh_ = source_rwh->GetWeakPtr(); + // Grab a weak pointer to the RenderWidgetHost, since it can be destroyed + // during the drag and drop nested message loop in StartDragAndDrop. + // For example, the RenderWidgetHost can be deleted if a cross-process + // transfer happens while dragging, since the RenderWidgetHost is deleted in + // that case. + base::WeakPtr<RenderWidgetHostImpl> source_rwh_weak_ptr = + source_rwh->GetWeakPtr(); ui::TouchSelectionController* selection_controller = GetSelectionController(); if (selection_controller) @@ -940,8 +949,7 @@ return; } - EndDrag(ConvertToWeb(result_op)); - web_contents_->SystemDragEnded(source_rwh); + EndDrag(source_rwh_weak_ptr.get(), ConvertToWeb(result_op)); } void WebContentsViewAura::UpdateDragCursor(blink::WebDragOperation operation) {
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index d032f18..6869095 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -66,7 +66,7 @@ void SizeChangedCommon(const gfx::Size& size); - void EndDrag(blink::WebDragOperationsMask ops); + void EndDrag(RenderWidgetHost* source_rwh, blink::WebDragOperationsMask ops); void InstallOverscrollControllerDelegate(RenderWidgetHostViewAura* view); @@ -203,10 +203,6 @@ // view. |current_rvh_for_drag_| should not be dereferenced. void* current_rvh_for_drag_; - // We keep track of the RenderWidgetHost from which the current drag started, - // in order to properly route the drag end message to it. - base::WeakPtr<RenderWidgetHostImpl> drag_start_rwh_; - // The overscroll gesture currently in progress. OverscrollMode current_overscroll_gesture_;
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index 139301f..988f637f 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -1303,7 +1303,8 @@ case base::TERMINATION_STATUS_STILL_RUNNING: break; default: - message_loop_runner_->Quit(); + if (message_loop_runner_.get()) + message_loop_runner_->Quit(); break; } }
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc index 5b585a7..bf4e5458 100644 --- a/content/shell/browser/layout_test/blink_test_controller.cc +++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -268,7 +268,10 @@ current_working_directory_ = current_working_directory; enable_pixel_dumping_ = enable_pixel_dumping; expected_pixel_hash_ = expected_pixel_hash; - test_url_ = test_url; + if (test_url.spec().find("/inspector-unit/") == std::string::npos) + test_url_ = test_url; + else + test_url_ = LayoutTestDevToolsFrontend::MapJSTestURL(test_url); did_send_initial_test_configuration_ = false; printer_->reset(); frame_to_layout_dump_map_.clear(); @@ -279,10 +282,10 @@ ShellBrowserContext* browser_context = ShellContentBrowserClient::Get()->browser_context(); is_compositing_test_ = - test_url.spec().find("compositing/") != std::string::npos; + test_url_.spec().find("compositing/") != std::string::npos; initial_size_ = Shell::GetShellDefaultSize(); // The W3C SVG layout tests use a different size than the other layout tests. - if (test_url.spec().find("W3C-SVG-1.1") != std::string::npos) + if (test_url_.spec().find("W3C-SVG-1.1") != std::string::npos) initial_size_ = gfx::Size(kTestSVGWindowWidthDip, kTestSVGWindowHeightDip); if (!main_window_) { main_window_ = content::Shell::CreateNewWindow( @@ -294,7 +297,7 @@ current_pid_ = base::kNullProcessId; default_prefs_ = main_window_->web_contents()->GetRenderViewHost()->GetWebkitPreferences(); - main_window_->LoadURL(test_url); + main_window_->LoadURL(test_url_); } else { #if defined(OS_MACOSX) // Shell::SizeTo is not implemented on all platforms. @@ -320,7 +323,7 @@ render_view_host->UpdateWebkitPreferences(default_prefs_); HandleNewRenderFrameHost(render_view_host->GetMainFrame()); - NavigationController::LoadURLParams params(test_url); + NavigationController::LoadURLParams params(test_url_); params.transition_type = ui::PageTransitionFromInt( ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); params.should_clear_history_list = true;
diff --git a/content/shell/browser/layout_test/layout_test_devtools_frontend.cc b/content/shell/browser/layout_test/layout_test_devtools_frontend.cc index d12ddd0e..917a8764 100644 --- a/content/shell/browser/layout_test/layout_test_devtools_frontend.cc +++ b/content/shell/browser/layout_test/layout_test_devtools_frontend.cc
@@ -73,6 +73,17 @@ return GURL(url_string); } +// static. +GURL LayoutTestDevToolsFrontend::MapJSTestURL(const GURL& test_url) { + std::string url_string = GetDevToolsPathAsURL(std::string()).spec(); + std::string inspector_file_name = "inspector.html"; + size_t start_position = url_string.find(inspector_file_name); + url_string.replace(start_position, inspector_file_name.length(), + "unit_test_runner.html"); + url_string += "&test=" + test_url.spec(); + return GURL(url_string); +} + void LayoutTestDevToolsFrontend::ReuseFrontend(const std::string& settings, const std::string frontend_url) { DisconnectFromTarget();
diff --git a/content/shell/browser/layout_test/layout_test_devtools_frontend.h b/content/shell/browser/layout_test/layout_test_devtools_frontend.h index a0720d21..a58c6f4 100644 --- a/content/shell/browser/layout_test/layout_test_devtools_frontend.h +++ b/content/shell/browser/layout_test/layout_test_devtools_frontend.h
@@ -22,6 +22,8 @@ static GURL GetDevToolsPathAsURL(const std::string& frontend_url); + static GURL MapJSTestURL(const GURL& test_url); + void ReuseFrontend(const std::string& settings, const std::string frontend_url); void EvaluateInFrontend(int call_id, const std::string& expression);
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc index e583efca..a8e3bdb 100644 --- a/extensions/renderer/module_system.cc +++ b/extensions/renderer/module_system.cc
@@ -309,6 +309,10 @@ v8::Local<v8::Function> function = GetModuleFunction(module_name, method_name); + if (function.IsEmpty()) { + NOTREACHED() << "GetModuleFunction() returns empty function handle"; + return handle_scope.Escape(v8::Undefined(GetIsolate())); + } v8::Local<v8::Value> result; { @@ -350,6 +354,10 @@ v8::Local<v8::Function> function = GetModuleFunction(module_name, method_name); + if (function.IsEmpty()) { + NOTREACHED() << "GetModuleFunction() returns empty function handle"; + return; + } { v8::TryCatch try_catch(GetIsolate());
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 39c7bbe..b78c429 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -76,8 +76,6 @@ {'name': 'cull_face'}, {'name': 'depth_test', 'state_flag': 'framebuffer_state_.clear_state_dirty'}, {'name': 'dither', 'default': True}, - {'name': 'framebuffer_srgb_ext', 'default': True, - 'extension_flag': 'ext_srgb_write_control'}, {'name': 'polygon_offset_fill'}, {'name': 'sample_alpha_to_coverage'}, {'name': 'sample_coverage'}, @@ -1539,14 +1537,6 @@ 'GL_COMPARE_REF_TO_TEXTURE', ], }, - 'TextureSrgbDecodeExt': { - 'type': 'GLenum', - 'is_complete': True, - 'valid': [ - 'GL_DECODE_EXT', - 'GL_SKIP_DECODE_EXT', - ], - }, 'TextureSwizzle': { 'type': 'GLenum', 'is_complete': True,
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc index 817efc1..74ccfec 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -428,6 +428,14 @@ return 1; case GL_TEXTURE_MAX_ANISOTROPY_EXT: return 1; + case GL_TEXTURE_SWIZZLE_R: + return 1; + case GL_TEXTURE_SWIZZLE_G: + return 1; + case GL_TEXTURE_SWIZZLE_B: + return 1; + case GL_TEXTURE_SWIZZLE_A: + return 1; // -- glGetVertexAttrib case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: @@ -1951,4 +1959,3 @@ } // namespace gles2 } // namespace gpu -
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h index 1775e7d..64a72fc 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -96,7 +96,6 @@ uint32_t value); static std::string GetStringTextureSizedTextureFilterableInternalFormat( uint32_t value); -static std::string GetStringTextureSrgbDecodeExt(uint32_t value); static std::string GetStringTextureStencilRenderableInternalFormat( uint32_t value); static std::string GetStringTextureSwizzle(uint32_t value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 5a6325c..9d6b4a5 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -4828,15 +4828,6 @@ arraysize(string_table), value); } -std::string GLES2Util::GetStringTextureSrgbDecodeExt(uint32_t value) { - static const EnumToString string_table[] = { - {GL_DECODE_EXT, "GL_DECODE_EXT"}, - {GL_SKIP_DECODE_EXT, "GL_SKIP_DECODE_EXT"}, - }; - return GLES2Util::GetQualifiedEnumString(string_table, - arraysize(string_table), value); -} - std::string GLES2Util::GetStringTextureStencilRenderableInternalFormat( uint32_t value) { static const EnumToString string_table[] = {
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc index 5aa24fb..94192a6 100644 --- a/gpu/command_buffer/service/context_state.cc +++ b/gpu/command_buffer/service/context_state.cc
@@ -221,6 +221,7 @@ pack_reverse_row_order(false), ignore_cached_state(false), fbo_binding_for_scissor_workaround_dirty(false), + framebuffer_srgb_(false), feature_info_(feature_info), error_state_(ErrorState::Create(error_state_client, logger)) { Initialize(); @@ -504,8 +505,15 @@ RestoreIndexedUniformBufferBindings(prev_state); RestoreGlobalState(prev_state); - // FRAMEBUFFER_SRGB will be restored lazily at render time. - framebuffer_srgb_valid_ = false; + if (!prev_state) { + if (feature_info_->feature_flags().desktop_srgb_support) { + framebuffer_srgb_ = false; + glDisable(GL_FRAMEBUFFER_SRGB); + } + } else if (framebuffer_srgb_ != prev_state->framebuffer_srgb_) { + // FRAMEBUFFER_SRGB will be restored lazily at render time. + framebuffer_srgb_ = prev_state->framebuffer_srgb_; + } } ErrorState* ContextState::GetErrorState() { @@ -698,11 +706,10 @@ } void ContextState::EnableDisableFramebufferSRGB(bool enable) { - if (framebuffer_srgb_valid_ && framebuffer_srgb_ == enable) + if (framebuffer_srgb_ == enable) return; EnableDisable(GL_FRAMEBUFFER_SRGB, enable); framebuffer_srgb_ = enable; - framebuffer_srgb_valid_ = true; } void ContextState::InitStateManual(const ContextState*) const {
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h index 6566974..72e4c6c2 100644 --- a/gpu/command_buffer/service/context_state.h +++ b/gpu/command_buffer/service/context_state.h
@@ -354,11 +354,7 @@ void InitStateManual(const ContextState* prev_state) const; - // EnableDisableFramebufferSRGB is called at very high frequency. Cache the - // true value of FRAMEBUFFER_SRGB, if we know it, to elide some of these - // calls. - bool framebuffer_srgb_valid_ = false; - bool framebuffer_srgb_ = false; + bool framebuffer_srgb_; // Generic vertex attrib base types: FLOAT, INT, or UINT. // Each base type is encoded into 2 bits, the lowest 2 bits for location 0,
diff --git a/gpu/command_buffer/service/context_state_autogen.h b/gpu/command_buffer/service/context_state_autogen.h index 38fae6e..c0da2cd 100644 --- a/gpu/command_buffer/service/context_state_autogen.h +++ b/gpu/command_buffer/service/context_state_autogen.h
@@ -22,8 +22,6 @@ bool cached_depth_test; bool dither; bool cached_dither; - bool framebuffer_srgb_ext; - bool cached_framebuffer_srgb_ext; bool polygon_offset_fill; bool cached_polygon_offset_fill; bool sample_alpha_to_coverage; @@ -145,12 +143,6 @@ return; enable_flags.cached_dither = enable; break; - case GL_FRAMEBUFFER_SRGB_EXT: - if (enable_flags.cached_framebuffer_srgb_ext == enable && - !ignore_cached_state) - return; - enable_flags.cached_framebuffer_srgb_ext = enable; - break; case GL_POLYGON_OFFSET_FILL: if (enable_flags.cached_polygon_offset_fill == enable && !ignore_cached_state)
diff --git a/gpu/command_buffer/service/context_state_impl_autogen.h b/gpu/command_buffer/service/context_state_impl_autogen.h index 3569bbf..6bc4a82 100644 --- a/gpu/command_buffer/service/context_state_impl_autogen.h +++ b/gpu/command_buffer/service/context_state_impl_autogen.h
@@ -21,8 +21,6 @@ cached_depth_test(false), dither(true), cached_dither(true), - framebuffer_srgb_ext(true), - cached_framebuffer_srgb_ext(true), polygon_offset_fill(false), cached_polygon_offset_fill(false), sample_alpha_to_coverage(false), @@ -169,13 +167,6 @@ if (prev_state->enable_flags.cached_dither != enable_flags.cached_dither) { EnableDisable(GL_DITHER, enable_flags.cached_dither); } - if (feature_info_->feature_flags().ext_srgb_write_control) { - if (prev_state->enable_flags.cached_framebuffer_srgb_ext != - enable_flags.cached_framebuffer_srgb_ext) { - EnableDisable(GL_FRAMEBUFFER_SRGB_EXT, - enable_flags.cached_framebuffer_srgb_ext); - } - } if (prev_state->enable_flags.cached_polygon_offset_fill != enable_flags.cached_polygon_offset_fill) { EnableDisable(GL_POLYGON_OFFSET_FILL, @@ -228,10 +219,6 @@ EnableDisable(GL_CULL_FACE, enable_flags.cached_cull_face); EnableDisable(GL_DEPTH_TEST, enable_flags.cached_depth_test); EnableDisable(GL_DITHER, enable_flags.cached_dither); - if (feature_info_->feature_flags().ext_srgb_write_control) { - EnableDisable(GL_FRAMEBUFFER_SRGB_EXT, - enable_flags.cached_framebuffer_srgb_ext); - } EnableDisable(GL_POLYGON_OFFSET_FILL, enable_flags.cached_polygon_offset_fill); EnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE, @@ -446,8 +433,6 @@ return enable_flags.depth_test; case GL_DITHER: return enable_flags.dither; - case GL_FRAMEBUFFER_SRGB_EXT: - return enable_flags.framebuffer_srgb_ext; case GL_POLYGON_OFFSET_FILL: return enable_flags.polygon_offset_fill; case GL_SAMPLE_ALPHA_TO_COVERAGE: @@ -850,12 +835,6 @@ params[0] = static_cast<GLint>(enable_flags.dither); } return true; - case GL_FRAMEBUFFER_SRGB_EXT: - *num_written = 1; - if (params) { - params[0] = static_cast<GLint>(enable_flags.framebuffer_srgb_ext); - } - return true; case GL_POLYGON_OFFSET_FILL: *num_written = 1; if (params) { @@ -1290,12 +1269,6 @@ params[0] = static_cast<GLfloat>(enable_flags.dither); } return true; - case GL_FRAMEBUFFER_SRGB_EXT: - *num_written = 1; - if (params) { - params[0] = static_cast<GLfloat>(enable_flags.framebuffer_srgb_ext); - } - return true; case GL_POLYGON_OFFSET_FILL: *num_written = 1; if (params) {
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index ba0f616d..3a34afa 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -572,13 +572,11 @@ validators_.index_type.AddValue(GL_UNSIGNED_INT); } - bool has_srgb_framebuffer_support = false; if (gl_version_info_->IsAtLeastGL(3, 2) || (gl_version_info_->IsAtLeastGL(2, 0) && (extensions.Contains("GL_EXT_framebuffer_sRGB") || extensions.Contains("GL_ARB_framebuffer_sRGB")))) { feature_flags_.desktop_srgb_support = true; - has_srgb_framebuffer_support = true; } // With EXT_sRGB, unsized SRGB_EXT and SRGB_ALPHA_EXT are accepted by the // <format> and <internalformat> parameter of TexImage2D. GLES3 adds support @@ -601,28 +599,6 @@ GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT); validators_.texture_unsized_internal_format.AddValue(GL_SRGB_EXT); validators_.texture_unsized_internal_format.AddValue(GL_SRGB_ALPHA_EXT); - has_srgb_framebuffer_support = true; - } - if (gl_version_info_->is_es3) - has_srgb_framebuffer_support = true; - - if (has_srgb_framebuffer_support && !IsWebGLContext()) { - // GL_FRAMEBUFFER_SRGB_EXT is exposed by the GLES extension - // GL_EXT_sRGB_write_control (which is not part of the core, even in GLES3), - // and the desktop extension GL_ARB_framebuffer_sRGB (part of the core in - // 3.0). - if (feature_flags_.desktop_srgb_support || - extensions.Contains("GL_EXT_sRGB_write_control")) { - feature_flags_.ext_srgb_write_control = true; - AddExtensionString("GL_EXT_sRGB_write_control"); - validators_.capability.AddValue(GL_FRAMEBUFFER_SRGB_EXT); - } - } - - // The extension GL_EXT_texture_sRGB_decode is the same on desktop and GLES. - if (extensions.Contains("GL_EXT_texture_sRGB_decode") && !IsWebGLContext()) { - AddExtensionString("GL_EXT_texture_sRGB_decode"); - validators_.texture_parameter.AddValue(GL_TEXTURE_SRGB_DECODE_EXT); } // On desktop, GL_EXT_texture_sRGB is required regardless of GL version, @@ -1515,6 +1491,13 @@ validators_.texture_sized_texture_filterable_internal_format.AddValue( GL_BGRA8_EXT); } + + if (!IsWebGLContext()) { + validators_.texture_parameter.AddValue(GL_TEXTURE_SWIZZLE_R); + validators_.texture_parameter.AddValue(GL_TEXTURE_SWIZZLE_G); + validators_.texture_parameter.AddValue(GL_TEXTURE_SWIZZLE_B); + validators_.texture_parameter.AddValue(GL_TEXTURE_SWIZZLE_A); + } } bool FeatureInfo::IsWebGLContext() const {
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 8128c72..d72dfc1 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h
@@ -98,7 +98,6 @@ bool khr_debug = false; bool chromium_bind_generates_resource = false; bool angle_webgl_compatibility = false; - bool ext_srgb_write_control = false; }; FeatureInfo();
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index 902a9531..49b8d19 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -246,11 +246,8 @@ NOTREACHED(); break; } - // Note that because GL_EXT_sRGB is a substring of GL_EXT_sRGB_write_control, - // which is not part of the ES3 core, we have to be careful to search for - // "GL_EXT_sRGB ", and append a space to the end of the extension string. if (expect_ext_srgb) { - EXPECT_THAT(info_->extensions() + " ", HasSubstr("GL_EXT_sRGB ")); + EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_sRGB")); EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT)); EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_ALPHA_EXT)); EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid( @@ -262,7 +259,7 @@ EXPECT_TRUE(info_->validators()->framebuffer_parameter.IsValid( GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)); } else { - EXPECT_THAT(info_->extensions() + " ", Not(HasSubstr("GL_EXT_sRGB "))); + EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_EXT_sRGB"))); EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT)); EXPECT_FALSE(info_->validators()->texture_format.IsValid( GL_SRGB_ALPHA_EXT)); @@ -596,7 +593,7 @@ SetupInitExpectations("GL_EXT_sRGB GL_OES_rgb8_rgba8"); if (GetContextType() == CONTEXT_TYPE_OPENGLES3) { - EXPECT_THAT(info_->extensions() + " ", Not(HasSubstr("GL_EXT_sRGB "))); + EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_EXT_sRGB"))); EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT)); EXPECT_FALSE( info_->validators()->texture_format.IsValid(GL_SRGB_ALPHA_EXT)); @@ -609,7 +606,7 @@ EXPECT_FALSE(info_->validators()->framebuffer_parameter.IsValid( GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)); } else { - EXPECT_THAT(info_->extensions() + " ", HasSubstr("GL_EXT_sRGB ")); + EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_sRGB")); EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT)); EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_ALPHA_EXT)); EXPECT_TRUE( @@ -925,7 +922,7 @@ TEST_P(FeatureInfoTest, Initialize_sRGBGLES3) { SetupInitExpectationsWithGLVersion("", "", "OpenGL ES 3.0"); - EXPECT_THAT(info_->extensions() + " ", Not(HasSubstr("GL_EXT_sRGB "))); + EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_EXT_sRGB"))); EXPECT_FALSE(info_->validators()->texture_format.IsValid( GL_SRGB_EXT)); EXPECT_FALSE(info_->validators()->texture_format.IsValid(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index f5c727b..bb5ccae 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -707,7 +707,6 @@ // Workarounds void OnFboChanged() const; void OnUseFramebuffer() const; - void UpdateFramebufferSRGB(Framebuffer* framebuffer); error::ContextLostReason GetContextLostReasonFromResetStatus( GLenum reset_status) const; @@ -3459,7 +3458,6 @@ DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); DoBindFramebuffer(GL_FRAMEBUFFER, 0); DoBindRenderbuffer(GL_RENDERBUFFER, 0); - UpdateFramebufferSRGB(nullptr); bool call_gl_clear = !surfaceless_ && !offscreen; #if defined(OS_ANDROID) @@ -4297,37 +4295,21 @@ Framebuffer* framebuffer = GetFramebufferInfoForTarget(target); bool valid = CheckFramebufferValid( framebuffer, target, GL_INVALID_FRAMEBUFFER_OPERATION, func_name); - if (!valid) - return false; - - if (!features().chromium_framebuffer_multisample) + if (valid && !features().chromium_framebuffer_multisample) OnUseFramebuffer(); - - UpdateFramebufferSRGB(framebuffer); - return true; -} - -void GLES2DecoderImpl::UpdateFramebufferSRGB(Framebuffer* framebuffer) { - // Manually set the value of FRAMEBUFFER_SRGB based on the state that was set - // by the client. - bool needs_enable_disable_framebuffer_srgb = false; - bool enable_framebuffer_srgb = true; - if (feature_info_->feature_flags().ext_srgb_write_control) { - needs_enable_disable_framebuffer_srgb = true; - enable_framebuffer_srgb &= state_.GetEnabled(GL_FRAMEBUFFER_SRGB); - } - // On desktop, enable FRAMEBUFFER_SRGB only if the framebuffer contains sRGB - // attachments. In theory, we can just leave FRAMEBUFFER_SRGB enabled, - // however, - // many drivers behave incorrectly when no attachments are sRGB. When at - // least one attachment is sRGB, then they behave correctly. - if (feature_info_->feature_flags().desktop_srgb_support) { - needs_enable_disable_framebuffer_srgb = true; - // Assume that the default fbo does not have an sRGB image. - enable_framebuffer_srgb &= framebuffer && framebuffer->HasSRGBAttachments(); - } - if (needs_enable_disable_framebuffer_srgb) + if (valid && feature_info_->feature_flags().desktop_srgb_support) { + // If framebuffer contains sRGB images, then enable FRAMEBUFFER_SRGB. + // Otherwise, disable FRAMEBUFFER_SRGB. Assume default fbo does not have + // sRGB image. + // In theory, we can just leave FRAMEBUFFER_SRGB on. However, many drivers + // behave incorrectly when all images are linear encoding, they still apply + // the sRGB conversion, but when at least one image is sRGB, then they + // behave correctly. + bool enable_framebuffer_srgb = + framebuffer && framebuffer->HasSRGBAttachments(); state_.EnableDisableFramebufferSRGB(enable_framebuffer_srgb); + } + return valid; } bool GLES2DecoderImpl::CheckBoundReadFramebufferValid( @@ -7442,11 +7424,6 @@ // DrawElements* for old desktop GL. return; } - if (cap == GL_FRAMEBUFFER_SRGB) { - // Enable and Disable GL_FRAMEBUFFER_SRGB is done manually in - // CheckBoundDrawFramebufferValid. - return; - } glDisable(cap); } } @@ -7459,11 +7436,6 @@ // DrawElements* for old desktop GL. return; } - if (cap == GL_FRAMEBUFFER_SRGB) { - // Enable and Disable GL_FRAMEBUFFER_SRGB is done manually in - // CheckBoundDrawFramebufferValid. - return; - } glEnable(cap); } } @@ -10561,6 +10533,7 @@ } return; } + break; case GL_TEXTURE_MAX_LEVEL: if (workarounds().use_shadowed_tex_level_params) { if (fparams) { @@ -10570,6 +10543,35 @@ } return; } + break; + case GL_TEXTURE_SWIZZLE_R: + if (fparams) { + fparams[0] = static_cast<GLfloat>(texture->swizzle_r()); + } else { + iparams[0] = texture->swizzle_r(); + } + return; + case GL_TEXTURE_SWIZZLE_G: + if (fparams) { + fparams[0] = static_cast<GLfloat>(texture->swizzle_g()); + } else { + iparams[0] = texture->swizzle_g(); + } + return; + case GL_TEXTURE_SWIZZLE_B: + if (fparams) { + fparams[0] = static_cast<GLfloat>(texture->swizzle_b()); + } else { + iparams[0] = texture->swizzle_b(); + } + return; + case GL_TEXTURE_SWIZZLE_A: + if (fparams) { + fparams[0] = static_cast<GLfloat>(texture->swizzle_a()); + } else { + iparams[0] = texture->swizzle_a(); + } + return; default: break; }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index 1f961d1..0895cdd 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -5140,14 +5140,6 @@ return true; } return false; - case GL_FRAMEBUFFER_SRGB_EXT: - state_.enable_flags.framebuffer_srgb_ext = enabled; - if (state_.enable_flags.cached_framebuffer_srgb_ext != enabled || - state_.ignore_cached_state) { - state_.enable_flags.cached_framebuffer_srgb_ext = enabled; - return true; - } - return false; case GL_POLYGON_OFFSET_FILL: state_.enable_flags.polygon_offset_fill = enabled; if (state_.enable_flags.cached_polygon_offset_fill != enabled ||
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 87c5e46..211792c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -90,6 +90,15 @@ TEST_P(GLES3DecoderTest, Basic) { // Make sure the setup is correct for ES3. EXPECT_TRUE(feature_info()->IsWebGL2OrES3Context()); + EXPECT_FALSE(feature_info()->IsWebGLContext()); + EXPECT_TRUE(feature_info()->validators()->texture_bind_target.IsValid( + GL_TEXTURE_3D)); +} + +TEST_P(WebGL2DecoderTest, Basic) { + // Make sure the setup is correct for WebGL2. + EXPECT_TRUE(feature_info()->IsWebGL2OrES3Context()); + EXPECT_TRUE(feature_info()->IsWebGLContext()); EXPECT_TRUE(feature_info()->validators()->texture_bind_target.IsValid( GL_TEXTURE_3D)); } @@ -1695,6 +1704,14 @@ InitDecoder(init); } +void WebGL2DecoderTest::SetUp() { + InitState init; + init.gl_version = "OpenGL ES 3.0"; + init.bind_generates_resource = true; + init.context_type = CONTEXT_TYPE_WEBGL2; + InitDecoder(init); +} + void GLES3DecoderWithShaderTest::SetUp() { InitState init; init.gl_version = "OpenGL ES 3.0";
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h index 9eab7fc..72577a3 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h
@@ -78,6 +78,15 @@ void SetUp() override; }; +class WebGL2DecoderTest : public GLES2DecoderTest { + public: + WebGL2DecoderTest() { shader_language_version_ = 300; } + + // Override default setup so ES3 capabilities are enabled by default + // and WebGL2 specific rules are enforced. + void SetUp() override; +}; + class GLES3DecoderWithShaderTest : public GLES2DecoderWithShaderTest { public: GLES3DecoderWithShaderTest() { shader_language_version_ = 300; }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h index d155c35..af2e41c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
@@ -17,9 +17,6 @@ ExpectEnableDisable(GL_CULL_FACE, false); ExpectEnableDisable(GL_DEPTH_TEST, false); ExpectEnableDisable(GL_DITHER, true); - if (group_->feature_info()->feature_flags().ext_srgb_write_control) { - ExpectEnableDisable(GL_FRAMEBUFFER_SRGB_EXT, true); - } ExpectEnableDisable(GL_POLYGON_OFFSET_FILL, false); ExpectEnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE, false); ExpectEnableDisable(GL_SAMPLE_COVERAGE, false);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 9352747..bbc96b4 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -435,13 +435,6 @@ .Times(1) .RetiresOnSaturation(); - if (group_->feature_info()->feature_flags().ext_srgb_write_control || - group_->feature_info()->feature_flags().desktop_srgb_support) { - EXPECT_CALL(*gl_, Disable(GL_FRAMEBUFFER_SRGB)) - .Times(1) - .RetiresOnSaturation(); - } - // TODO(boliu): Remove OS_ANDROID once crbug.com/259023 is fixed and the // workaround has been reverted. #if !defined(OS_ANDROID)
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc index 67e71bd4..266869dfd 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -4720,6 +4720,68 @@ EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); } +TEST_P(GLES3DecoderTest, TexSwizzleAllowed) { + const GLenum kTarget = GL_TEXTURE_2D; + const GLenum kSwizzleParam = GL_TEXTURE_SWIZZLE_R; + const GLenum kSwizzleValue = GL_BLUE; + const GLenum kInvalidSwizzleValue = GL_RG; + + { + EXPECT_CALL(*gl_, TexParameteri(kTarget, kSwizzleParam, kSwizzleValue)); + TexParameteri cmd; + cmd.Init(kTarget, kSwizzleParam, kSwizzleValue); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + } + + { + TexParameteri cmd; + cmd.Init(kTarget, kSwizzleParam, kInvalidSwizzleValue); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + } + + { + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetTexParameteriv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + result->size = 0; + GetTexParameteriv cmd; + cmd.Init(kTarget, kSwizzleParam, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(kSwizzleParam), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(kSwizzleValue, static_cast<GLenum>(result->GetData()[0])); + } +} + +TEST_P(WebGL2DecoderTest, TexSwizzleDisabled) { + const GLenum kTarget = GL_TEXTURE_2D; + const GLenum kSwizzleParam = GL_TEXTURE_SWIZZLE_R; + const GLenum kSwizzleValue = GL_BLUE; + + { + TexParameteri cmd; + cmd.Init(kTarget, kSwizzleParam, kSwizzleValue); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + } + + { + typedef GetTexParameteriv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + result->size = 0; + GetTexParameteriv cmd; + cmd.Init(kTarget, kSwizzleParam, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + } +} + // TODO(gman): Complete this test. // TEST_P(GLES2DecoderTest, CompressedTexImage2DGLError) { // }
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h index 2be3bab..1223a22 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -344,12 +344,6 @@ ValueValidator<GLenum> texture_parameter; ValueValidator<GLenum> texture_sized_color_renderable_internal_format; ValueValidator<GLenum> texture_sized_texture_filterable_internal_format; -class TextureSrgbDecodeExtValidator { - public: - bool IsValid(const GLenum value) const; -}; -TextureSrgbDecodeExtValidator texture_srgb_decode_ext; - ValueValidator<GLenum> texture_stencil_renderable_internal_format; class TextureSwizzleValidator { public:
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h index 280f736..632eaeed 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -1216,16 +1216,6 @@ GL_RGB_YCBCR_420V_CHROMIUM, }; -bool Validators::TextureSrgbDecodeExtValidator::IsValid( - const GLenum value) const { - switch (value) { - case GL_DECODE_EXT: - case GL_SKIP_DECODE_EXT: - return true; - } - return false; -}; - static const GLenum valid_texture_stencil_renderable_internal_format_table_es3[] = { GL_STENCIL_INDEX8, GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8,
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 8522da8..b02272b 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -1353,11 +1353,6 @@ } swizzle_a_ = param; break; - case GL_TEXTURE_SRGB_DECODE_EXT: - if (!feature_info->validators()->texture_srgb_decode_ext.IsValid(param)) { - return GL_INVALID_ENUM; - } - break; case GL_TEXTURE_IMMUTABLE_FORMAT: case GL_TEXTURE_IMMUTABLE_LEVELS: return GL_INVALID_ENUM;
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc index f10a919..bf860a6 100644 --- a/gpu/command_buffer/tests/gl_test_utils.cc +++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -71,13 +71,9 @@ } bool GLTestHelper::HasExtension(const char* extension) { - // Pad with an extra space to ensure that |extension| is not a substring of - // another extension. - std::string extensions = - std::string(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))) + - " "; - std::string extension_padded = std::string(extension) + " "; - return extensions.find(extension_padded) != std::string::npos; + std::string extensions( + reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); + return extensions.find(extension) != std::string::npos; } bool GLTestHelper::CheckGLError(const char* msg, int line) {
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm index 4a1009d..5a4ef07 100644 --- a/ios/chrome/browser/experimental_flags.mm +++ b/ios/chrome/browser/experimental_flags.mm
@@ -29,8 +29,8 @@ @"HeuristicsForPasswordGeneration"; NSString* const kEnableNewClearBrowsingDataUI = @"EnableNewClearBrowsingDataUI"; NSString* const kMDMIntegrationDisabled = @"MDMIntegrationDisabled"; -NSString* const kPendingIndexNavigationEnabled = - @"PendingIndexNavigationEnabled"; +NSString* const kPendingIndexNavigationDisabled = + @"PendingIndexNavigationDisabled"; const base::Feature kIOSDownloadImageRenaming{ "IOSDownloadImageRenaming", base::FEATURE_DISABLED_BY_DEFAULT}; } // namespace @@ -185,8 +185,8 @@ } bool IsPendingIndexNavigationEnabled() { - return [[NSUserDefaults standardUserDefaults] - boolForKey:kPendingIndexNavigationEnabled]; + return ![[NSUserDefaults standardUserDefaults] + boolForKey:kPendingIndexNavigationDisabled]; } bool IsDownloadRenamingEnabled() {
diff --git a/ios/web/public/test/earl_grey/js_test_util.mm b/ios/web/public/test/earl_grey/js_test_util.mm index f6d96f9e..b2bdcdf4 100644 --- a/ios/web/public/test/earl_grey/js_test_util.mm +++ b/ios/web/public/test/earl_grey/js_test_util.mm
@@ -84,14 +84,14 @@ __block id script_result = nil; __block bool did_finish = false; web::ExecuteScriptForTesting(interstitial, script, ^(id result, NSError*) { - script_result = [[result copy] autorelease]; + script_result = [result copy]; did_finish = true; }); BOOL suceeded = WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ return did_finish; }); GREYAssert(suceeded, @"Script execution timed out"); - return script_result; + return [script_result autorelease]; } } // namespace web
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index e884334b..75bee627 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2280,19 +2280,32 @@ CRWSessionEntry* fromEntry = self.sessionController.currentEntry; NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; - if ([userDefaults boolForKey:@"PendingIndexNavigationEnabled"]) { - [_delegate webWillFinishHistoryNavigationFromEntry:fromEntry]; - + if (![userDefaults boolForKey:@"PendingIndexNavigationDisabled"]) { BOOL sameDocumentNavigation = [sessionController isSameDocumentNavigationBetweenEntry:fromEntry andEntry:entries[index]]; if (sameDocumentNavigation) { [self.sessionController goToEntryAtIndex:index]; + + // Implementation of |webWillFinishHistoryNavigationFromEntry:| expects + // that NavigationManager has either a pending item or already made the + // navigation. Hence this delegate must be called after changing current + // navigation item. TODO(crbug.com/670149): Remove this delegate method as + // CRWWebController does not need to delegate setting Desktop User Agent. + [_delegate webWillFinishHistoryNavigationFromEntry:fromEntry]; [self updateHTML5HistoryState]; } else { [sessionController discardNonCommittedEntries]; [sessionController setPendingEntryIndex:index]; + // Implementation of |webWillFinishHistoryNavigationFromEntry:| expects + // that NavigationManager has either a pending item or already made the + // navigation. Hence this delegate must be called after changing pending + // navigation index. TODO(crbug.com/670149): Remove this delegate method + // as CRWWebController does not need to delegate setting Desktop User + // Agent. + [_delegate webWillFinishHistoryNavigationFromEntry:fromEntry]; + web::NavigationItemImpl* pendingItem = sessionController.pendingEntry.navigationItemImpl; pendingItem->SetTransitionType(ui::PageTransitionFromInt(
diff --git a/media/BUILD.gn b/media/BUILD.gn index 987b45d..db764547 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn
@@ -19,6 +19,7 @@ flags = [ "ENABLE_AC3_EAC3_AUDIO_DEMUXING=$enable_ac3_eac3_audio_demuxing", + "ENABLE_CBCS_ENCRYPTION_SCHEME=$enable_cbcs_encryption_scheme", "ENABLE_HEVC_DEMUXING=$enable_hevc_demuxing", "ENABLE_MSE_MPEG2TS_STREAM_PARSER=$enable_mse_mpeg2ts_stream_parser", "ENABLE_MEDIA_REMOTING=$enable_media_remoting",
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc index 773b4a2..6743605 100644 --- a/media/formats/mp4/box_definitions.cc +++ b/media/formats/mp4/box_definitions.cc
@@ -26,6 +26,12 @@ namespace media { namespace mp4 { +namespace { + +const size_t kKeyIdSize = 16; + +} // namespace + FileType::FileType() {} FileType::FileType(const FileType& other) = default; FileType::~FileType() {} @@ -160,8 +166,10 @@ uint8_t iv_size, bool has_subsamples) { // According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either - // 64-bit (8-byte) or 128-bit (16-byte). - RCHECK(iv_size == 8 || iv_size == 16); + // 64-bit (8-byte) or 128-bit (16-byte). The 3rd Edition allows |iv_size| + // to be 0, for the case of a "constant IV". In this case, the existence of + // the constant IV must be ensured by the caller. + RCHECK(iv_size == 0 || iv_size == 8 || iv_size == 16); memset(initialization_vector, 0, sizeof(initialization_vector)); for (uint8_t i = 0; i < iv_size; i++) @@ -235,7 +243,15 @@ } TrackEncryption::TrackEncryption() - : is_encrypted(false), default_iv_size(0) { + : is_encrypted(false), + default_iv_size(0) +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + , + default_crypt_byte_block(0), + default_skip_byte_block(0), + default_constant_iv_size(0) +#endif +{ } TrackEncryption::TrackEncryption(const TrackEncryption& other) = default; TrackEncryption::~TrackEncryption() {} @@ -243,14 +259,31 @@ bool TrackEncryption::Parse(BoxReader* reader) { uint8_t flag; + uint8_t possible_pattern_info; RCHECK(reader->ReadFullBoxHeader() && - reader->SkipBytes(2) && - reader->Read1(&flag) && + reader->SkipBytes(1) && // skip reserved byte + reader->Read1(&possible_pattern_info) && reader->Read1(&flag) && reader->Read1(&default_iv_size) && - reader->ReadVec(&default_kid, 16)); + reader->ReadVec(&default_kid, kKeyIdSize)); is_encrypted = (flag != 0); if (is_encrypted) { +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + if (reader->version() > 0) { + default_crypt_byte_block = (possible_pattern_info >> 4) & 0x0f; + default_skip_byte_block = possible_pattern_info & 0x0f; + } + if (default_iv_size == 0) { + RCHECK(reader->Read1(&default_constant_iv_size)); + RCHECK(default_constant_iv_size == 8 || default_constant_iv_size == 16); + memset(default_constant_iv, 0, sizeof(default_constant_iv)); + for (uint8_t i = 0; i < default_constant_iv_size; i++) + RCHECK(reader->Read1(default_constant_iv + i)); + } else { + RCHECK(default_iv_size == 8 || default_iv_size == 16); + } +#else RCHECK(default_iv_size == 8 || default_iv_size == 16); +#endif } else { RCHECK(default_iv_size == 0); } @@ -276,15 +309,26 @@ RCHECK(reader->ScanChildren() && reader->ReadChild(&format) && reader->ReadChild(&type)); - if (type.type == FOURCC_CENC) + if (HasSupportedScheme()) RCHECK(reader->ReadChild(&info)); // Other protection schemes are silently ignored. Since the protection scheme // type can't be determined until this box is opened, we return 'true' for - // non-CENC protection scheme types. It is the parent box's responsibility to + // unsupported protection schemes. It is the parent box's responsibility to // ensure that this scheme type is a supported one. return true; } +bool ProtectionSchemeInfo::HasSupportedScheme() const { + FourCC fourCC = type.type; + if (fourCC == FOURCC_CENC) + return true; +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + if (fourCC == FOURCC_CBCS) + return true; +#endif + return false; +} + MovieHeader::MovieHeader() : version(0), creation_time(0), @@ -652,7 +696,7 @@ if (format == FOURCC_ENCV) { // Continue scanning until a recognized protection scheme is found, or until // we run out of protection schemes. - while (sinf.type.type != FOURCC_CENC) { + while (!sinf.HasSupportedScheme()) { if (!reader->ReadChild(&sinf)) return false; } @@ -802,7 +846,7 @@ if (format == FOURCC_ENCA) { // Continue scanning until a recognized protection scheme is found, or until // we run out of protection schemes. - while (sinf.type.type != FOURCC_CENC) { + while (!sinf.HasSupportedScheme()) { if (!reader->ReadChild(&sinf)) return false; } @@ -1142,11 +1186,50 @@ } CencSampleEncryptionInfoEntry::CencSampleEncryptionInfoEntry() - : is_encrypted(false), iv_size(0) {} + : is_encrypted(false), + iv_size(0) +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + , + crypt_byte_block(0), + skip_byte_block(0), + constant_iv_size(0) +#endif +{ +} CencSampleEncryptionInfoEntry::CencSampleEncryptionInfoEntry( const CencSampleEncryptionInfoEntry& other) = default; CencSampleEncryptionInfoEntry::~CencSampleEncryptionInfoEntry() {} +bool CencSampleEncryptionInfoEntry::Parse(BoxReader* reader) { + uint8_t flag; + uint8_t possible_pattern_info; + RCHECK(reader->SkipBytes(1) && // reserved. + reader->Read1(&possible_pattern_info) && reader->Read1(&flag) && + reader->Read1(&iv_size) && reader->ReadVec(&key_id, kKeyIdSize)); + + is_encrypted = (flag != 0); + if (is_encrypted) { +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + crypt_byte_block = (possible_pattern_info >> 4) & 0x0f; + skip_byte_block = possible_pattern_info & 0x0f; + if (iv_size == 0) { + RCHECK(reader->Read1(&constant_iv_size)); + RCHECK(constant_iv_size == 8 || constant_iv_size == 16); + memset(constant_iv, 0, sizeof(constant_iv)); + for (uint8_t i = 0; i < constant_iv_size; i++) + RCHECK(reader->Read1(constant_iv + i)); + } else { + RCHECK(iv_size == 8 || iv_size == 16); + } +#else + RCHECK(iv_size == 8 || iv_size == 16); +#endif + } else { + RCHECK(iv_size == 0); + } + return true; +} + SampleGroupDescription::SampleGroupDescription() : grouping_type(0) {} SampleGroupDescription::SampleGroupDescription( const SampleGroupDescription& other) = default; @@ -1165,7 +1248,6 @@ const uint8_t version = reader->version(); - const size_t kKeyIdSize = 16; const size_t kEntrySize = sizeof(uint32_t) + kKeyIdSize; uint32_t default_length = 0; if (version == 1) { @@ -1184,19 +1266,7 @@ RCHECK(description_length >= kEntrySize); } } - - uint8_t flag; - RCHECK(reader->SkipBytes(2) && // reserved. - reader->Read1(&flag) && - reader->Read1(&entries[i].iv_size) && - reader->ReadVec(&entries[i].key_id, kKeyIdSize)); - - entries[i].is_encrypted = (flag != 0); - if (entries[i].is_encrypted) { - RCHECK(entries[i].iv_size == 8 || entries[i].iv_size == 16); - } else { - RCHECK(entries[i].iv_size == 0); - } + RCHECK(entries[i].Parse(reader)); } return true; }
diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h index 1493edc..311e782 100644 --- a/media/formats/mp4/box_definitions.h +++ b/media/formats/mp4/box_definitions.h
@@ -20,10 +20,14 @@ #include "media/formats/mp4/avc.h" #include "media/formats/mp4/box_reader.h" #include "media/formats/mp4/fourccs.h" +#include "media/media_features.h" namespace media { namespace mp4 { +// Size in bytes needed to store largest IV. +const int kInitializationVectorSize = 16; + enum TrackType { kInvalid = 0, kVideo, kAudio, kText, kHint }; enum SampleFlags { @@ -91,7 +95,7 @@ // anywhere. bool GetTotalSizeOfSubsamples(size_t* total_size) const; - uint8_t initialization_vector[16]; + uint8_t initialization_vector[kInitializationVectorSize]; std::vector<SubsampleEntry> subsamples; }; @@ -129,6 +133,12 @@ bool is_encrypted; uint8_t default_iv_size; std::vector<uint8_t> default_kid; +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + uint8_t default_crypt_byte_block; + uint8_t default_skip_byte_block; + uint8_t default_constant_iv_size; + uint8_t default_constant_iv[kInitializationVectorSize]; +#endif }; struct MEDIA_EXPORT SchemeInfo : Box { @@ -143,6 +153,8 @@ OriginalFormat format; SchemeType type; SchemeInfo info; + + bool HasSupportedScheme() const; }; struct MEDIA_EXPORT MovieHeader : Box { @@ -289,10 +301,17 @@ CencSampleEncryptionInfoEntry(); CencSampleEncryptionInfoEntry(const CencSampleEncryptionInfoEntry& other); ~CencSampleEncryptionInfoEntry(); + bool Parse(BoxReader* reader); bool is_encrypted; uint8_t iv_size; std::vector<uint8_t> key_id; +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + uint8_t crypt_byte_block; + uint8_t skip_byte_block; + uint8_t constant_iv_size; + uint8_t constant_iv[kInitializationVectorSize]; +#endif }; struct MEDIA_EXPORT SampleGroupDescription : Box { // 'sgpd'.
diff --git a/media/formats/mp4/fourccs.h b/media/formats/mp4/fourccs.h index 0d913e5d..e0a2922 100644 --- a/media/formats/mp4/fourccs.h +++ b/media/formats/mp4/fourccs.h
@@ -22,6 +22,7 @@ FOURCC_AVC3 = 0x61766333, FOURCC_AVCC = 0x61766343, FOURCC_BLOC = 0x626C6F63, + FOURCC_CBCS = 0x63626373, FOURCC_CENC = 0x63656e63, FOURCC_CO64 = 0x636f3634, FOURCC_CTTS = 0x63747473,
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc index 8e8ec08..97d47457 100644 --- a/media/formats/mp4/mp4_stream_parser.cc +++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -17,6 +17,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "media/base/audio_decoder_config.h" +#include "media/base/encryption_scheme.h" #include "media/base/media_tracks.h" #include "media/base/media_util.h" #include "media/base/stream_parser_buffer.h" @@ -35,6 +36,41 @@ namespace { const int kMaxEmptySampleLogs = 20; + +// Caller should be prepared to handle return of Unencrypted() in case of +// unsupported scheme. +EncryptionScheme GetEncryptionScheme(const ProtectionSchemeInfo& sinf) { + if (!sinf.HasSupportedScheme()) + return Unencrypted(); + FourCC fourcc = sinf.type.type; + EncryptionScheme::CipherMode mode = EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + EncryptionScheme::Pattern pattern; +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + bool uses_pattern_encryption = false; +#endif + switch (fourcc) { + case FOURCC_CENC: + mode = EncryptionScheme::CIPHER_MODE_AES_CTR; + break; +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + case FOURCC_CBCS: + mode = EncryptionScheme::CIPHER_MODE_AES_CBC; + uses_pattern_encryption = true; + break; +#endif + default: + NOTREACHED(); + break; + } +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + if (uses_pattern_encryption) { + uint8_t crypt = sinf.info.track_encryption.default_crypt_byte_block; + uint8_t skip = sinf.info.track_encryption.default_skip_byte_block; + pattern = EncryptionScheme::Pattern(crypt, skip); + } +#endif + return EncryptionScheme(mode, pattern); +} } // namespace MP4StreamParser::MP4StreamParser(const std::set<int>& audio_object_types, @@ -317,10 +353,15 @@ } bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; is_track_encrypted_[audio_track_id] = is_track_encrypted; - audio_config.Initialize( - codec, sample_format, channel_layout, sample_per_second, extra_data, - is_track_encrypted ? AesCtrEncryptionScheme() : Unencrypted(), - base::TimeDelta(), 0); + EncryptionScheme scheme = Unencrypted(); + if (is_track_encrypted) { + scheme = GetEncryptionScheme(entry.sinf); + if (!scheme.is_encrypted()) + return false; + } + audio_config.Initialize(codec, sample_format, channel_layout, + sample_per_second, extra_data, scheme, + base::TimeDelta(), 0); DVLOG(1) << "audio_track_id=" << audio_track_id << " config=" << audio_config.AsHumanReadableString(); if (!audio_config.IsValidConfig()) { @@ -378,13 +419,18 @@ } bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; is_track_encrypted_[video_track_id] = is_track_encrypted; - video_config.Initialize( - entry.video_codec, entry.video_codec_profile, PIXEL_FORMAT_YV12, - COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size, - // No decoder-specific buffer needed for AVC; - // SPS/PPS are embedded in the video stream - EmptyExtraData(), - is_track_encrypted ? AesCtrEncryptionScheme() : Unencrypted()); + EncryptionScheme scheme = Unencrypted(); + if (is_track_encrypted) { + scheme = GetEncryptionScheme(entry.sinf); + if (!scheme.is_encrypted()) + return false; + } + video_config.Initialize(entry.video_codec, entry.video_codec_profile, + PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709, + coded_size, visible_rect, natural_size, + // No decoder-specific buffer needed for AVC; + // SPS/PPS are embedded in the video stream + EmptyExtraData(), scheme); DVLOG(1) << "video_track_id=" << video_track_id << " config=" << video_config.AsHumanReadableString(); if (!video_config.IsValidConfig()) { @@ -622,11 +668,9 @@ if (decrypt_config) { if (!subsamples.empty()) { - // Create a new config with the updated subsamples. - decrypt_config.reset(new DecryptConfig( - decrypt_config->key_id(), - decrypt_config->iv(), - subsamples)); + // Create a new config with the updated subsamples. + decrypt_config.reset(new DecryptConfig(decrypt_config->key_id(), + decrypt_config->iv(), subsamples)); } // else, use the existing config. } else if (is_track_encrypted_[runs_->track_id()]) {
diff --git a/media/formats/mp4/track_run_iterator.cc b/media/formats/mp4/track_run_iterator.cc index bdd4e07..b2f6e739 100644 --- a/media/formats/mp4/track_run_iterator.cc +++ b/media/formats/mp4/track_run_iterator.cc
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "media/formats/mp4/rcheck.h" #include "media/formats/mp4/sample_to_group_iterator.h" +#include "media/media_features.h" namespace media { namespace mp4 { @@ -323,24 +324,21 @@ tri.fragment_sample_encryption_info = traf.sample_group_description.entries; - uint8_t default_iv_size = 0; + const TrackEncryption* track_encryption; tri.is_audio = (stsd.type == kAudio); if (tri.is_audio) { RCHECK(!stsd.audio_entries.empty()); if (desc_idx > stsd.audio_entries.size()) desc_idx = 0; tri.audio_description = &stsd.audio_entries[desc_idx]; - default_iv_size = - tri.audio_description->sinf.info.track_encryption.default_iv_size; + track_encryption = &tri.audio_description->sinf.info.track_encryption; } else { RCHECK(!stsd.video_entries.empty()); if (desc_idx > stsd.video_entries.size()) desc_idx = 0; tri.video_description = &stsd.video_entries[desc_idx]; - default_iv_size = - tri.video_description->sinf.info.track_encryption.default_iv_size; + track_encryption = &tri.video_description->sinf.info.track_encryption; } - // Initialize aux_info variables only if no sample encryption entries. if (sample_encryption_entries_count == 0 && traf.auxiliary_offset.offsets.size() > j) { @@ -408,12 +406,46 @@ tri.sample_encryption_entries.resize(trun.sample_count); for (size_t k = 0; k < trun.sample_count; k++) { uint32_t index = tri.samples[k].cenc_group_description_index; - const uint8_t iv_size = - index == 0 ? default_iv_size - : GetSampleEncryptionInfoEntry(tri, index)->iv_size; - RCHECK(tri.sample_encryption_entries[k].Parse( - sample_encryption_reader.get(), iv_size, - traf.sample_encryption.use_subsample_encryption)); + const CencSampleEncryptionInfoEntry* info_entry = + index == 0 ? nullptr : GetSampleEncryptionInfoEntry(tri, index); + const uint8_t iv_size = index == 0 ? track_encryption->default_iv_size + : info_entry->iv_size; + SampleEncryptionEntry& entry = tri.sample_encryption_entries[k]; + RCHECK(entry.Parse(sample_encryption_reader.get(), iv_size, + traf.sample_encryption.use_subsample_encryption)); +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + // If we don't have a per-sample IV, get the constant IV. + bool is_encrypted = index == 0 ? track_encryption->is_encrypted + : info_entry->is_encrypted; + // We only support setting the pattern values in the 'tenc' box for + // the track (not varying on per sample group basis). + // Thus we need to verify that the settings in the sample group match + // those in the 'tenc'. + if (is_encrypted && index != 0) { + RCHECK_MEDIA_LOGGED(info_entry->crypt_byte_block == + track_encryption->default_crypt_byte_block, + media_log_, + "Pattern value (crypt byte block) for the " + "sample group does not match that in the tenc " + "box . This is not currently supported."); + RCHECK_MEDIA_LOGGED(info_entry->skip_byte_block == + track_encryption->default_skip_byte_block, + media_log_, + "Pattern value (skip byte block) for the " + "sample group does not match that in the tenc " + "box . This is not currently supported."); + } + if (is_encrypted && !iv_size) { + const uint8_t constant_iv_size = + index == 0 ? track_encryption->default_constant_iv_size + : info_entry->constant_iv_size; + RCHECK(constant_iv_size != 0); + const uint8_t* constant_iv = + index == 0 ? track_encryption->default_constant_iv + : info_entry->constant_iv; + memcpy(entry.initialization_vector, constant_iv, constant_iv_size); + } +#endif } } runs_.push_back(tri); @@ -474,8 +506,14 @@ BufferReader reader(buf + pos, info_size); const uint8_t iv_size = GetIvSize(i); const bool has_subsamples = info_size > iv_size; - RCHECK( - sample_encryption_entries[i].Parse(&reader, iv_size, has_subsamples)); + SampleEncryptionEntry& entry = sample_encryption_entries[i]; + RCHECK(entry.Parse(&reader, iv_size, has_subsamples)); +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + // if we don't have a per-sample IV, get the constant IV. + if (!iv_size) { + RCHECK(ApplyConstantIv(i, &entry)); + } +#endif } pos += info_size; } @@ -592,14 +630,28 @@ std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { DCHECK(is_encrypted()); + size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); + const std::vector<uint8_t>& kid = GetKeyId(sample_idx); if (run_itr_->sample_encryption_entries.empty()) { DCHECK_EQ(0, aux_info_size()); +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + // The 'cbcs' scheme allows empty aux info when a constant IV is in use + // with full sample encryption. That case will fall through to here. + SampleEncryptionEntry sample_encryption_entry; + if (ApplyConstantIv(sample_idx, &sample_encryption_entry)) { + return std::unique_ptr<DecryptConfig>(new DecryptConfig( + std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), + std::string(reinterpret_cast<const char*>( + sample_encryption_entry.initialization_vector), + arraysize(sample_encryption_entry.initialization_vector)), + sample_encryption_entry.subsamples)); + } +#endif MEDIA_LOG(ERROR, media_log_) << "Sample encryption info is not available."; return std::unique_ptr<DecryptConfig>(); } - size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size()); const SampleEncryptionEntry& sample_encryption_entry = run_itr_->sample_encryption_entries[sample_idx]; @@ -612,7 +664,6 @@ return std::unique_ptr<DecryptConfig>(); } - const std::vector<uint8_t>& kid = GetKeyId(sample_idx); return std::unique_ptr<DecryptConfig>(new DecryptConfig( std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), std::string(reinterpret_cast<const char*>( @@ -648,5 +699,24 @@ : GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size; } +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) +bool TrackRunIterator::ApplyConstantIv(size_t sample_index, + SampleEncryptionEntry* entry) const { + DCHECK(IsSampleEncrypted(sample_index)); + uint32_t index = GetGroupDescriptionIndex(sample_index); + const uint8_t constant_iv_size = + index == 0 + ? track_encryption().default_constant_iv_size + : GetSampleEncryptionInfoEntry(*run_itr_, index)->constant_iv_size; + RCHECK(constant_iv_size != 0); + const uint8_t* constant_iv = + index == 0 ? track_encryption().default_constant_iv + : GetSampleEncryptionInfoEntry(*run_itr_, index)->constant_iv; + RCHECK(constant_iv != nullptr); + memcpy(entry->initialization_vector, constant_iv, kInitializationVectorSize); + return true; +} +#endif + } // namespace mp4 } // namespace media
diff --git a/media/formats/mp4/track_run_iterator.h b/media/formats/mp4/track_run_iterator.h index a04f2be..127cafa 100644 --- a/media/formats/mp4/track_run_iterator.h +++ b/media/formats/mp4/track_run_iterator.h
@@ -17,6 +17,7 @@ #include "media/base/media_log.h" #include "media/base/stream_parser_buffer.h" #include "media/formats/mp4/box_definitions.h" +#include "media/media_features.h" namespace media { @@ -99,6 +100,9 @@ bool IsSampleEncrypted(size_t sample_index) const; uint8_t GetIvSize(size_t sample_index) const; const std::vector<uint8_t>& GetKeyId(size_t sample_index) const; +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + bool ApplyConstantIv(size_t sample_index, SampleEncryptionEntry* entry) const; +#endif const Movie* moov_; scoped_refptr<MediaLog> media_log_;
diff --git a/media/formats/mp4/track_run_iterator_unittest.cc b/media/formats/mp4/track_run_iterator_unittest.cc index d1b3129..7c2043b 100644 --- a/media/formats/mp4/track_run_iterator_unittest.cc +++ b/media/formats/mp4/track_run_iterator_unittest.cc
@@ -97,6 +97,48 @@ 0x74, 0x43, 0x65, 0x6e, 0x63, 0x53, 0x61, 0x6d, }; +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) +// Sample encryption data for two samples, using constant IV (defined by 'tenc' +// or sample group entry). +const uint8_t kSampleEncryptionDataWithSubsamplesAndConstantIv[] = { + // Sample count. + 0x00, 0x00, 0x00, 0x05, + // Sample 1: Subsample count. + 0x00, 0x01, + // Sample 1: Subsample 1. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + // Sample 2: Subsample count. + 0x00, 0x02, + // Sample 2: Subsample 1. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + // Sample 2: Subsample 2. + 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + // Sample 3: Subsample count. + 0x00, 0x01, + // Sample 3: Subsample 1. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + // Sample 4: Subsample count. + 0x00, 0x01, + // Sample 4: Subsample 1. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + // Sample 5: Subsample count. + 0x00, 0x01, + // Sample 5: Subsample 1. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, +}; + +// Size of these IVs are 16 bytes. +const char kIv4[] = { + 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x34, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +}; + +const char kIv5[] = { + 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x35, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +}; +#endif + } // namespace namespace media { @@ -258,8 +300,7 @@ return moof; } - // Update the first sample description of a Track to indicate encryption - void AddEncryption(Track* track) { + ProtectionSchemeInfo* GetProtectionSchemeInfoForTrack(Track* track) { SampleDescription* stsd = &track->media.information.sample_table.description; ProtectionSchemeInfo* sinf; @@ -268,7 +309,12 @@ } else { sinf = &stsd->audio_entries[0].sinf; } + return sinf; + } + // Update the first sample description of a Track to indicate CENC encryption + void AddEncryption(Track* track) { + ProtectionSchemeInfo* sinf = GetProtectionSchemeInfoForTrack(track); sinf->type.type = FOURCC_CENC; sinf->info.track_encryption.is_encrypted = true; sinf->info.track_encryption.default_iv_size = 8; @@ -354,6 +400,70 @@ } } +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + // Update the first sample description of a Track to indicate CBCS encryption + // with a constant IV and pattern. + void AddEncryptionCbcs(Track* track) { + ProtectionSchemeInfo* sinf = GetProtectionSchemeInfoForTrack(track); + sinf->type.type = FOURCC_CBCS; + sinf->info.track_encryption.is_encrypted = true; + sinf->info.track_encryption.default_iv_size = 0; + sinf->info.track_encryption.default_crypt_byte_block = 1; + sinf->info.track_encryption.default_skip_byte_block = 9; + sinf->info.track_encryption.default_constant_iv_size = 16; + memcpy(sinf->info.track_encryption.default_constant_iv, kIv3, 16); + sinf->info.track_encryption.default_kid.assign(kKeyId, + kKeyId + arraysize(kKeyId)); + } + + void AddConstantIvsToCencSampleGroup(Track* track, TrackFragment* frag) { + auto& track_cenc_group = + track->media.information.sample_table.sample_group_description; + track_cenc_group.entries[0].iv_size = 0; + track_cenc_group.entries[0].crypt_byte_block = 1; + track_cenc_group.entries[0].skip_byte_block = 9; + track_cenc_group.entries[0].constant_iv_size = 16; + memcpy(track_cenc_group.entries[0].constant_iv, kIv4, 16); + + frag->sample_group_description.entries[1].iv_size = 0; + frag->sample_group_description.entries[1].crypt_byte_block = 1; + frag->sample_group_description.entries[1].skip_byte_block = 9; + frag->sample_group_description.entries[1].constant_iv_size = 16; + memcpy(frag->sample_group_description.entries[1].constant_iv, kIv5, 16); + frag->sample_group_description.entries[2].iv_size = 0; + frag->sample_group_description.entries[2].crypt_byte_block = 1; + frag->sample_group_description.entries[2].skip_byte_block = 9; + frag->sample_group_description.entries[2].constant_iv_size = 16; + memcpy(frag->sample_group_description.entries[2].constant_iv, kIv5, 16); + } + + void AddSampleEncryptionCbcs(TrackFragment* frag) { + frag->sample_encryption.use_subsample_encryption = true; + frag->sample_encryption.sample_encryption_data.assign( + kSampleEncryptionDataWithSubsamplesAndConstantIv, + kSampleEncryptionDataWithSubsamplesAndConstantIv + + arraysize(kSampleEncryptionDataWithSubsamplesAndConstantIv)); + + // Update sample sizes and aux info header. + frag->runs.resize(1); + frag->runs[0].sample_count = 5; + frag->auxiliary_offset.offsets.push_back(0); + frag->auxiliary_size.sample_count = 5; + // Update sample sizes to match with subsample entries above. + frag->runs[0].sample_sizes[0] = 3; + frag->runs[0].sample_sizes[1] = 10; + frag->runs[0].sample_sizes[2] = 3; + frag->runs[0].sample_sizes[3] = 3; + frag->runs[0].sample_sizes[4] = 3; + // Set aux info header. + frag->auxiliary_size.sample_info_sizes.push_back(16); + frag->auxiliary_size.sample_info_sizes.push_back(30); + frag->auxiliary_size.sample_info_sizes.push_back(16); + frag->auxiliary_size.sample_info_sizes.push_back(16); + frag->auxiliary_size.sample_info_sizes.push_back(16); + } +#endif + bool InitMoofWithArbitraryAuxInfo(MovieFragment* moof) { // Add aux info header (equal sized aux info for every sample). for (uint32_t i = 0; i < moof->tracks.size(); ++i) { @@ -879,5 +989,97 @@ EXPECT_EQ("2 K P P P K P", KeyframeAndRAPInfo(iter_.get())); } +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) +TEST_F(TrackRunIteratorTest, DecryptConfigTestWithConstantIvNoAuxInfo) { + AddEncryptionCbcs(&moov_.tracks[1]); + iter_.reset(new TrackRunIterator(&moov_, media_log_)); + + MovieFragment moof = CreateFragment(); + + ASSERT_TRUE(iter_->Init(moof)); + + // The run for track 2 will be the second. + iter_->AdvanceRun(); + EXPECT_EQ(iter_->track_id(), 2u); + EXPECT_TRUE(iter_->is_encrypted()); + ASSERT_FALSE(iter_->AuxInfoNeedsToBeCached()); + EXPECT_EQ(iter_->sample_offset(), 200); + std::unique_ptr<DecryptConfig> config = iter_->GetDecryptConfig(); + EXPECT_EQ( + std::string(reinterpret_cast<const char*>(kKeyId), arraysize(kKeyId)), + config->key_id()); + EXPECT_EQ(std::string(reinterpret_cast<const char*>(kIv3), arraysize(kIv3)), + config->iv()); + EXPECT_TRUE(config->subsamples().empty()); + iter_->AdvanceSample(); + config = iter_->GetDecryptConfig(); + EXPECT_EQ( + std::string(reinterpret_cast<const char*>(kKeyId), arraysize(kKeyId)), + config->key_id()); + EXPECT_EQ(std::string(reinterpret_cast<const char*>(kIv3), arraysize(kIv3)), + config->iv()); + EXPECT_TRUE(config->subsamples().empty()); +} + +TEST_F(TrackRunIteratorTest, DecryptConfigTestWithSampleGroupsAndConstantIv) { + // Add TrackEncryption Box. + AddEncryptionCbcs(&moov_.tracks[1]); + + MovieFragment moof = CreateFragment(); + AddSampleEncryptionCbcs(&moof.tracks[1]); + + const SampleToGroupEntry kSampleToGroupTable[] = { + // Associated with the 2nd entry in fragment SampleGroupDescription Box. + {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 2}, + // Associated with the default values specified in TrackEncryption Box. + {1, 0}, + // Associated with the 1st entry in fragment SampleGroupDescription Box. + {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 1}, + // Associated with the 1st entry in track SampleGroupDescription Box. + {1, 1}}; + AddCencSampleGroup(&moov_.tracks[1], &moof.tracks[1], kSampleToGroupTable, + arraysize(kSampleToGroupTable)); + AddConstantIvsToCencSampleGroup(&moov_.tracks[1], &moof.tracks[1]); + iter_.reset(new TrackRunIterator(&moov_, media_log_)); + ASSERT_TRUE(iter_->Init(moof)); + + // The run for track 2 will be the second. + iter_->AdvanceRun(); + + std::string track_encryption_iv(kIv3, kIv3 + arraysize(kIv3)); + std::string track_cenc_sample_group_iv(kIv4, kIv4 + arraysize(kIv4)); + std::string fragment_cenc_sample_group_iv(kIv5, kIv5 + arraysize(kIv5)); + + for (size_t i = 0; i < kSampleToGroupTable[0].sample_count; ++i) { + EXPECT_TRUE(iter_->is_encrypted()); + EXPECT_EQ(fragment_cenc_sample_group_iv, iter_->GetDecryptConfig()->iv()); + iter_->AdvanceSample(); + } + + for (size_t i = 0; i < kSampleToGroupTable[1].sample_count; ++i) { + EXPECT_TRUE(iter_->is_encrypted()); + EXPECT_EQ(track_encryption_iv, iter_->GetDecryptConfig()->iv()); + iter_->AdvanceSample(); + } + + for (size_t i = 0; i < kSampleToGroupTable[2].sample_count; ++i) { + EXPECT_FALSE(iter_->is_encrypted()); + iter_->AdvanceSample(); + } + + for (size_t i = 0; i < kSampleToGroupTable[3].sample_count; ++i) { + EXPECT_TRUE(iter_->is_encrypted()); + EXPECT_EQ(track_cenc_sample_group_iv, iter_->GetDecryptConfig()->iv()); + iter_->AdvanceSample(); + } + + // The remaining samples should be associated with the default values + // specified in TrackEncryption Box. + EXPECT_TRUE(iter_->is_encrypted()); + EXPECT_EQ(track_encryption_iv, iter_->GetDecryptConfig()->iv()); +} + +#endif + } // namespace mp4 } // namespace media
diff --git a/media/gpu/android_video_decode_accelerator.cc b/media/gpu/android_video_decode_accelerator.cc index 1fe3474a..55e49f8 100644 --- a/media/gpu/android_video_decode_accelerator.cc +++ b/media/gpu/android_video_decode_accelerator.cc
@@ -884,9 +884,9 @@ picture_buffer_manager_.CodecChanged(nullptr); } - codec_config_->task_type_ = + base::Optional<TaskType> task_type = AVDACodecAllocator::Instance()->TaskTypeForAllocation(); - if (codec_config_->task_type_ == TaskType::FAILED_CODEC) { + if (!task_type) { // If there is no free thread, then just fail. OnCodecConfigured(nullptr); return; @@ -894,12 +894,13 @@ // If autodetection is disallowed, fall back to Chrome's software decoders // instead of using the software decoders provided by MediaCodec. - if (codec_config_->task_type_ == TaskType::SW_CODEC && + if (task_type == TaskType::SW_CODEC && IsMediaCodecSoftwareDecodingForbidden()) { OnCodecConfigured(nullptr); return; } + codec_config_->task_type_ = task_type.value(); AVDACodecAllocator::Instance()->CreateMediaCodecAsync( weak_this_factory_.GetWeakPtr(), codec_config_); } @@ -910,13 +911,15 @@ DCHECK_NE(state_, WAITING_FOR_CODEC); state_ = WAITING_FOR_CODEC; - codec_config_->task_type_ = + base::Optional<TaskType> task_type = AVDACodecAllocator::Instance()->TaskTypeForAllocation(); - if (codec_config_->task_type_ == TaskType::FAILED_CODEC) { + if (!task_type) { + // If there is no free thread, then just fail. OnCodecConfigured(nullptr); return false; } + codec_config_->task_type_ = task_type.value(); std::unique_ptr<VideoCodecBridge> media_codec = AVDACodecAllocator::Instance()->CreateMediaCodecSync(codec_config_); OnCodecConfigured(std::move(media_codec));
diff --git a/media/gpu/avda_codec_allocator.cc b/media/gpu/avda_codec_allocator.cc index 0c1239d..1e4515a 100644 --- a/media/gpu/avda_codec_allocator.cc +++ b/media/gpu/avda_codec_allocator.cc
@@ -78,37 +78,27 @@ return g_avda_codec_allocator.Pointer(); } -// Make sure the construction threads are started for |client|. bool AVDACodecAllocator::StartThread(AVDACodecAllocatorClient* client) { DCHECK(thread_checker_.CalledOnValidThread()); // Cancel any pending StopThreadTask()s because we need the threads now. weak_this_factory_.InvalidateWeakPtrs(); - // Try to start all threads if they haven't been started. Remember that - // threads fail to start fairly often. - for (size_t i = 0; i < threads_.size(); i++) { - if (threads_[i]->thread.IsRunning()) + // Try to start the threads if they haven't been started. + for (auto* thread : threads_) { + if (thread->thread.IsRunning()) continue; - if (!threads_[i]->thread.Start()) - continue; + if (!thread->thread.Start()) + return false; // Register the hang detector to observe the thread's MessageLoop. - threads_[i]->thread.task_runner()->PostTask( - FROM_HERE, - base::Bind(&base::MessageLoop::AddTaskObserver, - base::Unretained(threads_[i]->thread.message_loop()), - &threads_[i]->hang_detector)); + thread->thread.task_runner()->PostTask( + FROM_HERE, base::Bind(&base::MessageLoop::AddTaskObserver, + base::Unretained(thread->thread.message_loop()), + &thread->hang_detector)); } - // Make sure that the construction thread started, else refuse to run. - // If other threads fail to start, then we'll post to the GPU main thread for - // those cases. SW allocation failures are much less rare, so this usually - // just costs us the latency of doing the codec allocation on the main thread. - if (!threads_[TaskType::AUTO_CODEC]->thread.IsRunning()) - return false; - clients_.insert(client); return true; } @@ -124,42 +114,29 @@ return; } - // Post a task to stop the thread through the thread's task runner and back - // to this thread. This ensures that all pending tasks are run first. If the - // thread is hung we don't post a task to avoid leaking an unbounded number - // of tasks on its queue. If the thread is not hung, but appears to be, it - // will stay alive until next time an AVDA tries to stop it. We're - // guaranteed to not run StopThreadTask() when the thread is hung because if - // an AVDA queues tasks after DoNothing(), the StopThreadTask() reply will - // be canceled by invalidating its weak pointer. + // Post a task to stop each thread through its task runner and back to this + // thread. This ensures that all pending tasks are run first. If a new AVDA + // calls StartThread() before StopThreadTask() runs, it's canceled by + // invalidating its weak pointer. As a result we're guaranteed to only call + // Thread::Stop() while there are no tasks on its queue. We don't try to stop + // hung threads. But if it recovers it will be stopped the next time a client + // calls this. for (size_t i = 0; i < threads_.size(); i++) { if (threads_[i]->thread.IsRunning() && !threads_[i]->hang_detector.IsThreadLikelyHung()) { threads_[i]->thread.task_runner()->PostTaskAndReply( FROM_HERE, base::Bind(&base::DoNothing), - base::Bind( - &AVDACodecAllocator::StopThreadTask, - weak_this_factory_.GetWeakPtr(), i, - (i == TaskType::AUTO_CODEC ? stop_event_for_testing_ : nullptr))); + base::Bind(&AVDACodecAllocator::StopThreadTask, + weak_this_factory_.GetWeakPtr(), i)); } } } -// Return the task runner for tasks of type |type|. If that thread failed -// to start, then fall back to the GPU main thread. +// Return the task runner for tasks of type |type|. scoped_refptr<base::SingleThreadTaskRunner> AVDACodecAllocator::TaskRunnerFor( TaskType task_type) { DCHECK(thread_checker_.CalledOnValidThread()); - base::Thread& thread = threads_[task_type]->thread; - - // Fail over to the main thread if this thread failed to start. Note that - // if the AUTO_CODEC thread fails to start, then AVDA init will fail. - // We won't fall back autodetection to the main thread, even without a - // special case here. - if (!thread.IsRunning()) - return base::ThreadTaskRunnerHandle::Get(); - - return thread.task_runner(); + return threads_[task_type]->thread.task_runner(); } bool AVDACodecAllocator::AllocateSurface(AVDACodecAllocatorClient* client, @@ -270,8 +247,7 @@ // |needs_protected_surface_| implies encrypted stream. DCHECK(!codec_config->needs_protected_surface_ || media_crypto); - const bool require_software_codec = - codec_config->task_type_ == TaskType::SW_CODEC; + const bool require_software_codec = codec_config->task_type_ == SW_CODEC; std::unique_ptr<VideoCodecBridge> codec(VideoCodecBridge::CreateDecoder( codec_config->codec_, codec_config->needs_protected_surface_, @@ -314,8 +290,6 @@ base::WaitableEvent* released = &pending_codec_releases_.find(surface_id)->second; - // TODO(watk): Even if this is the current thread, things will work, but we - // should refactor this to not tolerate threads failing to start. TaskRunnerFor(task_type)->PostTaskAndReply( FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, base::Passed(std::move(media_codec)), released), @@ -351,15 +325,14 @@ return !clients_.empty(); } -TaskType AVDACodecAllocator::TaskTypeForAllocation() { - if (!IsThreadLikelyHung(TaskType::AUTO_CODEC)) - return TaskType::AUTO_CODEC; +base::Optional<TaskType> AVDACodecAllocator::TaskTypeForAllocation() { + if (!IsThreadLikelyHung(AUTO_CODEC)) + return AUTO_CODEC; - if (!IsThreadLikelyHung(TaskType::SW_CODEC)) - return TaskType::SW_CODEC; + if (!IsThreadLikelyHung(SW_CODEC)) + return SW_CODEC; - // If nothing is working, then we can't allocate anyway. - return TaskType::FAILED_CODEC; + return base::nullopt; } base::Thread& AVDACodecAllocator::GetThreadForTesting(TaskType task_type) { @@ -372,28 +345,27 @@ // We leak the clock we create, but that's okay because we're a singleton. auto clock = tick_clock ? tick_clock : new base::DefaultTickClock(); - // Create threads with names / indices that match up with TaskType. - DCHECK_EQ(threads_.size(), TaskType::AUTO_CODEC); + // Create threads with names and indices that match up with TaskType. threads_.push_back(new ThreadAndHangDetector("AVDAAutoThread", clock)); - DCHECK_EQ(threads_.size(), TaskType::SW_CODEC); threads_.push_back(new ThreadAndHangDetector("AVDASWThread", clock)); + static_assert(AUTO_CODEC == 0 && SW_CODEC == 1, + "TaskType values are not ordered correctly."); } AVDACodecAllocator::~AVDACodecAllocator() { // Only tests should reach here. Shut down threads so that we guarantee that // nothing will use the threads. - for (size_t i = 0; i < threads_.size(); i++) { - if (!threads_[i]->thread.IsRunning()) - continue; - threads_[i]->thread.Stop(); - } + for (auto* thread : threads_) + thread->thread.Stop(); } -void AVDACodecAllocator::StopThreadTask(size_t index, - base::WaitableEvent* event) { +void AVDACodecAllocator::StopThreadTask(size_t index) { threads_[index]->thread.Stop(); - if (event) - event->Signal(); + // Signal the stop event after both threads are stopped. + if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && + !threads_[SW_CODEC]->thread.IsRunning()) { + stop_event_for_testing_->Signal(); + } } } // namespace media
diff --git a/media/gpu/avda_codec_allocator.h b/media/gpu/avda_codec_allocator.h index 4553ebf..ce05ca7 100644 --- a/media/gpu/avda_codec_allocator.h +++ b/media/gpu/avda_codec_allocator.h
@@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/logging.h" +#include "base/optional.h" #include "base/synchronization/waitable_event.h" #include "base/sys_info.h" #include "base/threading/thread.h" @@ -32,17 +33,12 @@ // For TaskRunnerFor. These are used as vector indices, so please update // AVDACodecAllocator's constructor if you add / change them. -// TODO(watk): Hide this from AVDA now that we manage codec creation. enum TaskType { // Task for an autodetected MediaCodec instance. AUTO_CODEC = 0, // Task for a software-codec-required MediaCodec. SW_CODEC = 1, - - // Special value to indicate "none". This is not used as an array index. It - // must, however, be positive to keep the enum unsigned. - FAILED_CODEC = 99, }; // Configuration info for MediaCodec. @@ -121,15 +117,12 @@ // browser UI thread. void OnSurfaceDestroyed(int surface_id); - // Make sure the construction thread is started for |client|. + // Make sure the construction threads are started for |client|. Returns true + // on success. bool StartThread(AVDACodecAllocatorClient* client); void StopThread(AVDACodecAllocatorClient* client); - // Return the task runner for tasks of type |type|. If that thread failed - // to start, then fall back to the GPU main thread. - scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerFor(TaskType task_type); - // Returns true if the caller now owns the surface, or false if someone else // owns the surface. |client| will be notified when the surface is available // via OnSurfaceAvailable(). @@ -166,9 +159,9 @@ // Return true if and only if there is any AVDA registered. bool IsAnyRegisteredAVDA(); - // Return the task type to use for a new codec allocation, or FAILED_CODEC if - // there is no thread that can support it. - TaskType TaskTypeForAllocation(); + // Return the task type to use for a new codec allocation, or nullopt if + // both threads are hung. + base::Optional<TaskType> TaskTypeForAllocation(); // Return a reference to the thread for unit tests. base::Thread& GetThreadForTesting(TaskType task_type); @@ -213,10 +206,14 @@ base::WaitableEvent* stop_event = nullptr); ~AVDACodecAllocator(); + // Return the task runner for tasks of type |type|. + scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerFor(TaskType task_type); + void OnMediaCodecAndSurfaceReleased(int surface_id); - // Stop the thread indicated by |index|, then signal |event| if provided. - void StopThreadTask(size_t index, base::WaitableEvent* event = nullptr); + // Stop the thread indicated by |index|. This signals stop_event_for_testing_ + // after both threads are stopped. + void StopThreadTask(size_t index); // All registered AVDAs. std::set<AVDACodecAllocatorClient*> clients_;
diff --git a/media/gpu/avda_codec_allocator_unittest.cc b/media/gpu/avda_codec_allocator_unittest.cc index 5d4d1be1..8c066f2 100644 --- a/media/gpu/avda_codec_allocator_unittest.cc +++ b/media/gpu/avda_codec_allocator_unittest.cc
@@ -136,7 +136,7 @@ allocator_, task_type)); } - TaskType TaskTypeForAllocation() { + base::Optional<TaskType> TaskTypeForAllocation() { return PostAndWait(FROM_HERE, base::Bind(&AVDACodecAllocator::TaskTypeForAllocation, base::Unretained(allocator_))); @@ -185,26 +185,26 @@ }; TEST_F(AVDACodecAllocatorTest, ThreadsStartWhenClientsStart) { - ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC)); - ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC)); - ASSERT_TRUE(StartThread(avda1_)); - // Assert that the AUTO_CODEC thread is started. The other might not be. - ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC)); + ASSERT_FALSE(IsThreadRunning(AUTO_CODEC)); + ASSERT_FALSE(IsThreadRunning(SW_CODEC)); + StartThread(avda1_); + ASSERT_TRUE(IsThreadRunning(AUTO_CODEC)); + ASSERT_TRUE(IsThreadRunning(SW_CODEC)); } TEST_F(AVDACodecAllocatorTest, ThreadsStopAfterAllClientsStop) { StartThread(avda1_); StartThread(avda2_); StopThread(avda1_); - ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC)); + ASSERT_TRUE(IsThreadRunning(AUTO_CODEC)); StopThread(avda2_); - ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC)); - // Note the SW_CODEC thread might still be running. + ASSERT_FALSE(IsThreadRunning(AUTO_CODEC)); + ASSERT_FALSE(IsThreadRunning(SW_CODEC)); } TEST_F(AVDACodecAllocatorTest, TestHangThread) { StartThread(avda1_); - ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation()); + ASSERT_EQ(AUTO_CODEC, TaskTypeForAllocation().value()); // Hang the AUTO_CODEC thread. base::WaitableEvent about_to_wait_event( @@ -213,7 +213,7 @@ base::WaitableEvent wait_event( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); - TaskRunnerFor(TaskType::AUTO_CODEC) + TaskRunnerFor(AUTO_CODEC) ->PostTask(FROM_HERE, base::Bind(&WaitUntilRestarted, &about_to_wait_event, &wait_event)); // Wait until the task starts, so that |allocator_| starts the hang timer. @@ -221,24 +221,21 @@ // Verify that we've failed over after a long time has passed. tick_clock_.Advance(base::TimeDelta::FromSeconds(1)); - // Note that this should return the SW codec task type even if that thread - // failed to start. TaskRunnerFor() will return the current thread in that - // case too. - ASSERT_EQ(TaskType::SW_CODEC, TaskTypeForAllocation()); + ASSERT_EQ(SW_CODEC, TaskTypeForAllocation().value()); // Un-hang the thread and wait for it to let another task run. This will // notify |allocator_| that the thread is no longer hung. base::WaitableEvent done_waiting_event( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); - TaskRunnerFor(TaskType::AUTO_CODEC) + TaskRunnerFor(AUTO_CODEC) ->PostTask(FROM_HERE, base::Bind(&SignalImmediately, &done_waiting_event)); wait_event.Signal(); done_waiting_event.Wait(); // Verify that we've un-failed over. - ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation()); + ASSERT_EQ(AUTO_CODEC, TaskTypeForAllocation().value()); } TEST_F(AVDACodecAllocatorTest, AllocatingASurfaceTextureAlwaysSucceeds) {
diff --git a/media/gpu/vt_video_decode_accelerator_mac.cc b/media/gpu/vt_video_decode_accelerator_mac.cc index e179548..f79b2da9 100644 --- a/media/gpu/vt_video_decode_accelerator_mac.cc +++ b/media/gpu/vt_video_decode_accelerator_mac.cc
@@ -815,8 +815,13 @@ FinishDelayedFrames(); - // Always queue a task, even if FinishDelayedFrames() fails, so that - // destruction always completes. + if (type == TASK_DESTROY && session_) { + // Destroy the decoding session before returning from the decoder thread. + VTDecompressionSessionInvalidate(session_); + session_.reset(); + } + + // Queue a task even if flushing fails, so that destruction always completes. gpu_task_runner_->PostTask( FROM_HERE, base::Bind(&VTVideoDecodeAccelerator::FlushDone, weak_this_, type));
diff --git a/media/media_options.gni b/media/media_options.gni index 61464d4..7307730 100644 --- a/media/media_options.gni +++ b/media/media_options.gni
@@ -41,6 +41,10 @@ enable_mse_mpeg2ts_stream_parser = (proprietary_codecs && is_chromecast) || use_libfuzzer || use_afl + # Enable support for the 'cbcs' encryption scheme added by MPEG Common + # Encryption 3rd Edition (ISO/IEC 23001-7), published 02/15/2016. + enable_cbcs_encryption_scheme = is_chromecast + # Enable HEVC/H265 demuxing. Actual decoding must be provided by the # platform. Enable by default for Chromecast. enable_hevc_demuxing = proprietary_codecs && is_chromecast
diff --git a/media/mojo/BUILD.gn b/media/mojo/BUILD.gn index bece3de..27af0fe3 100644 --- a/media/mojo/BUILD.gn +++ b/media/mojo/BUILD.gn
@@ -25,7 +25,7 @@ "//media/mojo/clients", "//media/mojo/common", "//media/mojo/interfaces", - "//media/mojo/services", + "//media/mojo/services:lib", "//services/service_manager/tests:interfaces", "//testing/gmock", "//testing/gtest",
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn index c2f93d7e..dd57bde 100644 --- a/media/mojo/services/BUILD.gn +++ b/media/mojo/services/BUILD.gn
@@ -49,6 +49,15 @@ component("services") { output_name = "media_mojo_services" + public_deps = [ + ":lib", + ] +} + +# TODO(xhwang): Add this intermediate target because ServiceTest doesn't support +# services that depend on shared libraries in component build. +# See http://crbug.com/670094 +source_set("lib") { sources = [ "demuxer_stream_provider_shim.cc", "demuxer_stream_provider_shim.h", @@ -126,15 +135,19 @@ ] public_deps = [ - ":services", "//base", "//media", ] deps = [ + ":lib", "//mojo/public/c/system", "//services/service_manager/public/cpp", ] + + data_deps = [ + ":media_manifest", + ] } test("media_mojo_shell_unittests") { @@ -157,8 +170,8 @@ ] data_deps = [ - "//media/mojo/services:test_manifest", - "//media/mojo/services:media", + ":media", + ":test_manifest", ] }
diff --git a/media/mojo/services/apptest_manifest.json b/media/mojo/services/apptest_manifest.json deleted file mode 100644 index 797c48b..0000000 --- a/media/mojo/services/apptest_manifest.json +++ /dev/null
@@ -1,12 +0,0 @@ -{ - "name": "media_apptests", - "display_name": "Media Apptests", - "interface_provider_specs": { - "service_manager:connector": { - "requires": { - "*": [ "app" ], - "media": [ "media:interface_factory" ] - } - } - } -}
diff --git a/media/mojo/services/media_manifest.json b/media/mojo/services/media_manifest.json index f1c7205..64c6194 100644 --- a/media/mojo/services/media_manifest.json +++ b/media/mojo/services/media_manifest.json
@@ -4,8 +4,7 @@ "interface_provider_specs": { "service_manager:connector": { "provides": { - "media:media": [ "media::mojom::MediaService" ], - "media:interface_factory": [ "media::mojom::InterfaceFactory" ] + "media:media": [ "media::mojom::MediaService" ] }, "requires": { "*": [ "app" ]
diff --git a/media/mojo/services/media_mojo_unittest.cc b/media/mojo/services/media_mojo_unittest.cc index 9939e957..ed5e770 100644 --- a/media/mojo/services/media_mojo_unittest.cc +++ b/media/mojo/services/media_mojo_unittest.cc
@@ -19,8 +19,11 @@ #include "media/mojo/interfaces/content_decryption_module.mojom.h" #include "media/mojo/interfaces/decryptor.mojom.h" #include "media/mojo/interfaces/interface_factory.mojom.h" +#include "media/mojo/interfaces/media_service.mojom.h" #include "media/mojo/interfaces/renderer.mojom.h" #include "mojo/public/cpp/bindings/associated_binding.h" +#include "mojo/public/cpp/bindings/interface_request.h" +#include "services/service_manager/public/cpp/interface_registry.h" #include "services/service_manager/public/cpp/service_test.h" #include "testing/gmock/include/gmock/gmock.h" @@ -65,7 +68,7 @@ class MediaServiceTest : public service_manager::test::ServiceTest { public: MediaServiceTest() - : ServiceTest("media_mojo_unittests"), + : ServiceTest("media_mojo_shell_unittests"), renderer_client_binding_(&renderer_client_), video_stream_(DemuxerStream::VIDEO) {} ~MediaServiceTest() override {} @@ -74,10 +77,19 @@ ServiceTest::SetUp(); connection_ = connector()->Connect("media"); - connection_->SetConnectionLostClosure(base::Bind( - &MediaServiceTest::ConnectionClosed, base::Unretained(this))); + media::mojom::MediaServicePtr media_service; + connection_->GetInterface(&media_service); - connection_->GetInterface(&interface_factory_); + auto registry = + base::MakeUnique<service_manager::InterfaceRegistry>(std::string()); + service_manager::mojom::InterfaceProviderPtr interfaces; + registry->Bind(GetProxy(&interfaces), service_manager::Identity(), + service_manager::InterfaceProviderSpec(), + service_manager::Identity(), + service_manager::InterfaceProviderSpec()); + + media_service->CreateInterfaceFactory(mojo::GetProxy(&interface_factory_), + std::move(interfaces)); run_loop_.reset(new base::RunLoop()); } @@ -135,6 +147,7 @@ MOCK_METHOD0(ConnectionClosed, void()); protected: + std::unique_ptr<service_manager::Connection> connection_; std::unique_ptr<base::RunLoop> run_loop_; mojom::InterfaceFactoryPtr interface_factory_; @@ -148,8 +161,6 @@ std::unique_ptr<MojoDemuxerStreamImpl> mojo_video_stream_; private: - std::unique_ptr<service_manager::Connection> connection_; - DISALLOW_COPY_AND_ASSIGN(MediaServiceTest); }; @@ -190,6 +201,9 @@ #endif // defined(ENABLE_MOJO_RENDERER) TEST_F(MediaServiceTest, Lifetime) { + connection_->SetConnectionLostClosure( + base::Bind(&MediaServiceTest::ConnectionClosed, base::Unretained(this))); + // Disconnecting CDM and Renderer services doesn't terminate the app. cdm_.reset(); renderer_.reset();
diff --git a/media/mojo/services/test_manifest.json b/media/mojo/services/test_manifest.json index 4a60bf0d..27063eb 100644 --- a/media/mojo/services/test_manifest.json +++ b/media/mojo/services/test_manifest.json
@@ -5,7 +5,7 @@ "service_manager:connector": { "requires": { "*": [ "app" ], - "media": [ "media:interface_factory" ] + "media": [ "media:media" ] } } }
diff --git a/net/BUILD.gn b/net/BUILD.gn index abd9c740..5754c47 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -1149,6 +1149,8 @@ "tools/quic/quic_simple_server_stream.h", "tools/quic/quic_spdy_client_stream.cc", "tools/quic/quic_spdy_client_stream.h", + "tools/quic/quic_spdy_server_stream_base.cc", + "tools/quic/quic_spdy_server_stream_base.h", "tools/quic/quic_time_wait_list_manager.cc", "tools/quic/quic_time_wait_list_manager.h", "tools/quic/stateless_rejector.cc",
diff --git a/net/cert/nss_cert_database_unittest.cc b/net/cert/nss_cert_database_unittest.cc index 9e20f886..9832289 100644 --- a/net/cert/nss_cert_database_unittest.cc +++ b/net/cert/nss_cert_database_unittest.cc
@@ -286,6 +286,26 @@ EXPECT_EQ(0U, ListCerts().size()); } +TEST_F(CertDatabaseNSSTest, ImportFromPKCS12EmptyPassword) { + std::string pkcs12_data = ReadTestFile("client-empty-password.p12"); + + EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(GetPublicModule(), pkcs12_data, + base::string16(), + true, // is_extractable + NULL)); + EXPECT_EQ(1U, ListCerts().size()); +} + +TEST_F(CertDatabaseNSSTest, ImportFromPKCS12NullPassword) { + std::string pkcs12_data = ReadTestFile("client-null-password.p12"); + + EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(GetPublicModule(), pkcs12_data, + base::string16(), + true, // is_extractable + NULL)); + EXPECT_EQ(1U, ListCerts().size()); +} + TEST_F(CertDatabaseNSSTest, ImportCACert_SSLTrust) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem",
diff --git a/net/data/quic_http_response_cache_data/quic-datatesturl.com/index.html b/net/data/quic_http_response_cache_data/quic-datatesturl.com/index.html deleted file mode 100644 index 71aaeb0..0000000 --- a/net/data/quic_http_response_cache_data/quic-datatesturl.com/index.html +++ /dev/null
@@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Date: Sat, 22 Jun 2013 01:21:01 GMT -Server: Apache/2.2.22 (Ubuntu) -Last-Modified: Fri, 21 Jun 2013 22:20:24 GMT -ETag: "2a9d2-98-4dfb17827450a" -Accept-Ranges: bytes -Vary: Accept-Encoding -Content-Encoding: None -Keep-Alive: timeout=5, max=100 -Connection: close -Content-Type: text/html -X-Original-Url: http://quic.test.url/index.html - -This is a test page.
diff --git a/net/data/quic_http_response_cache_data/www.example.com/index.html b/net/data/quic_http_response_cache_data/www.example.com/index.html new file mode 100644 index 0000000..5edaf9af --- /dev/null +++ b/net/data/quic_http_response_cache_data/www.example.com/index.html
@@ -0,0 +1,63 @@ +HTTP/1.1 200 OK +Date: Tue, 28 Aug 2012 15:08:56 GMT +Server: Apache/2.2.3 (CentOS) +X-Powered-By: PHP/5.1.6 +Set-Cookie: bblastvisit=1346166536; expires=Wed, 28-Aug-2013 15:08:56 GMT; path=/; domain=.nasioc.com +Set-Cookie: bblastactivity=0; expires=Wed, 28-Aug-2013 15:08:56 GMT; path=/; domain=.nasioc.com +Expires: 0 +Cache-Control: private, post-check=0, pre-check=0, max-age=0 +Pragma: no-cache +X-UA-Compatible: IE=7 +Connection: close +Content-Type: text/html; charset=ISO-8859-1 + +<!doctype html> +<html> +<head> + <title>Example Domain</title> + + <meta charset="utf-8" /> + <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <style type="text/css"> + body { + background-color: #f0f0f2; + margin: 0; + padding: 0; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + + } + div { + width: 600px; + margin: 5em auto; + padding: 50px; + background-color: #fff; + border-radius: 1em; + } + a:link, a:visited { + color: #38488f; + text-decoration: none; + } + @media (max-width: 700px) { + body { + background-color: #fff; + } + div { + width: auto; + margin: 0 auto; + border-radius: 0; + padding: 1em; + } + } + </style> +</head> + +<body> +<div> + <h1>Example Domain</h1> + <p>This domain is established to be used for illustrative examples in documents. You may use this + domain in examples without prior coordination or asking for permission.</p> + <p><a href="http://www.iana.org/domains/example">More information...</a></p> +</div> +</body> +</html>
diff --git a/net/data/quic_http_response_cache_data/www.example.com/map.html b/net/data/quic_http_response_cache_data/www.example.com/map.html new file mode 100644 index 0000000..470faa1 --- /dev/null +++ b/net/data/quic_http_response_cache_data/www.example.com/map.html
@@ -0,0 +1,65 @@ +HTTP/1.1 200 OK +Date: Tue, 28 Aug 2012 15:08:56 GMT +Server: Apache/2.2.3 (CentOS) +X-Powered-By: PHP/5.1.6 +Set-Cookie: bblastvisit=1346166536; expires=Wed, 28-Aug-2013 15:08:56 GMT; path=/; domain=.nasioc.com +Set-Cookie: bblastactivity=0; expires=Wed, 28-Aug-2013 15:08:56 GMT; path=/; domain=.nasioc.com +Expires: 0 +Cache-Control: private, post-check=0, pre-check=0, max-age=0 +Pragma: no-cache +X-UA-Compatible: IE=7 +Connection: close +Content-Type: text/html; charset=ISO-8859-1 +X-Original-Url: http://www.example.com/site_map.html + + +<!doctype html> +<html> +<head> + <title>Example Domain</title> + + <meta charset="utf-8" /> + <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <style type="text/css"> + body { + background-color: #f0f0f2; + margin: 0; + padding: 0; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + + } + div { + width: 600px; + margin: 5em auto; + padding: 50px; + background-color: #fff; + border-radius: 1em; + } + a:link, a:visited { + color: #38488f; + text-decoration: none; + } + @media (max-width: 700px) { + body { + background-color: #fff; + } + div { + width: auto; + margin: 0 auto; + border-radius: 0; + padding: 1em; + } + } + </style> +</head> + +<body> +<div> + <h1>Example Domain</h1> + <p>This domain is established to be used for illustrative examples in documents. You may use this + domain in examples without prior coordination or asking for permission.</p> + <p><a href="http://www.iana.org/domains/example">More information...</a></p> +</div> +</body> +</html>
diff --git a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/favicon.ico b/net/data/quic_http_response_cache_data_with_push/www.example.com/favicon.ico similarity index 94% rename from net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/favicon.ico rename to net/data/quic_http_response_cache_data_with_push/www.example.com/favicon.ico index a559c58..b7b01b5 100644 --- a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/favicon.ico +++ b/net/data/quic_http_response_cache_data_with_push/www.example.com/favicon.ico Binary files differ
diff --git a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/index.html b/net/data/quic_http_response_cache_data_with_push/www.example.com/index.html similarity index 78% rename from net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/index.html rename to net/data/quic_http_response_cache_data_with_push/www.example.com/index.html index d13a4d02..bfcb614 100644 --- a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/index.html +++ b/net/data/quic_http_response_cache_data_with_push/www.example.com/index.html
@@ -9,7 +9,7 @@ Keep-Alive: timeout=5, max=100 Connection: close Content-Type: text/html -X-Original-Url: https://quic.test.url/ -X-Push-Url: https://quic.test.url/kitten-1.jpg +X-Original-Url: https://www.example.com/ +X-Push-Url: https://www.example.com/kitten-1.jpg This is a test page.
diff --git a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/index2.html b/net/data/quic_http_response_cache_data_with_push/www.example.com/index2.html similarity index 68% rename from net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/index2.html rename to net/data/quic_http_response_cache_data_with_push/www.example.com/index2.html index 74afa66..58c5db9 100644 --- a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/index2.html +++ b/net/data/quic_http_response_cache_data_with_push/www.example.com/index2.html
@@ -9,8 +9,8 @@ Keep-Alive: timeout=5, max=100 Connection: close Content-Type: text/html -X-Original-Url: https://quic.test.url/index2.html -X-Push-Url: https://quic.test.url/kitten-1.jpg -X-Push-Url: https://quic.test.url/favicon.ico +X-Original-Url: https://www.example.com/index2.html +X-Push-Url: https://www.example.com/kitten-1.jpg +X-Push-Url: https://www.example.com/favicon.ico This is a test page.
diff --git a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/kitten-1.jpg b/net/data/quic_http_response_cache_data_with_push/www.example.com/kitten-1.jpg similarity index 99% rename from net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/kitten-1.jpg rename to net/data/quic_http_response_cache_data_with_push/www.example.com/kitten-1.jpg index 25ba08a..25d543b8 100644 --- a/net/data/quic_http_response_cache_data_with_push/quic-datatesturl.com/kitten-1.jpg +++ b/net/data/quic_http_response_cache_data_with_push/www.example.com/kitten-1.jpg Binary files differ
diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README index 2d32454..962978b 100644 --- a/net/data/ssl/certificates/README +++ b/net/data/ssl/certificates/README
@@ -79,6 +79,15 @@ - client-nokey.p12 : A PKCS #12 file containing a client certificate (the same as the one in client.p12) but no private key. The password is "12345". +- client-empty-password.p12 : A PKCS #12 file containing an unencrypted client + certificate and a encrypted private key. The password is the empty string, + encoded as two zero bytes. (PKCS#12 passwords are encoded as + NUL-terminated UTF-16.) + +- client-null-password.p12 : A PKCS #12 file containing an unencrypted client + certificate and a encrypted private key. The password is the empty string, + encoded as the empty byte string. + - unittest.selfsigned.der : A self-signed certificate generated using private key in unittest.key.bin. The common name is "unittest".
diff --git a/net/data/ssl/certificates/client-empty-password.p12 b/net/data/ssl/certificates/client-empty-password.p12 new file mode 100644 index 0000000..e0b514c4 --- /dev/null +++ b/net/data/ssl/certificates/client-empty-password.p12 Binary files differ
diff --git a/net/data/ssl/certificates/client-null-password.p12 b/net/data/ssl/certificates/client-null-password.p12 new file mode 100644 index 0000000..a8c45a7 --- /dev/null +++ b/net/data/ssl/certificates/client-null-password.p12 Binary files differ
diff --git a/net/data/ssl/certificates/quic_test.example.com.key.sct b/net/data/ssl/certificates/quic_test.example.com.key.sct index 55b0b42..0d19282 100644 --- a/net/data/ssl/certificates/quic_test.example.com.key.sct +++ b/net/data/ssl/certificates/quic_test.example.com.key.sct Binary files differ
diff --git a/net/data/ssl/certificates/quic_test_ecc.example.com.sct b/net/data/ssl/certificates/quic_test_ecc.example.com.sct new file mode 100644 index 0000000..3758265 --- /dev/null +++ b/net/data/ssl/certificates/quic_test_ecc.example.com.sct Binary files differ
diff --git a/net/net.gypi b/net/net.gypi index c6eeabb..598a8d3 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -1902,6 +1902,8 @@ 'quic/test_tools/simulator/alarm_factory.h', 'quic/test_tools/simulator/link.cc', 'quic/test_tools/simulator/link.h', + 'quic/test_tools/simulator/packet_filter.cc', + 'quic/test_tools/simulator/packet_filter.h', 'quic/test_tools/simulator/port.cc', 'quic/test_tools/simulator/port.h', 'quic/test_tools/simulator/queue.cc', @@ -2063,6 +2065,7 @@ 'tools/quic/quic_simple_server_stream_test.cc', 'tools/quic/quic_simple_server_test.cc', 'tools/quic/quic_spdy_client_stream_test.cc', + 'tools/quic/quic_spdy_server_stream_base_test.cc', 'tools/quic/quic_time_wait_list_manager_test.cc', 'tools/quic/stateless_rejector_test.cc', 'tools/quic/test_tools/limited_mtu_test_writer.cc',
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc index 04908c2..af248b3 100644 --- a/net/quic/core/congestion_control/bbr_sender.cc +++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -99,7 +99,8 @@ last_sample_is_app_limited_(false), recovery_state_(NOT_IN_RECOVERY), end_recovery_at_(0), - recovery_window_(max_congestion_window_) { + recovery_window_(max_congestion_window_), + enforce_startup_pacing_rate_increase_(FLAGS_quic_bbr_faster_startup) { EnterStartupMode(); } @@ -454,7 +455,24 @@ return; } - pacing_rate_ = pacing_gain_ * BandwidthEstimate(); + QuicBandwidth target_rate = pacing_gain_ * BandwidthEstimate(); + + // Ensure that the pacing rate does not drop too low during the startup. + if (!is_at_full_bandwidth_ && enforce_startup_pacing_rate_increase_) { + // Pace at the rate of initial_window / RTT as soon as RTT measurements are + // available. + if (pacing_rate_.IsZero() && !rtt_stats_->min_rtt().IsZero()) { + pacing_rate_ = QuicBandwidth::FromBytesAndTimeDelta( + initial_congestion_window_, rtt_stats_->min_rtt()); + return; + } + + // Do not decrease the pacing rate during the startup. + pacing_rate_ = std::max(pacing_rate_, target_rate); + return; + } + + pacing_rate_ = target_rate; } void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked) {
diff --git a/net/quic/core/congestion_control/bbr_sender.h b/net/quic/core/congestion_control/bbr_sender.h index 952568d..0838c54 100644 --- a/net/quic/core/congestion_control/bbr_sender.h +++ b/net/quic/core/congestion_control/bbr_sender.h
@@ -270,6 +270,10 @@ // A window used to limit the number of bytes in flight during loss recovery. QuicByteCount recovery_window_; + // Indicates whether to always only increase the pacing rate during startup. + // Latches |FLAGS_quic_bbr_faster_startup|. + bool enforce_startup_pacing_rate_increase_; + DISALLOW_COPY_AND_ASSIGN(BbrSender); };
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc index e85c86f4..b4ffa58 100644 --- a/net/quic/core/congestion_control/bbr_sender_test.cc +++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -78,6 +78,8 @@ "BBR sender", Perspective::IS_SERVER, 42) { + FLAGS_quic_bbr_faster_startup = true; + rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats(); sender_ = new BbrSender(simulator_.GetClock(), rtt_stats_, QuicSentPacketManagerPeer::GetUnackedPacketMap( @@ -109,6 +111,7 @@ const QuicClock* clock_; const RttStats* rtt_stats_; BbrSender* sender_; + QuicFlagSaver flags_; // Creates a default setup, which is a network with a bottleneck between the // receiver and the switch. The switch has the buffers four times larger than @@ -233,7 +236,7 @@ float loss_rate = static_cast<float>(bbr_sender_.connection()->GetStats().packets_lost) / bbr_sender_.connection()->GetStats().packets_sent; - EXPECT_LE(loss_rate, 0.20); + EXPECT_LE(loss_rate, 0.27); } // Ensures the code transitions loss recovery states correctly (NOT_IN_RECOVERY @@ -430,5 +433,36 @@ EXPECT_EQ(2, sender_->ExportDebugState().gain_cycle_index); } +// Ensure that the pacing rate does not drop at startup. +TEST_F(BbrSenderTest, NoBandwidthDropOnStartup) { + CreateDefaultSetup(); + + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5); + bool simulator_result; + + QuicBandwidth initial_rate = QuicBandwidth::FromBytesAndTimeDelta( + kInitialCongestionWindowPackets * kDefaultTCPMSS, + QuicTime::Delta::FromMicroseconds(rtt_stats_->initial_rtt_us())); + EXPECT_GE(sender_->PacingRate(0), initial_rate); + + // Send a packet. + bbr_sender_.AddBytesToTransfer(1000); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return receiver_.bytes_received() == 1000; }, timeout); + ASSERT_TRUE(simulator_result); + EXPECT_GE(sender_->PacingRate(0), initial_rate); + + // Wait for a while. + simulator_.RunFor(QuicTime::Delta::FromSeconds(2)); + EXPECT_GE(sender_->PacingRate(0), initial_rate); + + // Send another packet. + bbr_sender_.AddBytesToTransfer(1000); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return receiver_.bytes_received() == 2000; }, timeout); + ASSERT_TRUE(simulator_result); + EXPECT_GE(sender_->PacingRate(0), initial_rate); +} + } // namespace test } // namespace net
diff --git a/net/quic/core/congestion_control/cubic.cc b/net/quic/core/congestion_control/cubic.cc index 7b7d9f8..8a5083b 100644 --- a/net/quic/core/congestion_control/cubic.cc +++ b/net/quic/core/congestion_control/cubic.cc
@@ -44,7 +44,8 @@ num_connections_(kDefaultNumConnections), epoch_(QuicTime::Zero()), app_limited_start_time_(QuicTime::Zero()), - last_update_time_(QuicTime::Zero()) { + last_update_time_(QuicTime::Zero()), + fix_convex_mode_(false) { Reset(); } @@ -80,6 +81,7 @@ origin_point_congestion_window_ = 0; time_to_origin_point_ = 0; last_target_congestion_window_ = 0; + fix_convex_mode_ = false; } void Cubic::OnApplicationLimited() { @@ -88,6 +90,10 @@ epoch_ = QuicTime::Zero(); } +void Cubic::SetFixConvexMode(bool fix_convex_mode) { + fix_convex_mode_ = fix_convex_mode; +} + QuicPacketCount Cubic::CongestionWindowAfterPacketLoss( QuicPacketCount current_congestion_window) { if (current_congestion_window < last_max_congestion_window_) { @@ -139,16 +145,29 @@ // Change the time unit from microseconds to 2^10 fractions per second. Take // the round trip time in account. This is done to allow us to use shift as a // divide operator. - int64_t elapsed_time = + const int64_t elapsed_time = ((current_time + delay_min - epoch_).ToMicroseconds() << 10) / kNumMicrosPerSecond; + DCHECK_GE(elapsed_time, 0); int64_t offset = time_to_origin_point_ - elapsed_time; + if (fix_convex_mode_) { + // Right-shifts of negative, signed numbers have + // implementation-dependent behavior. Force the offset to be + // positive, similar to the kernel implementation. + offset = std::abs(time_to_origin_point_ - elapsed_time); + } + QuicPacketCount delta_congestion_window = (kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale; + const bool add_delta = elapsed_time > time_to_origin_point_; + DCHECK(add_delta || + (origin_point_congestion_window_ > delta_congestion_window)); QuicPacketCount target_congestion_window = - origin_point_congestion_window_ - delta_congestion_window; + (fix_convex_mode_ && add_delta) + ? origin_point_congestion_window_ + delta_congestion_window + : origin_point_congestion_window_ - delta_congestion_window; // Limit the CWND increase to half the acked packets rounded up to the // nearest packet.
diff --git a/net/quic/core/congestion_control/cubic.h b/net/quic/core/congestion_control/cubic.h index 30657e5..dba6493c 100644 --- a/net/quic/core/congestion_control/cubic.h +++ b/net/quic/core/congestion_control/cubic.h
@@ -34,9 +34,9 @@ QuicPacketCount CongestionWindowAfterPacketLoss(QuicPacketCount current); // Compute a new congestion window to use after a received ACK. - // Returns the new congestion window in packets. The new congestion window - // follows a cubic function that depends on the time passed since last - // packet loss. + // Returns the new congestion window in packets. The new congestion + // window follows a cubic function that depends on the time passed + // since last packet loss. QuicPacketCount CongestionWindowAfterAck(QuicPacketCount current, QuicTime::Delta delay_min); @@ -44,6 +44,11 @@ // window. Resets Cubic state during quiescence. void OnApplicationLimited(); + // If true, enable the fix for the convex-mode signing bug. See + // b/32170105 for more information about the bug. + // TODO(jokulik): Remove once the fix is enabled by default. + void SetFixConvexMode(bool fix_convex_mode); + private: static const QuicTime::Delta MaxCubicTimeInterval() { return QuicTime::Delta::FromMilliseconds(30); @@ -97,6 +102,10 @@ // Last congestion window in packets computed by cubic function. QuicPacketCount last_target_congestion_window_; + // Fix convex mode for cubic. + // TODO(jokulik): Remove once the cubic convex experiment is done. + bool fix_convex_mode_; + DISALLOW_COPY_AND_ASSIGN(Cubic); };
diff --git a/net/quic/core/congestion_control/cubic_bytes.cc b/net/quic/core/congestion_control/cubic_bytes.cc index 6f62aa4..fd7a945 100644 --- a/net/quic/core/congestion_control/cubic_bytes.cc +++ b/net/quic/core/congestion_control/cubic_bytes.cc
@@ -43,7 +43,8 @@ : clock_(clock), num_connections_(kDefaultNumConnections), epoch_(QuicTime::Zero()), - last_update_time_(QuicTime::Zero()) { + last_update_time_(QuicTime::Zero()), + fix_convex_mode_(false) { Reset(); } @@ -77,6 +78,11 @@ origin_point_congestion_window_ = 0; time_to_origin_point_ = 0; last_target_congestion_window_ = 0; + fix_convex_mode_ = false; +} + +void CubicBytes::SetFixConvexMode(bool fix_convex_mode) { + fix_convex_mode_ = fix_convex_mode; } void CubicBytes::OnApplicationLimited() { @@ -146,20 +152,36 @@ kNumMicrosPerSecond; int64_t offset = time_to_origin_point_ - elapsed_time; + if (fix_convex_mode_) { + // Right-shifts of negative, signed numbers have + // implementation-dependent behavior. In the fix, force the + // offset to be positive, as is done in the kernel. + const int64_t positive_offset = + std::abs(time_to_origin_point_ - elapsed_time); + offset = positive_offset; + } QuicByteCount delta_congestion_window = ((kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale) * kDefaultTCPMSS; + const bool add_delta = elapsed_time > time_to_origin_point_; + DCHECK(add_delta || + (origin_point_congestion_window_ > delta_congestion_window)); QuicByteCount target_congestion_window = - origin_point_congestion_window_ - delta_congestion_window; + (fix_convex_mode_ && add_delta) + ? origin_point_congestion_window_ + delta_congestion_window + : origin_point_congestion_window_ - delta_congestion_window; // Limit the CWND increase to half the acked bytes. target_congestion_window = min(target_congestion_window, current_congestion_window + acked_bytes_count_ / 2); DCHECK_LT(0u, estimated_tcp_congestion_window_); - // Increase the window by Alpha * 1 MSS of bytes every time we ack an - // estimated tcp window of bytes. + // Increase the window by approximately Alpha * 1 MSS of bytes every + // time we ack an estimated tcp window of bytes. For small + // congestion windows (less than 25), the formula below will + // increase slightly slower than linearly per estimated tcp window + // of bytes. estimated_tcp_congestion_window_ += acked_bytes_count_ * (Alpha() * kDefaultTCPMSS) / estimated_tcp_congestion_window_;
diff --git a/net/quic/core/congestion_control/cubic_bytes.h b/net/quic/core/congestion_control/cubic_bytes.h index 73998ad..784ce32 100644 --- a/net/quic/core/congestion_control/cubic_bytes.h +++ b/net/quic/core/congestion_control/cubic_bytes.h
@@ -45,6 +45,8 @@ // window. Resets Cubic state during quiescence. void OnApplicationLimited(); + void SetFixConvexMode(bool fix_convex_mode); + private: static const QuicTime::Delta MaxCubicTimeInterval() { return QuicTime::Delta::FromMilliseconds(30); @@ -89,6 +91,10 @@ // Last congestion window in packets computed by cubic function. QuicByteCount last_target_congestion_window_; + // Fix convex mode for cubic. + // TODO(jokulik): Remove once the cubic convex experiment is done. + bool fix_convex_mode_; + DISALLOW_COPY_AND_ASSIGN(CubicBytes); };
diff --git a/net/quic/core/congestion_control/cubic_bytes_test.cc b/net/quic/core/congestion_control/cubic_bytes_test.cc index 85ed458..57c5ef1 100644 --- a/net/quic/core/congestion_control/cubic_bytes_test.cc +++ b/net/quic/core/congestion_control/cubic_bytes_test.cc
@@ -18,48 +18,182 @@ const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections * (1 - kNConnectionBeta) / (1 + kNConnectionBeta); -class CubicBytesTest : public ::testing::Test { +class CubicBytesTest : public ::testing::TestWithParam<bool> { protected: CubicBytesTest() : one_ms_(QuicTime::Delta::FromMilliseconds(1)), hundred_ms_(QuicTime::Delta::FromMilliseconds(100)), - cubic_(&clock_) {} + cubic_(&clock_), + fix_convex_mode_(GetParam()) { + cubic_.SetFixConvexMode(fix_convex_mode_); + } + + QuicByteCount RenoCwndInBytes(QuicByteCount current_cwnd) { + QuicByteCount reno_estimated_cwnd = + current_cwnd + + kDefaultTCPMSS * (kNConnectionAlpha * kDefaultTCPMSS) / current_cwnd; + return reno_estimated_cwnd; + } + + QuicByteCount ConservativeCwndInBytes(QuicByteCount current_cwnd) { + QuicByteCount conservative_cwnd = current_cwnd + kDefaultTCPMSS / 2; + return conservative_cwnd; + } + + QuicByteCount CubicConvexCwndInBytes(QuicByteCount initial_cwnd, + int64_t rtt_ms, + int64_t elapsed_time_ms) { + const int64_t offset = ((elapsed_time_ms + rtt_ms) << 10) / 1000; + const QuicByteCount delta_congestion_window = + ((410 * offset * offset * offset) >> 40) * kDefaultTCPMSS; + const QuicByteCount cubic_cwnd = initial_cwnd + delta_congestion_window; + return cubic_cwnd; + } + const QuicTime::Delta one_ms_; const QuicTime::Delta hundred_ms_; MockClock clock_; CubicBytes cubic_; + bool fix_convex_mode_; }; -TEST_F(CubicBytesTest, AboveOrigin) { +INSTANTIATE_TEST_CASE_P(CubicBytesTests, CubicBytesTest, testing::Bool()); + +// TODO(jokulik): The original "AboveOrigin" test, below, is very +// loose. It's nearly impossible to make the test tighter without +// deploying the fix for convex mode. Once cubic convex is deployed, +// replace "AboveOrigin" with this test. +TEST_P(CubicBytesTest, AboveOriginWithTighterBounds) { + if (!fix_convex_mode_) { + // Without convex mode fixed, the behavior of the algorithm is so + // far from expected, there's no point in doing a tighter test. + return; + } + // Convex growth. + const QuicTime::Delta rtt_min = hundred_ms_; + int64_t rtt_min_ms = rtt_min.ToMilliseconds(); + float rtt_min_s = rtt_min_ms / 1000.0; + QuicByteCount current_cwnd = 10 * kDefaultTCPMSS; + const QuicByteCount initial_cwnd = current_cwnd; + + clock_.AdvanceTime(one_ms_); + const QuicTime initial_time = clock_.ApproximateNow(); + const QuicByteCount expected_first_cwnd = RenoCwndInBytes(current_cwnd); + current_cwnd = + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min); + ASSERT_EQ(expected_first_cwnd, current_cwnd); + + // Normal TCP phase. + // The maximum number of expected Reno RTTs is calculated by + // finding the point where the cubic curve and the reno curve meet. + const int max_reno_rtts = + std::sqrt(kNConnectionAlpha / (.4 * rtt_min_s * rtt_min_s * rtt_min_s)) - + 1; + for (int i = 0; i < max_reno_rtts; ++i) { + // Alternatively, we expect it to increase by one, every time we + // receive current_cwnd/Alpha acks back. (This is another way of + // saying we expect cwnd to increase by approximately Alpha once + // we receive current_cwnd number ofacks back). + const uint64_t num_acks_this_epoch = + current_cwnd / kDefaultTCPMSS / kNConnectionAlpha; + const QuicByteCount initial_cwnd_this_epoch = current_cwnd; + for (QuicPacketCount n = 0; n < num_acks_this_epoch; ++n) { + // Call once per ACK. + const QuicByteCount expected_next_cwnd = RenoCwndInBytes(current_cwnd); + current_cwnd = cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, + current_cwnd, rtt_min); + ASSERT_EQ(expected_next_cwnd, current_cwnd); + } + // Our byte-wise Reno implementation is an estimate. We expect + // the cwnd to increase by approximately one MSS every + // cwnd/kDefaultTCPMSS/Alpha acks, but it may be off by as much as + // half a packet for smaller values of current_cwnd. + const QuicByteCount cwnd_change_this_epoch = + current_cwnd - initial_cwnd_this_epoch; + ASSERT_NEAR(kDefaultTCPMSS, cwnd_change_this_epoch, kDefaultTCPMSS / 2); + clock_.AdvanceTime(hundred_ms_); + } + + // Because our byte-wise Reno under-estimates the cwnd, we switch to + // conservative increases for a few acks before switching to true + // cubic increases. + for (int i = 0; i < 3; ++i) { + const QuicByteCount next_expected_cwnd = + ConservativeCwndInBytes(current_cwnd); + current_cwnd = + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min); + ASSERT_EQ(next_expected_cwnd, current_cwnd); + } + + for (int i = 0; i < 54; ++i) { + const uint64_t max_acks_this_epoch = current_cwnd / kDefaultTCPMSS; + const int elapsed_time_ms = + (clock_.ApproximateNow() - initial_time).ToMilliseconds(); + const QuicByteCount expected_cwnd = CubicConvexCwndInBytes( + initial_cwnd, rtt_min.ToMilliseconds(), elapsed_time_ms); + current_cwnd = + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min); + ASSERT_EQ(expected_cwnd, current_cwnd); + + for (QuicPacketCount n = 1; n < max_acks_this_epoch; ++n) { + // Call once per ACK. + ASSERT_EQ(current_cwnd, cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min)); + } + clock_.AdvanceTime(hundred_ms_); + } + const int elapsed_time_ms = + (clock_.ApproximateNow() - initial_time).ToMilliseconds(); + const QuicByteCount expected_cwnd = CubicConvexCwndInBytes( + initial_cwnd, rtt_min.ToMilliseconds(), elapsed_time_ms); + current_cwnd = + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min); + ASSERT_EQ(expected_cwnd, current_cwnd); +} + +TEST_P(CubicBytesTest, AboveOrigin) { // Convex growth. const QuicTime::Delta rtt_min = hundred_ms_; QuicByteCount current_cwnd = 10 * kDefaultTCPMSS; - QuicByteCount expected_cwnd = current_cwnd + (kDefaultTCPMSS / 2); + // Without the signed-integer, cubic-convex fix, we start out in the + // wrong mode. + QuicPacketCount expected_cwnd = fix_convex_mode_ + ? RenoCwndInBytes(current_cwnd) + : ConservativeCwndInBytes(current_cwnd); // Initialize the state. clock_.AdvanceTime(one_ms_); - EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck( + ASSERT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck( kDefaultTCPMSS, current_cwnd, rtt_min)); current_cwnd = expected_cwnd; + const QuicPacketCount initial_cwnd = expected_cwnd; // Normal TCP phase. for (int i = 0; i < 48; ++i) { for (QuicPacketCount n = 1; n < current_cwnd / kDefaultTCPMSS / kNConnectionAlpha; ++n) { // Call once per ACK. - EXPECT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck( + ASSERT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck( kDefaultTCPMSS, current_cwnd, rtt_min), kDefaultTCPMSS); } clock_.AdvanceTime(hundred_ms_); current_cwnd = cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min); - EXPECT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS); - expected_cwnd += kDefaultTCPMSS; + if (fix_convex_mode_) { + // When we fix convex mode and the uint64 arithmetic, we + // increase the expected_cwnd only after after the first 100ms, + // rather than after the initial 1ms. + expected_cwnd += kDefaultTCPMSS; + ASSERT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS); + } else { + ASSERT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS); + expected_cwnd += kDefaultTCPMSS; + } } // Cubic phase. for (int i = 0; i < 52; ++i) { for (QuicPacketCount n = 1; n < current_cwnd / kDefaultTCPMSS; ++n) { // Call once per ACK. - EXPECT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck( + ASSERT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck( kDefaultTCPMSS, current_cwnd, rtt_min), kDefaultTCPMSS); } @@ -71,14 +205,23 @@ float elapsed_time_s = 10.0f + 0.1f; // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4. expected_cwnd = - 11 + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024; + initial_cwnd / kDefaultTCPMSS + + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024; + // Without the convex mode fix, the result is off by one. + if (!fix_convex_mode_) { + ++expected_cwnd; + } EXPECT_EQ(expected_cwnd, current_cwnd / kDefaultTCPMSS); } -TEST_F(CubicBytesTest, LossEvents) { +TEST_P(CubicBytesTest, LossEvents) { const QuicTime::Delta rtt_min = hundred_ms_; QuicByteCount current_cwnd = 422 * kDefaultTCPMSS; - QuicPacketCount expected_cwnd = current_cwnd + kDefaultTCPMSS / 2; + // Without the signed-integer, cubic-convex fix, we mistakenly + // increment cwnd after only one_ms_ and a single ack. + QuicPacketCount expected_cwnd = fix_convex_mode_ + ? RenoCwndInBytes(current_cwnd) + : current_cwnd + kDefaultTCPMSS / 2; // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck( @@ -91,11 +234,15 @@ cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); } -TEST_F(CubicBytesTest, BelowOrigin) { +TEST_P(CubicBytesTest, BelowOrigin) { // Concave growth. const QuicTime::Delta rtt_min = hundred_ms_; QuicByteCount current_cwnd = 422 * kDefaultTCPMSS; - QuicPacketCount expected_cwnd = current_cwnd + kDefaultTCPMSS / 2; + // Without the signed-integer, cubic-convex fix, we mistakenly + // increment cwnd after only one_ms_ and a single ack. + QuicPacketCount expected_cwnd = fix_convex_mode_ + ? RenoCwndInBytes(current_cwnd) + : current_cwnd + kDefaultTCPMSS / 2; // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
diff --git a/net/quic/core/congestion_control/cubic_test.cc b/net/quic/core/congestion_control/cubic_test.cc index a048f85c..578b94e 100644 --- a/net/quic/core/congestion_control/cubic_test.cc +++ b/net/quic/core/congestion_control/cubic_test.cc
@@ -18,62 +18,97 @@ const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections * (1 - kNConnectionBeta) / (1 + kNConnectionBeta); -class CubicTest : public ::testing::Test { +// TODO(jokulik): Once we've rolled out the cubic convex fix, we will +// no longer need a parameterized test. +class CubicTest : public ::testing::TestWithParam<bool> { protected: CubicTest() : one_ms_(QuicTime::Delta::FromMilliseconds(1)), hundred_ms_(QuicTime::Delta::FromMilliseconds(100)), - cubic_(&clock_) {} + cubic_(&clock_) { + fix_convex_mode_ = GetParam(); + cubic_.SetFixConvexMode(fix_convex_mode_); + } const QuicTime::Delta one_ms_; const QuicTime::Delta hundred_ms_; MockClock clock_; Cubic cubic_; + bool fix_convex_mode_; }; -TEST_F(CubicTest, AboveOrigin) { +INSTANTIATE_TEST_CASE_P(CubicTests, CubicTest, testing::Bool()); + +TEST_P(CubicTest, AboveOrigin) { // Convex growth. const QuicTime::Delta rtt_min = hundred_ms_; + const float rtt_min_s = rtt_min.ToMilliseconds() / 1000.0; QuicPacketCount current_cwnd = 10; - QuicPacketCount expected_cwnd = current_cwnd + 1; + // Without the signed-integer, cubic-convex fix, we mistakenly + // increment cwnd after only one_ms_ and a single ack. + QuicPacketCount expected_cwnd = + fix_convex_mode_ ? current_cwnd : current_cwnd + 1; // Initialize the state. clock_.AdvanceTime(one_ms_); - EXPECT_EQ(expected_cwnd, - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min)); - current_cwnd = expected_cwnd; + const QuicTime initial_time = clock_.ApproximateNow(); + current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); + ASSERT_EQ(expected_cwnd, current_cwnd); + const QuicPacketCount initial_cwnd = current_cwnd; // Normal TCP phase. - for (int i = 0; i < 48; ++i) { - for (QuicPacketCount n = 1; n < current_cwnd / kNConnectionAlpha; ++n) { + // The maximum number of expected reno RTTs can be calculated by + // finding the point where the cubic curve and the reno curve meet. + const int max_reno_rtts = + std::sqrt(kNConnectionAlpha / (.4 * rtt_min_s * rtt_min_s * rtt_min_s)) - + 1; + for (int i = 0; i < max_reno_rtts; ++i) { + const QuicByteCount max_per_ack_cwnd = current_cwnd; + for (QuicPacketCount n = 1; n < max_per_ack_cwnd / kNConnectionAlpha; ++n) { // Call once per ACK. - EXPECT_NEAR(current_cwnd, - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min), 1); + const QuicByteCount next_cwnd = + cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); + ASSERT_EQ(current_cwnd, next_cwnd); } clock_.AdvanceTime(hundred_ms_); current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); - EXPECT_NEAR(expected_cwnd, current_cwnd, 1); - expected_cwnd++; + if (fix_convex_mode_) { + // When we fix convex mode and the uint64 arithmetic, we + // increase the expected_cwnd only after after the first 100ms, + // rather than after the initial 1ms. + expected_cwnd++; + ASSERT_EQ(expected_cwnd, current_cwnd); + } else { + ASSERT_EQ(expected_cwnd, current_cwnd); + expected_cwnd++; + } } // Cubic phase. for (int i = 0; i < 52; ++i) { for (QuicPacketCount n = 1; n < current_cwnd; ++n) { // Call once per ACK. - EXPECT_EQ(current_cwnd, + ASSERT_EQ(current_cwnd, cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min)); } clock_.AdvanceTime(hundred_ms_); current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); } // Total time elapsed so far; add min_rtt (0.1s) here as well. - float elapsed_time_s = 10.0f + 0.1f; + const float elapsed_time_ms = + (clock_.ApproximateNow() - initial_time).ToMilliseconds() + + rtt_min.ToMilliseconds(); + const float elapsed_time_s = elapsed_time_ms / 1000.0; // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4. expected_cwnd = - 11 + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024; + initial_cwnd + + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024; EXPECT_EQ(expected_cwnd, current_cwnd); } -TEST_F(CubicTest, LossEvents) { +TEST_P(CubicTest, LossEvents) { const QuicTime::Delta rtt_min = hundred_ms_; QuicPacketCount current_cwnd = 422; - QuicPacketCount expected_cwnd = current_cwnd + 1; + // Without the signed-integer, cubic-convex fix, we mistakenly + // increment cwnd after only one_ms_ and a single ack. + QuicPacketCount expected_cwnd = + fix_convex_mode_ ? current_cwnd : current_cwnd + 1; // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, @@ -86,11 +121,14 @@ cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); } -TEST_F(CubicTest, BelowOrigin) { +TEST_P(CubicTest, BelowOrigin) { // Concave growth. const QuicTime::Delta rtt_min = hundred_ms_; QuicPacketCount current_cwnd = 422; - QuicPacketCount expected_cwnd = current_cwnd + 1; + // Without the signed-integer, cubic-convex fix, we mistakenly + // increment cwnd after only one_ms_ and a single ack. + QuicPacketCount expected_cwnd = + fix_convex_mode_ ? current_cwnd : current_cwnd + 1; // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd,
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc index f793211..0f914b2 100644 --- a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc +++ b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
@@ -47,6 +47,16 @@ TcpCubicSenderBytes::~TcpCubicSenderBytes() {} +void TcpCubicSenderBytes::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + TcpCubicSenderBase::SetFromConfig(config, perspective); + if (FLAGS_quic_fix_cubic_convex_mode && + config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kCCVX)) { + cubic_.SetFixConvexMode(true); + } +} + void TcpCubicSenderBytes::SetCongestionWindowFromBandwidthAndRtt( QuicBandwidth bandwidth, QuicTime::Delta rtt) {
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h index 1359b64..5711ccd 100644 --- a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h +++ b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h
@@ -39,6 +39,8 @@ ~TcpCubicSenderBytes() override; // Start implementation of SendAlgorithmInterface. + void SetFromConfig(const QuicConfig& config, + Perspective perspective) override; void SetNumEmulatedConnections(int num_connections) override; void OnConnectionMigration() override; QuicByteCount GetCongestionWindow() const override;
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc b/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc index 0a5d265..2a54db6b 100644 --- a/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc +++ b/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc
@@ -46,6 +46,16 @@ TcpCubicSenderPackets::~TcpCubicSenderPackets() {} +void TcpCubicSenderPackets::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + TcpCubicSenderBase::SetFromConfig(config, perspective); + if (FLAGS_quic_fix_cubic_convex_mode && + config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kCCVX)) { + cubic_.SetFixConvexMode(true); + } +} + void TcpCubicSenderPackets::SetCongestionWindowFromBandwidthAndRtt( QuicBandwidth bandwidth, QuicTime::Delta rtt) {
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_packets.h b/net/quic/core/congestion_control/tcp_cubic_sender_packets.h index 8f2286de..5e3c7c2 100644 --- a/net/quic/core/congestion_control/tcp_cubic_sender_packets.h +++ b/net/quic/core/congestion_control/tcp_cubic_sender_packets.h
@@ -41,6 +41,8 @@ ~TcpCubicSenderPackets() override; // Start implementation of SendAlgorithmInterface. + void SetFromConfig(const QuicConfig& config, + Perspective perspective) override; void SetNumEmulatedConnections(int num_connections) override; void OnConnectionMigration() override; QuicByteCount GetCongestionWindow() const override;
diff --git a/net/quic/core/crypto/crypto_protocol.h b/net/quic/core/crypto/crypto_protocol.h index 432b9f5..9772f171 100644 --- a/net/quic/core/crypto/crypto_protocol.h +++ b/net/quic/core/crypto/crypto_protocol.h
@@ -107,6 +107,7 @@ // Retransmissions. const QuicTag kLFAK = TAG('L', 'F', 'A', 'K'); // Don't invoke FACK on the // first ack. +const QuicTag kCCVX = TAG('C', 'C', 'V', 'X'); // Fix Cubic convex bug. // Optional support of truncated Connection IDs. If sent by a peer, the value // is the minimum number of bytes allowed for the connection ID sent to the
diff --git a/net/quic/core/crypto/crypto_server_test.cc b/net/quic/core/crypto/crypto_server_test.cc index 535dfa0..11838fe4 100644 --- a/net/quic/core/crypto/crypto_server_test.cc +++ b/net/quic/core/crypto/crypto_server_test.cc
@@ -121,7 +121,6 @@ client_version_string_ = QuicTagToString(QuicVersionToQuicTag(client_version_)); - FLAGS_quic_require_handshake_confirmation_pre33 = false; FLAGS_enable_quic_stateless_reject_support = GetParam().enable_stateless_rejects; use_stateless_rejects_ = GetParam().use_stateless_rejects;
diff --git a/net/quic/core/crypto/quic_crypto_server_config.cc b/net/quic/core/crypto/quic_crypto_server_config.cc index a3f5e2b..d7db1fa 100644 --- a/net/quic/core/crypto/quic_crypto_server_config.cc +++ b/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -461,8 +461,8 @@ if (result->error_code == QUIC_NO_ERROR) { // QUIC requires a new proof for each CHLO so clear any existing proof. signed_config->chain = nullptr; - signed_config->signature = ""; - signed_config->cert_sct = ""; + signed_config->proof.signature = ""; + signed_config->proof.leaf_cert_scts = ""; EvaluateClientHello(server_ip, version, requested_config, primary_config, signed_config, result, std::move(done_cb)); } else { @@ -554,9 +554,7 @@ std::unique_ptr<ProofSource::Details> details) override { if (ok) { signed_config_->chain = chain; - signed_config_->signature = proof.signature; - signed_config_->cert_sct = proof.leaf_cert_scts; - signed_config_->send_expect_ct_header = proof.send_expect_ct_header; + signed_config_->proof = proof; } config_->ProcessClientHelloAfterGetProof( !ok, std::move(details), *validate_chlo_result_, reject_only_, @@ -702,8 +700,7 @@ helper.Fail(QUIC_HANDSHAKE_FAILED, "Missing or invalid crypto proof."); return; } - signed_config->signature = proof.signature; - signed_config->cert_sct = proof.leaf_cert_scts; + signed_config->proof = proof; } helper.DetachCallback(); @@ -1148,9 +1145,7 @@ std::unique_ptr<ProofSource::Details> details) override { if (ok) { signed_config_->chain = chain; - signed_config_->signature = proof.signature; - signed_config_->cert_sct = proof.leaf_cert_scts; - signed_config_->send_expect_ct_header = proof.send_expect_ct_header; + signed_config_->proof = proof; } config_.EvaluateClientHelloAfterGetProof( found_error_, server_ip_, version_, requested_config_, primary_config_, @@ -1278,8 +1273,7 @@ if (proof_source_->GetProof( server_ip, info->sni.as_string(), serialized_config, version, chlo_hash, connection_options, &signed_config->chain, &proof)) { - signed_config->signature = proof.signature; - signed_config->cert_sct = proof.leaf_cert_scts; + signed_config->proof = proof; } else { get_proof_failed = true; } @@ -1589,22 +1583,23 @@ "overhead calculation may underflow"); bool should_return_sct = params->sct_supported_by_client && enable_serving_sct_; - const size_t sct_size = should_return_sct ? signed_config.cert_sct.size() : 0; + const string& cert_sct = signed_config.proof.leaf_cert_scts; + const size_t sct_size = should_return_sct ? cert_sct.size() : 0; const size_t total_size = - signed_config.signature.size() + compressed.size() + sct_size; + signed_config.proof.signature.size() + compressed.size() + sct_size; if (info.valid_source_address_token || total_size < max_unverified_size) { out->SetStringPiece(kCertificateTag, compressed); - out->SetStringPiece(kPROF, signed_config.signature); + out->SetStringPiece(kPROF, signed_config.proof.signature); if (should_return_sct) { - if (signed_config.cert_sct.empty()) { + if (cert_sct.empty()) { DLOG(WARNING) << "SCT is expected but it is empty."; } else { - out->SetStringPiece(kCertificateSCTTag, signed_config.cert_sct); + out->SetStringPiece(kCertificateSCTTag, cert_sct); } } } else { DLOG(WARNING) << "Sending inchoate REJ for hostname: " << info.sni - << " signature: " << signed_config.signature.size() + << " signature: " << signed_config.proof.signature.size() << " cert: " << compressed.size() << " sct:" << sct_size << " total: " << total_size << " max: " << max_unverified_size; @@ -2013,8 +2008,7 @@ QuicCryptoServerConfig::Config::~Config() { } -QuicSignedServerConfig::QuicSignedServerConfig() - : send_expect_ct_header(false) {} +QuicSignedServerConfig::QuicSignedServerConfig() {} QuicSignedServerConfig::~QuicSignedServerConfig() {} } // namespace net
diff --git a/net/quic/core/crypto/quic_crypto_server_config.h b/net/quic/core/crypto/quic_crypto_server_config.h index 24b476c..444102e7 100644 --- a/net/quic/core/crypto/quic_crypto_server_config.h +++ b/net/quic/core/crypto/quic_crypto_server_config.h
@@ -26,6 +26,7 @@ #include "net/quic/core/crypto/crypto_secret_boxer.h" #include "net/quic/core/crypto/proof_source.h" #include "net/quic/core/crypto/quic_compressed_certs_cache.h" +#include "net/quic/core/crypto/quic_crypto_proof.h" #include "net/quic/core/proto/cached_network_parameters.pb.h" #include "net/quic/core/proto/source_address_token.pb.h" #include "net/quic/core/quic_time.h" @@ -788,22 +789,12 @@ : public base::RefCounted<QuicSignedServerConfig> { QuicSignedServerConfig(); - // TODO(eranm): Have a QuicCryptoProof field instead of signature, cert_sct. - std::string signature; + QuicCryptoProof proof; scoped_refptr<ProofSource::Chain> chain; - std::string cert_sct; // The server config that is used for this proof (and the rest of the // request). scoped_refptr<QuicCryptoServerConfig::Config> config; std::string primary_scid; - // Indication whether the Expect-CT header should be sent on the session - // this proof relates to (for background, see - // https://www.ietf.org/id/draft-stark-expect-ct-00.txt). - // NOTE: This field is intentionally independent from the |cert_sct| one - // and can be true even if |cert_sct| is empty. - // The goal of the Expect-CT header is uncover cases where valid SCTs are - // expected to be served, but aren't. - bool send_expect_ct_header; private: friend class base::RefCounted<QuicSignedServerConfig>;
diff --git a/net/quic/core/quic_client_promised_info.cc b/net/quic/core/quic_client_promised_info.cc index 1648a2bc..186b192c 100644 --- a/net/quic/core/quic_client_promised_info.cc +++ b/net/quic/core/quic_client_promised_info.cc
@@ -26,11 +26,7 @@ void QuicClientPromisedInfo::CleanupAlarm::OnAlarm() { DVLOG(1) << "self GC alarm for stream " << promised_->id_; promised_->session()->OnPushStreamTimedOut(promised_->id_); - if (FLAGS_quic_send_push_stream_timed_out_error) { - promised_->Reset(QUIC_PUSH_STREAM_TIMED_OUT); - } else { - promised_->Reset(QUIC_STREAM_CANCELLED); - } + promised_->Reset(QUIC_PUSH_STREAM_TIMED_OUT); } void QuicClientPromisedInfo::Init() {
diff --git a/net/quic/core/quic_client_promised_info_test.cc b/net/quic/core/quic_client_promised_info_test.cc index 2b90272..c26823a 100644 --- a/net/quic/core/quic_client_promised_info_test.cc +++ b/net/quic/core/quic_client_promised_info_test.cc
@@ -124,13 +124,8 @@ ASSERT_NE(promised, nullptr); // Fire the alarm that will cancel the promised stream. - if (FLAGS_quic_send_push_stream_timed_out_error) { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_PUSH_STREAM_TIMED_OUT, 0)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_STREAM_CANCELLED, 0)); - } + EXPECT_CALL(*connection_, + SendRstStream(promise_id_, QUIC_PUSH_STREAM_TIMED_OUT, 0)); alarm_factory_.FireAlarm(QuicClientPromisedInfoPeer::GetAlarm(promised)); // Verify that the promise is gone after the alarm fires.
diff --git a/net/quic/core/quic_client_session_base.cc b/net/quic/core/quic_client_session_base.cc index ff61a9d..2abe509 100644 --- a/net/quic/core/quic_client_session_base.cc +++ b/net/quic/core/quic_client_session_base.cc
@@ -166,9 +166,6 @@ SendRstStream(id, error_code, 0); if (!IsOpenStream(id)) { MaybeIncreaseLargestPeerStreamId(id); - if (!FLAGS_quic_bugfix_reset_promised) { - InsertLocallyClosedStreamsHighestOffset(id, 0); - } } }
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc index 61b14b8f..d2a468b 100644 --- a/net/quic/core/quic_connection.cc +++ b/net/quic/core/quic_connection.cc
@@ -2007,6 +2007,8 @@ } void QuicConnection::CancelAllAlarms() { + DVLOG(1) << "Cancelling all QuicConnection alarms."; + ack_alarm_->Cancel(); ping_alarm_->Cancel(); resume_writes_alarm_->Cancel();
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc index 0c58039..da606e6e 100644 --- a/net/quic/core/quic_connection_test.cc +++ b/net/quic/core/quic_connection_test.cc
@@ -44,7 +44,6 @@ using std::vector; using testing::AnyNumber; using testing::AtLeast; -using testing::Contains; using testing::DoAll; using testing::InSequence; using testing::InvokeWithoutArgs;
diff --git a/net/quic/core/quic_crypto_server_stream.h b/net/quic/core/quic_crypto_server_stream.h index 1a08745e..27735755 100644 --- a/net/quic/core/quic_crypto_server_stream.h +++ b/net/quic/core/quic_crypto_server_stream.h
@@ -129,7 +129,7 @@ // However, it is exposed here because that is the only place where the // configuration for the certificate used in the connection is accessible. bool ShouldSendExpectCTHeader() const { - return signed_config_->send_expect_ct_header; + return signed_config_->proof.send_expect_ct_header; } protected:
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index 785f0b32..baaf6f7 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -61,10 +61,6 @@ // If true, use async codepaths to invoke ProofSource::GetProof. QUIC_FLAG(bool, FLAGS_enable_async_get_proof, false) -// If true, requires handshake confirmations for all QUIC handshakes with -// versions less than 33. -QUIC_FLAG(bool, FLAGS_quic_require_handshake_confirmation_pre33, false) - // If true, only open limited number of quic sessions per epoll event. Leave the // rest to next event. QUIC_FLAG(bool, FLAGS_quic_limit_num_new_sessions_per_epoll_loop, true) @@ -115,14 +111,6 @@ // If true, rejected packet number is removed from public reset packet. QUIC_FLAG(bool, FLAGS_quic_remove_packet_number_from_public_reset, false) -// If true, will send QUIC_PUSH_STREAM_TIMED_OUT when push stream is unclaimed -// and times out. -QUIC_FLAG(bool, FLAGS_quic_send_push_stream_timed_out_error, true) - -// If true, enable bugfix for FHOL experiment (fin-only -// WritevStreamData). -QUIC_FLAG(bool, FLAGS_quic_bugfix_fhol_writev_fin_only_v2, true) - // If true, v33 QUIC client uses 1 bit to specify 8-byte connection id in // public flag. QUIC_FLAG(bool, FLAGS_quic_remove_v33_hacks2, false) @@ -138,10 +126,6 @@ // Cubic in packets. QUIC_FLAG(bool, FLAGS_quic_default_enable_cubic_bytes, true) -// If enabled, fix double call of -// InsertLocallyClosedStreamsHighestOffset in ResetPromised. -QUIC_FLAG(bool, FLAGS_quic_bugfix_reset_promised, true) - // Set the retransmission alarm only when there are unacked // retransmittable packets. QUIC_FLAG(bool, FLAGS_quic_more_conservative_retransmission_alarm, true) @@ -160,3 +144,10 @@ // Add a new client connection options field to QuicOptions which is only used // to configure client side features, such as congestion control. QUIC_FLAG(bool, FLAGS_quic_client_connection_options, true) + +// If true, fix some casts that were causing off-by-one errors in QUIC's cubic +// "convex" increases. +QUIC_FLAG(bool, FLAGS_quic_fix_cubic_convex_mode, false) + +// Ensure that BBR startup pacing rate does not drop below the initial one. +QUIC_FLAG(bool, FLAGS_quic_bbr_faster_startup, false)
diff --git a/net/quic/core/quic_headers_stream.cc b/net/quic/core/quic_headers_stream.cc index 53ca278..383d44f 100644 --- a/net/quic/core/quic_headers_stream.cc +++ b/net/quic/core/quic_headers_stream.cc
@@ -400,90 +400,46 @@ QuicConsumedData result(0, false); size_t total_length = iov.total_length; - if (!FLAGS_quic_bugfix_fhol_writev_fin_only_v2) { - // Encapsulate the data into HTTP/2 DATA frames. The outer loop - // handles each element of the source iov, the inner loop handles - // the possibility of fragmenting eacho of those into multiple DATA - // frames, as the DATA frames have a max size of 16KB. - for (int i = 0; i < iov.iov_count; i++) { - size_t offset = 0; - const struct iovec* src_iov = &iov.iov[i]; - do { - size_t len = std::min(std::min(src_iov->iov_len - offset, max_len), - total_length); - char* data = static_cast<char*>(src_iov->iov_base) + offset; - SpdyDataIR spdy_data(id, StringPiece(data, len)); - offset += len; - // fin handling, only set it for the final HTTP/2 DATA frame. - bool last_iov = i == iov.iov_count - 1; - bool last_fragment_within_iov = offset >= src_iov->iov_len; - bool frame_fin = (last_iov && last_fragment_within_iov) ? fin : false; - spdy_data.set_fin(frame_fin); - if (frame_fin) { - result.fin_consumed = true; - } - SpdySerializedFrame frame(spdy_framer_.SerializeFrame(spdy_data)); - DVLOG(1) << "Encapsulating in DATA frame for stream " << id << " len " - << len << " fin " << spdy_data.fin() << " remaining " - << src_iov->iov_len - offset; + if (total_length == 0 && fin) { + WriteDataFrame(id, StringPiece(), true, ack_notifier_delegate); + result.fin_consumed = true; + return result; + } - scoped_refptr<ForceHolAckListener> ack_listener; - if (ack_notifier_delegate != nullptr) { - ack_listener = new ForceHolAckListener(ack_notifier_delegate, - frame.size() - len); - } - - WriteOrBufferData(StringPiece(frame.data(), frame.size()), false, - ack_listener.get()); - result.bytes_consumed += len; - total_length -= len; - if (total_length <= 0) { - return result; - } - } while (offset < src_iov->iov_len); - } - } else { - if (total_length == 0 && fin) { - WriteDataFrame(id, StringPiece(), true, ack_notifier_delegate); - result.fin_consumed = true; - return result; - } - - // Encapsulate the data into HTTP/2 DATA frames. The outer loop - // handles each element of the source iov, the inner loop handles - // the possibility of fragmenting each of those into multiple DATA - // frames, as the DATA frames have a max size of 16KB. - for (int i = 0; i < iov.iov_count; i++) { - size_t src_iov_offset = 0; - const struct iovec* src_iov = &iov.iov[i]; - do { - if (queued_data_bytes() > 0) { - // Limit the amount of buffering to the minimum needed to - // preserve framing. - return result; - } - size_t len = std::min( - std::min(src_iov->iov_len - src_iov_offset, max_len), total_length); - char* data = static_cast<char*>(src_iov->iov_base) + src_iov_offset; - src_iov_offset += len; - offset += len; - // fin handling, only set it for the final HTTP/2 DATA frame. - bool last_iov = i == iov.iov_count - 1; - bool last_fragment_within_iov = src_iov_offset >= src_iov->iov_len; - bool frame_fin = (last_iov && last_fragment_within_iov) ? fin : false; - WriteDataFrame(id, StringPiece(data, len), frame_fin, - ack_notifier_delegate); - result.bytes_consumed += len; - if (frame_fin) { - result.fin_consumed = true; - } - DCHECK_GE(total_length, len); - total_length -= len; - if (total_length <= 0) { - return result; - } - } while (src_iov_offset < src_iov->iov_len); - } + // Encapsulate the data into HTTP/2 DATA frames. The outer loop + // handles each element of the source iov, the inner loop handles + // the possibility of fragmenting each of those into multiple DATA + // frames, as the DATA frames have a max size of 16KB. + for (int i = 0; i < iov.iov_count; i++) { + size_t src_iov_offset = 0; + const struct iovec* src_iov = &iov.iov[i]; + do { + if (queued_data_bytes() > 0) { + // Limit the amount of buffering to the minimum needed to + // preserve framing. + return result; + } + size_t len = std::min( + std::min(src_iov->iov_len - src_iov_offset, max_len), total_length); + char* data = static_cast<char*>(src_iov->iov_base) + src_iov_offset; + src_iov_offset += len; + offset += len; + // fin handling, only set it for the final HTTP/2 DATA frame. + bool last_iov = i == iov.iov_count - 1; + bool last_fragment_within_iov = src_iov_offset >= src_iov->iov_len; + bool frame_fin = (last_iov && last_fragment_within_iov) ? fin : false; + WriteDataFrame(id, StringPiece(data, len), frame_fin, + ack_notifier_delegate); + result.bytes_consumed += len; + if (frame_fin) { + result.fin_consumed = true; + } + DCHECK_GE(total_length, len); + total_length -= len; + if (total_length <= 0) { + return result; + } + } while (src_iov_offset < src_iov->iov_len); } return result;
diff --git a/net/quic/core/quic_headers_stream_test.cc b/net/quic/core/quic_headers_stream_test.cc index 667715a..4b27ee1 100644 --- a/net/quic/core/quic_headers_stream_test.cc +++ b/net/quic/core/quic_headers_stream_test.cc
@@ -995,7 +995,6 @@ } TEST_P(QuicHeadersStreamTest, WritevStreamDataFinOnly) { - FLAGS_quic_bugfix_fhol_writev_fin_only_v2 = true; struct iovec iov; string data; @@ -1012,7 +1011,6 @@ } TEST_P(QuicHeadersStreamTest, WritevStreamDataSendBlocked) { - FLAGS_quic_bugfix_fhol_writev_fin_only_v2 = true; QuicStreamId id = kClientDataStreamId1; QuicStreamOffset offset = 0; struct iovec iov;
diff --git a/net/quic/core/quic_spdy_session.cc b/net/quic/core/quic_spdy_session.cc index b2bb42f..99af124 100644 --- a/net/quic/core/quic_spdy_session.cc +++ b/net/quic/core/quic_spdy_session.cc
@@ -121,24 +121,15 @@ if (FLAGS_quic_enable_force_hol_blocking && version > QUIC_VERSION_35 && config()->ForceHolBlocking(perspective())) { force_hol_blocking_ = true; - if (!FLAGS_quic_bugfix_fhol_writev_fin_only_v2) { - // Autotuning makes sure that the headers stream flow control does - // not get in the way, and normal stream and connection level flow - // control are active anyway. This is really only for the client - // side (and mainly there just in tests and toys), where - // autotuning and/or large buffers are not enabled by default. - headers_stream_->flow_controller()->set_auto_tune_receive_window(true); - } else { - // Since all streams are tunneled through the headers stream, it - // is important that headers stream never flow control blocks. - // Otherwise, busy-loop behaviour can ensue where data streams - // data try repeatedly to write data not realizing that the - // tunnel through the headers stream is blocked. - headers_stream_->flow_controller()->UpdateReceiveWindowSize( - kStreamReceiveWindowLimit); - headers_stream_->flow_controller()->UpdateSendWindowOffset( - kStreamReceiveWindowLimit); - } + // Since all streams are tunneled through the headers stream, it + // is important that headers stream never flow control blocks. + // Otherwise, busy-loop behaviour can ensue where data streams + // data try repeatedly to write data not realizing that the + // tunnel through the headers stream is blocked. + headers_stream_->flow_controller()->UpdateReceiveWindowSize( + kStreamReceiveWindowLimit); + headers_stream_->flow_controller()->UpdateSendWindowOffset( + kStreamReceiveWindowLimit); } if (version > QUIC_VERSION_34) {
diff --git a/net/quic/core/quic_spdy_stream.cc b/net/quic/core/quic_spdy_stream.cc index bb8b172..278cbba 100644 --- a/net/quic/core/quic_spdy_stream.cc +++ b/net/quic/core/quic_spdy_stream.cc
@@ -47,18 +47,6 @@ } } -void QuicSpdyStream::CloseWriteSide() { - if (!fin_received() && !rst_received() && sequencer()->ignore_read_data() && - !rst_sent()) { - DCHECK(fin_sent()); - // Tell the peer to stop sending further data. - DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id(); - Reset(QUIC_STREAM_NO_ERROR); - } - - QuicStream::CloseWriteSide(); -} - void QuicSpdyStream::StopReading() { if (!fin_received() && !rst_received() && write_side_closed() && !rst_sent()) {
diff --git a/net/quic/core/quic_spdy_stream.h b/net/quic/core/quic_spdy_stream.h index 19bcddc..97374e53 100644 --- a/net/quic/core/quic_spdy_stream.h +++ b/net/quic/core/quic_spdy_stream.h
@@ -67,9 +67,6 @@ QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session); ~QuicSpdyStream() override; - // Override the base class to send QUIC_STREAM_NO_ERROR to the peer - // when the stream has not received all the data. - void CloseWriteSide() override; void StopReading() override; // QuicStream implementation @@ -183,6 +180,8 @@ bool allow_bidirectional_data() const { return allow_bidirectional_data_; } + using QuicStream::CloseWriteSide; + protected: virtual void OnInitialHeadersComplete(bool fin, size_t frame_len,
diff --git a/net/quic/test_tools/simulator/packet_filter.cc b/net/quic/test_tools/simulator/packet_filter.cc new file mode 100644 index 0000000..a988d9b --- /dev/null +++ b/net/quic/test_tools/simulator/packet_filter.cc
@@ -0,0 +1,40 @@ +// Copyright (c) 2016 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 "net/quic/test_tools/simulator/packet_filter.h" + +namespace net { +namespace simulator { + +PacketFilter::PacketFilter(Simulator* simulator, + std::string name, + Endpoint* input) + : Endpoint(simulator, name), input_(input) { + input_->SetTxPort(this); +} + +PacketFilter::~PacketFilter() {} + +void PacketFilter::AcceptPacket(std::unique_ptr<Packet> packet) { + if (FilterPacket(*packet)) { + output_tx_port_->AcceptPacket(std::move(packet)); + } +} + +QuicTime::Delta PacketFilter::TimeUntilAvailable() { + return output_tx_port_->TimeUntilAvailable(); +} + +void PacketFilter::Act() {} + +UnconstrainedPortInterface* PacketFilter::GetRxPort() { + return input_->GetRxPort(); +} + +void PacketFilter::SetTxPort(ConstrainedPortInterface* port) { + output_tx_port_ = port; +} + +} // namespace simulator +} // namespace net
diff --git a/net/quic/test_tools/simulator/packet_filter.h b/net/quic/test_tools/simulator/packet_filter.h new file mode 100644 index 0000000..f8caa2f0 --- /dev/null +++ b/net/quic/test_tools/simulator/packet_filter.h
@@ -0,0 +1,77 @@ +// Copyright (c) 2016 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 NET_QUIC_TEST_TOOLS_SIMULATOR_PACKET_FILTER_H_ +#define NET_QUIC_TEST_TOOLS_SIMULATOR_PACKET_FILTER_H_ + +#include "net/quic/test_tools/simulator/port.h" + +namespace net { +namespace simulator { + +// Packet filter allows subclasses to filter out the packets that enter the +// input port and exit the output port. Packets in the other direction are +// always passed through. +// +// The filter wraps around the input endpoint, and exposes the resulting +// filtered endpoint via the output() method. For example, if initially there +// are two endpoints, A and B, connected via a symmetric link: +// +// QuicEndpoint endpoint_a; +// QuicEndpoint endpoint_b; +// +// [...] +// +// SymmetricLink a_b_link(&endpoint_a, &endpoint_b, ...); +// +// and the goal is to filter the traffic from A to B, then the new invocation +// would be as follows: +// +// PacketFilter filter(&simulator, "A-to-B packet filter", endpoint_a); +// SymmetricLink a_b_link(&filter, &endpoint_b, ...); +// +// Note that the filter drops the packet instanteneously, without it ever +// reaching the output wire. This means that in a direct endpoint-to-endpoint +// scenario, whenever the packet is dropped, the link would become immediately +// available for the next packet. +class PacketFilter : public Endpoint, public ConstrainedPortInterface { + public: + // Initialize the filter by wrapping around |input|. Does not take the + // ownership of |input|. + PacketFilter(Simulator* simulator, std::string name, Endpoint* input); + ~PacketFilter() override; + + Endpoint* input() { return input_; } + + // Implementation of ConstrainedPortInterface. + void AcceptPacket(std::unique_ptr<Packet> packet) override; + QuicTime::Delta TimeUntilAvailable() override; + + // Implementation of Endpoint interface methods. + UnconstrainedPortInterface* GetRxPort() override; + void SetTxPort(ConstrainedPortInterface* port) override; + + // Implementation of Actor interface methods. + void Act() override; + + protected: + // Returns true if the packet should be passed through, and false if it should + // be dropped. The function is called once per packet, in the order that the + // packets arrive, so it is safe for the function to alter the internal state + // of the filter. + virtual bool FilterPacket(const Packet& packet) = 0; + + private: + // The port onto which the filtered packets are egressed. + ConstrainedPortInterface* output_tx_port_; + + // The original network endpoint wrapped by the class. + Endpoint* input_; + + DISALLOW_COPY_AND_ASSIGN(PacketFilter); +}; + +} // namespace simulator +} // namespace net +#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_PACKET_FILTER_H_
diff --git a/net/quic/test_tools/simulator/simulator_test.cc b/net/quic/test_tools/simulator/simulator_test.cc index 4c85bead..07f19117 100644 --- a/net/quic/test_tools/simulator/simulator_test.cc +++ b/net/quic/test_tools/simulator/simulator_test.cc
@@ -8,6 +8,7 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/simulator/alarm_factory.h" #include "net/quic/test_tools/simulator/link.h" +#include "net/quic/test_tools/simulator/packet_filter.h" #include "net/quic/test_tools/simulator/queue.h" #include "net/quic/test_tools/simulator/switch.h" #include "net/quic/test_tools/simulator/traffic_policer.h" @@ -15,6 +16,10 @@ #include "net/test/gtest_util.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::_; +using testing::Return; +using testing::StrictMock; + namespace net { namespace simulator { @@ -564,6 +569,52 @@ EXPECT_EQ(33, counter.get_value()); } +class MockPacketFilter : public PacketFilter { + public: + MockPacketFilter(Simulator* simulator, std::string name, Endpoint* endpoint) + : PacketFilter(simulator, name, endpoint) {} + MOCK_METHOD1(FilterPacket, bool(const Packet&)); +}; + +// Set up two trivial packet filters, one allowing any packets, and one dropping +// all of them. +TEST(SimulatorTest, PacketFilter) { + const QuicBandwidth bandwidth = + QuicBandwidth::FromBytesPerSecond(1024 * 1024); + const QuicTime::Delta base_propagation_delay = + QuicTime::Delta::FromMilliseconds(5); + + Simulator simulator; + LinkSaturator saturator_a(&simulator, "Saturator A", 1000, "Saturator B"); + LinkSaturator saturator_b(&simulator, "Saturator B", 1000, "Saturator A"); + + // Attach packets to the switch to create a delay between the point at which + // the packet is generated and the point at which it is filtered. Note that + // if the saturators were connected directly, the link would be always + // available for the endpoint which has all of its packets dropped, resulting + // in saturator looping infinitely. + Switch network_switch(&simulator, "Switch", 8, + bandwidth * base_propagation_delay * 10); + StrictMock<MockPacketFilter> a_to_b_filter(&simulator, "A -> B filter", + network_switch.port(1)); + StrictMock<MockPacketFilter> b_to_a_filter(&simulator, "B -> A filter", + network_switch.port(2)); + SymmetricLink link_a(&a_to_b_filter, &saturator_b, bandwidth, + base_propagation_delay); + SymmetricLink link_b(&b_to_a_filter, &saturator_a, bandwidth, + base_propagation_delay); + + // Allow packets from A to B, but not from B to A. + EXPECT_CALL(a_to_b_filter, FilterPacket(_)).WillRepeatedly(Return(true)); + EXPECT_CALL(b_to_a_filter, FilterPacket(_)).WillRepeatedly(Return(false)); + + // Run the simulation for a while, and expect that only B will receive any + // packets. + simulator.RunFor(QuicTime::Delta::FromSeconds(10)); + EXPECT_GE(saturator_b.counter()->packets(), 1u); + EXPECT_EQ(saturator_a.counter()->packets(), 0u); +} + // Set up a traffic policer in one direction that throttles at 25% of link // bandwidth, and put two link saturators at each endpoint. TEST(SimulatorTest, TrafficPolicer) { @@ -587,8 +638,7 @@ SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth, base_propagation_delay); - SymmetricLink link2(&saturator2, policer.output(), bandwidth, - base_propagation_delay); + SymmetricLink link2(&saturator2, &policer, bandwidth, base_propagation_delay); // Ensure the initial burst passes without being dropped at all. bool simulator_result = simulator.RunUntilOrTimeout( @@ -646,8 +696,7 @@ SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth, base_propagation_delay); - SymmetricLink link2(&saturator2, policer.output(), bandwidth, - base_propagation_delay); + SymmetricLink link2(&saturator2, &policer, bandwidth, base_propagation_delay); // Ensure at least one packet is sent on each side. bool simulator_result = simulator.RunUntilOrTimeout(
diff --git a/net/quic/test_tools/simulator/traffic_policer.cc b/net/quic/test_tools/simulator/traffic_policer.cc index 84ea4db..93e1c8d3 100644 --- a/net/quic/test_tools/simulator/traffic_policer.cc +++ b/net/quic/test_tools/simulator/traffic_policer.cc
@@ -15,20 +15,14 @@ QuicByteCount max_bucket_size, QuicBandwidth target_bandwidth, Endpoint* input) - : Actor(simulator, name), + : PacketFilter(simulator, name, input), initial_bucket_size_(initial_bucket_size), max_bucket_size_(max_bucket_size), target_bandwidth_(target_bandwidth), - last_refill_time_(clock_->Now()), - input_(input), - output_(this) { - input_->SetTxPort(this); -} + last_refill_time_(clock_->Now()) {} TrafficPolicer::~TrafficPolicer() {} -void TrafficPolicer::Act() {} - void TrafficPolicer::Refill() { QuicTime::Delta time_passed = clock_->Now() - last_refill_time_; QuicByteCount refill_size = time_passed * target_bandwidth_; @@ -40,47 +34,27 @@ last_refill_time_ = clock_->Now(); } -void TrafficPolicer::AcceptPacket(std::unique_ptr<Packet> packet) { +bool TrafficPolicer::FilterPacket(const Packet& packet) { // Refill existing buckets. Refill(); // Create a new bucket if one does not exist. - if (token_buckets_.count(packet->destination) == 0) { + if (token_buckets_.count(packet.destination) == 0) { token_buckets_.insert( - std::make_pair(packet->destination, initial_bucket_size_)); + std::make_pair(packet.destination, initial_bucket_size_)); } - auto bucket = token_buckets_.find(packet->destination); + auto bucket = token_buckets_.find(packet.destination); DCHECK(bucket != token_buckets_.end()); // Silently drop the packet on the floor if out of tokens - if (bucket->second < packet->size) { - return; + if (bucket->second < packet.size) { + return false; } - bucket->second -= packet->size; - output_tx_port_->AcceptPacket(std::move(packet)); + bucket->second -= packet.size; + return true; } -QuicTime::Delta TrafficPolicer::TimeUntilAvailable() { - return output_tx_port_->TimeUntilAvailable(); -} - -TrafficPolicer::Output::Output(TrafficPolicer* policer) - : Endpoint(policer->simulator(), policer->name() + " (output port)"), - policer_(policer) {} - -TrafficPolicer::Output::~Output() {} - -UnconstrainedPortInterface* TrafficPolicer::Output::GetRxPort() { - return policer_->input_->GetRxPort(); -} - -void TrafficPolicer::Output::SetTxPort(ConstrainedPortInterface* port) { - policer_->output_tx_port_ = port; -} - -void TrafficPolicer::Output::Act() {} - } // namespace simulator } // namespace net
diff --git a/net/quic/test_tools/simulator/traffic_policer.h b/net/quic/test_tools/simulator/traffic_policer.h index caa5855..3a218ae0 100644 --- a/net/quic/test_tools/simulator/traffic_policer.h +++ b/net/quic/test_tools/simulator/traffic_policer.h
@@ -7,6 +7,7 @@ #include <unordered_map> +#include "net/quic/test_tools/simulator/packet_filter.h" #include "net/quic/test_tools/simulator/port.h" namespace net { @@ -16,8 +17,8 @@ // passing through. It wraps around an input port and exposes an output port. // Only the traffic from input to the output is policed, so in case when // bidirectional policing is desired, two policers have to be used. The flows -// are hashed by the source only. -class TrafficPolicer : public Actor, public ConstrainedPortInterface { +// are hashed by the destination only. +class TrafficPolicer : public PacketFilter { public: TrafficPolicer(Simulator* simulator, std::string name, @@ -27,28 +28,10 @@ Endpoint* input); ~TrafficPolicer() override; - Endpoint* input() { return input_; } - Endpoint* output() { return &output_; } - - void AcceptPacket(std::unique_ptr<Packet> packet) override; - QuicTime::Delta TimeUntilAvailable() override; - - void Act() override; + protected: + bool FilterPacket(const Packet& packet) override; private: - class Output : public Endpoint { - public: - explicit Output(TrafficPolicer* policer); - ~Output() override; - - UnconstrainedPortInterface* GetRxPort() override; - void SetTxPort(ConstrainedPortInterface* port) override; - void Act() override; - - private: - TrafficPolicer* policer_; - }; - // Refill the token buckets with all the tokens that have been granted since // |last_refill_time_|. void Refill(); @@ -60,11 +43,6 @@ // The time at which the token buckets were last refilled. QuicTime last_refill_time_; - ConstrainedPortInterface* output_tx_port_; - - Endpoint* input_; - Output output_; - // Maps each destination to the number of tokens it has left. std::unordered_map<std::string, QuicByteCount> token_buckets_;
diff --git a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp index 0cf3500c..a2466559 100644 --- a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp +++ b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
@@ -371,7 +371,9 @@ // We try both variations, zero length item and empty string, // without giving a user prompt when trying the different empty password // flavors. - if (rv == net::ERR_PKCS12_IMPORT_BAD_PASSWORD && password.empty()) { + if ((rv == net::ERR_PKCS12_IMPORT_BAD_PASSWORD || + rv == net::ERR_PKCS12_IMPORT_INVALID_MAC) && + password.empty()) { rv = nsPKCS12Blob_ImportHelper(pkcs12_data, pkcs12_len, password, is_extractable, true, slot, imported_certs); }
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index a8f0909..06f5399 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -378,6 +378,10 @@ // TODO(nimia): Consider setting the congestion control algorithm for the // client as well according to the test parameter. copt.push_back(GetParam().congestion_control_tag); + if (GetParam().congestion_control_tag == kQBIC && + FLAGS_quic_fix_cubic_convex_mode) { + copt.push_back(kCCVX); + } if (support_server_push_) { copt.push_back(kSPSH); }
diff --git a/net/tools/quic/quic_http_response_cache_test.cc b/net/tools/quic/quic_http_response_cache_test.cc index 4979d4c..f87f262 100644 --- a/net/tools/quic/quic_http_response_cache_test.cc +++ b/net/tools/quic/quic_http_response_cache_test.cc
@@ -98,7 +98,7 @@ TEST_F(QuicHttpResponseCacheTest, ReadsCacheDir) { cache_.InitializeFromDirectory(CacheDirectory()); const QuicHttpResponseCache::Response* response = - cache_.GetResponse("quic.test.url", "/index.html"); + cache_.GetResponse("www.example.com", "/index.html"); ASSERT_TRUE(response); ASSERT_TRUE(ContainsKey(response->headers(), ":status")); EXPECT_EQ("200", response->headers().find(":status")->second); @@ -109,22 +109,22 @@ TEST_F(QuicHttpResponseCacheTest, ReadsCacheDirWithServerPushResource) { cache_.InitializeFromDirectory(CacheDirectory() + "_with_push"); - list<ServerPushInfo> resources = - cache_.GetServerPushResources("quic.test.url/"); + std::list<ServerPushInfo> resources = + cache_.GetServerPushResources("www.example.com/"); ASSERT_EQ(1UL, resources.size()); } TEST_F(QuicHttpResponseCacheTest, ReadsCacheDirWithServerPushResources) { cache_.InitializeFromDirectory(CacheDirectory() + "_with_push"); - list<ServerPushInfo> resources = - cache_.GetServerPushResources("quic.test.url/index2.html"); + std::list<ServerPushInfo> resources = + cache_.GetServerPushResources("www.example.com/index2.html"); ASSERT_EQ(2UL, resources.size()); } TEST_F(QuicHttpResponseCacheTest, UsesOriginalUrl) { cache_.InitializeFromDirectory(CacheDirectory()); const QuicHttpResponseCache::Response* response = - cache_.GetResponse("quic.test.url", "/index.html"); + cache_.GetResponse("www.example.com", "/site_map.html"); ASSERT_TRUE(response); ASSERT_TRUE(ContainsKey(response->headers(), ":status")); EXPECT_EQ("200", response->headers().find(":status")->second);
diff --git a/net/tools/quic/quic_simple_server_stream.cc b/net/tools/quic/quic_simple_server_stream.cc index 1d32f9c0..89f262e 100644 --- a/net/tools/quic/quic_simple_server_stream.cc +++ b/net/tools/quic/quic_simple_server_stream.cc
@@ -30,7 +30,7 @@ QuicStreamId id, QuicSpdySession* session, QuicHttpResponseCache* response_cache) - : QuicSpdyStream(id, session), + : QuicSpdyServerStreamBase(id, session), content_length_(-1), response_cache_(response_cache) {}
diff --git a/net/tools/quic/quic_simple_server_stream.h b/net/tools/quic/quic_simple_server_stream.h index 7cb1819..2aa7b759 100644 --- a/net/tools/quic/quic_simple_server_stream.h +++ b/net/tools/quic/quic_simple_server_stream.h
@@ -14,6 +14,7 @@ #include "net/quic/core/quic_spdy_stream.h" #include "net/spdy/spdy_framer.h" #include "net/tools/quic/quic_http_response_cache.h" +#include "net/tools/quic/quic_spdy_server_stream_base.h" namespace net { @@ -24,7 +25,7 @@ // All this does right now is aggregate data, and on fin, send an HTTP // response. -class QuicSimpleServerStream : public QuicSpdyStream { +class QuicSimpleServerStream : public QuicSpdyServerStreamBase { public: QuicSimpleServerStream(QuicStreamId id, QuicSpdySession* session,
diff --git a/net/tools/quic/quic_spdy_server_stream_base.cc b/net/tools/quic/quic_spdy_server_stream_base.cc new file mode 100644 index 0000000..4b68127 --- /dev/null +++ b/net/tools/quic/quic_spdy_server_stream_base.cc
@@ -0,0 +1,29 @@ +// Copyright (c) 2016 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 "net/tools/quic/quic_spdy_server_stream_base.h" + +#include "net/quic/core/quic_error_codes.h" + +namespace net { + +QuicSpdyServerStreamBase::QuicSpdyServerStreamBase(QuicStreamId id, + QuicSpdySession* session) + : QuicSpdyStream(id, session) {} + +void QuicSpdyServerStreamBase::CloseWriteSide() { + if (!fin_received() && !rst_received() && sequencer()->ignore_read_data() && + !rst_sent()) { + // Early cancel the stream if it has stopped reading before receiving FIN + // or RST. + DCHECK(fin_sent()); + // Tell the peer to stop sending further data. + DVLOG(0) << " Server: Send QUIC_STREAM_NO_ERROR on stream " << id(); + Reset(QUIC_STREAM_NO_ERROR); + } + + QuicSpdyStream::CloseWriteSide(); +} + +} // namespace net
diff --git a/net/tools/quic/quic_spdy_server_stream_base.h b/net/tools/quic/quic_spdy_server_stream_base.h new file mode 100644 index 0000000..ebadee1 --- /dev/null +++ b/net/tools/quic/quic_spdy_server_stream_base.h
@@ -0,0 +1,26 @@ +// Copyright (c) 2016 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 NET_QUIC_CORE_QUIC_SPDY_SERVER_STREAM_BASE_H_ +#define NET_QUIC_CORE_QUIC_SPDY_SERVER_STREAM_BASE_H_ + +#include "net/quic/core/quic_spdy_stream.h" + +namespace net { + +class QuicSpdyServerStreamBase : public QuicSpdyStream { + public: + QuicSpdyServerStreamBase(QuicStreamId id, QuicSpdySession* session); + + // Override the base class to send QUIC_STREAM_NO_ERROR to the peer + // when the stream has not received all the data. + void CloseWriteSide() override; + + private: + DISALLOW_COPY_AND_ASSIGN(QuicSpdyServerStreamBase); +}; + +} // namespace net + +#endif // NET_QUIC_CORE_QUIC_SPDY_SERVER_STREAM_BASE_H_
diff --git a/net/tools/quic/quic_spdy_server_stream_base_test.cc b/net/tools/quic/quic_spdy_server_stream_base_test.cc new file mode 100644 index 0000000..32c9f87 --- /dev/null +++ b/net/tools/quic/quic_spdy_server_stream_base_test.cc
@@ -0,0 +1,65 @@ +// Copyright (c) 2016 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 "net/tools/quic/quic_spdy_server_stream_base.h" + +#include "base/memory/ptr_util.h" +#include "net/quic/test_tools/quic_test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace net { +namespace test { +namespace { + +class TestQuicSpdyServerStream : public QuicSpdyServerStreamBase { + public: + TestQuicSpdyServerStream(QuicStreamId id, QuicSpdySession* session) + : QuicSpdyServerStreamBase(id, session) {} + + void OnDataAvailable() override {} +}; + +class QuicSpdyServerStreamBaseTest : public ::testing::Test { + protected: + QuicSpdyServerStreamBaseTest() + : session_(new MockQuicConnection(&helper_, + &alarm_factory_, + Perspective::IS_SERVER)) { + stream_ = new TestQuicSpdyServerStream(kClientDataStreamId1, &session_); + session_.ActivateStream(base::WrapUnique(stream_)); + } + + QuicSpdyServerStreamBase* stream_ = nullptr; + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + MockQuicSpdySession session_; +}; + +TEST_F(QuicSpdyServerStreamBaseTest, + SendQuicRstStreamNoErrorWithEarlyResponse) { + stream_->StopReading(); + EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1); + stream_->set_fin_sent(true); + stream_->CloseWriteSide(); +} + +TEST_F(QuicSpdyServerStreamBaseTest, + DoNotSendQuicRstStreamNoErrorWithRstReceived) { + EXPECT_FALSE(stream_->reading_stopped()); + + EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0); + EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1); + QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 1234); + stream_->OnStreamReset(rst_frame); + + EXPECT_TRUE(stream_->reading_stopped()); + EXPECT_TRUE(stream_->write_side_closed()); +} + +} // namespace +} // namespace test +} // namespace net
diff --git a/services/ui/display/BUILD.gn b/services/ui/display/BUILD.gn index 76a50667..aef68ee1 100644 --- a/services/ui/display/BUILD.gn +++ b/services/ui/display/BUILD.gn
@@ -7,9 +7,9 @@ source_set("display") { sources = [ - "platform_screen.cc", - "platform_screen.h", - "platform_screen_delegate.h", + "screen_manager.cc", + "screen_manager.h", + "screen_manager_delegate.h", "viewport_metrics.cc", "viewport_metrics.h", ] @@ -23,8 +23,8 @@ if (use_ozone && is_chromeos) { sources += [ - "platform_screen_ozone.cc", - "platform_screen_ozone.h", + "screen_manager_ozone.cc", + "screen_manager_ozone.h", ] deps += [ @@ -35,8 +35,8 @@ ] } else { sources += [ - "platform_screen_stub.cc", - "platform_screen_stub.h", + "screen_manager_stub.cc", + "screen_manager_stub.h", ] } } @@ -44,7 +44,7 @@ if (use_ozone && is_chromeos) { test("display_service_unittests") { sources = [ - "platform_screen_ozone_unittests.cc", + "screen_manager_ozone_unittests.cc", ] deps = [
diff --git a/services/ui/display/platform_screen_stub.h b/services/ui/display/platform_screen_stub.h deleted file mode 100644 index 787f497..0000000 --- a/services/ui/display/platform_screen_stub.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2016 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 SERVICES_UI_DISPLAY_PLATFORM_SCREEN_STUB_H_ -#define SERVICES_UI_DISPLAY_PLATFORM_SCREEN_STUB_H_ - -#include <stdint.h> - -#include "base/memory/weak_ptr.h" -#include "services/ui/display/platform_screen.h" -#include "services/ui/display/viewport_metrics.h" - -namespace display { - -// PlatformScreenStub provides the necessary functionality to configure a fixed -// 1024x768 display for non-ozone platforms. -class PlatformScreenStub : public PlatformScreen { - public: - PlatformScreenStub(); - ~PlatformScreenStub() override; - - private: - // Fake creation of a single 1024x768 display. - void FixedSizeScreenConfiguration(); - - // PlatformScreen. - void AddInterfaces(service_manager::InterfaceRegistry* registry) override; - void Init(PlatformScreenDelegate* delegate) override; - void RequestCloseDisplay(int64_t display_id) override; - int64_t GetPrimaryDisplayId() const override; - - // Sample display information. - int64_t display_id_ = 1; - ViewportMetrics display_metrics_; - - PlatformScreenDelegate* delegate_ = nullptr; - - base::WeakPtrFactory<PlatformScreenStub> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PlatformScreenStub); -}; - -} // namespace display - -#endif // SERVICES_UI_DISPLAY_PLATFORM_SCREEN_STUB_H_
diff --git a/services/ui/display/platform_screen.cc b/services/ui/display/screen_manager.cc similarity index 64% rename from services/ui/display/platform_screen.cc rename to services/ui/display/screen_manager.cc index 153331d..9fb4746 100644 --- a/services/ui/display/platform_screen.cc +++ b/services/ui/display/screen_manager.cc
@@ -2,27 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "services/ui/display/platform_screen.h" +#include "services/ui/display/screen_manager.h" #include "base/logging.h" namespace display { // static -PlatformScreen* PlatformScreen::instance_ = nullptr; +ScreenManager* ScreenManager::instance_ = nullptr; -PlatformScreen::PlatformScreen() { +ScreenManager::ScreenManager() { DCHECK(!instance_); instance_ = this; } -PlatformScreen::~PlatformScreen() { +ScreenManager::~ScreenManager() { DCHECK_EQ(instance_, this); instance_ = nullptr; } // static -PlatformScreen* PlatformScreen::GetInstance() { +ScreenManager* ScreenManager::GetInstance() { DCHECK(instance_); return instance_; }
diff --git a/services/ui/display/platform_screen.h b/services/ui/display/screen_manager.h similarity index 60% rename from services/ui/display/platform_screen.h rename to services/ui/display/screen_manager.h index c266a57..3a0679cb 100644 --- a/services/ui/display/platform_screen.h +++ b/services/ui/display/screen_manager.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SERVICES_UI_DISPLAY_PLATFORM_SCREEN_H_ -#define SERVICES_UI_DISPLAY_PLATFORM_SCREEN_H_ +#ifndef SERVICES_UI_DISPLAY_SCREEN_MANAGER_H_ +#define SERVICES_UI_DISPLAY_SCREEN_MANAGER_H_ #include <memory> #include "base/macros.h" -#include "services/ui/display/platform_screen_delegate.h" +#include "services/ui/display/screen_manager_delegate.h" namespace service_manager { class InterfaceRegistry; @@ -16,16 +16,16 @@ namespace display { -// PlatformScreen provides the necessary functionality to configure all +// ScreenManager provides the necessary functionality to configure all // attached physical displays. -class PlatformScreen { +class ScreenManager { public: - PlatformScreen(); - virtual ~PlatformScreen(); + ScreenManager(); + virtual ~ScreenManager(); - // Creates a singleton PlatformScreen instance. - static std::unique_ptr<PlatformScreen> Create(); - static PlatformScreen* GetInstance(); + // Creates a singleton ScreenManager instance. + static std::unique_ptr<ScreenManager> Create(); + static ScreenManager* GetInstance(); // Registers Mojo interfaces provided. virtual void AddInterfaces(service_manager::InterfaceRegistry* registry) = 0; @@ -35,7 +35,7 @@ // more fake displays and pretend to configure them. A non-null |delegate| // must be provided that will receive notifications when displays are added, // removed or modified. - virtual void Init(PlatformScreenDelegate* delegate) = 0; + virtual void Init(ScreenManagerDelegate* delegate) = 0; // Handle requests from the platform to close a display. virtual void RequestCloseDisplay(int64_t display_id) = 0; @@ -43,11 +43,11 @@ virtual int64_t GetPrimaryDisplayId() const = 0; private: - static PlatformScreen* instance_; // Instance is not owned. + static ScreenManager* instance_; // Instance is not owned. - DISALLOW_COPY_AND_ASSIGN(PlatformScreen); + DISALLOW_COPY_AND_ASSIGN(ScreenManager); }; } // namespace display -#endif // SERVICES_UI_DISPLAY_PLATFORM_SCREEN_H_ +#endif // SERVICES_UI_DISPLAY_SCREEN_MANAGER_H_
diff --git a/services/ui/display/platform_screen_delegate.h b/services/ui/display/screen_manager_delegate.h similarity index 70% rename from services/ui/display/platform_screen_delegate.h rename to services/ui/display/screen_manager_delegate.h index 7ad956df..c6ed387 100644 --- a/services/ui/display/platform_screen_delegate.h +++ b/services/ui/display/screen_manager_delegate.h
@@ -2,24 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SERVICES_UI_DISPLAY_PLATFORM_SCREEN_DELEGATE_H_ -#define SERVICES_UI_DISPLAY_PLATFORM_SCREEN_DELEGATE_H_ +#ifndef SERVICES_UI_DISPLAY_SCREEN_MANAGER_DELEGATE_H_ +#define SERVICES_UI_DISPLAY_SCREEN_MANAGER_DELEGATE_H_ #include <stdint.h> -namespace gfx { -class Rect; -class Size; -} - namespace display { -class PlatformScreen; struct ViewportMetrics; -// The PlatformScreenDelegate will be informed of changes to the physical -// and/or virtual displays by PlatformScreen. -class PlatformScreenDelegate { +// The ScreenManagerDelegate will be informed of changes to the display or +// screen state by ScreenManager. +class ScreenManagerDelegate { public: // Called when a display is added. |id| is the display id of the new display // and |metrics| contains display viewport information. @@ -38,9 +32,9 @@ virtual void OnPrimaryDisplayChanged(int64_t primary_display_id) = 0; protected: - virtual ~PlatformScreenDelegate() {} + virtual ~ScreenManagerDelegate() {} }; } // namespace display -#endif // SERVICES_UI_DISPLAY_PLATFORM_SCREEN_DELEGATE_H_ +#endif // SERVICES_UI_DISPLAY_SCREEN_MANAGER_DELEGATE_H_
diff --git a/services/ui/display/platform_screen_ozone.cc b/services/ui/display/screen_manager_ozone.cc similarity index 83% rename from services/ui/display/platform_screen_ozone.cc rename to services/ui/display/screen_manager_ozone.cc index 6ffb7aa..fc2d4bc 100644 --- a/services/ui/display/platform_screen_ozone.cc +++ b/services/ui/display/screen_manager_ozone.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "services/ui/display/platform_screen_ozone.h" +#include "services/ui/display/screen_manager_ozone.h" #include <memory> #include <utility> @@ -55,25 +55,25 @@ } // namespace // static -std::unique_ptr<PlatformScreen> PlatformScreen::Create() { - return base::MakeUnique<PlatformScreenOzone>(); +std::unique_ptr<ScreenManager> ScreenManager::Create() { + return base::MakeUnique<ScreenManagerOzone>(); } -PlatformScreenOzone::PlatformScreenOzone() {} +ScreenManagerOzone::ScreenManagerOzone() {} -PlatformScreenOzone::~PlatformScreenOzone() { +ScreenManagerOzone::~ScreenManagerOzone() { // We are shutting down and don't want to make anymore display changes. fake_display_controller_ = nullptr; display_configurator_.RemoveObserver(this); } -void PlatformScreenOzone::AddInterfaces( +void ScreenManagerOzone::AddInterfaces( service_manager::InterfaceRegistry* registry) { registry->AddInterface<mojom::DisplayController>(this); registry->AddInterface<mojom::TestDisplayController>(this); } -void PlatformScreenOzone::Init(PlatformScreenDelegate* delegate) { +void ScreenManagerOzone::Init(ScreenManagerDelegate* delegate) { DCHECK(delegate); delegate_ = delegate; @@ -96,24 +96,24 @@ display_configurator_.ForceInitialConfigure(kChromeOsBootColor); } -void PlatformScreenOzone::RequestCloseDisplay(int64_t display_id) { +void ScreenManagerOzone::RequestCloseDisplay(int64_t display_id) { if (!fake_display_controller_ || wait_for_display_config_update_) return; CachedDisplayIterator iter = GetCachedDisplayIterator(display_id); if (iter != cached_displays_.end()) { - // Tell the NDD to remove the display. PlatformScreen will get an update + // Tell the NDD to remove the display. ScreenManager will get an update // that the display configuration has changed and the display will be gone. wait_for_display_config_update_ = fake_display_controller_->RemoveDisplay(iter->id); } } -int64_t PlatformScreenOzone::GetPrimaryDisplayId() const { +int64_t ScreenManagerOzone::GetPrimaryDisplayId() const { return primary_display_id_; } -void PlatformScreenOzone::ToggleAddRemoveDisplay() { +void ScreenManagerOzone::ToggleAddRemoveDisplay() { if (!fake_display_controller_ || wait_for_display_config_update_) return; @@ -129,7 +129,7 @@ } } -void PlatformScreenOzone::ToggleDisplayResolution() { +void ScreenManagerOzone::ToggleDisplayResolution() { DisplayInfo& display = cached_displays_[0]; // Toggle the display size to use. @@ -147,7 +147,23 @@ display_configurator_.OnConfigurationChanged(); } -void PlatformScreenOzone::SwapPrimaryDisplay() { +void ScreenManagerOzone::IncreaseInternalDisplayZoom() { + NOTIMPLEMENTED(); +} + +void ScreenManagerOzone::DecreaseInternalDisplayZoom() { + NOTIMPLEMENTED(); +} + +void ScreenManagerOzone::ResetInternalDisplayZoom() { + NOTIMPLEMENTED(); +} + +void ScreenManagerOzone::RotateCurrentDisplayCW() { + NOTIMPLEMENTED(); +} + +void ScreenManagerOzone::SwapPrimaryDisplay() { const size_t num_displays = cached_displays_.size(); if (num_displays <= 1) return; @@ -171,9 +187,13 @@ delegate_->OnPrimaryDisplayChanged(primary_display_id_); } -void PlatformScreenOzone::SetDisplayWorkArea(int64_t display_id, - const gfx::Size& size, - const gfx::Insets& insets) { +void ScreenManagerOzone::ToggleMirrorMode() { + NOTIMPLEMENTED(); +} + +void ScreenManagerOzone::SetDisplayWorkArea(int64_t display_id, + const gfx::Size& size, + const gfx::Insets& insets) { CachedDisplayIterator iter = GetCachedDisplayIterator(display_id); if (iter == cached_displays_.end()) { NOTREACHED() << display_id; @@ -194,12 +214,12 @@ } } -PlatformScreenOzone::DisplayInfo::DisplayInfo() = default; -PlatformScreenOzone::DisplayInfo::DisplayInfo(const DisplayInfo& other) = +ScreenManagerOzone::DisplayInfo::DisplayInfo() = default; +ScreenManagerOzone::DisplayInfo::DisplayInfo(const DisplayInfo& other) = default; -PlatformScreenOzone::DisplayInfo::~DisplayInfo() = default; +ScreenManagerOzone::DisplayInfo::~DisplayInfo() = default; -void PlatformScreenOzone::ProcessRemovedDisplays( +void ScreenManagerOzone::ProcessRemovedDisplays( const ui::DisplayConfigurator::DisplayStateList& snapshots) { std::vector<int64_t> current_ids; for (ui::DisplaySnapshot* snapshot : snapshots) @@ -216,7 +236,7 @@ } } -void PlatformScreenOzone::ProcessModifiedDisplays( +void ScreenManagerOzone::ProcessModifiedDisplays( const ui::DisplayConfigurator::DisplayStateList& snapshots) { for (ui::DisplaySnapshot* snapshot : snapshots) { auto iter = GetCachedDisplayIterator(snapshot->display_id()); @@ -234,7 +254,7 @@ } } -void PlatformScreenOzone::UpdateCachedDisplays() { +void ScreenManagerOzone::UpdateCachedDisplays() { // Walk through cached displays after processing the snapshots to find any // removed or modified displays. This ensures that we only send one update per // display to the delegate. @@ -264,7 +284,7 @@ } } -void PlatformScreenOzone::AddNewDisplays( +void ScreenManagerOzone::AddNewDisplays( const ui::DisplayConfigurator::DisplayStateList& snapshots) { for (ui::DisplaySnapshot* snapshot : snapshots) { const int64_t id = snapshot->display_id(); @@ -298,15 +318,15 @@ } } -PlatformScreenOzone::CachedDisplayIterator -PlatformScreenOzone::GetCachedDisplayIterator(int64_t display_id) { +ScreenManagerOzone::CachedDisplayIterator +ScreenManagerOzone::GetCachedDisplayIterator(int64_t display_id) { return std::find_if(cached_displays_.begin(), cached_displays_.end(), [display_id](const DisplayInfo& display_info) { return display_info.id == display_id; }); } -ViewportMetrics PlatformScreenOzone::MetricsFromSnapshot( +ViewportMetrics ScreenManagerOzone::MetricsFromSnapshot( const ui::DisplaySnapshot& snapshot, const gfx::Point& origin) { const ui::DisplayMode* current_mode = snapshot.current_mode(); @@ -325,7 +345,7 @@ return metrics; } -void PlatformScreenOzone::OnDisplayModeChanged( +void ScreenManagerOzone::OnDisplayModeChanged( const ui::DisplayConfigurator::DisplayStateList& displays) { ProcessRemovedDisplays(displays); ProcessModifiedDisplays(displays); @@ -348,28 +368,28 @@ wait_for_display_config_update_ = false; } -void PlatformScreenOzone::OnDisplayModeChangeFailed( +void ScreenManagerOzone::OnDisplayModeChangeFailed( const ui::DisplayConfigurator::DisplayStateList& displays, ui::MultipleDisplayState failed_new_state) { LOG(ERROR) << "OnDisplayModeChangeFailed from DisplayConfigurator"; wait_for_display_config_update_ = false; } -void PlatformScreenOzone::Create( +void ScreenManagerOzone::Create( const service_manager::Identity& remote_identity, mojom::DisplayControllerRequest request) { controller_bindings_.AddBinding(this, std::move(request)); } -ui::MultipleDisplayState PlatformScreenOzone::GetStateForDisplayIds( +ui::MultipleDisplayState ScreenManagerOzone::GetStateForDisplayIds( const ui::DisplayConfigurator::DisplayStateList& display_states) const { return (display_states.size() == 1 ? ui::MULTIPLE_DISPLAY_STATE_SINGLE : ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); } -bool PlatformScreenOzone::GetResolutionForDisplayId(int64_t display_id, - gfx::Size* size) const { +bool ScreenManagerOzone::GetResolutionForDisplayId(int64_t display_id, + gfx::Size* size) const { for (const DisplayInfo& display : cached_displays_) { if (display.id == display_id) { *size = display.requested_size; @@ -380,7 +400,7 @@ return false; } -void PlatformScreenOzone::Create( +void ScreenManagerOzone::Create( const service_manager::Identity& remote_identity, mojom::TestDisplayControllerRequest request) { test_bindings_.AddBinding(this, std::move(request));
diff --git a/services/ui/display/platform_screen_ozone.h b/services/ui/display/screen_manager_ozone.h similarity index 87% rename from services/ui/display/platform_screen_ozone.h rename to services/ui/display/screen_manager_ozone.h index 8e6bf27..7b3a28f 100644 --- a/services/ui/display/platform_screen_ozone.h +++ b/services/ui/display/screen_manager_ozone.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SERVICES_UI_DISPLAY_PLATFORM_SCREEN_OZONE_H_ -#define SERVICES_UI_DISPLAY_PLATFORM_SCREEN_OZONE_H_ +#ifndef SERVICES_UI_DISPLAY_SCREEN_MANAGER_OZONE_H_ +#define SERVICES_UI_DISPLAY_SCREEN_MANAGER_OZONE_H_ #include <stdint.h> @@ -15,7 +15,7 @@ #include "mojo/public/cpp/bindings/binding_set.h" #include "services/service_manager/public/cpp/connection.h" #include "services/service_manager/public/cpp/interface_factory.h" -#include "services/ui/display/platform_screen.h" +#include "services/ui/display/screen_manager.h" #include "services/ui/display/viewport_metrics.h" #include "services/ui/public/interfaces/display/display_controller.mojom.h" #include "services/ui/public/interfaces/display/test_display_controller.mojom.h" @@ -26,10 +26,10 @@ namespace display { -// PlatformScreenOzone provides the necessary functionality to configure all +// ScreenManagerOzone provides the necessary functionality to configure all // attached physical displays on the ozone platform. -class PlatformScreenOzone - : public PlatformScreen, +class ScreenManagerOzone + : public ScreenManager, public ui::DisplayConfigurator::Observer, public ui::DisplayConfigurator::StateController, public service_manager::InterfaceFactory<mojom::DisplayController>, @@ -37,12 +37,12 @@ public mojom::DisplayController, public mojom::TestDisplayController { public: - PlatformScreenOzone(); - ~PlatformScreenOzone() override; + ScreenManagerOzone(); + ~ScreenManagerOzone() override; - // PlatformScreen: + // ScreenManager: void AddInterfaces(service_manager::InterfaceRegistry* registry) override; - void Init(PlatformScreenDelegate* delegate) override; + void Init(ScreenManagerDelegate* delegate) override; void RequestCloseDisplay(int64_t display_id) override; int64_t GetPrimaryDisplayId() const override; @@ -51,13 +51,18 @@ void ToggleDisplayResolution() override; // mojom::DisplayController: + void IncreaseInternalDisplayZoom() override; + void DecreaseInternalDisplayZoom() override; + void ResetInternalDisplayZoom() override; + void RotateCurrentDisplayCW() override; void SwapPrimaryDisplay() override; + void ToggleMirrorMode() override; void SetDisplayWorkArea(int64_t display_id, const gfx::Size& size, const gfx::Insets& insets) override; private: - friend class PlatformScreenOzoneTest; + friend class ScreenManagerOzoneTest; // TODO(kylechar): This struct is just temporary until we migrate // DisplayManager code out of ash so it can be used here. @@ -140,7 +145,7 @@ mojom::TestDisplayControllerRequest request) override; ui::DisplayConfigurator display_configurator_; - PlatformScreenDelegate* delegate_ = nullptr; + ScreenManagerDelegate* delegate_ = nullptr; // If not null it provides a way to modify the display state when running off // device (eg. running mustash on Linux). @@ -158,9 +163,9 @@ mojo::BindingSet<mojom::DisplayController> controller_bindings_; mojo::BindingSet<mojom::TestDisplayController> test_bindings_; - DISALLOW_COPY_AND_ASSIGN(PlatformScreenOzone); + DISALLOW_COPY_AND_ASSIGN(ScreenManagerOzone); }; } // namespace display -#endif // SERVICES_UI_DISPLAY_PLATFORM_SCREEN_OZONE_H_ +#endif // SERVICES_UI_DISPLAY_SCREEN_MANAGER_OZONE_H_
diff --git a/services/ui/display/platform_screen_ozone_unittests.cc b/services/ui/display/screen_manager_ozone_unittests.cc similarity index 84% rename from services/ui/display/platform_screen_ozone_unittests.cc rename to services/ui/display/screen_manager_ozone_unittests.cc index 87d40ed..6525b110 100644 --- a/services/ui/display/platform_screen_ozone_unittests.cc +++ b/services/ui/display/screen_manager_ozone_unittests.cc
@@ -9,8 +9,8 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" -#include "services/ui/display/platform_screen.h" -#include "services/ui/display/platform_screen_ozone.h" +#include "services/ui/display/screen_manager.h" +#include "services/ui/display/screen_manager_ozone.h" #include "services/ui/display/viewport_metrics.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -63,15 +63,15 @@ } // Test delegate to track what functions calls the delegate receives. -class TestPlatformScreenDelegate : public PlatformScreenDelegate { +class TestScreenManagerDelegate : public ScreenManagerDelegate { public: - TestPlatformScreenDelegate() {} - ~TestPlatformScreenDelegate() override {} + TestScreenManagerDelegate() {} + ~TestScreenManagerDelegate() override {} const std::vector<DisplayState>& added() const { return added_; } const std::vector<DisplayState>& modified() const { return modified_; } - // Returns a string containing the function calls that PlatformScreenDelegate + // Returns a string containing the function calls that ScreenManagerDelegate // has received in the order they occured. Each function call will be in the // form "<action>(<id>)" and multiple function calls will be separated by ";". // For example, if display 2 was added then display 1 was modified, changes() @@ -113,20 +113,20 @@ std::vector<DisplayState> modified_; std::string changes_; - DISALLOW_COPY_AND_ASSIGN(TestPlatformScreenDelegate); + DISALLOW_COPY_AND_ASSIGN(TestScreenManagerDelegate); }; } // namespace // Test fixture with helpers to act like ui::DisplayConfigurator and send -// OnDisplayModeChanged() to PlatformScreenOzone. -class PlatformScreenOzoneTest : public testing::Test { +// OnDisplayModeChanged() to ScreenManagerOzone. +class ScreenManagerOzoneTest : public testing::Test { public: - PlatformScreenOzoneTest() {} - ~PlatformScreenOzoneTest() override {} + ScreenManagerOzoneTest() {} + ~ScreenManagerOzoneTest() override {} - PlatformScreenOzone* platform_screen() { return platform_screen_.get(); } - TestPlatformScreenDelegate* delegate() { return &delegate_; } + ScreenManagerOzone* screen_manager() { return screen_manager_.get(); } + TestScreenManagerDelegate* delegate() { return &delegate_; } // Adds a display snapshot with specified ID and default size. void AddDisplay(int64_t id) { return AddDisplay(id, gfx::Size(1024, 768)); } @@ -174,7 +174,7 @@ for (auto& snapshot : snapshots_) { snapshots_ptrs.push_back(snapshot.get()); } - platform_screen_->OnDisplayModeChanged(snapshots_ptrs); + screen_manager_->OnDisplayModeChanged(snapshots_ptrs); } private: @@ -193,8 +193,8 @@ testing::Test::SetUp(); ui::OzonePlatform::InitializeForUI(); - platform_screen_ = base::MakeUnique<PlatformScreenOzone>(); - platform_screen_->Init(&delegate_); + screen_manager_ = base::MakeUnique<ScreenManagerOzone>(); + screen_manager_->Init(&delegate_); // Have all tests start with a 1024x768 display by default. AddDisplay(1, gfx::Size(1024, 768)); @@ -212,22 +212,22 @@ void TearDown() override { snapshots_.clear(); delegate_.Reset(); - platform_screen_.reset(); + screen_manager_.reset(); } - TestPlatformScreenDelegate delegate_; - std::unique_ptr<PlatformScreenOzone> platform_screen_; + TestScreenManagerDelegate delegate_; + std::unique_ptr<ScreenManagerOzone> screen_manager_; std::vector<std::unique_ptr<DisplaySnapshot>> snapshots_; }; -TEST_F(PlatformScreenOzoneTest, AddDisplay) { +TEST_F(ScreenManagerOzoneTest, AddDisplay) { AddDisplay(2); // Check that display 2 was added. EXPECT_EQ("Added(2)", delegate()->changes()); } -TEST_F(PlatformScreenOzoneTest, RemoveDisplay) { +TEST_F(ScreenManagerOzoneTest, RemoveDisplay) { AddDisplay(2); delegate()->Reset(); @@ -237,7 +237,7 @@ EXPECT_EQ("Removed(2)", delegate()->changes()); } -TEST_F(PlatformScreenOzoneTest, RemoveFirstDisplay) { +TEST_F(ScreenManagerOzoneTest, RemoveFirstDisplay) { AddDisplay(2); delegate()->Reset(); @@ -251,7 +251,7 @@ EXPECT_THAT(delegate()->modified()[0], DisplayOrigin("0,0")); } -TEST_F(PlatformScreenOzoneTest, RemoveMultipleDisplay) { +TEST_F(ScreenManagerOzoneTest, RemoveMultipleDisplay) { AddDisplay(2); AddDisplay(3); delegate()->Reset(); @@ -264,7 +264,7 @@ EXPECT_EQ("Removed(2);Modified(3);Removed(3)", delegate()->changes()); } -TEST_F(PlatformScreenOzoneTest, ModifyDisplaySize) { +TEST_F(ScreenManagerOzoneTest, ModifyDisplaySize) { const gfx::Size size1(1920, 1200); const gfx::Size size2(1680, 1050); @@ -286,7 +286,7 @@ EXPECT_EQ("Modified(2)", delegate()->changes()); } -TEST_F(PlatformScreenOzoneTest, ModifyFirstDisplaySize) { +TEST_F(ScreenManagerOzoneTest, ModifyFirstDisplaySize) { const gfx::Size size(1920, 1200); AddDisplay(2, size); @@ -309,7 +309,7 @@ EXPECT_THAT(delegate()->modified()[1], DisplayOrigin("1920,0")); } -TEST_F(PlatformScreenOzoneTest, RemovePrimaryDisplay) { +TEST_F(ScreenManagerOzoneTest, RemovePrimaryDisplay) { AddDisplay(2); delegate()->Reset(); @@ -319,7 +319,7 @@ EXPECT_EQ("Primary(2);Removed(1);Modified(2)", delegate()->changes()); } -TEST_F(PlatformScreenOzoneTest, RemoveLastDisplay) { +TEST_F(ScreenManagerOzoneTest, RemoveLastDisplay) { RemoveDisplay(1); // Check that display 1 is removed and no updates for the primary display are @@ -327,23 +327,23 @@ EXPECT_EQ("Removed(1)", delegate()->changes()); } -TEST_F(PlatformScreenOzoneTest, SwapPrimaryDisplay) { +TEST_F(ScreenManagerOzoneTest, SwapPrimaryDisplay) { AddDisplay(2); delegate()->Reset(); - platform_screen()->SwapPrimaryDisplay(); + screen_manager()->SwapPrimaryDisplay(); EXPECT_EQ("Primary(2)", delegate()->changes()); } -TEST_F(PlatformScreenOzoneTest, SwapPrimaryThreeDisplays) { +TEST_F(ScreenManagerOzoneTest, SwapPrimaryThreeDisplays) { AddDisplay(2); AddDisplay(3); EXPECT_EQ("Added(2);Added(3)", delegate()->changes()); delegate()->Reset(); - platform_screen()->SwapPrimaryDisplay(); - platform_screen()->SwapPrimaryDisplay(); - platform_screen()->SwapPrimaryDisplay(); + screen_manager()->SwapPrimaryDisplay(); + screen_manager()->SwapPrimaryDisplay(); + screen_manager()->SwapPrimaryDisplay(); EXPECT_EQ("Primary(2);Primary(3);Primary(1)", delegate()->changes()); }
diff --git a/services/ui/display/platform_screen_stub.cc b/services/ui/display/screen_manager_stub.cc similarity index 69% rename from services/ui/display/platform_screen_stub.cc rename to services/ui/display/screen_manager_stub.cc index 8a90a4d2..c664c84 100644 --- a/services/ui/display/platform_screen_stub.cc +++ b/services/ui/display/screen_manager_stub.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "services/ui/display/platform_screen_stub.h" +#include "services/ui/display/screen_manager_stub.h" #include <memory> @@ -39,40 +39,39 @@ } // namespace // static -std::unique_ptr<PlatformScreen> PlatformScreen::Create() { - return base::MakeUnique<PlatformScreenStub>(); +std::unique_ptr<ScreenManager> ScreenManager::Create() { + return base::MakeUnique<ScreenManagerStub>(); } -PlatformScreenStub::PlatformScreenStub() - : weak_ptr_factory_(this) {} +ScreenManagerStub::ScreenManagerStub() : weak_ptr_factory_(this) {} -PlatformScreenStub::~PlatformScreenStub() {} +ScreenManagerStub::~ScreenManagerStub() {} -void PlatformScreenStub::FixedSizeScreenConfiguration() { +void ScreenManagerStub::FixedSizeScreenConfiguration() { delegate_->OnDisplayAdded(display_id_, display_metrics_); } -void PlatformScreenStub::AddInterfaces( +void ScreenManagerStub::AddInterfaces( service_manager::InterfaceRegistry* registry) {} -void PlatformScreenStub::Init(PlatformScreenDelegate* delegate) { +void ScreenManagerStub::Init(ScreenManagerDelegate* delegate) { DCHECK(delegate); delegate_ = delegate; display_metrics_ = DefaultViewportMetrics(); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&PlatformScreenStub::FixedSizeScreenConfiguration, + FROM_HERE, base::Bind(&ScreenManagerStub::FixedSizeScreenConfiguration, weak_ptr_factory_.GetWeakPtr())); } -void PlatformScreenStub::RequestCloseDisplay(int64_t display_id) { +void ScreenManagerStub::RequestCloseDisplay(int64_t display_id) { if (display_id == display_id_) { base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&PlatformScreenDelegate::OnDisplayRemoved, + FROM_HERE, base::Bind(&ScreenManagerDelegate::OnDisplayRemoved, base::Unretained(delegate_), display_id)); } } -int64_t PlatformScreenStub::GetPrimaryDisplayId() const { +int64_t ScreenManagerStub::GetPrimaryDisplayId() const { return display_id_; }
diff --git a/services/ui/display/screen_manager_stub.h b/services/ui/display/screen_manager_stub.h new file mode 100644 index 0000000..b780bb4d --- /dev/null +++ b/services/ui/display/screen_manager_stub.h
@@ -0,0 +1,46 @@ +// Copyright 2016 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 SERVICES_UI_DISPLAY_SCREEN_MANAGER_STUB_H_ +#define SERVICES_UI_DISPLAY_SCREEN_MANAGER_STUB_H_ + +#include <stdint.h> + +#include "base/memory/weak_ptr.h" +#include "services/ui/display/screen_manager.h" +#include "services/ui/display/viewport_metrics.h" + +namespace display { + +// ScreenManagerStub provides the necessary functionality to configure a fixed +// 1024x768 display for non-ozone platforms. +class ScreenManagerStub : public ScreenManager { + public: + ScreenManagerStub(); + ~ScreenManagerStub() override; + + private: + // Fake creation of a single 1024x768 display. + void FixedSizeScreenConfiguration(); + + // ScreenManager. + void AddInterfaces(service_manager::InterfaceRegistry* registry) override; + void Init(ScreenManagerDelegate* delegate) override; + void RequestCloseDisplay(int64_t display_id) override; + int64_t GetPrimaryDisplayId() const override; + + // Sample display information. + int64_t display_id_ = 1; + ViewportMetrics display_metrics_; + + ScreenManagerDelegate* delegate_ = nullptr; + + base::WeakPtrFactory<ScreenManagerStub> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ScreenManagerStub); +}; + +} // namespace display + +#endif // SERVICES_UI_DISPLAY_SCREEN_MANAGER_STUB_H_
diff --git a/services/ui/gpu/gpu_main.cc b/services/ui/gpu/gpu_main.cc index 7b14ea5e..5be189b 100644 --- a/services/ui/gpu/gpu_main.cc +++ b/services/ui/gpu/gpu_main.cc
@@ -10,6 +10,7 @@ #include "gpu/ipc/gpu_in_process_thread_service.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" #include "gpu/ipc/service/gpu_watchdog_thread.h" +#include "services/ui/common/mus_gpu_memory_buffer_manager.h" #include "services/ui/gpu/gpu_service_internal.h" namespace {
diff --git a/services/ui/public/interfaces/display/display_controller.mojom b/services/ui/public/interfaces/display/display_controller.mojom index c4e126d..0d991ae 100644 --- a/services/ui/public/interfaces/display/display_controller.mojom +++ b/services/ui/public/interfaces/display/display_controller.mojom
@@ -10,9 +10,29 @@ // state. interface DisplayController { + // =========================== Keyboard Shortcuts =========================== + + // Increase zoom on internal display. + IncreaseInternalDisplayZoom(); + + // Decrease zoom on internal display. + DecreaseInternalDisplayZoom(); + + // Reset zoom on internal display to default level. + ResetInternalDisplayZoom(); + + // Rotate the current display by 90° CW. The current display is the display + // closest to the mouse cursor. + RotateCurrentDisplayCW(); + // Swap the primary display and the next display. SwapPrimaryDisplay(); + // Toggles between mirroring and extended mode. + ToggleMirrorMode(); + + // ========================= Configuration Changes ========================== + // Sets the display work area with the provided insets. The display size is // included to ensure that the insets are for the current display size. SetDisplayWorkArea(int64 display_id,
diff --git a/services/ui/service.cc b/services/ui/service.cc index 03de291..16dcc4be 100644 --- a/services/ui/service.cc +++ b/services/ui/service.cc
@@ -24,7 +24,7 @@ #include "services/tracing/public/cpp/provider.h" #include "services/ui/clipboard/clipboard_impl.h" #include "services/ui/common/switches.h" -#include "services/ui/display/platform_screen.h" +#include "services/ui/display/screen_manager.h" #include "services/ui/ime/ime_registrar_impl.h" #include "services/ui/ime/ime_server_impl.h" #include "services/ui/ws/accessibility_manager.h" @@ -87,7 +87,7 @@ Service::Service() : test_config_(false), - platform_screen_(display::PlatformScreen::Create()), + screen_manager_(display::ScreenManager::Create()), ime_registrar_(&ime_server_) {} Service::~Service() { @@ -187,7 +187,7 @@ // so keep this line below both of those. input_device_server_.RegisterAsObserver(); - // Gpu must be running before the PlatformScreen can be initialized. + // Gpu must be running before the ScreenManager can be initialized. window_server_.reset(new ws::WindowServer(this)); // DeviceDataManager must be initialized before TouchController. On non-Linux @@ -220,7 +220,7 @@ if (input_device_server_.IsRegisteredAsObserver()) input_device_server_.AddInterface(registry); - platform_screen_->AddInterfaces(registry); + screen_manager_->AddInterfaces(registry); #if defined(USE_OZONE) ui::OzonePlatform::GetInstance()->AddInterfaces(registry); @@ -230,7 +230,7 @@ } void Service::StartDisplayInit() { - platform_screen_->Init(window_server_->display_manager()); + screen_manager_->Init(window_server_->display_manager()); } void Service::OnFirstDisplayReady() {
diff --git a/services/ui/service.h b/services/ui/service.h index 6b1a18a0..40cd1b1 100644 --- a/services/ui/service.h +++ b/services/ui/service.h
@@ -41,7 +41,7 @@ #endif namespace display { -class PlatformScreen; +class ScreenManager; } namespace gfx { @@ -181,7 +181,7 @@ // Manages display hardware and handles display management. May register Mojo // interfaces and must outlive service_manager::InterfaceRegistry. - std::unique_ptr<display::PlatformScreen> platform_screen_; + std::unique_ptr<display::ScreenManager> screen_manager_; std::unique_ptr<ws::TouchController> touch_controller_; IMERegistrarImpl ime_registrar_;
diff --git a/services/ui/surfaces/BUILD.gn b/services/ui/surfaces/BUILD.gn index c4f8e46..7817fc5c 100644 --- a/services/ui/surfaces/BUILD.gn +++ b/services/ui/surfaces/BUILD.gn
@@ -30,9 +30,6 @@ "//gpu/ipc/common", "//services/service_manager/public/cpp", "//services/tracing/public/cpp", - "//services/ui/common:server_gpu", - "//services/ui/gpu/interfaces", - "//services/ui/public/interfaces", "//ui/display/types", "//ui/gfx", "//ui/gfx/geometry/mojo",
diff --git a/services/ui/surfaces/display_compositor.cc b/services/ui/surfaces/display_compositor.cc index ab1508a..97cc327 100644 --- a/services/ui/surfaces/display_compositor.cc +++ b/services/ui/surfaces/display_compositor.cc
@@ -9,7 +9,6 @@ #include "gpu/command_buffer/client/shared_memory_limits.h" #include "gpu/ipc/gpu_in_process_thread_service.h" #include "mojo/public/cpp/bindings/strong_binding.h" -#include "services/ui/common/mus_gpu_memory_buffer_manager.h" #include "services/ui/surfaces/gpu_compositor_frame_sink.h" namespace ui {
diff --git a/services/ui/surfaces/display_compositor.h b/services/ui/surfaces/display_compositor.h index 950250d..0b3e67fb 100644 --- a/services/ui/surfaces/display_compositor.h +++ b/services/ui/surfaces/display_compositor.h
@@ -20,7 +20,6 @@ #include "gpu/ipc/in_process_command_buffer.h" #include "ipc/ipc_channel_handle.h" #include "mojo/public/cpp/bindings/binding.h" -#include "services/ui/common/mus_gpu_memory_buffer_manager.h" namespace gpu { class GpuMemoryBufferManager;
diff --git a/services/ui/ws/cursor_unittest.cc b/services/ui/ws/cursor_unittest.cc index 8e38e2b..bfd4008 100644 --- a/services/ui/ws/cursor_unittest.cc +++ b/services/ui/ws/cursor_unittest.cc
@@ -48,8 +48,8 @@ protected: // testing::Test: void SetUp() override { - platform_screen_.Init(window_server()->display_manager()); - platform_screen_.AddDisplay(); + screen_manager_.Init(window_server()->display_manager()); + screen_manager_.AddDisplay(); // As a side effect, this allocates Displays. AddWindowManager(window_server(), kTestId1); @@ -103,7 +103,7 @@ private: WindowServerTestHelper ws_test_helper_; - TestPlatformScreen platform_screen_; + TestScreenManager screen_manager_; DISALLOW_COPY_AND_ASSIGN(CursorTest); };
diff --git a/services/ui/ws/display_manager.cc b/services/ui/ws/display_manager.cc index 3607d60..2d9abf3 100644 --- a/services/ui/ws/display_manager.cc +++ b/services/ui/ws/display_manager.cc
@@ -8,7 +8,6 @@ #include "base/memory/ptr_util.h" #include "base/trace_event/trace_event.h" -#include "services/ui/display/platform_screen.h" #include "services/ui/ws/display.h" #include "services/ui/ws/display_binding.h" #include "services/ui/ws/event_dispatcher.h"
diff --git a/services/ui/ws/display_manager.h b/services/ui/ws/display_manager.h index 1915aaa1..00eeebb 100644 --- a/services/ui/ws/display_manager.h +++ b/services/ui/ws/display_manager.h
@@ -10,7 +10,7 @@ #include <set> #include "base/macros.h" -#include "services/ui/display/platform_screen_delegate.h" +#include "services/ui/display/screen_manager_delegate.h" #include "services/ui/ws/ids.h" #include "services/ui/ws/user_id.h" #include "services/ui/ws/user_id_tracker_observer.h" @@ -29,7 +29,7 @@ // between displays that do yet have an accelerated widget (pending), vs // those that do. class DisplayManager : public UserIdTrackerObserver, - public display::PlatformScreenDelegate { + public display::ScreenManagerDelegate { public: DisplayManager(WindowServer* window_server, UserIdTracker* user_id_tracker); ~DisplayManager() override; @@ -81,7 +81,7 @@ void OnActiveUserIdChanged(const UserId& previously_active_id, const UserId& active_id) override; - // display::PlatformScreenDelegate: + // display::ScreenManagerDelegate: void OnDisplayAdded(int64_t id, const display::ViewportMetrics& metrics) override; void OnDisplayRemoved(int64_t id) override;
diff --git a/services/ui/ws/display_unittest.cc b/services/ui/ws/display_unittest.cc index 46f07aa..f2041f1 100644 --- a/services/ui/ws/display_unittest.cc +++ b/services/ui/ws/display_unittest.cc
@@ -103,19 +103,19 @@ TestWindowServerDelegate* window_server_delegate() { return ws_test_helper_.window_server_delegate(); } - TestPlatformScreen& platform_screen() { return platform_screen_; } + TestScreenManager& screen_manager() { return screen_manager_; } protected: // testing::Test: void SetUp() override { - platform_screen_.Init(window_server()->display_manager()); + screen_manager_.Init(window_server()->display_manager()); window_server()->user_id_tracker()->AddUserId(kTestId1); window_server()->user_id_tracker()->AddUserId(kTestId2); } private: WindowServerTestHelper ws_test_helper_; - TestPlatformScreen platform_screen_; + TestScreenManager screen_manager_; DISALLOW_COPY_AND_ASSIGN(DisplayTest); }; @@ -123,7 +123,7 @@ TEST_F(DisplayTest, CreateDisplay) { AddWindowManager(window_server(), kTestId1); const int64_t display_id = - platform_screen().AddDisplay(MakeViewportMetrics(0, 0, 1024, 768, 1.0f)); + screen_manager().AddDisplay(MakeViewportMetrics(0, 0, 1024, 768, 1.0f)); ASSERT_EQ(1u, display_manager()->displays().size()); Display* display = display_manager()->GetDisplayById(display_id); @@ -144,7 +144,7 @@ TEST_F(DisplayTest, CreateDisplayBeforeWM) { // Add one display, no WM exists yet. const int64_t display_id = - platform_screen().AddDisplay(MakeViewportMetrics(0, 0, 1024, 768, 1.0f)); + screen_manager().AddDisplay(MakeViewportMetrics(0, 0, 1024, 768, 1.0f)); EXPECT_EQ(1u, display_manager()->displays().size()); Display* display = display_manager()->GetDisplayById(display_id); @@ -170,7 +170,7 @@ TEST_F(DisplayTest, CreateDisplayWithTwoWindowManagers) { AddWindowManager(window_server(), kTestId1); - const int64_t display_id = platform_screen().AddDisplay(); + const int64_t display_id = screen_manager().AddDisplay(); Display* display = display_manager()->GetDisplayById(display_id); // There should be only be one WM at this point. @@ -201,7 +201,7 @@ EXPECT_EQ("0,0 512x384", metrics.bounds.ToString()); EXPECT_EQ("1024x768", metrics.pixel_size.ToString()); - const int64_t display_id = platform_screen().AddDisplay(metrics); + const int64_t display_id = screen_manager().AddDisplay(metrics); Display* display = display_manager()->GetDisplayById(display_id); // The root ServerWindow bounds should be in PP. @@ -209,7 +209,7 @@ ViewportMetrics modified_metrics = metrics; modified_metrics.work_area.set_height(metrics.work_area.height() - 48); - platform_screen().ModifyDisplay(display_id, modified_metrics); + screen_manager().ModifyDisplay(display_id, modified_metrics); // The root ServerWindow should still be in PP after updating the work area. EXPECT_EQ("0,0 1024x768", display->root_window()->bounds().ToString()); @@ -218,7 +218,7 @@ TEST_F(DisplayTest, Destruction) { AddWindowManager(window_server(), kTestId1); - int64_t display_id = platform_screen().AddDisplay(); + int64_t display_id = screen_manager().AddDisplay(); // Add a second WM. AddWindowManager(window_server(), kTestId2); @@ -240,14 +240,14 @@ } EXPECT_FALSE(window_server_delegate()->got_on_no_more_displays()); - platform_screen().RemoveDisplay(display_id); + screen_manager().RemoveDisplay(display_id); // There is still one tree left. EXPECT_EQ(1u, window_server()->num_trees()); EXPECT_TRUE(window_server_delegate()->got_on_no_more_displays()); } TEST_F(DisplayTest, EventStateResetOnUserSwitch) { - const int64_t display_id = platform_screen().AddDisplay(); + const int64_t display_id = screen_manager().AddDisplay(); AddWindowManager(window_server(), kTestId1); AddWindowManager(window_server(), kTestId2); @@ -290,7 +290,7 @@ // Verifies capture fails when wm is inactive and succeeds when wm is active. TEST_F(DisplayTest, SetCaptureFromWindowManager) { - const int64_t display_id = platform_screen().AddDisplay(); + const int64_t display_id = screen_manager().AddDisplay(); AddWindowManager(window_server(), kTestId1); AddWindowManager(window_server(), kTestId2); window_server()->user_id_tracker()->SetActiveUserId(kTestId1); @@ -318,7 +318,7 @@ } TEST_F(DisplayTest, FocusFailsForInactiveUser) { - const int64_t display_id = platform_screen().AddDisplay(); + const int64_t display_id = screen_manager().AddDisplay(); AddWindowManager(window_server(), kTestId1); TestWindowTreeClient* window_tree_client1 = window_server_delegate()->last_client(); @@ -353,8 +353,8 @@ // Verifies a single tree is used for multiple displays. TEST_F(DisplayTest, MultipleDisplays) { - platform_screen().AddDisplay(); - platform_screen().AddDisplay(); + screen_manager().AddDisplay(); + screen_manager().AddDisplay(); AddWindowManager(window_server(), kTestId1); window_server()->user_id_tracker()->SetActiveUserId(kTestId1); ASSERT_EQ(1u, window_server_delegate()->bindings()->size()); @@ -382,8 +382,8 @@ // Assertions around destroying a secondary display. TEST_F(DisplayTest, DestroyingDisplayDoesntDelete) { AddWindowManager(window_server(), kTestId1); - platform_screen().AddDisplay(); - const int64_t secondary_display_id = platform_screen().AddDisplay(); + screen_manager().AddDisplay(); + const int64_t secondary_display_id = screen_manager().AddDisplay(); window_server()->user_id_tracker()->SetActiveUserId(kTestId1); ASSERT_EQ(1u, window_server_delegate()->bindings()->size()); WindowTree* tree = (*window_server_delegate()->bindings())[0]->tree(); @@ -404,7 +404,7 @@ TestWindowManager* test_window_manager = window_server_delegate()->last_binding()->window_manager(); EXPECT_FALSE(test_window_manager->got_display_removed()); - platform_screen().RemoveDisplay(secondary_display_id); + screen_manager().RemoveDisplay(secondary_display_id); // Destroying the display should result in the following: // . The WindowManager should be told it was removed with the right id.
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc index 41d40ca..11f105d 100644 --- a/services/ui/ws/platform_display_default.cc +++ b/services/ui/ws/platform_display_default.cc
@@ -5,7 +5,7 @@ #include "services/ui/ws/platform_display_default.h" #include "gpu/ipc/client/gpu_channel_host.h" -#include "services/ui/display/platform_screen.h" +#include "services/ui/display/screen_manager.h" #include "services/ui/ws/platform_display_init_params.h" #include "services/ui/ws/server_window.h" #include "ui/base/cursor/cursor_loader.h" @@ -212,7 +212,7 @@ } void PlatformDisplayDefault::OnCloseRequest() { - display::PlatformScreen::GetInstance()->RequestCloseDisplay(GetId()); + display::ScreenManager::GetInstance()->RequestCloseDisplay(GetId()); } void PlatformDisplayDefault::OnClosed() {}
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc index 4e797f3c..c30f4472 100644 --- a/services/ui/ws/test_utils.cc +++ b/services/ui/ws/test_utils.cc
@@ -86,18 +86,17 @@ } // namespace -// TestPlatformScreen ------------------------------------------------- +// TestScreenManager ------------------------------------------------- -TestPlatformScreen::TestPlatformScreen() {} +TestScreenManager::TestScreenManager() {} -TestPlatformScreen::~TestPlatformScreen() {} +TestScreenManager::~TestScreenManager() {} -int64_t TestPlatformScreen::AddDisplay() { +int64_t TestScreenManager::AddDisplay() { return AddDisplay(MakeViewportMetrics(0, 0, 100, 100, 1.0f)); } -int64_t TestPlatformScreen::AddDisplay( - const display::ViewportMetrics& metrics) { +int64_t TestScreenManager::AddDisplay(const display::ViewportMetrics& metrics) { // Generate a unique display id. int64_t display_id = display_ids_.empty() ? 1 : *display_ids_.rbegin() + 1; display_ids_.insert(display_id); @@ -113,27 +112,26 @@ return display_id; } -void TestPlatformScreen::ModifyDisplay( - int64_t id, - const display::ViewportMetrics& metrics) { +void TestScreenManager::ModifyDisplay(int64_t id, + const display::ViewportMetrics& metrics) { DCHECK(display_ids_.count(id) == 1); delegate_->OnDisplayModified(id, metrics); } -void TestPlatformScreen::RemoveDisplay(int64_t id) { +void TestScreenManager::RemoveDisplay(int64_t id) { DCHECK(display_ids_.count(id) == 1); delegate_->OnDisplayRemoved(id); display_ids_.erase(id); } -void TestPlatformScreen::Init(display::PlatformScreenDelegate* delegate) { +void TestScreenManager::Init(display::ScreenManagerDelegate* delegate) { // Reset delegate_ = delegate; display_ids_.clear(); primary_display_id_ = display::kInvalidDisplayId; } -int64_t TestPlatformScreen::GetPrimaryDisplayId() const { +int64_t TestScreenManager::GetPrimaryDisplayId() const { return primary_display_id_; }
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h index bf2bc0e..9cafaa9 100644 --- a/services/ui/ws/test_utils.h +++ b/services/ui/ws/test_utils.h
@@ -13,7 +13,7 @@ #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" -#include "services/ui/display/platform_screen.h" +#include "services/ui/display/screen_manager.h" #include "services/ui/display/viewport_metrics.h" #include "services/ui/public/interfaces/display_manager.mojom.h" #include "services/ui/public/interfaces/window_tree.mojom.h" @@ -41,14 +41,14 @@ // Collection of utilities useful in creating mus tests. -// Test PlatformDisplay instance that allows adding/modifying/removing displays. +// Test ScreenManager instance that allows adding/modifying/removing displays. // Tracks display ids to perform some basic verification that no duplicates are // added and display was added before being modified or removed. Display ids // reset when Init() is called. -class TestPlatformScreen : public display::PlatformScreen { +class TestScreenManager : public display::ScreenManager { public: - TestPlatformScreen(); - ~TestPlatformScreen() override; + TestScreenManager(); + ~TestScreenManager() override; // Adds a new display with default metrics, generates a unique display id and // returns it. Calls OnDisplayAdded() on delegate. @@ -64,18 +64,18 @@ // Calls OnDisplayRemoved() on delegate. void RemoveDisplay(int64_t id); - // display::PlatformScreen: + // display::ScreenManager: void AddInterfaces(service_manager::InterfaceRegistry* registry) override {} - void Init(display::PlatformScreenDelegate* delegate) override; + void Init(display::ScreenManagerDelegate* delegate) override; void RequestCloseDisplay(int64_t display_id) override {} int64_t GetPrimaryDisplayId() const override; private: - display::PlatformScreenDelegate* delegate_; + display::ScreenManagerDelegate* delegate_; int64_t primary_display_id_ = display::kInvalidDisplayId; std::set<int64_t> display_ids_; - DISALLOW_COPY_AND_ASSIGN(TestPlatformScreen); + DISALLOW_COPY_AND_ASSIGN(TestScreenManager); }; // -----------------------------------------------------------------------------
diff --git a/services/ui/ws/user_display_manager.cc b/services/ui/ws/user_display_manager.cc index d70d246..4b9129c 100644 --- a/services/ui/ws/user_display_manager.cc +++ b/services/ui/ws/user_display_manager.cc
@@ -6,7 +6,7 @@ #include <utility> -#include "services/ui/display/platform_screen.h" +#include "services/ui/display/screen_manager.h" #include "services/ui/ws/display.h" #include "services/ui/ws/display_manager.h" #include "services/ui/ws/user_display_manager_delegate.h" @@ -158,7 +158,7 @@ // TODO(kylechar): Pass internal display id to clients here. observer->OnDisplays( GetAllDisplays().PassStorage(), - display::PlatformScreen::GetInstance()->GetPrimaryDisplayId(), + display::ScreenManager::GetInstance()->GetPrimaryDisplayId(), display::kInvalidDisplayId); }
diff --git a/services/ui/ws/user_display_manager_unittest.cc b/services/ui/ws/user_display_manager_unittest.cc index afb1c70e..174886f 100644 --- a/services/ui/ws/user_display_manager_unittest.cc +++ b/services/ui/ws/user_display_manager_unittest.cc
@@ -17,7 +17,7 @@ #include "services/ui/common/task_runner_test_base.h" #include "services/ui/common/types.h" #include "services/ui/common/util.h" -#include "services/ui/display/platform_screen.h" +#include "services/ui/display/screen_manager.h" #include "services/ui/ws/display_manager.h" #include "services/ui/ws/ids.h" #include "services/ui/ws/server_window.h" @@ -110,22 +110,22 @@ return ws_test_helper_.window_server_delegate(); } - TestPlatformScreen& platform_screen() { return platform_screen_; } + TestScreenManager& screen_manager() { return screen_manager_; } private: // testing::Test: void SetUp() override { TaskRunnerTestBase::SetUp(); - platform_screen_.Init(window_server()->display_manager()); + screen_manager_.Init(window_server()->display_manager()); } WindowServerTestHelper ws_test_helper_; - TestPlatformScreen platform_screen_; + TestScreenManager screen_manager_; DISALLOW_COPY_AND_ASSIGN(UserDisplayManagerTest); }; TEST_F(UserDisplayManagerTest, OnlyNotifyWhenFrameDecorationsSet) { - platform_screen().AddDisplay(); + screen_manager().AddDisplay(); TestDisplayManagerObserver display_manager_observer1; DisplayManager* display_manager = window_server()->display_manager(); @@ -153,7 +153,7 @@ } TEST_F(UserDisplayManagerTest, AddObserverAfterFrameDecorationsSet) { - platform_screen().AddDisplay(); + screen_manager().AddDisplay(); TestDisplayManagerObserver display_manager_observer1; DisplayManager* display_manager = window_server()->display_manager(); @@ -175,7 +175,7 @@ } TEST_F(UserDisplayManagerTest, AddRemoveDisplay) { - platform_screen().AddDisplay(); + screen_manager().AddDisplay(); TestDisplayManagerObserver display_manager_observer1; DisplayManager* display_manager = window_server()->display_manager(); @@ -195,7 +195,7 @@ display_manager_observer1.GetAndClearObserverCalls()); // Add another display. - const int64_t second_display_id = platform_screen().AddDisplay(); + const int64_t second_display_id = screen_manager().AddDisplay(); RunUntilIdle(); // Observer should be notified immediately as frame decorations were set. @@ -203,7 +203,7 @@ display_manager_observer1.GetAndClearObserverCalls()); // Remove the display and verify observer is notified. - platform_screen().RemoveDisplay(second_display_id); + screen_manager().RemoveDisplay(second_display_id); RunUntilIdle(); EXPECT_EQ("OnDisplayRemoved 2", @@ -211,7 +211,7 @@ } TEST_F(UserDisplayManagerTest, NegativeCoordinates) { - platform_screen().AddDisplay(); + screen_manager().AddDisplay(); TestDisplayManagerObserver display_manager_observer1; DisplayManager* display_manager = window_server()->display_manager();
diff --git a/services/ui/ws/window_manager_state_unittest.cc b/services/ui/ws/window_manager_state_unittest.cc index eebde14..a67f0bf 100644 --- a/services/ui/ws/window_manager_state_unittest.cc +++ b/services/ui/ws/window_manager_state_unittest.cc
@@ -547,9 +547,9 @@ TEST(WindowManagerStateShutdownTest, DestroyTreeBeforeDisplay) { WindowServerTestHelper ws_test_helper; WindowServer* window_server = ws_test_helper.window_server(); - TestPlatformScreen platform_screen; - platform_screen.Init(window_server->display_manager()); - platform_screen.AddDisplay(); + TestScreenManager screen_manager; + screen_manager.Init(window_server->display_manager()); + screen_manager.AddDisplay(); const UserId kUserId1 = "2"; AddWindowManager(window_server, kUserId1); ASSERT_EQ(1u, window_server->display_manager()->displays().size());
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc index 708298c..2c0ded3 100644 --- a/services/ui/ws/window_tree_unittest.cc +++ b/services/ui/ws/window_tree_unittest.cc
@@ -1355,10 +1355,10 @@ // Create a tree with one window. WindowServerTestHelper ws_test_helper; WindowServer* window_server = ws_test_helper.window_server(); - TestPlatformScreen platform_screen; - platform_screen.Init(window_server->display_manager()); + TestScreenManager screen_manager; + screen_manager.Init(window_server->display_manager()); window_server->user_id_tracker()->AddUserId(kTestUserId1); - platform_screen.AddDisplay(); + screen_manager.AddDisplay(); AddWindowManager(window_server, kTestUserId1); window_server->user_id_tracker()->SetActiveUserId(kTestUserId1);
diff --git a/testing/buildbot/README.md b/testing/buildbot/README.md new file mode 100644 index 0000000..68cfcce5 --- /dev/null +++ b/testing/buildbot/README.md
@@ -0,0 +1,67 @@ +# Buildbot Testing Configuration Files + +The files in this directory control how tests are run on the +[Chromium buildbots](https://www.chromium.org/developers/testing/chromium-build-infrastructure/tour-of-the-chromium-buildbot). +In addition to specifying what tests run on which builders, they also specify +special arguments and constraints for the tests. + +## A tour of the directory +* <master_name\>.json -- buildbot configuration json files. These are used to +configure what tests are run on what builders, in addition to specifying +builder-specific arguments and parameters. +* [gn_isolate_map.pyl](./gn_isolate_map.pyl) -- maps Ninja build target names +to GN labels. Allows for certain overrides to get certain tests targets to work +with GN (and properly run when isolated). +* [trybot_analyze_config.json](./trybot_analyze_config.json) -- used to provide +exclusions to +[the analyze step](https://www.chromium.org/developers/testing/commit-queue/chromium_trybot-json) +on trybots. +* [filters/](./filters/) -- filters out tests that shouldn't be +run in a particular mode. +* [timeouts.py](./timeouts.py) -- calculates acceptable timeouts for tests by +analyzing their execution on +[swarming](https://github.com/luci/luci-py/tree/master/appengine/swarming). +* [manage.py](./manage.py) -- makes sure the buildbot configuration json is in +a standardized format. + +## How the files are consumed +### Buildbot configuration json +Logic in the +[Chromium recipe](https://chromium.googlesource.com/chromium/tools/build/+/refs/heads/master/scripts/slave/recipes/chromium.py) +looks up each builder for each master and test generators in +[chromium_tests/steps.py](https://chromium.googlesource.com/chromium/tools/build/+/refs/heads/master/scripts/slave/recipe_modules/chromium_tests/steps.py) +parse the data. For example, as of +[a6e11220](https://chromium.googlesource.com/chromium/tools/build/+/a6e11220d97d578d6ba091abd68beba28a004722) +[generate_gtest](https://chromium.googlesource.com/chromium/tools/build/+/a6e11220d97d578d6ba091abd68beba28a004722/scripts/slave/recipe_modules/chromium_tests/steps.py#416) +parses any entry in a builder's +['gtest_tests'](https://chromium.googlesource.com/chromium/src/+/5750756522296b2a9a08009d8d2cc90db3b88f56/testing/buildbot/chromium.android.json#1243) +entry. + +## How to edit +### Making the changes +#### Buildbot configuration json +After editing any buildbot json, run `./manage.py -w` to load and write in the +canonical format. Then commit as normal. + +Note that trybots mirror regular waterfall bots, with the mapping defined in +[trybots.py](https://chromium.googlesource.com/chromium/tools/build/+/refs/heads/master/scripts/slave/recipe_modules/chromium_tests/trybots.py). +This means that, as of +[81fcc4bc](https://chromium.googlesource.com/chromium/src/+/81fcc4bc6123ace8dd37db74fd2592e3e15ea46a/testing/buildbot/), +if you want to edit +[linux_android_rel_ng](https://chromium.googlesource.com/chromium/tools/build/+/59a2653d5f143213f4f166714657808b0c646bd7/scripts/slave/recipe_modules/chromium_tests/trybots.py#142), +you actually need to edit +[Android Tests](https://chromium.googlesource.com/chromium/src/+/81fcc4bc6123ace8dd37db74fd2592e3e15ea46a/testing/buildbot/chromium.linux.json#23). + +### Trying the changes on trybots +You should be able to try build changes that affect the trybots directly (for +example, adding a test to linux_android_rel_ng should show up immediately in +your tryjob). Non-trybot changes have to be landed manually :(. + +## Capacity considerations when editing the buildbot configuration json +When adding tests or bumping timeouts in the buildbot configuration json, care +must be taken to ensure the infrastructure has capacity to handle the extra +load. This is especially true for the established +[Chromium CQ builders](https://chromium.googlesource.com/chromium/src/+/master/infra/config/cq.cfg), +as they operate under strict execution requirements. Make sure to get an +infrastructure engineer on the Crossover Team to sign off that there is both +buildbot and swarming capacity available.
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index b94763bd..b5968ca 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -29,12 +29,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "ash_content_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "aura_unittests" }, { @@ -541,12 +535,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "ash_content_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "aura_unittests" }, { @@ -995,12 +983,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "ash_content_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "aura_unittests" }, { @@ -1467,12 +1449,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "ash_content_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "aura_unittests" }, {
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index ab95d59..07ff7fe 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -535,7 +535,10 @@ crbug.com/498539 [ Mac ] inspector/sources/debugger/live-edit-no-reveal.html [ Crash Pass Timeout ] crbug.com/498539 [ Win7 ] inspector/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.html [ Failure Pass ] crbug.com/498539 [ Mac10.9 ] inspector/console/console-uncaught-exception.html [ Failure Pass ] -crbug.com/498539 crbug.com/405845 [ Win7 ] inspector/console/console-dir-es6.html [ Failure Pass NeedsManualRebaseline ] + +# TODO(luoe): The old expectation before NeedsManualRebaseline was the following +# crbug.com/498539 [ Win7 ] inspector/console/console-dir-es6.html [ Failure Pass ] +crbug.com/405845 inspector/console/console-dir-es6.html [ NeedsManualRebaseline ] crbug.com/498539 [ Win7 ] inspector/elements/styles-4/styles-update-from-js.html [ Crash Pass ] crbug.com/596968 [ Win ] inspector-protocol/input/eventTimestamp.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-zero-size-readback.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-zero-size-readback.html new file mode 100644 index 0000000..c9acf3a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-zero-size-readback.html
@@ -0,0 +1,64 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +promise_test( + t => { return zeroSizeReadback("width", "none", t); }, + "Verify convertToBlob on a 0 width OffscreenCanvas with no context." +); + +promise_test( + t => { return zeroSizeReadback("width", "2d", t); }, + "Verify convertToBlob and getImageData on a 0 width OffscreenCanvas with a 2d context." +); + +promise_test( + t => { return zeroSizeReadback("width", "webgl", t); }, + "Verify convertToBlob on a 0 width OffscreenCanvas with a webgl context." +); + +promise_test( + t => { return zeroSizeReadback("width", "webgl2", t); }, + "Verify convertToBlob on a 0 width OffscreenCanvas with a webgl2 context." +); + +promise_test( + t => { return zeroSizeReadback("height", "none", t); }, + "Verify convertToBlob on a 0 height OffscreenCanvas with no context." +); + +promise_test( + t => { return zeroSizeReadback("height", "2d", t); }, + "Verify convertToBlob and getImageData on a 0 height OffscreenCanvas with a 2d context." +); + +promise_test( + t => { return zeroSizeReadback("height", "webgl", t); }, + "Verify convertToBlob on a 0 height OffscreenCanvas with a webgl context." +); + +promise_test( + t => { return zeroSizeReadback("height", "webgl2", t); }, + "Verify convertToBlob on a 0 height OffscreenCanvas with a webgl2 context." +); + +function zeroSizeReadback(zeroDimension, contextType, t) { + var offscreen = new OffscreenCanvas(10, 10); + eval("offscreen." + zeroDimension + " = 0"); + // Verify that one of the dimensions was indeed zeroed. + assert_equals(offscreen.width * offscreen.height, 0); + + var ctx; + if (contextType != "none") { + ctx = offscreen.getContext(contextType); + } + + if (contextType == '2d') { + var imgdata = ctx.getImageData(0, 0, 1, 1); + assert_equals(imgdata.width, 1); + assert_equals(imgdata.height, 1); + } + + return promise_rejects(t, new DOMException('', 'IndexSizeError'), offscreen.convertToBlob()); +} +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/filtered-item-selection-dialog-filtering.html b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/filtered-item-selection-dialog-filtering.js similarity index 70% rename from third_party/WebKit/LayoutTests/http/tests/inspector-unit/filtered-item-selection-dialog-filtering.html rename to third_party/WebKit/LayoutTests/http/tests/inspector-unit/filtered-item-selection-dialog-filtering.js index 8c79670a..3d4a7ad 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/filtered-item-selection-dialog-filtering.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/filtered-item-selection-dialog-filtering.js
@@ -1,12 +1,7 @@ -<html> -<head> -<base href="/inspector-debug/"></base> -<script src="/inspector-debug/Runtime.js"></script> -<script src="/inspector-unit/inspector-unit-test.js"></script> -<script> -UnitTest.addDependency("ui_lazy"); -function test() -{ +TestRunner.loadLazyModules(["ui_lazy"]).then(test); +function test() { + TestRunner.addResult("Check to see that FilteredItemSelectionDialog uses proper regex to filter results."); + var overridenInput = []; var overrideShowMatchingItems = true; var history = []; @@ -22,7 +17,7 @@ itemCount() { return overridenInput.length; } selectItem(itemIndex, promptValue) { - UnitTest.addResult("Selected item index: " + itemIndex); + TestRunner.addResult("Selected item index: " + itemIndex); } shouldShowMatchingItems () { return overrideShowMatchingItems; } }; @@ -34,34 +29,34 @@ overridenInput = input; overrideShowMatchingItems = !hideMatchingItems; - UnitTest.addResult("Input:" + JSON.stringify(input)); + TestRunner.addResult("Input:" + JSON.stringify(input)); var filteredSelectionDialog = new UI.FilteredListWidget(delegate); filteredSelectionDialog.showAsDialog(); - var promise = UnitTest.addSniffer(filteredSelectionDialog, "_itemsFilteredForTest").then(accept); + var promise = TestRunner.addSniffer(filteredSelectionDialog, "_itemsFilteredForTest").then(accept); filteredSelectionDialog.setQuery(query); filteredSelectionDialog._updateAfterItemsLoaded(); return promise; function dump() { - UnitTest.addResult("Query:" + JSON.stringify(filteredSelectionDialog._value())); + TestRunner.addResult("Query:" + JSON.stringify(filteredSelectionDialog._value())); var items = filteredSelectionDialog._filteredItems; var output = []; for (var i = 0; i < items.length; ++i) output.push(delegate.itemKeyAt(items[i])); - UnitTest.addResult("Output:" + JSON.stringify(output)); + TestRunner.addResult("Output:" + JSON.stringify(output)); } function accept() { dump(); - filteredSelectionDialog._onEnter(UnitTest.createKeyEvent("Enter")); - UnitTest.addResult("History:" + JSON.stringify(history)); + filteredSelectionDialog._onEnter(TestRunner.createKeyEvent("Enter")); + TestRunner.addResult("History:" + JSON.stringify(history)); } } - UnitTest.runTests([ + TestRunner.runTests([ function emptyQueryMatchesEverything() { return checkQuery("", ["a", "bc"]); @@ -98,12 +93,3 @@ } ]); } - -</script> -</head> - -<body> -<p>Check to see that FilteredItemSelectionDialog uses proper regex to filter results.</p> -</body> -</html> -
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/inspector-unit-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/inspector-unit-test.js deleted file mode 100644 index bb1ca19..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/inspector-unit-test.js +++ /dev/null
@@ -1,157 +0,0 @@ -var UnitTest = {}; -(function() -{ - var lazyModules = []; - var oldLoadResourcePromise = Runtime.loadResourcePromise; - Runtime.loadResourcePromise = function(url) - { - if (url.startsWith("/")) - return oldLoadResourcePromise(url); - - if (!url.startsWith("http://")) - return oldLoadResourcePromise("/inspector-debug/" + url); - - var parsedURL = new URL(url, location.href); - var parsedLocation = new URL(location.href); - - // hosted devtools is confused. - parsedURL.pathname = parsedURL.pathname.replace('/inspector-unit/', '/inspector-debug/'); - return oldLoadResourcePromise(parsedURL.toString()); - } - - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - var results = []; - UnitTest.completeTest = function() - { - if (!window.testRunner) { - console.log("Test Done"); - return; - } - - document.documentElement.childNodes.forEach(x => x.remove()); - var outputElement = document.createElement("div"); - // Support for svg - add to document, not body, check for style. - if (outputElement.style) { - outputElement.style.whiteSpace = "pre"; - outputElement.style.height = "10px"; - outputElement.style.overflow = "hidden"; - } - document.documentElement.appendChild(outputElement); - for (var i = 0; i < results.length; i++) { - outputElement.appendChild(document.createTextNode(results[i])); - outputElement.appendChild(document.createElement("br")); - } - results = []; - testRunner.notifyDone(); - }; - - UnitTest.addResult = function(text) - { - if (window.testRunner) - results.push(String(text)); - else - console.log(text); - }; - - UnitTest.runTests = function(tests) - { - nextTest(); - - function nextTest() - { - var test = tests.shift(); - if (!test) { - UnitTest.completeTest(); - return; - } - UnitTest.addResult("\ntest: " + test.name); - var testPromise = test(); - if (!(testPromise instanceof Promise)) - testPromise = Promise.resolve(); - testPromise.then(nextTest); - } - }; - - UnitTest.addSniffer = function(receiver, methodName) - { - return new Promise(function(resolve, reject) - { - var original = receiver[methodName]; - if (typeof original !== "function") { - reject("Cannot find method to override: " + methodName); - return; - } - - receiver[methodName] = function(var_args) - { - try { - var result = original.apply(this, arguments); - } finally { - receiver[methodName] = original; - } - // In case of exception the override won't be called. - try { - Array.prototype.push.call(arguments, result); - resolve.apply(this, arguments); - } catch (e) { - reject("Exception in overriden method '" + methodName + "': " + e); - UnitTest.completeTest(); - } - return result; - }; - }); - }; - - UnitTest.addDependency = function(lazyModule) - { - lazyModules.push(lazyModule); - }; - - UnitTest.createKeyEvent = function(key, ctrlKey, altKey, shiftKey, metaKey) - { - return new KeyboardEvent("keydown", { key: key, bubbles: true, cancelable: true, ctrlKey: ctrlKey, altKey: altKey, shiftKey: shiftKey, metaKey: metaKey }); - }; - - function completeTestOnError(message, source, lineno, colno, error) - { - UnitTest.addResult("TEST ENDED IN ERROR: " + error.stack); - UnitTest.completeTest(); - } - window.onerror = completeTestOnError; - - Runtime.startApplication("/inspector-unit/inspector-unit-test").then(runTest); - - function runTest() - { - var description = document.body.textContent.trim(); - if (description) - UnitTest.addResult(description); - - Common.settings = new Common.Settings(new Common.SettingsStorage( - {}, - InspectorFrontendHost.setPreference, - InspectorFrontendHost.removePreference, - InspectorFrontendHost.clearPreferences)); - - - UI.viewManager = new UI.ViewManager(); - UI.initializeUIUtils(document, Common.settings.createSetting("uiTheme", "default")); - UI.installComponentRootStyles(document.body); - - UI.zoomManager = new UI.ZoomManager(window, InspectorFrontendHost); - UI.inspectorView = UI.InspectorView.instance(); - UI.ContextMenu.initialize(); - UI.ContextMenu.installHandler(document); - UI.Tooltip.installHandler(document); - - var rootView = new UI.RootView(); - UI.inspectorView.show(rootView.element); - rootView.attachToDocument(document); - Promise.all(lazyModules.map(lazyModule => window.runtime.loadModulePromise(lazyModule))).then(test); - } -})(); -
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/inspector-unit-test.json b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/inspector-unit-test.json deleted file mode 100644 index a5a7695..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/inspector-unit-test.json +++ /dev/null
@@ -1,16 +0,0 @@ -{ - "modules" : [ - { "name": "platform", "type": "autostart" }, - { "name": "ui", "type": "autostart" }, - { "name": "host", "type": "autostart" }, - { "name": "common", "type": "autostart" }, - { "name": "workspace", "type": "autostart" }, - { "name": "source_frame", "type": "autostart" }, - { "name": "text_editor", "type": "autostart" }, - { "name": "cm_modes", "type": "autostart" }, - { "name": "diff", "type": "autostart" }, - { "name": "ui_lazy" } - ], - - "has_html": true -}
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.html b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.html deleted file mode 100644 index 493b6805..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.html +++ /dev/null
@@ -1,62 +0,0 @@ -<html> -<head> -<base href="/inspector-debug/"></base> -<script src="/inspector-debug/Runtime.js"></script> -<script src="/inspector-unit/inspector-unit-test.js"></script> -<script> -function test() { - var items = []; - var heights = []; - for (var i = 0; i < 100; i++){ - items[i] = document.createElement("div"); - items[i].style.height = (heights[i] = (i % 4) ? 50 : 28) + "px"; - items[i].textContent = i; - } - var viewport = new UI.StaticViewportControl({ - fastItemHeight: i => heights[i], - itemCount: _ => items.length, - itemElement: i => items[i] - }); - viewport.element.style.height = "300px"; - UI.inspectorView.element.appendChild(viewport.element); - - viewport.refresh(); - dumpViewport(); - - viewport.forceScrollItemToBeFirst(26); - dumpViewport(); - - viewport.scrollItemIntoView(33); - dumpViewport(); - - viewport.scrollItemIntoView(30); - dumpViewport(); - - viewport.forceScrollItemToBeFirst(30); - dumpViewport(); - - viewport.forceScrollItemToBeLast(88); - dumpViewport(); - - for (var i = 0; i < 100; i++) - items[i].style.height = (heights[i] = (i % 2) ? 55 : 63) + "px"; - viewport.refresh(); - viewport.forceScrollItemToBeLast(88); - dumpViewport(); - - UnitTest.completeTest(); - - function dumpViewport() - { - UnitTest.addResult("First:" + viewport.firstVisibleIndex()); - UnitTest.addResult("Last:" + viewport.lastVisibleIndex()); - UnitTest.addResult("Active Items:" + viewport._innerElement.children.length); - UnitTest.addResult(""); - } -} -</script> -</head> -<body> -This tests if the StaticViewportControl works properly. -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.js new file mode 100644 index 0000000..0b333830 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.js
@@ -0,0 +1,50 @@ +TestRunner.addResult("This tests if the StaticViewportControl works properly."); + +var items = []; +var heights = []; +for (var i = 0; i < 100; i++){ + items[i] = document.createElement("div"); + items[i].style.height = (heights[i] = (i % 4) ? 50 : 28) + "px"; + items[i].textContent = i; +} +var viewport = new UI.StaticViewportControl({ + fastItemHeight: i => heights[i], + itemCount: _ => items.length, + itemElement: i => items[i] +}); +viewport.element.style.height = "300px"; +UI.inspectorView.element.appendChild(viewport.element); + +viewport.refresh(); +dumpViewport(); + +viewport.forceScrollItemToBeFirst(26); +dumpViewport(); + +viewport.scrollItemIntoView(33); +dumpViewport(); + +viewport.scrollItemIntoView(30); +dumpViewport(); + +viewport.forceScrollItemToBeFirst(30); +dumpViewport(); + +viewport.forceScrollItemToBeLast(88); +dumpViewport(); + +for (var i = 0; i < 100; i++) + items[i].style.height = (heights[i] = (i % 2) ? 55 : 63) + "px"; +viewport.refresh(); +viewport.forceScrollItemToBeLast(88); +dumpViewport(); + +TestRunner.completeTest(); + +function dumpViewport() +{ + TestRunner.addResult("First:" + viewport.firstVisibleIndex()); + TestRunner.addResult("Last:" + viewport.lastVisibleIndex()); + TestRunner.addResult("Active Items:" + viewport._innerElement.children.length); + TestRunner.addResult(""); +} \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/suggest-box.html b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/suggest-box.html deleted file mode 100644 index 590cdb5..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/suggest-box.html +++ /dev/null
@@ -1,67 +0,0 @@ -<html> -<head> -<base href="/inspector-debug/"></base> -<script src="/inspector-debug/Runtime.js"></script> -<script src="/inspector-unit/inspector-unit-test.js"></script> -<script> -function test() { - var delegate = { - applySuggestion: function(suggestion, isIntermediateSuggestion) { - UnitTest.addResult((isIntermediateSuggestion ? "Intermediate " : "") + "Suggestion Applied: " + suggestion); - }, - acceptSuggestion: function() { - UnitTest.addResult("Suggestion accepted"); - } - }; - var div = document.createElement("div"); - UI.inspectorView.element.appendChild(div); - var suggestBox = new UI.SuggestBox(delegate); - - UnitTest.addResult(""); - UnitTest.addResult("Testing that the first item is selected."); - suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ - {title: "First"}, - {title: "Hello"}, - {title: "The best suggestion"}], true, true, "e"); - - UnitTest.addResult(""); - UnitTest.addResult("Testing that no item is selected."); - suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ - {title: "First"}, - {title: "Hello", priority: 2}, - {title: "The best suggestion", priority: 5}], false, true, "e"); - - UnitTest.addResult(""); - UnitTest.addResult("Testing that highest priority item is selected."); - suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ - {title: "First"}, - {title: "Hello", priority: 2}, - {title: "The best suggestion", priority: 5}], true, true, "e"); - - UnitTest.addResult(""); - UnitTest.addResult("Testing that arrow keys can be used for selection."); - suggestBox.keyPressed(UnitTest.createKeyEvent("ArrowUp")); - suggestBox.keyPressed(UnitTest.createKeyEvent("ArrowUp")); - suggestBox.keyPressed(UnitTest.createKeyEvent("ArrowUp")); - suggestBox.keyPressed(UnitTest.createKeyEvent("ArrowDown")); - suggestBox.keyPressed(UnitTest.createKeyEvent("ArrowDown")); - - UnitTest.addResult(""); - UnitTest.addResult("Testing that enter can be used to accept a suggestion."); - suggestBox.keyPressed(UnitTest.createKeyEvent("Enter")); - - UnitTest.addResult(""); - UnitTest.addResult("Testing that highest priority item is selected."); - suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ - {title: "First"}, - {title: "Hello", priority: 2}, - {title: "The best suggestion", priority: 5}], true, true, "e"); - - UnitTest.completeTest(); -} -</script> -</head> -<body> -This tests if the SuggestBox works properly. -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/suggest-box.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/suggest-box.js new file mode 100644 index 0000000..0e784ca --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/suggest-box.js
@@ -0,0 +1,55 @@ +TestRunner.addResult("This tests if the SuggestBox works properly."); + +var delegate = { + applySuggestion: function(suggestion, isIntermediateSuggestion) { + TestRunner.addResult((isIntermediateSuggestion ? "Intermediate " : "") + "Suggestion Applied: " + suggestion); + }, + acceptSuggestion: function() { + TestRunner.addResult("Suggestion accepted"); + } +}; +var div = document.createElement("div"); +UI.inspectorView.element.appendChild(div); +var suggestBox = new UI.SuggestBox(delegate); + +TestRunner.addResult(""); +TestRunner.addResult("Testing that the first item is selected."); +suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ + {title: "First"}, + {title: "Hello"}, + {title: "The best suggestion"}], true, true, "e"); + +TestRunner.addResult(""); +TestRunner.addResult("Testing that no item is selected."); +suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ + {title: "First"}, + {title: "Hello", priority: 2}, + {title: "The best suggestion", priority: 5}], false, true, "e"); + +TestRunner.addResult(""); +TestRunner.addResult("Testing that highest priority item is selected."); +suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ + {title: "First"}, + {title: "Hello", priority: 2}, + {title: "The best suggestion", priority: 5}], true, true, "e"); + +TestRunner.addResult(""); +TestRunner.addResult("Testing that arrow keys can be used for selection."); +suggestBox.keyPressed(TestRunner.createKeyEvent("ArrowUp")); +suggestBox.keyPressed(TestRunner.createKeyEvent("ArrowUp")); +suggestBox.keyPressed(TestRunner.createKeyEvent("ArrowUp")); +suggestBox.keyPressed(TestRunner.createKeyEvent("ArrowDown")); +suggestBox.keyPressed(TestRunner.createKeyEvent("ArrowDown")); + +TestRunner.addResult(""); +TestRunner.addResult("Testing that enter can be used to accept a suggestion."); +suggestBox.keyPressed(TestRunner.createKeyEvent("Enter")); + +TestRunner.addResult(""); +TestRunner.addResult("Testing that highest priority item is selected."); +suggestBox.updateSuggestions(new AnchorBox(50, 50, 400, 400), [ + {title: "First"}, + {title: "Hello", priority: 2}, + {title: "The best suggestion", priority: 5}], true, true, "e"); + +TestRunner.completeTest(); \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/test-failure.html b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/test-failure.html deleted file mode 100644 index 1a0bc248..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/test-failure.html +++ /dev/null
@@ -1,16 +0,0 @@ -<html> -<head> -<base href="/inspector-debug/"></base> -<script src="/inspector-debug/Runtime.js"></script> -<script src="/inspector-unit/inspector-unit-test.js"></script> -<script> -function test() -{ - setTimeout(_ => { throw {stack: "This error is expected"} }, 0); -} -</script> -</head> -<body> -Tests that a test will properly exit if it has an asynchronous error. -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/test-failure.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/test-failure.js new file mode 100644 index 0000000..7db1257 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/test-failure.js
@@ -0,0 +1,2 @@ +TestRunner.addResult("Tests that a test will properly exit if it has an asynchronous error."); +setTimeout(_ => { throw {stack: "This error is expected"} }, 0); \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint.html b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint.html deleted file mode 100644 index ac8a2c1..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint.html +++ /dev/null
@@ -1,124 +0,0 @@ -<html> -<head> -<base href="/inspector-debug/"></base> -<script src="/inspector-debug/Runtime.js"></script> -<script src="/inspector-unit/inspector-unit-test.js"></script> -<script type="text/javascript"> - -function test() -{ - var suggestions = [{title:"testTextPrompt"}]; - var waitingForAutocomplete = null; - var completionsDone = function () { - console.error("completionsDone called too early!"); - UnitTest.completeTest(); - } - var prompt = new UI.TextPrompt(); - prompt.initialize(completions); - var element = createElement("div"); - UI.inspectorView.element.appendChild(element); - var proxy = prompt.attachAndStartEditing(element); - prompt.setText("testT"); - waitForAutocomplete().then(step1); - prompt.complete(); - dumpTextPrompt(); - - function step1() { - dumpTextPrompt(); - - typeCharacter("e"); - dumpTextPrompt(); - - waitForAutocomplete().then(step2); - } - function step2() - { - dumpTextPrompt(); - - typeCharacter("z"); - waitForAutocomplete().then(step3); - } - - function step3() - { - dumpTextPrompt(); - typeCharacter(null); - waitForAutocomplete().then(step4); - } - - function step4() - { - dumpTextPrompt(); - typeCharacter(null); - waitForAutocomplete().then(step5); - } - function step5() - { - dumpTextPrompt(); - prompt.setText("something_before test"); - prompt.complete(); - completionsDone().then(()=>{ - dumpTextPrompt(); - typeCharacter("T"); - dumpTextPrompt(); - UnitTest.completeTest(); - }); - } - - function completions(expression, query) - { - var callback; - var promise = new Promise(x => callback = x); - UnitTest.addResult("Requesting completions"); - completionsDone = () => { - callback(suggestions.filter(s => s.title.startsWith(query.toString()))) - return Promise.resolve(); - }; - var temp = waitingForAutocomplete; - waitingForAutocomplete = null; - if (temp) - temp(); - return promise; - } - - function waitForAutocomplete() - { - return new Promise(x => waitingForAutocomplete = x).then(() => completionsDone()); - } - - function dumpTextPrompt() - { - UnitTest.addResult("Text:" + prompt.text()); - UnitTest.addResult("TextWithCurrentSuggestion:" + prompt.textWithCurrentSuggestion()); - UnitTest.addResult(""); - } - - function typeCharacter(character) - { - var keyboardEvent = new KeyboardEvent("keydown", { - key: character || "Backspace", - charCode: character ? character.charCodeAt(0) : "" - }); - element.dispatchEvent(keyboardEvent); - - var selection = element.getComponentSelection(); - var range = selection.getRangeAt(0); - var textNode = prompt._ghostTextElement.parentNode ? prompt._ghostTextElement.previousSibling : element.childTextNodes()[element.childTextNodes().length - 1]; - if (!character) - textNode.textContent = textNode.textContent.substring(0,textNode.textContent.length-1); - else - textNode.textContent += character; - range.setStart(range.startContainer, range.startContainer.textContent.length); - selection.removeAllRanges(); - selection.addRange(range); - element.dispatchEvent(new Event("input", {bubbles: true, cancelable: false})); - } -} - - -</script> -</head> -<body> -<p>Tests that the hint displays properly on a UI.TextPrompt with autocomplete.</p> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint.js new file mode 100644 index 0000000..cb309dc7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint.js
@@ -0,0 +1,108 @@ +TestRunner.addResult("Tests that the hint displays properly on a UI.TextPrompt with autocomplete."); + +var suggestions = [{title:"testTextPrompt"}]; +var waitingForAutocomplete = null; +var completionsDone = function () { + console.error("completionsDone called too early!"); + TestRunner.completeTest(); +} +var prompt = new UI.TextPrompt(); +prompt.initialize(completions); +var element = createElement("div"); +UI.inspectorView.element.appendChild(element); +var proxy = prompt.attachAndStartEditing(element); +prompt.setText("testT"); +waitForAutocomplete().then(step1); +prompt.complete(); +dumpTextPrompt(); + +function step1() { + dumpTextPrompt(); + + typeCharacter("e"); + dumpTextPrompt(); + + waitForAutocomplete().then(step2); +} +function step2() +{ + dumpTextPrompt(); + + typeCharacter("z"); + waitForAutocomplete().then(step3); +} + +function step3() +{ + dumpTextPrompt(); + typeCharacter(null); + waitForAutocomplete().then(step4); +} + +function step4() +{ + dumpTextPrompt(); + typeCharacter(null); + waitForAutocomplete().then(step5); +} +function step5() +{ + dumpTextPrompt(); + prompt.setText("something_before test"); + prompt.complete(); + completionsDone().then(()=>{ + dumpTextPrompt(); + typeCharacter("T"); + dumpTextPrompt(); + TestRunner.completeTest(); + }); +} + +function completions(expression, query) +{ + var callback; + var promise = new Promise(x => callback = x); + TestRunner.addResult("Requesting completions"); + completionsDone = () => { + callback(suggestions.filter(s => s.title.startsWith(query.toString()))) + return Promise.resolve(); + }; + var temp = waitingForAutocomplete; + waitingForAutocomplete = null; + if (temp) + temp(); + return promise; +} + +function waitForAutocomplete() +{ + return new Promise(x => waitingForAutocomplete = x).then(() => completionsDone()); +} + +function dumpTextPrompt() +{ + TestRunner.addResult("Text:" + prompt.text()); + TestRunner.addResult("TextWithCurrentSuggestion:" + prompt.textWithCurrentSuggestion()); + TestRunner.addResult(""); +} + +function typeCharacter(character) +{ + var keyboardEvent = new KeyboardEvent("keydown", { + key: character || "Backspace", + charCode: character ? character.charCodeAt(0) : "" + }); + element.dispatchEvent(keyboardEvent); + + var selection = element.getComponentSelection(); + var range = selection.getRangeAt(0); + var textNode = prompt._ghostTextElement.parentNode ? prompt._ghostTextElement.previousSibling : element.childTextNodes()[element.childTextNodes().length - 1]; + if (!character) + textNode.textContent = textNode.textContent.substring(0,textNode.textContent.length-1); + else + textNode.textContent += character; + range.setStart(range.startContainer, range.startContainer.textContent.length); + selection.removeAllRanges(); + selection.addRange(range); + element.dispatchEvent(new Event("input", {bubbles: true, cancelable: false})); +} \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt.html b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt.html deleted file mode 100644 index ef50f84..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt.html +++ /dev/null
@@ -1,38 +0,0 @@ -<html> -<head> -<base href="/inspector-debug/"></base> -<script src="/inspector-debug/Runtime.js"></script> -<script src="/inspector-unit/inspector-unit-test.js"></script> -<script> -function test() { - var suggestions = ["heyoo", "hey it's a suggestion", "hey another suggestion"].map(s => ({title: s})); - var prompt = new UI.TextPrompt(); - prompt.initialize(() => Promise.resolve(suggestions)); - var div = document.createElement("div"); - UI.inspectorView.element.appendChild(div); - prompt.attachAndStartEditing(div); - prompt.setText("hey"); - UnitTest.addSniffer(prompt, "_completionsReady").then(step2); - prompt.complete(); - function step2() { - UnitTest.addResult("Text:" + prompt.text()); - UnitTest.addResult("TextWithCurrentSuggestion:" + prompt.textWithCurrentSuggestion()); - - UnitTest.addResult("Test with inexact match:"); - prompt.clearAutocomplete(); - prompt.setText("inexactmatch"); - UnitTest.addSniffer(prompt, "_completionsReady").then(step3); - prompt.complete(); - } - function step3() { - UnitTest.addResult("Text:" + prompt.text()); - UnitTest.addResult("TextWithCurrentSuggestion:" + prompt.textWithCurrentSuggestion()); - UnitTest.completeTest(); - } -} -</script> -</head> -<body> -This tests if the TextPrompt autocomplete works properly. -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt.js new file mode 100644 index 0000000..9712fe2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt.js
@@ -0,0 +1,26 @@ +TestRunner.addResult("This tests if the TextPrompt autocomplete works properly."); + +var suggestions = ["heyoo", "hey it's a suggestion", "hey another suggestion"].map(s => ({title: s})); +var prompt = new UI.TextPrompt(); +prompt.initialize(() => Promise.resolve(suggestions)); +var div = document.createElement("div"); +UI.inspectorView.element.appendChild(div); +prompt.attachAndStartEditing(div); +prompt.setText("hey"); +TestRunner.addSniffer(prompt, "_completionsReady").then(step2); +prompt.complete(); +function step2() { + TestRunner.addResult("Text:" + prompt.text()); + TestRunner.addResult("TextWithCurrentSuggestion:" + prompt.textWithCurrentSuggestion()); + + TestRunner.addResult("Test with inexact match:"); + prompt.clearAutocomplete(); + prompt.setText("inexactmatch"); + TestRunner.addSniffer(prompt, "_completionsReady").then(step3); + prompt.complete(); +} +function step3() { + TestRunner.addResult("Text:" + prompt.text()); + TestRunner.addResult("TextWithCurrentSuggestion:" + prompt.textWithCurrentSuggestion()); + TestRunner.completeTest(); +} \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/trie.html b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/trie.html deleted file mode 100644 index c6f5582..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/trie.html +++ /dev/null
@@ -1,183 +0,0 @@ -<html> -<head> -<base href="/inspector-debug/"></base> -<script src="/inspector-debug/Runtime.js"></script> -<script src="/inspector-unit/inspector-unit-test.js"></script> -<script> -function test() { - var trie; - - UnitTest.runTests([ - function testAddWord() - { - var trie = new Common.Trie(); - addWord(trie, "hello"); - hasWord(trie, "he"); - hasWord(trie, "hello"); - hasWord(trie, "helloo"); - }, - - function testAddWords() - { - var trie = new Common.Trie(); - addWord(trie, "foo"); - addWord(trie, "bar"); - addWord(trie, "bazz"); - hasWord(trie, "f"); - hasWord(trie, "ba"); - hasWord(trie, "baz"); - hasWord(trie, "bar"); - hasWord(trie, "bazz"); - }, - - function testRemoveWord() - { - var trie = new Common.Trie(); - addWord(trie, "foo"); - removeWord(trie, "f"); - removeWord(trie, "fo"); - removeWord(trie, "fooo"); - hasWord(trie, "foo"); - removeWord(trie, "foo"); - hasWord(trie, "foo"); - }, - - function testAddAfterRemove() - { - var trie = new Common.Trie(); - addWord(trie, "foo"); - removeWord(trie, "foo"); - addWord(trie, "bar"); - hasWord(trie, "foo"); - hasWord(trie, "bar"); - }, - - function testWordOverwrite() - { - var trie = new Common.Trie(); - addWord(trie, "foo"); - addWord(trie, "foo"); - removeWord(trie, "foo"); - hasWord(trie, "foo"); - }, - - function testRemoveNonExisting() - { - var trie = new Common.Trie(); - addWord(trie, "foo"); - removeWord(trie, "bar"); - removeWord(trie, "baz"); - hasWord(trie, "foo"); - }, - - function testEmptyWord() - { - var trie = new Common.Trie(); - addWord(trie, ""); - hasWord(trie, ""); - removeWord(trie, ""); - hasWord(trie, ""); - }, - - function testAllWords() - { - var trie = new Common.Trie(); - addWord(trie, "foo"); - addWord(trie, "bar"); - addWord(trie, "bazzz"); - words(trie); - words(trie, "f"); - words(trie, "g"); - words(trie, "b"); - words(trie, "ba"); - words(trie, "bar"); - words(trie, "barz"); - words(trie, "baz"); - }, - - function testOneCharWords() - { - var trie = new Common.Trie(); - addWord(trie, "a"); - addWord(trie, "b"); - addWord(trie, "c"); - words(trie); - }, - - function testChainWords() - { - var trie = new Common.Trie(); - addWord(trie, "f"); - addWord(trie, "fo"); - addWord(trie, "foo"); - addWord(trie, "foo"); - words(trie); - }, - - function testClearTrie() - { - var trie = new Common.Trie(); - addWord(trie, "foo"); - addWord(trie, "bar"); - words(trie); - clear(trie); - words(trie); - }, - - function testLongestPrefix() - { - var trie = new Common.Trie(); - addWord(trie, "fo"); - addWord(trie, "food"); - longestPrefix(trie, "fear", false); - longestPrefix(trie, "fear", true); - longestPrefix(trie, "football", false); - longestPrefix(trie, "football", true); - longestPrefix(trie, "bar", false); - longestPrefix(trie, "bar", true); - longestPrefix(trie, "foo", false); - longestPrefix(trie, "foo", true); - }, - ]); - - function hasWord(trie, word) - { - UnitTest.addResult(`trie.has("${word}") = ${trie.has(word)}`); - } - - function addWord(trie, word) - { - UnitTest.addResult(`trie.add("${word}")`); - trie.add(word); - } - - function removeWord(trie, word) - { - UnitTest.addResult(`trie.remove("${word}") = ${trie.remove(word)}`); - } - - function words(trie, prefix) - { - var title = prefix ? `trie.words("${prefix}")` : `trie.words()`; - var words = trie.words(prefix); - var text = words.length ? `[\n ${words.join(",\n ")}\n]` : "[]"; - UnitTest.addResult(title + " = " + text); - } - - function clear(trie) - { - trie.clear(); - UnitTest.addResult("trie.clear()"); - } - - function longestPrefix(trie, word, fullWordOnly) - { - UnitTest.addResult(`trie.longestPrefix("${word}", ${fullWordOnly}) = "${trie.longestPrefix(word, fullWordOnly)}"`); - } -} -</script> -</head> -<body> -Verify "trie" functionality. -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/trie.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/trie.js new file mode 100644 index 0000000..bcc354f2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/trie.js
@@ -0,0 +1,170 @@ +var trie; +TestRunner.addResult(`Verify "trie" functionality.`); + +TestRunner.runTests([ + function testAddWord() + { + var trie = new Common.Trie(); + addWord(trie, "hello"); + hasWord(trie, "he"); + hasWord(trie, "hello"); + hasWord(trie, "helloo"); + }, + + function testAddWords() + { + var trie = new Common.Trie(); + addWord(trie, "foo"); + addWord(trie, "bar"); + addWord(trie, "bazz"); + hasWord(trie, "f"); + hasWord(trie, "ba"); + hasWord(trie, "baz"); + hasWord(trie, "bar"); + hasWord(trie, "bazz"); + }, + + function testRemoveWord() + { + var trie = new Common.Trie(); + addWord(trie, "foo"); + removeWord(trie, "f"); + removeWord(trie, "fo"); + removeWord(trie, "fooo"); + hasWord(trie, "foo"); + removeWord(trie, "foo"); + hasWord(trie, "foo"); + }, + + function testAddAfterRemove() + { + var trie = new Common.Trie(); + addWord(trie, "foo"); + removeWord(trie, "foo"); + addWord(trie, "bar"); + hasWord(trie, "foo"); + hasWord(trie, "bar"); + }, + + function testWordOverwrite() + { + var trie = new Common.Trie(); + addWord(trie, "foo"); + addWord(trie, "foo"); + removeWord(trie, "foo"); + hasWord(trie, "foo"); + }, + + function testRemoveNonExisting() + { + var trie = new Common.Trie(); + addWord(trie, "foo"); + removeWord(trie, "bar"); + removeWord(trie, "baz"); + hasWord(trie, "foo"); + }, + + function testEmptyWord() + { + var trie = new Common.Trie(); + addWord(trie, ""); + hasWord(trie, ""); + removeWord(trie, ""); + hasWord(trie, ""); + }, + + function testAllWords() + { + var trie = new Common.Trie(); + addWord(trie, "foo"); + addWord(trie, "bar"); + addWord(trie, "bazzz"); + words(trie); + words(trie, "f"); + words(trie, "g"); + words(trie, "b"); + words(trie, "ba"); + words(trie, "bar"); + words(trie, "barz"); + words(trie, "baz"); + }, + + function testOneCharWords() + { + var trie = new Common.Trie(); + addWord(trie, "a"); + addWord(trie, "b"); + addWord(trie, "c"); + words(trie); + }, + + function testChainWords() + { + var trie = new Common.Trie(); + addWord(trie, "f"); + addWord(trie, "fo"); + addWord(trie, "foo"); + addWord(trie, "foo"); + words(trie); + }, + + function testClearTrie() + { + var trie = new Common.Trie(); + addWord(trie, "foo"); + addWord(trie, "bar"); + words(trie); + clear(trie); + words(trie); + }, + + function testLongestPrefix() + { + var trie = new Common.Trie(); + addWord(trie, "fo"); + addWord(trie, "food"); + longestPrefix(trie, "fear", false); + longestPrefix(trie, "fear", true); + longestPrefix(trie, "football", false); + longestPrefix(trie, "football", true); + longestPrefix(trie, "bar", false); + longestPrefix(trie, "bar", true); + longestPrefix(trie, "foo", false); + longestPrefix(trie, "foo", true); + }, +]); + +function hasWord(trie, word) +{ + TestRunner.addResult(`trie.has("${word}") = ${trie.has(word)}`); +} + +function addWord(trie, word) +{ + TestRunner.addResult(`trie.add("${word}")`); + trie.add(word); +} + +function removeWord(trie, word) +{ + TestRunner.addResult(`trie.remove("${word}") = ${trie.remove(word)}`); +} + +function words(trie, prefix) +{ + var title = prefix ? `trie.words("${prefix}")` : `trie.words()`; + var words = trie.words(prefix); + var text = words.length ? `[\n ${words.join(",\n ")}\n]` : "[]"; + TestRunner.addResult(title + " = " + text); +} + +function clear(trie) +{ + trie.clear(); + TestRunner.addResult("trie.clear()"); +} + +function longestPrefix(trie, word, fullWordOnly) +{ + TestRunner.addResult(`trie.longestPrefix("${word}", ${fullWordOnly}) = "${trie.longestPrefix(word, fullWordOnly)}"`); +} \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/payments/payment-request-interface.html b/third_party/WebKit/LayoutTests/payments/payment-request-interface.html index 094f5e8..dcab558c 100644 --- a/third_party/WebKit/LayoutTests/payments/payment-request-interface.html +++ b/third_party/WebKit/LayoutTests/payments/payment-request-interface.html
@@ -368,51 +368,51 @@ generate_tests(assert_throws, [ // Invalid currency code formats. ['Undefined currency code should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': undefined})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': undefined}), {requestShipping: true}) }], // Invalid amount formats. ['Invalid amount "-" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-'}), {requestShipping: true}) }], ['Invalid amount "notdigits" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'notdigits'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'notdigits'}), {requestShipping: true}) }], ['Invalid amount "ALSONOTDIGITS" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'ALSONOTDIGITS'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'ALSONOTDIGITS'}), {requestShipping: true}) }], ['Invalid amount "10." should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10.'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10.'}), {requestShipping: true}) }], ['Invalid amount ".99" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '.99'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '.99'}), {requestShipping: true}) }], ['Invalid amount "-10." should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-10.'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-10.'}), {requestShipping: true}) }], ['Invalid amount "-.99" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-.99'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-.99'}), {requestShipping: true}) }], ['Invalid amount "10-" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10-'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10-'}), {requestShipping: true}) }], ['Invalid amount "1-0" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1-0'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1-0'}), {requestShipping: true}) }], ['Invalid amount "1.0.0" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1.0.0'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1.0.0'}), {requestShipping: true}) }], ['Invalid amount "1/3" should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1/3'})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1/3'}), {requestShipping: true}) }], ['Empty amount should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': ''})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': ''}), {requestShipping: true}) }], ['Null amount should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': null})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': null}), {requestShipping: true}) }], ['Undefined amount should throw', null, function() { - new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': undefined})) + new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': undefined}), {requestShipping: true}) }], ]); }
diff --git a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp index 5c8e371..f3c7d40 100644 --- a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp
@@ -33,6 +33,10 @@ #include "platform/RuntimeEnabledFeatures.h" #include "wtf/Assertions.h" +#if DCHECK_IS_ON() +#include "wtf/text/WTFString.h" +#endif + namespace blink { static DocumentLifecycle::DeprecatedTransition* s_deprecatedTransitionStack = 0; @@ -288,40 +292,12 @@ m_state == PrePaintClean || m_state == PaintClean; } -#endif - -void DocumentLifecycle::advanceTo(LifecycleState nextState) { -#if DCHECK_IS_ON() - DCHECK(canAdvanceTo(nextState)) << "Cannot advance document lifecycle from " - << stateAsDebugString(m_state) << " to " - << stateAsDebugString(nextState) << "."; -#endif - m_state = nextState; -} - -void DocumentLifecycle::ensureStateAtMost(LifecycleState state) { - DCHECK(state == VisualUpdatePending || state == StyleClean || - state == LayoutClean); - if (m_state <= state) - return; -#if DCHECK_IS_ON() - DCHECK(canRewindTo(state)) << "Cannot rewind document lifecycle from " - << stateAsDebugString(m_state) << " to " - << stateAsDebugString(state) << "."; -#endif - m_state = state; -} - -bool DocumentLifecycle::throttlingAllowed() const { - return s_allowThrottlingCount; -} - -#if DCHECK_IS_ON() #define DEBUG_STRING_CASE(StateName) \ - case StateName: \ + case DocumentLifecycle::StateName: \ return #StateName -const char* DocumentLifecycle::stateAsDebugString(const LifecycleState state) { +static WTF::String stateAsDebugString( + const DocumentLifecycle::LifecycleState& state) { switch (state) { DEBUG_STRING_CASE(Uninitialized); DEBUG_STRING_CASE(Inactive); @@ -349,6 +325,36 @@ NOTREACHED(); return "Unknown"; } + +WTF::String DocumentLifecycle::toString() const { + return stateAsDebugString(m_state); +} #endif +void DocumentLifecycle::advanceTo(LifecycleState nextState) { +#if DCHECK_IS_ON() + DCHECK(canAdvanceTo(nextState)) << "Cannot advance document lifecycle from " + << stateAsDebugString(m_state) << " to " + << stateAsDebugString(nextState) << "."; +#endif + m_state = nextState; +} + +void DocumentLifecycle::ensureStateAtMost(LifecycleState state) { + DCHECK(state == VisualUpdatePending || state == StyleClean || + state == LayoutClean); + if (m_state <= state) + return; +#if DCHECK_IS_ON() + DCHECK(canRewindTo(state)) << "Cannot rewind document lifecycle from " + << stateAsDebugString(m_state) << " to " + << stateAsDebugString(state) << "."; +#endif + m_state = state; +} + +bool DocumentLifecycle::throttlingAllowed() const { + return s_allowThrottlingCount; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/DocumentLifecycle.h b/third_party/WebKit/Source/core/dom/DocumentLifecycle.h index 8a05f66..e2ef48bb 100644 --- a/third_party/WebKit/Source/core/dom/DocumentLifecycle.h +++ b/third_party/WebKit/Source/core/dom/DocumentLifecycle.h
@@ -36,6 +36,10 @@ #include "wtf/Assertions.h" #include "wtf/Noncopyable.h" +#if DCHECK_IS_ON() +#include "wtf/Forward.h" +#endif + namespace blink { class CORE_EXPORT DocumentLifecycle { @@ -206,9 +210,11 @@ bool throttlingAllowed() const; +#if DCHECK_IS_ON() + WTF::String toString() const; +#endif private: #if DCHECK_IS_ON() - static const char* stateAsDebugString(const LifecycleState); bool canAdvanceTo(LifecycleState) const; bool canRewindTo(LifecycleState) const; #endif
diff --git a/third_party/WebKit/Source/core/frame/BUILD.gn b/third_party/WebKit/Source/core/frame/BUILD.gn index eceddee..d75dc18 100644 --- a/third_party/WebKit/Source/core/frame/BUILD.gn +++ b/third_party/WebKit/Source/core/frame/BUILD.gn
@@ -89,6 +89,8 @@ "RootFrameViewport.h", "Screen.cpp", "Screen.h", + "ScreenOrientationController.cpp", + "ScreenOrientationController.h", "Settings.cpp", "SettingsDelegate.cpp", "SettingsDelegate.h",
diff --git a/third_party/WebKit/Source/core/frame/ScreenOrientationController.cpp b/third_party/WebKit/Source/core/frame/ScreenOrientationController.cpp new file mode 100644 index 0000000..e8104123 --- /dev/null +++ b/third_party/WebKit/Source/core/frame/ScreenOrientationController.cpp
@@ -0,0 +1,32 @@ +// Copyright 2016 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 "core/frame/ScreenOrientationController.h" + +namespace blink { + +// static +ScreenOrientationController* ScreenOrientationController::from( + LocalFrame& frame) { + return static_cast<ScreenOrientationController*>( + Supplement<LocalFrame>::from(frame, supplementName())); +} + +DEFINE_TRACE(ScreenOrientationController) { + Supplement<LocalFrame>::trace(visitor); +} + +// static +void ScreenOrientationController::provideTo( + LocalFrame& frame, + ScreenOrientationController* controller) { + Supplement<LocalFrame>::provideTo(frame, supplementName(), controller); +} + +// static +const char* ScreenOrientationController::supplementName() { + return "ScreenOrientationController"; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/ScreenOrientationController.h b/third_party/WebKit/Source/core/frame/ScreenOrientationController.h new file mode 100644 index 0000000..378fd153 --- /dev/null +++ b/third_party/WebKit/Source/core/frame/ScreenOrientationController.h
@@ -0,0 +1,45 @@ +// Copyright 2016 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 ScreenOrientationController_h +#define ScreenOrientationController_h + +#include "core/CoreExport.h" +#include "core/frame/LocalFrame.h" +#include "platform/Supplementable.h" +#include "public/platform/modules/screen_orientation/WebScreenOrientationLockType.h" + +namespace blink { + +class WebLockOrientationCallback; + +// ScreenOrientationController allows to manipulate screen orientation in Blink +// outside of the screen_orientation/ modules. It is an interface that the +// module will implement and add a provider for. +// Callers of ScreenOrientationController::from() should always assume the +// returned pointer can be nullptr. +class CORE_EXPORT ScreenOrientationController : public Supplement<LocalFrame> { + public: + virtual ~ScreenOrientationController() = default; + + static ScreenOrientationController* from(LocalFrame&); + + virtual void lock(WebScreenOrientationLockType, + std::unique_ptr<WebLockOrientationCallback>) = 0; + virtual void unlock() = 0; + + DECLARE_VIRTUAL_TRACE(); + + protected: + // To be called by an ScreenOrientationController to register its + // implementation. + static void provideTo(LocalFrame&, ScreenOrientationController*); + + private: + static const char* supplementName(); +}; + +} // namespace blink + +#endif // ScreenOrientationController_h
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp index 9dc16fe..da83239 100644 --- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp +++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -175,7 +175,7 @@ bool OffscreenCanvas::isPaintable() const { if (!m_context) return ImageBuffer::canCreateImageBuffer(m_size); - return m_context->isPaintable(); + return m_context->isPaintable() && m_size.width() && m_size.height(); } bool OffscreenCanvas::isAccelerated() const {
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp index 33e635c..185a3b53 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -1101,22 +1101,6 @@ notifyGeometryChanged(); } -#if OS(MACOSX) -void ScrollingCoordinator::handleWheelEventPhase( - PlatformWheelEventPhase phase) { - DCHECK(isMainThread()); - - if (!m_page) - return; - - FrameView* frameView = m_page->deprecatedLocalMainFrame()->view(); - if (!frameView) - return; - - frameView->scrollAnimator().handleWheelEventPhase(phase); -} -#endif - bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects( FrameView* frameView) const { const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects =
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h index 3b63359..b5775ab 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
@@ -94,12 +94,6 @@ // Should be called whenever the root layer for the given frame view changes. void frameViewRootLayerDidChange(FrameView*); -#if OS(MACOSX) - // Dispatched by the scrolling tree during handleWheelEvent. This is required - // as long as scrollbars are painted on the main thread. - void handleWheelEventPhase(PlatformWheelEventPhase); -#endif - MainThreadScrollingReasons mainThreadScrollingReasons() const; bool shouldUpdateScrollLayerPositionOnMainThread() const { return mainThreadScrollingReasons() != 0;
diff --git a/third_party/WebKit/Source/devtools/.gitignore b/third_party/WebKit/Source/devtools/.gitignore index eb6f6b0..456908cd 100644 --- a/third_party/WebKit/Source/devtools/.gitignore +++ b/third_party/WebKit/Source/devtools/.gitignore
@@ -13,5 +13,6 @@ /.test_cache /release /scripts/local_node/runtimes +/front_end/protocol_externs.js /front_end/InspectorBackendCommands.js /front_end/SupportedCSSProperties.js \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn index cff1ae0..0025228 100644 --- a/third_party/WebKit/Source/devtools/BUILD.gn +++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -21,6 +21,8 @@ "front_end/heap_snapshot_worker.json", "front_end/utility_shared_worker.js", "front_end/utility_shared_worker.json", + "front_end/unit_test_runner.js", + "front_end/unit_test_runner.json", "front_end/toolbox.js", "front_end/toolbox.json", "front_end/Runtime.js", @@ -334,10 +336,12 @@ "front_end/formatter_worker/module.json", "front_end/sdk/module.json", "front_end/settings/module.json", + "front_end/shell/module.json", "front_end/source_frame/module.json", "front_end/sources/module.json", "front_end/snippets/module.json", "front_end/utility_shared_worker/module.json", + "front_end/test_runner/module.json", "front_end/text_editor/module.json", "front_end/timeline_model/module.json", "front_end/timeline/module.json", @@ -710,6 +714,8 @@ "front_end/terminal/xterm.js/build/xterm.css", "front_end/terminal/xterm.js/build/xterm.js", ] +devtools_shell_js_files = [ "front_end/shell/TestShell.js" ] +devtools_test_runner_js_files = [ "front_end/test_runner/TestRunner.js" ] devtools_timeline_model_js_files = [ "front_end/timeline_model/TracingLayerTree.js", "front_end/timeline_model/TimelineFrameModel.js", @@ -888,9 +894,10 @@ devtools_resources_js_files + devtools_sass_js_files + devtools_security_js_files + devtools_screencast_js_files + devtools_formatter_worker_js_files + devtools_settings_js_files + - devtools_services_js_files + devtools_snippets_js_files + - devtools_source_frame_js_files + devtools_sources_js_files + - devtools_utility_shared_worker_js_files + devtools_text_editor_js_files + + devtools_services_js_files + devtools_shell_js_files + + devtools_snippets_js_files + devtools_source_frame_js_files + + devtools_sources_js_files + devtools_utility_shared_worker_js_files + + devtools_text_editor_js_files + devtools_test_runner_js_files + devtools_terminal_js_files + devtools_timeline_model_js_files + devtools_timeline_js_files + devtools_ui_lazy_js_files + devtools_layer_viewer_js_files + devtools_worker_service_js_files @@ -911,6 +918,8 @@ "$resources_out_dir/inspector.js", "$resources_out_dir/toolbox.html", "$resources_out_dir/toolbox.js", + "$resources_out_dir/unit_test_runner.html", + "$resources_out_dir/unit_test_runner.js", ] generated_workers = [ @@ -957,6 +966,7 @@ devtools_applications = [ "inspector", "toolbox", + "unit_test_runner", "formatter_worker", "heap_snapshot_worker", "utility_shared_worker", @@ -1103,6 +1113,7 @@ inputs = helper_scripts + all_devtools_files + generated_scripts + [ "front_end/inspector.html", "front_end/toolbox.html", + "front_end/unit_test_runner.html", ] outputs = generated_entry_files + generated_workers + @@ -1129,11 +1140,13 @@ inputs = all_devtools_files + [ "front_end/inspector.html", "front_end/toolbox.html", + "front_end/unit_test_runner.html", ] outputs = [ "$resources_out_debug_dir/inspector.html", "$resources_out_debug_dir/toolbox.html", + "$resources_out_debug_dir/unit_test_runner.html", ] args = devtools_applications + [
diff --git a/third_party/WebKit/Source/devtools/PRESUBMIT.py b/third_party/WebKit/Source/devtools/PRESUBMIT.py index c7ebd1a7..bd9c111 100644 --- a/third_party/WebKit/Source/devtools/PRESUBMIT.py +++ b/third_party/WebKit/Source/devtools/PRESUBMIT.py
@@ -32,10 +32,13 @@ for more details about the presubmit API built into gcl. """ +from collections import namedtuple import sys compile_note = "Be sure to run your patch by the compile_frontend.py script prior to committing!" +CheckOutput = namedtuple('CheckOutput', ['results', 'has_errors']) + def _CheckNodeAndNPMModules(input_api, output_api): node_script_path = input_api.os_path.join(input_api.PresubmitLocalPath(), "scripts", "install_node_deps.py") @@ -45,13 +48,14 @@ stderr=input_api.subprocess.STDOUT) out, _ = process.communicate() if process.returncode != 0: - return [output_api.PresubmitError(out)] - return [output_api.PresubmitNotifyResult(out)] + return CheckOutput([output_api.PresubmitError(out)], has_errors=True) + return CheckOutput([output_api.PresubmitNotifyResult(out)], has_errors=False) + def _FormatDevtools(input_api, output_api): affected_front_end_files = _getAffectedFrontEndFiles(input_api) if len(affected_front_end_files) == 0: - return [] + return CheckOutput([], has_errors=False) original_sys_path = sys.path try: sys.path = sys.path + [input_api.os_path.join(input_api.PresubmitLocalPath(), "scripts")] @@ -66,9 +70,9 @@ args=[node_path, format_path] + [glob_arg, "--output-replacements-xml"]) check_formatting_out, _ = check_formatting_process.communicate() if check_formatting_process.returncode != 0: - return [output_api.PresubmitError(check_formatting_out)] + return CheckOutput([output_api.PresubmitError(check_formatting_out)], has_errors=True) if "</replacement>" not in check_formatting_out: - return [output_api.PresubmitNotifyResult("CL is properly formatted")] + return CheckOutput([output_api.PresubmitNotifyResult("CL is properly formatted")], has_errors=False) format_args = [node_path, format_path] + [glob_arg] format_process = _inputPopen(input_api, format_args) @@ -86,10 +90,10 @@ reformat_process = _inputPopen(input_api, format_args) reformat_process.communicate() - return [output_api.PresubmitError("ERROR: Found formatting violations.\n" + return CheckOutput([output_api.PresubmitError("ERROR: Found formatting violations.\n" "Ran clang-format on files changed in CL\n" "Use git status to check the formatting changes"), - output_api.PresubmitError(format_process_out)] + output_api.PresubmitError(format_process_out)], has_errors=True) def _CheckDevtoolsStyle(input_api, output_api): @@ -202,8 +206,19 @@ def CheckChangeOnUpload(input_api, output_api): results = [] - results.extend(_CheckNodeAndNPMModules(input_api, output_api)) - results.extend(_FormatDevtools(input_api, output_api)) + + (node_results, has_errors) = _CheckNodeAndNPMModules(input_api, output_api) + results.extend(node_results) + if has_errors: + results.append(output_api.PresubmitError("ERROR: Bailed out early because error using node.js/npm")) + return results + + (format_results, has_errors) = _FormatDevtools(input_api, output_api) + results.extend(format_results) + if has_errors: + results.append(output_api.PresubmitError("ERROR: Bailed out early because formatting errors were found")) + return results + results.extend(_CheckDevtoolsStyle(input_api, output_api)) results.extend(_CompileDevtoolsFrontend(input_api, output_api)) results.extend(_CheckConvertSVGToPNGHashes(input_api, output_api)) @@ -215,6 +230,7 @@ def CheckChangeOnCommit(input_api, output_api): return [] + def _getAffectedFrontEndFiles(input_api): local_paths = [f.AbsoluteLocalPath() for f in input_api.AffectedFiles() if f.Action() != "D"] devtools_root = input_api.PresubmitLocalPath() @@ -222,6 +238,7 @@ affected_front_end_files = [file_name for file_name in local_paths if devtools_front_end in file_name and file_name.endswith(".js")] return [input_api.os_path.relpath(file_name, devtools_root) for file_name in affected_front_end_files] + def _inputPopen(input_api, args): return input_api.subprocess.Popen( args,
diff --git a/third_party/WebKit/Source/devtools/front_end/externs.js b/third_party/WebKit/Source/devtools/front_end/externs.js index ce5dd2e..e05c8f4 100644 --- a/third_party/WebKit/Source/devtools/front_end/externs.js +++ b/third_party/WebKit/Source/devtools/front_end/externs.js
@@ -840,10 +840,12 @@ var Security = {}; var Services = {}; var Settings = {}; +var Shell = {}; var Snippets = {}; var SourceFrame = {}; var Sources = {}; var Terminal = {}; +var TestRunner = {}; var TextEditor = {}; var Timeline = {}; var TimelineModel = {};
diff --git a/third_party/WebKit/Source/devtools/front_end/shell/TestShell.js b/third_party/WebKit/Source/devtools/front_end/shell/TestShell.js new file mode 100644 index 0000000..fa84429 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/shell/TestShell.js
@@ -0,0 +1,41 @@ +// Copyright 2016 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. + +Shell.TestShell = class { + /** + * @suppressGlobalPropertiesCheck + */ + constructor() { + runOnWindowLoad(this.initializeUnitTest.bind(this)); + } + + /** + * @suppressGlobalPropertiesCheck + */ + initializeUnitTest() { + var globalStorage = new Common.SettingsStorage( + {}, InspectorFrontendHost.setPreference, InspectorFrontendHost.removePreference, + InspectorFrontendHost.clearPreferences); + var storagePrefix = ''; + var localStorage = new Common.SettingsStorage({}, undefined, undefined, undefined, storagePrefix); + Common.settings = new Common.Settings(globalStorage, localStorage); + + UI.viewManager = new UI.ViewManager(); + UI.initializeUIUtils(document, Common.settings.createSetting('uiTheme', 'default')); + UI.installComponentRootStyles(/** @type {!Element} */ (document.body)); + + UI.zoomManager = new UI.ZoomManager(self, InspectorFrontendHost); + UI.inspectorView = UI.InspectorView.instance(); + UI.ContextMenu.initialize(); + UI.ContextMenu.installHandler(document); + UI.Tooltip.installHandler(document); + + var rootView = new UI.RootView(); + UI.inspectorView.show(rootView.element); + rootView.attachToDocument(document); + TestRunner.executeTestScript(); + } +}; + +new Shell.TestShell();
diff --git a/third_party/WebKit/Source/devtools/front_end/shell/module.json b/third_party/WebKit/Source/devtools/front_end/shell/module.json new file mode 100644 index 0000000..0b2846b4 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/shell/module.json
@@ -0,0 +1,10 @@ +{ + "dependencies": [ + "common", + "test_runner", + "ui" + ], + "scripts": [ + "TestShell.js" + ] +}
diff --git a/third_party/WebKit/Source/devtools/front_end/test_runner/TestRunner.js b/third_party/WebKit/Source/devtools/front_end/test_runner/TestRunner.js new file mode 100644 index 0000000..e45f29df --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/test_runner/TestRunner.js
@@ -0,0 +1,151 @@ +// Copyright 2016 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. + +/** @type {!{notifyDone: function()}|undefined} */ +self.testRunner; + +TestRunner.executeTestScript = function() { + fetch(`${Runtime.queryParam('test')}`) + .then((data) => data.text()) + .then((testScript) => eval(`(function(){${testScript}})()`)) + .catch((error) => { + TestRunner.addResult(`Unable to execute test script because of error: ${error}`); + TestRunner.completeTest(); + }); +}; + +/** @type {!Array<string>} */ +TestRunner._results = []; + +/** + * @suppressGlobalPropertiesCheck + */ +TestRunner.completeTest = function() { + if (!self.testRunner) { + console.log('Test Done'); + return; + } + + Array.prototype.forEach.call(document.documentElement.childNodes, x => x.remove()); + var outputElement = document.createElement('div'); + // Support for svg - add to document, not body, check for style. + if (outputElement.style) { + outputElement.style.whiteSpace = 'pre'; + outputElement.style.height = '10px'; + outputElement.style.overflow = 'hidden'; + } + document.documentElement.appendChild(outputElement); + for (var i = 0; i < TestRunner._results.length; i++) { + outputElement.appendChild(document.createTextNode(TestRunner._results[i])); + outputElement.appendChild(document.createElement('br')); + } + TestRunner._results = []; + self.testRunner.notifyDone(); +}; + +/** + * @param {*} text + */ +TestRunner.addResult = function(text) { + if (self.testRunner) + TestRunner._results.push(String(text)); + else + console.log(text); +}; + +/** + * @param {!Array<function()>} tests + */ +TestRunner.runTests = function(tests) { + nextTest(); + + function nextTest() { + var test = tests.shift(); + if (!test) { + TestRunner.completeTest(); + return; + } + TestRunner.addResult('\ntest: ' + test.name); + var testPromise = test(); + if (!(testPromise instanceof Promise)) + testPromise = Promise.resolve(); + testPromise.then(nextTest); + } +}; + +/** + * @param {!Object} receiver + * @param {string} methodName + * @return {!Promise<*>} + */ +TestRunner.addSniffer = function(receiver, methodName) { + return new Promise(function(resolve, reject) { + var original = receiver[methodName]; + if (typeof original !== 'function') { + reject('Cannot find method to override: ' + methodName); + return; + } + + receiver[methodName] = function(var_args) { + try { + var result = original.apply(this, arguments); + } finally { + receiver[methodName] = original; + } + // In case of exception the override won't be called. + try { + Array.prototype.push.call(arguments, result); + resolve.apply(this, arguments); + } catch (e) { + reject('Exception in overridden method \'' + methodName + '\': ' + e); + TestRunner.completeTest(); + } + return result; + }; + }); +}; + +/** + * @param {!Array<string>} lazyModules + * @return {!Promise<!Array<undefined>>} + */ +TestRunner.loadLazyModules = function(lazyModules) { + return Promise.all(lazyModules.map(lazyModule => self.runtime.loadModulePromise(lazyModule))); +}; + +/** + * @param {string} key + * @param {boolean} ctrlKey + * @param {boolean} altKey + * @param {boolean} shiftKey + * @param {boolean} metaKey + * @return {!KeyboardEvent} + */ +TestRunner.createKeyEvent = function(key, ctrlKey, altKey, shiftKey, metaKey) { + return new KeyboardEvent('keydown', { + key: key, + bubbles: true, + cancelable: true, + ctrlKey: ctrlKey, + altKey: altKey, + shiftKey: shiftKey, + metaKey: metaKey + }); +}; + +(function() { + /** + * @param {string|!Event} message + * @param {string} source + * @param {number} lineno + * @param {number} colno + * @param {!Error} error + */ + function completeTestOnError(message, source, lineno, colno, error) { + TestRunner.addResult('TEST ENDED IN ERROR: ' + error.stack); + TestRunner.completeTest(); + } + + self['onerror'] = completeTestOnError; +})(); \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/test_runner/module.json b/third_party/WebKit/Source/devtools/front_end/test_runner/module.json new file mode 100644 index 0000000..ebd476c4 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/test_runner/module.json
@@ -0,0 +1,5 @@ +{ + "scripts": [ + "TestRunner.js" + ] +}
diff --git a/third_party/WebKit/Source/devtools/front_end/unit_test_runner.html b/third_party/WebKit/Source/devtools/front_end/unit_test_runner.html new file mode 100644 index 0000000..b4ebe421 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/unit_test_runner.html
@@ -0,0 +1,15 @@ +<!-- + * Copyright 2016 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. +--> +<!doctype html> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Security-Policy" content="object-src 'none'; script-src 'self' 'unsafe-eval' https://chrome-devtools-frontend.appspot.com"> + <script type="text/javascript" src="Runtime.js"></script> + <script type="text/javascript" src="unit_test_runner.js"></script> +</head> +<body></body> +</html>
diff --git a/third_party/WebKit/Source/devtools/front_end/unit_test_runner.js b/third_party/WebKit/Source/devtools/front_end/unit_test_runner.js new file mode 100644 index 0000000..68b2da8 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/unit_test_runner.js
@@ -0,0 +1,10 @@ +// Copyright 2016 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. + +if (self.testRunner) { + testRunner.dumpAsText(); + testRunner.waitUntilDone(); +} + +Runtime.startApplication('unit_test_runner');
diff --git a/third_party/WebKit/Source/devtools/front_end/unit_test_runner.json b/third_party/WebKit/Source/devtools/front_end/unit_test_runner.json new file mode 100644 index 0000000..7356125 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/unit_test_runner.json
@@ -0,0 +1,18 @@ +{ + "modules" : [ + { "name": "platform", "type": "autostart" }, + { "name": "ui", "type": "autostart" }, + { "name": "host", "type": "autostart" }, + { "name": "common", "type": "autostart" }, + { "name": "workspace", "type": "autostart" }, + { "name": "source_frame", "type": "autostart" }, + { "name": "text_editor", "type": "autostart" }, + { "name": "cm_modes", "type": "autostart" }, + { "name": "diff", "type": "autostart" }, + { "name": "shell", "type": "autostart" }, + { "name": "test_runner", "type": "autostart" }, + { "name": "ui_lazy" } + ], + + "has_html": true +} \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py index c94eaf6..afc5667 100755 --- a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py +++ b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
@@ -123,7 +123,14 @@ sys.__excepthook__(exctype, value, traceback) sys.excepthook = error_excepthook -application_descriptors = ['inspector.json', 'toolbox.json', 'formatter_worker.json', 'heap_snapshot_worker.json', 'utility_shared_worker.json'] +application_descriptors = [ + 'inspector.json', + 'toolbox.json', + 'unit_test_runner.json', + 'formatter_worker.json', + 'heap_snapshot_worker.json', + 'utility_shared_worker.json', +] loader = modular_build.DescriptorLoader(devtools_frontend_path) descriptors = loader.load_applications(application_descriptors) modules_by_name = descriptors.modules
diff --git a/third_party/WebKit/Source/modules/payments/PaymentDetailsModifier.idl b/third_party/WebKit/Source/modules/payments/PaymentDetailsModifier.idl index 14657ee..e58c21c 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentDetailsModifier.idl +++ b/third_party/WebKit/Source/modules/payments/PaymentDetailsModifier.idl
@@ -8,4 +8,5 @@ required sequence<DOMString> supportedMethods; PaymentItem total; sequence<PaymentItem> additionalDisplayItems; + [RuntimeEnabled=PaymentDetailsModifierData] object data; };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp index f57a1ee5..239a7a14 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -35,26 +35,20 @@ #include "public/platform/Platform.h" #include "public/platform/WebTraceLocation.h" #include "wtf/HashSet.h" +#include <stddef.h> #include <utility> using payments::mojom::blink::ActivePaymentQueryResult; using payments::mojom::blink::PaymentAddressPtr; using payments::mojom::blink::PaymentCurrencyAmount; using payments::mojom::blink::PaymentCurrencyAmountPtr; -using payments::mojom::blink::PaymentDetails; -using payments::mojom::blink::PaymentDetailsModifier; using payments::mojom::blink::PaymentDetailsModifierPtr; using payments::mojom::blink::PaymentDetailsPtr; -using payments::mojom::blink::PaymentDetailsPtr; using payments::mojom::blink::PaymentErrorReason; -using payments::mojom::blink::PaymentItem; using payments::mojom::blink::PaymentItemPtr; -using payments::mojom::blink::PaymentMethodData; using payments::mojom::blink::PaymentMethodDataPtr; -using payments::mojom::blink::PaymentOptions; using payments::mojom::blink::PaymentOptionsPtr; using payments::mojom::blink::PaymentResponsePtr; -using payments::mojom::blink::PaymentShippingOption; using payments::mojom::blink::PaymentShippingOptionPtr; using payments::mojom::blink::PaymentShippingType; @@ -76,7 +70,7 @@ template <> struct TypeConverter<PaymentItemPtr, blink::PaymentItem> { static PaymentItemPtr Convert(const blink::PaymentItem& input) { - PaymentItemPtr output = PaymentItem::New(); + PaymentItemPtr output = payments::mojom::blink::PaymentItem::New(); output->label = input.label(); output->amount = PaymentCurrencyAmount::From(input.amount()); output->pending = input.pending(); @@ -88,7 +82,8 @@ struct TypeConverter<PaymentShippingOptionPtr, blink::PaymentShippingOption> { static PaymentShippingOptionPtr Convert( const blink::PaymentShippingOption& input) { - PaymentShippingOptionPtr output = PaymentShippingOption::New(); + PaymentShippingOptionPtr output = + payments::mojom::blink::PaymentShippingOption::New(); output->id = input.id(); output->label = input.label(); output->amount = PaymentCurrencyAmount::From(input.amount()); @@ -98,65 +93,9 @@ }; template <> -struct TypeConverter<PaymentDetailsModifierPtr, blink::PaymentDetailsModifier> { - static PaymentDetailsModifierPtr Convert( - const blink::PaymentDetailsModifier& input) { - PaymentDetailsModifierPtr output = PaymentDetailsModifier::New(); - output->supported_methods = input.supportedMethods(); - - if (input.hasTotal()) - output->total = PaymentItem::From(input.total()); - - if (input.hasAdditionalDisplayItems()) { - for (size_t i = 0; i < input.additionalDisplayItems().size(); ++i) { - output->additional_display_items.append( - PaymentItem::From(input.additionalDisplayItems()[i])); - } - } - return output; - } -}; - -template <> -struct TypeConverter<PaymentDetailsPtr, blink::PaymentDetails> { - static PaymentDetailsPtr Convert(const blink::PaymentDetails& input) { - PaymentDetailsPtr output = PaymentDetails::New(); - output->total = PaymentItem::From(input.total()); - - if (input.hasDisplayItems()) { - for (size_t i = 0; i < input.displayItems().size(); ++i) { - output->display_items.append( - PaymentItem::From(input.displayItems()[i])); - } - } - - if (input.hasShippingOptions()) { - for (size_t i = 0; i < input.shippingOptions().size(); ++i) { - output->shipping_options.append( - PaymentShippingOption::From(input.shippingOptions()[i])); - } - } - - if (input.hasModifiers()) { - for (size_t i = 0; i < input.modifiers().size(); ++i) { - output->modifiers.append( - PaymentDetailsModifier::From(input.modifiers()[i])); - } - } - - if (input.hasError()) - output->error = input.error(); - else - output->error = emptyString(); - - return output; - } -}; - -template <> struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) { - PaymentOptionsPtr output = PaymentOptions::New(); + PaymentOptionsPtr output = payments::mojom::blink::PaymentOptions::New(); output->request_payer_name = input.requestPayerName(); output->request_payer_email = input.requestPayerEmail(); output->request_payer_phone = input.requestPayerPhone(); @@ -240,128 +179,67 @@ } } -void validateDisplayItems(const HeapVector<PaymentItem>& items, - ExceptionState& exceptionState) { - for (const auto& item : items) { +void validateAndConvertDisplayItems(const HeapVector<PaymentItem>& input, + Vector<PaymentItemPtr>& output, + ExceptionState& exceptionState) { + for (const PaymentItem& item : input) { validateShippingOptionOrPaymentItem(item, exceptionState); if (exceptionState.hadException()) return; + output.append(payments::mojom::blink::PaymentItem::From(item)); } } -// Returns false if |options| should be ignored, even if an exception was not -// thrown. TODO(rouslan): Clear shipping options instead of ignoring them when -// http://crbug.com/601193 is fixed. -bool validateShippingOptions(const HeapVector<PaymentShippingOption>& options, - ExceptionState& exceptionState) { +// Validates and converts |input| shipping options into |output|. Throws an +// exception if the data is not valid, except for duplicate identifiers, which +// returns an empty |output| instead of throwing an exception. There's no need +// to clear |output| when an exception is thrown, because the caller takes care +// of deleting |output|. +void validateAndConvertShippingOptions( + const HeapVector<PaymentShippingOption>& input, + Vector<PaymentShippingOptionPtr>& output, + ExceptionState& exceptionState) { HashSet<String> uniqueIds; - for (const auto& option : options) { + for (const PaymentShippingOption& option : input) { if (!option.hasId() || option.id().isEmpty()) { exceptionState.throwTypeError("ShippingOption id required"); - return false; + return; } - if (uniqueIds.contains(option.id())) - return false; + if (uniqueIds.contains(option.id())) { + // Clear |output| instead of throwing an exception. + output.clear(); + return; + } uniqueIds.add(option.id()); validateShippingOptionOrPaymentItem(option, exceptionState); if (exceptionState.hadException()) - return false; - } + return; - return true; + output.append(payments::mojom::blink::PaymentShippingOption::From(option)); + } } -void validatePaymentDetailsModifiers( - const HeapVector<PaymentDetailsModifier>& modifiers, - ExceptionState& exceptionState) { - if (modifiers.isEmpty()) { - exceptionState.throwTypeError( - "Must specify at least one payment details modifier"); +void validateAndConvertTotal(const PaymentItem& input, + PaymentItemPtr& output, + ExceptionState& exceptionState) { + validateShippingOptionOrPaymentItem(input, exceptionState); + if (exceptionState.hadException()) + return; + + if (input.amount().value()[0] == '-') { + exceptionState.throwTypeError("Total amount value should be non-negative"); return; } - for (const auto& modifier : modifiers) { - if (modifier.supportedMethods().isEmpty()) { - exceptionState.throwTypeError( - "Must specify at least one payment method identifier"); - return; - } - - if (modifier.hasTotal()) { - validateShippingOptionOrPaymentItem(modifier.total(), exceptionState); - if (exceptionState.hadException()) - return; - - if (modifier.total().amount().value()[0] == '-') { - exceptionState.throwTypeError( - "Total amount value should be non-negative"); - return; - } - } - - if (modifier.hasAdditionalDisplayItems()) { - validateDisplayItems(modifier.additionalDisplayItems(), exceptionState); - if (exceptionState.hadException()) - return; - } - } + output = payments::mojom::blink::PaymentItem::From(input); } -// Returns false if the shipping options should be ignored without throwing an -// exception. -bool validatePaymentDetails(const PaymentDetails& details, - ExceptionState& exceptionState) { - bool keepShippingOptions = true; - if (!details.hasTotal()) { - exceptionState.throwTypeError("Must specify total"); - return keepShippingOptions; - } - - validateShippingOptionOrPaymentItem(details.total(), exceptionState); - if (exceptionState.hadException()) - return keepShippingOptions; - - if (details.total().amount().value()[0] == '-') { - exceptionState.throwTypeError("Total amount value should be non-negative"); - return keepShippingOptions; - } - - if (details.hasDisplayItems()) { - validateDisplayItems(details.displayItems(), exceptionState); - if (exceptionState.hadException()) - return keepShippingOptions; - } - - if (details.hasShippingOptions()) { - keepShippingOptions = - validateShippingOptions(details.shippingOptions(), exceptionState); - - if (exceptionState.hadException()) - return keepShippingOptions; - } - - if (details.hasModifiers()) { - validatePaymentDetailsModifiers(details.modifiers(), exceptionState); - if (exceptionState.hadException()) - return keepShippingOptions; - } - - String errorMessage; - if (!PaymentsValidators::isValidErrorMsgFormat(details.error(), - &errorMessage)) { - exceptionState.throwTypeError(errorMessage); - } - - return keepShippingOptions; -} - -void maybeSetAndroidPayMethodData( - const ScriptValue& input, - payments::mojom::blink::PaymentMethodDataPtr& output, - ExceptionState& exceptionState) { +void maybeSetAndroidPayMethodData(const ScriptValue& input, + PaymentMethodDataPtr& output, + ExceptionState& exceptionState) { AndroidPayMethodData androidPay; DummyExceptionStateForTesting dummyExceptionState; V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay, @@ -376,19 +254,14 @@ output->merchant_id = androidPay.merchantId(); if (androidPay.hasAllowedCardNetworks()) { - output->allowed_card_networks.resize( - androidPay.allowedCardNetworks().size()); - size_t numberOfNetworks = 0; - for (size_t i = 0; i < androidPay.allowedCardNetworks().size(); ++i) { - for (size_t j = 0; j < arraysize(kAndroidPayNetwork); ++j) { - if (androidPay.allowedCardNetworks()[i] == kAndroidPayNetwork[j].name) { - output->allowed_card_networks[numberOfNetworks++] = - kAndroidPayNetwork[j].code; + for (const String& allowedCardNetwork : androidPay.allowedCardNetworks()) { + for (size_t i = 0; i < arraysize(kAndroidPayNetwork); ++i) { + if (allowedCardNetwork == kAndroidPayNetwork[i].name) { + output->allowed_card_networks.append(kAndroidPayNetwork[i].code); break; } } } - output->allowed_card_networks.resize(numberOfNetworks); } if (androidPay.hasPaymentMethodTokenizationParameters()) { @@ -397,10 +270,10 @@ output->tokenization_type = payments::mojom::blink::AndroidPayTokenization::UNSPECIFIED; if (tokenization.hasTokenizationType()) { - for (size_t j = 0; j < arraysize(kAndroidPayTokenization); ++j) { + for (size_t i = 0; i < arraysize(kAndroidPayTokenization); ++i) { if (tokenization.tokenizationType() == - kAndroidPayTokenization[j].name) { - output->tokenization_type = kAndroidPayTokenization[j].code; + kAndroidPayTokenization[i].name) { + output->tokenization_type = kAndroidPayTokenization[i].code; break; } } @@ -411,23 +284,147 @@ tokenization.parameters().getPropertyNames(exceptionState); if (exceptionState.hadException()) return; - output->parameters.resize(keys.size()); - size_t numberOfParameters = 0; String value; - for (size_t i = 0; i < keys.size(); ++i) { - if (!DictionaryHelper::get(tokenization.parameters(), keys[i], value)) + for (const String& key : keys) { + if (!DictionaryHelper::get(tokenization.parameters(), key, value)) continue; - output->parameters[numberOfParameters] = - payments::mojom::blink::AndroidPayTokenizationParameter::New(); - output->parameters[numberOfParameters]->key = keys[i]; - output->parameters[numberOfParameters]->value = value; - ++numberOfParameters; + output->parameters.append( + payments::mojom::blink::AndroidPayTokenizationParameter::New()); + output->parameters.back()->key = key; + output->parameters.back()->value = value; } - output->parameters.resize(numberOfParameters); } } } +void stringifyAndParseMethodSpecificData(const ScriptValue& input, + PaymentMethodDataPtr& output, + ExceptionState& exceptionState) { + DCHECK(!input.isEmpty()); + if (!input.v8Value()->IsObject() || input.v8Value()->IsArray()) { + exceptionState.throwTypeError("Data should be a JSON-serializable object"); + return; + } + + v8::Local<v8::String> value; + if (!v8::JSON::Stringify(input.context(), input.v8Value().As<v8::Object>()) + .ToLocal(&value)) { + exceptionState.throwTypeError( + "Unable to parse payment method specific data"); + return; + } + + output->stringified_data = + v8StringToWebCoreString<String>(value, DoNotExternalize); + maybeSetAndroidPayMethodData(input, output, exceptionState); +} + +void validateAndConvertPaymentDetailsModifiers( + const HeapVector<PaymentDetailsModifier>& input, + Vector<PaymentDetailsModifierPtr>& output, + ExceptionState& exceptionState) { + if (input.isEmpty()) { + exceptionState.throwTypeError( + "Must specify at least one payment details modifier"); + return; + } + + for (const PaymentDetailsModifier& modifier : input) { + output.append(payments::mojom::blink::PaymentDetailsModifier::New()); + if (modifier.hasTotal()) { + validateAndConvertTotal(modifier.total(), output.back()->total, + exceptionState); + if (exceptionState.hadException()) + return; + } + + if (modifier.hasAdditionalDisplayItems()) { + validateAndConvertDisplayItems(modifier.additionalDisplayItems(), + output.back()->additional_display_items, + exceptionState); + if (exceptionState.hadException()) + return; + } + + if (modifier.supportedMethods().isEmpty()) { + exceptionState.throwTypeError( + "Must specify at least one payment method identifier"); + return; + } + + output.back()->method_data = + payments::mojom::blink::PaymentMethodData::New(); + output.back()->method_data->supported_methods = modifier.supportedMethods(); + + if (modifier.hasData() && !modifier.data().isEmpty()) { + stringifyAndParseMethodSpecificData( + modifier.data(), output.back()->method_data, exceptionState); + } else { + output.back()->method_data->stringified_data = ""; + } + } +} + +String getSelectedShippingOption( + const Vector<PaymentShippingOptionPtr>& shippingOptions) { + String result; + for (const PaymentShippingOptionPtr& shippingOption : shippingOptions) { + if (shippingOption->selected) + result = shippingOption->id; + } + return result; +} + +void validateAndConvertPaymentDetails(const PaymentDetails& input, + bool requestShipping, + PaymentDetailsPtr& output, + String& shippingOptionOutput, + ExceptionState& exceptionState) { + if (!input.hasTotal()) { + exceptionState.throwTypeError("Must specify total"); + return; + } + + validateAndConvertTotal(input.total(), output->total, exceptionState); + if (exceptionState.hadException()) + return; + + if (input.hasDisplayItems()) { + validateAndConvertDisplayItems(input.displayItems(), output->display_items, + exceptionState); + if (exceptionState.hadException()) + return; + } + + if (input.hasShippingOptions() && requestShipping) { + validateAndConvertShippingOptions(input.shippingOptions(), + output->shipping_options, exceptionState); + if (exceptionState.hadException()) + return; + } + + shippingOptionOutput = getSelectedShippingOption(output->shipping_options); + + if (input.hasModifiers()) { + validateAndConvertPaymentDetailsModifiers( + input.modifiers(), output->modifiers, exceptionState); + if (exceptionState.hadException()) + return; + } + + if (input.hasError() && !input.error().isNull()) { + String errorMessage; + if (!PaymentsValidators::isValidErrorMsgFormat(input.error(), + &errorMessage)) { + exceptionState.throwTypeError(errorMessage); + return; + } + output->error = input.error(); + } else { + output->error = ""; + } +} + void validateAndConvertPaymentMethodData( const HeapVector<PaymentMethodData>& input, Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, @@ -438,81 +435,36 @@ return; } - output.resize(input.size()); - for (size_t i = 0; i < input.size(); ++i) { - const auto& paymentMethodData = input[i]; + for (const PaymentMethodData paymentMethodData : input) { if (paymentMethodData.supportedMethods().isEmpty()) { exceptionState.throwTypeError( "Must specify at least one payment method identifier"); return; } - String stringifiedData = ""; + output.append(payments::mojom::blink::PaymentMethodData::New()); + output.back()->supported_methods = paymentMethodData.supportedMethods(); + if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) { - if (!paymentMethodData.data().v8Value()->IsObject() || - paymentMethodData.data().v8Value()->IsArray()) { - exceptionState.throwTypeError( - "Data should be a JSON-serializable object"); - return; - } - - v8::Local<v8::String> value; - if (!v8::JSON::Stringify( - paymentMethodData.data().context(), - paymentMethodData.data().v8Value().As<v8::Object>()) - .ToLocal(&value)) { - exceptionState.throwTypeError( - "Unable to parse payment method specific data"); - return; - } - stringifiedData = - v8StringToWebCoreString<String>(value, DoNotExternalize); - } - - output[i] = payments::mojom::blink::PaymentMethodData::New(); - output[i]->supported_methods = paymentMethodData.supportedMethods(); - output[i]->stringified_data = stringifiedData; - maybeSetAndroidPayMethodData(paymentMethodData.data(), output[i], - exceptionState); - if (exceptionState.hadException()) - return; - } -} - -String getSelectedShippingOption(const PaymentDetails& details) { - String result; - if (!details.hasShippingOptions()) - return result; - - for (int i = details.shippingOptions().size() - 1; i >= 0; --i) { - if (details.shippingOptions()[i].hasSelected() && - details.shippingOptions()[i].selected()) { - return details.shippingOptions()[i].id(); + stringifyAndParseMethodSpecificData(paymentMethodData.data(), + output.back(), exceptionState); + } else { + output.back()->stringified_data = ""; } } - - return result; } String getValidShippingType(const String& shippingType) { static const char* const validValues[] = { "shipping", "delivery", "pickup", }; - for (size_t i = 0; i < WTF_ARRAY_LENGTH(validValues); i++) { + for (size_t i = 0; i < arraysize(validValues); i++) { if (shippingType == validValues[i]) return shippingType; } return validValues[0]; } -PaymentDetailsPtr maybeKeepShippingOptions(PaymentDetailsPtr details, - bool keep) { - if (!keep) - details->shipping_options.resize(0); - - return details; -} - bool allowedToUsePaymentRequest(const Frame* frame) { // To determine whether a Document object |document| is allowed to use the // feature indicated by attribute name |allowpaymentrequest|, run these steps: @@ -672,7 +624,11 @@ return; } - bool keepShippingOptions = validatePaymentDetails(details, exceptionState); + PaymentDetailsPtr validatedDetails = + payments::mojom::blink::PaymentDetails::New(); + validateAndConvertPaymentDetails(details, m_options.requestShipping(), + validatedDetails, m_shippingOption, + exceptionState); if (exceptionState.hadException()) { m_showResolver->reject( DOMException::create(SyntaxError, exceptionState.message())); @@ -680,16 +636,7 @@ return; } - if (m_options.requestShipping()) { - if (keepShippingOptions) - m_shippingOption = getSelectedShippingOption(details); - else - m_shippingOption = String(); - } - - m_paymentProvider->UpdateWith(maybeKeepShippingOptions( - payments::mojom::blink::PaymentDetails::From(details), - keepShippingOptions)); + m_paymentProvider->UpdateWith(std::move(validatedDetails)); } void PaymentRequest::onUpdatePaymentDetailsFailure(const String& error) { @@ -746,7 +693,11 @@ return; } - bool keepShippingOptions = validatePaymentDetails(details, exceptionState); + PaymentDetailsPtr validatedDetails = + payments::mojom::blink::PaymentDetails::New(); + validateAndConvertPaymentDetails(details, m_options.requestShipping(), + validatedDetails, m_shippingOption, + exceptionState); if (exceptionState.hadException()) return; @@ -755,11 +706,8 @@ return; } - if (m_options.requestShipping()) { - if (keepShippingOptions) - m_shippingOption = getSelectedShippingOption(details); + if (m_options.requestShipping()) m_shippingType = getValidShippingType(m_options.shippingType()); - } scriptState->domWindow()->frame()->interfaceProvider()->getInterface( mojo::GetProxy(&m_paymentProvider)); @@ -768,10 +716,7 @@ PaymentErrorReason::UNKNOWN))); m_paymentProvider->Init( m_clientBinding.CreateInterfacePtrAndBind(), - std::move(validatedMethodData), - maybeKeepShippingOptions( - payments::mojom::blink::PaymentDetails::From(details), - keepShippingOptions && m_options.requestShipping()), + std::move(validatedMethodData), std::move(validatedDetails), payments::mojom::blink::PaymentOptions::From(m_options)); } @@ -813,8 +758,7 @@ ALLOW_UNUSED_LOCAL(success); } -void PaymentRequest::OnPaymentResponse( - payments::mojom::blink::PaymentResponsePtr response) { +void PaymentRequest::OnPaymentResponse(PaymentResponsePtr response) { DCHECK(m_showResolver); DCHECK(!m_completeResolver); DCHECK(!m_completeTimer.isActive());
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp index 988948e..374e6b77 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp
@@ -10,6 +10,7 @@ #include "core/dom/Document.h" #include "core/dom/ExceptionCode.h" #include "modules/payments/PaymentDetails.h" +#include "modules/payments/PaymentOptions.h" #include "modules/payments/PaymentTestHelper.h" #include "testing/gtest/include/gtest/gtest.h" #include <ostream> // NOLINT @@ -129,9 +130,11 @@ V8TestingScope scope; scope.document().setSecurityOrigin( SecurityOrigin::create(KURL(KURL(), "https://www.example.com/"))); - PaymentRequest::create(scope.getScriptState(), - buildPaymentMethodDataForTest(), - GetParam().buildDetails(), scope.getExceptionState()); + PaymentOptions options; + options.setRequestShipping(true); + PaymentRequest::create( + scope.getScriptState(), buildPaymentMethodDataForTest(), + GetParam().buildDetails(), options, scope.getExceptionState()); EXPECT_EQ(GetParam().expectException(), scope.getExceptionState().hadException());
diff --git a/third_party/WebKit/Source/modules/screen_orientation/BUILD.gn b/third_party/WebKit/Source/modules/screen_orientation/BUILD.gn index e06285b3..863fe41 100644 --- a/third_party/WebKit/Source/modules/screen_orientation/BUILD.gn +++ b/third_party/WebKit/Source/modules/screen_orientation/BUILD.gn
@@ -10,8 +10,8 @@ "LockOrientationCallback.h", "ScreenOrientation.cpp", "ScreenOrientation.h", - "ScreenOrientationController.cpp", - "ScreenOrientationController.h", + "ScreenOrientationControllerImpl.cpp", + "ScreenOrientationControllerImpl.h", "ScreenOrientationDispatcher.cpp", "ScreenOrientationDispatcher.h", "ScreenScreenOrientation.cpp",
diff --git a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp index aa75279..937f9dbf 100644 --- a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp +++ b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.cpp
@@ -12,7 +12,7 @@ #include "core/frame/LocalFrame.h" #include "modules/EventTargetModules.h" #include "modules/screen_orientation/LockOrientationCallback.h" -#include "modules/screen_orientation/ScreenOrientationController.h" +#include "modules/screen_orientation/ScreenOrientationControllerImpl.h" #include "public/platform/modules/screen_orientation/WebScreenOrientationType.h" // This code assumes that WebScreenOrientationType values are included in @@ -98,7 +98,7 @@ // Check if the ScreenOrientationController is supported for the // frame. It will not be for all LocalFrames, or the frame may // have been detached. - if (!ScreenOrientationController::from(*frame)) + if (!ScreenOrientationControllerImpl::from(*frame)) return nullptr; ScreenOrientation* orientation = new ScreenOrientation(frame); @@ -182,11 +182,11 @@ controller()->unlock(); } -ScreenOrientationController* ScreenOrientation::controller() { +ScreenOrientationControllerImpl* ScreenOrientation::controller() { if (!frame()) return 0; - return ScreenOrientationController::from(*frame()); + return ScreenOrientationControllerImpl::from(*frame()); } DEFINE_TRACE(ScreenOrientation) {
diff --git a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.h b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.h index 3fe30b7..9d24694 100644 --- a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.h +++ b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientation.h
@@ -19,7 +19,7 @@ class LocalFrame; class ScriptPromise; class ScriptState; -class ScreenOrientationController; +class ScreenOrientationControllerImpl; class ScreenOrientation final : public EventTargetWithInlineData, public DOMWindowProperty { @@ -54,7 +54,7 @@ private: explicit ScreenOrientation(LocalFrame*); - ScreenOrientationController* controller(); + ScreenOrientationControllerImpl* controller(); WebScreenOrientationType m_type; unsigned short m_angle;
diff --git a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationController.cpp b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp similarity index 75% rename from third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationController.cpp rename to third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp index af8642e..342b15f 100644 --- a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationController.cpp +++ b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "modules/screen_orientation/ScreenOrientationController.h" +#include "modules/screen_orientation/ScreenOrientationControllerImpl.h" #include "core/events/Event.h" #include "core/frame/FrameHost.h" @@ -21,23 +21,22 @@ namespace blink { -ScreenOrientationController::~ScreenOrientationController() {} +ScreenOrientationControllerImpl::~ScreenOrientationControllerImpl() = default; -void ScreenOrientationController::provideTo( +void ScreenOrientationControllerImpl::provideTo( LocalFrame& frame, WebScreenOrientationClient* client) { - ScreenOrientationController* controller = - new ScreenOrientationController(frame, client); - Supplement<LocalFrame>::provideTo(frame, supplementName(), controller); + ScreenOrientationController::provideTo( + frame, new ScreenOrientationControllerImpl(frame, client)); } -ScreenOrientationController* ScreenOrientationController::from( +ScreenOrientationControllerImpl* ScreenOrientationControllerImpl::from( LocalFrame& frame) { - return static_cast<ScreenOrientationController*>( - Supplement<LocalFrame>::from(frame, supplementName())); + return static_cast<ScreenOrientationControllerImpl*>( + ScreenOrientationController::from(frame)); } -ScreenOrientationController::ScreenOrientationController( +ScreenOrientationControllerImpl::ScreenOrientationControllerImpl( LocalFrame& frame, WebScreenOrientationClient* client) : DOMWindowProperty(&frame), @@ -45,15 +44,11 @@ m_client(client), m_dispatchEventTimer( this, - &ScreenOrientationController::dispatchEventTimerFired) {} - -const char* ScreenOrientationController::supplementName() { - return "ScreenOrientationController"; -} + &ScreenOrientationControllerImpl::dispatchEventTimerFired) {} // Compute the screen orientation using the orientation angle and the screen // width / height. -WebScreenOrientationType ScreenOrientationController::computeOrientation( +WebScreenOrientationType ScreenOrientationControllerImpl::computeOrientation( const IntRect& rect, uint16_t rotation) { // Bypass orientation detection in layout tests to get consistent results. @@ -78,15 +73,15 @@ return isTallDisplay ? WebScreenOrientationLandscapeSecondary : WebScreenOrientationPortraitPrimary; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); return WebScreenOrientationPortraitPrimary; } } -void ScreenOrientationController::updateOrientation() { - ASSERT(m_orientation); - ASSERT(frame()); - ASSERT(frame()->host()); +void ScreenOrientationControllerImpl::updateOrientation() { + DCHECK(m_orientation); + DCHECK(frame()); + DCHECK(frame()->host()); ChromeClient& chromeClient = frame()->host()->chromeClient(); WebScreenInfo screenInfo = chromeClient.screenInfo(); @@ -97,17 +92,17 @@ orientationType = computeOrientation(chromeClient.screenInfo().rect, screenInfo.orientationAngle); } - ASSERT(orientationType != WebScreenOrientationUndefined); + DCHECK(orientationType != WebScreenOrientationUndefined); m_orientation->setType(orientationType); m_orientation->setAngle(screenInfo.orientationAngle); } -bool ScreenOrientationController::isActiveAndVisible() const { +bool ScreenOrientationControllerImpl::isActiveAndVisible() const { return m_orientation && m_client && page() && page()->isPageVisible(); } -void ScreenOrientationController::pageVisibilityChanged() { +void ScreenOrientationControllerImpl::pageVisibilityChanged() { notifyDispatcher(); if (!isActiveAndVisible()) @@ -131,7 +126,7 @@ notifyOrientationChanged(); } -void ScreenOrientationController::notifyOrientationChanged() { +void ScreenOrientationControllerImpl::notifyOrientationChanged() { if (!isActiveAndVisible()) return; @@ -151,15 +146,15 @@ if (!m_dispatchEventTimer.isActive()) m_dispatchEventTimer.startOneShot(0, BLINK_FROM_HERE); - // ... and child frames, if they have a ScreenOrientationController. + // ... and child frames, if they have a ScreenOrientationControllerImpl. for (size_t i = 0; i < childFrames.size(); ++i) { - if (ScreenOrientationController* controller = - ScreenOrientationController::from(*childFrames[i])) + if (ScreenOrientationControllerImpl* controller = + ScreenOrientationControllerImpl::from(*childFrames[i])) controller->notifyOrientationChanged(); } } -void ScreenOrientationController::setOrientation( +void ScreenOrientationControllerImpl::setOrientation( ScreenOrientation* orientation) { m_orientation = orientation; if (m_orientation) @@ -167,7 +162,7 @@ notifyDispatcher(); } -void ScreenOrientationController::lock( +void ScreenOrientationControllerImpl::lock( WebScreenOrientationLockType orientation, std::unique_ptr<WebLockOrientationCallback> callback) { // When detached, the client is no longer valid. @@ -176,14 +171,14 @@ m_client->lockOrientation(orientation, std::move(callback)); } -void ScreenOrientationController::unlock() { +void ScreenOrientationControllerImpl::unlock() { // When detached, the client is no longer valid. if (!m_client) return; m_client->unlockOrientation(); } -void ScreenOrientationController::dispatchEventTimerFired(TimerBase*) { +void ScreenOrientationControllerImpl::dispatchEventTimerFired(TimerBase*) { if (!m_orientation) return; @@ -191,35 +186,35 @@ m_orientation->dispatchEvent(Event::create(EventTypeNames::change)); } -void ScreenOrientationController::didUpdateData() { +void ScreenOrientationControllerImpl::didUpdateData() { // Do nothing. } -void ScreenOrientationController::registerWithDispatcher() { +void ScreenOrientationControllerImpl::registerWithDispatcher() { ScreenOrientationDispatcher::instance().addController(this); } -void ScreenOrientationController::unregisterWithDispatcher() { +void ScreenOrientationControllerImpl::unregisterWithDispatcher() { ScreenOrientationDispatcher::instance().removeController(this); } -bool ScreenOrientationController::hasLastData() { +bool ScreenOrientationControllerImpl::hasLastData() { return true; } -void ScreenOrientationController::frameDestroyed() { +void ScreenOrientationControllerImpl::frameDestroyed() { m_client = nullptr; DOMWindowProperty::frameDestroyed(); } -void ScreenOrientationController::notifyDispatcher() { +void ScreenOrientationControllerImpl::notifyDispatcher() { if (m_orientation && page()->isPageVisible()) startUpdating(); else stopUpdating(); } -DEFINE_TRACE(ScreenOrientationController) { +DEFINE_TRACE(ScreenOrientationControllerImpl) { visitor->trace(m_orientation); DOMWindowProperty::trace(visitor); Supplement<LocalFrame>::trace(visitor);
diff --git a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationController.h b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.h similarity index 67% rename from third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationController.h rename to third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.h index 2fb4e89..b054aaf 100644 --- a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationController.h +++ b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ScreenOrientationController_h -#define ScreenOrientationController_h +#ifndef ScreenOrientationControllerImpl_h +#define ScreenOrientationControllerImpl_h #include "core/frame/DOMWindowProperty.h" #include "core/frame/PlatformEventController.h" +#include "core/frame/ScreenOrientationController.h" #include "modules/ModulesExport.h" -#include "platform/Supplementable.h" #include "platform/Timer.h" #include "public/platform/modules/screen_orientation/WebLockOrientationCallback.h" #include "public/platform/modules/screen_orientation/WebScreenOrientationLockType.h" @@ -20,32 +20,32 @@ class ScreenOrientation; class WebScreenOrientationClient; -class MODULES_EXPORT ScreenOrientationController final - : public GarbageCollectedFinalized<ScreenOrientationController>, - public Supplement<LocalFrame>, +class MODULES_EXPORT ScreenOrientationControllerImpl final + : public GarbageCollectedFinalized<ScreenOrientationControllerImpl>, + public ScreenOrientationController, public DOMWindowProperty, public PlatformEventController { - USING_GARBAGE_COLLECTED_MIXIN(ScreenOrientationController); - WTF_MAKE_NONCOPYABLE(ScreenOrientationController); + USING_GARBAGE_COLLECTED_MIXIN(ScreenOrientationControllerImpl); + WTF_MAKE_NONCOPYABLE(ScreenOrientationControllerImpl); public: - ~ScreenOrientationController() override; + ~ScreenOrientationControllerImpl() override; void setOrientation(ScreenOrientation*); void notifyOrientationChanged(); + // Implementation of ScreenOrientationController. void lock(WebScreenOrientationLockType, - std::unique_ptr<WebLockOrientationCallback>); - void unlock(); + std::unique_ptr<WebLockOrientationCallback>) override; + void unlock() override; static void provideTo(LocalFrame&, WebScreenOrientationClient*); - static ScreenOrientationController* from(LocalFrame&); - static const char* supplementName(); + static ScreenOrientationControllerImpl* from(LocalFrame&); DECLARE_VIRTUAL_TRACE(); private: - ScreenOrientationController(LocalFrame&, WebScreenOrientationClient*); + ScreenOrientationControllerImpl(LocalFrame&, WebScreenOrientationClient*); static WebScreenOrientationType computeOrientation(const IntRect&, uint16_t); @@ -69,9 +69,9 @@ Member<ScreenOrientation> m_orientation; WebScreenOrientationClient* m_client; - Timer<ScreenOrientationController> m_dispatchEventTimer; + Timer<ScreenOrientationControllerImpl> m_dispatchEventTimer; }; } // namespace blink -#endif // ScreenOrientationController_h +#endif // ScreenOrientationControllerImpl_h
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp index 091e628..48237e05 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -4101,9 +4101,14 @@ synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason); return; } - if (!validateReadPixelsFuncParameters( - width, height, format, type, pixels, - (pixels->byteLength() - offsetInBytes).ValueOrDie())) { + CheckedNumeric<GLuint> bufferSize = pixels->byteLength() - offsetInBytes; + if (!bufferSize.IsValid()) { + synthesizeGLError(GL_INVALID_VALUE, "readPixels", + "destination offset out of range"); + return; + } + if (!validateReadPixelsFuncParameters(width, height, format, type, pixels, + bufferSize.ValueOrDie())) { return; } clearIfComposited();
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index 7efe2b45..a1494f30 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -173,6 +173,7 @@ PassPaintVisualRectToCompositor PaymentApp status=experimental PaymentDetailsError status=experimental +PaymentDetailsModifierData status=experimental // PaymentRequest is enabled by default on Android PaymentRequest status=experimental PaymentRequestIFrame status=experimental
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp b/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp index 88ae543..06f0a0d 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp +++ b/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp
@@ -2660,7 +2660,11 @@ } unsigned padding = 0; - unsigned residual = (checkedValue % params.alignment).ValueOrDie(); + CheckedNumeric<uint32_t> checkedResidual = checkedValue % params.alignment; + if (!checkedResidual.IsValid()) { + return GL_INVALID_VALUE; + } + unsigned residual = checkedResidual.ValueOrDie(); if (residual) { padding = params.alignment - residual; checkedValue += padding;
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h index 800a1221..05e5c9a 100644 --- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h +++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h
@@ -92,8 +92,6 @@ const ScrollOffset& delta) override; void scrollToOffsetWithoutAnimation(const ScrollOffset&) override; - void handleWheelEventPhase(PlatformWheelEventPhase) override; - void cancelAnimation() override; void contentAreaWillPaint() const override; @@ -105,9 +103,6 @@ void contentsResized() const override; void contentAreaDidShow() const override; void contentAreaDidHide() const override; - void didBeginScrollGesture() const; - void didEndScrollGesture() const; - void mayBeginScrollGesture() const; void finishCurrentScrollAnimations() override;
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm index 0a52e4f..fa1161c 100644 --- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm +++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
@@ -871,25 +871,6 @@ [m_scrollbarPainterController.get() windowOrderedOut]; } -void ScrollAnimatorMac::didBeginScrollGesture() const { - if (!getScrollableArea()->scrollbarsCanBeActive()) - return; - [m_scrollbarPainterController.get() beginScrollGesture]; -} - -void ScrollAnimatorMac::didEndScrollGesture() const { - if (!getScrollableArea()->scrollbarsCanBeActive()) - return; - [m_scrollbarPainterController.get() endScrollGesture]; -} - -void ScrollAnimatorMac::mayBeginScrollGesture() const { - if (!getScrollableArea()->scrollbarsCanBeActive()) - return; - [m_scrollbarPainterController.get() beginScrollGesture]; - [m_scrollbarPainterController.get() contentAreaScrolled]; -} - void ScrollAnimatorMac::finishCurrentScrollAnimations() { [m_scrollbarPainterController.get() hideOverlayScrollers]; } @@ -972,21 +953,6 @@ m_haveScrolledSincePageLoad = false; } -void ScrollAnimatorMac::handleWheelEventPhase(PlatformWheelEventPhase phase) { - // This may not have been set to true yet if the wheel event was handled by - // the ScrollingTree, - // So set it to true here. - m_haveScrolledSincePageLoad = true; - - if (phase == PlatformWheelEventPhaseBegan) - didBeginScrollGesture(); - else if (phase == PlatformWheelEventPhaseEnded || - phase == PlatformWheelEventPhaseCancelled) - didEndScrollGesture(); - else if (phase == PlatformWheelEventPhaseMayBegin) - mayBeginScrollGesture(); -} - void ScrollAnimatorMac::updateScrollerStyle() { if (!getScrollableArea()->scrollbarsCanBeActive()) { m_needsScrollerStyleUpdate = true;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h index 42d431d..6a81c42b 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
@@ -63,10 +63,6 @@ virtual void scrollToOffsetWithoutAnimation(const ScrollOffset&); -#if OS(MACOSX) - virtual void handleWheelEventPhase(PlatformWheelEventPhase) {} -#endif - void setCurrentOffset(const ScrollOffset&); ScrollOffset currentOffset() const; virtual ScrollOffset desiredTargetOffset() const { return currentOffset(); }
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp index 52377c6..ec3508f 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp +++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -60,7 +60,7 @@ #include "modules/mediastream/UserMediaController.h" #include "modules/presentation/PresentationController.h" #include "modules/push_messaging/PushController.h" -#include "modules/screen_orientation/ScreenOrientationController.h" +#include "modules/screen_orientation/ScreenOrientationControllerImpl.h" #include "modules/vr/VRController.h" #include "platform/Cursor.h" #include "platform/FileChooser.h" @@ -1165,8 +1165,8 @@ if (RuntimeEnabledFeatures::webBluetoothEnabled()) BluetoothSupplement::provideTo(frame, client->bluetooth()); - ScreenOrientationController::provideTo(frame, - client->webScreenOrientationClient()); + ScreenOrientationControllerImpl::provideTo( + frame, client->webScreenOrientationClient()); if (RuntimeEnabledFeatures::presentationEnabled()) PresentationController::provideTo(frame, client->presentationClient()); if (RuntimeEnabledFeatures::audioOutputDevicesEnabled())
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index 9887dd8..e0108fad 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -157,7 +157,7 @@ #include "core/timing/DOMWindowPerformance.h" #include "core/timing/Performance.h" #include "modules/app_banner/AppBannerController.h" -#include "modules/screen_orientation/ScreenOrientationController.h" +#include "modules/screen_orientation/ScreenOrientationControllerImpl.h" #include "platform/ScriptForbiddenScope.h" #include "platform/UserGestureIndicator.h" #include "platform/clipboard/ClipboardUtilities.h" @@ -2057,8 +2057,8 @@ return; // Screen Orientation API - if (ScreenOrientationController::from(*frame())) - ScreenOrientationController::from(*frame())->notifyOrientationChanged(); + if (ScreenOrientationControllerImpl::from(*frame())) + ScreenOrientationControllerImpl::from(*frame())->notifyOrientationChanged(); // Legacy window.orientation API if (RuntimeEnabledFeatures::orientationEventEnabled() && frame()->domWindow())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py index db8be0a..c85cd20 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -785,6 +785,8 @@ else: path_in_wpt = filename return self._manifest_items_for_path(path_in_wpt) is not None + if 'inspector-unit' in dirname: + return filesystem.splitext(filename)[1] == '.js' return Port._has_supported_extension( filesystem, filename) and not Port.is_reference_html_file(filesystem, dirname, filename) @@ -1093,9 +1095,6 @@ def inspector_build_directory(self): return self._build_path('resources', 'inspector') - def inspector_debug_directory(self): - return self.path_from_webkit_base('Source', 'devtools', 'front_end') - def apache_config_directory(self): return self.path_from_webkit_base('Tools', 'Scripts', 'apache_config')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py index 36d4dd3..c508704 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -355,6 +355,9 @@ self.assertTrue(is_test_file('', 'foo.html')) self.assertTrue(is_test_file('', 'foo.svg')) self.assertTrue(is_test_file('', 'test-ref-test.html')) + self.assertTrue(is_test_file('inspector-unit', 'trie.js')) + self.assertFalse(is_test_file('inspector-unit', 'foo.html')) + self.assertFalse(is_test_file('inspector', 'devtools.js')) self.assertFalse(is_test_file('', 'foo.png')) self.assertFalse(is_test_file('', 'foo-expected.html')) self.assertFalse(is_test_file('', 'foo-expected.svg'))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py index d2a658a9..d1b3e58 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py
@@ -63,7 +63,6 @@ mime_types_path = self._filesystem.join(self._port_obj.apache_config_directory(), "mime.types") cert_file = self._filesystem.join(self._port_obj.apache_config_directory(), "webkit-httpd.pem") inspector_sources_dir = self._port_obj.inspector_build_directory() - inspector_debug_dir = self._port_obj.inspector_debug_directory() self._access_log_path = self._filesystem.join(output_dir, "access_log.txt") self._error_log_path = self._filesystem.join(output_dir, "error_log.txt") @@ -87,7 +86,6 @@ '-c', 'PidFile %s' % self._pid_file, '-c', 'SSLCertificateFile "%s"' % cert_file, '-c', 'Alias /inspector-sources "%s"' % inspector_sources_dir, - '-c', 'Alias /inspector-debug "%s"' % inspector_debug_dir, '-c', 'DefaultType None', ]
diff --git a/third_party/polymer/v1_0/chromium.patch b/third_party/polymer/v1_0/chromium.patch index 7649e0d..d6a80e8 100644 --- a/third_party/polymer/v1_0/chromium.patch +++ b/third_party/polymer/v1_0/chromium.patch
@@ -13,7 +13,7 @@ index 2eaa665..7416f94 100644 --- a/components-chromium/paper-icon-button/paper-icon-button-light.html +++ b/components-chromium/paper-icon-button/paper-icon-button-light.html -@@ -45,9 +45,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN +@@ +45,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN paper-ripple { opacity: 0.6; color: currentColor; @@ -21,6 +21,4 @@ } </style> <content></content> - </template> - </dom-module>
diff --git a/third_party/polymer/v1_0/find_unused_elements.py b/third_party/polymer/v1_0/find_unused_elements.py old mode 100755 new mode 100644 index a93b177..5dbacdb --- a/third_party/polymer/v1_0/find_unused_elements.py +++ b/third_party/polymer/v1_0/find_unused_elements.py
@@ -1,5 +1,3 @@ -#!/usr/bin/python2 - # Copyright 2016 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.
diff --git a/third_party/polymer/v1_0/reproduce.sh b/third_party/polymer/v1_0/reproduce.sh index 9f388c7..8fb85b4 100755 --- a/third_party/polymer/v1_0/reproduce.sh +++ b/third_party/polymer/v1_0/reproduce.sh
@@ -112,4 +112,4 @@ popd > /dev/null echo 'Searching for unused elements...' -"$(dirname "$0")"/find_unused_elements.py +python "$(dirname "$0")"/find_unused_elements.py
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 46579b9..8c611e9 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -9837,6 +9837,14 @@ <description>Please enter the description of this user action.</description> </action> +<action name="MobileSadTabFeedback"> + <owner>jwanda@chromium.org</owner> + <description> + The user pressed the Send Feedback button on a tab that is displaying the + sad view. + </description> +</action> + <action name="MobileSettingsStorageClearAll"> <owner>dmurph@chromium.org</owner> <description>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index ae162cf..b6cb3d29 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -40913,6 +40913,17 @@ </summary> </histogram> +<histogram name="Omnibox.HistoryQuickHistoryIDSetFromWords" units="ms"> + <owner>mpearson@chromium.org</owner> + <summary> + Times URLIndexPrivateData::HistoryIDSetFromWords(), which is called by the + omnibox's HistoryQuick provider. + URLIndexPrivateData::HistoryIDSetFromWords() can be called multiple times + per keystroke due to, for example, the cursor being in the middle of the + input string or SearchProvider's calls to Classify(). + </summary> +</histogram> + <histogram name="Omnibox.InputType" enum="OmniboxInputType"> <owner>mpearson@chromium.org</owner> <summary> @@ -80908,9 +80919,9 @@ <enum name="DownEventDestination" type="int"> <int value="0" label="Others, everything except browser and apps"/> <int value="1" label="Inside the browser frame"/> - <int value="2" label="Regular chrome app, except default note-taking app"/> - <int value="3" label="ARC app (android app on Chrome)"/> - <int value="4" label="Default note-taking app"/> + <int value="2" label="Regular Chrome app"/> + <int value="3" label="ARC app (Android app on Chrome)"/> + <int value="4" label="Default note-taking app (deprecated)"/> </enum> <enum name="DownEventFormFactor" type="int"> @@ -101084,9 +101095,28 @@ <int value="1" label="Recovered"> Failed to open the existing db, deleted it, and created a new empty db. </int> - <int value="2" label="Total Fail"> + <int value="2" label="Reopen: Total Fail"> + <obsolete> + Deprecated 2016/11. Replaced by other "Reopen:" errors. + </obsolete> Failed to open the database and also failed to delete and start over. </int> + <int value="3" label="Reopen: not found"> + Reopen attempt failed with (not found) after successful database delete. + </int> + <int value="4" label="Reopen: not supported"> + Reopen attempt failed with (not supported) after successful database delete. + </int> + <int value="5" label="Reopen: corruption"> + Reopen attempt failed with (corruption) after successful database delete. + </int> + <int value="6" label="Reopen: invalid argument"> + Reopen attempt failed with (invalid argument) after successful database + delete. + </int> + <int value="7" label="Reopen: I/O error"> + Reopen attempt failed with (I/O error) after successful database delete. + </int> </enum> <enum name="SetDefaultAttemptResult" type="int">
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc index 52985fe..d5a64e8 100644 --- a/ui/aura/mus/window_port_mus.cc +++ b/ui/aura/mus/window_port_mus.cc
@@ -58,6 +58,9 @@ } void WindowPortMus::SetPredefinedCursor(ui::mojom::Cursor cursor_id) { + if (cursor_id == predefined_cursor_) + return; + window_tree_client_->SetPredefinedCursor(this, predefined_cursor_, cursor_id); predefined_cursor_ = cursor_id; }
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index 71e88f2..58ffddfc 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js
@@ -2729,10 +2729,10 @@ }, /** - * Enables or disables transitions on the user pod. + * Enables or disables transitions on every pod instance. * @param {boolean} enable */ - togglePinTransitions: function(enable) { + toggleTransitions: function(enable) { for (var i = 0; i < this.pods.length; ++i) this.pods[i].toggleTransitions(enable); }, @@ -2773,15 +2773,6 @@ }, /** - * Function that hides the pin keyboard. Meant to be called when the virtual - * keyboard is enabled and being toggled. - * @param {boolean} hidden - */ - setPinHidden: function(hidden) { - this.setFocusedPodPinVisibility(!hidden); - }, - - /** * Remove the pin keyboard from the pod with the given |username|. * @param {!user} username * @param {boolean} visible
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js index fb08fb3..a3b5210c 100644 --- a/ui/login/display_manager.js +++ b/ui/login/display_manager.js
@@ -266,7 +266,7 @@ set pinHidden(hidden) { this.virtualKeyboardShown = hidden; - $('pod-row').setPinHidden(hidden); + $('pod-row').setFocusedPodPinVisibility(!hidden); }, /**
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc index 61f1f7e..53a0506 100644 --- a/ui/views/bubble/tray_bubble_view.cc +++ b/ui/views/bubble/tray_bubble_view.cc
@@ -192,6 +192,7 @@ : BubbleDialogDelegateView(anchor, GetArrowAlignment(init_params.anchor_alignment)), params_(init_params), + layout_(new BottomAlignedBoxLayout(this)), delegate_(delegate), preferred_width_(init_params.min_width), bubble_border_(new BubbleBorder(arrow(), @@ -211,6 +212,9 @@ bubble_content_mask_.reset( new TrayBubbleContentMask(bubble_border_->GetBorderCornerRadius())); + + layout_->SetDefaultFlex(1); + SetLayoutManager(layout_); } TrayBubbleView::~TrayBubbleView() { @@ -243,6 +247,10 @@ SizeToContents(); } +void TrayBubbleView::SetBottomPadding(int padding) { + layout_->set_inside_border_insets(gfx::Insets(0, 0, padding, 0)); +} + void TrayBubbleView::SetWidth(int width) { width = std::max(std::min(width, params_.max_width), params_.min_width); if (preferred_width_ == width) @@ -260,12 +268,6 @@ return ui::DIALOG_BUTTON_NONE; } -void TrayBubbleView::Init() { - BoxLayout* layout = new BottomAlignedBoxLayout(this); - layout->SetDefaultFlex(1); - SetLayoutManager(layout); -} - void TrayBubbleView::OnBeforeBubbleWidgetInit(Widget::InitParams* params, Widget* bubble_widget) const { if (delegate_)
diff --git a/ui/views/bubble/tray_bubble_view.h b/ui/views/bubble/tray_bubble_view.h index a50791d9..8de9c30 100644 --- a/ui/views/bubble/tray_bubble_view.h +++ b/ui/views/bubble/tray_bubble_view.h
@@ -13,6 +13,7 @@ #include "ui/views/views_export.h" namespace views { +class BoxLayout; class View; class Widget; } @@ -102,6 +103,9 @@ // Sets the maximum bubble height and resizes the bubble. void SetMaxHeight(int height); + // Sets the bottom padding that child views will be laid out within. + void SetBottomPadding(int padding); + // Sets the bubble width. void SetWidth(int width); @@ -145,7 +149,6 @@ // Overridden from views::BubbleDialogDelegateView. int GetDialogButtons() const override; - void Init() override; // Overridden from views::View. void ChildPreferredSizeChanged(View* child) override; @@ -154,6 +157,7 @@ private: InitParams params_; + BoxLayout* layout_; Delegate* delegate_; int preferred_width_; // |bubble_border_| and |owned_bubble_border_| point to the same thing, but
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc index 29197e63..8d441d91 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.cc +++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -6,9 +6,11 @@ #include "base/memory/ptr_util.h" #include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/cursor_client.h" #include "ui/aura/client/drag_drop_client.h" #include "ui/aura/client/focus_client.h" #include "ui/aura/env.h" +#include "ui/aura/mus/window_port_mus.h" #include "ui/aura/mus/window_tree_host_mus.h" #include "ui/aura/window.h" #include "ui/base/hit_test.h" @@ -20,6 +22,8 @@ #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/widget_delegate.h" +#include "ui/wm/core/cursor_manager.h" +#include "ui/wm/core/native_cursor_manager.h" #include "ui/wm/core/window_util.h" #include "ui/wm/public/activation_client.h" @@ -106,6 +110,62 @@ DISALLOW_COPY_AND_ASSIGN(ClientSideNonClientFrameView); }; +class NativeCursorManagerMus : public wm::NativeCursorManager { + public: + explicit NativeCursorManagerMus(aura::Window* window) : window_(window) {} + ~NativeCursorManagerMus() override {} + + // wm::NativeCursorManager: + void SetDisplay(const display::Display& display, + wm::NativeCursorManagerDelegate* delegate) override { + // We ignore this entirely, as cursor are set on the client. + } + + void SetCursor(gfx::NativeCursor cursor, + wm::NativeCursorManagerDelegate* delegate) override { + aura::WindowPortMus::Get(window_)->SetPredefinedCursor( + ui::mojom::Cursor(cursor.native_type())); + delegate->CommitCursor(cursor); + } + + void SetVisibility(bool visible, + wm::NativeCursorManagerDelegate* delegate) override { + delegate->CommitVisibility(visible); + + if (visible) { + SetCursor(delegate->GetCursor(), delegate); + } else { + aura::WindowPortMus::Get(window_)->SetPredefinedCursor( + ui::mojom::Cursor::NONE); + } + } + + void SetCursorSet(ui::CursorSetType cursor_set, + wm::NativeCursorManagerDelegate* delegate) override { + // TODO(erg): For now, ignore the difference between SET_NORMAL and + // SET_LARGE here. This feels like a thing that mus should decide instead. + // + // Also, it's NOTIMPLEMENTED() in the desktop version!? Including not + // acknowledging the call in the delegate. + NOTIMPLEMENTED(); + } + + void SetMouseEventsEnabled( + bool enabled, + wm::NativeCursorManagerDelegate* delegate) override { + // TODO(erg): How do we actually implement this? + // + // Mouse event dispatch is potentially done in a different process, + // definitely in a different mojo service. Each app is fairly locked down. + delegate->CommitMouseEventsEnabled(enabled); + NOTIMPLEMENTED(); + } + + private: + aura::Window* window_; + + DISALLOW_COPY_AND_ASSIGN(NativeCursorManagerMus); +}; } // namespace DesktopWindowTreeHostMus::DesktopWindowTreeHostMus( @@ -180,6 +240,10 @@ content_window->layer()->SetFillsBoundsOpaquely(false); if (!params.bounds.IsEmpty()) SetBoundsInDIP(params.bounds); + + cursor_manager_ = base::MakeUnique<wm::CursorManager>( + base::MakeUnique<NativeCursorManagerMus>(window())); + aura::client::SetCursorClient(window(), cursor_manager_.get()); } void DesktopWindowTreeHostMus::OnNativeWidgetCreated( @@ -546,6 +610,11 @@ return false; } +bool DesktopWindowTreeHostMus::ShouldUseDesktopNativeCursorManager() const { + // We manage the cursor ourself. + return false; +} + void DesktopWindowTreeHostMus::OnWindowManagerFrameValuesChanged() { NonClientView* non_client_view = native_widget_delegate_->AsWidget()->non_client_view();
diff --git a/ui/views/mus/desktop_window_tree_host_mus.h b/ui/views/mus/desktop_window_tree_host_mus.h index eb0e6930..b988aee 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.h +++ b/ui/views/mus/desktop_window_tree_host_mus.h
@@ -16,6 +16,10 @@ #include "ui/views/widget/desktop_aura/desktop_window_tree_host.h" #include "ui/views/widget/widget.h" +namespace wm { +class CursorManager; +} + namespace views { class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus @@ -102,6 +106,7 @@ bool IsTranslucentWindowOpacitySupported() const override; void SizeConstraintsChanged() override; bool ShouldUpdateWindowTransparency() const override; + bool ShouldUseDesktopNativeCursorManager() const override; // MusClientObserver: void OnWindowManagerFrameValuesChanged() override; @@ -131,6 +136,8 @@ bool is_active_ = false; + std::unique_ptr<wm::CursorManager> cursor_manager_; + // Used so that Close() isn't immediate. base::WeakPtrFactory<DesktopWindowTreeHostMus> close_widget_factory_;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 91698f4..e50108f 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -326,14 +326,16 @@ void DesktopNativeWidgetAura::OnDesktopWindowTreeHostDestroyed( aura::WindowTreeHost* host) { - // We explicitly do NOT clear the cursor client property. Since the cursor - // manager is a singleton, it can outlive any window hierarchy, and it's - // important that objects attached to this destroying window hierarchy have - // an opportunity to deregister their observers from the cursor manager. - // They may want to do this when they are notified that they're being - // removed from the window hierarchy, which happens soon after this - // function when DesktopWindowTreeHost* calls DestroyDispatcher(). - native_cursor_manager_->RemoveHost(host); + if (use_desktop_native_cursor_manager_) { + // We explicitly do NOT clear the cursor client property. Since the cursor + // manager is a singleton, it can outlive any window hierarchy, and it's + // important that objects attached to this destroying window hierarchy have + // an opportunity to deregister their observers from the cursor manager. + // They may want to do this when they are notified that they're being + // removed from the window hierarchy, which happens soon after this + // function when DesktopWindowTreeHost* calls DestroyDispatcher(). + native_cursor_manager_->RemoveHost(host); + } aura::client::SetScreenPositionClient(host->window(), NULL); position_client_.reset(); @@ -447,17 +449,21 @@ root_window_event_filter_.reset(new wm::CompoundEventFilter); host_->window()->AddPreTargetHandler(root_window_event_filter_.get()); - // The host's dispatcher must be added to |native_cursor_manager_| before - // OnNativeWidgetCreated() is called. - cursor_reference_count_++; - if (!native_cursor_manager_) - native_cursor_manager_ = new DesktopNativeCursorManager(); - if (!cursor_manager_) { - cursor_manager_ = new wm::CursorManager( - std::unique_ptr<wm::NativeCursorManager>(native_cursor_manager_)); + use_desktop_native_cursor_manager_ = + desktop_window_tree_host_->ShouldUseDesktopNativeCursorManager(); + if (use_desktop_native_cursor_manager_) { + // The host's dispatcher must be added to |native_cursor_manager_| before + // OnNativeWidgetCreated() is called. + cursor_reference_count_++; + if (!native_cursor_manager_) + native_cursor_manager_ = new DesktopNativeCursorManager(); + if (!cursor_manager_) { + cursor_manager_ = new wm::CursorManager( + std::unique_ptr<wm::NativeCursorManager>(native_cursor_manager_)); + } + native_cursor_manager_->AddHost(host()); + aura::client::SetCursorClient(host_->window(), cursor_manager_); } - native_cursor_manager_->AddHost(host()); - aura::client::SetCursorClient(host_->window(), cursor_manager_); desktop_window_tree_host_->OnNativeWidgetCreated(params);
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index 3b81ddf3..c12b6ff 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -307,6 +307,9 @@ // See class documentation for Widget in widget.h for a note about type. Widget::InitParams::Type widget_type_; + // See DesktopWindowTreeHost::ShouldUseDesktopNativeCursorManager(). + bool use_desktop_native_cursor_manager_ = false; + // The following factory is used for calls to close the NativeWidgetAura // instance. base::WeakPtrFactory<DesktopNativeWidgetAura> close_widget_factory_;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/ui/views/widget/desktop_aura/desktop_window_tree_host.h index e8bfb9d..6528cf5 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -162,6 +162,11 @@ // Returns true if the transparency of the DesktopNativeWidgetAura's // |content_window_| should change. virtual bool ShouldUpdateWindowTransparency() const = 0; + + // A return value of true indicates DesktopNativeCursorManager should be + // used, a return value of false indicates the DesktopWindowTreeHost manages + // cursors itself. + virtual bool ShouldUseDesktopNativeCursorManager() const = 0; }; } // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index 8f030fb..2c3c254 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -488,6 +488,10 @@ return true; } +bool DesktopWindowTreeHostWin::ShouldUseDesktopNativeCursorManager() const { + return true; +} + //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostWin, WindowTreeHost implementation:
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h index 8935db5..8de99c58 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -105,6 +105,7 @@ bool IsTranslucentWindowOpacitySupported() const override; void SizeConstraintsChanged() override; bool ShouldUpdateWindowTransparency() const override; + bool ShouldUseDesktopNativeCursorManager() const override; // Overridden from aura::WindowTreeHost: ui::EventSource* GetEventSource() override;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc index d4a5387..8c566fa 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -1171,6 +1171,10 @@ return true; } +bool DesktopWindowTreeHostX11::ShouldUseDesktopNativeCursorManager() const { + return true; +} + //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h index fc227c35..7dfc750 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -153,6 +153,7 @@ bool IsTranslucentWindowOpacitySupported() const override; void SizeConstraintsChanged() override; bool ShouldUpdateWindowTransparency() const override; + bool ShouldUseDesktopNativeCursorManager() const override; // Overridden from aura::WindowTreeHost: gfx::Transform GetRootTransform() const override;