diff --git a/DEPS b/DEPS index c6af233..3ad96f6 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': '70e3e9adc57d765cbd1e86d8f54145e1b4a564f4', + 'skia_revision': 'ed50200682e0de72c3abecaa4d5324ebcd1ed9f9', # 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': 'd3230cfb7f2df6997c76111740cc9f9bf7289423', + 'v8_revision': '23203004176173339487767d9a9ff0968f5641e5', # 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. @@ -52,7 +52,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '579d8c7dfcfaeb44fc7a650cd151539d87eedcd2', + 'angle_revision': '0dc97810e5e4ed49d4a6c31d071550e618e9e25e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # 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': 'd261b065d09046bbcc6594e48220cff44a371732', + 'pdfium_revision': 'c0c39cbb638dd24b07b9cdcf7e9179e88b162ad3', # 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': '520dd376a20eb6ab41cd88a5dbfd56ee3d156d2f', + 'catapult_revision': '45d20f29a9ac09db8e197637ff975b0c9fbe01b3', # 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/android_webview/test/embedded_test_server/BUILD.gn b/android_webview/test/embedded_test_server/BUILD.gn index f9d6dbf9..e9b2f3af 100644 --- a/android_webview/test/embedded_test_server/BUILD.gn +++ b/android_webview/test/embedded_test_server/BUILD.gn
@@ -57,8 +57,6 @@ ":aw_java_test_native_support", "//net:test_support", ] - configs -= [ "//build/config/android:hide_all_but_jni_onload" ] - configs += [ "//build/config/android:hide_all_but_jni" ] } android_apk("aw_net_test_support_apk") {
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc index cff2bbf..b5145db4 100644 --- a/ash/accelerators/accelerator_controller.cc +++ b/ash/accelerators/accelerator_controller.cc
@@ -12,6 +12,7 @@ #include "ash/accessibility_delegate.h" #include "ash/accessibility_types.h" #include "ash/focus_cycler.h" +#include "ash/ime/ime_controller.h" #include "ash/ime/ime_switch_type.h" #include "ash/media_controller.h" #include "ash/multi_profile_uma.h" @@ -259,14 +260,7 @@ } bool CanCycleInputMethod() { - InputMethodManager* manager = InputMethodManager::Get(); - DCHECK(manager); - if (!manager->GetActiveIMEState()) { - LOG(WARNING) << "Cannot cycle through input methods as they are not " - "initialized yet."; - return false; - } - return manager->GetActiveIMEState()->CanCycleInputMethod(); + return Shell::Get()->ime_controller()->CanSwitchIme(); } bool CanHandleCycleMru(const ui::Accelerator& accelerator) { @@ -284,7 +278,7 @@ void HandleNextIme() { base::RecordAction(UserMetricsAction("Accel_Next_Ime")); RecordImeSwitchByAccelerator(); - InputMethodManager::Get()->GetActiveIMEState()->SwitchToNextInputMethod(); + Shell::Get()->ime_controller()->SwitchToNextIme(); } void HandleOpenFeedbackPage() { @@ -296,9 +290,7 @@ base::RecordAction(UserMetricsAction("Accel_Previous_Ime")); if (accelerator.key_state() == ui::Accelerator::KeyState::PRESSED) { RecordImeSwitchByAccelerator(); - InputMethodManager::Get() - ->GetActiveIMEState() - ->SwitchToPreviousInputMethod(); + Shell::Get()->ime_controller()->SwitchToPreviousIme(); } // Else: consume the Ctrl+Space ET_KEY_RELEASED event but do not do anything. } @@ -368,21 +360,14 @@ } bool CanHandleSwitchIme(const ui::Accelerator& accelerator) { - InputMethodManager* manager = InputMethodManager::Get(); - DCHECK(manager); - if (!manager->GetActiveIMEState()) { - LOG(WARNING) << "Cannot switch input methods as they are not " - "initialized yet."; - return false; - } - return manager->GetActiveIMEState()->CanSwitchInputMethod(accelerator); + return Shell::Get()->ime_controller()->CanSwitchImeWithAccelerator( + accelerator); } void HandleSwitchIme(const ui::Accelerator& accelerator) { base::RecordAction(UserMetricsAction("Accel_Switch_Ime")); RecordImeSwitchByAccelerator(); - InputMethodManager::Get()->GetActiveIMEState()->SwitchInputMethod( - accelerator); + Shell::Get()->ime_controller()->SwitchImeWithAccelerator(accelerator); } bool CanHandleToggleAppList(const ui::Accelerator& accelerator,
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index d5120d95..84034f9 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -8,8 +8,10 @@ #include "ash/accessibility_delegate.h" #include "ash/accessibility_types.h" #include "ash/ash_switches.h" +#include "ash/ime/ime_controller.h" #include "ash/public/cpp/config.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/interfaces/ime_info.mojom.h" #include "ash/session/session_controller.h" #include "ash/shell.h" #include "ash/shell_port.h" @@ -58,6 +60,18 @@ namespace { +void AddTestImes() { + mojom::ImeInfoPtr ime1 = mojom::ImeInfo::New(); + ime1->id = "id1"; + mojom::ImeInfoPtr ime2 = mojom::ImeInfo::New(); + ime2->id = "id2"; + std::vector<mojom::ImeInfoPtr> available_imes; + available_imes.push_back(std::move(ime1)); + available_imes.push_back(std::move(ime2)); + Shell::Get()->ime_controller()->RefreshIme( + "id1", std::move(available_imes), std::vector<mojom::ImeMenuItemPtr>()); +} + class TestTarget : public ui::AcceleratorTarget { public: TestTarget() : accelerator_pressed_count_(0), accelerator_repeat_count_(0) {} @@ -124,54 +138,18 @@ DISALLOW_COPY_AND_ASSIGN(DummyBrightnessControlDelegate); }; -class TestInputMethodManagerState - : public chromeos::input_method::MockInputMethodManager::State { - public: - TestInputMethodManagerState() = default; - - // InputMethodManager::State: - bool CanCycleInputMethod() override { return can_change_input_method_; } - void SwitchToNextInputMethod() override { next_ime_count_++; } - void SwitchToPreviousInputMethod() override { previous_ime_count_++; } - bool CanSwitchInputMethod(const ui::Accelerator& accelerator) override { - return can_change_input_method_; - } - void SwitchInputMethod(const ui::Accelerator& accelerator) override { - switch_ime_count_++; - } - - bool can_change_input_method_ = true; - int next_ime_count_ = 0; - int previous_ime_count_ = 0; - int switch_ime_count_ = 0; - - private: - // Base class is ref-counted. - ~TestInputMethodManagerState() override = default; - - DISALLOW_COPY_AND_ASSIGN(TestInputMethodManagerState); -}; - class TestInputMethodManager : public chromeos::input_method::MockInputMethodManager { public: - TestInputMethodManager() : state_(new TestInputMethodManagerState) {} + TestInputMethodManager() = default; ~TestInputMethodManager() override = default; - void SetCanChangeInputMethod(bool can_change) { - state_->can_change_input_method_ = can_change; - } - // MockInputMethodManager: chromeos::input_method::ImeKeyboard* GetImeKeyboard() override { return &keyboard_; } - scoped_refptr<InputMethodManager::State> GetActiveIMEState() override { - return state_; - } chromeos::input_method::FakeImeKeyboard keyboard_; - scoped_refptr<TestInputMethodManagerState> state_; private: DISALLOW_COPY_AND_ASSIGN(TestInputMethodManager); @@ -887,45 +865,23 @@ } TEST_F(AcceleratorControllerTest, ImeGlobalAccelerators) { - TestInputMethodManagerState* test_state = - test_input_method_manager_->state_.get(); + ASSERT_EQ(0u, Shell::Get()->ime_controller()->available_imes().size()); - // Test IME shortcuts when cycling IME is blocked. - test_state->can_change_input_method_ = false; + // Cycling IME is blocked because there is nothing to switch to. ui::Accelerator control_space_down(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); ui::Accelerator control_space_up(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); control_space_up.set_key_state(ui::Accelerator::KeyState::RELEASED); - const ui::Accelerator convert(ui::VKEY_CONVERT, ui::EF_NONE); - const ui::Accelerator non_convert(ui::VKEY_NONCONVERT, ui::EF_NONE); - const ui::Accelerator wide_half_1(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE); - const ui::Accelerator wide_half_2(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE); - const ui::Accelerator hangul(ui::VKEY_HANGUL, ui::EF_NONE); + ui::Accelerator control_shift_space(ui::VKEY_SPACE, + ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN); EXPECT_FALSE(ProcessInController(control_space_down)); EXPECT_FALSE(ProcessInController(control_space_up)); - EXPECT_FALSE(ProcessInController(convert)); - EXPECT_FALSE(ProcessInController(non_convert)); - EXPECT_FALSE(ProcessInController(wide_half_1)); - EXPECT_FALSE(ProcessInController(wide_half_2)); - EXPECT_FALSE(ProcessInController(hangul)); + EXPECT_FALSE(ProcessInController(control_shift_space)); - // Test IME shortcuts when cycling IME is allowed. - test_state->can_change_input_method_ = true; - EXPECT_EQ(0, test_state->previous_ime_count_); + // Cycling IME works when there are IMEs available. + AddTestImes(); EXPECT_TRUE(ProcessInController(control_space_down)); - EXPECT_EQ(1, test_state->previous_ime_count_); EXPECT_TRUE(ProcessInController(control_space_up)); - EXPECT_EQ(1, test_state->previous_ime_count_); - EXPECT_EQ(0, test_state->switch_ime_count_); - EXPECT_TRUE(ProcessInController(convert)); - EXPECT_EQ(1, test_state->switch_ime_count_); - EXPECT_TRUE(ProcessInController(non_convert)); - EXPECT_EQ(2, test_state->switch_ime_count_); - EXPECT_TRUE(ProcessInController(wide_half_1)); - EXPECT_EQ(3, test_state->switch_ime_count_); - EXPECT_TRUE(ProcessInController(wide_half_2)); - EXPECT_EQ(4, test_state->switch_ime_count_); - EXPECT_TRUE(ProcessInController(hangul)); - EXPECT_EQ(5, test_state->switch_ime_count_); + EXPECT_TRUE(ProcessInController(control_shift_space)); } // TODO(nona|mazda): Remove this when crbug.com/139556 in a better way. @@ -1348,6 +1304,9 @@ SHOW_IME_MENU_BUBBLE}, }; + // The NEXT_IME accelerator requires multiple IMEs to be available. + AddTestImes(); + EXPECT_TRUE(IsMessageCenterEmpty()); for (auto data : kNewAccelerators) {
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc index 0139b12c..a4cc748 100644 --- a/ash/accelerators/accelerator_table.cc +++ b/ash/accelerators/accelerator_table.cc
@@ -20,8 +20,6 @@ {true, ui::VKEY_NONCONVERT, ui::EF_NONE, SWITCH_IME}, {true, ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE, SWITCH_IME}, {true, ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE, SWITCH_IME}, - // Shortcut for Koren IME. - {true, ui::VKEY_HANGUL, ui::EF_NONE, SWITCH_IME}, {true, ui::VKEY_TAB, ui::EF_ALT_DOWN, CYCLE_FORWARD_MRU}, {true, ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
diff --git a/ash/accelerators/accelerator_table_unittest.cc b/ash/accelerators/accelerator_table_unittest.cc index 79ae8833..2bee4f5 100644 --- a/ash/accelerators/accelerator_table_unittest.cc +++ b/ash/accelerators/accelerator_table_unittest.cc
@@ -15,12 +15,12 @@ namespace { -// The number of non-Search-based accelerators as of 2017-04-11. -constexpr int kNonSearchAcceleratorsNum = 93; -// The hash of non-Search-based accelerators as of 2017-04-11. +// The number of non-Search-based accelerators as of 2017-06-26. +constexpr int kNonSearchAcceleratorsNum = 92; +// The hash of non-Search-based accelerators as of 2017-06-26. // See HashAcceleratorData(). constexpr char kNonSearchAcceleratorsHash[] = - "8230d7ecd3180fdbc10f96bfa170b1ac"; + "c45246c981cba1fe2c6d0d3c494e1117"; struct Cmp { bool operator()(const AcceleratorData& lhs, const AcceleratorData& rhs) {
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc index 3db6f13..664c269 100644 --- a/ash/ash_switches.cc +++ b/ash/ash_switches.cc
@@ -110,6 +110,30 @@ // enables the IME service (i.e. InputMethodMus) instead. const char kUseIMEService[] = "use-ime-service"; +// Number of recent accelerometer samples to examine to determine if a power +// button event was spurious. +const char kSpuriousPowerButtonWindow[] = "spurious-power-button-window"; + +// Number of recent acceleration samples that must meet or exceed the threshold +// in order for a power button event to be considered spurious. +const char kSpuriousPowerButtonAccelCount[] = + "spurious-power-button-accel-count"; + +// Threshold (in m/s^2, disregarding gravity) that screen acceleration must meet +// or exceed for a power button event to be considered spurious. +const char kSpuriousPowerButtonScreenAccel[] = + "spurious-power-button-screen-accel"; + +// Threshold (in m/s^2, disregarding gravity) that keyboard acceleration must +// meet or exceed for a power button event to be considered spurious. +const char kSpuriousPowerButtonKeyboardAccel[] = + "spurious-power-button-keyboard-accel"; + +// Change in lid angle (i.e. hinge between keyboard and screen) that must be +// exceeded for a power button event to be considered spurious. +const char kSpuriousPowerButtonLidAngleChange[] = + "spurious-power-button-lid-angle-change"; + // Constrains the pointer movement within a root window on desktop. bool ConstrainPointerToRoot() { const char kAshConstrainPointerToRoot[] = "ash-constrain-pointer-to-root";
diff --git a/ash/ash_switches.h b/ash/ash_switches.h index e3e7337..66f8266 100644 --- a/ash/ash_switches.h +++ b/ash/ash_switches.h
@@ -47,6 +47,11 @@ ASH_EXPORT extern const char kAshShelfColorSchemeDarkVibrant[]; ASH_EXPORT extern const char kAshTouchHud[]; ASH_EXPORT extern const char kAuraLegacyPowerButton[]; +ASH_EXPORT extern const char kSpuriousPowerButtonWindow[]; +ASH_EXPORT extern const char kSpuriousPowerButtonAccelCount[]; +ASH_EXPORT extern const char kSpuriousPowerButtonScreenAccel[]; +ASH_EXPORT extern const char kSpuriousPowerButtonKeyboardAccel[]; +ASH_EXPORT extern const char kSpuriousPowerButtonLidAngleChange[]; ASH_EXPORT extern const char kUseIMEService[]; // True if the pointer (cursor) position should be kept inside root windows.
diff --git a/ash/ime/ime_controller.cc b/ash/ime/ime_controller.cc index b73c8bf8..496c1e0 100644 --- a/ash/ime/ime_controller.cc +++ b/ash/ime/ime_controller.cc
@@ -6,6 +6,8 @@ #include "ash/shell.h" #include "ash/system/tray/system_tray_notifier.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/ime/chromeos/extension_ime_util.h" namespace ash { @@ -22,27 +24,50 @@ } bool ImeController::CanSwitchIme() const { - NOTIMPLEMENTED(); - return true; + // Cannot switch unless there is an active IME. + if (current_ime_.id.empty()) + return false; + + // Do not consume key event if there is only one input method is enabled. + // Ctrl+Space or Alt+Shift may be used by other application. + return available_imes_.size() > 1; } void ImeController::SwitchToNextIme() { - NOTIMPLEMENTED(); + if (client_) + client_->SwitchToNextIme(); } void ImeController::SwitchToPreviousIme() { - NOTIMPLEMENTED(); + if (client_) + client_->SwitchToPreviousIme(); } bool ImeController::CanSwitchImeWithAccelerator( const ui::Accelerator& accelerator) const { - NOTIMPLEMENTED(); - return true; + // If none of the input methods associated with |accelerator| are active, we + // should ignore the accelerator. + std::vector<std::string> candidate_ids = + GetCandidateImesForAccelerator(accelerator); + return !candidate_ids.empty(); } void ImeController::SwitchImeWithAccelerator( const ui::Accelerator& accelerator) { - NOTIMPLEMENTED(); + if (!client_) + return; + + std::vector<std::string> candidate_ids = + GetCandidateImesForAccelerator(accelerator); + if (candidate_ids.empty()) + return; + auto it = + std::find(candidate_ids.begin(), candidate_ids.end(), current_ime_.id); + if (it != candidate_ids.end()) + ++it; + if (it == candidate_ids.end()) + it = candidate_ids.begin(); + client_->SwitchImeById(*it); } // mojom::ImeController: @@ -85,4 +110,46 @@ Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(show); } +void ImeController::FlushMojoForTesting() { + client_.FlushForTesting(); +} + +std::vector<std::string> ImeController::GetCandidateImesForAccelerator( + const ui::Accelerator& accelerator) const { + std::vector<std::string> candidate_ids; + + using chromeos::extension_ime_util::GetInputMethodIDByEngineID; + std::vector<std::string> input_method_ids_to_switch; + switch (accelerator.key_code()) { + case ui::VKEY_CONVERT: // Henkan key on JP106 keyboard + input_method_ids_to_switch.push_back( + GetInputMethodIDByEngineID("nacl_mozc_jp")); + break; + case ui::VKEY_NONCONVERT: // Muhenkan key on JP106 keyboard + input_method_ids_to_switch.push_back( + GetInputMethodIDByEngineID("xkb:jp::jpn")); + break; + case ui::VKEY_DBE_SBCSCHAR: // ZenkakuHankaku key on JP106 keyboard + case ui::VKEY_DBE_DBCSCHAR: + input_method_ids_to_switch.push_back( + GetInputMethodIDByEngineID("nacl_mozc_jp")); + input_method_ids_to_switch.push_back( + GetInputMethodIDByEngineID("xkb:jp::jpn")); + break; + default: + break; + } + if (input_method_ids_to_switch.empty()) { + DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code(); + return std::vector<std::string>(); + } + + // Obtain the intersection of input_method_ids_to_switch and available_imes_. + for (const mojom::ImeInfo& ime : available_imes_) { + if (base::ContainsValue(input_method_ids_to_switch, ime.id)) + candidate_ids.push_back(ime.id); + } + return candidate_ids; +} + } // namespace ash
diff --git a/ash/ime/ime_controller.h b/ash/ime/ime_controller.h index ce967bbc..a9652b8 100644 --- a/ash/ime/ime_controller.h +++ b/ash/ime/ime_controller.h
@@ -42,11 +42,14 @@ // Binds the mojo interface to this object. void BindRequest(mojom::ImeControllerRequest request); - // TODO(jamescook): Implement these. http://crbug.com/724305 bool CanSwitchIme() const; void SwitchToNextIme(); void SwitchToPreviousIme(); + + // Returns true if the switch is allowed and the keystroke should be + // consumed. bool CanSwitchImeWithAccelerator(const ui::Accelerator& accelerator) const; + void SwitchImeWithAccelerator(const ui::Accelerator& accelerator); // mojom::ImeController: @@ -57,7 +60,15 @@ void SetImesManagedByPolicy(bool managed) override; void ShowImeMenuOnShelf(bool show) override; + void FlushMojoForTesting(); + private: + // Returns the IDs of the subset of input methods which are active and are + // associated with |accelerator|. For example, two Japanese IMEs can be + // returned for ui::VKEY_DBE_SBCSCHAR if both are active. + std::vector<std::string> GetCandidateImesForAccelerator( + const ui::Accelerator& accelerator) const; + // Bindings for users of the mojo interface. mojo::BindingSet<mojom::ImeController> bindings_;
diff --git a/ash/ime/ime_controller_unittest.cc b/ash/ime/ime_controller_unittest.cc index d6716cf..46a93cf 100644 --- a/ash/ime/ime_controller_unittest.cc +++ b/ash/ime/ime_controller_unittest.cc
@@ -11,10 +11,34 @@ #include "ash/system/ime/ime_observer.h" #include "ash/system/tray/system_tray_notifier.h" #include "ash/test/ash_test_base.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/ime/chromeos/extension_ime_util.h" +#include "ui/events/keycodes/keyboard_codes.h" namespace ash { namespace { +// Refreshes the IME list with fake IMEs and fake menu items. +void RefreshImes(const std::string& current_ime_id, + const std::vector<std::string>& ime_ids, + const std::vector<std::string>& menu_item_keys = + std::vector<std::string>()) { + std::vector<mojom::ImeInfoPtr> available_imes; + for (const std::string& ime_id : ime_ids) { + mojom::ImeInfoPtr ime = mojom::ImeInfo::New(); + ime->id = ime_id; + available_imes.push_back(std::move(ime)); + } + std::vector<mojom::ImeMenuItemPtr> menu_items; + for (const std::string& menu_item_key : menu_item_keys) { + mojom::ImeMenuItemPtr item = mojom::ImeMenuItem::New(); + item->key = menu_item_key; + menu_items.push_back(std::move(item)); + } + Shell::Get()->ime_controller()->RefreshIme( + current_ime_id, std::move(available_imes), std::move(menu_items)); +} + class TestImeObserver : public IMEObserver { public: TestImeObserver() = default; @@ -30,6 +54,37 @@ bool ime_menu_active_ = false; }; +class TestImeControllerClient : public mojom::ImeControllerClient { + public: + TestImeControllerClient() : binding_(this) {} + ~TestImeControllerClient() override = default; + + mojom::ImeControllerClientPtr CreateInterfacePtr() { + mojom::ImeControllerClientPtr ptr; + binding_.Bind(mojo::MakeRequest(&ptr)); + return ptr; + } + + // mojom::ImeControllerClient: + void SwitchToNextIme() override { ++next_ime_count_; } + void SwitchToPreviousIme() override { ++previous_ime_count_; } + void SwitchImeById(const std::string& id) override { + ++switch_ime_count_; + last_switch_ime_id_ = id; + } + void ActivateImeProperty(const std::string& key) override {} + + int next_ime_count_ = 0; + int previous_ime_count_ = 0; + int switch_ime_count_ = 0; + std::string last_switch_ime_id_; + + private: + mojo::Binding<mojom::ImeControllerClient> binding_; + + DISALLOW_COPY_AND_ASSIGN(TestImeControllerClient); +}; + using ImeControllerTest = test::AshTestBase; TEST_F(ImeControllerTest, RefreshIme) { @@ -37,23 +92,7 @@ TestImeObserver observer; Shell::Get()->system_tray_notifier()->AddIMEObserver(&observer); - mojom::ImeInfoPtr ime1 = mojom::ImeInfo::New(); - ime1->id = "ime1"; - mojom::ImeInfoPtr ime2 = mojom::ImeInfo::New(); - ime2->id = "ime2"; - - std::vector<mojom::ImeInfoPtr> available_imes; - available_imes.push_back(ime1.Clone()); - available_imes.push_back(ime2.Clone()); - - mojom::ImeMenuItemPtr item1 = mojom::ImeMenuItem::New(); - item1->key = "key1"; - - std::vector<mojom::ImeMenuItemPtr> menu_items; - menu_items.push_back(item1.Clone()); - - controller->RefreshIme("ime1", std::move(available_imes), - std::move(menu_items)); + RefreshImes("ime1", {"ime1", "ime2"}, {"menu1"}); // Cached data was updated. EXPECT_EQ("ime1", controller->current_ime().id); @@ -61,7 +100,7 @@ EXPECT_EQ("ime1", controller->available_imes()[0].id); EXPECT_EQ("ime2", controller->available_imes()[1].id); ASSERT_EQ(1u, controller->current_ime_menu_items().size()); - EXPECT_EQ("key1", controller->current_ime_menu_items()[0].key); + EXPECT_EQ("menu1", controller->current_ime_menu_items()[0].key); // Observer was notified. EXPECT_EQ(1, observer.refresh_count_); @@ -71,20 +110,12 @@ ImeController* controller = Shell::Get()->ime_controller(); // Set up a single IME. - mojom::ImeInfoPtr ime1 = mojom::ImeInfo::New(); - ime1->id = "ime1"; - std::vector<mojom::ImeInfoPtr> available_imes1; - available_imes1.push_back(ime1.Clone()); - controller->RefreshIme("ime1", std::move(available_imes1), - std::vector<mojom::ImeMenuItemPtr>()); + RefreshImes("ime1", {"ime1"}); EXPECT_EQ("ime1", controller->current_ime().id); // When there is no current IME the cached current IME is empty. - std::vector<mojom::ImeInfoPtr> available_imes2; - available_imes2.push_back(ime1.Clone()); const std::string empty_ime_id; - controller->RefreshIme(empty_ime_id, std::move(available_imes2), - std::vector<mojom::ImeMenuItemPtr>()); + RefreshImes(empty_ime_id, {"ime1"}); EXPECT_TRUE(controller->current_ime().id.empty()); } @@ -111,5 +142,105 @@ EXPECT_TRUE(observer.ime_menu_active_); } +TEST_F(ImeControllerTest, CanSwitchIme) { + ImeController* controller = Shell::Get()->ime_controller(); + + // Can't switch IMEs when none are available. + ASSERT_EQ(0u, controller->available_imes().size()); + EXPECT_FALSE(controller->CanSwitchIme()); + + // Can't switch with only 1 IME. + RefreshImes("ime1", {"ime1"}); + EXPECT_FALSE(controller->CanSwitchIme()); + + // Can switch with more than 1 IME. + RefreshImes("ime1", {"ime1", "ime2"}); + EXPECT_TRUE(controller->CanSwitchIme()); +} + +TEST_F(ImeControllerTest, SwitchIme) { + ImeController* controller = Shell::Get()->ime_controller(); + TestImeControllerClient client; + + // Can't switch IME before the client is set. + controller->SwitchToNextIme(); + EXPECT_EQ(0, client.next_ime_count_); + + controller->SwitchToPreviousIme(); + EXPECT_EQ(0, client.previous_ime_count_); + + // After setting the client the requests are forwarded. + controller->SetClient(client.CreateInterfacePtr()); + controller->SwitchToNextIme(); + controller->FlushMojoForTesting(); + EXPECT_EQ(1, client.next_ime_count_); + + controller->SwitchToPreviousIme(); + controller->FlushMojoForTesting(); + EXPECT_EQ(1, client.previous_ime_count_); +} + +TEST_F(ImeControllerTest, SwitchImeWithAccelerator) { + ImeController* controller = Shell::Get()->ime_controller(); + TestImeControllerClient client; + controller->SetClient(client.CreateInterfacePtr()); + + const ui::Accelerator convert(ui::VKEY_CONVERT, ui::EF_NONE); + const ui::Accelerator non_convert(ui::VKEY_NONCONVERT, ui::EF_NONE); + const ui::Accelerator wide_half_1(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE); + const ui::Accelerator wide_half_2(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE); + + // When there are no IMEs available switching by accelerator does not work. + ASSERT_EQ(0u, controller->available_imes().size()); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(convert)); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(non_convert)); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_1)); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_2)); + + // With only test IMEs (and no Japanese IMEs) the special keys do not work. + RefreshImes("ime1", {"ime1", "ime2"}); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(convert)); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(non_convert)); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_1)); + EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_2)); + + // Install both a test IME and Japanese IMEs. + using chromeos::extension_ime_util::GetInputMethodIDByEngineID; + const std::string nacl_mozc_jp = GetInputMethodIDByEngineID("nacl_mozc_jp"); + const std::string xkb_jp_jpn = GetInputMethodIDByEngineID("xkb:jp::jpn"); + RefreshImes("ime1", {"ime1", nacl_mozc_jp, xkb_jp_jpn}); + + // Accelerator based switching now works. + EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(convert)); + EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(non_convert)); + EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(wide_half_1)); + EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(wide_half_2)); + + // Convert keys jump directly to the requested IME. + controller->SwitchImeWithAccelerator(convert); + controller->FlushMojoForTesting(); + EXPECT_EQ(1, client.switch_ime_count_); + EXPECT_EQ(nacl_mozc_jp, client.last_switch_ime_id_); + + controller->SwitchImeWithAccelerator(non_convert); + controller->FlushMojoForTesting(); + EXPECT_EQ(2, client.switch_ime_count_); + EXPECT_EQ(xkb_jp_jpn, client.last_switch_ime_id_); + + // Switch from nacl_mozc_jp to xkb_jp_jpn. + RefreshImes(nacl_mozc_jp, {"ime1", nacl_mozc_jp, xkb_jp_jpn}); + controller->SwitchImeWithAccelerator(wide_half_1); + controller->FlushMojoForTesting(); + EXPECT_EQ(3, client.switch_ime_count_); + EXPECT_EQ(xkb_jp_jpn, client.last_switch_ime_id_); + + // Switch from xkb_jp_jpn to nacl_mozc_jp. + RefreshImes(xkb_jp_jpn, {"ime1", nacl_mozc_jp, xkb_jp_jpn}); + controller->SwitchImeWithAccelerator(wide_half_2); + controller->FlushMojoForTesting(); + EXPECT_EQ(4, client.switch_ime_count_); + EXPECT_EQ(nacl_mozc_jp, client.last_switch_ime_id_); +} + } // namespace } // namespace ash
diff --git a/ash/public/interfaces/ime_controller.mojom b/ash/public/interfaces/ime_controller.mojom index 549e5966..d66f415 100644 --- a/ash/public/interfaces/ime_controller.mojom +++ b/ash/public/interfaces/ime_controller.mojom
@@ -38,8 +38,10 @@ // method is installed. SwitchToPreviousIme(); - // Switches to an input method by |id| (for example, "xkb:jp::jpn"). Does - // nothing if the input method is not installed. + // Switches to an input method by |id|. Does nothing if the input method is + // not installed. The ID is usually the output of a call like + // chromeos::extension_ime_util::GetInputMethodIDByEngineID("xkb:jp::jpn"), + // see that function for details. SwitchImeById(string id); // Activates an input method property. These are settings that are provided by
diff --git a/ash/system/power/tablet_power_button_controller.cc b/ash/system/power/tablet_power_button_controller.cc index 0f8dea77..fafda54 100644 --- a/ash/system/power/tablet_power_button_controller.cc +++ b/ash/system/power/tablet_power_button_controller.cc
@@ -5,13 +5,19 @@ #include "ash/system/power/tablet_power_button_controller.h" #include "ash/accessibility_delegate.h" +#include "ash/ash_switches.h" #include "ash/session/session_controller.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/wm/lock_state_controller.h" #include "ash/wm/maximize_mode/maximize_mode_controller.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/time/default_tick_clock.h" #include "chromeos/dbus/dbus_thread_manager.h" +#include "ui/chromeos/accelerometer/accelerometer_util.h" #include "ui/events/devices/input_device_manager.h" #include "ui/events/devices/stylus_state.h" #include "ui/events/event.h" @@ -55,6 +61,36 @@ maximize_mode_controller->IsMaximizeModeWindowManagerEnabled(); } +// Returns the value for the command-line switch identified by |name|. Returns 0 +// if the switch was unset or contained a non-float value. +double GetNumSwitch(const base::CommandLine& command_line, + const std::string& name) { + std::string str = command_line.GetSwitchValueASCII(name); + if (str.empty()) + return 0.0; + + double value = 0.0; + if (!base::StringToDouble(str, &value)) { + LOG(WARNING) << "Failed to parse value \"" << str << "\" from switch " + << "--" << name << " as float"; + return 0.0; + } + return value; +} + +// Computes the lid angle based on readings from accelerometers in the screen +// and keyboard panels. +float GetLidAngle(const gfx::Vector3dF& screen, + const gfx::Vector3dF& keyboard) { + constexpr gfx::Vector3dF kHingeVector(1.0f, 0.0f, 0.0f); + float lid_angle = 180.0f - gfx::ClockwiseAngleBetweenVectorsInDegrees( + keyboard, screen, kHingeVector); + if (lid_angle < 0.0f) + lid_angle += 360.0f; + + return lid_angle; +} + } // namespace TabletPowerButtonController::TestApi::TestApi( @@ -73,10 +109,26 @@ controller_->shutdown_timer_.Stop(); } +bool TabletPowerButtonController::TestApi::IsObservingAccelerometerReader( + chromeos::AccelerometerReader* reader) const { + DCHECK(reader); + return controller_->accelerometer_scoped_observer_.IsObserving(reader); +} + +void TabletPowerButtonController::TestApi::ParseSpuriousPowerButtonSwitches( + const base::CommandLine& command_line) { + controller_->ParseSpuriousPowerButtonSwitches(command_line); +} + +bool TabletPowerButtonController::TestApi::IsSpuriousPowerButtonEvent() const { + return controller_->IsSpuriousPowerButtonEvent(); +} + TabletPowerButtonController::TabletPowerButtonController( LockStateController* controller) : tick_clock_(new base::DefaultTickClock()), controller_(controller), + accelerometer_scoped_observer_(this), weak_ptr_factory_(this) { chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( this); @@ -87,6 +139,7 @@ ui::InputDeviceManager::GetInstance()->AddObserver(this); Shell::Get()->PrependPreTargetHandler(this); + ParseSpuriousPowerButtonSwitches(*base::CommandLine::ForCurrentProcess()); GetInitialBacklightsForcedOff(); } @@ -107,6 +160,11 @@ bool down, const base::TimeTicks& timestamp) { if (down) { + if ((power_button_down_was_spurious_ = IsSpuriousPowerButtonEvent())) { + LOG(WARNING) << "Ignoring spurious power button down event"; + return; + } + force_off_on_button_up_ = true; // When the system resumes in response to the power button being pressed, // Chrome receives powerd's SuspendDone signal and notification that the @@ -121,6 +179,10 @@ SetDisplayForcedOff(false); StartShutdownTimer(); } else { + // Don't process the up event if we previously ignored the down event. + if (power_button_down_was_spurious_) + return; + // When power button is released, cancel shutdown animation whenever it is // still cancellable. if (controller_->CanCancelShutdownAnimation()) @@ -145,6 +207,25 @@ } } +void TabletPowerButtonController::OnAccelerometerUpdated( + scoped_refptr<const chromeos::AccelerometerUpdate> update) { + const gfx::Vector3dF screen = ui::ConvertAccelerometerReadingToVector3dF( + update->get(chromeos::ACCELEROMETER_SOURCE_SCREEN)); + const gfx::Vector3dF keyboard = ui::ConvertAccelerometerReadingToVector3dF( + update->get(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)); + + DCHECK_GT(max_accelerometer_samples_, 0u); + if (accelerometer_samples_.size() < max_accelerometer_samples_) { + accelerometer_samples_.push_back(std::make_pair(screen, keyboard)); + last_accelerometer_sample_index_ = accelerometer_samples_.size() - 1; + } else { + last_accelerometer_sample_index_ = + (last_accelerometer_sample_index_ + 1) % max_accelerometer_samples_; + accelerometer_samples_[last_accelerometer_sample_index_] = + std::make_pair(screen, keyboard); + } +} + void TabletPowerButtonController::PowerManagerRestarted() { chromeos::DBusThreadManager::Get() ->GetPowerManagerClient() @@ -213,6 +294,114 @@ tick_clock_ = std::move(tick_clock); } +void TabletPowerButtonController::ParseSpuriousPowerButtonSwitches( + const base::CommandLine& command_line) { + // Support being called multiple times from tests. + max_accelerometer_samples_ = 0; + accelerometer_samples_.clear(); + accelerometer_scoped_observer_.RemoveAll(); + + int window = static_cast<int>( + GetNumSwitch(command_line, switches::kSpuriousPowerButtonWindow)); + if (window <= 0) + return; + + max_accelerometer_samples_ = static_cast<size_t>(window); + accelerometer_samples_.reserve(max_accelerometer_samples_); + accelerometer_scoped_observer_.Add( + chromeos::AccelerometerReader::GetInstance()); + + spurious_accel_count_ = static_cast<size_t>( + GetNumSwitch(command_line, switches::kSpuriousPowerButtonAccelCount)); + spurious_screen_accel_ = + GetNumSwitch(command_line, switches::kSpuriousPowerButtonScreenAccel); + spurious_keyboard_accel_ = + GetNumSwitch(command_line, switches::kSpuriousPowerButtonKeyboardAccel); + spurious_lid_angle_change_ = + GetNumSwitch(command_line, switches::kSpuriousPowerButtonLidAngleChange); +} + +bool TabletPowerButtonController::IsSpuriousPowerButtonEvent() const { + if (max_accelerometer_samples_ <= 0) + return false; + + // Number of screen and keyboard accelerations exceeding the threshold. + size_t num_big_screen_accels = 0; + size_t num_big_keyboard_accels = 0; + + // The last lid angle that we saw. + float last_angle = 0.0f; + // The current distance (in degrees) that we've traveled from the starting + // angle and the max distance that we've seen so far. + float cur_angle_dist = 0.0f, max_angle_dist = 0.0f; + + std::string screen_debug, keyboard_debug, angle_debug; + + // Get the index of the oldest pair of samples. + const size_t start = + accelerometer_samples_.size() == max_accelerometer_samples_ + ? (last_accelerometer_sample_index_ + 1) % max_accelerometer_samples_ + : 0; + for (size_t i = 0; i < accelerometer_samples_.size(); ++i) { + const auto& pair = + accelerometer_samples_[(start + i) % max_accelerometer_samples_]; + const gfx::Vector3dF& screen = pair.first; + const gfx::Vector3dF& keyboard = pair.second; + + const float screen_accel = std::abs(screen.Length() - kGravity); + if (spurious_screen_accel_ > 0 && screen_accel >= spurious_screen_accel_) + num_big_screen_accels++; + + const float keyboard_accel = std::abs(keyboard.Length() - kGravity); + if (spurious_keyboard_accel_ > 0 && + keyboard_accel >= spurious_keyboard_accel_) { + num_big_keyboard_accels++; + } + + float angle = GetLidAngle(screen, keyboard); + if (i > 0u) { + // Lid angle readings are computed based on the screen and keyboard + // acceleration vectors and can be noisy. Compute the minimum angle + // difference between the previous reading and the current one and use it + // to maintain a running total of how far the lid has traveled, also + // keeping track of the max distance from the start that we've seen. + float min_diff = angle - last_angle; + if (min_diff < -180.0f) + min_diff += 360.0f; + else if (min_diff > 180.0f) + min_diff -= 360.0f; + + cur_angle_dist += min_diff; + max_angle_dist = + std::min(std::max(max_angle_dist, std::abs(cur_angle_dist)), 360.0f); + } + last_angle = angle; + + if (VLOG_IS_ON(1)) { + screen_debug = base::StringPrintf("%0.1f", screen_accel) + + (screen_debug.empty() ? "" : " " + screen_debug); + keyboard_debug = base::StringPrintf("%0.1f", keyboard_accel) + + (keyboard_debug.empty() ? "" : " " + keyboard_debug); + angle_debug = base::IntToString(static_cast<int>(angle + 0.5)) + + (angle_debug.empty() ? "" : " " + angle_debug); + } + } + + VLOG(1) << "Screen accelerations (" << num_big_screen_accels << " big): " + << "[" << screen_debug << "]"; + VLOG(1) << "Keyboard accelerations (" << num_big_keyboard_accels << " big): " + << "[" << keyboard_debug << "]"; + VLOG(1) << "Lid angles (" << base::StringPrintf("%0.1f", max_angle_dist) + << " degrees): [" << angle_debug << "]"; + + return (spurious_screen_accel_ > 0 && + num_big_screen_accels >= spurious_accel_count_) || + (spurious_keyboard_accel_ > 0 && + num_big_keyboard_accels >= spurious_accel_count_) || + (spurious_lid_angle_change_ > 0 && + max_angle_dist >= spurious_lid_angle_change_); +} + void TabletPowerButtonController::SetDisplayForcedOff(bool forced_off) { if (backlights_forced_off_ == forced_off) return;
diff --git a/ash/system/power/tablet_power_button_controller.h b/ash/system/power/tablet_power_button_controller.h index 69d32cc1..ab89f72 100644 --- a/ash/system/power/tablet_power_button_controller.h +++ b/ash/system/power/tablet_power_button_controller.h
@@ -6,17 +6,26 @@ #define ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_ #include <memory> +#include <utility> #include "ash/ash_export.h" #include "ash/shell_observer.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observer.h" #include "base/time/tick_clock.h" #include "base/time/time.h" #include "base/timer/timer.h" +#include "chromeos/accelerometer/accelerometer_reader.h" +#include "chromeos/accelerometer/accelerometer_types.h" #include "chromeos/dbus/power_manager_client.h" #include "ui/events/devices/input_device_event_observer.h" #include "ui/events/event_handler.h" +#include "ui/gfx/geometry/vector3d_f.h" + +namespace base { +class CommandLine; +} // namespace base namespace ash { @@ -25,7 +34,8 @@ // Handles power button events on convertible/tablet device. This class is // instantiated and used in PowerButtonController. class ASH_EXPORT TabletPowerButtonController - : public chromeos::PowerManagerClient::Observer, + : public chromeos::AccelerometerReader::Observer, + public chromeos::PowerManagerClient::Observer, public ShellObserver, public ui::EventHandler, public ui::InputDeviceEventObserver { @@ -42,12 +52,26 @@ // Emulates |shutdown_timer_| timeout. void TriggerShutdownTimeout(); + // Returns true if |controller_| is observing |reader|. + bool IsObservingAccelerometerReader( + chromeos::AccelerometerReader* reader) const; + + // Calls |controller_|'s ParseSpuriousPowerButtonSwitches() method. + void ParseSpuriousPowerButtonSwitches( + const base::CommandLine& command_line); + + // Calls |controller_|'s IsSpuriousPowerButtonEvent() method. + bool IsSpuriousPowerButtonEvent() const; + private: TabletPowerButtonController* controller_; // Not owned. DISALLOW_COPY_AND_ASSIGN(TestApi); }; + // Public for tests. + static constexpr float kGravity = 9.80665f; + explicit TabletPowerButtonController(LockStateController* controller); ~TabletPowerButtonController() override; @@ -58,6 +82,10 @@ // Handles a power button event. void OnPowerButtonEvent(bool down, const base::TimeTicks& timestamp); + // Overridden from chromeos::AccelerometerReader::Observer: + void OnAccelerometerUpdated( + scoped_refptr<const chromeos::AccelerometerUpdate> update) override; + // Overridden from chromeos::PowerManagerClient::Observer: void PowerManagerRestarted() override; void BrightnessChanged(int level, bool user_initiated) override; @@ -80,6 +108,15 @@ void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); private: + // Parses command-line switches that provide settings used to attempt to + // ignore accidental power button presses by looking at accelerometer data. + void ParseSpuriousPowerButtonSwitches(const base::CommandLine& command_line); + + // Returns true if the device's accelerometers have reported enough recent + // movement that we should consider a power button event that was just + // received to be accidental and ignore it. + bool IsSpuriousPowerButtonEvent() const; + // Updates the power manager's backlights-forced-off state and enables or // disables the touchscreen. No-op if |backlights_forced_off_| already equals // |forced_off|. @@ -116,6 +153,10 @@ // True if the screen was off when the power button was pressed. bool screen_off_when_power_button_down_ = false; + // True if the last power button down event was deemed spurious and ignored as + // a result. + bool power_button_down_was_spurious_ = false; + // Time source for performed action times. std::unique_ptr<base::TickClock> tick_clock_; @@ -135,6 +176,30 @@ LockStateController* controller_; // Not owned. + ScopedObserver<chromeos::AccelerometerReader, TabletPowerButtonController> + accelerometer_scoped_observer_; + + // Number of recent screen and keyboard accelerometer samples to retain. + size_t max_accelerometer_samples_ = 0; + + // Circular buffer of recent (screen, keyboard) accelerometer samples. + std::vector<std::pair<gfx::Vector3dF, gfx::Vector3dF>> accelerometer_samples_; + size_t last_accelerometer_sample_index_ = 0; + + // Number of acceleration readings in |accelerometer_samples_| that must + // exceed the threshold in order for a power button event to be considered + // spurious. + size_t spurious_accel_count_ = 0; + + // Thresholds for screen and keyboard accelerations (excluding gravity). See + // |spurious_accel_count_|. + float spurious_screen_accel_ = 0; + float spurious_keyboard_accel_ = 0; + + // Threshold for the lid angle change seen within |accelerometer_samples_| + // in order for a power button event to be considered spurious. + float spurious_lid_angle_change_ = 0; + base::WeakPtrFactory<TabletPowerButtonController> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonController);
diff --git a/ash/system/power/tablet_power_button_controller_unittest.cc b/ash/system/power/tablet_power_button_controller_unittest.cc index 526c9349..7a834405 100644 --- a/ash/system/power/tablet_power_button_controller_unittest.cc +++ b/ash/system/power/tablet_power_button_controller_unittest.cc
@@ -35,6 +35,18 @@ // A non-zero brightness used for test. constexpr int kNonZeroBrightness = 10; +// Vector pointing up (e.g. keyboard in clamshell). +constexpr gfx::Vector3dF kUpVector = {0, 0, + TabletPowerButtonController::kGravity}; + +// Vector pointing down (e.g. keyboard in tablet sitting on table). +constexpr gfx::Vector3dF kDownVector = {0, 0, + -TabletPowerButtonController::kGravity}; + +// Vector pointing sideways (e.g. screen in 90-degree clamshell). +constexpr gfx::Vector3dF kSidewaysVector = { + 0, TabletPowerButtonController::kGravity, 0}; + void CopyResult(bool* dest, bool src) { *dest = src; } @@ -57,7 +69,7 @@ AshTestBase::SetUp(); // Trigger an accelerometer update so that |tablet_controller_| can be // initialized. - SendAccelerometerUpdate(); + SendAccelerometerUpdate(kSidewaysVector, kUpVector); tablet_controller_ = Shell::Get() ->power_button_controller() ->tablet_power_button_controller_for_test(); @@ -87,11 +99,32 @@ } protected: - void SendAccelerometerUpdate() { + // Resets the TabletPowerButtonController and associated members. + void ResetTabletPowerButtonController() { + test_api_ = nullptr; + tablet_controller_ = nullptr; + Shell::Get() + ->power_button_controller() + ->ResetTabletPowerButtonControllerForTest(); + } + + // Sends an update with screen and keyboard accelerometer readings to + // PowerButtonController, and also |tablet_controller_| if it's non-null and + // has registered as an observer. + void SendAccelerometerUpdate(const gfx::Vector3dF& screen, + const gfx::Vector3dF& keyboard) { scoped_refptr<chromeos::AccelerometerUpdate> update( new chromeos::AccelerometerUpdate()); - update->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, 1.0f, 0.0f, 0.0f); + update->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, screen.x(), screen.y(), + screen.z()); + update->Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, keyboard.x(), + keyboard.y(), keyboard.z()); + Shell::Get()->power_button_controller()->OnAccelerometerUpdated(update); + + if (test_api_ && test_api_->IsObservingAccelerometerReader( + chromeos::AccelerometerReader::GetInstance())) + tablet_controller_->OnAccelerometerUpdated(update); } void PressPowerButton() { @@ -134,14 +167,14 @@ } // Ownership is passed on to chromeos::DBusThreadManager. - chromeos::FakePowerManagerClient* power_manager_client_; + chromeos::FakePowerManagerClient* power_manager_client_ = nullptr; - LockStateController* lock_state_controller_; // Not owned. - TabletPowerButtonController* tablet_controller_; // Not owned. + LockStateController* lock_state_controller_ = nullptr; // Not owned. + TabletPowerButtonController* tablet_controller_ = nullptr; // Not owned. std::unique_ptr<TabletPowerButtonController::TestApi> test_api_; std::unique_ptr<LockStateControllerTestApi> lock_state_test_api_; - base::SimpleTestTickClock* tick_clock_; // Not owned. - TestShellDelegate* shell_delegate_; // Not owned. + base::SimpleTestTickClock* tick_clock_ = nullptr; // Not owned. + TestShellDelegate* shell_delegate_ = nullptr; // Not owned. ui::test::EventGenerator* generator_ = nullptr; DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonControllerTest); @@ -527,10 +560,8 @@ // Simulate system reboot by resetting backlights forced off state in powerd // and TabletPowerButtonController. power_manager_client_->SetBacklightsForcedOff(false); - Shell::Get() - ->power_button_controller() - ->ResetTabletPowerButtonControllerForTest(); - SendAccelerometerUpdate(); + ResetTabletPowerButtonController(); + SendAccelerometerUpdate(kSidewaysVector, kSidewaysVector); // Check that the local state of touchscreen enabled state is in line with // backlights forced off state. @@ -542,19 +573,93 @@ // accelerometer update, otherwise it is disabled. TEST_F(TabletPowerButtonControllerTest, EnableOnAccelerometerUpdate) { ASSERT_TRUE(tablet_controller_); - Shell::Get() - ->power_button_controller() - ->ResetTabletPowerButtonControllerForTest(); - tablet_controller_ = Shell::Get() - ->power_button_controller() - ->tablet_power_button_controller_for_test(); - EXPECT_FALSE(tablet_controller_); + ResetTabletPowerButtonController(); + EXPECT_FALSE(Shell::Get() + ->power_button_controller() + ->tablet_power_button_controller_for_test()); - SendAccelerometerUpdate(); - tablet_controller_ = Shell::Get() - ->power_button_controller() - ->tablet_power_button_controller_for_test(); - EXPECT_TRUE(tablet_controller_); + SendAccelerometerUpdate(kSidewaysVector, kSidewaysVector); + EXPECT_TRUE(Shell::Get() + ->power_button_controller() + ->tablet_power_button_controller_for_test()); +} + +TEST_F(TabletPowerButtonControllerTest, IgnoreSpuriousEventsForAcceleration) { + base::CommandLine cl(base::CommandLine::NO_PROGRAM); + cl.AppendSwitchASCII(switches::kSpuriousPowerButtonWindow, "3"); + cl.AppendSwitchASCII(switches::kSpuriousPowerButtonAccelCount, "2"); + cl.AppendSwitchASCII(switches::kSpuriousPowerButtonKeyboardAccel, "4.5"); + cl.AppendSwitchASCII(switches::kSpuriousPowerButtonScreenAccel, "8.0"); + test_api_->ParseSpuriousPowerButtonSwitches(cl); + ASSERT_FALSE(test_api_->IsSpuriousPowerButtonEvent()); + + // Vectors with varying amounts of acceleration beyond gravity. + static constexpr gfx::Vector3dF kVector0 = { + 0, 0, TabletPowerButtonController::kGravity}; + static constexpr gfx::Vector3dF kVector3 = { + 0, 0, TabletPowerButtonController::kGravity + 3}; + static constexpr gfx::Vector3dF kVector5 = { + 0, 0, TabletPowerButtonController::kGravity + 5}; + static constexpr gfx::Vector3dF kVector9 = { + 0, 0, TabletPowerButtonController::kGravity + 9}; + + // Send two keyboard readings with vectors that exceed the threshold after + // subtracting gravity. + SendAccelerometerUpdate(kVector0, kVector5); + SendAccelerometerUpdate(kVector0, kVector9); + EXPECT_TRUE(test_api_->IsSpuriousPowerButtonEvent()); + + // Now send two more keyboard readings that are close to gravity. We only have + // one large reading saved now, so we should permit power button events again. + SendAccelerometerUpdate(kVector0, kVector0); + SendAccelerometerUpdate(kVector0, kVector0); + EXPECT_FALSE(test_api_->IsSpuriousPowerButtonEvent()); + + // Send a few large screen vectors and check that the button is again blocked. + SendAccelerometerUpdate(kVector9, kVector0); + SendAccelerometerUpdate(kVector9, kVector0); + EXPECT_TRUE(test_api_->IsSpuriousPowerButtonEvent()); +} + +TEST_F(TabletPowerButtonControllerTest, IgnoreSpuriousEventsForLidAngle) { + base::CommandLine cl(base::CommandLine::NO_PROGRAM); + cl.AppendSwitchASCII(switches::kSpuriousPowerButtonWindow, "5"); + cl.AppendSwitchASCII(switches::kSpuriousPowerButtonLidAngleChange, "200"); + test_api_->ParseSpuriousPowerButtonSwitches(cl); + ASSERT_FALSE(test_api_->IsSpuriousPowerButtonEvent()); + + // Send two updates in tablet mode with the screen facing up and the keyboard + // facing down (i.e. 360 degrees between the two). + SendAccelerometerUpdate(kUpVector, kDownVector); + SendAccelerometerUpdate(kUpVector, kDownVector); + EXPECT_FALSE(test_api_->IsSpuriousPowerButtonEvent()); + + // Now keep the screen facing up and report the keyboard as being sideways, as + // if it's been rotated 90 degrees. + SendAccelerometerUpdate(kUpVector, kSidewaysVector); + EXPECT_FALSE(test_api_->IsSpuriousPowerButtonEvent()); + + // Make the keyboard also face up (180 degrees from start). + SendAccelerometerUpdate(kUpVector, kUpVector); + EXPECT_FALSE(test_api_->IsSpuriousPowerButtonEvent()); + + // Now make the screen face sideways, completing the 270-degree change to + // a clamshell orientation. We've exceeded the threshold over the last four + // samples, so events should be ignored. + SendAccelerometerUpdate(kSidewaysVector, kUpVector); + EXPECT_TRUE(test_api_->IsSpuriousPowerButtonEvent()); + + // Make the screen travel 90 more degrees so the lid is closed (360 degrees + // from start). + SendAccelerometerUpdate(kDownVector, kUpVector); + EXPECT_TRUE(test_api_->IsSpuriousPowerButtonEvent()); + + // After two more closed samples, the 5-sample buffer just contains a + // 180-degree transition, so events should be accepted again. + SendAccelerometerUpdate(kDownVector, kUpVector); + EXPECT_TRUE(test_api_->IsSpuriousPowerButtonEvent()); + SendAccelerometerUpdate(kDownVector, kUpVector); + EXPECT_FALSE(test_api_->IsSpuriousPowerButtonEvent()); } // Tests that when backlights get forced off due to tablet power button, media
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc index a9c8156..77cc034 100644 --- a/ash/system/tray/system_tray.cc +++ b/ash/system/tray/system_tray.cc
@@ -52,6 +52,7 @@ #include "ash/system/user/tray_user.h" #include "ash/system/web_notification/web_notification_tray.h" #include "ash/wm/container_finder.h" +#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/widget_finder.h" #include "base/logging.h" #include "base/memory/ptr_util.h" @@ -169,8 +170,10 @@ int container_id = wm::GetContainerForWindow(gained_active)->id(); // Don't close the bubble if a popup notification is activated. - if (container_id == kShellWindowId_StatusContainer) + if (container_id == kShellWindowId_StatusContainer || + container_id == kShellWindowId_SettingBubbleContainer) { return; + } views::Widget* bubble_widget = tray_->GetSystemBubble()->bubble_view()->GetWidget(); @@ -195,7 +198,8 @@ // SystemTray -SystemTray::SystemTray(Shelf* shelf) : TrayBackgroundView(shelf) { +SystemTray::SystemTray(Shelf* shelf) + : TrayBackgroundView(shelf), shelf_(shelf) { SetInkDropMode(InkDropMode::ON); // Since user avatar is on the right hand side of System tray of a @@ -620,6 +624,21 @@ bubble_view->GetWidget()->Activate(); } +void SystemTray::OnGestureEvent(ui::GestureEvent* event) { + if (Shell::Get() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled() && + shelf_->IsHorizontalAlignment() && ProcessGestureEvent(*event)) { + event->SetHandled(); + } else { + TrayBackgroundView::OnGestureEvent(event); + } +} + +gfx::Rect SystemTray::GetWorkAreaBoundsInScreen() const { + return shelf_->GetUserWorkAreaBounds(); +} + bool SystemTray::PerformAction(const ui::Event& event) { // If we're already showing a full system tray menu, either default or // detailed menu, hide it; otherwise, show it (and hide any popup that's @@ -634,6 +653,96 @@ return true; } +bool SystemTray::ProcessGestureEvent(const ui::GestureEvent& event) { + if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) + return StartGestureDrag(event); + + if (!HasSystemBubble() || !is_in_drag_) + return false; + + if (event.type() == ui::ET_GESTURE_SCROLL_UPDATE) { + UpdateGestureDrag(event); + return true; + } + + if (event.type() == ui::ET_GESTURE_SCROLL_END || + event.type() == ui::ET_SCROLL_FLING_START) { + CompleteGestureDrag(event); + return true; + } + + // Unexpected event. Reset the drag state and close the bubble. + is_in_drag_ = false; + CloseSystemBubble(); + return false; +} + +bool SystemTray::StartGestureDrag(const ui::GestureEvent& gesture) { + // Close the system bubble if there is already a full one opened. And return + // false to let shelf handle the event. + if (HasSystemBubble() && full_system_tray_menu_) { + system_bubble_->bubble()->Close(); + return false; + } + + // If the scroll sequence begins to scroll downward, return false so that the + // event will instead by handled by the shelf. + if (gesture.details().scroll_y_hint() > 0) + return false; + + is_in_drag_ = true; + gesture_drag_amount_ = 0.f; + ShowDefaultView(BUBBLE_CREATE_NEW); + system_tray_bubble_bounds_ = + system_bubble_->bubble_view()->GetWidget()->GetWindowBoundsInScreen(); + SetBubbleBounds(gesture.location()); + return true; +} + +void SystemTray::UpdateGestureDrag(const ui::GestureEvent& gesture) { + SetBubbleBounds(gesture.location()); + gesture_drag_amount_ += gesture.details().scroll_y(); +} + +void SystemTray::CompleteGestureDrag(const ui::GestureEvent& gesture) { + const bool hide_bubble = !ShouldShowSystemBubbleAfterScrollSequence(gesture); + gfx::Rect target_bounds = system_tray_bubble_bounds_; + + if (hide_bubble) + target_bounds.set_y(shelf_->GetIdealBounds().y()); + + system_bubble_->bubble()->AnimateToTargetBounds(target_bounds, hide_bubble); + is_in_drag_ = false; +} + +void SystemTray::SetBubbleBounds(const gfx::Point& location) { + gfx::Point location_in_screen_coordinates(location); + View::ConvertPointToScreen(this, &location_in_screen_coordinates); + + // System tray bubble should not be dragged higher than its original height. + if (location_in_screen_coordinates.y() < system_tray_bubble_bounds_.y()) + location_in_screen_coordinates.set_y(system_tray_bubble_bounds_.y()); + + gfx::Rect bounds_on_location = system_tray_bubble_bounds_; + bounds_on_location.set_y(location_in_screen_coordinates.y()); + system_bubble_->bubble_view()->GetWidget()->SetBounds(bounds_on_location); +} + +bool SystemTray::ShouldShowSystemBubbleAfterScrollSequence( + const ui::GestureEvent& sequence_end) { + // If the scroll sequence terminates with a fling, show the system menu if the + // fling was fast enough and in the correct direction. + if (sequence_end.type() == ui::ET_SCROLL_FLING_START && + fabs(sequence_end.details().velocity_y()) > kFlingVelocity) { + return sequence_end.details().velocity_y() < 0; + } + + DCHECK(sequence_end.type() == ui::ET_GESTURE_SCROLL_END || + sequence_end.type() == ui::ET_SCROLL_FLING_START); + // Show the system menu if it is already at least one-third visible. + return -gesture_drag_amount_ >= system_tray_bubble_bounds_.height() / 3.0; +} + void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() { activation_observer_.reset(); system_bubble_.reset();
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h index 8483db92..fe8a0fd 100644 --- a/ash/system/tray/system_tray.h +++ b/ash/system/tray/system_tray.h
@@ -46,6 +46,9 @@ class ASH_EXPORT SystemTray : public TrayBackgroundView, public views::TrayBubbleView::Delegate { public: + // The threshold of the velocity of the fling event. + static constexpr float kFlingVelocity = 100.0f; + explicit SystemTray(Shelf* shelf); ~SystemTray() override; @@ -146,6 +149,11 @@ // Activates the system tray bubble. void ActivateBubble(); + // ui::EventHandler: + void OnGestureEvent(ui::GestureEvent* event) override; + + gfx::Rect GetWorkAreaBoundsInScreen() const; + private: friend class SystemTrayTestApi; class ActivationObserver; @@ -193,6 +201,37 @@ // Overridden from ActionableView. bool PerformAction(const ui::Event& event) override; + // Gesture related functions: + bool ProcessGestureEvent(const ui::GestureEvent& event); + bool StartGestureDrag(const ui::GestureEvent& gesture); + void UpdateGestureDrag(const ui::GestureEvent& gesture); + void CompleteGestureDrag(const ui::GestureEvent& gesture); + + // Update the bounds of the system tray bubble according to |location|. Note + // that |location| is in the local coordinate space of |this|. + void SetBubbleBounds(const gfx::Point& location); + + // Return true if the system bubble should be shown (i.e., animated upward to + // be made fully visible) after a sequence of scroll events terminated by + // |sequence_end|. Otherwise return false, indicating that the + // partially-visible system bubble should be animated downward and made fully + // hidden. + bool ShouldShowSystemBubbleAfterScrollSequence( + const ui::GestureEvent& sequence_end); + + // Shelf the system tray is in. + Shelf* const shelf_; + + // The original bounds of the system tray bubble. + gfx::Rect system_tray_bubble_bounds_; + + // Tracks the amount of the drag. Only valid if |is_in_drag_| is true. + float gesture_drag_amount_ = 0.f; + + // True if the user is in the process of gesture-dragging to open the system + // tray bubble, false otherwise. + bool is_in_drag_ = false; + // The web notification tray view that appears adjacent to this view. WebNotificationTray* web_notification_tray_ = nullptr;
diff --git a/ash/system/tray/system_tray_bubble.cc b/ash/system/tray/system_tray_bubble.cc index bd639391..a9036cd 100644 --- a/ash/system/tray/system_tray_bubble.cc +++ b/ash/system/tray/system_tray_bubble.cc
@@ -15,6 +15,7 @@ #include "ash/system/tray/system_tray_item.h" #include "ash/system/tray/tray_bubble_wrapper.h" #include "ash/system/tray/tray_constants.h" +#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/metrics/histogram_macros.h" #include "base/threading/thread_task_runner_handle.h" #include "ui/compositor/layer.h" @@ -68,6 +69,26 @@ } // namespace +// CloseBubbleObserver is used to delay closing the system tray bubble until the +// animation completes. +class CloseBubbleObserver : public ui::ImplicitAnimationObserver { + public: + explicit CloseBubbleObserver(SystemTrayBubble* system_tray_bubble) + : system_tray_bubble_(system_tray_bubble) {} + + ~CloseBubbleObserver() override {} + + void OnImplicitAnimationsCompleted() override { + system_tray_bubble_->Close(); + delete this; + } + + private: + SystemTrayBubble* system_tray_bubble_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(CloseBubbleObserver); +}; + // SystemTrayBubble SystemTrayBubble::SystemTrayBubble( @@ -200,8 +221,27 @@ } init_params->delegate = tray_; - // Place the bubble on same display as this system tray. - init_params->parent_window = tray_->GetBubbleWindowContainer(); + // Place the bubble on same display as this system tray if it is not on + // maximize mode. Otherwise, create an clipping window to hold the system + // bubble. And place the clipping window on the same display as the system + // tray. + if (Shell::Get() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled()) { + if (!clipping_window_.get()) { + clipping_window_ = + std::unique_ptr<aura::Window>(new aura::Window(nullptr)); + clipping_window_->Init(ui::LAYER_NOT_DRAWN); + clipping_window_->layer()->SetMasksToBounds(true); + tray_->GetBubbleWindowContainer()->AddChild(clipping_window_.get()); + clipping_window_->Show(); + } + clipping_window_->SetBounds(tray_->GetWorkAreaBoundsInScreen()); + init_params->parent_window = clipping_window_.get(); + } else { + init_params->parent_window = tray_->GetBubbleWindowContainer(); + } + init_params->anchor_view = anchor; bubble_view_ = new TrayBubbleView(*init_params); UpdateBottomPadding(); @@ -290,6 +330,22 @@ } } +void SystemTrayBubble::AnimateToTargetBounds(const gfx::Rect& target_bounds, + bool close_bubble) { + const int kAnimationDurationMS = 200; + + ui::ScopedLayerAnimationSettings settings( + bubble_view()->GetWidget()->GetNativeView()->layer()->GetAnimator()); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationMS)); + settings.SetTweenType(gfx::Tween::EASE_OUT); + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + if (close_bubble) + settings.AddObserver(new CloseBubbleObserver(this)); + bubble_view()->GetWidget()->SetBounds(target_bounds); +} + void SystemTrayBubble::UpdateBottomPadding() { if (bubble_type_ == BUBBLE_TYPE_DEFAULT) bubble_view_->SetBottomPadding(kDefaultViewBottomPadding);
diff --git a/ash/system/tray/system_tray_bubble.h b/ash/system/tray/system_tray_bubble.h index 3ee439d..89c490f 100644 --- a/ash/system/tray/system_tray_bubble.h +++ b/ash/system/tray/system_tray_bubble.h
@@ -58,6 +58,10 @@ // BUBBLE_TYPE_DEFAULT BubbleType. void RecordVisibleRowMetrics(); + // Update the bounds of the system tray bubble. Close the bubble if + // |close_bubble| is set. + void AnimateToTargetBounds(const gfx::Rect& target_bounds, bool close_bubble); + private: // Updates the bottom padding of the |bubble_view_| based on the // |bubble_type_|. @@ -75,6 +79,10 @@ int autoclose_delay_; base::OneShotTimer autoclose_; + // Used in maximize mode to make sure the system tray bubble only be shown in + // work area. + std::unique_ptr<aura::Window> clipping_window_; + DISALLOW_COPY_AND_ASSIGN(SystemTrayBubble); };
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc index c8dc570c..771e4de 100644 --- a/ash/system/tray/system_tray_unittest.cc +++ b/ash/system/tray/system_tray_unittest.cc
@@ -12,6 +12,7 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/shelf/shelf.h" +#include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/system/status_area_widget.h" #include "ash/system/tray/system_tray_bubble.h" @@ -21,6 +22,7 @@ #include "ash/test/ash_test_base.h" #include "ash/test/status_area_widget_test_helper.h" #include "ash/test/test_system_tray_item.h" +#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" @@ -56,7 +58,267 @@ } // namespace -typedef AshTestBase SystemTrayTest; +class SystemTrayTest : public AshTestBase { + public: + SystemTrayTest() {} + ~SystemTrayTest() override {} + + // Swiping on the system tray and ends with finger released. + void SendGestureEvent(gfx::Point& start, + float delta, + bool is_fling, + float velocity_y) { + SystemTray* system_tray = GetPrimarySystemTray(); + base::TimeTicks timestamp = base::TimeTicks::Now(); + SendScrollStartAndUpdate(start, delta, timestamp); + + ui::GestureEventDetails details = + is_fling + ? ui::GestureEventDetails(ui::ET_SCROLL_FLING_START, 0, velocity_y) + : ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END); + ui::GestureEvent event = ui::GestureEvent(start.x(), start.y() + delta, + ui::EF_NONE, timestamp, details); + system_tray->OnGestureEvent(&event); + } + + // Swiping on the system tray without releasing the finger. + void SendScrollStartAndUpdate(gfx::Point& start, + float delta, + base::TimeTicks& timestamp) { + SystemTray* system_tray = GetPrimarySystemTray(); + ui::GestureEventDetails begin_details(ui::ET_GESTURE_SCROLL_BEGIN); + ui::GestureEvent begin_event = ui::GestureEvent( + start.x(), start.y(), ui::EF_NONE, timestamp, begin_details); + system_tray->OnGestureEvent(&begin_event); + + ui::GestureEventDetails update_details(ui::ET_GESTURE_SCROLL_UPDATE, 0, + delta); + timestamp += base::TimeDelta::FromMilliseconds(100); + ui::GestureEvent update_event = ui::GestureEvent( + start.x(), start.y() + delta, ui::EF_NONE, timestamp, update_details); + system_tray->OnGestureEvent(&update_event); + } + + // Open the default system tray bubble to get the height of the bubble and + // then close it. + float GetSystemBubbleHeight() { + SystemTray* system_tray = GetPrimarySystemTray(); + system_tray->ShowDefaultView(BUBBLE_CREATE_NEW); + gfx::Rect bounds = GetSystemBubbleBoundsInScreen(); + system_tray->CloseSystemBubble(); + return bounds.height(); + } + + gfx::Rect GetSystemBubbleBoundsInScreen() { + return GetPrimarySystemTray() + ->GetSystemBubble() + ->bubble_view() + ->GetWidget() + ->GetWindowBoundsInScreen(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(SystemTrayTest); +}; + +// Swiping on the overlap area of shelf and system tray bubble during the +// animation should close the bubble. +TEST_F(SystemTrayTest, SwipingOnShelfDuringAnimation) { + Shelf* shelf = GetPrimaryShelf(); + SystemTray* system_tray = GetPrimarySystemTray(); + gfx::Point start = system_tray->GetLocalBounds().CenterPoint(); + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + + gfx::Rect shelf_bounds_in_screen = + shelf->shelf_widget()->GetWindowBoundsInScreen(); + + system_tray->ShowDefaultView(BUBBLE_CREATE_NEW); + gfx::Rect original_bounds = GetSystemBubbleBoundsInScreen(); + system_tray->CloseSystemBubble(); + + // Enable animations so that we can make sure that they occur. + ui::ScopedAnimationDurationScaleMode regular_animations( + ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + + ui::test::EventGenerator& generator = GetEventGenerator(); + gfx::Point point_on_shelf_start = + gfx::Point(original_bounds.x() + 5, shelf_bounds_in_screen.y() + 5); + gfx::Point point_on_shelf_end(point_on_shelf_start.x(), + shelf_bounds_in_screen.bottom()); + + // Swiping up exceed one third of the height of the bubble should show the + // bubble. + float delta = -original_bounds.height() / 2; + SendGestureEvent(start, delta, false, 0); + EXPECT_TRUE(system_tray->HasSystemBubble()); + gfx::Rect current_bounds = GetSystemBubbleBoundsInScreen(); + + // Dragging the shelf during up animation should close the bubble. + if (current_bounds.y() != original_bounds.y()) { + generator.GestureScrollSequence(point_on_shelf_start, point_on_shelf_end, + base::TimeDelta::FromMilliseconds(100), 5); + EXPECT_FALSE(system_tray->HasSystemBubble()); + } + + // Fling down on the shelf with a velocity that exceeds |kFlingVelocity|. + EXPECT_FALSE(system_tray->HasSystemBubble()); + SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity + 1); + current_bounds = GetSystemBubbleBoundsInScreen(); + EXPECT_TRUE(system_tray->HasSystemBubble()); + + // Dragging the shelf during down animation should close the bubble. + if (current_bounds.y() != original_bounds.y()) { + generator.GestureScrollSequence(point_on_shelf_start, point_on_shelf_end, + base::TimeDelta::FromMilliseconds(100), 5); + EXPECT_FALSE(system_tray->HasSystemBubble()); + } +} + +// Swiping on the system tray ends with fling event. +TEST_F(SystemTrayTest, FlingOnSystemTray) { + Shelf* shelf = GetPrimaryShelf(); + SystemTray* system_tray = GetPrimarySystemTray(); + gfx::Point start = system_tray->GetBoundsInScreen().CenterPoint(); + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + + // Fling up on the system tray should show the bubble if the |velocity_y| is + // larger than |kFlingVelocity| and the dragging amount is larger than one + // third of the height of the bubble. + float delta = -GetSystemBubbleHeight(); + SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity + 1)); + EXPECT_TRUE(system_tray->HasSystemBubble()); + system_tray->CloseSystemBubble(); + + // Fling up on the system tray should show the bubble if the |velocity_y| is + // larger than |kFlingVelocity| even the dragging amount is less than one + // third of the height of the bubble. + delta /= 4; + SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity + 1)); + EXPECT_TRUE(system_tray->HasSystemBubble()); + system_tray->CloseSystemBubble(); + + // Fling up on the system tray should show the bubble if the |velocity_y| is + // less than |kFlingVelocity| but the dragging amount if larger than one third + // of the height of the bubble. + delta = -GetSystemBubbleHeight(); + SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity - 1)); + EXPECT_TRUE(system_tray->HasSystemBubble()); + system_tray->CloseSystemBubble(); + + // Fling up on the system tray should close the bubble if the |velocity_y| + // is less than |kFlingVelocity| and the dragging amount is less than one + // third of the height of the bubble. + delta /= 4; + SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity - 1)); + EXPECT_FALSE(system_tray->HasSystemBubble()); + + // Fling down on the system tray should close the bubble if the |velocity_y| + // is larger than kFLingVelocity. + SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity + 1); + EXPECT_FALSE(system_tray->HasSystemBubble()); + + // Fling down on the system tray should close the bubble if the |velocity_y| + // is larger than |kFlingVelocity| even the dragging amount is larger than one + // third of the height of the bubble. + delta = -GetSystemBubbleHeight(); + SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity + 1); + EXPECT_FALSE(system_tray->HasSystemBubble()); + + // Fling down on the system tray should open the bubble if the |velocity_y| is + // less than |kFlingVelocity| but the dragging amount exceed one third of the + // height of the bubble. + SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity - 1); + EXPECT_TRUE(system_tray->HasSystemBubble()); + system_tray->CloseSystemBubble(); + + // Fling down on the system tray should close the bubble if the |velocity_y| + // is less than |kFlingVelocity| and the dragging amount is less than one + // third of the height of the bubble. + delta /= 4; + SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity - 1); + EXPECT_FALSE(system_tray->HasSystemBubble()); +} + +// Touch outside the system tray bubble during swiping should close the bubble. +TEST_F(SystemTrayTest, TapOutsideCloseBubble) { + Shelf* shelf = GetPrimaryShelf(); + SystemTray* system_tray = GetPrimarySystemTray(); + gfx::Point start = system_tray->GetLocalBounds().CenterPoint(); + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + + float delta = -GetSystemBubbleHeight(); + Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + base::TimeTicks timestamp = base::TimeTicks::Now(); + SendScrollStartAndUpdate(start, delta, timestamp); + EXPECT_TRUE(system_tray->HasSystemBubble()); + + ui::test::EventGenerator& generator = GetEventGenerator(); + gfx::Rect bounds = GetSystemBubbleBoundsInScreen(); + gfx::Point point_outside = gfx::Point(bounds.x() - 5, bounds.y() - 5); + generator.GestureTapAt(point_outside); + EXPECT_FALSE(system_tray->HasSystemBubble()); +} + +// Swiping on the system tray ends with scroll event. +TEST_F(SystemTrayTest, SwipingOnSystemTray) { + Shelf* shelf = GetPrimaryShelf(); + SystemTray* system_tray = GetPrimarySystemTray(); + gfx::Point start = system_tray->GetLocalBounds().CenterPoint(); + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + + // Swiping up on the system tray has no effect if it is not in maximize mode. + float delta = -GetSystemBubbleHeight(); + Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + EXPECT_FALSE(system_tray->HasSystemBubble()); + SendGestureEvent(start, delta, false, 0); + EXPECT_FALSE(system_tray->HasSystemBubble()); + + // Swiping up on the system tray should show the system tray bubble if it is + // in maximize mode. + Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + SendGestureEvent(start, delta, false, 0); + EXPECT_TRUE(system_tray->HasSystemBubble()); + system_tray->CloseSystemBubble(); + + // Swiping up less than one third of the bubble's height should not show the + // bubble. + delta /= 4; + SendGestureEvent(start, delta, false, 0); + EXPECT_FALSE(system_tray->HasSystemBubble()); + + // Swiping up more than one third of the bubble's height should show the + // bubble. + delta = -GetSystemBubbleHeight() / 2; + SendGestureEvent(start, delta, false, 0); + EXPECT_TRUE(system_tray->HasSystemBubble()); + system_tray->CloseSystemBubble(); + + // Swiping up on system tray should not show the system tray bubble if the + // shelf is left alignment. + delta = -GetSystemBubbleHeight(); + shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); + SendGestureEvent(start, delta, false, 0); + EXPECT_FALSE(system_tray->HasSystemBubble()); + + // Swiping up on system tray should not show the system tray bubble if the + // shelf is right alignment. + shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); + SendGestureEvent(start, delta, false, 0); + EXPECT_FALSE(system_tray->HasSystemBubble()); + + // Swiping down on the shelf should not show the system tray bubble. + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + delta = -delta; + SendGestureEvent(start, delta, false, 0); + EXPECT_FALSE(system_tray->HasSystemBubble()); +} // Verifies only the visible default views are recorded in the // "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
diff --git a/ash/system/tray/tray_event_filter.cc b/ash/system/tray/tray_event_filter.cc index 43f142b..873e7df 100644 --- a/ash/system/tray/tray_event_filter.cc +++ b/ash/system/tray/tray_event_filter.cc
@@ -5,10 +5,12 @@ #include "ash/system/tray/tray_event_filter.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/shell.h" #include "ash/shell_port.h" #include "ash/system/tray/tray_background_view.h" #include "ash/system/tray/tray_bubble_wrapper.h" #include "ash/wm/container_finder.h" +#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ui/aura/window.h" #include "ui/views/widget/widget.h" @@ -73,6 +75,19 @@ gfx::Rect bounds = bubble_widget->GetWindowBoundsInScreen(); bounds.Inset(wrapper->bubble_view()->GetBorderInsets()); + // System tray can be dragged to show the bubble if it is in maximize mode. + // During the drag, the bubble's logical bounds can extend outside of the + // work area, but its visual bounds are only within the work area. Restrict + // |bounds| so that events located outside the bubble's visual bounds are + // treated as outside of the bubble. + int bubble_container_id = + wm::GetContainerForWindow(bubble_widget->GetNativeWindow())->id(); + if (Shell::Get() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled() && + bubble_container_id == kShellWindowId_SettingBubbleContainer) { + bounds.Intersect(bubble_widget->GetWorkAreaBoundsInScreen()); + } if (bounds.Contains(location_in_screen)) continue; if (wrapper->tray()) {
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java index d57cd3c..24f85d66 100644 --- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java +++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -26,6 +26,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.StatFs; +import android.os.StrictMode; import android.os.UserManager; import android.provider.Settings; import android.text.Html; @@ -446,10 +447,15 @@ */ @SuppressWarnings("deprecation") public static Drawable getDrawable(Resources res, int id) throws NotFoundException { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return res.getDrawable(id, null); - } else { - return res.getDrawable(id); + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + return res.getDrawable(id, null); + } else { + return res.getDrawable(id); + } + } finally { + StrictMode.setThreadPolicy(oldPolicy); } }
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceImpl.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceImpl.java index 09f508a..e7ba8d5 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceImpl.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceImpl.java
@@ -158,11 +158,11 @@ } sCreateCalled = true; - mDelegate.onServiceCreated(); - // Initialize the context for the application that owns this ChildProcessServiceImpl object. ContextUtils.initApplicationContext(context); + mDelegate.onServiceCreated(); + mMainThread = new Thread(new Runnable() { @Override @SuppressFBWarnings("DM_EXIT")
diff --git a/base/android/jni_generator/SampleForTests_jni.golden b/base/android/jni_generator/SampleForTests_jni.golden index e50583ab..7b384252 100644 --- a/base/android/jni_generator/SampleForTests_jni.golden +++ b/base/android/jni_generator/SampleForTests_jni.golden
@@ -482,35 +482,24 @@ }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; -} // namespace android -} // namespace base - -JNI_REGISTRATION_EXPORT bool - RegisterNative_org_chromium_example_jni_1generator_SampleForTests(JNIEnv* - env) { - - const int kMethodsInnerClassSize = - arraysize(base::android::kMethodsInnerClass); + const int kMethodsInnerClassSize = arraysize(kMethodsInnerClass); if (env->RegisterNatives(InnerClass_clazz(env), - base::android::kMethodsInnerClass, + kMethodsInnerClass, kMethodsInnerClassSize) < 0) { jni_generator::HandleRegistrationError( env, InnerClass_clazz(env), __FILE__); return false; } - const int kMethodsSampleForTestsSize = - arraysize(base::android::kMethodsSampleForTests); + const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests); if (env->RegisterNatives(SampleForTests_clazz(env), - base::android::kMethodsSampleForTests, + kMethodsSampleForTests, kMethodsSampleForTestsSize) < 0) { jni_generator::HandleRegistrationError( env, SampleForTests_clazz(env), __FILE__); @@ -520,4 +509,7 @@ return true; } +} // namespace android +} // namespace base + #endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py index 8249fc9e..3818009 100755 --- a/base/android/jni_generator/jni_generator.py +++ b/base/android/jni_generator/jni_generator.py
@@ -401,7 +401,7 @@ def IsMainDexJavaClass(contents): - """Returns True if the class is annotated with "@MainDex", False if not. + """Returns "true" if the class is annotated with "@MainDex", "false" if not. JNI registration doesn't always need to be completed for non-browser processes since most Java code is only used by the browser process. Classes that are @@ -409,17 +409,8 @@ to force JNI registration. """ re_maindex = re.compile(r'@MainDex[\s\S]*class({|[\s\S]*{)') - return bool(re.search(re_maindex, contents)) - - -def GetBinaryClassName(fully_qualified_class): - """Returns a string concatenating the Java package and class.""" - return fully_qualified_class.replace('_', '_1').replace('/', '_') - - -def GetRegistrationFunctionName(fully_qualified_class): - """Returns the register name with a given class.""" - return 'RegisterNative_' + GetBinaryClassName(fully_qualified_class) + found = re.search(re_maindex, contents) + return 'true' if found else 'false' def GetStaticCastForReturnType(return_type): @@ -629,6 +620,7 @@ is_constructor=True)] self.called_by_natives = MangleCalledByNatives(self.jni_params, self.called_by_natives) + self.constant_fields = [] re_constant_field = re.compile('.*?public static final int (?P<name>.*?);') re_constant_field_value = re.compile( @@ -681,12 +673,13 @@ jni_namespace = ExtractJNINamespace(contents) or options.namespace natives = ExtractNatives(contents, options.ptr_type) called_by_natives = ExtractCalledByNatives(self.jni_params, contents) + maindex = IsMainDexJavaClass(contents) if len(natives) == 0 and len(called_by_natives) == 0: raise SyntaxError('Unable to find any JNI methods for %s.' % fully_qualified_class) inl_header_file_generator = InlHeaderFileGenerator( jni_namespace, fully_qualified_class, natives, called_by_natives, [], - self.jni_params, options) + self.jni_params, options, maindex) self.content = inl_header_file_generator.GetContent() @classmethod @@ -722,7 +715,8 @@ """Generates an inline header file for JNI integration.""" def __init__(self, namespace, fully_qualified_class, natives, - called_by_natives, constant_fields, jni_params, options): + called_by_natives, constant_fields, jni_params, options, + maindex='false'): self.namespace = namespace self.fully_qualified_class = fully_qualified_class self.class_name = self.fully_qualified_class.split('/')[-1] @@ -730,6 +724,7 @@ self.called_by_natives = called_by_natives self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' self.constant_fields = constant_fields + self.maindex = maindex self.jni_params = jni_params self.options = options @@ -771,9 +766,8 @@ // Step 3: RegisterNatives. $JNI_NATIVE_METHODS -$REGISTER_NATIVES_EMPTY -$CLOSE_NAMESPACE $REGISTER_NATIVES +$CLOSE_NAMESPACE #endif // ${HEADER_GUARD} """) @@ -785,9 +779,8 @@ 'METHOD_STUBS': self.GetMethodStubsString(), 'OPEN_NAMESPACE': self.GetOpenNamespaceString(), 'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(), - 'REGISTER_NATIVES_EMPTY': self.GetOriginalRegisterNativesString(), - 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(), 'REGISTER_NATIVES': self.GetRegisterNativesString(), + 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(), 'HEADER_GUARD': self.header_guard, 'INCLUDES': self.GetIncludesString(), } @@ -836,19 +829,14 @@ return '\n'.join(ret) def SubstituteNativeMethods(self, template): - """Substitutes NAMESPACE, JAVA_CLASS and KMETHODS in the provided - template.""" + """Substitutes JAVA_CLASS and KMETHODS in the provided template.""" ret = [] all_classes = self.GetUniqueClasses(self.natives) all_classes[self.class_name] = self.fully_qualified_class for clazz in all_classes: kmethods = self.GetKMethodsString(clazz) - namespace_str = '' - if self.namespace: - namespace_str = self.namespace + '::' if kmethods: - values = {'NAMESPACE': namespace_str, - 'JAVA_CLASS': clazz, + values = {'JAVA_CLASS': clazz, 'KMETHODS': kmethods} ret += [template.substitute(values)] if not ret: return '' @@ -865,38 +853,32 @@ """) return self.SubstituteNativeMethods(template) - # TODO(agrieve): Remove this function when deleting original registers. - # https://crbug.com/683256. - def GetOriginalRegisterNativesString(self): - """Return the code for original RegisterNatives""" - natives = self.GetRegisterNativesImplString() - if not natives: - return '' - - return """ -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. -static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} -""" - def GetRegisterNativesString(self): """Returns the code for RegisterNatives.""" natives = self.GetRegisterNativesImplString() if not natives: return '' + template = Template("""\ -JNI_REGISTRATION_EXPORT bool ${REGISTER_NAME}(JNIEnv* env) { +${REGISTER_NATIVES_SIGNATURE} { +${EARLY_EXIT} ${NATIVES} return true; } """) - values = { - 'REGISTER_NAME': - GetRegistrationFunctionName(self.fully_qualified_class), - 'NATIVES': natives - } + signature = 'static bool RegisterNativesImpl(JNIEnv* env)' + early_exit = '' + if self.options.native_exports_optional: + early_exit = """\ + if (jni_generator::ShouldSkipJniRegistration(%s)) + return true; +""" % self.maindex + + values = {'REGISTER_NATIVES_SIGNATURE': signature, + 'EARLY_EXIT': early_exit, + 'NATIVES': natives, + } + return template.substitute(values) def GetRegisterNativesImplString(self): @@ -905,11 +887,10 @@ return '' template = Template("""\ - const int kMethods${JAVA_CLASS}Size = - arraysize(${NAMESPACE}kMethods${JAVA_CLASS}); + const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); if (env->RegisterNatives(${JAVA_CLASS}_clazz(env), - ${NAMESPACE}kMethods${JAVA_CLASS}, + kMethods${JAVA_CLASS}, kMethods${JAVA_CLASS}Size) < 0) { jni_generator::HandleRegistrationError( env, ${JAVA_CLASS}_clazz(env), __FILE__); @@ -993,7 +974,7 @@ """ template = Template("Java_${JAVA_NAME}_native${NAME}") - java_name = GetBinaryClassName(self.fully_qualified_class) + java_name = self.fully_qualified_class.replace('_', '_1').replace('/', '_') if native.java_class_name: java_name += '_00024' + native.java_class_name @@ -1333,21 +1314,19 @@ print e sys.exit(1) if output_file: - WriteOutput(output_file, content) + if not os.path.exists(os.path.dirname(os.path.abspath(output_file))): + os.makedirs(os.path.dirname(os.path.abspath(output_file))) + if options.optimize_generation and os.path.exists(output_file): + with file(output_file, 'r') as f: + existing_content = f.read() + if existing_content == content: + return + with file(output_file, 'w') as f: + f.write(content) else: print content -def WriteOutput(output_file, content): - if os.path.exists(output_file): - with open(output_file) as f: - existing_content = f.read() - if existing_content == content: - return - with open(output_file, 'w') as f: - f.write(content) - - def GetScriptName(): script_components = os.path.abspath(sys.argv[0]).split(os.path.sep) base_index = 0 @@ -1384,6 +1363,10 @@ option_parser.add_option('--output_dir', help='The output directory. Must be used with ' '--input') + option_parser.add_option('--optimize_generation', type="int", + default=0, help='Whether we should optimize JNI ' + 'generation by not regenerating files if they have ' + 'not changed.') option_parser.add_option('--script_name', default=GetScriptName(), help='The name of this script in the generated ' 'header.')
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h index 53629a657..3062806 100644 --- a/base/android/jni_generator/jni_generator_helper.h +++ b/base/android/jni_generator/jni_generator_helper.h
@@ -30,13 +30,6 @@ #define JNI_GENERATOR_EXPORT extern "C" __attribute__((visibility("default"))) #endif -// Used to export JNI registration functions. -#if defined(COMPONENT_BUILD) -#define JNI_REGISTRATION_EXPORT __attribute__((visibility("default"))) -#else -#define JNI_REGISTRATION_EXPORT -#endif - namespace jni_generator { inline void HandleRegistrationError(JNIEnv* env, @@ -49,14 +42,12 @@ base::android::CheckException(env); } -// TODO(estevenson): Remove this function since all natives are registered -// together. Currently gvr-android-sdk stil calls it. -// https://crbug.com/664306. inline bool ShouldSkipJniRegistration(bool is_maindex_class) { switch (base::android::GetJniRegistrationType()) { case base::android::ALL_JNI_REGISTRATION: return false; case base::android::NO_JNI_REGISTRATION: + // TODO(estevenson): Change this to a DCHECK. return true; case base::android::SELECTIVE_JNI_REGISTRATION: return !is_maindex_class;
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py index 41e617f..d667a47 100755 --- a/base/android/jni_generator/jni_generator_tests.py +++ b/base/android/jni_generator/jni_generator_tests.py
@@ -967,6 +967,33 @@ test_options) self.assertGoldenTextEquals(h.GetContent()) + def testMainDexFile(self): + test_data = """ + package org.chromium.example.jni_generator; + + @MainDex + class Test { + private static native int nativeStaticMethod(long nativeTest, int arg1); + } + """ + options = TestOptions() + jni_from_java = jni_generator.JNIFromJavaSource( + test_data, 'org/chromium/foo/Bar', options) + self.assertGoldenTextEquals(jni_from_java.GetContent()) + + def testNonMainDexFile(self): + test_data = """ + package org.chromium.example.jni_generator; + + class Test { + private static native int nativeStaticMethod(long nativeTest, int arg1); + } + """ + options = TestOptions() + jni_from_java = jni_generator.JNIFromJavaSource( + test_data, 'org/chromium/foo/Bar', options) + self.assertGoldenTextEquals(jni_from_java.GetContent()) + def testMainDexAnnotation(self): mainDexEntries = [ '@MainDex public class Test {', @@ -994,7 +1021,7 @@ '@MainDex public class Test extends Testable<java.io.Serializable> {', ] for entry in mainDexEntries: - self.assertEquals(True, IsMainDexJavaClass(entry)) + self.assertEquals("true", IsMainDexJavaClass(entry)) def testNoMainDexAnnotation(self): noMainDexEntries = [ @@ -1004,7 +1031,7 @@ 'public class Test extends BaseTest {' ] for entry in noMainDexEntries: - self.assertEquals(False, IsMainDexJavaClass(entry)) + self.assertEquals("false", IsMainDexJavaClass(entry)) def testNativeExportsOnlyOption(self): test_data = """
diff --git a/base/android/jni_generator/jni_registration_generator.py b/base/android/jni_generator/jni_registration_generator.py deleted file mode 100755 index febb5b7..0000000 --- a/base/android/jni_generator/jni_registration_generator.py +++ /dev/null
@@ -1,179 +0,0 @@ -#!/usr/bin/env python -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Generate JNI registration entry points - -Creates a header file with two static functions: RegisterMainDexNatives() and -RegisterNonMainDexNatives(). Together, these will use manual JNI registration -to register all native methods that exist within an application.""" - -import argparse -import jni_generator -import os -import string -import sys -from util import build_utils - - -def GenerateJNIHeader(java_file_paths, output_file, args): - """Generate a header file including two registration functions. - - Forward declares all JNI registration functions created by jni_generator.py. - Calls the functions in RegisterMainDexNatives() if they are main dex. And - calls them in RegisterNonMainDexNatives() if they are non-main dex. - - Args: - java_file_paths: A list of java file paths. - output_file: A relative path to output file. - args: All input arguments. - """ - registration_dict = { - 'FORWARD_DECLARATIONS': '', - 'REGISTER_MAIN_DEX_NATIVES': '', - 'REGISTER_NON_MAIN_DEX_NATIVES': '' - } - # Sort the file list to make sure the order is deterministic. - java_file_paths.sort() - for path in java_file_paths: - if path in args.no_register_java: - continue - with open(path) as f: - contents = f.read() - natives = jni_generator.ExtractNatives(contents, 'long') - if len(natives) == 0: - continue - fully_qualified_class = jni_generator.ExtractFullyQualifiedJavaClassName( - path, contents) - main_dex = jni_generator.IsMainDexJavaClass(contents) - header_generator = HeaderGenerator( - fully_qualified_class, registration_dict, main_dex) - registration_dict = header_generator.GetContent() - - header_content = CreateFromDict(registration_dict) - if output_file: - jni_generator.WriteOutput(output_file, header_content) - else: - print header_content - - -def CreateFromDict(registration_dict): - """Returns the content of the header file.""" - - template = string.Template("""\ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -// This file is autogenerated by -// base/android/jni_generator/jni_registration_generator.py -// Please do not change its content. - -#ifndef HEADER_GUARD -#define HEADER_GUARD - -#include <jni.h> - -#include "base/android/jni_generator/jni_generator_helper.h" -#include "base/android/jni_int_wrapper.h" - -// Step 1: Forward declaration. -${FORWARD_DECLARATIONS} - -// Step 2: Main dex and non-main dex registration functions. - -bool RegisterMainDexNatives(JNIEnv* env) { -${REGISTER_MAIN_DEX_NATIVES} - - return true; -} - -bool RegisterNonMainDexNatives(JNIEnv* env) { -${REGISTER_NON_MAIN_DEX_NATIVES} - - return true; -} - -#endif // HEADER_GUARD -""") - if len(registration_dict['FORWARD_DECLARATIONS']) == 0: - return '' - return jni_generator.WrapOutput(template.substitute(registration_dict)) - - -class HeaderGenerator(object): - """Generates an inline header file for JNI registration.""" - - def __init__(self, fully_qualified_class, registration_dict, main_dex): - self.fully_qualified_class = fully_qualified_class - self.class_name = self.fully_qualified_class.split('/')[-1] - self.registration_dict = registration_dict - self.main_dex = main_dex - - def GetContent(self): - self._AddForwardDeclaration() - self._AddRegisterNatives() - return self.registration_dict - - def _AddForwardDeclaration(self): - """Add the content of the forward declaration to the dictionary.""" - template = string.Template('JNI_REGISTRATION_EXPORT bool ${METHOD_NAME}(' - 'JNIEnv* env);\n') - value = { - 'METHOD_NAME': - jni_generator.GetRegistrationFunctionName( - self.fully_qualified_class) - } - self.registration_dict['FORWARD_DECLARATIONS'] += template.substitute(value) - - def _AddRegisterNatives(self): - """Add the body of the RegisterNativesImpl method to the dictionary.""" - template = string.Template(""" -if (!${REGISTER_NAME}(env)) - return false; -""") - value = { - 'REGISTER_NAME': - jni_generator.GetRegistrationFunctionName( - self.fully_qualified_class) - } - register_body = template.substitute(value) - if self.main_dex: - self.registration_dict['REGISTER_MAIN_DEX_NATIVES'] += register_body - else: - self.registration_dict['REGISTER_NON_MAIN_DEX_NATIVES'] += register_body - - -def main(argv): - arg_parser = argparse.ArgumentParser() - build_utils.AddDepfileOption(arg_parser) - - arg_parser.add_argument('--sources_files', - help='A list of .sources files which contain Java ' - 'file paths. Must be used with --output.') - arg_parser.add_argument('--output', - help='The output file path.') - arg_parser.add_argument('--no_register_java', - help='A list of Java files which should be ignored ' - 'by the parser.') - args = arg_parser.parse_args(build_utils.ExpandFileArgs(argv[1:])) - args.sources_files = build_utils.ParseGnList(args.sources_files) - - if args.sources_files: - java_file_paths = [] - for f in args.sources_files: - # java_file_paths stores each Java file path as a string. - java_file_paths += build_utils.ReadSourcesList(f) - else: - print '\nError: Must specify --sources_files.' - return 1 - output_file = args.output - GenerateJNIHeader(java_file_paths, output_file, args) - - if args.depfile: - build_utils.WriteDepfile(args.depfile, output_file) - -if __name__ == '__main__': - sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden index 363f916..20b8830 100644 --- a/base/android/jni_generator/testInnerClassNatives.golden +++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -51,16 +51,11 @@ }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; -JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_TestJni(JNIEnv* env) { - - const int kMethodsMyInnerClassSize = - arraysize(kMethodsMyInnerClass); + const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass); if (env->RegisterNatives(MyInnerClass_clazz(env), kMethodsMyInnerClass,
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden index 6c07b58..67352e7 100644 --- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden +++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -67,13 +67,9 @@ "I", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeInit) }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} - -JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_TestJni(JNIEnv* env) { + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; const int kMethodsMyOtherInnerClassSize = arraysize(kMethodsMyOtherInnerClass); @@ -86,8 +82,7 @@ return false; } - const int kMethodsTestJniSize = - arraysize(kMethodsTestJni); + const int kMethodsTestJniSize = arraysize(kMethodsTestJni); if (env->RegisterNatives(TestJni_clazz(env), kMethodsTestJni,
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden index add5ac9..7807efa 100644 --- a/base/android/jni_generator/testInnerClassNativesMultiple.golden +++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -74,13 +74,9 @@ }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} - -JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_TestJni(JNIEnv* env) { + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; const int kMethodsMyOtherInnerClassSize = arraysize(kMethodsMyOtherInnerClass); @@ -93,8 +89,7 @@ return false; } - const int kMethodsMyInnerClassSize = - arraysize(kMethodsMyInnerClass); + const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass); if (env->RegisterNatives(MyInnerClass_clazz(env), kMethodsMyInnerClass,
diff --git a/base/android/jni_generator/testMainDexFile.golden b/base/android/jni_generator/testMainDexFile.golden new file mode 100644 index 0000000..cbb2a7d --- /dev/null +++ b/base/android/jni_generator/testMainDexFile.golden
@@ -0,0 +1,67 @@ +// Copyright 2014 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. + +// This file is autogenerated by +// base/android/jni_generator/jni_generator.py +// For +// org/chromium/foo/Bar + +#ifndef org_chromium_foo_Bar_JNI +#define org_chromium_foo_Bar_JNI + +#include <jni.h> + +#include "base/android/jni_generator/jni_generator_helper.h" + +#include "base/android/jni_int_wrapper.h" + +// Step 1: forward declarations. +namespace { +const char kBarClassPath[] = "org/chromium/foo/Bar"; +// Leaking this jclass as we cannot use LazyInstance from some threads. +base::subtle::AtomicWord g_Bar_clazz __attribute__((unused)) = 0; +#define Bar_clazz(env) base::android::LazyGetClass(env, kBarClassPath, &g_Bar_clazz) + +} // namespace + +// Step 2: method stubs. +JNI_GENERATOR_EXPORT jint Java_org_chromium_foo_Bar_nativeStaticMethod(JNIEnv* + env, jobject jcaller, + jlong nativeTest, + jint arg1) { + Test* native = reinterpret_cast<Test*>(nativeTest); + CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0); + return native->StaticMethod(env, base::android::JavaParamRef<jobject>(env, + jcaller), arg1); +} + +// Step 3: RegisterNatives. + +static const JNINativeMethod kMethodsBar[] = { + { "nativeStaticMethod", +"(" +"J" +"I" +")" +"I", reinterpret_cast<void*>(Java_org_chromium_foo_Bar_nativeStaticMethod) }, +}; + +static bool RegisterNativesImpl(JNIEnv* env) { + if (jni_generator::ShouldSkipJniRegistration(true)) + return true; + + const int kMethodsBarSize = arraysize(kMethodsBar); + + if (env->RegisterNatives(Bar_clazz(env), + kMethodsBar, + kMethodsBarSize) < 0) { + jni_generator::HandleRegistrationError( + env, Bar_clazz(env), __FILE__); + return false; + } + + return true; +} + +#endif // org_chromium_foo_Bar_JNI
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden index 03aac48e..0eecb5a 100644 --- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden +++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -75,16 +75,11 @@ "V", reinterpret_cast<void*>(Java_org_chromium_foo_Foo_nativeDoSomething) }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; -JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_foo_Foo(JNIEnv* env) { - - const int kMethodsFooSize = - arraysize(kMethodsFoo); + const int kMethodsFooSize = arraysize(kMethodsFoo); if (env->RegisterNatives(Foo_clazz(env), kMethodsFoo,
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden index 0bfbe04..3362c928 100644 --- a/base/android/jni_generator/testNatives.golden +++ b/base/android/jni_generator/testNatives.golden
@@ -320,16 +320,11 @@ }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; -JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_TestJni(JNIEnv* env) { - - const int kMethodsTestJniSize = - arraysize(kMethodsTestJni); + const int kMethodsTestJniSize = arraysize(kMethodsTestJni); if (env->RegisterNatives(TestJni_clazz(env), kMethodsTestJni,
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden index 201a066..ec029ce3 100644 --- a/base/android/jni_generator/testNativesLong.golden +++ b/base/android/jni_generator/testNativesLong.golden
@@ -46,16 +46,11 @@ "V", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeDestroy) }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; -JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_TestJni(JNIEnv* env) { - - const int kMethodsTestJniSize = - arraysize(kMethodsTestJni); + const int kMethodsTestJniSize = arraysize(kMethodsTestJni); if (env->RegisterNatives(TestJni_clazz(env), kMethodsTestJni,
diff --git a/base/android/jni_generator/testNonMainDexFile.golden b/base/android/jni_generator/testNonMainDexFile.golden new file mode 100644 index 0000000..533241e --- /dev/null +++ b/base/android/jni_generator/testNonMainDexFile.golden
@@ -0,0 +1,67 @@ +// Copyright 2014 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. + +// This file is autogenerated by +// base/android/jni_generator/jni_generator.py +// For +// org/chromium/foo/Bar + +#ifndef org_chromium_foo_Bar_JNI +#define org_chromium_foo_Bar_JNI + +#include <jni.h> + +#include "base/android/jni_generator/jni_generator_helper.h" + +#include "base/android/jni_int_wrapper.h" + +// Step 1: forward declarations. +namespace { +const char kBarClassPath[] = "org/chromium/foo/Bar"; +// Leaking this jclass as we cannot use LazyInstance from some threads. +base::subtle::AtomicWord g_Bar_clazz __attribute__((unused)) = 0; +#define Bar_clazz(env) base::android::LazyGetClass(env, kBarClassPath, &g_Bar_clazz) + +} // namespace + +// Step 2: method stubs. +JNI_GENERATOR_EXPORT jint Java_org_chromium_foo_Bar_nativeStaticMethod(JNIEnv* + env, jobject jcaller, + jlong nativeTest, + jint arg1) { + Test* native = reinterpret_cast<Test*>(nativeTest); + CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0); + return native->StaticMethod(env, base::android::JavaParamRef<jobject>(env, + jcaller), arg1); +} + +// Step 3: RegisterNatives. + +static const JNINativeMethod kMethodsBar[] = { + { "nativeStaticMethod", +"(" +"J" +"I" +")" +"I", reinterpret_cast<void*>(Java_org_chromium_foo_Bar_nativeStaticMethod) }, +}; + +static bool RegisterNativesImpl(JNIEnv* env) { + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; + + const int kMethodsBarSize = arraysize(kMethodsBar); + + if (env->RegisterNatives(Bar_clazz(env), + kMethodsBar, + kMethodsBarSize) < 0) { + jni_generator::HandleRegistrationError( + env, Bar_clazz(env), __FILE__); + return false; + } + + return true; +} + +#endif // org_chromium_foo_Bar_JNI
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden index a367ae7..ef618da8 100644 --- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden +++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -69,16 +69,11 @@ "V", reinterpret_cast<void*>(Java_org_chromium_foo_Foo_nativeDoSomething) }, }; -// TODO(agrieve): Remove these empty registration functions and functions -// calling them. https://crbug.com/683256. static bool RegisterNativesImpl(JNIEnv* env) { - return true; -} + if (jni_generator::ShouldSkipJniRegistration(false)) + return true; -JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_foo_Foo(JNIEnv* env) { - - const int kMethodsFooSize = - arraysize(kMethodsFoo); + const int kMethodsFooSize = arraysize(kMethodsFoo); if (env->RegisterNatives(Foo_clazz(env), kMethodsFoo,
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc index b7ef107..1bfcffc 100644 --- a/base/metrics/histogram.cc +++ b/base/metrics/histogram.cc
@@ -614,12 +614,14 @@ std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const { // TODO(bcwhite): Remove these CHECKs once crbug/734049 is resolved. + HistogramSamples* unlogged = unlogged_samples_.get(); CHECK(unlogged_samples_); CHECK(unlogged_samples_->id()); CHECK(bucket_ranges()); std::unique_ptr<SampleVector> samples( new SampleVector(unlogged_samples_->id(), bucket_ranges())); samples->Add(*unlogged_samples_); + debug::Alias(&unlogged); return samples; }
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn index 11bc3bb..6c496401 100644 --- a/base/test/BUILD.gn +++ b/base/test/BUILD.gn
@@ -359,7 +359,6 @@ ] srcjar_deps = [ ":test_support_java_aidl" ] java_files = [ - "android/java/src/org/chromium/base/ChildProcessConstants.java", "android/java/src/org/chromium/base/MainReturnCodeResult.java", "android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java", "android/java/src/org/chromium/base/MultiprocessTestClientService.java", @@ -368,6 +367,7 @@ "android/java/src/org/chromium/base/MultiprocessTestClientService2.java", "android/java/src/org/chromium/base/MultiprocessTestClientService3.java", "android/java/src/org/chromium/base/MultiprocessTestClientService4.java", + "android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java", ] }
diff --git a/base/test/android/java/src/org/chromium/base/ChildProcessConstants.java b/base/test/android/java/src/org/chromium/base/ChildProcessConstants.java deleted file mode 100644 index 457c59cb..0000000 --- a/base/test/android/java/src/org/chromium/base/ChildProcessConstants.java +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -/** - * Constants to be used by child processes. - */ -public interface ChildProcessConstants { - // Key for the command line. - public static final String EXTRA_COMMAND_LINE = "org.chromium.base.extra.command_line"; - - // Key for the file descriptors that should be mapped in the child process.. - public static final String EXTRA_FILES = "org.chromium.base.extra.extra_files"; -}
diff --git a/base/test/android/java/src/org/chromium/base/ITestCallback.aidl b/base/test/android/java/src/org/chromium/base/ITestCallback.aidl index 48d9994..dd208d55 100644 --- a/base/test/android/java/src/org/chromium/base/ITestCallback.aidl +++ b/base/test/android/java/src/org/chromium/base/ITestCallback.aidl
@@ -5,12 +5,19 @@ package org.chromium.base; import org.chromium.base.ITestController; -import org.chromium.base.MainReturnCodeResult; import org.chromium.base.process_launcher.FileDescriptorInfo; /** * This interface is called by the child process to pass its controller to its parent. */ -oneway interface ITestCallback { - void childConnected(ITestController controller); +interface ITestCallback { + oneway void childConnected(ITestController controller); + + /** + * Invoked by the service to notify that the main method returned. + * IMPORTANT! Should not be marked oneway as the caller will terminate the running process after + * this call. Marking it oneway would make the call asynchronous and the process could terminate + * before the call was actually sent. + */ + void mainReturned(int returnCode); }
diff --git a/base/test/android/java/src/org/chromium/base/ITestController.aidl b/base/test/android/java/src/org/chromium/base/ITestController.aidl index 4bf7429..d927ee5 100644 --- a/base/test/android/java/src/org/chromium/base/ITestController.aidl +++ b/base/test/android/java/src/org/chromium/base/ITestController.aidl
@@ -4,23 +4,12 @@ package org.chromium.base; -import org.chromium.base.MainReturnCodeResult; import org.chromium.base.process_launcher.FileDescriptorInfo; /** * This interface is used to control child processes. */ interface ITestController { - /** - * Blocks until the <code>main</code> method started with {@link #launch()} returns, or returns - * immediately if main has already returned. - * @param timeoutMs time in milliseconds after which this method returns even if the main method - * has not returned yet. - * @return a result containing whether a timeout occured and the value returned by the - * <code>main</code> method - */ - MainReturnCodeResult waitForMainToReturn(int timeoutMs); - /** * Forces the service process to terminate and block until the process stops. * @param exitCode the exit code the process should terminate with. @@ -32,5 +21,5 @@ * Forces the service process to terminate. * @param exitCode the exit code the process should terminate with. */ - void forceStop(int exitCode); + oneway void forceStop(int exitCode); }
diff --git a/base/test/android/java/src/org/chromium/base/MainReturnCodeResult.aidl b/base/test/android/java/src/org/chromium/base/MainReturnCodeResult.aidl deleted file mode 100644 index dc7501f..0000000 --- a/base/test/android/java/src/org/chromium/base/MainReturnCodeResult.aidl +++ /dev/null
@@ -1,7 +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. - -package org.chromium.base; - -parcelable MainReturnCodeResult;
diff --git a/base/test/android/java/src/org/chromium/base/MainReturnCodeResult.java b/base/test/android/java/src/org/chromium/base/MainReturnCodeResult.java index 05a15b58..9756c976 100644 --- a/base/test/android/java/src/org/chromium/base/MainReturnCodeResult.java +++ b/base/test/android/java/src/org/chromium/base/MainReturnCodeResult.java
@@ -4,9 +4,6 @@ package org.chromium.base; -import android.os.Parcel; -import android.os.Parcelable; - import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; @@ -14,18 +11,21 @@ * Contains the result of a native main method that ran in a child process. */ @JNINamespace("base::android") -public final class MainReturnCodeResult implements Parcelable { +public final class MainReturnCodeResult { private final int mMainReturnCode; private final boolean mTimedOut; - public MainReturnCodeResult(int mainReturnCode, boolean timedOut) { - mMainReturnCode = mainReturnCode; - mTimedOut = timedOut; + public static MainReturnCodeResult createMainResult(int returnCode) { + return new MainReturnCodeResult(returnCode, false /* timedOut */); } - MainReturnCodeResult(Parcel in) { - mMainReturnCode = in.readInt(); - mTimedOut = (in.readInt() != 0); + public static MainReturnCodeResult createTimeoutMainResult() { + return new MainReturnCodeResult(0, true /* timedOut */); + } + + private MainReturnCodeResult(int mainReturnCode, boolean timedOut) { + mMainReturnCode = mainReturnCode; + mTimedOut = timedOut; } @CalledByNative @@ -37,28 +37,4 @@ public boolean hasTimedOut() { return mTimedOut; } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mMainReturnCode); - dest.writeInt(mTimedOut ? 1 : 0); - } - - public static final Parcelable.Creator<MainReturnCodeResult> CREATOR = - new Parcelable.Creator<MainReturnCodeResult>() { - @Override - public MainReturnCodeResult createFromParcel(Parcel in) { - return new MainReturnCodeResult(in); - } - - @Override - public MainReturnCodeResult[] newArray(int size) { - return new MainReturnCodeResult[size]; - } - }; }
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java index 18fca7f3..7c19179 100644 --- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java +++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
@@ -12,9 +12,11 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.SparseArray; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.process_launcher.ChildProcessConstants; import org.chromium.base.process_launcher.FileDescriptorInfo; import org.chromium.base.process_launcher.ICallbackInt; import org.chromium.base.process_launcher.IChildProcessService; @@ -25,6 +27,9 @@ import java.util.List; import java.util.Queue; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import javax.annotation.concurrent.GuardedBy; @@ -35,7 +40,9 @@ public final class MultiprocessTestClientLauncher { private static final String TAG = "cr_MProcTCLauncher"; - private static ConnectionAllocator sConnectionAllocator = new ConnectionAllocator(); + private static final ConnectionAllocator sConnectionAllocator = new ConnectionAllocator(); + + private static final SparseArray<Integer> sPidToMainResult = new SparseArray<>(); // Not supposed to be instantiated. private MultiprocessTestClientLauncher() {} @@ -108,11 +115,22 @@ private final CountDownLatch mPidReceived = new CountDownLatch(1); private final int mSlot; private IChildProcessService mService = null; + @GuardedBy("mConnectedLock") private boolean mConnected; + private int mPid; private ITestController mTestController; + + private final ReentrantLock mMainReturnCodeLock = new ReentrantLock(); + private final Condition mMainReturnCodeCondition = mMainReturnCodeLock.newCondition(); + // The return code returned by the service's main method. + // null if the service has not sent it yet. + @GuardedBy("mMainReturnCodeLock") + private Integer mMainReturnCode; + private final ITestCallback.Stub mCallback = new ITestCallback.Stub() { + @Override public void childConnected(ITestController controller) { mTestController = controller; // This method can be called before onServiceConnected below has set the PID. @@ -129,6 +147,22 @@ mConnectedLock.notifyAll(); } } + + @Override + public void mainReturned(int returnCode) { + mMainReturnCodeLock.lock(); + try { + mMainReturnCode = returnCode; + mMainReturnCodeCondition.signal(); + } finally { + mMainReturnCodeLock.unlock(); + } + + // Also store the return code in a map as the connection might get disconnected + // before waitForMainToReturn is called and then we would not have a way to retrieve + // the connection. + sPidToMainResult.put(mPid, returnCode); + } }; ClientServiceConnection(int slot, String[] commandLine, FileDescriptorInfo[] filesToMap) { @@ -150,6 +184,26 @@ } } + public Integer getMainReturnCode(long timeoutMs) { + long timeoutNs = TimeUnit.MILLISECONDS.toNanos(timeoutMs); + mMainReturnCodeLock.lock(); + try { + while (mMainReturnCode == null) { + if (timeoutNs <= 0L) { + return null; + } + try { + timeoutNs = mMainReturnCodeCondition.awaitNanos(timeoutNs); + } catch (InterruptedException ie) { + Log.e(TAG, "Interrupted while waiting for main return code."); + } + } + return mMainReturnCode; + } finally { + mMainReturnCodeLock.unlock(); + } + } + @Override public void onServiceConnected(ComponentName className, IBinder service) { try { @@ -250,19 +304,23 @@ @CalledByNative private static MainReturnCodeResult waitForMainToReturn(int pid, int timeoutMs) { ClientServiceConnection connection = sConnectionAllocator.getConnectionByPid(pid); - if (connection == null) { + if (connection != null) { + try { + Integer mainResult = connection.getMainReturnCode(timeoutMs); + return mainResult == null ? MainReturnCodeResult.createTimeoutMainResult() + : MainReturnCodeResult.createMainResult(mainResult); + } finally { + freeConnection(connection); + } + } + + Integer mainResult = sPidToMainResult.get(pid); + if (mainResult == null) { Log.e(TAG, "waitForMainToReturn called on unknown connection for pid " + pid); return null; } - try { - ITestController testController = connection.getTestController(); - return testController.waitForMainToReturn(timeoutMs); - } catch (RemoteException e) { - Log.e(TAG, "Remote call to waitForMainToReturn failed."); - return null; - } finally { - freeConnection(connection); - } + sPidToMainResult.remove(pid); + return MainReturnCodeResult.createMainResult(mainResult); } @CalledByNative
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java index 4ac4dd5..9b50001 100644 --- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java +++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java
@@ -4,189 +4,11 @@ package org.chromium.base; -import android.app.Service; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Parcelable; -import android.os.Process; -import android.os.RemoteException; +import org.chromium.base.process_launcher.ChildProcessService; -import org.chromium.base.annotations.SuppressFBWarnings; -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.library_loader.LibraryProcessType; -import org.chromium.base.library_loader.ProcessInitException; -import org.chromium.base.process_launcher.FileDescriptorInfo; -import org.chromium.base.process_launcher.ICallbackInt; -import org.chromium.base.process_launcher.IChildProcessService; -import org.chromium.native_test.MainRunner; - -import javax.annotation.concurrent.GuardedBy; - -/** - * The service implementation used to host all multiprocess test client code. - */ -public class MultiprocessTestClientService extends Service { - private static final String TAG = "cr_TestClient"; - - private static boolean sAlreadyInitialized = false; - - private final Handler mHandler = new Handler(); - - private final Object mResultLock = new Object(); - - @GuardedBy("mResultLock") - private MainReturnCodeResult mResult; - - private final ITestController.Stub mTestController = new ITestController.Stub() { - @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE") - @Override - public MainReturnCodeResult waitForMainToReturn(int timeoutMs) { - synchronized (mResultLock) { - while (mResult == null) { - try { - mResultLock.wait(timeoutMs); - } catch (InterruptedException ie) { - continue; - } - // Check if we timed-out. - if (mResult == null) { - Log.e(TAG, "Failed to wait for main return value."); - return new MainReturnCodeResult(0, true /* timed-out */); - } - } - return mResult; - } - } - - @SuppressFBWarnings("DM_EXIT") - @Override - public boolean forceStopSynchronous(int exitCode) { - System.exit(exitCode); - return true; - } - - @SuppressFBWarnings("DM_EXIT") - @Override - public void forceStop(int exitCode) { - System.exit(exitCode); - } - }; - - private final IChildProcessService.Stub mBinder = new IChildProcessService.Stub() { - @Override - public boolean bindToCaller() { - return true; - } - - @Override - public void setupConnection(Bundle args, ICallbackInt pidCallback, final IBinder callback) { - // Required to unparcel FileDescriptorInfo. - args.setClassLoader(getApplicationContext().getClassLoader()); - - final String[] commandLine = - args.getStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE); - final Parcelable[] fdInfosAsParcelable = - args.getParcelableArray(ChildProcessConstants.EXTRA_FILES); - - FileDescriptorInfo[] fdsToMap = new FileDescriptorInfo[fdInfosAsParcelable.length]; - System.arraycopy(fdInfosAsParcelable, 0, fdsToMap, 0, fdInfosAsParcelable.length); - - final int[] fdKeys = new int[fdsToMap.length]; - final int[] fdFds = new int[fdsToMap.length]; - for (int i = 0; i < fdsToMap.length; i++) { - fdKeys[i] = fdsToMap[i].id; - // Take ownership of the file descriptor so they outlive the FileDescriptorInfo - // instances. Native code will own them. - fdFds[i] = fdsToMap[i].fd.detachFd(); - } - - // Prevent potential deadlocks by letting this method return before calling back to the - // launcher: the childConnected implementation on the launcher side might block until - // this method returns. - mHandler.post(new Runnable() { - @Override - public void run() { - try { - ITestCallback testCallback = ITestCallback.Stub.asInterface(callback); - testCallback.childConnected(mTestController); - } catch (RemoteException re) { - Log.e(TAG, "Failed to notify parent process of connection.", re); - } - } - }); - - // Don't run main directly, it would block and the response would not be returned. - // We post to the main thread as this thread does not have a Looper. - mHandler.post(new Runnable() { - @Override - public void run() { - int result = MainRunner.runMain(commandLine, fdKeys, fdFds); - setMainReturnValue(result); - } - }); - - try { - pidCallback.call(Process.myPid()); - } catch (RemoteException re) { - Log.e(TAG, "Service failed to report PID to launcher.", re); - } - } - - @Override - public void crashIntentionallyForTesting() { - assert false : "crashIntentionallyForTesting not implemented."; - } - }; - - @SuppressFBWarnings("DM_EXIT") - @Override - public void onCreate() { - super.onCreate(); - - if (sAlreadyInitialized) { - // The framework controls how services are reused and even though nothing is bound to a - // service it might be kept around. Since we really want to fork a new process when we - // bind, we'll kill the process early when a service is reused, forcing the framework to - // recreate the service in a new process. - // This is not ideal, but there are no clear alternatives at this point. - Log.e(TAG, "Service being reused, forcing stoppage."); - System.exit(0); - return; - } - markInitialized(); - - ContextUtils.initApplicationContext(getApplicationContext()); - - PathUtils.setPrivateDataDirectorySuffix("chrome_multiprocess_test_client_service"); - - loadLibraries(); - } - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - private void loadLibraries() { - try { - LibraryLoader.get(LibraryProcessType.PROCESS_CHILD).loadNow(); - } catch (ProcessInitException pie) { - Log.e(TAG, "Unable to load native libraries.", pie); - } - } - - private void setMainReturnValue(int result) { - synchronized (mResultLock) { - mResult = new MainReturnCodeResult(result, false /* timed-out */); - mResultLock.notifyAll(); - } - } - - private static void markInitialized() { - // We don't set sAlreadyInitialized directly in onCreate to avoid FindBugs complaining about - // a static member been set from a non-static function. - sAlreadyInitialized = true; +/** The service implementation used to host all multiprocess test client code. */ +public class MultiprocessTestClientService extends ChildProcessService { + public MultiprocessTestClientService() { + super(new MultiprocessTestClientServiceDelegate()); } }
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java new file mode 100644 index 0000000..1ef4cfe --- /dev/null +++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java
@@ -0,0 +1,91 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +package org.chromium.base; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.SparseArray; + +import org.chromium.base.annotations.SuppressFBWarnings; +import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.base.library_loader.LibraryProcessType; +import org.chromium.base.library_loader.ProcessInitException; +import org.chromium.base.process_launcher.ChildProcessServiceDelegate; +import org.chromium.native_test.MainRunner; + +/** Implmentation of the ChildProcessServiceDelegate used for the Multiprocess tests. */ +public class MultiprocessTestClientServiceDelegate implements ChildProcessServiceDelegate { + private static final String TAG = "MPTestCSDelegate"; + + private ITestCallback mTestCallback; + + private final ITestController.Stub mTestController = new ITestController.Stub() { + @SuppressFBWarnings("DM_EXIT") + @Override + public boolean forceStopSynchronous(int exitCode) { + System.exit(exitCode); + return true; + } + + @SuppressFBWarnings("DM_EXIT") + @Override + public void forceStop(int exitCode) { + System.exit(exitCode); + } + }; + + @Override + public void onServiceCreated() { + PathUtils.setPrivateDataDirectorySuffix("chrome_multiprocess_test_client_service"); + } + + @Override + public void onServiceBound(Intent intent) {} + + @Override + public void onConnectionSetup(Bundle connectionBundle, IBinder callback) { + mTestCallback = ITestCallback.Stub.asInterface(callback); + } + + @Override + public void onDestroy() {} + + @Override + public boolean loadNativeLibrary(Context hostContext) { + try { + LibraryLoader.get(LibraryProcessType.PROCESS_CHILD).loadNow(); + return true; + } catch (ProcessInitException pie) { + Log.e(TAG, "Unable to load native libraries.", pie); + return false; + } + } + + @Override + public SparseArray<String> getFileDescriptorsIdsToKeys() { + return null; + } + + @Override + public void onBeforeMain() { + try { + mTestCallback.childConnected(mTestController); + } catch (RemoteException re) { + Log.e(TAG, "Failed to notify parent process of connection."); + } + } + + @Override + public void runMain() { + int result = MainRunner.runMain(CommandLine.getJavaSwitchesOrNull()); + try { + mTestCallback.mainReturned(result); + } catch (RemoteException re) { + Log.e(TAG, "Failed to notify parent process of main returning."); + } + } +}
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py index ba2311a..e7bf827 100755 --- a/build/android/gradle/generate_gradle.py +++ b/build/android/gradle/generate_gradle.py
@@ -211,7 +211,7 @@ def JavaFiles(self): if self._java_files is None: - java_sources_file = self.DepsInfo().get('java_sources_file') + java_sources_file = self.Gradle().get('java_sources_file') java_files = [] if java_sources_file: java_sources_file = _RebasePath(java_sources_file)
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index 6eab4b2..c085176 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -413,7 +413,7 @@ gradle['android_manifest'] = options.android_manifest if options.type in ('java_binary', 'java_library', 'android_apk'): if options.java_sources_file: - deps_info['java_sources_file'] = options.java_sources_file + gradle['java_sources_file'] = options.java_sources_file if options.bundled_srcjars: gradle['bundled_srcjars'] = ( build_utils.ParseGnList(options.bundled_srcjars)) @@ -436,14 +436,6 @@ gradle['dependent_java_projects'].append(c['path']) - if options.type == 'android_apk': - config['jni'] = {} - all_java_sources = [c['java_sources_file'] for c in all_library_deps - if 'java_sources_file' in c] - if options.java_sources_file: - all_java_sources.append(options.java_sources_file) - config['jni']['all_source'] = all_java_sources - if (options.type in ('java_binary', 'java_library')): deps_info['requires_android'] = options.requires_android deps_info['supports_android'] = options.supports_android
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py index d5536c7..cc376d18 100644 --- a/build/android/pylib/local/device/local_device_environment.py +++ b/build/android/pylib/local/device/local_device_environment.py
@@ -82,7 +82,7 @@ self._blacklist = (device_blacklist.Blacklist(args.blacklist_file) if args.blacklist_file else None) - self._device_serial = args.test_device + self._device_serials = args.test_devices self._devices_lock = threading.Lock() self._devices = None self._concurrent_adb = args.enable_concurrent_adb @@ -124,8 +124,8 @@ else: logging.info( 'Read device list %s from target devices file.', str(device_arg)) - elif self._device_serial: - device_arg = self._device_serial + elif self._device_serials: + device_arg = self._device_serials self._devices = device_utils.DeviceUtils.HealthyDevices( self._blacklist, enable_device_files_cache=self._enable_device_cache,
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 8574607..835888b0 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -216,9 +216,9 @@ type=os.path.realpath, help='Device blacklist file.') parser.add_argument( - '-d', '--device', - dest='test_device', - help='Target device for the test suite to run on.') + '-d', '--device', nargs='+', + dest='test_devices', + help='Target device(s) for the test suite to run on.') parser.add_argument( '--enable-concurrent-adb', action='store_true',
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index ceffd063..38032b768 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -192,6 +192,7 @@ "--depfile", rebase_path(depfile, root_build_dir), "--input_file={{source}}", + "--optimize_generation=1", "--ptr_type=long", "--output_dir", rebase_path(jni_output_dir, root_build_dir), @@ -301,6 +302,7 @@ rebase_path(jar_file, root_build_dir), "--input_file", class, + "--optimize_generation=1", "--ptr_type=long", "--output_dir", rebase_path(jni_output_dir, root_build_dir), @@ -332,61 +334,6 @@ } } - # Declare a jni registration target. - # - # This target generates a header file calling JNI registration functions - # created by generate_jni and generate_jar_jni. - # - # See base/android/jni_generator/jni_registration_generator.py for more info - # about the format of the header file. - # - # Variables - # target: The Apk target to generate registrations for. - # output: Path to the generated .h file. - # exception_files: List of .java files that should be ignored when searching - # for native methods. (optional) - # - # Example - # generate_jni_registration("chrome_jni_registration") { - # target = ":chrome_public_apk" - # output = "$root_gen_dir/chrome/browser/android/${target_name}.h" - # exception_files = [ - # "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - # "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - # "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - # ] - # } - template("generate_jni_registration") { - action(target_name) { - forward_variables_from(invoker, [ "testonly" ]) - _build_config = get_label_info(invoker.target, "target_gen_dir") + "/" + - get_label_info(invoker.target, "name") + ".build_config" - _rebased_build_config = rebase_path(_build_config, root_build_dir) - - _rebase_exception_java_files = - rebase_path(invoker.exception_files, root_build_dir) - - script = "//base/android/jni_generator/jni_registration_generator.py" - deps = [ - "${invoker.target}__build_config", - ] - inputs = [ - _build_config, - ] - outputs = [ - invoker.output, - ] - - args = [ - # This is a list of .sources files. - "--sources_files=@FileArg($_rebased_build_config:jni:all_source)", - "--output", - rebase_path(invoker.output, root_build_dir), - "--no_register_java=$_rebase_exception_java_files", - ] - } - } - # Declare a target for c-preprocessor-generated java files # # NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum
diff --git a/build/landmines.py b/build/landmines.py index 1b2f1cdb..991ec045 100755 --- a/build/landmines.py +++ b/build/landmines.py
@@ -11,6 +11,16 @@ A landmine is tripped when a builder checks out a different revision, and the diff between the new landmines and the old ones is non-null. At this point, the build is clobbered. + +Before adding or changing a landmine consider the consequences of doing so. +Doing so will wipe out every output directory on every Chrome developer's +machine. This can be particularly problematic on Windows where the directory +deletion may well fail (locked files, command prompt in the directory, etc.), +and generated .sln and .vcxproj files will be deleted. + +This output directory deletion will be repated when going back and forth across +the change that added the landmine, adding to the cost. There are usually less +troublesome alternatives. """ import difflib
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index eb5167d..1bb7d1ce 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -681,7 +681,6 @@ "../browser/android/chrome_entry_point.cc", ] deps = [ - ":chrome_jni_registration($default_toolchain)", "//build/config:exe_and_shlib_deps", "//chrome:chrome_android_core", ] @@ -706,30 +705,8 @@ } # Ensure that .pak files are built only once (build them in the default -# toolchain). The central header file calling JNI registration functions -# is generated from Java code so it just needs to be generated once. +# toolchain). if (current_toolchain == default_toolchain) { - generate_jni_registration("chrome_jni_registration") { - target = ":chrome_public_apk" - output = "$root_gen_dir/chrome/browser/android/${target_name}.h" - exception_files = [ - "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - ] - } - - generate_jni_registration("chrome_sync_shell_jni_registration") { - testonly = true - target = ":chrome_sync_shell_apk" - output = "$root_gen_dir/chrome/browser/android/${target_name}.h" - exception_files = [ - "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - ] - } - if (enable_resource_whitelist_generation) { generate_resource_whitelist("monochrome_resource_whitelist") { # Always use the 32-bit library's whitelist since the 64-bit one is @@ -825,13 +802,12 @@ shared_library("chrome_sync_shell") { testonly = true sources = [ - "../browser/android/chrome_sync_shell_entry_point.cc", + "../browser/android/chrome_entry_point.cc", "../browser/android/chrome_sync_shell_main_delegate.cc", "../browser/android/chrome_sync_shell_main_delegate.h", "../browser/android/chrome_sync_shell_main_delegate_initializer.cc", ] deps = [ - ":chrome_sync_shell_jni_registration($default_toolchain)", "//build/config:exe_and_shlib_deps", "//chrome:chrome_android_core", "//components/sync", @@ -912,9 +888,6 @@ apk_name = "ChromeSyncShell" shared_libraries = [ ":chrome_sync_shell" ] - # This exists here rather than in chrome_sync_shell_test_apk for JNI - # registration to be able to find the native side functions. - java_files = [ "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java" ] deps = [ ":chrome_sync_shell_apk_template_resources", @@ -922,7 +895,6 @@ # but that code is stripped out via proguard. Adding this deps adds # usages and prevents removal of the proto code. "//components/sync:test_support_proto_java", - "//third_party/android_protobuf:protobuf_nano_javalib", ] } @@ -1016,23 +988,11 @@ } } -instrumentation_test_apk("chrome_sync_shell_test_apk") { - apk_name = "ChromeSyncShellTest" - apk_under_test = ":chrome_sync_shell_apk" - android_manifest = chrome_sync_shell_test_apk_manifest - android_manifest_dep = ":chrome_sync_shell_test_apk_manifest" - java_files = [ - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java", - "sync_shell/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java", - ] +android_library("chrome_sync_shell_test_apk_java") { + testonly = true + + # From java_sources.jni. + java_files = sync_shell_test_java_sources deps = [ "//base:base_java", @@ -1048,9 +1008,21 @@ "//components/sync/android:sync_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", + "//third_party/android_protobuf:protobuf_nano_javalib", "//third_party/android_support_test_runner:runner_java", "//third_party/android_tools:android_support_v7_appcompat_java", "//ui/android:ui_java", ] +} + +instrumentation_test_apk("chrome_sync_shell_test_apk") { + apk_name = "ChromeSyncShellTest" + apk_under_test = ":chrome_sync_shell_apk" + android_manifest = chrome_sync_shell_test_apk_manifest + android_manifest_dep = ":chrome_sync_shell_test_apk_manifest" + deps = [ + ":chrome_sync_shell_test_apk_java", + "//third_party/android_support_test_runner:runner_java", + ] proguard_enabled = !is_java_debug }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java index f10b515..2c400dd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -287,7 +287,14 @@ mRenderToSurfaceLayoutParent = new FrameLayout(mActivity) { @Override public boolean dispatchTouchEvent(MotionEvent event) { - getContainer().dispatchTouchEvent(event); + // We only want to target touch events to the actual screen to the GvrUiLayout, + // which is dynamically loaded and attached to the GvrLayoutImpl. + for (int i = 0; i < getContainer().getChildCount(); ++i) { + View child = getContainer().getChildAt(i); + if (child.getClass().getSimpleName().equals("GvrLayoutImpl")) { + child.dispatchTouchEvent(event); + } + } return true; } }; @@ -334,6 +341,7 @@ } @Override protected void onPostExecute(Bitmap bitmap) { + if (mNativeVrShell == 0) return; nativeSetSplashScreenIcon(mNativeVrShell, bitmap); } }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 2c2e877..a72e0ac 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -1520,6 +1520,7 @@ "javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java", "javatests/src/org/chromium/chrome/browser/policy/CombinedPolicyProviderTest.java", "javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java", + "javatests/src/org/chromium/chrome/browser/payments/PaymentManifestParserTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java", @@ -1809,6 +1810,20 @@ "junit/src/org/chromium/chrome/browser/widget/selection/SelectionDelegateTest.java", ] +sync_shell_test_java_sources = [ + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java", + "sync_shell/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java", +] + # Only used for testing, should not be shipped to end users. if (enable_offline_pages_harness) { chrome_java_sources += [ "java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java" ]
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestParserTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestParserTest.java new file mode 100644 index 0000000..a926184 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestParserTest.java
@@ -0,0 +1,209 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.payments; + +import android.support.test.filters.MediumTest; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.components.payments.PaymentManifestParser; +import org.chromium.components.payments.PaymentManifestParser.ManifestParseCallback; +import org.chromium.content.browser.test.util.Criteria; +import org.chromium.content.browser.test.util.CriteriaHelper; +import org.chromium.payments.mojom.WebAppManifestSection; + +import java.net.URI; + +/** An integration test for the payment manifest parser. */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentManifestParserTest implements ManifestParseCallback { + @Rule + public ChromeActivityTestRule<ChromeActivity> mRule = + new ChromeActivityTestRule<>(ChromeActivity.class); + + private final PaymentManifestParser mParser = new PaymentManifestParser(); + private URI[] mWebAppManifestUris; + private WebAppManifestSection[] mWebAppManifest; + private boolean mParseFailure; + private boolean mParsePaymentMethodManifestSuccess; + private boolean mParseWebAppManifestSuccess; + + @Override + public void onPaymentMethodManifestParseSuccess(URI[] webAppManifestUris) { + mParsePaymentMethodManifestSuccess = true; + mWebAppManifestUris = webAppManifestUris.clone(); + } + + @Override + public void onWebAppManifestParseSuccess(WebAppManifestSection[] manifest) { + mParseWebAppManifestSuccess = true; + mWebAppManifest = manifest.clone(); + } + + @Override + public void onManifestParseFailure() { + mParseFailure = true; + } + + @Before + public void setUp() throws Throwable { + mRule.startMainActivityOnBlankPage(); + mRule.runOnUiThread(new Runnable() { + @Override + public void run() { + mParser.startUtilityProcess(); + } + }); + mWebAppManifestUris = null; + mWebAppManifest = null; + mParseFailure = false; + mParsePaymentMethodManifestSuccess = false; + mParseWebAppManifestSuccess = false; + } + + @After + public void tearDown() throws Throwable { + mRule.runOnUiThread(new Runnable() { + @Override + public void run() { + mParser.stopUtilityProcess(); + } + }); + } + + @Test + @MediumTest + @Feature({"Payments"}) + public void testParseInvalidPaymentMethodManifest() throws Throwable { + mRule.runOnUiThread(new Runnable() { + @Override + public void run() { + mParser.parsePaymentMethodManifest( + "invalid payment method manifest", PaymentManifestParserTest.this); + } + }); + CriteriaHelper.pollInstrumentationThread(new Criteria() { + @Override + public boolean isSatisfied() { + return mParseFailure; + } + }); + } + + @Test + @MediumTest + @Feature({"Payments"}) + public void testParsePaymentMethodManifest() throws Throwable { + mRule.runOnUiThread(new Runnable() { + @Override + public void run() { + mParser.parsePaymentMethodManifest("{" + + " \"default_applications\": [" + + " \"https://bobpay.com/app.json\"," + + " \"https://alicepay.com/app.json\"" + + " ]," + + " \"supported_origins\": [" + + " \"https://charliepay.com\"," + + " \"https://evepay.com\"" + + " ]" + + "}", + PaymentManifestParserTest.this); + } + }); + CriteriaHelper.pollInstrumentationThread(new Criteria() { + @Override + public boolean isSatisfied() { + return mParsePaymentMethodManifestSuccess; + } + }); + Assert.assertNotNull(mWebAppManifestUris); + Assert.assertEquals(2, mWebAppManifestUris.length); + Assert.assertEquals(new URI("https://bobpay.com/app.json"), mWebAppManifestUris[0]); + Assert.assertEquals(new URI("https://alicepay.com/app.json"), mWebAppManifestUris[1]); + } + + @Test + @MediumTest + @Feature({"Payments"}) + public void testParseInvalidWebAppManifest() throws Throwable { + mRule.runOnUiThread(new Runnable() { + @Override + public void run() { + mParser.parseWebAppManifest( + "invalid web app manifest", PaymentManifestParserTest.this); + } + }); + CriteriaHelper.pollInstrumentationThread(new Criteria() { + @Override + public boolean isSatisfied() { + return mParseFailure; + } + }); + } + + @Test + @MediumTest + @Feature({"Payments"}) + public void testParseWebAppManifest() throws Throwable { + mRule.runOnUiThread(new Runnable() { + @Override + public void run() { + mParser.parseWebAppManifest("{" + + " \"related_applications\": [{" + + " \"platform\": \"play\", " + + " \"id\": \"com.bobpay.app\", " + + " \"min_version\": \"1\", " + + " \"fingerprints\": [{" + + " \"type\": \"sha256_cert\", " + + " \"value\": \"" + + "00:01:02:03:04:05:06:07:08:09:" + + "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:" + + "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\"" + + " }]" + + " }]" + + "}", + PaymentManifestParserTest.this); + } + }); + CriteriaHelper.pollInstrumentationThread(new Criteria() { + @Override + public boolean isSatisfied() { + return mParseWebAppManifestSuccess; + } + }); + Assert.assertNotNull(mWebAppManifest); + Assert.assertEquals(1, mWebAppManifest.length); + Assert.assertNotNull(mWebAppManifest[0]); + Assert.assertEquals("com.bobpay.app", mWebAppManifest[0].id); + Assert.assertEquals(1, mWebAppManifest[0].minVersion); + Assert.assertNotNull(mWebAppManifest[0].fingerprints); + Assert.assertEquals(1, mWebAppManifest[0].fingerprints.length); + Assert.assertNotNull(mWebAppManifest[0].fingerprints[0]); + Assert.assertEquals(32, mWebAppManifest[0].fingerprints[0].length); + Assert.assertArrayEquals( + new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, (byte) 0xA0, + (byte) 0xA1, (byte) 0xA2, (byte) 0xA3, (byte) 0xA4, (byte) 0xA5, + (byte) 0xA6, (byte) 0xA7, (byte) 0xA8, (byte) 0xA9, (byte) 0xB0, + (byte) 0xB1, (byte) 0xB2, (byte) 0xB3, (byte) 0xB4, (byte) 0xB5, + (byte) 0xB6, (byte) 0xB7, (byte) 0xB8, (byte) 0xB9, (byte) 0xC0, + (byte) 0xC1}, + mWebAppManifest[0].fingerprints[0]); + } +} \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 9ec24e72..13ea874 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -508,6 +508,45 @@ cc::switches::kCompositedLayerBorders}, {flag_descriptions::kUiShowCompositedLayerBordersAll, cc::switches::kUIShowCompositedLayerBorders, ""}}; + +const FeatureEntry::Choice kSpuriousPowerButtonWindowChoices[] = { + {"0", "", ""}, + {"5", ash::switches::kSpuriousPowerButtonWindow, "5"}, + {"10", ash::switches::kSpuriousPowerButtonWindow, "10"}, + {"15", ash::switches::kSpuriousPowerButtonWindow, "15"}, + {"20", ash::switches::kSpuriousPowerButtonWindow, "20"}, +}; +const FeatureEntry::Choice kSpuriousPowerButtonAccelCountChoices[] = { + {"0", "", ""}, + {"1", ash::switches::kSpuriousPowerButtonAccelCount, "1"}, + {"2", ash::switches::kSpuriousPowerButtonAccelCount, "2"}, + {"3", ash::switches::kSpuriousPowerButtonAccelCount, "3"}, + {"4", ash::switches::kSpuriousPowerButtonAccelCount, "4"}, + {"5", ash::switches::kSpuriousPowerButtonAccelCount, "5"}, +}; +const FeatureEntry::Choice kSpuriousPowerButtonScreenAccelChoices[] = { + {"0", "", ""}, + {"0.2", ash::switches::kSpuriousPowerButtonScreenAccel, "0.2"}, + {"0.4", ash::switches::kSpuriousPowerButtonScreenAccel, "0.4"}, + {"0.6", ash::switches::kSpuriousPowerButtonScreenAccel, "0.6"}, + {"0.8", ash::switches::kSpuriousPowerButtonScreenAccel, "0.8"}, + {"1.0", ash::switches::kSpuriousPowerButtonScreenAccel, "1.0"}, +}; +const FeatureEntry::Choice kSpuriousPowerButtonKeyboardAccelChoices[] = { + {"0", "", ""}, + {"0.2", ash::switches::kSpuriousPowerButtonKeyboardAccel, "0.2"}, + {"0.4", ash::switches::kSpuriousPowerButtonKeyboardAccel, "0.4"}, + {"0.6", ash::switches::kSpuriousPowerButtonKeyboardAccel, "0.6"}, + {"0.8", ash::switches::kSpuriousPowerButtonKeyboardAccel, "0.8"}, + {"1.0", ash::switches::kSpuriousPowerButtonKeyboardAccel, "1.0"}, +}; +const FeatureEntry::Choice kSpuriousPowerButtonLidAngleChangeChoices[] = { + {"0", "", ""}, + {"45", ash::switches::kSpuriousPowerButtonLidAngleChange, "45"}, + {"90", ash::switches::kSpuriousPowerButtonLidAngleChange, "90"}, + {"135", ash::switches::kSpuriousPowerButtonLidAngleChange, "135"}, + {"180", ash::switches::kSpuriousPowerButtonLidAngleChange, "180"}, +}; #endif // OS_CHROMEOS const FeatureEntry::Choice kV8CacheOptionsChoices[] = { @@ -1341,6 +1380,26 @@ kOsCrOS, SINGLE_VALUE_TYPE( proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)}, + {"spurious-power-button-window", + flag_descriptions::kSpuriousPowerButtonWindowName, + flag_descriptions::kSpuriousPowerButtonWindowDescription, kOsCrOS, + MULTI_VALUE_TYPE(kSpuriousPowerButtonWindowChoices)}, + {"spurious-power-button-accel-count", + flag_descriptions::kSpuriousPowerButtonAccelCountName, + flag_descriptions::kSpuriousPowerButtonAccelCountDescription, kOsCrOS, + MULTI_VALUE_TYPE(kSpuriousPowerButtonAccelCountChoices)}, + {"spurious-power-button-screen-accel", + flag_descriptions::kSpuriousPowerButtonScreenAccelName, + flag_descriptions::kSpuriousPowerButtonScreenAccelDescription, kOsCrOS, + MULTI_VALUE_TYPE(kSpuriousPowerButtonScreenAccelChoices)}, + {"spurious-power-button-keyboard-accel", + flag_descriptions::kSpuriousPowerButtonKeyboardAccelName, + flag_descriptions::kSpuriousPowerButtonKeyboardAccelDescription, kOsCrOS, + MULTI_VALUE_TYPE(kSpuriousPowerButtonKeyboardAccelChoices)}, + {"spurious-power-button-lid-angle-change", + flag_descriptions::kSpuriousPowerButtonLidAngleChangeName, + flag_descriptions::kSpuriousPowerButtonLidAngleChangeDescription, kOsCrOS, + MULTI_VALUE_TYPE(kSpuriousPowerButtonLidAngleChangeChoices)}, #endif // OS_CHROMEOS #if defined(USE_ASH) {"ash-disable-night-light", flag_descriptions::kDisableNightLightName,
diff --git a/chrome/browser/android/DEPS b/chrome/browser/android/DEPS index 8f032b7..bb55a8c 100644 --- a/chrome/browser/android/DEPS +++ b/chrome/browser/android/DEPS
@@ -2,7 +2,6 @@ "-components/devtools_bridge", "+cc/layers/layer.h", "+cc/output/context_provider.h", - "+chrome_jni_registration/chrome_jni_registration.h", "+components/doodle", "+components/ntp_snippets", "+components/spellcheck/browser",
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc index b9229eb8..796faab0 100644 --- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc +++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -41,7 +41,6 @@ bool AppBannerInfoBarDelegateAndroid::Create( content::WebContents* web_contents, base::WeakPtr<AppBannerManager> weak_manager, - const base::string16& app_title, std::unique_ptr<ShortcutInfo> shortcut_info, const SkBitmap& primary_icon, const SkBitmap& badge_icon, @@ -55,8 +54,8 @@ auto infobar_delegate = base::WrapUnique(new banners::AppBannerInfoBarDelegateAndroid( - weak_manager, app_title, std::move(shortcut_info), primary_icon, - badge_icon, event_request_id, is_webapk, webapk_install_source)); + weak_manager, std::move(shortcut_info), primary_icon, badge_icon, + event_request_id, is_webapk, webapk_install_source)); auto* raw_delegate = infobar_delegate.get(); auto infobar = base::MakeUnique<AppBannerInfoBarAndroid>( std::move(infobar_delegate), url, is_webapk); @@ -203,7 +202,6 @@ AppBannerInfoBarDelegateAndroid::AppBannerInfoBarDelegateAndroid( base::WeakPtr<AppBannerManager> weak_manager, - const base::string16& app_title, std::unique_ptr<ShortcutInfo> shortcut_info, const SkBitmap& primary_icon, const SkBitmap& badge_icon, @@ -211,7 +209,7 @@ bool is_webapk, webapk::InstallSource webapk_install_source) : weak_manager_(weak_manager), - app_title_(app_title), + app_title_(shortcut_info->name), shortcut_info_(std::move(shortcut_info)), primary_icon_(primary_icon), badge_icon_(badge_icon),
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h index c3c7561..ecba8527 100644 --- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h +++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
@@ -39,7 +39,6 @@ // app, and adds the infobar to the InfoBarManager for |web_contents|. static bool Create(content::WebContents* web_contents, base::WeakPtr<AppBannerManager> weak_manager, - const base::string16& app_title, std::unique_ptr<ShortcutInfo> info, const SkBitmap& primary_icon, const SkBitmap& badge_icon, @@ -94,7 +93,6 @@ // Delegate for promoting a web app. AppBannerInfoBarDelegateAndroid( base::WeakPtr<AppBannerManager> weak_manager, - const base::string16& app_title, std::unique_ptr<ShortcutInfo> info, const SkBitmap& primary_icon, const SkBitmap& badge_icon,
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc index 84126a3e..f50e444 100644 --- a/chrome/browser/android/banners/app_banner_manager_android.cc +++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -245,12 +245,11 @@ DCHECK(contents); if (native_app_data_.is_null()) { - std::unique_ptr<ShortcutInfo> info = - CreateShortcutInfo(manifest_url_, manifest_, primary_icon_url_, - badge_icon_url_, can_install_webapk_); if (AppBannerInfoBarDelegateAndroid::Create( - contents, GetWeakPtr(), info->name, std::move(info), primary_icon_, - badge_icon_, event_request_id(), can_install_webapk_, + contents, GetWeakPtr(), + CreateShortcutInfo(manifest_url_, manifest_, primary_icon_url_, + badge_icon_url_, can_install_webapk_), + primary_icon_, badge_icon_, event_request_id(), can_install_webapk_, webapk::INSTALL_SOURCE_BANNER)) { RecordDidShowBanner("AppBanner.WebApp.Shown"); TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED);
diff --git a/chrome/browser/android/chrome_entry_point.cc b/chrome/browser/android/chrome_entry_point.cc index 079358b..ee46cd6c 100644 --- a/chrome/browser/android/chrome_entry_point.cc +++ b/chrome/browser/android/chrome_entry_point.cc
@@ -7,7 +7,6 @@ #include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "chrome/app/android/chrome_jni_onload.h" -#include "chrome/browser/android/chrome_jni_registration.h" namespace { @@ -24,19 +23,6 @@ // Java side and only register a subset of JNI methods. base::android::InitVM(vm); JNIEnv* env = base::android::AttachCurrentThread(); - - if (!base::android::IsSelectiveJniRegistrationEnabled(env)) { - if (!RegisterNonMainDexNatives(env)) { - return -1; - } - } - - if (!RegisterMainDexNatives(env)) { - return -1; - } - - // TODO(agrieve): Delete this block, this is a no-op now. - // https://crbug.com/683256. if (base::android::IsSelectiveJniRegistrationEnabled(env)) { base::android::SetJniRegistrationType( base::android::SELECTIVE_JNI_REGISTRATION);
diff --git a/chrome/browser/android/chrome_sync_shell_entry_point.cc b/chrome/browser/android/chrome_sync_shell_entry_point.cc deleted file mode 100644 index e14ea511..0000000 --- a/chrome/browser/android/chrome_sync_shell_entry_point.cc +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_android.h" -#include "base/android/jni_utils.h" -#include "base/android/library_loader/library_loader_hooks.h" -#include "base/bind.h" -#include "chrome/app/android/chrome_jni_onload.h" -#include "chrome/browser/android/chrome_sync_shell_jni_registration.h" - -namespace { - -bool NativeInit() { - return android::OnJNIOnLoadInit(); -} - -} // namespace - -// This is called by the VM when the shared library is first loaded. -JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - // By default, all JNI methods are registered. However, since render processes - // don't need very much Java code, we enable selective JNI registration on the - // Java side and only register a subset of JNI methods. - base::android::InitVM(vm); - JNIEnv* env = base::android::AttachCurrentThread(); - - if (!base::android::IsSelectiveJniRegistrationEnabled(env)) { - if (!RegisterNonMainDexNatives(env)) { - return -1; - } - } - - if (!RegisterMainDexNatives(env)) { - return -1; - } - - // TODO(agrieve): Delete this block, this is a no-op now. - // https://crbug.com/683256. - if (base::android::IsSelectiveJniRegistrationEnabled(env)) { - base::android::SetJniRegistrationType( - base::android::SELECTIVE_JNI_REGISTRATION); - } - if (!android::OnJNIOnLoadRegisterJNI(env)) { - return -1; - } - base::android::SetNativeInitializationHook(NativeInit); - return JNI_VERSION_1_4; -}
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc index f5e8ecd..bba4d5d 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -176,7 +176,7 @@ banners::AppBannerManagerAndroid* app_banner_manager = banners::AppBannerManagerAndroid::FromWebContents(web_contents); banners::AppBannerInfoBarDelegateAndroid::Create( - web_contents, app_banner_manager->GetWeakPtr(), info.user_title, + web_contents, app_banner_manager->GetWeakPtr(), base::MakeUnique<ShortcutInfo>(info), primary_icon, badge_icon, -1 /* event_request_id */, true /* is_webapk */, webapk::INSTALL_SOURCE_MENU);
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm index f87d266..212af96 100644 --- a/chrome/browser/app_controller_mac_browsertest.mm +++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -426,7 +426,6 @@ SessionStartupPref pref(GetParam()); pref.urls.push_back(GURL(kPresetURL)); SessionStartupPref::SetStartupPref(browser()->profile(), pref); - InProcessBrowserTest::SetUpOnMainThread(); } protected: @@ -504,7 +503,6 @@ SessionStartupPref pref(session_startup_pref_); pref.urls.push_back(GURL(kPresetURL)); SessionStartupPref::SetStartupPref(browser()->profile(), pref); - InProcessBrowserTest::SetUpOnMainThread(); } void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc index 62fb446..56f0fbc 100644 --- a/chrome/browser/autofill/autofill_browsertest.cc +++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -108,7 +108,6 @@ test::DisableSystemServices(browser()->profile()->GetPrefs()); ASSERT_TRUE(embedded_test_server()->Start()); - InProcessBrowserTest::SetUpOnMainThread(); } void TearDownOnMainThread() override {
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc index 7fbb4d0..34f6096 100644 --- a/chrome/browser/banners/app_banner_manager_browsertest.cc +++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -115,7 +115,6 @@ AppBannerSettingsHelper::SetTotalEngagementToTrigger(10); SiteEngagementScore::SetParamValuesForTesting(); ASSERT_TRUE(embedded_test_server()->Start()); - InProcessBrowserTest::SetUpOnMainThread(); } void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/budget_service/budget_manager_browsertest.cc b/chrome/browser/budget_service/budget_manager_browsertest.cc index 954e4d59..f72dfb2d 100644 --- a/chrome/browser/budget_service/budget_manager_browsertest.cc +++ b/chrome/browser/budget_service/budget_manager_browsertest.cc
@@ -58,7 +58,6 @@ std::string(), CONTENT_SETTING_ALLOW); LoadTestPage(); - InProcessBrowserTest::SetUpOnMainThread(); budget_manager_ = BudgetManagerFactory::GetForProfile(browser()->profile()); }
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc index c6cfad40..c47f338 100644 --- a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
@@ -23,8 +23,6 @@ ~SelectToSpeakTest() override {} void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - ASSERT_FALSE(AccessibilityManager::Get()->IsSelectToSpeakEnabled()); content::WindowedNotificationObserver extension_load_waiter( @@ -42,6 +40,7 @@ SpeechMonitor speech_monitor_; std::unique_ptr<ui::test::EventGenerator> generator_; + private: DISALLOW_COPY_AND_ASSIGN(SelectToSpeakTest); };
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_live_site_browsertest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_live_site_browsertest.cc index f1776ed..e8298190 100644 --- a/chrome/browser/chromeos/accessibility/select_to_speak_live_site_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/select_to_speak_live_site_browsertest.cc
@@ -25,7 +25,6 @@ class SelectToSpeakLiveSiteTest : public InProcessBrowserTest { protected: void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); ASSERT_FALSE(AccessibilityManager::Get()->IsSelectToSpeakEnabled());
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc index 4f02848..3ec20534 100644 --- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc +++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc
@@ -87,8 +87,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - settings_helper_.ReplaceProvider(kAccountsPrefDeviceLocalAccounts); owner_settings_service_ = settings_helper_.CreateOwnerSettingsService(browser()->profile());
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc index a6b51ce..4ccc3e6 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
@@ -250,8 +250,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - host_resolver()->AddRule("*", "127.0.0.1"); // Start the accept thread as the sandbox host process has already been
diff --git a/chrome/browser/chromeos/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/file_manager/url_util_unittest.cc index fa1a9a1..16d4439e 100644 --- a/chrome/browser/chromeos/file_manager/url_util_unittest.cc +++ b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
@@ -11,6 +11,7 @@ #include "base/json/json_writer.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "extensions/common/constants.h" #include "net/base/escape.h" #include "testing/gtest/include/gtest/gtest.h" @@ -45,7 +46,7 @@ NULL, // No file types 0, // Hence no file type index. FILE_PATH_LITERAL("txt")); - EXPECT_EQ("chrome-extension", url.scheme()); + EXPECT_EQ(extensions::kExtensionScheme, url.scheme()); EXPECT_EQ("hhaomjibdihmijegdhdafkllkbggdgoj", url.host()); EXPECT_EQ("/main.html", url.path()); // Confirm that "%20" is used instead of "+" in the query. @@ -94,7 +95,7 @@ &file_types, 1, // The file type index is 1-based. FILE_PATH_LITERAL("txt")); - EXPECT_EQ("chrome-extension", url.scheme()); + EXPECT_EQ(extensions::kExtensionScheme, url.scheme()); EXPECT_EQ("hhaomjibdihmijegdhdafkllkbggdgoj", url.host()); EXPECT_EQ("/main.html", url.path()); // Confirm that "%20" is used instead of "+" in the query.
diff --git a/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc b/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc index a2619f0a..70eac8eb 100644 --- a/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc +++ b/chrome/browser/chromeos/fileapi/file_system_backend_unittest.cc
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h" #include "chromeos/dbus/cros_disks_client.h" +#include "extensions/common/constants.h" #include "storage/browser/fileapi/external_mount_points.h" #include "storage/browser/fileapi/file_system_url.h" #include "testing/gtest/include/gtest/gtest.h" @@ -108,7 +109,8 @@ } TEST(ChromeOSFileSystemBackendTest, AccessPermissions) { - url::AddStandardScheme("chrome-extension", url::SCHEME_WITHOUT_PORT); + url::AddStandardScheme(extensions::kExtensionScheme, + url::SCHEME_WITHOUT_PORT); scoped_refptr<storage::ExternalMountPoints> mount_points( storage::ExternalMountPoints::CreateRefCounted());
diff --git a/chrome/browser/chromeos/first_run/drive_first_run_browsertest.cc b/chrome/browser/chromeos/first_run/drive_first_run_browsertest.cc index 7f1d08a..2350a9c2 100644 --- a/chrome/browser/chromeos/first_run/drive_first_run_browsertest.cc +++ b/chrome/browser/chromeos/first_run/drive_first_run_browsertest.cc
@@ -88,7 +88,6 @@ success_(false) {} void DriveFirstRunTest::SetUpOnMainThread() { - InProcessBrowserTest::SetUpOnMainThread(); PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_); test_data_dir_ = test_data_dir_.AppendASCII(kTestDirectory);
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc index 2c2eff8..4c74e46 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -41,7 +41,6 @@ #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" #include "third_party/icu/source/common/unicode/uloc.h" -#include "ui/base/accelerators/accelerator.h" #include "ui/base/ime/chromeos/component_extension_ime_manager.h" #include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/fake_ime_keyboard.h" @@ -730,7 +729,7 @@ } } -bool InputMethodManagerImpl::StateImpl::CanCycleInputMethod() { +bool InputMethodManagerImpl::StateImpl::CanCycleInputMethod() const { // Sanity checks. if (active_input_method_ids.empty()) { DVLOG(1) << "active input method is empty"; @@ -742,13 +741,10 @@ return false; } - // Do not consume key event if there is only one input method is enabled. - // Ctrl+Space or Alt+Shift may be used by other application. return active_input_method_ids.size() > 1; } void InputMethodManagerImpl::StateImpl::SwitchToNextInputMethod() { - DCHECK(CanCycleInputMethod()); if (!CanCycleInputMethod()) return; @@ -758,7 +754,6 @@ } void InputMethodManagerImpl::StateImpl::SwitchToPreviousInputMethod() { - DCHECK(CanCycleInputMethod()); if (!CanCycleInputMethod()) return; @@ -780,25 +775,6 @@ ChangeInputMethod(*iter, true); } -bool InputMethodManagerImpl::StateImpl::CanSwitchInputMethod( - const ui::Accelerator& accelerator) { - // If none of the input methods associated with |accelerator| are active, we - // should ignore the accelerator. For example, we should just ignore - // VKEY_HANGUL when mozc-hangul is not active. - std::vector<std::string> candidate_ids; - GetCandidateInputMethodsForAccelerator(accelerator, &candidate_ids); - return !candidate_ids.empty(); -} - -void InputMethodManagerImpl::StateImpl::SwitchInputMethod( - const ui::Accelerator& accelerator) { - std::vector<std::string> candidate_ids; - GetCandidateInputMethodsForAccelerator(accelerator, &candidate_ids); - DCHECK(!candidate_ids.empty()); - if (!candidate_ids.empty()) - SwitchToNextInputMethodInternal(candidate_ids, current_input_method.id()); -} - void InputMethodManagerImpl::StateImpl::SwitchToNextInputMethodInternal( const std::vector<std::string>& input_method_ids, const std::string& current_input_methodid) { @@ -811,52 +787,6 @@ ChangeInputMethod(*iter, true); } -void InputMethodManagerImpl::StateImpl::GetCandidateInputMethodsForAccelerator( - const ui::Accelerator& accelerator, - std::vector<std::string>* out_candidate_ids) { - out_candidate_ids->clear(); - - // Sanity check. - if (active_input_method_ids.empty()) { - DVLOG(1) << "active input method is empty"; - return; - } - - std::vector<std::string> input_method_ids_to_switch; - switch (accelerator.key_code()) { - case ui::VKEY_CONVERT: // Henkan key on JP106 keyboard - input_method_ids_to_switch.push_back( - extension_ime_util::GetInputMethodIDByEngineID("nacl_mozc_jp")); - break; - case ui::VKEY_NONCONVERT: // Muhenkan key on JP106 keyboard - input_method_ids_to_switch.push_back( - extension_ime_util::GetInputMethodIDByEngineID("xkb:jp::jpn")); - break; - case ui::VKEY_DBE_SBCSCHAR: // ZenkakuHankaku key on JP106 keyboard - case ui::VKEY_DBE_DBCSCHAR: - input_method_ids_to_switch.push_back( - extension_ime_util::GetInputMethodIDByEngineID("nacl_mozc_jp")); - input_method_ids_to_switch.push_back( - extension_ime_util::GetInputMethodIDByEngineID("xkb:jp::jpn")); - break; - default: - NOTREACHED(); - break; - } - if (input_method_ids_to_switch.empty()) { - DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code(); - return; - } - - // Obtain the intersection of input_method_ids_to_switch and - // active_input_method_ids. - for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) { - const std::string& id = input_method_ids_to_switch[i]; - if (base::ContainsValue(active_input_method_ids, id)) - out_candidate_ids->push_back(id); - } -} - InputMethodDescriptor InputMethodManagerImpl::StateImpl::GetCurrentInputMethod() const { if (current_input_method.id().empty())
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h index b5c5d8a3..7a4dd45 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -66,17 +66,14 @@ const std::vector<std::string>& input_method_ids, const std::string& current_input_methodid); - // Returns the IDs of the subset of input methods which are active and are - // associated with |accelerator|. For example, - // { "mozc-hangul", "xkb:kr:kr104:kor" } is returned for - // ui::VKEY_DBE_SBCSCHAR if the two input methods are active. - void GetCandidateInputMethodsForAccelerator( - const ui::Accelerator& accelerator, - std::vector<std::string>* out_candidate_ids); - // Returns true if given input method requires pending extension. bool MethodAwaitsExtensionLoad(const std::string& input_method_id) const; + // Returns whether the input method (or keyboard layout) can be switched + // to the next or previous one. Returns false if only one input method is + // enabled. + bool CanCycleInputMethod() const; + // InputMethodManager::State overrides. scoped_refptr<InputMethodManager::State> Clone() const override; void AddInputMethodExtension( @@ -103,11 +100,8 @@ void SetInputMethodLoginDefault() override; void SetInputMethodLoginDefaultFromVPD(const std::string& locale, const std::string& layout) override; - bool CanCycleInputMethod() override; void SwitchToNextInputMethod() override; void SwitchToPreviousInputMethod() override; - bool CanSwitchInputMethod(const ui::Accelerator& accelerator) override; - void SwitchInputMethod(const ui::Accelerator& accelerator) override; InputMethodDescriptor GetCurrentInputMethod() const override; bool ReplaceEnabledInputMethods( const std::vector<std::string>& new_active_input_method_ids) override;
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc index 3e657f0..9253734 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -29,7 +29,6 @@ #include "chrome/test/base/testing_profile_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/accelerators/accelerator.h" #include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/fake_ime_keyboard.h" #include "ui/base/ime/chromeos/fake_input_method_delegate.h" @@ -39,7 +38,6 @@ #include "ui/base/ime/input_method_initializer.h" #include "ui/chromeos/ime/input_method_menu_item.h" #include "ui/chromeos/ime/input_method_menu_manager.h" -#include "ui/events/keycodes/keyboard_codes.h" #include "ui/keyboard/content/keyboard_content_util.h" namespace chromeos { @@ -1013,7 +1011,6 @@ keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng")); manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts); EXPECT_EQ(8U, manager_->GetActiveIMEState()->GetNumActiveInputMethods()); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanCycleInputMethod()); EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); EXPECT_EQ("us", keyboard_->last_layout_); @@ -1061,160 +1058,24 @@ manager_->RemoveObserver(&observer); } -TEST_F(InputMethodManagerImplTest, - TestCanCycleInputMethodForOneActiveInputMethod) { - TestObserver observer; +TEST_F(InputMethodManagerImplTest, CycleInputMethodForOneActiveInputMethod) { InitComponentExtension(); - manager_->AddObserver(&observer); + // Simulate a single input method. std::vector<std::string> ids; - ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); + ids.push_back(ImeIdFromEngineId("xkb:us::eng")); EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids)); EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods()); - // CanCycleInputMethod() should return false if there is only one active input - // method. - EXPECT_FALSE(manager_->GetActiveIMEState()->CanCycleInputMethod()); - - manager_->RemoveObserver(&observer); -} - -TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithUsLayouts) { - InitComponentExtension(); - std::vector<std::string> keyboard_layouts; - keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng")); - manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts); - EXPECT_EQ(8U, manager_->GetActiveIMEState()->GetNumActiveInputMethods()); - - // Henkan, Muhenkan, ZenkakuHankaku should be ignored when no Japanese IMEs - // and keyboards are enabled. - EXPECT_FALSE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE))); - EXPECT_FALSE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); - EXPECT_FALSE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); - EXPECT_FALSE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); -} - -TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpLayout) { - // Enable "xkb:jp::jpn" and press Muhenkan/ZenkakuHankaku. - InitComponentExtension(); - - std::vector<std::string> keyboard_layouts; - keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng")); - manager_->GetActiveIMEState()->EnableLoginLayouts("ja", keyboard_layouts); - EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods()); + // Switching to next does nothing. + manager_->GetActiveIMEState()->SwitchToNextInputMethod(); EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("us", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanCycleInputMethod()); + + // Switching to previous does nothing. manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(); EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("us", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanCycleInputMethod()); - manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(); - EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("us", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); -} - -TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) { - InitComponentExtension(); - manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); - std::vector<std::string> ids; - ids.push_back(ImeIdFromEngineId("xkb:jp::jpn")); - ids.push_back(ImeIdFromEngineId(kNaclMozcJpId)); - EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - - // Add Dvorak. - ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); - EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); - EXPECT_TRUE(manager_->GetActiveIMEState()->CanSwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); - manager_->GetActiveIMEState()->SwitchInputMethod( - ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)); - EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"), - manager_->GetActiveIMEState()->GetCurrentInputMethod().id()); - EXPECT_EQ("jp", keyboard_->last_layout_); } TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
diff --git a/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc b/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc index d9c843b7..a21a5857 100644 --- a/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc +++ b/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc
@@ -133,7 +133,6 @@ // Add keyboard layouts to enable the mode indicator. imm->GetActiveIMEState()->EnableLoginLayouts("fr", keyboard_layouts); ASSERT_LT(1UL, imm->GetActiveIMEState()->GetNumActiveInputMethods()); - EXPECT_TRUE(imm->GetActiveIMEState()->CanCycleInputMethod()); chromeos::IMECandidateWindowHandlerInterface* candidate_window = ui::IMEBridge::Get()->GetCandidateWindowHandler(); @@ -203,7 +202,6 @@ // Add keyboard layouts to enable the mode indicator. imm->GetActiveIMEState()->EnableLoginLayouts("fr", keyboard_layouts); ASSERT_LT(1UL, imm->GetActiveIMEState()->GetNumActiveInputMethods()); - EXPECT_TRUE(imm->GetActiveIMEState()->CanCycleInputMethod()); chromeos::IMECandidateWindowHandlerInterface* candidate_window = ui::IMEBridge::Get()->GetCandidateWindowHandler();
diff --git a/chrome/browser/chromeos/login/mixin_based_browser_test.cc b/chrome/browser/chromeos/login/mixin_based_browser_test.cc index 4d6cbe22..fdeaae4 100644 --- a/chrome/browser/chromeos/login/mixin_based_browser_test.cc +++ b/chrome/browser/chromeos/login/mixin_based_browser_test.cc
@@ -36,8 +36,6 @@ setup_was_launched_ = true; for (const auto& mixin : mixins_) mixin->SetUpOnMainThread(); - - InProcessBrowserTest::SetUpOnMainThread(); } void MixinBasedBrowserTest::TearDownOnMainThread() {
diff --git a/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc b/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc index 83085ff..1234a84 100644 --- a/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc +++ b/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc
@@ -101,7 +101,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); ASSERT_TRUE(embedded_test_server()->Start()); web_contents_ = browser()->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/dom_distiller/tab_utils_browsertest.cc b/chrome/browser/dom_distiller/tab_utils_browsertest.cc index ddc07da6..c494ba3 100644 --- a/chrome/browser/dom_distiller/tab_utils_browsertest.cc +++ b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
@@ -41,7 +41,6 @@ if (!DistillerJavaScriptWorldIdIsSet()) { SetDistillerJavaScriptWorldId(content::ISOLATED_WORLD_ID_CONTENT_END); } - InProcessBrowserTest::SetUpOnMainThread(); } void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/domain_reliability/browsertest.cc b/chrome/browser/domain_reliability/browsertest.cc index c70aacd..b87684c 100644 --- a/chrome/browser/domain_reliability/browsertest.cc +++ b/chrome/browser/domain_reliability/browsertest.cc
@@ -36,8 +36,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - DomainReliabilityService* service = GetService(); if (service) service->SetDiscardUploadsForTesting(false);
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc index 4dbbf13..0a4e9ba 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc +++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -316,7 +316,6 @@ BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::BindOnce(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); - InProcessBrowserTest::SetUpOnMainThread(); GoOnTheRecord(); CreateAndSetDownloadsDirectory(); current_browser()->profile()->GetPrefs()->SetBoolean(
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc index e76e4ff3..622235a 100644 --- a/chrome/browser/extensions/extension_browsertest.cc +++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -185,7 +185,6 @@ } void ExtensionBrowserTest::SetUpOnMainThread() { - InProcessBrowserTest::SetUpOnMainThread(); observer_.reset( new extensions::ChromeExtensionTestNotificationObserver(browser())); if (extension_service()->updater()) {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index e88f4d37..0714a23 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -3049,6 +3049,37 @@ "If enabled and the device supports ARC, the user will be asked to update " "the encryption of user data when the user signs in."; +// Spurious power button detection + +const char kSpuriousPowerButtonWindowName[] = "Spurious power button window"; +const char kSpuriousPowerButtonWindowDescription[] = + "Number of recent accelerometer samples to examine to determine if a power " + "button event was spurious."; + +const char kSpuriousPowerButtonAccelCountName[] = + "Spurious power button acceleration count"; +const char kSpuriousPowerButtonAccelCountDescription[] = + "Number of recent acceleration samples that must meet or exceed exceed the " + "threshold in order for a power button event to be considered spurious."; + +const char kSpuriousPowerButtonScreenAccelName[] = + "Spurious power button screen acceleration threshold"; +const char kSpuriousPowerButtonScreenAccelDescription[] = + "Threshold (in m/s^2, disregarding gravity) that screen acceleration must " + "meet or exceed for a power button event to be considered spurious."; + +const char kSpuriousPowerButtonKeyboardAccelName[] = + "Spurious power button keyboard acceleration threshold"; +const char kSpuriousPowerButtonKeyboardAccelDescription[] = + "Threshold (in m/s^2, disregarding gravity) that keyboard acceleration " + "must meet or exceed for a power button event to be considered spurious."; + +const char kSpuriousPowerButtonLidAngleChangeName[] = + "Spurious power button lid angle change threshold"; +const char kSpuriousPowerButtonLidAngleChangeDescription[] = + "Change in lid angle (i.e. hinge between keyboard and screen) that must be " + "met or exceeded for a power button event to be considered spurious."; + #endif // #if defined(OS_CHROMEOS) #if defined(OS_ANDROID)
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 89342fc..e5a1429 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1367,6 +1367,17 @@ extern const char kSmartVirtualKeyboardName[]; extern const char kSmartVirtualKeyboardDescription[]; +extern const char kSpuriousPowerButtonWindowName[]; +extern const char kSpuriousPowerButtonWindowDescription[]; +extern const char kSpuriousPowerButtonAccelCountName[]; +extern const char kSpuriousPowerButtonAccelCountDescription[]; +extern const char kSpuriousPowerButtonScreenAccelName[]; +extern const char kSpuriousPowerButtonScreenAccelDescription[]; +extern const char kSpuriousPowerButtonKeyboardAccelName[]; +extern const char kSpuriousPowerButtonKeyboardAccelDescription[]; +extern const char kSpuriousPowerButtonLidAngleChangeName[]; +extern const char kSpuriousPowerButtonLidAngleChangeDescription[]; + extern const char kTeamDrivesName[]; extern const char kTeamDrivesDescription[];
diff --git a/chrome/browser/installable/installable_manager_browsertest.cc b/chrome/browser/installable/installable_manager_browsertest.cc index f9e5bf92..3ac72f6 100644 --- a/chrome/browser/installable/installable_manager_browsertest.cc +++ b/chrome/browser/installable/installable_manager_browsertest.cc
@@ -176,7 +176,6 @@ class InstallableManagerBrowserTest : public InProcessBrowserTest { public: void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); ASSERT_TRUE(embedded_test_server()->Start()); }
diff --git a/chrome/browser/io_thread_browsertest.cc b/chrome/browser/io_thread_browsertest.cc index b7c536e1..b5c3c00 100644 --- a/chrome/browser/io_thread_browsertest.cc +++ b/chrome/browser/io_thread_browsertest.cc
@@ -73,8 +73,6 @@ void SetUpOnMainThread() override { embedded_test_server()->StartAcceptingConnections(); - - InProcessBrowserTest::SetUpOnMainThread(); } void TearDown() override {
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc index 0a4173a..1b3e44a 100644 --- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc +++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -223,7 +223,6 @@ public testing::WithParamInterface<bool> { protected: void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); SessionStartupPref::SetStartupPref( browser()->profile(), SessionStartupPref(SessionStartupPref::LAST)); browsers_.push_back(browser());
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc index afd87c1..7867326 100644 --- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc +++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
@@ -209,7 +209,6 @@ ChromeResourceDispatcherHostDelegateBrowserTest() {} void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); // Hook navigations with our delegate. dispatcher_host_delegate_.reset(new TestDispatcherHostDelegate); content::ResourceDispatcherHost::Get()->SetDelegate( @@ -301,7 +300,6 @@ IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest, PolicyHeaderForRedirect) { - // Build up a URL that results in a redirect to the DMServer URL to make // sure the policy header is still added. std::string redirect_url;
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc index 6c3e609..531e3f4 100644 --- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc +++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -262,6 +262,7 @@ // static bool RemoteMediaPlayerBridge::RegisterRemoteMediaPlayerBridge(JNIEnv* env) { bool ret = RegisterNativesImpl(env); + DCHECK(g_RemoteMediaPlayerBridge_clazz); return ret; }
diff --git a/chrome/browser/media/android/router/media_router_android_bridge.cc b/chrome/browser/media/android/router/media_router_android_bridge.cc index 4c57cde..e56bbb59 100644 --- a/chrome/browser/media/android/router/media_router_android_bridge.cc +++ b/chrome/browser/media/android/router/media_router_android_bridge.cc
@@ -29,6 +29,7 @@ // static bool MediaRouterAndroidBridge::Register(JNIEnv* env) { bool ret = RegisterNativesImpl(env); + DCHECK(g_ChromeMediaRouter_clazz); return ret; }
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc index 9f8104c..f6badf40 100644 --- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc +++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -191,8 +191,6 @@ #endif // BUILDFLAG(ENABLE_PEPPER_CDMS) void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - // Load the test page needed so that checkKeySystemWithMediaMimeType() // is available. std::unique_ptr<net::EmbeddedTestServer> http_test_server(
diff --git a/chrome/browser/media/router/media_router_dialog_controller.cc b/chrome/browser/media/router/media_router_dialog_controller.cc index 43ffd5f..31cdd96 100644 --- a/chrome/browser/media/router/media_router_dialog_controller.cc +++ b/chrome/browser/media/router/media_router_dialog_controller.cc
@@ -10,13 +10,9 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" -#include "device/vr/features/features.h" #if defined(OS_ANDROID) #include "chrome/browser/media/android/router/media_router_dialog_controller_android.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) #else #include "chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.h" #endif @@ -28,11 +24,6 @@ MediaRouterDialogController::GetOrCreateForWebContents( content::WebContents* contents) { #if defined(OS_ANDROID) -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr(contents)) { - return nullptr; - } -#endif return MediaRouterDialogControllerAndroid::GetOrCreateForWebContents( contents); #else
diff --git a/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc b/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc index 3e027e0..dbfa3b6 100644 --- a/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc +++ b/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc
@@ -109,8 +109,8 @@ ASSERT_TRUE(thread_checker_.CalledOnValidThread()); base::HistogramTester histograms; SetFullNamesFeatureEnabled(expect_unhashed_value_); - // Make sure the I/O is happening on the FILE thread by disallowing it on - // the main thread. + // Make sure the I/O is happening on a valid thread by disallowing it on the + // main thread. bool previous_value = base::ThreadRestrictions::SetIOAllowed(false); provider_->GetAntiVirusMetrics( base::Bind(&AntiVirusMetricsProviderTest::GetMetricsCallback,
diff --git a/chrome/browser/net/proxy_browsertest.cc b/chrome/browser/net/proxy_browsertest.cc index a5f0c1c..326ee58 100644 --- a/chrome/browser/net/proxy_browsertest.cc +++ b/chrome/browser/net/proxy_browsertest.cc
@@ -312,8 +312,6 @@ ALLOW_ADDITIONAL_CONNECTIONS); embedded_test_server()->SetConnectionListener(connection_listener_.get()); embedded_test_server()->StartAcceptingConnections(); - - InProcessBrowserTest::SetUpOnMainThread(); } void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc index 8eef933..0b6f6cd0 100644 --- a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc +++ b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
@@ -169,7 +169,6 @@ display_service_.reset( new MessageCenterDisplayService(browser()->profile(), ui_manager_.get())); service()->SetNotificationDisplayServiceForTesting(display_service_.get()); - InProcessBrowserTest::SetUpOnMainThread(); } void PlatformNotificationServiceBrowserTest::TearDown() {
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc index 8623212..01535a4 100644 --- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
@@ -28,7 +28,6 @@ void SetUpOnMainThread() override { ASSERT_TRUE(embedded_test_server()->Start()); - InProcessBrowserTest::SetUpOnMainThread(); } private:
diff --git a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc index eab2896b..da96052 100644 --- a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc
@@ -30,7 +30,6 @@ void SetUpOnMainThread() override { ASSERT_TRUE(embedded_test_server()->Start()); - InProcessBrowserTest::SetUpOnMainThread(); } };
diff --git a/chrome/browser/payments/payment_manifest_parser_host_browsertest.cc b/chrome/browser/payments/payment_manifest_parser_host_browsertest.cc new file mode 100644 index 0000000..7975d58 --- /dev/null +++ b/chrome/browser/payments/payment_manifest_parser_host_browsertest.cc
@@ -0,0 +1,359 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/payments/content/payment_manifest_parser_host.h" + +#include <utility> + +#include "base/run_loop.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace payments { + +// Test fixture for payment manifest parser host. +class PaymentManifestParserHostTest : public InProcessBrowserTest { + public: + PaymentManifestParserHostTest() : all_origins_supported_(false) {} + ~PaymentManifestParserHostTest() override {} + + // Starts the utility process. If this is not called, all parse requests fail. + void StartUtilityProcess() { host_.StartUtilityProcess(); } + + // Sends the |content| to the utility process to parse as a web app manifest + // and waits until the utility process responds. + void ParseWebAppManifest(const std::string& content) { + base::RunLoop run_loop; + host_.ParseWebAppManifest( + content, + base::BindOnce(&PaymentManifestParserHostTest::OnWebAppManifestParsed, + base::Unretained(this), run_loop.QuitClosure())); + run_loop.Run(); + } + + // Sets up the internal state of the utility process host as if it sent a + // request to parse a web app manifest, although nothing is sent to the + // utility process. + void MockParseWebAppManifest() { + host_.pending_web_app_callbacks_.insert(std::make_pair( + 0, + base::BindOnce(&PaymentManifestParserHostTest::OnWebAppManifestParsed, + base::Unretained(this), base::Closure()))); + } + + // Directly invokes the host's callback for web app manifest parsing. + void InvokeOnWebAppManifestParsed( + std::vector<mojom::WebAppManifestSectionPtr> web_app_manifest) { + host_.OnWebAppParse(0, std::move(web_app_manifest)); + } + + // Sends the |content| to the utility process to parse as a payment method + // manifest and waits until the utility process responds. + void ParsePaymentMethodManifest(const std::string& content) { + base::RunLoop run_loop; + host_.ParsePaymentMethodManifest( + content, + base::BindOnce( + &PaymentManifestParserHostTest::OnPaymentMethodManifestParsed, + base::Unretained(this), run_loop.QuitClosure())); + run_loop.Run(); + } + + // Sets up the internal state of the utility process host as if it sent a + // request to parse a payment method manifest, although nothing is sent to the + // utility process. + void MockParsePaymentMethodManifest() { + host_.pending_payment_method_callbacks_.insert(std::make_pair( + 0, base::BindOnce( + &PaymentManifestParserHostTest::OnPaymentMethodManifestParsed, + base::Unretained(this), base::Closure()))); + } + + // Directly invokes the host's callback for payment method manifest parsing. + void InvokeOnPaymentMethodManifestParse( + const std::vector<GURL>& web_app_manifest_urls, + const std::vector<url::Origin>& supported_origins, + bool all_origins_supported) { + host_.OnPaymentMethodParse(0, web_app_manifest_urls, supported_origins, + all_origins_supported); + } + + // The parsed web app manifest. + const std::vector<mojom::WebAppManifestSectionPtr>& web_app_manifest() const { + return web_app_manifest_; + } + + // The parsed web app manifest URLs from the payment method manifest. + const std::vector<GURL>& web_app_manifest_urls() const { + return web_app_manifest_urls_; + } + + // The parsed supported origins from the payment method manifest. + const std::vector<url::Origin>& supported_origins() const { + return supported_origins_; + } + + // Whether the parsed payment method manifest allows all origins to use the + // payment method. + bool all_origins_supported() const { return all_origins_supported_; } + + private: + // Called after the utility process has parsed the web app manifest. + void OnWebAppManifestParsed( + const base::Closure& resume_test, + std::vector<mojom::WebAppManifestSectionPtr> web_app_manifest) { + web_app_manifest_ = std::move(web_app_manifest); + if (!resume_test.is_null()) + resume_test.Run(); + } + + // Called after the utility process has parsed the payment method manifest. + void OnPaymentMethodManifestParsed( + const base::Closure& resume_test, + const std::vector<GURL>& web_app_manifest_urls, + const std::vector<url::Origin>& supported_origins, + bool all_origins_supported) { + web_app_manifest_urls_ = web_app_manifest_urls; + supported_origins_ = supported_origins; + all_origins_supported_ = all_origins_supported; + if (!resume_test.is_null()) + resume_test.Run(); + } + + PaymentManifestParserHost host_; + std::vector<mojom::WebAppManifestSectionPtr> web_app_manifest_; + std::vector<GURL> web_app_manifest_urls_; + std::vector<url::Origin> supported_origins_; + bool all_origins_supported_; + + DISALLOW_COPY_AND_ASSIGN(PaymentManifestParserHostTest); +}; + +// If the utility process has not been started, parsing a payment method +// manifest should fail. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, + NotStarted_PaymentMethodManifest) { + ParsePaymentMethodManifest("{\"supported_origins\": \"*\"}"); + + EXPECT_TRUE(web_app_manifest_urls().empty()); + EXPECT_TRUE(supported_origins().empty()); + EXPECT_FALSE(all_origins_supported()); +} + +// Handle a utility process that returns a result unexpectedly. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, + UnexpectedOnPaymentMethodParse) { + InvokeOnPaymentMethodManifestParse(std::vector<GURL>(), + std::vector<url::Origin>(), true); + + EXPECT_FALSE(all_origins_supported()); +} + +// Handle a utility process that returns more than 100 web app +// manifest URLs. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, TooManyWebAppUrls) { + MockParsePaymentMethodManifest(); + + InvokeOnPaymentMethodManifestParse( + std::vector<GURL>(101, GURL("https://bobpay.com/manifest.json")), + std::vector<url::Origin>(), false); + + EXPECT_TRUE(web_app_manifest_urls().empty()); +} + +// Handle a utility process that returns more than 100 supported +// origins. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, TooManySupportedOrigins) { + MockParsePaymentMethodManifest(); + + InvokeOnPaymentMethodManifestParse( + std::vector<GURL>(), + std::vector<url::Origin>(101, url::Origin(GURL("https://bobpay.com"))), + false); + + EXPECT_TRUE(supported_origins().empty()); +} + +// Handle a utility process that returns an insecure supported +// origin. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, InsecureSupportedOrigin) { + MockParsePaymentMethodManifest(); + + InvokeOnPaymentMethodManifestParse( + std::vector<GURL>(), + std::vector<url::Origin>(1, url::Origin(GURL("http://bobpay.com"))), + false); + + EXPECT_TRUE(supported_origins().empty()); +} + +// Handle a utility process that returns an insecure web app manifest +// URL. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, + InsecureWebAppManifestUrl) { + MockParsePaymentMethodManifest(); + + InvokeOnPaymentMethodManifestParse( + std::vector<GURL>(1, GURL("http://bobpay.com/manifest.json")), + std::vector<url::Origin>(), false); + + EXPECT_TRUE(web_app_manifest_urls().empty()); +} + +// Handle a utility process that returns an invalid supported origin. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, InvalidSupportedOrigin) { + MockParsePaymentMethodManifest(); + + InvokeOnPaymentMethodManifestParse( + std::vector<GURL>(), std::vector<url::Origin>(1, url::Origin(GURL())), + false); + + EXPECT_TRUE(supported_origins().empty()); +} + +// Handle a utility process that returns an invalid web app manifest URL. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, + InvalidWebAppManifestUrl) { + MockParsePaymentMethodManifest(); + + InvokeOnPaymentMethodManifestParse(std::vector<GURL>(1, GURL()), + std::vector<url::Origin>(), false); + + EXPECT_TRUE(web_app_manifest_urls().empty()); +} + +// Handle a utility process that returns both a list of supported origins and +// the indicator that all origins are supported. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, + InvalidAllOriginsSupported) { + MockParsePaymentMethodManifest(); + + InvokeOnPaymentMethodManifestParse( + std::vector<GURL>(), + std::vector<url::Origin>(1, url::Origin(GURL("https://bobpay.com"))), + true); + + EXPECT_TRUE(supported_origins().empty()); + EXPECT_FALSE(all_origins_supported()); +} + +// Verify that the utility process correctly parses a payment method manifest +// that allows all origins to use the corresponding payment method name. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, AllOriginsSupported) { + StartUtilityProcess(); + + ParsePaymentMethodManifest("{\"supported_origins\": \"*\"}"); + + EXPECT_TRUE(web_app_manifest_urls().empty()); + EXPECT_TRUE(supported_origins().empty()); + EXPECT_TRUE(all_origins_supported()); +} + +// Verify that the utility process correctly parses a payment method manifest +// with default applications and some supported origins. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, UrlsAndOrigins) { + StartUtilityProcess(); + + ParsePaymentMethodManifest( + "{\"default_applications\": " + "[\"https://alicepay.com/web-app-manifest.json\"], " + "\"supported_origins\": [\"https://bobpay.com\"]}"); + + EXPECT_EQ( + std::vector<GURL>(1, GURL("https://alicepay.com/web-app-manifest.json")), + web_app_manifest_urls()); + EXPECT_EQ( + std::vector<url::Origin>(1, url::Origin(GURL("https://bobpay.com"))), + supported_origins()); + EXPECT_FALSE(all_origins_supported()); +} + +// If the utility process has not been started, parsing a web app manifest +// should fail. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, + NotStarted_WebAppManifest) { + ParseWebAppManifest( + "{" + " \"related_applications\": [{" + " \"platform\": \"play\", " + " \"id\": \"com.bobpay.app\", " + " \"min_version\": \"1\", " + " \"fingerprints\": [{" + " \"type\": \"sha256_cert\", " + " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7" + ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\"" + " }]" + " }]" + "}"); + + EXPECT_TRUE(web_app_manifest().empty()); +} + +// Handle a utility process that returns a result unexpectedly. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, UnexpectedOnWebAppParse) { + std::vector<mojom::WebAppManifestSectionPtr> manifest; + manifest.push_back(mojom::WebAppManifestSection::New()); + + InvokeOnWebAppManifestParsed(std::move(manifest)); + + EXPECT_TRUE(web_app_manifest().empty()); +} + +// Verify that the utility process parses correctly a valid web app manifest. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, WebAppManifest) { + StartUtilityProcess(); + + ParseWebAppManifest( + "{" + " \"related_applications\": [{" + " \"platform\": \"play\", " + " \"id\": \"com.bobpay.app\", " + " \"min_version\": \"1\", " + " \"fingerprints\": [{" + " \"type\": \"sha256_cert\", " + " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7" + ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\"" + " }]" + " }]" + "}"); + + ASSERT_EQ(1U, web_app_manifest().size()); + EXPECT_EQ("com.bobpay.app", web_app_manifest().front()->id); + EXPECT_EQ(1, web_app_manifest().front()->min_version); + ASSERT_EQ(1U, web_app_manifest().front()->fingerprints.size()); + EXPECT_EQ( + std::vector<uint8_t>({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1}), + web_app_manifest().front()->fingerprints.front()); +} + +// Handle a utility process that returns too many web app manifest sections. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, + TooManyWebAppManifestSections) { + MockParseWebAppManifest(); + std::vector<mojom::WebAppManifestSectionPtr> manifest; + for (size_t i = 0; i < 101; ++i) { + manifest.push_back(mojom::WebAppManifestSection::New()); + } + + InvokeOnWebAppManifestParsed(std::move(manifest)); + + EXPECT_TRUE(web_app_manifest().empty()); +} + +// Handle a utility process that returns too many fingerprints. +IN_PROC_BROWSER_TEST_F(PaymentManifestParserHostTest, TooManyFingerprints) { + MockParseWebAppManifest(); + std::vector<mojom::WebAppManifestSectionPtr> manifest; + manifest.push_back(mojom::WebAppManifestSection::New()); + manifest.back()->fingerprints.assign(101, std::vector<uint8_t>()); + + InvokeOnWebAppManifestParsed(std::move(manifest)); + + EXPECT_TRUE(web_app_manifest().empty()); +} + +} // namespace payments
diff --git a/chrome/browser/permissions/permission_request_manager_browsertest.cc b/chrome/browser/permissions/permission_request_manager_browsertest.cc index a6de20a..86a3c39 100644 --- a/chrome/browser/permissions/permission_request_manager_browsertest.cc +++ b/chrome/browser/permissions/permission_request_manager_browsertest.cc
@@ -78,7 +78,6 @@ ~PermissionRequestManagerBrowserTest() override = default; void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); PermissionRequestManager* manager = GetPermissionRequestManager(); mock_permission_prompt_factory_.reset( new MockPermissionPromptFactory(manager)); @@ -127,7 +126,6 @@ void SetUpOnMainThread() override { // Skip super: It will install a mock permission UI factory, but for this // test we want to show "real" UI. - InProcessBrowserTest::SetUpOnMainThread(); ui_test_utils::NavigateToURL(browser(), GetUrl()); }
diff --git a/chrome/browser/permissions/permissions_browsertest.cc b/chrome/browser/permissions/permissions_browsertest.cc index 06bd4ed..92440a7 100644 --- a/chrome/browser/permissions/permissions_browsertest.cc +++ b/chrome/browser/permissions/permissions_browsertest.cc
@@ -21,8 +21,6 @@ PermissionsBrowserTest::~PermissionsBrowserTest() {} void PermissionsBrowserTest::SetUpOnMainThread() { - InProcessBrowserTest::SetUpOnMainThread(); - PermissionRequestManager* manager = PermissionRequestManager::FromWebContents( browser()->tab_strip_model()->GetActiveWebContents()); prompt_factory_.reset(new MockPermissionPromptFactory(manager));
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc index c87fc065..fc613dc 100644 --- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc +++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
@@ -259,8 +259,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - embedded_test_server()->ServeFilesFromDirectory( ui_test_utils::GetTestFilePath( base::FilePath(FILE_PATH_LITERAL("plugin_power_saver")),
diff --git a/chrome/browser/policy/policy_helpers.cc b/chrome/browser/policy/policy_helpers.cc index 662f3b7..0fc1133 100644 --- a/chrome/browser/policy/policy_helpers.cc +++ b/chrome/browser/policy/policy_helpers.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/policy/policy_helpers.h" #include "build/build_config.h" +#include "extensions/features/features.h" #include "net/base/net_errors.h" #include "url/gurl.h" @@ -17,6 +18,10 @@ #include "google_apis/gaia/gaia_urls.h" #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/common/constants.h" +#endif + namespace policy { bool OverrideBlacklistForURL(const GURL& url, bool* block, int* reason) { @@ -27,10 +32,12 @@ return false; } +#if BUILDFLAG(ENABLE_EXTENSIONS) // Don't block internal pages and extensions. - if (url.SchemeIs("chrome") || url.SchemeIs("chrome-extension")) { + if (url.SchemeIs("chrome") || url.SchemeIs(extensions::kExtensionScheme)) { return false; } +#endif // Don't block Google's support web site. if (url.SchemeIs(url::kHttpsScheme) && url.DomainIs("support.google.com")) {
diff --git a/chrome/browser/prefetch/prefetch_browsertest.cc b/chrome/browser/prefetch/prefetch_browsertest.cc index 19112909..032a31c 100644 --- a/chrome/browser/prefetch/prefetch_browsertest.cc +++ b/chrome/browser/prefetch/prefetch_browsertest.cc
@@ -54,7 +54,6 @@ void SetUpOnMainThread() override { ASSERT_TRUE(embedded_test_server()->Start()); - InProcessBrowserTest::SetUpOnMainThread(); } void SetPreference(NetworkPredictionOptions value) {
diff --git a/chrome/browser/prerender/prerender_util.cc b/chrome/browser/prerender/prerender_util.cc index b35ad93..dec66b23 100644 --- a/chrome/browser/prerender/prerender_util.cc +++ b/chrome/browser/prerender/prerender_util.cc
@@ -6,8 +6,13 @@ #include "base/metrics/histogram_macros.h" #include "components/google/core/browser/google_util.h" +#include "extensions/features/features.h" #include "url/gurl.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/common/constants.h" +#endif + namespace prerender { namespace { @@ -68,9 +73,11 @@ ReportPrerenderSchemeCancelReason(PRERENDER_SCHEME_CANCEL_REASON_FTP); } else if (url.SchemeIs("chrome")) { ReportPrerenderSchemeCancelReason(PRERENDER_SCHEME_CANCEL_REASON_CHROME); - } else if (url.SchemeIs("chrome-extension")) { +#if BUILDFLAG(ENABLE_EXTENSIONS) + } else if (url.SchemeIs(extensions::kExtensionScheme)) { ReportPrerenderSchemeCancelReason( PRERENDER_SCHEME_CANCEL_REASON_CHROME_EXTENSION); +#endif } else if (url.SchemeIs("about")) { ReportPrerenderSchemeCancelReason(PRERENDER_SCHEME_CANCEL_REASON_ABOUT); } else {
diff --git a/chrome/browser/previews/previews_service.cc b/chrome/browser/previews/previews_service.cc index ead4e6e..d1037404 100644 --- a/chrome/browser/previews/previews_service.cc +++ b/chrome/browser/previews/previews_service.cc
@@ -10,6 +10,7 @@ #include "base/sequenced_task_runner.h" #include "base/task_scheduler/post_task.h" #include "chrome/common/chrome_constants.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "components/previews/core/previews_experiments.h" #include "components/previews/core/previews_io_data.h" @@ -22,15 +23,19 @@ // Returns true if previews can be shown for |type|. bool IsPreviewsTypeEnabled(previews::PreviewsType type) { + bool server_previews_enabled = base::FeatureList::IsEnabled( + data_reduction_proxy::features::kDataReductionProxyDecidesTransform); switch (type) { case previews::PreviewsType::OFFLINE: return previews::params::IsOfflinePreviewsEnabled(); case previews::PreviewsType::LOFI: - return previews::params::IsClientLoFiEnabled() || + return server_previews_enabled || + previews::params::IsClientLoFiEnabled() || data_reduction_proxy::params::IsLoFiOnViaFlags() || data_reduction_proxy::params::IsIncludedInLoFiEnabledFieldTrial(); case previews::PreviewsType::LITE_PAGE: - return (data_reduction_proxy::params::IsLoFiOnViaFlags() && + return server_previews_enabled || + (data_reduction_proxy::params::IsLoFiOnViaFlags() && data_reduction_proxy::params::AreLitePagesEnabledViaFlags()) || data_reduction_proxy::params::IsIncludedInLitePageFieldTrial(); case previews::PreviewsType::NONE:
diff --git a/chrome/browser/previews/previews_service_unittest.cc b/chrome/browser/previews/previews_service_unittest.cc index 39d8f8c..f2b7e07 100644 --- a/chrome/browser/previews/previews_service_unittest.cc +++ b/chrome/browser/previews/previews_service_unittest.cc
@@ -16,6 +16,8 @@ #include "base/metrics/field_trial_params.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/scoped_feature_list.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" #include "components/previews/core/previews_io_data.h" #include "components/previews/core/previews_ui_service.h" #include "components/variations/variations_associated_data.h" @@ -66,7 +68,7 @@ public: PreviewsServiceTest() - : field_trial_list_(nullptr) {} + : field_trial_list_(nullptr), scoped_feature_list_() {} void SetUp() override { io_data_ = base::MakeUnique<TestPreviewsIOData>(); @@ -77,6 +79,8 @@ content::BrowserThread::GetTaskRunnerForThread( content::BrowserThread::UI), file_path); + scoped_feature_list_.InitAndDisableFeature( + data_reduction_proxy::features::kDataReductionProxyDecidesTransform); } void TearDown() override { variations::testing::ClearAllVariationParams(); } @@ -90,6 +94,7 @@ base::FieldTrialList field_trial_list_; std::unique_ptr<TestPreviewsIOData> io_data_; std::unique_ptr<PreviewsService> service_; + base::test::ScopedFeatureList scoped_feature_list_; }; } // namespace @@ -146,6 +151,9 @@ } TEST_F(PreviewsServiceTest, TestLitePageFieldTrialEnabledPreview) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + data_reduction_proxy::features::kDataReductionProxyDecidesTransform); base::FieldTrialList::CreateFieldTrial("DataCompressionProxyLoFi", "Enabled_Preview"); EXPECT_TRUE(io_data()->IsPreviewEnabled(previews::PreviewsType::LITE_PAGE)); @@ -165,3 +173,17 @@ TEST_F(PreviewsServiceTest, TestLitePageFieldTrialNotSet) { EXPECT_FALSE(io_data()->IsPreviewEnabled(previews::PreviewsType::LITE_PAGE)); } + +TEST_F(PreviewsServiceTest, TestServerLoFiProxyDecidesTransform) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + data_reduction_proxy::features::kDataReductionProxyDecidesTransform); + EXPECT_TRUE(io_data()->IsPreviewEnabled(previews::PreviewsType::LITE_PAGE)); +} + +TEST_F(PreviewsServiceTest, TestLitePageProxyDecidesTransform) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + data_reduction_proxy::features::kDataReductionProxyDecidesTransform); + EXPECT_TRUE(io_data()->IsPreviewEnabled(previews::PreviewsType::LITE_PAGE)); +}
diff --git a/chrome/browser/profiles/profile_list_desktop_browsertest.cc b/chrome/browser/profiles/profile_list_desktop_browsertest.cc index 2a18925..b4db78a 100644 --- a/chrome/browser/profiles/profile_list_desktop_browsertest.cc +++ b/chrome/browser/profiles/profile_list_desktop_browsertest.cc
@@ -59,6 +59,9 @@ // This test doesn't make sense for Chrome OS since it has a different // multi-profiles menu in the system tray instead. #define MAYBE_SignOut DISABLED_SignOut +#elif defined(OS_LINUX) +// Flaky on Linux debug builds with libc++ (https://crbug.com/734875) +#define MAYBE_SignOut DISABLED_SignOut #else #define MAYBE_SignOut SignOut #endif
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc index 8a8fe225..34d127ec 100644 --- a/chrome/browser/push_messaging/push_messaging_browsertest.cc +++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -164,7 +164,6 @@ display_service_.get()); LoadTestPage(); - InProcessBrowserTest::SetUpOnMainThread(); } // Calls should be wrapped in the ASSERT_NO_FATAL_FAILURE() macro.
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h index b195d0db..7ffd501 100644 --- a/chrome/browser/push_messaging/push_messaging_service_impl.h +++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -22,6 +22,7 @@ #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" #include "components/gcm_driver/common/gcm_messages.h" +#include "components/gcm_driver/crypto/gcm_encryption_provider.h" #include "components/gcm_driver/gcm_app_handler.h" #include "components/gcm_driver/gcm_client.h" #include "components/gcm_driver/instance_id/instance_id.h"
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc index 85c08294..122f6bd7 100644 --- a/chrome/browser/resource_coordinator/tab_manager.cc +++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -35,6 +35,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/resource_coordinator/tab_manager_observer.h" #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h" +#include "chrome/browser/sessions/session_restore.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" @@ -126,6 +127,29 @@ //////////////////////////////////////////////////////////////////////////////// // TabManager +class TabManager::TabManagerSessionRestoreObserver + : public SessionRestoreObserver { + public: + explicit TabManagerSessionRestoreObserver(TabManager* tab_manager) + : tab_manager_(tab_manager) { + SessionRestore::AddObserver(this); + } + + ~TabManagerSessionRestoreObserver() { SessionRestore::RemoveObserver(this); } + + // SessionRestoreObserver implementation: + void OnSessionRestoreStartedLoadingTabs() override { + tab_manager_->OnSessionRestoreStartedLoadingTabs(); + } + + void OnSessionRestoreFinishedLoadingTabs() override { + tab_manager_->OnSessionRestoreFinishedLoadingTabs(); + } + + private: + TabManager* tab_manager_; +}; + constexpr base::TimeDelta TabManager::kDefaultMinTimeToPurge; TabManager::TabManager() @@ -137,11 +161,13 @@ #endif browser_tab_strip_tracker_(this, nullptr, nullptr), test_tick_clock_(nullptr), + is_session_restore_loading_tabs_(false), weak_ptr_factory_(this) { #if defined(OS_CHROMEOS) delegate_.reset(new TabManagerDelegate(weak_ptr_factory_.GetWeakPtr())); #endif browser_tab_strip_tracker_.Init(); + session_restore_observer_.reset(new TabManagerSessionRestoreObserver(this)); } TabManager::~TabManager() { @@ -478,6 +504,16 @@ return reinterpret_cast<int64_t>(web_contents); } +void TabManager::OnSessionRestoreStartedLoadingTabs() { + DCHECK(!is_session_restore_loading_tabs_); + is_session_restore_loading_tabs_ = true; +} + +void TabManager::OnSessionRestoreFinishedLoadingTabs() { + DCHECK(is_session_restore_loading_tabs_); + is_session_restore_loading_tabs_ = false; +} + /////////////////////////////////////////////////////////////////////////////// // TabManager, private:
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h index 3cd08c9..414b743 100644 --- a/chrome/browser/resource_coordinator/tab_manager.h +++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -24,6 +24,7 @@ #include "build/build_config.h" #include "chrome/browser/resource_coordinator/tab_manager_observer.h" #include "chrome/browser/resource_coordinator/tab_stats.h" +#include "chrome/browser/sessions/session_restore_observer.h" #include "chrome/browser/ui/browser_tab_strip_tracker.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "ui/gfx/geometry/rect.h" @@ -156,6 +157,11 @@ // the WebContents could be deleted if the user closed the tab. static int64_t IdFromWebContents(content::WebContents* web_contents); + // Return whether tabs are being loaded during session restore. + bool IsSessionRestoreLoadingTabs() const { + return is_session_restore_loading_tabs_; + } + private: FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PurgeBackgroundRenderer); FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ActivateTabResetPurgeState); @@ -321,6 +327,9 @@ // list is constructed from either |test_browser_info_list_| or BrowserList. std::vector<BrowserInfo> GetBrowserInfoList() const; + void OnSessionRestoreStartedLoadingTabs(); + void OnSessionRestoreFinishedLoadingTabs(); + // Timer to periodically update the stats of the renderers. base::RepeatingTimer update_timer_; @@ -383,6 +392,11 @@ // List of observers that will receive notifications on state changes. base::ObserverList<TabManagerObserver> observers_; + bool is_session_restore_loading_tabs_; + + class TabManagerSessionRestoreObserver; + std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_; + // Weak pointer factory used for posting delayed tasks. base::WeakPtrFactory<TabManager> weak_ptr_factory_;
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc index afec480..238610c 100644 --- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc +++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -6,6 +6,7 @@ #include <algorithm> #include <map> +#include <memory> #include <vector> #include "base/logging.h" @@ -17,9 +18,11 @@ #include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" #include "build/build_config.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h" #include "chrome/browser/resource_coordinator/tab_stats.h" +#include "chrome/browser/sessions/tab_loader.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h" #include "chrome/common/chrome_features.h" @@ -578,4 +581,24 @@ EXPECT_FALSE(tab_stats[5].is_in_visible_window); } +TEST_F(TabManagerTest, OnSessionRestoreStartedAndFinishedLoadingTabs) { + std::unique_ptr<content::WebContents> test_contents( + WebContentsTester::CreateTestWebContents(browser_context(), nullptr)); + + std::vector<SessionRestoreDelegate::RestoredTab> restored_tabs{ + SessionRestoreDelegate::RestoredTab(test_contents.get(), false, false, + false)}; + + TabManager* tab_manager = g_browser_process->GetTabManager(); + EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs()); + + TabLoader::RestoreTabs(restored_tabs, base::TimeTicks()); + EXPECT_TRUE(tab_manager->IsSessionRestoreLoadingTabs()); + + WebContentsTester::For(test_contents.get()) + ->NavigateAndCommit(GURL("about:blank")); + WebContentsTester::For(test_contents.get())->TestSetIsLoading(false); + EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs()); +} + } // namespace resource_coordinator
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc index be1fa7f..297ec1c 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc
@@ -88,7 +88,6 @@ ->SetServiceResetCallbackForTesting( base::Bind(&CertificateReportingServiceObserver::OnServiceReset, base::Unretained(&service_observer_))); - InProcessBrowserTest::SetUpOnMainThread(); } void TearDownOnMainThread() override {
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc index a04005c..b0a6baf 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc
@@ -75,8 +75,6 @@ ASSERT_NE(mock_time_task_runner_, saved_task_runner_); base::MessageLoop::current()->SetTaskRunner(mock_time_task_runner_); - InProcessBrowserTest::SetUpOnMainThread(); - // SetDateInLocalState calculates a time as Now() minus an offset. Move the // simulated clock ahead far enough that this calculation won't underflow. mock_time_task_runner_->FastForwardBy(
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index a38a9c9..dc1d6be3 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -545,7 +545,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); g_browser_process->safe_browsing_service()->ui_manager()->AddObserver( &observer_); }
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index 2818f7f..49831a2 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -865,5 +865,19 @@ } // static +void SessionRestore::AddObserver(SessionRestoreObserver* observer) { + observers().AddObserver(observer); +} + +// static +void SessionRestore::RemoveObserver(SessionRestoreObserver* observer) { + observers().RemoveObserver(observer); +} + +// static base::CallbackList<void(int)>* SessionRestore::on_session_restored_callbacks_ = nullptr; + +// static +base::ObserverList<SessionRestoreObserver>* SessionRestore::observers_ = + nullptr;
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h index e7ad887c..10dabff1 100644 --- a/chrome/browser/sessions/session_restore.h +++ b/chrome/browser/sessions/session_restore.h
@@ -12,6 +12,8 @@ #include "base/callback_list.h" #include "base/macros.h" +#include "base/observer_list.h" +#include "chrome/browser/sessions/session_restore_observer.h" #include "components/history/core/browser/history_service.h" #include "components/sessions/core/session_types.h" #include "ui/base/window_open_disposition.h" @@ -106,6 +108,18 @@ static void AddURLsToOpen(const Profile* profile, const std::vector<GURL>& urls); + // Add/remove an observer to/from this session restore. + static void AddObserver(SessionRestoreObserver* observer); + static void RemoveObserver(SessionRestoreObserver* observer); + + // Accessor for the observer list. Create the list the first time to always + // return a valid reference. + static base::ObserverList<SessionRestoreObserver>& observers() { + if (!observers_) + observers_ = new base::ObserverList<SessionRestoreObserver>(); + return *observers_; + } + private: SessionRestore(); @@ -120,6 +134,9 @@ // Contains all registered callbacks for session restore notifications. static CallbackList* on_session_restored_callbacks_; + // Contains all registered observers for session restore events. + static base::ObserverList<SessionRestoreObserver>* observers_; + DISALLOW_COPY_AND_ASSIGN(SessionRestore); };
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index ef42430..596deefb 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -106,8 +106,6 @@ helper.ReleaseService(); } #endif - - InProcessBrowserTest::SetUpOnMainThread(); } bool SetUpUserDataDirectory() override {
diff --git a/chrome/browser/sessions/session_restore_observer.h b/chrome/browser/sessions/session_restore_observer.h new file mode 100644 index 0000000..8d51103 --- /dev/null +++ b/chrome/browser/sessions/session_restore_observer.h
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_ +#define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_ + +// Observer of events during session restore. +class SessionRestoreObserver { + public: + // OnSessionRestoreStartedLoadingTabs is triggered when the browser starts + // loading tabs in session restore. + virtual void OnSessionRestoreStartedLoadingTabs() {} + + // OnSessionRestoreFinishedLoadingTabs is triggered when the browser finishes + // loading tabs in session restore. In case of memory pressure, not all + // WebContents may have been created (i.e., some are deferred). + virtual void OnSessionRestoreFinishedLoadingTabs() {} +}; + +#endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_
diff --git a/chrome/browser/sessions/session_restore_observer_unittest.cc b/chrome/browser/sessions/session_restore_observer_unittest.cc new file mode 100644 index 0000000..9d1b39a --- /dev/null +++ b/chrome/browser/sessions/session_restore_observer_unittest.cc
@@ -0,0 +1,148 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sessions/session_restore_observer.h" + +#include "chrome/browser/sessions/session_restore.h" +#include "chrome/browser/sessions/tab_loader.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/web_contents_tester.h" + +using content::WebContentsTester; + +namespace { + +const char kDefaultUrl[] = "https://www.google.com"; + +} // namespace + +class MockSessionRestoreObserver : public SessionRestoreObserver { + public: + MockSessionRestoreObserver() { SessionRestore::AddObserver(this); } + + ~MockSessionRestoreObserver() { SessionRestore::RemoveObserver(this); } + + enum class SessionRestoreEvent { + STARTED_LOADING_TABS, + FINISHED_LOADING_TABS + }; + + const std::vector<SessionRestoreEvent>& session_restore_events() const { + return session_restore_events_; + } + + // SessionRestoreObserver implementation: + void OnSessionRestoreStartedLoadingTabs() override { + session_restore_events_.emplace_back( + SessionRestoreEvent::STARTED_LOADING_TABS); + } + + void OnSessionRestoreFinishedLoadingTabs() override { + session_restore_events_.emplace_back( + SessionRestoreEvent::FINISHED_LOADING_TABS); + } + + private: + std::vector<SessionRestoreEvent> session_restore_events_; + + DISALLOW_COPY_AND_ASSIGN(MockSessionRestoreObserver); +}; + +class SessionRestoreObserverTest : public ChromeRenderViewHostTestHarness { + public: + using RestoredTab = SessionRestoreDelegate::RestoredTab; + + SessionRestoreObserverTest() {} + + // testing::Test: + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + restored_tabs_.emplace_back(web_contents(), false, false, false); + } + + void TearDown() override { + ChromeRenderViewHostTestHarness::TearDown(); + restored_tabs_.clear(); + } + + protected: + void RestoreTabs() { + TabLoader::RestoreTabs(restored_tabs_, base::TimeTicks()); + } + + void LoadWebContents(content::WebContents* contents) { + WebContentsTester::For(contents)->NavigateAndCommit(GURL(kDefaultUrl)); + WebContentsTester::For(contents)->TestSetIsLoading(false); + } + + const std::vector<MockSessionRestoreObserver::SessionRestoreEvent>& + session_restore_events() const { + return mock_observer_.session_restore_events(); + } + + size_t number_of_session_restore_events() const { + return session_restore_events().size(); + } + + private: + MockSessionRestoreObserver mock_observer_; + std::vector<RestoredTab> restored_tabs_; + + DISALLOW_COPY_AND_ASSIGN(SessionRestoreObserverTest); +}; + +TEST_F(SessionRestoreObserverTest, SingleSessionRestore) { + RestoreTabs(); + ASSERT_EQ(1u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS, + session_restore_events()[0]); + + LoadWebContents(web_contents()); + ASSERT_EQ(2u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS, + session_restore_events()[1]); +} + +TEST_F(SessionRestoreObserverTest, SequentialSessionRestore) { + const int number_of_session_restores = 3; + size_t event_index = 0; + for (int i = 0; i < number_of_session_restores; ++i) { + RestoreTabs(); + ASSERT_EQ(event_index + 1, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS, + session_restore_events()[event_index++]); + + LoadWebContents(web_contents()); + ASSERT_EQ(event_index + 1, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS, + session_restore_events()[event_index++]); + } +} + +TEST_F(SessionRestoreObserverTest, ConcurrentSessionRestore) { + std::vector<RestoredTab> another_restored_tabs; + std::unique_ptr<content::WebContents> test_contents( + WebContentsTester::CreateTestWebContents(browser_context(), nullptr)); + another_restored_tabs.emplace_back(test_contents.get(), false, false, false); + + RestoreTabs(); + TabLoader::RestoreTabs(another_restored_tabs, base::TimeTicks()); + ASSERT_EQ(1u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS, + session_restore_events()[0]); + + LoadWebContents(web_contents()); + LoadWebContents(test_contents.get()); + + ASSERT_EQ(2u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS, + session_restore_events()[1]); +}
diff --git a/chrome/browser/sessions/tab_loader.cc b/chrome/browser/sessions/tab_loader.cc index 753f4e04..80aa058 100644 --- a/chrome/browser/sessions/tab_loader.cc +++ b/chrome/browser/sessions/tab_loader.cc
@@ -103,6 +103,8 @@ shared_tab_loader_ = this; this_retainer_ = this; base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this); + for (auto& observer : SessionRestore::observers()) + observer.OnSessionRestoreStartedLoadingTabs(); } TabLoader::~TabLoader() { @@ -110,6 +112,8 @@ DCHECK(shared_tab_loader_ == this); shared_tab_loader_ = nullptr; base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this); + for (auto& observer : SessionRestore::observers()) + observer.OnSessionRestoreFinishedLoadingTabs(); } void TabLoader::StartLoading(const std::vector<RestoredTab>& tabs) {
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc index 70fc7a7..7e2dcd4 100644 --- a/chrome/browser/sessions/tab_restore_browsertest.cc +++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -100,7 +100,6 @@ protected: void SetUpOnMainThread() override { active_browser_list_ = BrowserList::GetInstance(); - InProcessBrowserTest::SetUpOnMainThread(); } Browser* GetBrowser(int index) {
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc index 11ea969..161c030 100644 --- a/chrome/browser/signin/chrome_signin_client.cc +++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -273,19 +273,37 @@ const base::Callback<void()>& sign_out, signin_metrics::ProfileSignout signout_source_metric) { #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) - if (signin_util::IsForceSigninEnabled() && !profile_->IsSystemProfile() && - !profile_->IsGuestSession() && !profile_->IsSupervised()) { - // TODO(zmin): force window closing based on the reason of sign-out. - // This will be updated after force window closing CL is commited. - // User can't abort the window closing unless user sign out manually. - BrowserList::CloseAllBrowsersWithProfile( - profile_, - base::Bind(&ChromeSigninClient::OnCloseBrowsersSuccess, - base::Unretained(this), sign_out, signout_source_metric), - base::Bind(&ChromeSigninClient::OnCloseBrowsersAborted, - base::Unretained(this)), - false); + // These sign out won't remove the policy cache, keep the window opened. + bool keep_window_opened = + signout_source_metric == + signin_metrics::GOOGLE_SERVICE_NAME_PATTERN_CHANGED || + signout_source_metric == signin_metrics::SERVER_FORCED_DISABLE || + signout_source_metric == signin_metrics::SIGNOUT_PREF_CHANGED; + if (signin_util::IsForceSigninEnabled() && !profile_->IsSystemProfile() && + !profile_->IsGuestSession() && !profile_->IsSupervised() && + !keep_window_opened) { + if (signout_source_metric == + signin_metrics::SIGNIN_PREF_CHANGED_DURING_SIGNIN) { + // SIGNIN_PREF_CHANGED_DURING_SIGNIN will be triggered when SigninManager + // is initialized before window opening, there is no need to close window. + // Call OnCloseBrowsersSuccess to continue sign out and show UserManager + // afterwards. + should_display_user_manager_ = false; // Don't show UserManager twice. + OnCloseBrowsersSuccess(sign_out, signout_source_metric, + profile_->GetPath()); + } else { + BrowserList::CloseAllBrowsersWithProfile( + profile_, + base::Bind(&ChromeSigninClient::OnCloseBrowsersSuccess, + base::Unretained(this), sign_out, signout_source_metric), + base::Bind(&ChromeSigninClient::OnCloseBrowsersAborted, + base::Unretained(this)), + signout_source_metric == signin_metrics::ABORT_SIGNIN || + signout_source_metric == + signin_metrics::AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN || + signout_source_metric == signin_metrics::TRANSFER_CREDENTIALS); + } } else { #else { @@ -441,8 +459,10 @@ const signin_metrics::ProfileSignout signout_source_metric, const base::FilePath& profile_path) { #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) - if (signin_util::IsForceSigninEnabled() && force_signin_verifier_.get()) + if (signin_util::IsForceSigninEnabled() && force_signin_verifier_.get()) { force_signin_verifier_->Cancel(); + force_signin_verifier_->AbortSignoutCountdownIfExisted(); + } #endif SigninClient::PreSignOut(sign_out, signout_source_metric);
diff --git a/chrome/browser/signin/chrome_signin_client_unittest.cc b/chrome/browser/signin/chrome_signin_client_unittest.cc index 16d57bb..704c7b7 100644 --- a/chrome/browser/signin/chrome_signin_client_unittest.cc +++ b/chrome/browser/signin/chrome_signin_client_unittest.cc
@@ -175,7 +175,7 @@ TEST_F(ChromeSigninClientSignoutTest, SignOut) { signin_metrics::ProfileSignout source_metric = - signin_metrics::ProfileSignout::SIGNOUT_TEST; + signin_metrics::ProfileSignout::ABORT_SIGNIN; signin_metrics::SignoutDelete delete_metric = signin_metrics::SignoutDelete::IGNORE_METRIC; @@ -190,7 +190,7 @@ TEST_F(ChromeSigninClientSignoutTest, SignOutWithoutManager) { signin_metrics::ProfileSignout source_metric = - signin_metrics::ProfileSignout::SIGNOUT_TEST; + signin_metrics::ProfileSignout::ABORT_SIGNIN; signin_metrics::SignoutDelete delete_metric = signin_metrics::SignoutDelete::IGNORE_METRIC; @@ -220,7 +220,7 @@ manager_.reset(new MockSigninManager(client_.get())); signin_metrics::ProfileSignout source_metric = - signin_metrics::ProfileSignout::SIGNOUT_TEST; + signin_metrics::ProfileSignout::ABORT_SIGNIN; signin_metrics::SignoutDelete delete_metric = signin_metrics::SignoutDelete::IGNORE_METRIC; @@ -241,7 +241,7 @@ manager_.reset(new MockSigninManager(client_.get())); signin_metrics::ProfileSignout source_metric = - signin_metrics::ProfileSignout::SIGNOUT_TEST; + signin_metrics::ProfileSignout::ABORT_SIGNIN; signin_metrics::SignoutDelete delete_metric = signin_metrics::SignoutDelete::IGNORE_METRIC;
diff --git a/chrome/browser/signin/force_signin_verifier.cc b/chrome/browser/signin/force_signin_verifier.cc index 9afd378..0311d85 100644 --- a/chrome/browser/signin/force_signin_verifier.cc +++ b/chrome/browser/signin/force_signin_verifier.cc
@@ -4,10 +4,12 @@ #include <string> +#include "base/bind.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/force_signin_verifier.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/ui/forced_reauthentication_dialog.h" #include "components/signin/core/browser/signin_manager.h" #include "google_apis/gaia/gaia_constants.h" @@ -23,10 +25,22 @@ false // Do not always use initial delay. }; +// The duration of window closing countdown when verification failed. Use the +// short countdown if the verfication is finished in +// |kShortCountdownVerificationTimeLimitInSeconds|, otherwise use the normal +// countdown. +const int kShortCountdownVerificationTimeLimitInSeconds = 3; +const int kWindowClosingNormalCountdownDurationInSecond = 300; +const int kWindowClosingShortCountdownDurationInSecond = 30; + } // namespace ForceSigninVerifier::ForceSigninVerifier(Profile* profile) : OAuth2TokenService::Consumer("force_signin_verifier"), +#if !defined(OS_MACOSX) + profile_(profile), + dialog_(ForcedReauthenticationDialog::Create()), +#endif has_token_verified_(false), backoff_entry_(&kBackoffPolicy), oauth2_token_service_( @@ -90,6 +104,10 @@ return has_token_verified_; } +void ForceSigninVerifier::AbortSignoutCountdownIfExisted() { + window_close_timer_.Stop(); +} + void ForceSigninVerifier::SendRequest() { if (!ShouldSendRequest()) return; @@ -107,8 +125,38 @@ signin_manager_->IsAuthenticated(); } +base::TimeDelta ForceSigninVerifier::StartCountdown() { + base::TimeDelta countdown_duration; + if (base::Time::Now() - token_request_time_ > + base::TimeDelta::FromSeconds( + kShortCountdownVerificationTimeLimitInSeconds)) { + countdown_duration = base::TimeDelta::FromSeconds( + kWindowClosingNormalCountdownDurationInSecond); + } else { + countdown_duration = base::TimeDelta::FromSeconds( + kWindowClosingShortCountdownDurationInSecond); + } + + window_close_timer_.Start(FROM_HERE, countdown_duration, this, + &ForceSigninVerifier::CloseAllBrowserWindows); + return countdown_duration; +} + void ForceSigninVerifier::ShowDialog() { - // TODO(zmin): Show app modal dialog. +#if !defined(OS_MACOSX) + base::TimeDelta countdown_duration = StartCountdown(); + dialog_->ShowDialog(profile_, signin_manager_, countdown_duration); +#endif +} + +void ForceSigninVerifier::CloseAllBrowserWindows() { + // Do not close window if there is ongoing reauth. If it fails later, the + // signin process should take care of the signout. + if (signin_manager_->AuthInProgress()) + return; + signin_manager_->SignOut( + signin_metrics::AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN, + signin_metrics::SignoutDelete::IGNORE_METRIC); } OAuth2TokenService::Request* ForceSigninVerifier::GetRequestForTesting() { @@ -122,3 +170,7 @@ base::OneShotTimer* ForceSigninVerifier::GetOneShotTimerForTesting() { return &backoff_request_timer_; } + +base::OneShotTimer* ForceSigninVerifier::GetWindowCloseTimerForTesting() { + return &window_close_timer_; +}
diff --git a/chrome/browser/signin/force_signin_verifier.h b/chrome/browser/signin/force_signin_verifier.h index 03548c03..5106bee 100644 --- a/chrome/browser/signin/force_signin_verifier.h +++ b/chrome/browser/signin/force_signin_verifier.h
@@ -15,6 +15,7 @@ #include "net/base/backoff_entry.h" #include "net/base/network_change_notifier.h" +class ForcedReauthenticationDialog; class Profile; class SigninManager; @@ -28,14 +29,14 @@ explicit ForceSigninVerifier(Profile* profile); ~ForceSigninVerifier() override; - // OAuth2TokenService::Consumer implementation + // override OAuth2TokenService::Consumer void OnGetTokenSuccess(const OAuth2TokenService::Request* request, const std::string& access_token, const base::Time& expiration_time) override; void OnGetTokenFailure(const OAuth2TokenService::Request* request, const GoogleServiceAuthError& error) override; - // net::NetworkChangeNotifier::NetworkChangeObserver + // override net::NetworkChangeNotifier::NetworkChangeObserver void OnNetworkChanged( net::NetworkChangeNotifier::ConnectionType type) override; @@ -45,6 +46,9 @@ // Return the value of |has_token_verified_|. bool HasTokenBeenVerified(); + // Abort signout countdown. + void AbortSignoutCountdownIfExisted(); + protected: // Send the token verification request. The request will be sent only if // - The token has never been verified before. @@ -60,13 +64,25 @@ // browser window. virtual void ShowDialog(); + // Start the window closing countdown, return the duration. + base::TimeDelta StartCountdown(); + OAuth2TokenService::Request* GetRequestForTesting(); net::BackoffEntry* GetBackoffEntryForTesting(); base::OneShotTimer* GetOneShotTimerForTesting(); + base::OneShotTimer* GetWindowCloseTimerForTesting(); private: + void CloseAllBrowserWindows(); + std::unique_ptr<OAuth2TokenService::Request> access_token_request_; +#if !defined(OS_MACOSX) + Profile* profile_; + + std::unique_ptr<ForcedReauthenticationDialog> dialog_; +#endif + // Indicates whether the verification is finished successfully or with a // persistent error. bool has_token_verified_; @@ -78,6 +94,9 @@ base::Time token_request_time_; + // The countdown of window closing. + base::OneShotTimer window_close_timer_; + DISALLOW_COPY_AND_ASSIGN(ForceSigninVerifier); };
diff --git a/chrome/browser/signin/force_signin_verifier_unittest.cc b/chrome/browser/signin/force_signin_verifier_unittest.cc index d5f2f555..23cf4f1a 100644 --- a/chrome/browser/signin/force_signin_verifier_unittest.cc +++ b/chrome/browser/signin/force_signin_verifier_unittest.cc
@@ -24,6 +24,13 @@ OAuth2TokenService::Request* request() { return GetRequestForTesting(); } + bool IsCountdownTimerRunning() { + base::Timer* timer = GetWindowCloseTimerForTesting(); + return timer && timer->IsRunning(); + } + + void OnShowDialog() { StartCountdown(); } + MOCK_METHOD0(ShowDialog, void(void)); }; @@ -124,3 +131,16 @@ ASSERT_NE(nullptr, verifier_->request()); ASSERT_FALSE(verifier_->IsDelayTaskPosted()); } + +TEST_F(ForceSigninVerifierTest, OnGetTokenPersistentFailureAndStartCountdown) { + ASSERT_EQ(nullptr, verifier_->request()); + ASSERT_FALSE(verifier_->IsCountdownTimerRunning()); + EXPECT_CALL(*verifier_.get(), ShowDialog()) + .WillOnce(::testing::Invoke(verifier_.get(), + &MockForceSigninVerifier::OnShowDialog)); + + verifier_->SendTestRequest(); + verifier_->OnGetTokenFailure(verifier_->request(), persistent_error_); + + ASSERT_TRUE(verifier_->IsCountdownTimerRunning()); +}
diff --git a/chrome/browser/translate/translate_browsertest.cc b/chrome/browser/translate/translate_browsertest.cc index d8f5f33..503193d9 100644 --- a/chrome/browser/translate/translate_browsertest.cc +++ b/chrome/browser/translate/translate_browsertest.cc
@@ -70,7 +70,6 @@ net::EmbeddedTestServer* test_server = embedded_test_server(); test_server->ServeFilesFromSourceDirectory(kTranslateRoot); ASSERT_TRUE(test_server->Start()); - InProcessBrowserTest::SetUpOnMainThread(); } protected:
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc index 28215907..a76421f 100644 --- a/chrome/browser/translate/translate_manager_browsertest.cc +++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -82,7 +82,6 @@ } void SetUpOnMainThread() override { ResetObserver(); - InProcessBrowserTest::SetUpOnMainThread(); } private:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index bcf223ed..7d94805 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -112,6 +112,7 @@ "find_bar/find_notification_details.h", "find_bar/find_tab_helper.cc", "find_bar/find_tab_helper.h", + "forced_reauthentication_dialog.h", "history_ui.cc", "history_ui.h", "javascript_dialogs/chrome_javascript_native_dialog_factory.h", @@ -1656,8 +1657,8 @@ "views/frame/opaque_browser_frame_view_linux.h", "views/frame/opaque_browser_frame_view_platform_specific.cc", "views/frame/opaque_browser_frame_view_platform_specific.h", - "views/profiles/forced_reauthentication_dialog.cc", - "views/profiles/forced_reauthentication_dialog.h", + "views/profiles/forced_reauthentication_dialog_view.cc", + "views/profiles/forced_reauthentication_dialog_view.h", "views/profiles/profile_chooser_view.cc", "views/profiles/profile_chooser_view.h", "views/screen_capture_notification_ui_views.cc",
diff --git a/chrome/browser/ui/app_list/speech_recognizer_browsertest.cc b/chrome/browser/ui/app_list/speech_recognizer_browsertest.cc index 8429e95e..a3913944 100644 --- a/chrome/browser/ui/app_list/speech_recognizer_browsertest.cc +++ b/chrome/browser/ui/app_list/speech_recognizer_browsertest.cc
@@ -49,8 +49,6 @@ AppListSpeechRecognizerBrowserTest() {} void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - fake_speech_recognition_manager_.reset( new content::FakeSpeechRecognitionManager()); fake_speech_recognition_manager_->set_should_send_fake_response(true);
diff --git a/chrome/browser/ui/ash/ime_controller_client.cc b/chrome/browser/ui/ash/ime_controller_client.cc index 18ccedbf..cd34faf 100644 --- a/chrome/browser/ui/ash/ime_controller_client.cc +++ b/chrome/browser/ui/ash/ime_controller_client.cc
@@ -75,15 +75,24 @@ // ash::mojom::ImeControllerClient: void ImeControllerClient::SwitchToNextIme() { - NOTIMPLEMENTED(); + InputMethodManager::State* state = + input_method_manager_->GetActiveIMEState().get(); + if (state) + state->SwitchToNextInputMethod(); } void ImeControllerClient::SwitchToPreviousIme() { - NOTIMPLEMENTED(); + InputMethodManager::State* state = + input_method_manager_->GetActiveIMEState().get(); + if (state) + state->SwitchToPreviousInputMethod(); } void ImeControllerClient::SwitchImeById(const std::string& id) { - NOTIMPLEMENTED(); + InputMethodManager::State* state = + input_method_manager_->GetActiveIMEState().get(); + if (state) + state->ChangeInputMethod(id, true /* show_message */); } void ImeControllerClient::ActivateImeProperty(const std::string& key) {
diff --git a/chrome/browser/ui/ash/ime_controller_client_unittest.cc b/chrome/browser/ui/ash/ime_controller_client_unittest.cc index 457756fb..e4d74e4 100644 --- a/chrome/browser/ui/ash/ime_controller_client_unittest.cc +++ b/chrome/browser/ui/ash/ime_controller_client_unittest.cc
@@ -59,6 +59,11 @@ } // MockInputMethodManager::State: + void ChangeInputMethod(const std::string& input_method_id, + bool show_message) override { + ++change_input_method_count_; + current_ime_id_ = input_method_id; + } std::unique_ptr<std::vector<InputMethodDescriptor>> GetActiveInputMethods() const override { return base::MakeUnique<std::vector<InputMethodDescriptor>>( @@ -79,9 +84,16 @@ } return InputMethodUtil::GetFallbackInputMethodDescriptor(); } + void SwitchToNextInputMethod() override { ++next_input_method_count_; } + void SwitchToPreviousInputMethod() override { + ++previous_input_method_count_; + } std::string current_ime_id_; std::vector<InputMethodDescriptor> input_methods_; + int next_input_method_count_ = 0; + int previous_input_method_count_ = 0; + int change_input_method_count_ = 0; protected: friend base::RefCounted<InputMethodManager::State>; @@ -271,4 +283,23 @@ EXPECT_FALSE(ime_controller_.menu_items_[1]->checked); } +TEST_F(ImeControllerClientTest, SwitchToNextIme) { + ImeControllerClient client(&input_method_manager_); + client.SwitchToNextIme(); + EXPECT_EQ(1, input_method_manager_.state_->next_input_method_count_); +} + +TEST_F(ImeControllerClientTest, SwitchToPreviousIme) { + ImeControllerClient client(&input_method_manager_); + client.SwitchToPreviousIme(); + EXPECT_EQ(1, input_method_manager_.state_->previous_input_method_count_); +} + +TEST_F(ImeControllerClientTest, SwitchImeById) { + ImeControllerClient client(&input_method_manager_); + client.SwitchImeById("ime2"); + EXPECT_EQ(1, input_method_manager_.state_->change_input_method_count_); + EXPECT_EQ("ime2", input_method_manager_.state_->current_ime_id_); +} + } // namespace
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc index 2a9fd4f..2c4d4c28 100644 --- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -116,8 +116,6 @@ ~PopupBlockerBrowserTest() override {} void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - host_resolver()->AddRule("*", "127.0.0.1"); ASSERT_TRUE(embedded_test_server()->Start()); }
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_test.mm b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_test.mm index 975601d..231c39b 100644 --- a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_test.mm +++ b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_test.mm
@@ -49,7 +49,6 @@ } void BookmarkAppleScriptTest::SetUpOnMainThread() { - InProcessBrowserTest::SetUpOnMainThread(); ASSERT_TRUE(profile()); BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile());
diff --git a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.h b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.h index 38ce5296..ad12f31 100644 --- a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.h +++ b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.h
@@ -9,10 +9,6 @@ @interface ServiceDelegate : NSObject<NSXPCListenerDelegate, NSUserNotificationCenterDelegate> - -// The connection used to talk back to Chrome. -@property(assign, nonatomic, nullable) NSXPCConnection* connection; - @end #endif // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_NOTIFICATION_SERVICE_DELEGATE_H_
diff --git a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm index b5e9cc9..0d529ae 100644 --- a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm +++ b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm
@@ -15,10 +15,14 @@ @class NSUserNotificationCenter; @implementation ServiceDelegate { + // Helper to manage the XPC transaction reference count with respect to + // still-visible notifications. base::scoped_nsobject<XPCTransactionHandler> transactionHandler_; -} -@synthesize connection = connection_; + // Client connection accepted from the browser process, to which messages + // are sent in response to notification actions. + base::scoped_nsobject<NSXPCConnection> connection_; +} - (instancetype)init { if ((self = [super init])) { @@ -52,7 +56,7 @@ newConnection.exportedObject = object.get(); newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(NotificationReply)]; - connection_ = newConnection; + connection_.reset(newConnection, base::scoped_policy::RETAIN); [newConnection resume]; return YES;
diff --git a/chrome/browser/ui/forced_reauthentication_dialog.h b/chrome/browser/ui/forced_reauthentication_dialog.h new file mode 100644 index 0000000..edcb757c --- /dev/null +++ b/chrome/browser/ui/forced_reauthentication_dialog.h
@@ -0,0 +1,41 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_FORCED_REAUTHENTICATION_DIALOG_H_ +#define CHROME_BROWSER_UI_FORCED_REAUTHENTICATION_DIALOG_H_ + +#include <memory> + +#include "base/macros.h" + +class Profile; +class SigninManager; + +namespace base { +class TimeDelta; +} // namespace base + +// The virtual class of ForcedReauthenticationDialog. +class ForcedReauthenticationDialog { + public: + static std::unique_ptr<ForcedReauthenticationDialog> Create(); + + virtual ~ForcedReauthenticationDialog() {} + // Show the ForcedReauthenticationDialog for |profile|. If there're no opened + // browser windows for |profile|, |signin_manager| will be called to signed + // out immediately. Otherwise, dialog will be closed with all browser windows + // are assoicated to |profile| after |countdown_duration| if there is no + // reauth. + virtual void ShowDialog(Profile* profile, + SigninManager* signin_manager, + base::TimeDelta countdown_duration) = 0; + + protected: + ForcedReauthenticationDialog() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ForcedReauthenticationDialog); +}; + +#endif // CHROME_BROWSER_UI_FORCED_REAUTHENTICATION_DIALOG_H_
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc index b3f00cb0..66d9de0 100644 --- a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc +++ b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
@@ -21,8 +21,6 @@ ~ComponentToolbarActionsBrowserTest() override {} void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - // Replace the actions factory with a mock one. toolbar_model_ = ToolbarActionsModel::Get(browser()->profile()); toolbar_model_->SetMockActionsFactoryForTest(
diff --git a/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc b/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc index 2df9319..5c0e839 100644 --- a/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc
@@ -44,7 +44,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); profile_ = browser()->profile(); arc_app_list_pref_ = ArcAppListPrefs::Get(profile_); if (!arc_app_list_pref_) {
diff --git a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc index 0de5911..0a5081c 100644 --- a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc +++ b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
@@ -49,8 +49,6 @@ ~MediaRouterUIBrowserTest() override {} void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - BrowserActionsContainer* browser_actions_container = BrowserView::GetBrowserViewForBrowser(browser()) ->toolbar()
diff --git a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog.h b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog.h deleted file mode 100644 index 3e377d10..0000000 --- a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog.h +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_PROFILES_FORCED_REAUTHENTICATION_DIALOG_H_ -#define CHROME_BROWSER_UI_VIEWS_PROFILES_FORCED_REAUTHENTICATION_DIALOG_H_ - -#include <memory> -#include <string> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/timer/timer.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/window/dialog_delegate.h" - -class Browser; -class Profile; -class SigninManager; - -// A modal dialog that displays a warning message of the auth failure -// and ask user to sign in again. -class ForcedReauthenticationDialog : public views::DialogDelegateView { - public: - ~ForcedReauthenticationDialog() override; - - // Shows a warning dialog for |profile|. If there are no Browser windows - // associated with |profile|, signs out the profile immediately, otherwise the - // user can clicks accept to sign in again. Dialog will be closed after - // |countdown_duration| seconds. - // Dialog will delete itself after closing. - static ForcedReauthenticationDialog* ShowDialog( - Profile* profile, - SigninManager* signin_manager, - const base::TimeDelta& countdown_duration); - - // override views::DialogDelegateView - bool Accept() override; - bool Cancel() override; - void WindowClosing() override; - base::string16 GetWindowTitle() const override; - base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; - ui::ModalType GetModalType() const override; - - // override views::View - void AddedToWidget() override; - - private: - // Show the dialog for |browser|. The dialog will delete itself after closing. - ForcedReauthenticationDialog(Browser* browser, - SigninManager* signin_manager, - const base::TimeDelta& countdown_duration); - - void OnCountDown(); - base::TimeDelta GetTimeRemaining() const; - - Browser* browser_; - SigninManager* signin_manager_; - - const base::TimeTicks desired_close_time_; - - // The timer which is used to refresh the dialog title to display the - // remaining time. - base::RepeatingTimer refresh_timer_; - - DISALLOW_COPY_AND_ASSIGN(ForcedReauthenticationDialog); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_PROFILES_FORCED_REAUTHENTICATION_DIALOG_H_
diff --git a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog.cc b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.cc similarity index 80% rename from chrome/browser/ui/views/profiles/forced_reauthentication_dialog.cc rename to chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.cc index d02b926..997d433 100644 --- a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog.cc +++ b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.cc
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/profiles/forced_reauthentication_dialog.h" +#include "chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h" +#include <map> #include <memory> #include <string> #include <utility> @@ -82,13 +83,16 @@ } // namespace -ForcedReauthenticationDialog::ForcedReauthenticationDialog( +// ForcedReauthenticationDialogView + +ForcedReauthenticationDialogView::ForcedReauthenticationDialogView( Browser* browser, SigninManager* signin_manager, - const base::TimeDelta& countdown_duration) + base::TimeDelta countdown_duration) : browser_(browser), signin_manager_(signin_manager), - desired_close_time_(base::TimeTicks::Now() + countdown_duration) { + desired_close_time_(base::TimeTicks::Now() + countdown_duration), + weak_factory_(this) { constrained_window::CreateBrowserModalDialogViews( this, browser->window()->GetNativeWindow()) ->Show(); @@ -96,13 +100,13 @@ browser->window()->Activate(); } -ForcedReauthenticationDialog::~ForcedReauthenticationDialog() {} +ForcedReauthenticationDialogView::~ForcedReauthenticationDialogView() {} // static -ForcedReauthenticationDialog* ForcedReauthenticationDialog::ShowDialog( +ForcedReauthenticationDialogView* ForcedReauthenticationDialogView::ShowDialog( Profile* profile, SigninManager* signin_manager, - const base::TimeDelta& countdown_duration) { + base::TimeDelta countdown_duration) { Browser* browser = FindBrowserWithProfile(profile); if (browser == nullptr) { // If there is no browser, we can just sign // out profile directly. @@ -110,11 +114,11 @@ return nullptr; } - return new ForcedReauthenticationDialog(browser, signin_manager, - countdown_duration); + return new ForcedReauthenticationDialogView(browser, signin_manager, + countdown_duration); } -bool ForcedReauthenticationDialog::Accept() { +bool ForcedReauthenticationDialogView::Accept() { if (GetTimeRemaining() < base::TimeDelta::FromSeconds(kCloseDirectlyTimer)) { Signout(signin_manager_); } else { @@ -125,22 +129,22 @@ return true; } -bool ForcedReauthenticationDialog::Cancel() { +bool ForcedReauthenticationDialogView::Cancel() { return true; } -void ForcedReauthenticationDialog::WindowClosing() { +void ForcedReauthenticationDialogView::WindowClosing() { refresh_timer_.Stop(); } -base::string16 ForcedReauthenticationDialog::GetWindowTitle() const { +base::string16 ForcedReauthenticationDialogView::GetWindowTitle() const { base::TimeDelta time_left = GetTimeRemaining(); return base::i18n::MessageFormatter::FormatWithNumberedArgs( l10n_util::GetStringUTF16(IDS_ENTERPRISE_FORCE_SIGNOUT_TITLE), time_left.InMinutes(), time_left.InSeconds() % 60); } -base::string16 ForcedReauthenticationDialog::GetDialogButtonLabel( +base::string16 ForcedReauthenticationDialogView::GetDialogButtonLabel( ui::DialogButton button) const { if (button == ui::DIALOG_BUTTON_OK) { return l10n_util::GetStringUTF16( @@ -149,11 +153,11 @@ return l10n_util::GetStringUTF16(IDS_ENTERPRISE_FORCE_SIGNOUT_CLOSE_DELAY); } -ui::ModalType ForcedReauthenticationDialog::GetModalType() const { +ui::ModalType ForcedReauthenticationDialogView::GetModalType() const { return ui::MODAL_TYPE_WINDOW; } -void ForcedReauthenticationDialog::AddedToWidget() { +void ForcedReauthenticationDialogView::AddedToWidget() { const SkColor prompt_bar_background_color = GetSigninConfirmationPromptBarColor( GetNativeTheme(), ui::kSigninConfirmationPromptBarBackgroundAlpha); @@ -231,10 +235,14 @@ explanation_label->GetHeightForWidth(kPreferredWidth)); refresh_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kRefreshTitleTimer), this, - &ForcedReauthenticationDialog::OnCountDown); + &ForcedReauthenticationDialogView::OnCountDown); } -void ForcedReauthenticationDialog::OnCountDown() { +void ForcedReauthenticationDialogView::CloseDialog() { + GetWidget()->Close(); +} + +void ForcedReauthenticationDialogView::OnCountDown() { if (desired_close_time_ <= base::TimeTicks::Now()) { Cancel(); GetWidget()->Close(); @@ -242,9 +250,34 @@ GetWidget()->UpdateWindowTitle(); } -base::TimeDelta ForcedReauthenticationDialog::GetTimeRemaining() const { +base::TimeDelta ForcedReauthenticationDialogView::GetTimeRemaining() const { base::TimeTicks now = base::TimeTicks::Now(); if (desired_close_time_ <= now) return base::TimeDelta(); return desired_close_time_ - now; } + +// ForcedReauthenticationDialogImpl + +ForcedReauthenticationDialogImpl::ForcedReauthenticationDialogImpl() {} +ForcedReauthenticationDialogImpl::~ForcedReauthenticationDialogImpl() { + if (dialog_view_) + dialog_view_->CloseDialog(); +} + +void ForcedReauthenticationDialogImpl::ShowDialog( + Profile* profile, + SigninManager* signin_manager, + base::TimeDelta countdown_duration) { + dialog_view_ = ForcedReauthenticationDialogView::ShowDialog( + profile, signin_manager, countdown_duration) + ->AsWeakPtr(); +} + +// ForcedReauthenticationDialog + +// static +std::unique_ptr<ForcedReauthenticationDialog> +ForcedReauthenticationDialog::Create() { + return base::MakeUnique<ForcedReauthenticationDialogImpl>(); +}
diff --git a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h new file mode 100644 index 0000000..9530c953 --- /dev/null +++ b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h
@@ -0,0 +1,94 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_PROFILES_FORCED_REAUTHENTICATION_DIALOG_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_PROFILES_FORCED_REAUTHENTICATION_DIALOG_VIEW_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "chrome/browser/ui/forced_reauthentication_dialog.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/window/dialog_delegate.h" + +class Browser; +class Profile; +class SigninManager; + +// A modal dialog that displays a warning message of the auth failure +// and ask user to sign in again. +class ForcedReauthenticationDialogView : public views::DialogDelegateView { + public: + ~ForcedReauthenticationDialogView() override; + + // Shows a warning dialog for |profile|. If there are no Browser windows + // associated with |profile|, signs out the profile immediately, otherwise the + // user can clicks accept to sign in again. Dialog will be closed after + // |countdown_duration| seconds. + // Dialog will delete itself after closing. + static ForcedReauthenticationDialogView* ShowDialog( + Profile* profile, + SigninManager* signin_manager, + base::TimeDelta countdown_duration); + + // override views::DialogDelegateView + bool Accept() override; + bool Cancel() override; + void WindowClosing() override; + base::string16 GetWindowTitle() const override; + base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; + ui::ModalType GetModalType() const override; + + // override views::View + void AddedToWidget() override; + + // Close the dialog + void CloseDialog(); + + base::WeakPtr<ForcedReauthenticationDialogView> AsWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + private: + // Show the dialog for |browser|. The dialog will delete itself after closing. + ForcedReauthenticationDialogView(Browser* browser, + SigninManager* signin_manager, + base::TimeDelta countdown_duration); + + void OnCountDown(); + base::TimeDelta GetTimeRemaining() const; + + Browser* browser_; + SigninManager* signin_manager_; + + const base::TimeTicks desired_close_time_; + + // The timer which is used to refresh the dialog title to display the + // remaining time. + base::RepeatingTimer refresh_timer_; + + base::WeakPtrFactory<ForcedReauthenticationDialogView> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ForcedReauthenticationDialogView); +}; + +class ForcedReauthenticationDialogImpl : public ForcedReauthenticationDialog { + public: + ForcedReauthenticationDialogImpl(); + ~ForcedReauthenticationDialogImpl() override; + + // override ForcedReauthenticationDialog + void ShowDialog(Profile* profile, + SigninManager* signin_manager, + base::TimeDelta countdown_duration) override; + + private: + base::WeakPtr<ForcedReauthenticationDialogView> dialog_view_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_PROFILES_FORCED_REAUTHENTICATION_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_browsertest.cc b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.cc similarity index 73% rename from chrome/browser/ui/views/profiles/forced_reauthentication_dialog_browsertest.cc rename to chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.cc index 4639449..33d1dfd77 100644 --- a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_browsertest.cc +++ b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.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 "chrome/browser/ui/views/profiles/forced_reauthentication_dialog.h" +#include "chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h" #include "base/bind.h" #include "base/bind_helpers.h" @@ -15,48 +15,48 @@ #include "components/signin/core/browser/signin_manager.h" #include "ui/base/ui_base_types.h" -class ForcedReauthenticationDialogBrowserTest : public DialogBrowserTest { +class ForcedReauthenticationDialogViewBrowserTest : public DialogBrowserTest { public: - ForcedReauthenticationDialogBrowserTest() {} + ForcedReauthenticationDialogViewBrowserTest() {} // override DialogBrowserTest void ShowDialog(const std::string& name) override { Profile* profile = browser()->profile(); SigninManager* manager = SigninManagerFactory::GetForProfile(profile); manager->SetAuthenticatedAccountInfo("test1", "test@xyz.com"); - ForcedReauthenticationDialog::ShowDialog(profile, manager, - base::TimeDelta::FromSeconds(60)); + ForcedReauthenticationDialogView::ShowDialog( + profile, manager, base::TimeDelta::FromSeconds(60)); } // An integer represents the buttons of dialog. private: - DISALLOW_COPY_AND_ASSIGN(ForcedReauthenticationDialogBrowserTest); + DISALLOW_COPY_AND_ASSIGN(ForcedReauthenticationDialogViewBrowserTest); }; -IN_PROC_BROWSER_TEST_F(ForcedReauthenticationDialogBrowserTest, +IN_PROC_BROWSER_TEST_F(ForcedReauthenticationDialogViewBrowserTest, InvokeDialog_default) { RunDialog(); } // Dialog will not be display if there is no valid browser window. -IN_PROC_BROWSER_TEST_F(ForcedReauthenticationDialogBrowserTest, +IN_PROC_BROWSER_TEST_F(ForcedReauthenticationDialogViewBrowserTest, NotOpenDialogDueToNoBrowser) { Profile* profile = browser()->profile(); CloseBrowserSynchronously(browser()); - EXPECT_EQ(nullptr, ForcedReauthenticationDialog::ShowDialog( + EXPECT_EQ(nullptr, ForcedReauthenticationDialogView::ShowDialog( profile, SigninManagerFactory::GetForProfile(profile), base::TimeDelta::FromSeconds(60))); } -IN_PROC_BROWSER_TEST_F(ForcedReauthenticationDialogBrowserTest, +IN_PROC_BROWSER_TEST_F(ForcedReauthenticationDialogViewBrowserTest, NotOpenDialogDueToNoTabs) { Profile* profile = browser()->profile(); TabStripModel* model = browser()->tab_strip_model(); ASSERT_EQ(1, model->count()); model->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE); ASSERT_TRUE(model->empty()); - EXPECT_EQ(nullptr, ForcedReauthenticationDialog::ShowDialog( + EXPECT_EQ(nullptr, ForcedReauthenticationDialogView::ShowDialog( profile, SigninManagerFactory::GetForProfile(profile), base::TimeDelta::FromSeconds(60))); }
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc index 3bb84430..df2c59c5 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc
@@ -24,9 +24,6 @@ public: TranslateBubbleViewBrowserTest() {} ~TranslateBubbleViewBrowserTest() override {} - void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - } private: DISALLOW_COPY_AND_ASSIGN(TranslateBubbleViewBrowserTest);
diff --git a/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc b/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc index dbed0b1d..ccdee6ab 100644 --- a/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc +++ b/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc
@@ -21,8 +21,6 @@ BookmarksTest() {} void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - // Re-enable accessibility checks when audit failures are resolved. // AX_TEXT_01: http://crbug.com/559201 // AX_ARIA_08: http://crbug.com/559202
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc index 1802b08..1c9fdf9 100644 --- a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc +++ b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
@@ -482,8 +482,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - // Grab references to the fake signin manager and token service. Profile* profile = browser()->profile(); signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc index 22e6322..5eebc0c 100644 --- a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc +++ b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
@@ -10,6 +10,7 @@ #include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h" #include "components/crx_file/id_util.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/features/simple_feature.h" #include "extensions/common/manifest_constants.h" @@ -119,7 +120,7 @@ // Test with an options page. extension = LoadAndExpectSuccess("init_valid_options.json"); - EXPECT_EQ("chrome-extension", + EXPECT_EQ(extensions::kExtensionScheme, OptionsPageInfo::GetOptionsPage(extension.get()).scheme()); EXPECT_EQ("/options.html", OptionsPageInfo::GetOptionsPage(extension.get()).path());
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 3a01ea6b..d3d31b7 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -141,6 +141,7 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) #include "chrome/common/extensions/chrome_extensions_client.h" #include "chrome/renderer/extensions/chrome_extensions_renderer_client.h" +#include "extensions/common/constants.h" #include "extensions/common/extension_urls.h" #include "extensions/common/switches.h" #include "extensions/renderer/dispatcher.h" @@ -1014,7 +1015,7 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) bool is_extension_from_webstore = extension && extension->from_webstore(); - bool is_invoked_by_extension = app_url.SchemeIs("chrome-extension"); + bool is_invoked_by_extension = app_url.SchemeIs(extensions::kExtensionScheme); bool is_invoked_by_hosted_app = extension && extension->is_hosted_app() && extension->web_extent().MatchesURL(app_url);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 4fb0caf..884c2e8 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2046,6 +2046,7 @@ } if (toolkit_views) { sources += [ + "../browser/payments/payment_manifest_parser_host_browsertest.cc", "../browser/payments/site_per_process_payments_browsertest.cc", "../browser/ui/global_error/global_error_service_browsertest.cc", "../browser/ui/views/bookmarks/bookmark_editor_view_browsertest.cc", @@ -2085,7 +2086,7 @@ deps += [ "//ui/views" ] if (!is_chromeos && (!is_mac || mac_views_browser)) { sources += [ - "../browser/ui/views/profiles/forced_reauthentication_dialog_browsertest.cc", + "../browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.cc", "../browser/ui/views/profiles/profile_chooser_view_browsertest.cc", ] } @@ -4411,6 +4412,7 @@ } if (enable_session_service) { sources += [ + "../browser/sessions/session_restore_observer_unittest.cc", "../browser/sessions/session_restore_stats_collector_unittest.cc", "../browser/sessions/session_service_unittest.cc", "../browser/sessions/tab_loader_unittest.cc",
diff --git a/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py b/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py index c39ef194..803bb6f 100644 --- a/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py +++ b/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py
@@ -31,11 +31,11 @@ """Cast page to open a cast-enabled page and open media router dialog.""" def __init__(self, page_set, url='file://basic_test.html', - shared_page_state_class=shared_page_state.SharedPageState, - name='basic_test.html'): + shared_page_state_class=shared_page_state.SharedPageState): super(CastDialogPage, self).__init__( url=url, page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name='basic_test.html') def RunPageInteractions(self, action_runner): # Wait for 5s after Chrome is opened in order to get consistent results.
diff --git a/chrome/test/perf/mach_ports_performancetest.cc b/chrome/test/perf/mach_ports_performancetest.cc index e7b1d78..77c5db9 100644 --- a/chrome/test/perf/mach_ports_performancetest.cc +++ b/chrome/test/perf/mach_ports_performancetest.cc
@@ -30,7 +30,6 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); ASSERT_TRUE(embedded_test_server()->Start()); }
diff --git a/chrome/test/vr/perf/BUILD.gn b/chrome/test/vr/perf/BUILD.gn index 95ec12e..d4d724e 100644 --- a/chrome/test/vr/perf/BUILD.gn +++ b/chrome/test/vr/perf/BUILD.gn
@@ -2,17 +2,38 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +common_data = [ + "./__init__.py", + "./android_vr_perf_test.py", + "./vr_perf_test.py", + "//third_party/android_tools/sdk/platform-tools/adb", + "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", +] + group("motopho_latency_test") { testonly = true - data = [ + data = common_data + [ "./latency/__init__.py", "./latency/android_webvr_latency_test.py", + "./latency/latency_test_config.py", "./latency/motopho_thread.py", "./latency/robot_arm.py", "./latency/run_latency_test.py", "./latency/webvr_latency_test.py", - "//third_party/android_tools/sdk/platform-tools/adb", - "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", + ] + data_deps = [ + "//chrome/android:chrome_public_apk", + ] +} + +group("vrcore_fps_test") { + testonly = true + data = common_data + [ + "./vrcore_fps/__init__.py", + "./vrcore_fps/run_vrcore_fps_test.py", + "./vrcore_fps/vrcore_fps_test.py", + "./vrcore_fps/vrcore_fps_test_config.py", + "./vrcore_fps/vr_perf_summary.py", ] data_deps = [ "//chrome/android:chrome_public_apk",
diff --git a/chrome/test/vr/perf/__init__.py b/chrome/test/vr/perf/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/test/vr/perf/__init__.py
diff --git a/chrome/test/vr/perf/android_vr_perf_test.py b/chrome/test/vr/perf/android_vr_perf_test.py new file mode 100644 index 0000000..e82c704 --- /dev/null +++ b/chrome/test/vr/perf/android_vr_perf_test.py
@@ -0,0 +1,127 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import vr_perf_test + +import logging +import os +import time + +DEFAULT_SCREEN_WIDTH = 720 +DEFAULT_SCREEN_HEIGHT = 1280 +NUM_VR_ENTRY_ATTEMPTS = 5 + +class AndroidVrPerfTest(vr_perf_test.VrPerfTest): + """Base class for VrPerfTests running on Android. + + Handles the setup and teardown portions of the test. The _Run function + that actually runs the test is to be implemented in a subclass or in + a separate class that a subclass also inherits from. + """ + def __init__(self, args): + super(AndroidVrPerfTest, self).__init__(args) + # Swarming stuff seems to routinely kill off adbd once a minute or so, + # which often causes adb's startup message to appear in the output. We need + # to remove this before getting the device name. + # TODO(bsheedy): Look into preventing adbd from being killed altogether + # instead of working around it. + self._device_name = self._Adb(['shell', 'getprop', + 'ro.product.name']).strip().split('\n')[-1] + + def _Adb(self, cmd): + """Runs the given command via adb. + + Returns: + A string containing the stdout and stderr of the adb command. + """ + # TODO(bsheedy): Maybe migrate to use Devil (overkill?). + return self._RunCommand([self._args.adb_path] + cmd) + + def _OneTimeSetup(self): + self._Adb(['root']) + + # Install the latest VrCore and Chrome APKs. + self._Adb(['install', '-r', '-d', + '../../third_party/gvr-android-sdk/test-apks/vr_services' + '/vr_services_current.apk']) + # TODO(bsheedy): Make APK path configurable so usable with other channels. + self._Adb(['install', '-r', 'apks/ChromePublic.apk']) + + # Force WebVR support, remove open tabs, and don't have first run + # experience. + self._SetChromeCommandLineFlags(['--enable-webvr', '--no-restore-state', + '--disable-fre']) + # Wake up the device and sleep, otherwise WebGL can crash on startup. + self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_WAKEUP']) + time.sleep(1) + + def _Setup(self, url): + # Start Chrome + self._Adb(['shell', 'am', 'start', + '-a', 'android.intent.action.MAIN', + '-n', 'org.chromium.chrome/com.google.android.apps.chrome.Main', + url]) + # TODO(bsheedy): Remove this sleep - poll for magic window GVR + # initialization to know when page fully loaded and ready? + time.sleep(10) + + # Tap the center of the screen to start presenting. + # It's technically possible that the screen tap won't enter VR on the first + # time, so try several times by checking for the logcat output from + # entering VR. + (width, height) = self._GetScreenResolution() + entered_vr = False + for _ in xrange(NUM_VR_ENTRY_ATTEMPTS): + self._Adb(['logcat', '-c']) + self._Adb(['shell', 'input', 'touchscreen', 'tap', str(width/2), + str(height/2)]) + time.sleep(5) + output = self._Adb(['logcat', '-d']) + if 'Initialized GVR version' in output: + entered_vr = True + break + logging.warning('Failed to enter VR, retrying') + if not entered_vr: + raise RuntimeError('Failed to enter VR after %d attempts' + % NUM_VR_ENTRY_ATTEMPTS) + + def _Teardown(self): + # Exit VR and close Chrome. + self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_BACK']) + self._Adb(['shell', 'am', 'force-stop', 'org.chromium.chrome']) + + def _OneTimeTeardown(self): + # Turn off the screen. + self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_POWER']) + + def _SetChromeCommandLineFlags(self, flags): + """Sets the Chrome command line flags to the given list.""" + self._Adb(['shell', "echo 'chrome " + ' '.join(flags) + "' > " + + '/data/local/tmp/chrome-command-line']) + + def _GetScreenResolution(self): + """Retrieves the device's screen resolution, or a default if not found. + + Returns: + A tuple (width, height). + """ + output = self._Adb(['shell', 'dumpsys', 'display']) + width = None + height = None + for line in output.split('\n'): + if 'mDisplayWidth' in line: + width = int(line.split('=')[1]) + elif 'mDisplayHeight' in line: + height = int(line.split('=')[1]) + if width and height: + break + if not width: + logging.warning('Could not get actual screen width, defaulting to %d', + DEFAULT_SCREEN_WIDTH) + width = DEFAULT_SCREEN_WIDTH + if not height: + logging.warning('Could not get actual screen height, defaulting to %d', + DEFAULT_SCREEN_HEIGHT) + height = DEFAULT_SCREEN_HEIGHT + return (width, height)
diff --git a/chrome/test/vr/perf/latency/android_webvr_latency_test.py b/chrome/test/vr/perf/latency/android_webvr_latency_test.py index 6608dc5b..5ebc1b4 100644 --- a/chrome/test/vr/perf/latency/android_webvr_latency_test.py +++ b/chrome/test/vr/perf/latency/android_webvr_latency_test.py
@@ -2,145 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import android_vr_perf_test import webvr_latency_test -import logging -import os -import time - - -DEFAULT_SCREEN_WIDTH = 720 -DEFAULT_SCREEN_HEIGHT = 1280 -NUM_VR_ENTRY_ATTEMPTS = 5 - - -class AndroidWebVrLatencyTest(webvr_latency_test.WebVrLatencyTest): +class AndroidWebVrLatencyTest(webvr_latency_test.WebVrLatencyTest, + android_vr_perf_test.AndroidVrPerfTest): """Android implementation of the WebVR latency test.""" def __init__(self, args): super(AndroidWebVrLatencyTest, self).__init__(args) - # Swarming stuff seems to routinely kill off adbd once a minute or so, - # which often causes adb's startup message to appear in the output. We need - # to remove this before getting the device name - # TODO(bsheedy): Look into preventing adbd from being killed altogether - # instead of working around it - self._device_name = self._Adb(['shell', 'getprop', - 'ro.product.name']).strip().split('\n')[-1] - - def _OneTimeSetup(self): - self._Adb(['root']) - - # Install the latest VrCore and Chrome APKs - self._Adb(['install', '-r', '-d', - '../../third_party/gvr-android-sdk/test-apks/vr_services' - '/vr_services_current.apk']) - self._SaveInstalledVrCoreVersion() - # TODO(bsheedy): Make APK path configurable so usable with other channels - self._Adb(['install', '-r', 'apks/ChromePublic.apk']) - - # Force WebVR support, remove open tabs, and don't have first run - # experience. - self._SetChromeCommandLineFlags(['--enable-webvr', '--no-restore-state', - '--disable-fre']) - # Wake up the device and sleep, otherwise WebGL can crash on startup. - self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_WAKEUP']) - time.sleep(1) - - - def _Setup(self, url): - # Start Chrome - self._Adb(['shell', 'am', 'start', - '-a', 'android.intent.action.MAIN', - '-n', 'org.chromium.chrome/com.google.android.apps.chrome.Main', - url]) - time.sleep(10) - - # Tap the center of the screen to start presenting. - # It's technically possible that the screen tap won't enter VR on the first - # time, so try several times by checking for the logcat output from - # entering VR - (width, height) = self._GetScreenResolution() - entered_vr = False - for _ in xrange(NUM_VR_ENTRY_ATTEMPTS): - self._Adb(['logcat', '-c']) - self._Adb(['shell', 'input', 'touchscreen', 'tap', str(width/2), - str(height/2)]) - time.sleep(5) - output = self._Adb(['logcat', '-d']) - if 'Initialized GVR version' in output: - entered_vr = True - break - logging.warning('Failed to enter VR, retrying') - if not entered_vr: - raise RuntimeError('Failed to enter VR after %d attempts' - % NUM_VR_ENTRY_ATTEMPTS) - - def _Teardown(self): - # Exit VR and close Chrome - self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_BACK']) - self._Adb(['shell', 'am', 'force-stop', 'org.chromium.chrome']) - - def _OneTimeTeardown(self): - # Perform teardown again in case an exception was thrown - self._Teardown() - # Turn off the screen - self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_POWER']) - - def _Adb(self, cmd): - """Runs the given command via adb. - - Returns: - A string containing the stdout and stderr of the adb command. - """ - # TODO(bsheedy): Maybe migrate to use Devil (overkill?) - return self._RunCommand([self.args.adb_path] + cmd) - - def _SaveInstalledVrCoreVersion(self): - """Retrieves the VrCore version and saves it for dashboard uploading.""" - output = self._Adb(['shell', 'dumpsys', 'package', 'com.google.vr.vrcore']) - version = None - for line in output.split('\n'): - if 'versionName' in line: - version = line.split('=')[1] - break - if version: - logging.info('VrCore version is %s', version) - else: - logging.info('VrCore version not retrieved') - version = '0' - if not (self.args.output_dir and os.path.isdir(self.args.output_dir)): - logging.warning('No output directory, not saving VrCore version') - return - with file(os.path.join(self.args.output_dir, - self.args.vrcore_version_file), 'w') as outfile: - outfile.write(version) - - def _SetChromeCommandLineFlags(self, flags): - """Sets the Chrome command line flags to the given list.""" - self._Adb(['shell', "echo 'chrome " + ' '.join(flags) + "' > " - + '/data/local/tmp/chrome-command-line']) - - def _GetScreenResolution(self): - """Retrieves the device's screen resolution, or a default if not found. - - Returns: - A tuple (width, height). - """ - output = self._Adb(['shell', 'dumpsys', 'display']) - width = None - height = None - for line in output.split('\n'): - if 'mDisplayWidth' in line: - width = int(line.split('=')[1]) - elif 'mDisplayHeight' in line: - height = int(line.split('=')[1]) - if width and height: - break - if not width: - logging.warning('Could not get actual screen width, defaulting to %d', - DEFAULT_SCREEN_WIDTH) - width = DEFAULT_SCREEN_WIDTH - if not height: - logging.warning('Could not get actual screen height, defaulting to %d', - DEFAULT_SCREEN_HEIGHT) - height = DEFAULT_SCREEN_HEIGHT - return (width, height)
diff --git a/chrome/test/vr/perf/latency/latency_test_config.py b/chrome/test/vr/perf/latency/latency_test_config.py new file mode 100644 index 0000000..58acb7c --- /dev/null +++ b/chrome/test/vr/perf/latency/latency_test_config.py
@@ -0,0 +1,10 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import sys + +# Add //chrome/test/vr/perf to system path. +sys.path.append(os.path.join(os.path.dirname(__file__), + os.pardir))
diff --git a/chrome/test/vr/perf/latency/motopho_thread.py b/chrome/test/vr/perf/latency/motopho_thread.py index aca45614..0681752f 100644 --- a/chrome/test/vr/perf/latency/motopho_thread.py +++ b/chrome/test/vr/perf/latency/motopho_thread.py
@@ -16,7 +16,7 @@ self._correlations = [] # Threads can't be restarted, so in order to gather multiple samples, we # need to either re-create the thread for every iteration or use a loop - # and locks in a single thread -> use the latter solution + # and locks in a single thread -> use the latter solution. self._start_lock = threading.Event() self._finish_lock = threading.Event() self.BlockNextIteration()
diff --git a/chrome/test/vr/perf/latency/robot_arm.py b/chrome/test/vr/perf/latency/robot_arm.py index 052b9617..18d574b 100644 --- a/chrome/test/vr/perf/latency/robot_arm.py +++ b/chrome/test/vr/perf/latency/robot_arm.py
@@ -29,7 +29,7 @@ return # If the servo stopped very close to the desired position, it can just # vibrate instead of moving, so move away before going to the reset - # position + # position. self._connection.write('5 300 0 5\n') time.sleep(0.5) self._connection.write('5 250 0 5\n')
diff --git a/chrome/test/vr/perf/latency/run_latency_test.py b/chrome/test/vr/perf/latency/run_latency_test.py index cd96b164..3f5c747 100644 --- a/chrome/test/vr/perf/latency/run_latency_test.py +++ b/chrome/test/vr/perf/latency/run_latency_test.py
@@ -10,7 +10,8 @@ a set of servos, which physically moves the test device and Motopho during the latency test. """ - +# Must be first import in order to add parent directory to system path. +import latency_test_config import android_webvr_latency_test import argparse @@ -21,7 +22,7 @@ DEFAULT_ADB_PATH = os.path.realpath('../../third_party/android_tools/sdk/' 'platform-tools/adb') # TODO(bsheedy): See about adding tool via DEPS instead of relying on it -# existing on the bot already +# existing on the bot already. DEFAULT_MOTOPHO_PATH = os.path.join(os.path.expanduser('~'), 'motopho/Motopho') DEFAULT_NUM_SAMPLES = 10 DEFAULT_RESULTS_FILE = 'results-chart.json' @@ -71,10 +72,6 @@ parser.add_argument('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') - parser.add_argument('--vrcore-version-file', - default=DEFAULT_VRCORE_VERSION_FILE, - help='The name of the text file that the VrCore APK ' - 'version number will be saved to') (args, unknown_args) = parser.parse_known_args() SetLogLevel(args.verbose_count) if unknown_args:
diff --git a/chrome/test/vr/perf/latency/webvr_latency_test.py b/chrome/test/vr/perf/latency/webvr_latency_test.py index 4f69c287..25dc048 100644 --- a/chrome/test/vr/perf/latency/webvr_latency_test.py +++ b/chrome/test/vr/perf/latency/webvr_latency_test.py
@@ -20,28 +20,28 @@ DEFAULT_URLS = [ # TODO(bsheedy): See about having versioned copies of the flicker app # instead of using personal github. - # Purely a flicker app - no additional CPU/GPU load + # Purely a flicker app - no additional CPU/GPU load. 'https://weableandbob.github.io/Motopho/' 'flicker_apps/webvr/webvr-flicker-app-klaus.html?' 'polyfill=0\&canvasClickPresents=1', - # URLs that render 3D scenes in addition to the Motopho patch - # Heavy CPU load, moderate GPU load + # URLs that render 3D scenes in addition to the Motopho patch. + # Heavy CPU load, moderate GPU load. 'https://webvr.info/samples/test-slow-render.html?' 'latencyPatch=1\&canvasClickPresents=1\&' 'heavyGpu=1\&workTime=20\&cubeCount=8\&cubeScale=0.4', - # Moderate CPU load, light GPU load + # Moderate CPU load, light GPU load. 'https://webvr.info/samples/test-slow-render.html?' 'latencyPatch=1\&canvasClickPresents=1\&' 'heavyGpu=1\&workTime=12\&cubeCount=8\&cubeScale=0.3', - # Light CPU load, moderate GPU load + # Light CPU load, moderate GPU load. 'https://webvr.info/samples/test-slow-render.html?' 'latencyPatch=1\&canvasClickPresents=1\&' 'heavyGpu=1\&workTime=5\&cubeCount=8\&cubeScale=0.4', - # Heavy CPU load, very light GPU load + # Heavy CPU load, very light GPU load. 'https://webvr.info/samples/test-slow-render.html?' 'latencyPatch=1\&canvasClickPresents=1\&' 'workTime=20', - # No additional CPU load, very light GPU load + # No additional CPU load, very light GPU load. 'https://webvr.info/samples/test-slow-render.html?' 'latencyPatch=1\&canvasClickPresents=1', ] @@ -90,72 +90,44 @@ class WebVrLatencyTest(object): """Base class for all WebVR latency tests. - This is meant to be subclassed for each platform the test is run on. While - the latency test itself is cross-platform, the setup and teardown for - tests is platform-dependent. + This handles the platform-independent _Run and _SaveResultsToFile functions. + Platform-specific setup and teardown should be somehow handled by classes + that inherit from this one. """ def __init__(self, args): - self.args = args + super(WebVrLatencyTest, self).__init__(args) self._num_samples = args.num_samples self._test_urls = args.urls or DEFAULT_URLS assert (self._num_samples > 0),'Number of samples must be greater than 0' - self._device_name = 'generic_device' self._test_results = {} - # Connect to the Arduino that drives the servos + # Connect to the Arduino that drives the servos. devices = GetTtyDevices(r'ttyACM\d+', [0x2a03, 0x2341]) assert (len(devices) == 1),'Found %d devices, expected 1' % len(devices) self.robot_arm = ra.RobotArm(devices[0]) - def RunTests(self): - """Runs latency tests on all the URLs provided to the test on creation. - - Repeatedly runs the steps to start Chrome, measure/store latency, and - clean up before storing all results to a single file for dashboard - uploading. - """ - try: - self._OneTimeSetup() - for url in self._test_urls: - self._Setup(url) - self._Run(url) - self._Teardown() - self._SaveResultsToFile() - finally: - self._OneTimeTeardown() - - def _OneTimeSetup(self): - """Performs any platform-specific setup once before any tests.""" - raise NotImplementedError( - 'Platform-specific setup must be implemented in subclass') - - def _Setup(self, url): - """Performs any platform-specific setup before each test.""" - raise NotImplementedError( - 'Platform-specific setup must be implemented in subclass') - def _Run(self, url): """Run the latency test. Handles the actual latency measurement, which is identical across different platforms, as well as result storing. """ - # Motopho scripts use relative paths, so switch to the Motopho directory - os.chdir(self.args.motopho_path) + # Motopho scripts use relative paths, so switch to the Motopho directory. + os.chdir(self._args.motopho_path) - # Set up the thread that runs the Motopho script + # Set up the thread that runs the Motopho script. motopho_thread = mt.MotophoThread(self._num_samples) motopho_thread.start() - # Run multiple times so we can get an average and standard deviation + # Run multiple times so we can get an average and standard deviation. for _ in xrange(self._num_samples): self.robot_arm.ResetPosition() - # Start the Motopho script + # Start the Motopho script. motopho_thread.StartIteration() - # Let the Motopho be stationary so the script can calculate the bias + # Let the Motopho be stationary so the script can calculate the bias. time.sleep(3) motopho_thread.BlockNextIteration() - # Move so we can measure latency + # Move so we can measure latency. self.robot_arm.StartMotophoMovement() if not motopho_thread.WaitForIterationEnd(MOTOPHO_THREAD_TIMEOUT): # TODO(bsheedy): Look into ways to prevent Motopho from not sending any @@ -167,34 +139,6 @@ self._StoreResults(motopho_thread.latencies, motopho_thread.correlations, url) - def _Teardown(self): - """Performs any platform-specific teardown after each test.""" - raise NotImplementedError( - 'Platform-specific teardown must be implemented in subclass') - - def _OneTimeTeardown(self): - """Performs any platform-specific teardown after all tests.""" - raise NotImplementedError( - 'Platform-specific teardown must be implemented in sublcass') - - def _RunCommand(self, cmd): - """Runs the given cmd list and returns its output. - - Prints the command's output and exits if any error occurs. - - Returns: - A string containing the stdout and stderr of the command. - """ - try: - return subprocess.check_output(cmd, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - logging.error('Failed command output: %s', e.output) - raise e - - def _SetChromeCommandLineFlags(self, flags): - raise NotImplementedError( - 'Command-line flag setting must be implemented in subclass') - def _StoreResults(self, latencies, correlations, url): """Temporarily stores the results of a test. @@ -220,7 +164,7 @@ } def _SaveResultsToFile(self): - if not (self.args.output_dir and os.path.isdir(self.args.output_dir)): + if not (self._args.output_dir and os.path.isdir(self._args.output_dir)): logging.warning('No output directory set, not saving results to file') return @@ -279,6 +223,6 @@ 'charts': charts, } - with file(os.path.join(self.args.output_dir, - self.args.results_file), 'w') as outfile: + with file(os.path.join(self._args.output_dir, + self._args.results_file), 'w') as outfile: json.dump(results, outfile)
diff --git a/chrome/test/vr/perf/vr_perf_test.py b/chrome/test/vr/perf/vr_perf_test.py new file mode 100644 index 0000000..5b10ed4b --- /dev/null +++ b/chrome/test/vr/perf/vr_perf_test.py
@@ -0,0 +1,85 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import subprocess + +class VrPerfTest(object): + """Base class for all non-Telemetry VR perf tests. + + This class is meant to be subclassed for each platform and test type to + be run. + """ + def __init__(self, args): + super(VrPerfTest, self).__init__() + self._args = args + self._test_urls = [] + + def RunTests(self): + """Runs some test on all the URLs provided to the test on creation. + + Repeatedly runs the steps to start Chrome, measure/store metrics, and + clean up before storing all results to a single file for dashboard + uploading. + """ + try: + self._OneTimeSetup() + for url in self._test_urls: + try: + self._Setup(url) + self._Run(url) + finally: + # We always want to perform teardown even if an exception gets raised. + self._Teardown() + self._SaveResultsToFile() + finally: + self._OneTimeTeardown() + + def _OneTimeSetup(self): + """Performs any platform-specific setup once before any tests.""" + raise NotImplementedError( + 'Platform-specific setup must be implemented in subclass') + + def _Setup(self, url): + """Performs any platform-specific setup before each test.""" + raise NotImplementedError( + 'Platform-specific setup must be implemented in subclass') + + def _Run(self, url): + """Performs the actual test.""" + raise NotImplementedError('Test must be implemented in subclass') + + def _Teardown(self): + """Performs any platform-specific teardown after each test.""" + raise NotImplementedError( + 'Platform-specific teardown must be implemented in subclass') + + def _OneTimeTeardown(self): + """Performs any platform-specific teardown after all tests.""" + raise NotImplementedError( + 'Platform-specific teardown must be implemented in subclass') + + def _RunCommand(self, cmd): + """Runs the given cmd list and returns its output. + + Prints the command's output and exits if any error occurs. + + Returns: + A string containing the stdout and stderr of the command. + """ + try: + return subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + logging.error('Failed command output: %s', e.output) + raise e + + def _SetChromeCommandLineFlags(self, flags): + """Sets the commandline flags that Chrome reads on startup.""" + raise NotImplementedError( + 'Command-line flag setting must be implemented in subclass') + + def _SaveResultsToFile(): + """Saves test results to a Chrome perf dashboard-compatible JSON file.""" + raise NotImplementedError( + 'Result saving must be implemented in subclass') +
diff --git a/chrome/test/vr/perf/vrcore_fps/__init__.py b/chrome/test/vr/perf/vrcore_fps/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/test/vr/perf/vrcore_fps/__init__.py
diff --git a/chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py b/chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py new file mode 100644 index 0000000..b17bb48 --- /dev/null +++ b/chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py
@@ -0,0 +1,86 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Script for automatically measuring FPS for VR via VrCore perf logging. + +Android only. +VrCore has a developer option to log performance data to logcat. This test +visits various WebVR URLs and collects the FPS data reported by VrCore. +""" + +# Needs to be imported first in order to add the parent directory to path. +import vrcore_fps_test_config +import vrcore_fps_test + +import argparse +import logging +import os + +DEFAULT_ADB_PATH = os.path.realpath('../../third_party/android_tools/sdk/' + 'platform-tools/adb') +DEFAULT_DURATION_SECONDS = 30 +DEFAULT_RESULTS_FILE = 'results-chart.json' + + +# TODO(bsheedy): Move common arg parsing code to shared file. +def GetParsedArgs(): + """Parses the command line arguments passed to the script. + + Fails if any unknown arguments are present. + + Returns: + An object containing all known, parsed arguments. + """ + parser = argparse.ArgumentParser() + parser.add_argument('--adb-path', + type=os.path.realpath, + help='The absolute path to adb', + default=DEFAULT_ADB_PATH) + parser.add_argument('--duration', + default=DEFAULT_DURATION_SECONDS, + type=int, + help='The duration spent collecting data from each URL') + parser.add_argument('--output-dir', + type=os.path.realpath, + help='The directory where the script\'s output files ' + 'will be saved') + parser.add_argument('--results-file', + default=DEFAULT_RESULTS_FILE, + help='The name of the JSON file the results will be ' + 'saved to') + parser.add_argument('--url', + action='append', + default=[], + dest='urls', + help='The URL of a WebVR app to use. Defaults to a ' + 'set of URLs with various CPU and GPU loads') + parser.add_argument('-v', '--verbose', + dest='verbose_count', default=0, action='count', + help='Verbose level (multiple times for more)') + (args, unknown_args) = parser.parse_known_args() + SetLogLevel(args.verbose_count) + if unknown_args: + parser.error('Received unknown arguments: %s' % ' '.join(unknown_args)) + return args + + +def SetLogLevel(verbose_count): + """Sets the log level based on the command line arguments.""" + log_level = logging.WARNING + if verbose_count == 1: + log_level = logging.INFO + elif verbose_count >= 2: + log_level = logging.DEBUG + logger = logging.getLogger() + logger.setLevel(log_level) + + +def main(): + args = GetParsedArgs() + test = vrcore_fps_test.VrCoreFpsTest(args) + test.RunTests() + + +if __name__ == '__main__': + main()
diff --git a/chrome/test/vr/perf/vrcore_fps/vr_perf_summary.py b/chrome/test/vr/perf/vrcore_fps/vr_perf_summary.py new file mode 100644 index 0000000..02880dc3 --- /dev/null +++ b/chrome/test/vr/perf/vrcore_fps/vr_perf_summary.py
@@ -0,0 +1,186 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Parses logcat output for VrCore performance logs and computes stats. + +Can be used either as a standalone manual script or as part of the automated +VR performance tests. + +For manual use, simply pipe logcat output into the script. +""" + +import logging +import math +import sys + +LINE_SESSION_START = 'PerfMon: Start of session' +LINE_SESSION_END = 'PerfMon: End of session' + +LINE_ASYNC_FPS = 'Async reprojection thread FPS: ' +LINE_APP_FPS = 'Application FPS: ' +LINE_BLOCKED_FRAME = 'Application frame submits blocked on GPU in FPS window: ' +LINE_MISSED_VSYNC = 'Async reprojection thread missed vsync (late by ' + +APP_FPS_KEY ='app_fps_data' +ASYNC_FPS_KEY = 'async_fps_data' +ASYNC_MISSED_KEY = 'asymc_missed_data' +BLOCKED_SUBMISSION_KEY = 'blocked_submission_key' + +def CalculateAverage(inputs): + return sum(inputs) / len(inputs) + +# Implement own standard deviation function instead of using numpy so that +# script has no dependencies on third-party libraries. +def CalculateStandardDeviation(inputs): + average = sum(inputs) / len(inputs) + sum_of_squares = 0 + for element in inputs: + sum_of_squares += math.pow(element - average, 2) + sum_of_squares /= len(inputs) + return math.sqrt(sum_of_squares) + +def GetInputFromStdin(): + """Turns stdin input into a single string. + + Returns: + A single string containing all lines input via Stdin + """ + print 'Waiting for stdin input.' + lines = [] + while True: + try: + line = sys.stdin.readline() + except KeyboardInterrupt: + break + if not line: + break + lines.append(line) + + return '\n'.join(lines) + +def ParseLinesIntoSessions(lines): + """Parses a string for VR performance logs. + + lines: A string containing lines of logcat output. + + Returns: + A list of strings, where each element contains all the lines of interest + for a single session + """ + logging_sessions = [] + lines_of_interest = [LINE_ASYNC_FPS, LINE_APP_FPS, LINE_BLOCKED_FRAME, + LINE_MISSED_VSYNC] + for line in lines.split('\n'): + if LINE_SESSION_START in line: + logging_sessions.append("") + elif LINE_SESSION_END in line: + continue + for loi in lines_of_interest: + if loi in line: + logging_sessions[-1] += (line + "\n") + break + return logging_sessions + +def ComputeSessionStatistics(session): + """Extracts raw statistical data from a session string. + + session: A string containing all the performance logging lines from + a single VR session + + Returns: + A dictionary containing the raw statistics + """ + app_fps_data = [] + async_fps_data = [] + async_missed_data = [] + blocked_submission_data = [] + + for line in session.split("\n"): + if LINE_ASYNC_FPS in line: # Async thread FPS. + async_fps_data.append( float(line.split(LINE_ASYNC_FPS)[1]) ) + elif LINE_APP_FPS in line: # Application FPS. + app_fps_data.append( float(line.split(LINE_APP_FPS)[1]) ) + elif LINE_BLOCKED_FRAME in line: # Application frame blocked. + blocked_submission_data.append(int(line.split(LINE_BLOCKED_FRAME)[1])) + elif LINE_MISSED_VSYNC in line: # Async thread missed vsync. + # Convert to milliseconds as well. + async_missed_data.append( float( + line.split(LINE_MISSED_VSYNC)[1].split("us")[0]) / 1000) + + return { + APP_FPS_KEY: app_fps_data, + ASYNC_FPS_KEY: async_fps_data, + ASYNC_MISSED_KEY: async_missed_data, + BLOCKED_SUBMISSION_KEY: blocked_submission_data, + } + +def StringifySessionStatistics(statistics): + """Turns a raw statistics dictionary into a formatted string. + + statistics: A raw statistics dictionary + + Returns: + A string with min/max/average calculations + """ + app_fps_data = statistics[APP_FPS_KEY] + async_fps_data = statistics[ASYNC_FPS_KEY] + async_missed_data = statistics[ASYNC_MISSED_KEY] + blocked_submission_data = statistics[BLOCKED_SUBMISSION_KEY] + + output = """ + Min application FPS: %(min_app_fps).4f + Max application FPS: %(max_app_fps).4f + Average application FPS: %(avg_app_fps).4f +/- %(std_app_fps).4f + %(blocked)d total application frame submissions blocked on GPU + --- + Min application FPS after first second: %(min_app_fps_after).4f + Max application FPS after first second: %(max_app_fps_after).4f + Average application FPS after first second: %(avg_app_fps_after).4f +/- %(std_app_fps_after).4f + --- + Min async reprojection thread FPS: %(min_async_fps).4f + Max async reprojection thread FPS: %(max_async_fps).4f + Average async reprojection thread FPS: %(avg_async_fps).4f +/- %(std_async_fps).4f + Async reprojection thread missed %(async_missed)d vsyncs + """ % ({ + 'min_app_fps': min(app_fps_data), + 'max_app_fps': max(app_fps_data), + 'avg_app_fps': CalculateAverage(app_fps_data), + 'std_app_fps': CalculateStandardDeviation(app_fps_data), + 'blocked': sum(blocked_submission_data), + 'min_app_fps_after': min(app_fps_data[1:]), + 'max_app_fps_after': max(app_fps_data[1:]), + 'avg_app_fps_after': CalculateAverage(app_fps_data[1:]), + 'std_app_fps_after': CalculateStandardDeviation(app_fps_data[1:]), + 'min_async_fps': min(async_fps_data), + 'max_async_fps': max(async_fps_data), + 'avg_async_fps': CalculateAverage(async_fps_data), + 'std_async_fps': CalculateStandardDeviation(async_fps_data), + 'async_missed': len(async_missed_data)}) + + + if len(async_missed_data) > 0: + output += 'Average vsync miss time: %.4f +/- %.4f ms' % ( + CalculateAverage(async_missed_data), + CalculateStandardDeviation(async_missed_data)) + return output + + +def ComputeAndPrintStatistics(session): + if len(session) == 0: + logging.warning('No data collected for session') + return + logging.warning(StringifySessionStatistics(ComputeSessionStatistics(session))) + + +def main(): + logging_sessions = ParseLinesIntoSessions(GetInputFromStdin()) + logging.warning('Found %d sessions', len(logging_sessions)) + counter = 1 + for session in logging_sessions: + logging.warning('\n#### Session %d ####', counter) + ComputeAndPrintStatistics(session) + counter += 1 + +if __name__ == '__main__': + main()
diff --git a/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test.py b/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test.py new file mode 100644 index 0000000..e73e26c --- /dev/null +++ b/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test.py
@@ -0,0 +1,174 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Visits various WebVR app URLs and records performance metrics from VrCore. +""" + +import android_vr_perf_test +import vr_perf_summary + +import json +import logging +import numpy +import os +import time + +DEFAULT_URLS = [ + # Standard WebVR sample app with no changes. + 'https://webvr.info/samples/test-slow-render.html?' + 'canvasClickPresents=1\&renderScale=1', + # Increased render scale. + 'https://webvr.info/samples/test-slow-render.html?' + 'canvasClickPresents=1\&renderScale=1.5', + # Default render scale, but increased load. + 'https://webvr.info/samples/test-slow-render.html?' + 'canvasClickPresents=1\&' + 'renderScale=1\&heavyGpu=1\&cubeScale=0.2\&workTime=5', + # Further increased load. + 'https://webvr.info/samples/test-slow-render.html?' + 'canvasClickPresents=1\&' + 'renderScale=1\&heavyGpu=1\&cubeScale=0.3\&workTime=10', +] + + +class VrCoreFpsTest(android_vr_perf_test.AndroidVrPerfTest): + def __init__(self, args): + super(VrCoreFpsTest, self).__init__(args) + self._duration = args.duration + assert (self._duration > 0),'Duration must be positive' + self._test_urls = args.urls or DEFAULT_URLS + self._test_results = {} + + def _Run(self, url): + # We're already in VR and logcat is cleared during setup, so wait for + # the test duration. + time.sleep(self._duration) + + # Exit VR so that VrCore stops logging performance data. + self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_BACK']) + time.sleep(1) + + output = self._Adb(['logcat', '-d']) + logging_sessions = vr_perf_summary.ParseLinesIntoSessions(output) + if len(logging_sessions) != 1: + raise RuntimeError('Expected 1 VR session, found %d' % + len(logging_sessions)) + session = logging_sessions[0] + if len(session) == 0: + raise RuntimeError('No data actually collected in logging session') + self._StoreResults(url, vr_perf_summary.ComputeSessionStatistics(session)) + + def _StoreResults(self, url, results): + """Temporarily stores the results of a test. + + Stores the given results in memory to be later retrieved and written to + a file in _SaveResultsToFile once all tests are done. Also logs the raw + data and calculated statistics. + """ + logging.info('\nURL: %s\n' + 'Raw app FPS: %s\n' + 'Raw asynchronous reprojection thread FPS: %s\n' + 'Raw asynchronous reprojection thread missed frames: %s\n' + 'Raw frame submissions blocked on gpu: %s\n' + '%s\n' % + (url, str(results[vr_perf_summary.APP_FPS_KEY]), + str(results[vr_perf_summary.ASYNC_FPS_KEY]), + str(results[vr_perf_summary.ASYNC_MISSED_KEY]), + str(results[vr_perf_summary.BLOCKED_SUBMISSION_KEY]), + vr_perf_summary.StringifySessionStatistics(results))) + self._test_results[url] = results + + def _SaveResultsToFile(self): + if not (self._args.output_dir and os.path.isdir(self._args.output_dir)): + logging.warning('No output directory set, not saving results to file') + return + + # TODO(bsheedy): Move this to a common place so other tests can use it. + def _GenerateTrace(name, improvement_direction, std=None, + value_type=None, units=None, values=None): + return { + 'improvement_direction': improvement_direction, + 'name': name, + 'std': std or 0.0, + 'type': value_type or 'list_of_scalar_values', + 'units': units or '', + 'values': values or [], + } + + def _GenerateBaseChart(name, improvement_direction, std=None, + value_type=None, units=None, values=None): + return {'summary': _GenerateTrace(name, improvement_direction, std=std, + value_type=value_type, units=units, + values=values)} + + registered_charts = {} + def _RegisterChart(name, improvement_direction, value_func, std_func, + results_key, units=None): + registered_charts[self._device_name + name] = { + 'improvement_direction': improvement_direction, + 'value_func': value_func, + 'std_func': std_func, + 'results_key': results_key, + 'units': units or '' + } + + # value/summary functions. + def f_identity(x): return x + def f_min(x): return [min(x)] + def f_max(x): return [max(x)] + # std functions. + def f_zero(x): return 0.0 + def f_numpy(x): return numpy.std(x) + + _RegisterChart('_avg_app_fps', 'up', f_identity, f_numpy, + vr_perf_summary.APP_FPS_KEY, units='FPS') + _RegisterChart('_min_app_fps', 'up', f_min, f_zero, + vr_perf_summary.APP_FPS_KEY, units='FPS') + _RegisterChart('_max_app_fps', 'up', f_max, f_zero, + vr_perf_summary.APP_FPS_KEY, units='FPS') + _RegisterChart('_avg_async_thread_fps', 'up', f_identity, f_numpy, + vr_perf_summary.ASYNC_FPS_KEY, units='FPS') + _RegisterChart('_min_async_thread_fps', 'up', f_min, f_zero, + vr_perf_summary.ASYNC_FPS_KEY, units='FPS') + _RegisterChart('_max_async_thread_fps', 'up', f_max, f_zero, + vr_perf_summary.ASYNC_FPS_KEY, units='FPS') + # Unlike the rest of the data, missed async reprojection thread vsyncs are + # only logged when they happen so it's normal to get an empty list, which + # makes numpy and the perf dashboard unhappy. + _RegisterChart('_avg_async_thread_vsync_miss_time', 'down', + lambda x: x or [0.0], + lambda x: 0.0 if len(x) == 0 else numpy.std(x), + vr_perf_summary.ASYNC_MISSED_KEY, units='ms') + _RegisterChart('_num_async_thread_vsync_misses', 'down', lambda x: [len(x)], + f_zero, vr_perf_summary.ASYNC_MISSED_KEY) + _RegisterChart('_num_blocked_frame_submissions', 'down', lambda x: [sum(x)], + f_zero, vr_perf_summary.BLOCKED_SUBMISSION_KEY) + + charts = {} + # Set up empty summary charts. + for chart, config in registered_charts.iteritems(): + charts[chart] = _GenerateBaseChart(chart, config['improvement_direction'], + units=config['units']) + + # Populate a trace for each URL in each chart. + for url, results in self._test_results.iteritems(): + for chart, config in registered_charts.iteritems(): + result = results[config['results_key']] + charts[chart][url] = ( + _GenerateTrace(chart, config['improvement_direction'], + units=config['units'], + std=config['std_func'](result), + values=config['value_func'](result))) + charts[chart]['summary']['values'].extend(config['value_func'](result)) + + results = { + 'format_version': '1.0', + 'benchmarck_name': 'vrcore_fps', + 'benchmark_description': 'Measures VR FPS using VrCore perf logging', + 'charts': charts, + } + + with file(os.path.join(self._args.output_dir, + self._args.results_file), 'w') as outfile: + json.dump(results, outfile)
diff --git a/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test_config.py b/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test_config.py new file mode 100644 index 0000000..58acb7c --- /dev/null +++ b/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test_config.py
@@ -0,0 +1,10 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import sys + +# Add //chrome/test/vr/perf to system path. +sys.path.append(os.path.join(os.path.dirname(__file__), + os.pardir))
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn index 93f65e7..08cbad2c 100644 --- a/chromecast/BUILD.gn +++ b/chromecast/BUILD.gn
@@ -481,15 +481,6 @@ } if (is_android) { - generate_jni_registration("cast_shell_jni_registration") { - target = ":cast_shell_apk" - output = "$root_gen_dir/chromecast/android/${target_name}.h" - exception_files = [ - "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - ] - } android_assets("cast_shell_apk_assets") { assert(v8_use_external_startup_data)
diff --git a/chromecast/android/BUILD.gn b/chromecast/android/BUILD.gn index 321a3d2..1d29974 100644 --- a/chromecast/android/BUILD.gn +++ b/chromecast/android/BUILD.gn
@@ -27,7 +27,6 @@ deps = [ ":platform_jni_loader", "//base", - "//chromecast:cast_shell_jni_registration", "//chromecast:cast_shell_lib", "//chromecast:chromecast_features", "//chromecast/app",
diff --git a/chromecast/app/android/cast_jni_loader.cc b/chromecast/app/android/cast_jni_loader.cc index 73b829bb..79a32fe 100644 --- a/chromecast/app/android/cast_jni_loader.cc +++ b/chromecast/app/android/cast_jni_loader.cc
@@ -6,7 +6,6 @@ #include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "chromecast/android/cast_jni_registrar.h" -#include "chromecast/android/cast_shell_jni_registration.h" #include "chromecast/android/platform_jni_loader.h" #include "chromecast/app/cast_main_delegate.h" #include "chromecast/browser/android/jni_registrar.h" @@ -43,12 +42,6 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { base::android::InitVM(vm); JNIEnv* env = base::android::AttachCurrentThread(); - if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { - return -1; - } - - // TODO(agrieve): Delete this block, this is a no-op now. - // https://crbug.com/683256. if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || !NativeInit()) { return -1;
diff --git a/components/BUILD.gn b/components/BUILD.gn index c61ae0ad..fb0cac8 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -225,7 +225,6 @@ "//components/subresource_filter/content/renderer:unit_tests", "//components/tracing:unit_tests", "//components/visitedlink/test:unit_tests", - "//components/viz/common:unit_tests", "//components/viz/host:unit_tests", "//components/viz/service:unit_tests", "//components/wallpaper:unit_tests",
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index 2fdc2d87..5e727a3 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -25,16 +25,6 @@ jni_package = "cronet" } -generate_jni_registration("cronet_jni_registration") { - target = ":cronet_sample_apk" - output = "$root_gen_dir/components/cronet/android/${target_name}.h" - exception_files = [ - "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - ] -} - java_cpp_enum("effective_connection_type_java") { sources = [ "//net/nqe/effective_connection_type.h", @@ -175,7 +165,6 @@ deps = [ ":cronet_android_cert_proto", ":cronet_jni_headers", - ":cronet_jni_registration", ":cronet_version_header", "//base", "//base/third_party/dynamic_annotations", @@ -540,9 +529,6 @@ ] include_dirs = [ _cronet_version_header_include_dir ] - - configs -= [ "//build/config/android:hide_all_but_jni_onload" ] - configs += [ "//build/config/android:hide_all_but_jni" ] } android_resources("cronet_test_apk_resources") {
diff --git a/components/cronet/android/cronet_library_loader.cc b/components/cronet/android/cronet_library_loader.cc index b7aa07a..72c416e 100644 --- a/components/cronet/android/cronet_library_loader.cc +++ b/components/cronet/android/cronet_library_loader.cc
@@ -19,7 +19,6 @@ #include "base/message_loop/message_loop.h" #include "base/metrics/statistics_recorder.h" #include "components/cronet/android/cronet_bidirectional_stream_adapter.h" -#include "components/cronet/android/cronet_jni_registration.h" #include "components/cronet/android/cronet_upload_data_stream_adapter.h" #include "components/cronet/android/cronet_url_request_adapter.h" #include "components/cronet/android/cronet_url_request_context_adapter.h" @@ -85,11 +84,6 @@ jint CronetOnLoad(JavaVM* vm, void* reserved) { base::android::InitVM(vm); JNIEnv* env = base::android::AttachCurrentThread(); - if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { - return -1; - } - // TODO(agrieve): Delete this block, this is a no-op now. - // https://crbug.com/683256. if (!RegisterJNI(env) || !NativeInit()) { return -1; }
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc index 5274d9e..c8b2ea2 100644 --- a/components/cronet/android/cronet_url_request_context_adapter.cc +++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -63,6 +63,7 @@ #include "net/nqe/network_quality_estimator_params.h" #include "net/proxy/proxy_config_service_android.h" #include "net/proxy/proxy_service.h" +#include "net/quic/core/quic_versions.h" #include "net/sdch/sdch_owner.h" #include "net/ssl/channel_id_service.h" #include "net/url_request/url_request_context.h" @@ -758,8 +759,9 @@ net::AlternativeService alternative_service( net::kProtoQUIC, "", static_cast<uint16_t>(quic_hint->alternate_port)); - context_->http_server_properties()->SetAlternativeService( - quic_server, alternative_service, base::Time::Max()); + context_->http_server_properties()->SetQuicAlternativeService( + quic_server, alternative_service, base::Time::Max(), + net::QuicVersionVector()); } }
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm index 0154346..be5ee3c 100644 --- a/components/cronet/ios/cronet_environment.mm +++ b/components/cronet/ios/cronet_environment.mm
@@ -41,6 +41,7 @@ #include "net/log/net_log_capture_mode.h" #include "net/log/write_to_file_net_log_observer.h" #include "net/proxy/proxy_service.h" +#include "net/quic/core/quic_versions.h" #include "net/socket/ssl_client_socket.h" #include "net/ssl/channel_id_service.h" #include "net/url_request/http_user_agent_settings.h" @@ -333,13 +334,15 @@ std::unique_ptr<net::HttpServerProperties> http_server_properties( new net::HttpServerPropertiesImpl()); + for (const auto& quic_hint : quic_hints_) { net::AlternativeService alternative_service(net::kProtoQUIC, "", quic_hint.port()); url::SchemeHostPort quic_hint_server("https", quic_hint.host(), quic_hint.port()); - http_server_properties->SetAlternativeService( - quic_hint_server, alternative_service, base::Time::Max()); + http_server_properties->SetQuicAlternativeService( + quic_hint_server, alternative_service, base::Time::Max(), + net::QuicVersionVector()); } context_builder.SetHttpServerProperties(std::move(http_server_properties));
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc index 15e9b94..a9154966 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -1168,12 +1168,6 @@ return false; } -void DataReductionProxyConfig::GetNetworkList( - net::NetworkInterfaceList* interfaces, - int policy) { - net::GetNetworkList(interfaces, policy); -} - const std::vector<base::TimeDelta>& DataReductionProxyConfig::GetLofiAccuracyRecordingIntervals() const { DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h index ec1889f..b53ea782 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -22,7 +22,6 @@ #include "components/previews/core/previews_experiments.h" #include "net/base/net_errors.h" #include "net/base/network_change_notifier.h" -#include "net/base/network_interfaces.h" #include "net/log/net_log_with_source.h" #include "net/nqe/effective_connection_type.h" #include "net/nqe/network_quality_estimator.h" @@ -218,11 +217,6 @@ std::vector<DataReductionProxyServer> GetProxiesForHttp() const; protected: - // Virtualized for mocking. Returns the list of network interfaces in use. - // |interfaces| can be null. - virtual void GetNetworkList(net::NetworkInterfaceList* interfaces, - int policy); - // Virtualized for testing. Returns the list of intervals at which accuracy of // network quality prediction should be recorded. virtual const std::vector<base::TimeDelta>&
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc index ae158e4..ce2beb1 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -53,7 +53,6 @@ network_quality_prohibitively_slow_(false), lofi_accuracy_recording_intervals_set_(false), is_captive_portal_(false) { - network_interfaces_.reset(new net::NetworkInterfaceList()); } TestDataReductionProxyConfig::~TestDataReductionProxyConfig() { @@ -67,13 +66,6 @@ network_quality_estimator); } -void TestDataReductionProxyConfig::GetNetworkList( - net::NetworkInterfaceList* interfaces, - int policy) { - for (size_t i = 0; i < network_interfaces_->size(); ++i) - interfaces->push_back(network_interfaces_->at(i)); -} - void TestDataReductionProxyConfig::ResetParamFlagsForTest() { config_values_ = base::MakeUnique<TestDataReductionProxyParams>(); }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h index 11476d8..5e3b62ca3 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -13,7 +13,6 @@ #include "base/optional.h" #include "base/time/time.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" -#include "net/base/network_interfaces.h" #include "testing/gmock/include/gmock/gmock.h" namespace base { @@ -58,9 +57,6 @@ ~TestDataReductionProxyConfig() override; - void GetNetworkList(net::NetworkInterfaceList* interfaces, - int policy) override; - // Allows tests to reset the params being used for configuration. void ResetParamFlagsForTest(); @@ -80,10 +76,6 @@ bool IsNetworkQualityProhibitivelySlow( const net::NetworkQualityEstimator* network_quality_estimator) override; - net::NetworkInterfaceList* interfaces() { - return network_interfaces_.get(); - } - void SetLofiAccuracyRecordingIntervals( const std::vector<base::TimeDelta>& lofi_accuracy_recording_intervals); @@ -129,8 +121,6 @@ base::Optional<bool> was_data_reduction_proxy_used_; base::Optional<int> proxy_index_; - std::unique_ptr<net::NetworkInterfaceList> network_interfaces_; - bool network_quality_prohibitively_slow_set_; // True if the network quality is slow enough to turn Lo-Fi ON. bool network_quality_prohibitively_slow_;
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc index ea1e1e2..a270ad00 100644 --- a/components/exo/pointer.cc +++ b/components/exo/pointer.cc
@@ -61,14 +61,14 @@ return offset.LengthSquared() < (2 * kLocatedEventEpsilonSquared); } -float GetCaptureScale() { - float capture_scale = 1.0f; +display::ManagedDisplayInfo GetCaptureDisplayInfo() { + display::ManagedDisplayInfo capture_info; for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) { const auto& info = WMHelper::GetInstance()->GetDisplayInfo(display.id()); - if (info.device_scale_factor() > capture_scale) - capture_scale = info.device_scale_factor(); + if (info.device_scale_factor() >= capture_info.device_scale_factor()) + capture_info = info; } - return capture_scale; + return capture_info; } } // namespace @@ -79,7 +79,8 @@ Pointer::Pointer(PointerDelegate* delegate) : delegate_(delegate), cursor_(ui::CursorType::kNull), - capture_scale_(GetCaptureScale()), + capture_scale_(GetCaptureDisplayInfo().device_scale_factor()), + capture_ratio_(GetCaptureDisplayInfo().GetDensityRatio()), cursor_capture_source_id_(base::UnguessableToken::Create()), cursor_capture_weak_ptr_factory_(this) { auto* helper = WMHelper::GetInstance(); @@ -277,7 +278,9 @@ void Pointer::OnDisplayConfigurationChanged() { UpdatePointerSurface(surface_); - capture_scale_ = GetCaptureScale(); + auto info = GetCaptureDisplayInfo(); + capture_scale_ = info.device_scale_factor(); + capture_ratio_ = info.GetDensityRatio(); } //////////////////////////////////////////////////////////////////////////////// @@ -387,12 +390,12 @@ cursor_ = ui::CursorType::kNone; } else { SkBitmap bitmap = cursor_bitmap_; - gfx::Point hotspot = gfx::ScaleToFlooredPoint(hotspot_, capture_scale_); + gfx::Point hotspot = gfx::ScaleToFlooredPoint(hotspot_, capture_ratio_); auto* helper = WMHelper::GetInstance(); const display::Display& display = helper->GetCursorDisplay(); - float scale = helper->GetDisplayInfo(display.id()).device_scale_factor() / - capture_scale_; + float scale = + helper->GetDisplayInfo(display.id()).GetDensityRatio() / capture_ratio_; if (helper->GetCursorSize() == ui::CursorSize::kLarge) scale *= kLargeCursorScale;
diff --git a/components/exo/pointer.h b/components/exo/pointer.h index 6dc1a0b..c64d1af 100644 --- a/components/exo/pointer.h +++ b/components/exo/pointer.h
@@ -111,10 +111,13 @@ // The current cursor. ui::Cursor cursor_; - // Scale at which cursor snapshot is captured. The resulting bitmap is scaled - // on displays whose DSF does not match this scale. + // Scale at which cursor snapshot is captured. float capture_scale_; + // Density ratio of the cursor snapshot. The bitmap is scaled on displays with + // a different ratio. + float capture_ratio_; + // Source used for cursor capture copy output requests. const base::UnguessableToken cursor_capture_source_id_;
diff --git a/components/gcm_driver/crypto/BUILD.gn b/components/gcm_driver/crypto/BUILD.gn index 20d24ee..5ee3c7d 100644 --- a/components/gcm_driver/crypto/BUILD.gn +++ b/components/gcm_driver/crypto/BUILD.gn
@@ -8,6 +8,8 @@ sources = [ "encryption_header_parsers.cc", "encryption_header_parsers.h", + "gcm_decryption_result.cc", + "gcm_decryption_result.h", "gcm_encryption_provider.cc", "gcm_encryption_provider.h", "gcm_key_store.cc",
diff --git a/components/gcm_driver/crypto/gcm_decryption_result.cc b/components/gcm_driver/crypto/gcm_decryption_result.cc new file mode 100644 index 0000000..099e7f5 --- /dev/null +++ b/components/gcm_driver/crypto/gcm_decryption_result.cc
@@ -0,0 +1,39 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/gcm_driver/crypto/gcm_decryption_result.h" + +#include "base/logging.h" + +namespace gcm { + +std::string ToGCMDecryptionResultDetailsString(GCMDecryptionResult result) { + switch (result) { + case GCMDecryptionResult::UNENCRYPTED: + return "Message was not encrypted"; + case GCMDecryptionResult::DECRYPTED_DRAFT_03: + return "Message decrypted (draft 03)"; + case GCMDecryptionResult::DECRYPTED_DRAFT_08: + return "Message decrypted (draft 08)"; + case GCMDecryptionResult::INVALID_ENCRYPTION_HEADER: + return "Invalid format for the Encryption header"; + case GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER: + return "Invalid format for the Crypto-Key header"; + case GCMDecryptionResult::NO_KEYS: + return "There are no associated keys with the subscription"; + case GCMDecryptionResult::INVALID_SHARED_SECRET: + return "The shared secret cannot be derived from the keying material"; + case GCMDecryptionResult::INVALID_PAYLOAD: + return "AES-GCM decryption failed"; + case GCMDecryptionResult::INVALID_BINARY_HEADER: + return "The message's binary header could not be parsed."; + case GCMDecryptionResult::ENUM_SIZE: + break; // deliberate fall-through + } + + NOTREACHED(); + return "(invalid result)"; +} + +} // namespace gcm
diff --git a/components/gcm_driver/crypto/gcm_decryption_result.h b/components/gcm_driver/crypto/gcm_decryption_result.h new file mode 100644 index 0000000..0126a5a6 --- /dev/null +++ b/components/gcm_driver/crypto/gcm_decryption_result.h
@@ -0,0 +1,58 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GCM_DRIVER_CRYPTO_GCM_DECRYPTION_RESULT_H_ +#define COMPONENTS_GCM_DRIVER_CRYPTO_GCM_DECRYPTION_RESULT_H_ + +#include <string> + +namespace gcm { + +// Result of decrypting an incoming message. The values of these reasons must +// not be changed as they are being recorded using UMA. When adding a value, +// please update GCMDecryptionResult in //tools/metrics/histograms/enums.xml. +enum class GCMDecryptionResult { + // The message had not been encrypted by the sender. + UNENCRYPTED = 0, + + // The message had been encrypted by the sender, and could successfully be + // decrypted for the registration it has been received for. The encryption + // scheme used for the message was draft-ietf-webpush-encryption-03. + DECRYPTED_DRAFT_03 = 1, + + // The contents of the Encryption HTTP header could not be parsed. + INVALID_ENCRYPTION_HEADER = 2, + + // The contents of the Crypto-Key HTTP header could not be parsed. + INVALID_CRYPTO_KEY_HEADER = 3, + + // No public/private key-pair was associated with the app_id. + NO_KEYS = 4, + + // The shared secret cannot be derived from the keying material. + INVALID_SHARED_SECRET = 5, + + // The payload could not be decrypted as AES-128-GCM. + INVALID_PAYLOAD = 6, + + // The binary header leading the ciphertext could not be parsed. Only + // applicable to messages encrypted per draft-ietf-webpush-encryption-08. + INVALID_BINARY_HEADER = 7, + + // The message had been encrypted by the sender, and could successfully be + // decrypted for the registration it has been received for. The encryption + // scheme used for the message was draft-ietf-webpush-encryption-08. + DECRYPTED_DRAFT_08 = 8, + + // Should be one more than the otherwise highest value in this enumeration. + ENUM_SIZE = DECRYPTED_DRAFT_08 + 1 +}; + +// Converts the GCMDecryptionResult value to a string that can be used to +// explain the issue on chrome://gcm-internals/. +std::string ToGCMDecryptionResultDetailsString(GCMDecryptionResult result); + +} // namespace gcm + +#endif // COMPONENTS_GCM_DRIVER_CRYPTO_GCM_DECRYPTION_RESULT_H_
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider.cc b/components/gcm_driver/crypto/gcm_encryption_provider.cc index 6a4bdc5f..20f6d8e4 100644 --- a/components/gcm_driver/crypto/gcm_encryption_provider.cc +++ b/components/gcm_driver/crypto/gcm_encryption_provider.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "components/gcm_driver/common/gcm_messages.h" #include "components/gcm_driver/crypto/encryption_header_parsers.h" +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "components/gcm_driver/crypto/gcm_key_store.h" #include "components/gcm_driver/crypto/gcm_message_cryptographer.h" #include "components/gcm_driver/crypto/message_payload_parser.h" @@ -34,33 +35,6 @@ } // namespace -std::string GCMEncryptionProvider::ToDecryptionResultDetailsString( - DecryptionResult result) { - switch (result) { - case DECRYPTION_RESULT_UNENCRYPTED: - return "Message was not encrypted"; - case DECRYPTION_RESULT_DECRYPTED_DRAFT_03: - return "Message decrypted (draft 03)"; - case DECRYPTION_RESULT_DECRYPTED_DRAFT_08: - return "Message decrypted (draft 08)"; - case DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER: - return "Invalid format for the Encryption header"; - case DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER: - return "Invalid format for the Crypto-Key header"; - case DECRYPTION_RESULT_NO_KEYS: - return "There are no associated keys with the subscription"; - case DECRYPTION_RESULT_INVALID_SHARED_SECRET: - return "The shared secret cannot be derived from the keying material"; - case DECRYPTION_RESULT_INVALID_PAYLOAD: - return "AES-GCM decryption failed"; - case DECRYPTION_RESULT_INVALID_BINARY_HEADER: - return "The message's binary header could not be parsed."; - } - - NOTREACHED(); - return "(invalid result)"; -} - GCMEncryptionProvider::GCMEncryptionProvider() : weak_ptr_factory_(this) { } @@ -129,7 +103,7 @@ const MessageCallback& callback) { DCHECK(key_store_); if (!IsEncryptedMessage(message)) { - callback.Run(DECRYPTION_RESULT_UNENCRYPTED, message); + callback.Run(GCMDecryptionResult::UNENCRYPTED, message); return; } @@ -146,7 +120,8 @@ MessagePayloadParser parser(message.raw_data); if (!parser.IsValid()) { DLOG(ERROR) << "Unable to parse the message's binary header"; - callback.Run(DECRYPTION_RESULT_INVALID_BINARY_HEADER, IncomingMessage()); + callback.Run(GCMDecryptionResult::INVALID_BINARY_HEADER, + IncomingMessage()); return; } @@ -170,7 +145,7 @@ encryption_header->second.begin(), encryption_header->second.end()); if (!encryption_header_iterator.GetNext()) { DLOG(ERROR) << "Unable to parse the value of the Encryption header"; - callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER, + callback.Run(GCMDecryptionResult::INVALID_ENCRYPTION_HEADER, IncomingMessage()); return; } @@ -178,7 +153,7 @@ if (encryption_header_iterator.salt().size() != GCMMessageCryptographer::kSaltSize) { DLOG(ERROR) << "Invalid values supplied in the Encryption header"; - callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER, + callback.Run(GCMDecryptionResult::INVALID_ENCRYPTION_HEADER, IncomingMessage()); return; } @@ -190,7 +165,7 @@ crypto_key_header->second.begin(), crypto_key_header->second.end()); if (!crypto_key_header_iterator.GetNext()) { DLOG(ERROR) << "Unable to parse the value of the Crypto-Key header"; - callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, + callback.Run(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER, IncomingMessage()); return; } @@ -219,7 +194,7 @@ if (!valid_crypto_key_header) { DLOG(ERROR) << "Invalid values supplied in the Crypto-Key header"; - callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, + callback.Run(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER, IncomingMessage()); return; } @@ -284,7 +259,7 @@ const std::string& auth_secret) { if (!pair.IsInitialized()) { DLOG(ERROR) << "Unable to retrieve the keys for the incoming message."; - callback.Run(DECRYPTION_RESULT_NO_KEYS, IncomingMessage()); + callback.Run(GCMDecryptionResult::NO_KEYS, IncomingMessage()); return; } @@ -294,7 +269,7 @@ if (!ComputeSharedP256Secret(pair.private_key(), pair.public_key_x509(), public_key, &shared_secret)) { DLOG(ERROR) << "Unable to calculate the shared secret."; - callback.Run(DECRYPTION_RESULT_INVALID_SHARED_SECRET, IncomingMessage()); + callback.Run(GCMDecryptionResult::INVALID_SHARED_SECRET, IncomingMessage()); return; } @@ -306,7 +281,7 @@ auth_secret, salt, ciphertext, record_size, &plaintext)) { DLOG(ERROR) << "Unable to decrypt the incoming data."; - callback.Run(DECRYPTION_RESULT_INVALID_PAYLOAD, IncomingMessage()); + callback.Run(GCMDecryptionResult::INVALID_PAYLOAD, IncomingMessage()); return; } @@ -321,8 +296,8 @@ DCHECK_EQ(0u, decrypted_message.data.size()); callback.Run(version == GCMMessageCryptographer::Version::DRAFT_03 - ? DECRYPTION_RESULT_DECRYPTED_DRAFT_03 - : DECRYPTION_RESULT_DECRYPTED_DRAFT_08, + ? GCMDecryptionResult::DECRYPTED_DRAFT_03 + : GCMDecryptionResult::DECRYPTED_DRAFT_08, decrypted_message); }
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider.h b/components/gcm_driver/crypto/gcm_encryption_provider.h index 65c1c9cc..7d65b17e0 100644 --- a/components/gcm_driver/crypto/gcm_encryption_provider.h +++ b/components/gcm_driver/crypto/gcm_encryption_provider.h
@@ -23,6 +23,7 @@ namespace gcm { +enum class GCMDecryptionResult; class GCMKeyStore; struct IncomingMessage; class KeyPair; @@ -31,44 +32,6 @@ // and decryption of incoming messages. class GCMEncryptionProvider { public: - // Result of decrypting an incoming message. The values of these reasons must - // not be changed, because they are being recorded using UMA. - enum DecryptionResult { - // The message had not been encrypted by the sender. - DECRYPTION_RESULT_UNENCRYPTED = 0, - - // The message had been encrypted by the sender, and could successfully be - // decrypted for the registration it has been received for. The encryption - // scheme used for the message was draft-ietf-webpush-encryption-03. - DECRYPTION_RESULT_DECRYPTED_DRAFT_03 = 1, - - // The contents of the Encryption HTTP header could not be parsed. - DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER = 2, - - // The contents of the Crypto-Key HTTP header could not be parsed. - DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER = 3, - - // No public/private key-pair was associated with the app_id. - DECRYPTION_RESULT_NO_KEYS = 4, - - // The shared secret cannot be derived from the keying material. - DECRYPTION_RESULT_INVALID_SHARED_SECRET = 5, - - // The payload could not be decrypted as AES-128-GCM. - DECRYPTION_RESULT_INVALID_PAYLOAD = 6, - - // The binary header leading the ciphertext could not be parsed. Only - // applicable to messages encrypted per draft-ietf-webpush-encryption-08. - DECRYPTION_RESULT_INVALID_BINARY_HEADER = 7, - - // The message had been encrypted by the sender, and could successfully be - // decrypted for the registration it has been received for. The encryption - // scheme used for the message was draft-ietf-webpush-encryption-08. - DECRYPTION_RESULT_DECRYPTED_DRAFT_08 = 8, - - DECRYPTION_RESULT_LAST = DECRYPTION_RESULT_DECRYPTED_DRAFT_08 - }; - // Callback to be invoked when the public key and auth secret are available. using EncryptionInfoCallback = base::Callback<void(const std::string& p256dh, @@ -77,12 +40,9 @@ // Callback to be invoked when a message may have been decrypted, as indicated // by the |result|. The |message| contains the dispatchable message in success // cases, or will be initialized to an empty, default state for failure. - using MessageCallback = base::Callback<void(DecryptionResult result, + using MessageCallback = base::Callback<void(GCMDecryptionResult result, const IncomingMessage& message)>; - // Converts |result| to a string describing the details of said result. - static std::string ToDecryptionResultDetailsString(DecryptionResult result); - GCMEncryptionProvider(); ~GCMEncryptionProvider();
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc b/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc index 0f0fc0c4..3d18c61f 100644 --- a/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc +++ b/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc
@@ -21,6 +21,7 @@ #include "base/strings/string_util.h" #include "base/test/histogram_tester.h" #include "components/gcm_driver/common/gcm_messages.h" +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "components/gcm_driver/crypto/gcm_key_store.h" #include "components/gcm_driver/crypto/gcm_message_cryptographer.h" #include "components/gcm_driver/crypto/p256_key_util.h" @@ -128,9 +129,7 @@ } // Returns the result of the previous decryption operation. - GCMEncryptionProvider::DecryptionResult decryption_result() { - return decryption_result_; - } + GCMDecryptionResult decryption_result() { return decryption_result_; } // Returns the message resulting from the previous decryption operation. const IncomingMessage& decrypted_message() { return decrypted_message_; } @@ -146,7 +145,7 @@ GCMMessageCryptographer::Version version); private: - void DidDecryptMessage(GCMEncryptionProvider::DecryptionResult result, + void DidDecryptMessage(GCMDecryptionResult result, const IncomingMessage& message) { decryption_result_ = result; decrypted_message_ = message; @@ -158,8 +157,7 @@ std::unique_ptr<GCMEncryptionProvider> encryption_provider_; - GCMEncryptionProvider::DecryptionResult decryption_result_ = - GCMEncryptionProvider::DECRYPTION_RESULT_UNENCRYPTED; + GCMDecryptionResult decryption_result_ = GCMDecryptionResult::UNENCRYPTED; IncomingMessage decrypted_message_; }; @@ -205,7 +203,7 @@ invalid_message.raw_data = "foo"; ASSERT_NO_FATAL_FAILURE(Decrypt(invalid_message)); - EXPECT_EQ(GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER, + EXPECT_EQ(GCMDecryptionResult::INVALID_ENCRYPTION_HEADER, decryption_result()); IncomingMessage valid_message; @@ -214,7 +212,7 @@ valid_message.raw_data = "foo"; ASSERT_NO_FATAL_FAILURE(Decrypt(valid_message)); - EXPECT_NE(GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER, + EXPECT_NE(GCMDecryptionResult::INVALID_ENCRYPTION_HEADER, decryption_result()); } @@ -228,7 +226,7 @@ invalid_message.raw_data = "foo"; ASSERT_NO_FATAL_FAILURE(Decrypt(invalid_message)); - EXPECT_EQ(GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, + EXPECT_EQ(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER, decryption_result()); IncomingMessage valid_message; @@ -237,7 +235,7 @@ valid_message.raw_data = "foo"; ASSERT_NO_FATAL_FAILURE(Decrypt(valid_message)); - EXPECT_NE(GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, + EXPECT_NE(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER, decryption_result()); } @@ -251,7 +249,7 @@ valid_message.raw_data = "foo"; ASSERT_NO_FATAL_FAILURE(Decrypt(valid_message)); - EXPECT_NE(GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, + EXPECT_NE(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER, decryption_result()); } @@ -265,7 +263,7 @@ valid_message.raw_data = "foo"; ASSERT_NO_FATAL_FAILURE(Decrypt(valid_message)); - EXPECT_EQ(GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, + EXPECT_EQ(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER, decryption_result()); } @@ -279,8 +277,7 @@ message.raw_data = "foo"; ASSERT_NO_FATAL_FAILURE(Decrypt(message)); - EXPECT_EQ(GCMEncryptionProvider::DECRYPTION_RESULT_NO_KEYS, - decryption_result()); + EXPECT_EQ(GCMDecryptionResult::NO_KEYS, decryption_result()); std::string public_key, auth_secret; encryption_provider()->GetEncryptionInfo( @@ -295,8 +292,7 @@ ASSERT_GT(auth_secret.size(), 0u); ASSERT_NO_FATAL_FAILURE(Decrypt(message)); - EXPECT_NE(GCMEncryptionProvider::DECRYPTION_RESULT_NO_KEYS, - decryption_result()); + EXPECT_NE(GCMDecryptionResult::NO_KEYS, decryption_result()); } TEST_F(GCMEncryptionProviderTest, VerifiesKeyRemovalGCMRegistration) { @@ -566,8 +562,8 @@ // Decrypt the message, and expect everything to go wonderfully well. ASSERT_NO_FATAL_FAILURE(Decrypt(message)); ASSERT_EQ(version == GCMMessageCryptographer::Version::DRAFT_03 - ? GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_03 - : GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_08, + ? GCMDecryptionResult::DECRYPTED_DRAFT_03 + : GCMDecryptionResult::DECRYPTED_DRAFT_08, decryption_result()); EXPECT_TRUE(decrypted_message().decrypted);
diff --git a/components/gcm_driver/fake_gcm_client.cc b/components/gcm_driver/fake_gcm_client.cc index 2f992c52..38a1688c97 100644 --- a/components/gcm_driver/fake_gcm_client.cc +++ b/components/gcm_driver/fake_gcm_client.cc
@@ -166,9 +166,8 @@ weak_ptr_factory_.GetWeakPtr(), app_id, message)); } -void FakeGCMClient::RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { +void FakeGCMClient::RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) { recorder_.RecordDecryptionFailure(app_id, result); }
diff --git a/components/gcm_driver/fake_gcm_client.h b/components/gcm_driver/fake_gcm_client.h index 0199b3ab7..9abb5f8 100644 --- a/components/gcm_driver/fake_gcm_client.h +++ b/components/gcm_driver/fake_gcm_client.h
@@ -62,8 +62,7 @@ const std::string& receiver_id, const OutgoingMessage& message) override; void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) - override; + GCMDecryptionResult result) override; void SetRecording(bool recording) override; void ClearActivityLogs() override; GCMStatistics GetStatistics() const override;
diff --git a/components/gcm_driver/fake_gcm_driver.cc b/components/gcm_driver/fake_gcm_driver.cc index 9974f92bf..89ceea45 100644 --- a/components/gcm_driver/fake_gcm_driver.cc +++ b/components/gcm_driver/fake_gcm_driver.cc
@@ -86,10 +86,8 @@ const OutgoingMessage& message) { } -void FakeGCMDriver::RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { -} +void FakeGCMDriver::RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) {} void FakeGCMDriver::SetAccountTokens( const std::vector<GCMClient::AccountTokenInfo>& account_tokens) {
diff --git a/components/gcm_driver/fake_gcm_driver.h b/components/gcm_driver/fake_gcm_driver.h index 131802e2..ba1664ec 100644 --- a/components/gcm_driver/fake_gcm_driver.h +++ b/components/gcm_driver/fake_gcm_driver.h
@@ -65,8 +65,7 @@ const std::string& receiver_id, const OutgoingMessage& message) override; void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) - override; + GCMDecryptionResult result) override; private: DISALLOW_COPY_AND_ASSIGN(FakeGCMDriver);
diff --git a/components/gcm_driver/gcm_client.h b/components/gcm_driver/gcm_client.h index 921c414..64cbd56 100644 --- a/components/gcm_driver/gcm_client.h +++ b/components/gcm_driver/gcm_client.h
@@ -14,7 +14,6 @@ #include "base/memory/linked_ptr.h" #include "components/gcm_driver/common/gcm_messages.h" -#include "components/gcm_driver/crypto/gcm_encryption_provider.h" #include "components/gcm_driver/gcm_activity.h" #include "components/gcm_driver/registration_info.h" @@ -33,8 +32,9 @@ namespace gcm { -class Encryptor; struct AccountMapping; +class Encryptor; +enum class GCMDecryptionResult; // Interface that encapsulates the network communications with the Google Cloud // Messaging server. This interface is not supposed to be thread-safe. @@ -288,9 +288,8 @@ const OutgoingMessage& message) = 0; // Records a decryption failure due to |result| for the |app_id|. - virtual void RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) = 0; + virtual void RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) = 0; // Enables or disables internal activity recording. virtual void SetRecording(bool recording) = 0;
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc index 8754ba2..9cd3eb9 100644 --- a/components/gcm_driver/gcm_client_impl.cc +++ b/components/gcm_driver/gcm_client_impl.cc
@@ -24,6 +24,7 @@ #include "base/time/default_clock.h" #include "base/timer/timer.h" #include "components/crx_file/id_util.h" +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "components/gcm_driver/gcm_account_mapper.h" #include "components/gcm_driver/gcm_backoff_policy.h" #include "google_apis/gcm/base/encryptor.h" @@ -1217,9 +1218,8 @@ return std::string(); } -void GCMClientImpl::RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { +void GCMClientImpl::RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) { recorder_.RecordDecryptionFailure(app_id, result); }
diff --git a/components/gcm_driver/gcm_client_impl.h b/components/gcm_driver/gcm_client_impl.h index 62c4d3b..68c9e2e4 100644 --- a/components/gcm_driver/gcm_client_impl.h +++ b/components/gcm_driver/gcm_client_impl.h
@@ -125,8 +125,7 @@ const std::string& receiver_id, const OutgoingMessage& message) override; void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) - override; + GCMDecryptionResult result) override; void SetRecording(bool recording) override; void ClearActivityLogs() override; GCMStatistics GetStatistics() const override;
diff --git a/components/gcm_driver/gcm_driver.cc b/components/gcm_driver/gcm_driver.cc index 0f797f7..c13ae9e 100644 --- a/components/gcm_driver/gcm_driver.cc +++ b/components/gcm_driver/gcm_driver.cc
@@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "components/gcm_driver/gcm_app_handler.h" namespace gcm { @@ -279,17 +280,16 @@ weak_ptr_factory_.GetWeakPtr(), app_id)); } -void GCMDriver::DispatchMessageInternal( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result, - const IncomingMessage& message) { +void GCMDriver::DispatchMessageInternal(const std::string& app_id, + GCMDecryptionResult result, + const IncomingMessage& message) { UMA_HISTOGRAM_ENUMERATION("GCM.Crypto.DecryptMessageResult", result, - GCMEncryptionProvider::DECRYPTION_RESULT_LAST + 1); + GCMDecryptionResult::ENUM_SIZE); switch (result) { - case GCMEncryptionProvider::DECRYPTION_RESULT_UNENCRYPTED: - case GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_03: - case GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_08: { + case GCMDecryptionResult::UNENCRYPTED: + case GCMDecryptionResult::DECRYPTED_DRAFT_03: + case GCMDecryptionResult::DECRYPTED_DRAFT_08: { GCMAppHandler* handler = GetAppHandler(app_id); if (handler) handler->OnMessage(app_id, message); @@ -298,14 +298,16 @@ // chrome://gcm-internals and send a delivery receipt. return; } - case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER: - case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER: - case GCMEncryptionProvider::DECRYPTION_RESULT_NO_KEYS: - case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_SHARED_SECRET: - case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_PAYLOAD: - case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_BINARY_HEADER: + case GCMDecryptionResult::INVALID_ENCRYPTION_HEADER: + case GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER: + case GCMDecryptionResult::NO_KEYS: + case GCMDecryptionResult::INVALID_SHARED_SECRET: + case GCMDecryptionResult::INVALID_PAYLOAD: + case GCMDecryptionResult::INVALID_BINARY_HEADER: RecordDecryptionFailure(app_id, result); return; + case GCMDecryptionResult::ENUM_SIZE: + break; // deliberate fall-through } NOTREACHED();
diff --git a/components/gcm_driver/gcm_driver.h b/components/gcm_driver/gcm_driver.h index 8d671b7d..0bdb150 100644 --- a/components/gcm_driver/gcm_driver.h +++ b/components/gcm_driver/gcm_driver.h
@@ -27,6 +27,7 @@ class GCMAppHandler; class GCMConnectionObserver; +enum class GCMDecryptionResult; struct AccountMapping; // Provides the InstanceID support via GCMDriver. @@ -279,9 +280,8 @@ const OutgoingMessage& message) = 0; // Platform-specific implementation of recording message decryption failures. - virtual void RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) = 0; + virtual void RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) = 0; // Runs the Register callback. void RegisterFinished(const std::string& app_id, @@ -323,7 +323,7 @@ // if |result| indicates that it is safe to do so, or will report a decryption // failure for the |app_id| otherwise. void DispatchMessageInternal(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result, + GCMDecryptionResult result, const IncomingMessage& message); // Called after unregistration completes in order to trigger the pending
diff --git a/components/gcm_driver/gcm_driver_android.cc b/components/gcm_driver/gcm_driver_android.cc index b7230f2..702ac28 100644 --- a/components/gcm_driver/gcm_driver_android.cc +++ b/components/gcm_driver/gcm_driver_android.cc
@@ -267,9 +267,8 @@ NOTIMPLEMENTED(); } -void GCMDriverAndroid::RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { +void GCMDriverAndroid::RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) { recorder_.RecordDecryptionFailure(app_id, result); }
diff --git a/components/gcm_driver/gcm_driver_android.h b/components/gcm_driver/gcm_driver_android.h index fb37f754..7cfcd63 100644 --- a/components/gcm_driver/gcm_driver_android.h +++ b/components/gcm_driver/gcm_driver_android.h
@@ -99,8 +99,7 @@ const std::string& receiver_id, const OutgoingMessage& message) override; void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) - override; + GCMDecryptionResult result) override; private: base::android::ScopedJavaGlobalRef<jobject> java_ref_;
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc index 9c3fa552..67867c3 100644 --- a/components/gcm_driver/gcm_driver_desktop.cc +++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -114,7 +114,7 @@ const std::string& scope); void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result); + GCMDecryptionResult result); // For testing purpose. Can be called from UI thread. Use with care. GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); } @@ -518,7 +518,7 @@ void GCMDriverDesktop::IOWorker::RecordDecryptionFailure( const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { + GCMDecryptionResult result) { DCHECK(io_thread_->RunsTasksInCurrentSequence()); gcm_client_->RecordDecryptionFailure(app_id, result); } @@ -798,9 +798,8 @@ message)); } -void GCMDriverDesktop::RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { +void GCMDriverDesktop::RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) { DCHECK(ui_thread_->RunsTasksInCurrentSequence()); io_thread_->PostTask( FROM_HERE,
diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h index c7568035..90e5d1c 100644 --- a/components/gcm_driver/gcm_driver_desktop.h +++ b/components/gcm_driver/gcm_driver_desktop.h
@@ -17,6 +17,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/tuple.h" +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "components/gcm_driver/gcm_channel_status_syncer.h" #include "components/gcm_driver/gcm_client.h" #include "components/gcm_driver/gcm_connection_observer.h" @@ -38,6 +39,7 @@ class GCMAccountMapper; class GCMAppHandler; class GCMClientFactory; +enum class GCMDecryptionResult; class GCMDelayedTaskController; // GCMDriver implementation for desktop and Chrome OS, using GCMClient. @@ -107,8 +109,7 @@ const std::string& receiver_id, const OutgoingMessage& message) override; void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) - override; + GCMDecryptionResult result) override; // InstanceIDHandler implementation: void GetToken(const std::string& app_id,
diff --git a/components/gcm_driver/gcm_stats_recorder_android.cc b/components/gcm_driver/gcm_stats_recorder_android.cc index fedd7ba..dc3137be 100644 --- a/components/gcm_driver/gcm_stats_recorder_android.cc +++ b/components/gcm_driver/gcm_stats_recorder_android.cc
@@ -4,6 +4,7 @@ #include <stddef.h> +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "components/gcm_driver/gcm_stats_recorder_android.h" namespace gcm { @@ -125,19 +126,16 @@ void GCMStatsRecorderAndroid::RecordDecryptionFailure( const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { - DCHECK_NE(result, GCMEncryptionProvider::DECRYPTION_RESULT_UNENCRYPTED); - DCHECK_NE(result, - GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_03); - DCHECK_NE(result, - GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_08); + GCMDecryptionResult result) { + DCHECK_NE(result, GCMDecryptionResult::UNENCRYPTED); + DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_03); + DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_08); if (!is_recording_) return; DecryptionFailureActivity activity; activity.app_id = app_id; - activity.details = - GCMEncryptionProvider::ToDecryptionResultDetailsString(result); + activity.details = ToGCMDecryptionResultDetailsString(result); decryption_failure_activities_.push_front(activity); if (decryption_failure_activities_.size() > MAX_LOGGED_ACTIVITY_COUNT)
diff --git a/components/gcm_driver/gcm_stats_recorder_android.h b/components/gcm_driver/gcm_stats_recorder_android.h index 64d0575..6a0c79a 100644 --- a/components/gcm_driver/gcm_stats_recorder_android.h +++ b/components/gcm_driver/gcm_stats_recorder_android.h
@@ -9,11 +9,12 @@ #include <string> #include "base/macros.h" -#include "components/gcm_driver/crypto/gcm_encryption_provider.h" #include "components/gcm_driver/gcm_activity.h" namespace gcm { +enum class GCMDecryptionResult; + // Stats recorder for Android, used for recording stats and activities on the // GCM Driver level for debugging purposes. Based on the GCMStatsRecorder, as // defined in the GCM Engine, which does not exist on Android. @@ -62,7 +63,7 @@ // Records a message decryption failure caused by |result| for |app_id|. void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result); + GCMDecryptionResult result); bool is_recording() const { return is_recording_; } void set_is_recording(bool recording) { is_recording_ = recording; }
diff --git a/components/gcm_driver/gcm_stats_recorder_android_unittest.cc b/components/gcm_driver/gcm_stats_recorder_android_unittest.cc index e7b3267..d789e769 100644 --- a/components/gcm_driver/gcm_stats_recorder_android_unittest.cc +++ b/components/gcm_driver/gcm_stats_recorder_android_unittest.cc
@@ -6,7 +6,7 @@ #include <stddef.h> -#include "components/gcm_driver/crypto/gcm_encryption_provider.h" +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "testing/gtest/include/gtest/gtest.h" namespace gcm { @@ -58,8 +58,8 @@ 42 /* message_byte_size */); EXPECT_EQ(5u, activity_recorded_calls()); - recorder.RecordDecryptionFailure( - kTestAppId, GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_PAYLOAD); + recorder.RecordDecryptionFailure(kTestAppId, + GCMDecryptionResult::INVALID_PAYLOAD); EXPECT_EQ(6u, activity_recorded_calls()); RecordedActivities activities;
diff --git a/components/gcm_driver/gcm_stats_recorder_impl.cc b/components/gcm_driver/gcm_stats_recorder_impl.cc index 14544a9..cf511d8 100644 --- a/components/gcm_driver/gcm_stats_recorder_impl.cc +++ b/components/gcm_driver/gcm_stats_recorder_impl.cc
@@ -12,6 +12,8 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "components/gcm_driver/crypto/gcm_decryption_result.h" +#include "components/gcm_driver/crypto/gcm_encryption_provider.h" namespace gcm { @@ -187,14 +189,11 @@ delegate_->OnActivityRecorded(); } -void GCMStatsRecorderImpl::RecordDecryptionFailure( - const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result) { - DCHECK_NE(result, GCMEncryptionProvider::DECRYPTION_RESULT_UNENCRYPTED); - DCHECK_NE(result, - GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_03); - DCHECK_NE(result, - GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED_DRAFT_08); +void GCMStatsRecorderImpl::RecordDecryptionFailure(const std::string& app_id, + GCMDecryptionResult result) { + DCHECK_NE(result, GCMDecryptionResult::UNENCRYPTED); + DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_03); + DCHECK_NE(result, GCMDecryptionResult::DECRYPTED_DRAFT_08); if (!is_recording_) return; @@ -202,8 +201,7 @@ DecryptionFailureActivity* inserted_data = InsertCircularBuffer( &decryption_failure_activities_, data); inserted_data->app_id = app_id; - inserted_data->details = - GCMEncryptionProvider::ToDecryptionResultDetailsString(result); + inserted_data->details = ToGCMDecryptionResultDetailsString(result); NotifyActivityRecorded(); }
diff --git a/components/gcm_driver/gcm_stats_recorder_impl.h b/components/gcm_driver/gcm_stats_recorder_impl.h index a2c46d1f..77af2970 100644 --- a/components/gcm_driver/gcm_stats_recorder_impl.h +++ b/components/gcm_driver/gcm_stats_recorder_impl.h
@@ -13,7 +13,6 @@ #include "base/macros.h" #include "base/time/time.h" -#include "components/gcm_driver/crypto/gcm_encryption_provider.h" #include "components/gcm_driver/gcm_activity.h" #include "google_apis/gcm/engine/connection_factory.h" #include "google_apis/gcm/engine/mcs_client.h" @@ -23,6 +22,8 @@ namespace gcm { +enum class GCMDecryptionResult; + // Records GCM internal stats and activities for debugging purpose. Recording // can be turned on/off by calling set_is_recording(...) function. It is turned // off by default. @@ -41,7 +42,7 @@ // Records a message decryption failure caused by |result| for |app_id|. void RecordDecryptionFailure(const std::string& app_id, - GCMEncryptionProvider::DecryptionResult result); + GCMDecryptionResult result); // GCMStatsRecorder implementation: void RecordCheckinInitiated(uint64_t android_id) override;
diff --git a/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc b/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc index eae8909..a73a78b 100644 --- a/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc +++ b/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc
@@ -10,6 +10,7 @@ #include <string> #include <vector> +#include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "components/gcm_driver/crypto/gcm_encryption_provider.h" #include "google_apis/gcm/engine/mcs_client.h" #include "testing/gtest/include/gtest/gtest.h" @@ -99,8 +100,8 @@ static const char kIncomingSendErrorEvent[] = "Received 'send error' msg"; static const char kIncomingSendErrorDetails[] = ""; -static const GCMEncryptionProvider::DecryptionResult kDecryptionResultFailure = - GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_PAYLOAD; +static const GCMDecryptionResult kDecryptionResultFailure = + GCMDecryptionResult::INVALID_PAYLOAD; } // namespace @@ -301,10 +302,9 @@ const auto& queue = recorder_.decryption_failure_activities(); EXPECT_EQ(kAppId, queue.front().app_id) << remark; - EXPECT_EQ( - GCMEncryptionProvider::ToDecryptionResultDetailsString( - kDecryptionResultFailure), - queue.front().details) << remark; + EXPECT_EQ(ToGCMDecryptionResultDetailsString(kDecryptionResultFailure), + queue.front().details) + << remark; } protected:
diff --git a/components/grpc_support/test/get_stream_engine.cc b/components/grpc_support/test/get_stream_engine.cc index 8385f54..a4dbae0 100644 --- a/components/grpc_support/test/get_stream_engine.cc +++ b/components/grpc_support/test/get_stream_engine.cc
@@ -53,8 +53,9 @@ params->enable_http2 = true; net::AlternativeService alternative_service(net::kProtoQUIC, "", 443); url::SchemeHostPort quic_hint_server("https", kTestServerHost, 443); - server_properties_->SetAlternativeService( - quic_hint_server, alternative_service, base::Time::Max()); + server_properties_->SetQuicAlternativeService( + quic_hint_server, alternative_service, base::Time::Max(), + params->quic_supported_versions); request_context_->set_cert_verifier(mock_cert_verifier_.get()); request_context_->set_host_resolver(host_resolver_.get());
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java index 289c5eee..56ff80a5 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java
@@ -4,6 +4,7 @@ package org.chromium.components.payments; +import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.payments.mojom.WebAppManifestSection; @@ -42,6 +43,7 @@ /** Starts the utility process. */ public void startUtilityProcess() { + ThreadUtils.assertOnUiThread(); assert mNativePaymentManifestParserAndroid == 0; mNativePaymentManifestParserAndroid = nativeCreatePaymentManifestParserAndroid(); nativeStartUtilityProcess(mNativePaymentManifestParserAndroid); @@ -49,6 +51,7 @@ /** Stops the utility process. */ public void stopUtilityProcess() { + ThreadUtils.assertOnUiThread(); assert mNativePaymentManifestParserAndroid != 0; nativeStopUtilityProcess(mNativePaymentManifestParserAndroid); mNativePaymentManifestParserAndroid = 0; @@ -56,6 +59,7 @@ /** @return Whether the utility process is running. */ public boolean isUtilityProcessRunning() { + ThreadUtils.assertOnUiThread(); return mNativePaymentManifestParserAndroid != 0; } @@ -66,6 +70,8 @@ * @param callback The callback to invoke when finished parsing. */ public void parsePaymentMethodManifest(String content, ManifestParseCallback callback) { + ThreadUtils.assertOnUiThread(); + assert mNativePaymentManifestParserAndroid != 0; nativeParsePaymentMethodManifest(mNativePaymentManifestParserAndroid, content, callback); } @@ -76,6 +82,8 @@ * @param callback The callback to invoke when finished parsing. */ public void parseWebAppManifest(String content, ManifestParseCallback callback) { + ThreadUtils.assertOnUiThread(); + assert mNativePaymentManifestParserAndroid != 0; nativeParseWebAppManifest(mNativePaymentManifestParserAndroid, content, callback); }
diff --git a/components/payments/content/android/payment_manifest_parser_android.cc b/components/payments/content/android/payment_manifest_parser_android.cc index 65a3e26..7587d0a 100644 --- a/components/payments/content/android/payment_manifest_parser_android.cc +++ b/components/payments/content/android/payment_manifest_parser_android.cc
@@ -26,7 +26,10 @@ ~ParseCallback() {} // Copies payment method manifest into Java. - void OnPaymentMethodManifestParsed(std::vector<GURL> web_app_manifest_urls) { + void OnPaymentMethodManifestParsed( + const std::vector<GURL>& web_app_manifest_urls, + const std::vector<url::Origin>& unused_supported_origins, + bool unused_all_origins_supported) { DCHECK_GE(100U, web_app_manifest_urls.size()); JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/components/payments/content/payment_manifest_parser_host.cc b/components/payments/content/payment_manifest_parser_host.cc index 0af9a38..aaea07c4 100644 --- a/components/payments/content/payment_manifest_parser_host.cc +++ b/components/payments/content/payment_manifest_parser_host.cc
@@ -17,6 +17,11 @@ #include "url/url_constants.h" namespace payments { +namespace { + +const size_t kMaximumNumberOfItems = 100U; + +} // namespace PaymentManifestParserHost::PaymentManifestParserHost() : callback_counter_(0) {} @@ -37,7 +42,8 @@ const std::string& content, PaymentMethodCallback callback) { if (!mojo_client_) { - std::move(callback).Run(std::vector<GURL>()); + std::move(callback).Run(std::vector<GURL>(), std::vector<url::Origin>(), + false); return; } @@ -72,7 +78,9 @@ void PaymentManifestParserHost::OnPaymentMethodParse( int64_t callback_identifier, - const std::vector<GURL>& web_app_manifest_urls) { + const std::vector<GURL>& web_app_manifest_urls, + const std::vector<url::Origin>& supported_origins, + bool all_origins_supported) { const auto& pending_callback_it = pending_payment_method_callbacks_.find(callback_identifier); if (pending_callback_it == pending_payment_method_callbacks_.end()) { @@ -82,8 +90,8 @@ return; } - const size_t kMaximumNumberOfWebAppUrls = 100U; - if (web_app_manifest_urls.size() > kMaximumNumberOfWebAppUrls) { + if (web_app_manifest_urls.size() > kMaximumNumberOfItems || + supported_origins.size() > kMaximumNumberOfItems) { // If more than 100 items, then something went wrong in the utility // process. Stop the utility process and notify all callbacks. OnUtilityProcessStopped(); @@ -99,12 +107,30 @@ } } + if (all_origins_supported && !supported_origins.empty()) { + // The format of the payment method manifest does not allow for both of + // these conditions to be true. Something went wrong in the utility process. + // Stop the utility process and notify all callbacks. + OnUtilityProcessStopped(); + return; + } + + for (const auto& origin : supported_origins) { + if (!origin.GetURL().is_valid() || origin.scheme() != url::kHttpsScheme) { + // If not a valid origin with HTTPS scheme, then something went wrong in + // the utility process. Stop the utility process and notify all callbacks. + OnUtilityProcessStopped(); + return; + } + } + PaymentMethodCallback callback = std::move(pending_callback_it->second); pending_payment_method_callbacks_.erase(pending_callback_it); // Can trigger synchronous deletion of this object, so can't access any of // the member variables after this block. - std::move(callback).Run(web_app_manifest_urls); + std::move(callback).Run(web_app_manifest_urls, supported_origins, + all_origins_supported); } void PaymentManifestParserHost::OnWebAppParse( @@ -119,8 +145,7 @@ return; } - const size_t kMaximumNumberOfSections = 100U; - if (manifest.size() > kMaximumNumberOfSections) { + if (manifest.size() > kMaximumNumberOfItems) { // If more than 100 items, then something went wrong in the utility // process. Stop the utility process and notify all callbacks. OnUtilityProcessStopped(); @@ -128,8 +153,7 @@ } for (size_t i = 0; i < manifest.size(); ++i) { - const size_t kMaximumNumberOfFingerprints = 100U; - if (manifest[i]->fingerprints.size() > kMaximumNumberOfFingerprints) { + if (manifest[i]->fingerprints.size() > kMaximumNumberOfItems) { // If more than 100 items, then something went wrong in the utility // process. Stop the utility process and notify all callbacks. OnUtilityProcessStopped(); @@ -148,15 +172,16 @@ void PaymentManifestParserHost::OnUtilityProcessStopped() { mojo_client_.reset(); - std::unordered_map<int64_t, PaymentMethodCallback> payment_method_callbacks = + std::map<int64_t, PaymentMethodCallback> payment_method_callbacks = std::move(pending_payment_method_callbacks_); - std::unordered_map<int64_t, WebAppCallback> web_app_callbacks = + std::map<int64_t, WebAppCallback> web_app_callbacks = std::move(pending_web_app_callbacks_); for (auto& callback : payment_method_callbacks) { // Can trigger synchronous deletion of this object, so can't access any of // the member variables after this line. - std::move(callback.second).Run(std::vector<GURL>()); + std::move(callback.second) + .Run(std::vector<GURL>(), std::vector<url::Origin>(), false); } for (auto& callback : web_app_callbacks) {
diff --git a/components/payments/content/payment_manifest_parser_host.h b/components/payments/content/payment_manifest_parser_host.h index eb68875..7d358328 100644 --- a/components/payments/content/payment_manifest_parser_host.h +++ b/components/payments/content/payment_manifest_parser_host.h
@@ -7,14 +7,16 @@ #include <stdint.h> +#include <map> #include <memory> -#include <unordered_map> +#include <string> #include <vector> #include "base/callback_forward.h" #include "base/macros.h" #include "components/payments/mojom/payment_manifest_parser.mojom.h" #include "url/gurl.h" +#include "url/origin.h" namespace content { template <class MojoInterface> @@ -23,12 +25,15 @@ namespace payments { +class PaymentManifestParserHostTest; + // Host of the utility process that parses manifest contents. class PaymentManifestParserHost { public: - // Called on successful parsing of a payment method manifest. The result is a - // move-only vector, which is empty on parse failure. - using PaymentMethodCallback = base::OnceCallback<void(std::vector<GURL>)>; + // Called on successful parsing of a payment method manifest. Parse failure + // results in empty vectors and "false". + using PaymentMethodCallback = base::OnceCallback< + void(const std::vector<GURL>&, const std::vector<url::Origin>&, bool)>; // Called on successful parsing of a web app manifest. The result is a // move-only vector, which is empty on parse failure. using WebAppCallback = @@ -48,8 +53,12 @@ void ParseWebAppManifest(const std::string& content, WebAppCallback callback); private: + friend class PaymentManifestParserHostTest; + void OnPaymentMethodParse(int64_t callback_identifier, - const std::vector<GURL>& web_app_manifest_urls); + const std::vector<GURL>& web_app_manifest_urls, + const std::vector<url::Origin>& supported_origins, + bool all_origins_supported); void OnWebAppParse(int64_t callback_identifier, std::vector<mojom::WebAppManifestSectionPtr> manifest); @@ -60,9 +69,8 @@ mojo_client_; int64_t callback_counter_; - std::unordered_map<int64_t, PaymentMethodCallback> - pending_payment_method_callbacks_; - std::unordered_map<int64_t, WebAppCallback> pending_web_app_callbacks_; + std::map<int64_t, PaymentMethodCallback> pending_payment_method_callbacks_; + std::map<int64_t, WebAppCallback> pending_web_app_callbacks_; DISALLOW_COPY_AND_ASSIGN(PaymentManifestParserHost); };
diff --git a/components/payments/content/utility/fingerprint_parser.cc b/components/payments/content/utility/fingerprint_parser.cc index 594d589..98cb171 100644 --- a/components/payments/content/utility/fingerprint_parser.cc +++ b/components/payments/content/utility/fingerprint_parser.cc
@@ -24,11 +24,17 @@ std::vector<uint8_t> FingerprintStringToByteArray(const std::string& input) { std::vector<uint8_t> output; - if (input.size() != 32 * 3 - 1) + const size_t kLength = 32 * 3 - 1; + if (input.size() != kLength) { + LOG(ERROR) << "Fingerprint \"" << input << "\" should contain exactly " + << kLength << " characters."; return output; + } for (size_t i = 0; i < input.size(); i += 3) { if (i < input.size() - 2 && input[i + 2] != ':') { + LOG(ERROR) << "Bytes in fingerprint \"" << input + << "\" should separated by \":\" characters."; output.clear(); return output; } @@ -36,6 +42,8 @@ char big_end = input[i]; char little_end = input[i + 1]; if (!IsUpperCaseHexDigit(big_end) || !IsUpperCaseHexDigit(little_end)) { + LOG(ERROR) << "Bytes in fingerprint \"" << input + << "\" should be upper case hex digits 0-9 and A-F."; output.clear(); return output; }
diff --git a/components/payments/content/utility/payment_manifest_parser.cc b/components/payments/content/utility/payment_manifest_parser.cc index f3a4aaa..2bdf4b4 100644 --- a/components/payments/content/utility/payment_manifest_parser.cc +++ b/components/payments/content/utility/payment_manifest_parser.cc
@@ -10,6 +10,7 @@ #include <utility> #include "base/json/json_reader.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -19,6 +20,118 @@ #include "url/url_constants.h" namespace payments { +namespace { + +const size_t kMaximumNumberOfEntries = 100U; +const char* const kDefaultApplications = "default_applications"; +const char* const kSupportedOrigins = "supported_origins"; + +// Parses the "default_applications": ["https://some/url"] from |dict| into +// |web_app_manifest_urls|. Returns 'false' for invalid data. +bool ParseDefaultApplications(base::DictionaryValue* dict, + std::vector<GURL>* web_app_manifest_urls) { + DCHECK(dict); + DCHECK(web_app_manifest_urls); + + base::ListValue* list = nullptr; + if (!dict->GetList(kDefaultApplications, &list)) { + LOG(ERROR) << "\"" << kDefaultApplications << "\" must be a list."; + return false; + } + + size_t apps_number = list->GetSize(); + if (apps_number > kMaximumNumberOfEntries) { + LOG(ERROR) << "\"" << kDefaultApplications << "\" must contain at most " + << kMaximumNumberOfEntries << " entries."; + return false; + } + + std::string item; + for (size_t i = 0; i < apps_number; ++i) { + if (!list->GetString(i, &item) && item.empty()) { + LOG(ERROR) << "Each entry in \"" << kDefaultApplications + << "\" must be a string."; + web_app_manifest_urls->clear(); + return false; + } + + GURL url(item); + if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme)) { + LOG(ERROR) << "\"" << item << "\" entry in \"" << kDefaultApplications + << "\" is not a valid URL with HTTPS scheme."; + web_app_manifest_urls->clear(); + return false; + } + + web_app_manifest_urls->push_back(url); + } + + return true; +} + +// Parses the "supported_origins": "*" (or ["https://some.origin"]) from |dict| +// into |supported_origins| and |all_origins_supported|. Returns 'false' for +// invalid data. +bool ParseSupportedOrigins(base::DictionaryValue* dict, + std::vector<url::Origin>* supported_origins, + bool* all_origins_supported) { + DCHECK(dict); + DCHECK(supported_origins); + DCHECK(all_origins_supported); + + *all_origins_supported = false; + + std::string item; + if (dict->GetString(kSupportedOrigins, &item)) { + if (item != "*") { + LOG(ERROR) << "\"" << item << "\" is not a valid value for \"" + << kSupportedOrigins + << "\". Must be either \"*\" or a list of origins."; + return false; + } + + *all_origins_supported = true; + return true; + } + + base::ListValue* list = nullptr; + if (!dict->GetList(kSupportedOrigins, &list)) { + LOG(ERROR) << "\"" << kSupportedOrigins + << "\" must be either \"*\" or a list of origins."; + return false; + } + + size_t supported_origins_number = list->GetSize(); + if (supported_origins_number > kMaximumNumberOfEntries) { + LOG(ERROR) << "\"" << kSupportedOrigins << "\" must contain at most " + << kMaximumNumberOfEntries << " entires."; + return false; + } + + for (size_t i = 0; i < supported_origins_number; ++i) { + if (!list->GetString(i, &item) && item.empty()) { + LOG(ERROR) << "Each entry in \"" << kSupportedOrigins + << "\" must be a string."; + supported_origins->clear(); + return false; + } + + GURL url(item); + if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme) || + url.path() != "/" || url.has_query() || url.has_ref()) { + LOG(ERROR) << "\"" << item << "\" entry in \"" << kSupportedOrigins + << "\" is not a valid origin with HTTPS scheme."; + supported_origins->clear(); + return false; + } + + supported_origins->push_back(url::Origin(url)); + } + + return true; +} + +} // namespace // static void PaymentManifestParser::Create( @@ -29,44 +142,40 @@ } // static -std::vector<GURL> PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - const std::string& input) { - std::vector<GURL> output; +void PaymentManifestParser::ParsePaymentMethodManifestIntoVectors( + const std::string& input, + std::vector<GURL>* web_app_manifest_urls, + std::vector<url::Origin>* supported_origins, + bool* all_origins_supported) { + DCHECK(web_app_manifest_urls); + DCHECK(supported_origins); + DCHECK(all_origins_supported); + + *all_origins_supported = false; + std::unique_ptr<base::Value> value(base::JSONReader::Read(input)); - if (!value) - return output; + if (!value) { + LOG(ERROR) << "Payment method manifest must be in JSON format."; + return; + } std::unique_ptr<base::DictionaryValue> dict = base::DictionaryValue::From(std::move(value)); - if (!dict) - return output; - - base::ListValue* list = nullptr; - if (!dict->GetList("default_applications", &list)) - return output; - - size_t apps_number = list->GetSize(); - const size_t kMaximumNumberOfApps = 100U; - if (apps_number > kMaximumNumberOfApps) - return output; - - std::string item; - for (size_t i = 0; i < apps_number; ++i) { - if (!list->GetString(i, &item) && item.empty()) { - output.clear(); - return output; - } - - GURL url(item); - if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme)) { - output.clear(); - return output; - } - - output.push_back(url); + if (!dict) { + LOG(ERROR) << "Payment method manifest must be a JSON dictionary."; + return; } - return output; + if (dict->HasKey(kDefaultApplications) && + !ParseDefaultApplications(dict.get(), web_app_manifest_urls)) { + return; + } + + if (dict->HasKey(kSupportedOrigins) && + !ParseSupportedOrigins(dict.get(), supported_origins, + all_origins_supported)) { + web_app_manifest_urls->clear(); + } } // static @@ -74,22 +183,29 @@ PaymentManifestParser::ParseWebAppManifestIntoVector(const std::string& input) { std::vector<mojom::WebAppManifestSectionPtr> output; std::unique_ptr<base::Value> value(base::JSONReader::Read(input)); - if (!value) + if (!value) { + LOG(ERROR) << "Web app manifest must be in JSON format."; return output; + } std::unique_ptr<base::DictionaryValue> dict = base::DictionaryValue::From(std::move(value)); - if (!dict) + if (!dict) { + LOG(ERROR) << "Web app manifest must be a JSON dictionary."; return output; + } base::ListValue* list = nullptr; - if (!dict->GetList("related_applications", &list)) + if (!dict->GetList("related_applications", &list)) { + LOG(ERROR) << "\"related_applications\" must be a list."; return output; + } size_t related_applications_size = list->GetSize(); for (size_t i = 0; i < related_applications_size; ++i) { base::DictionaryValue* related_application = nullptr; if (!list->GetDictionary(i, &related_application) || !related_application) { + LOG(ERROR) << "\"related_applications\" must be a list of dictionaries."; output.clear(); return output; } @@ -100,8 +216,10 @@ continue; } - const size_t kMaximumNumberOfRelatedApplications = 100U; - if (output.size() >= kMaximumNumberOfRelatedApplications) { + if (output.size() >= kMaximumNumberOfEntries) { + LOG(ERROR) << "\"related_applications\" must contain at most " + << kMaximumNumberOfEntries + << " entries with \"platform\": \"play\"."; output.clear(); return output; } @@ -112,7 +230,10 @@ if (!related_application->HasKey(kId) || !related_application->HasKey(kMinVersion) || !related_application->HasKey(kFingerprints)) { - output.clear(); + LOG(ERROR) << "Each \"platform\": \"play\" entry in " + "\"related_applications\" must contain \"" + << kId << "\", \"" << kMinVersion << "\", and \"" + << kFingerprints << "\"."; return output; } @@ -122,6 +243,7 @@ if (!related_application->GetString(kId, §ion->id) || section->id.empty() || !base::IsStringASCII(section->id)) { + LOG(ERROR) << "\"" << kId << "\" must be a non-empty ASCII string."; output.clear(); return output; } @@ -130,15 +252,19 @@ if (!related_application->GetString(kMinVersion, &min_version) || min_version.empty() || !base::IsStringASCII(min_version) || !base::StringToInt64(min_version, §ion->min_version)) { + LOG(ERROR) << "\"" << kMinVersion + << "\" must be a string convertible into a number."; output.clear(); return output; } - const size_t kMaximumNumberOfFingerprints = 100U; base::ListValue* fingerprints_list = nullptr; if (!related_application->GetList(kFingerprints, &fingerprints_list) || fingerprints_list->empty() || - fingerprints_list->GetSize() > kMaximumNumberOfFingerprints) { + fingerprints_list->GetSize() > kMaximumNumberOfEntries) { + LOG(ERROR) << "\"" << kFingerprints + << "\" must be a non-empty list of at most " + << kMaximumNumberOfEntries << " items."; output.clear(); return output; } @@ -153,7 +279,11 @@ !fingerprint_dict->GetString("type", &fingerprint_type) || fingerprint_type != "sha256_cert" || !fingerprint_dict->GetString("value", &fingerprint_value) || - fingerprint_value.empty()) { + fingerprint_value.empty() || + !base::IsStringASCII(fingerprint_value)) { + LOG(ERROR) << "Each entry in \"" << kFingerprints + << "\" must be a dictionary with \"type\": " + "\"sha256_cert\" and a non-empty ASCII string \"value\"."; output.clear(); return output; } @@ -181,7 +311,16 @@ void PaymentManifestParser::ParsePaymentMethodManifest( const std::string& content, ParsePaymentMethodManifestCallback callback) { - std::move(callback).Run(ParsePaymentMethodManifestIntoVector(content)); + std::vector<GURL> web_app_manifest_urls; + std::vector<url::Origin> supported_origins; + bool all_origins_supported = false; + + ParsePaymentMethodManifestIntoVectors(content, &web_app_manifest_urls, + &supported_origins, + &all_origins_supported); + + std::move(callback).Run(web_app_manifest_urls, supported_origins, + all_origins_supported); } void PaymentManifestParser::ParseWebAppManifest(
diff --git a/components/payments/content/utility/payment_manifest_parser.h b/components/payments/content/utility/payment_manifest_parser.h index cabdc1592..4b2bc4b3 100644 --- a/components/payments/content/utility/payment_manifest_parser.h +++ b/components/payments/content/utility/payment_manifest_parser.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "components/payments/mojom/payment_manifest_parser.mojom.h" #include "url/gurl.h" +#include "url/origin.h" namespace service_manager { struct BindSourceInfo; @@ -21,11 +22,18 @@ // Parser for payment method manifests and web app manifests. Should be used // only in a sandboxed utility process. // -// Example valid payment method manifest structure: +// Example 1 of valid payment method manifest structure: // // { // "default_applications": ["https://bobpay.com/payment-app.json"], -// "supported_origins": ["https://alicepay.com"] // Not yet parsed or used. +// "supported_origins": ["https://alicepay.com"] +// } +// +// Example 2 of valid payment method manifest structure: +// +// { +// "default_applications": ["https://bobpay.com/payment-app.json"], +// "supported_origins": "*" // } // // Example valid web app manifest structure: @@ -49,8 +57,11 @@ static void Create(const service_manager::BindSourceInfo& source_info, mojom::PaymentManifestParserRequest request); - static std::vector<GURL> ParsePaymentMethodManifestIntoVector( - const std::string& input); + static void ParsePaymentMethodManifestIntoVectors( + const std::string& input, + std::vector<GURL>* web_app_manifest_urls, + std::vector<url::Origin>* supported_origins, + bool* all_origins_supported); // The return value is move-only, so no copying occurs. static std::vector<mojom::WebAppManifestSectionPtr>
diff --git a/components/payments/content/utility/payment_manifest_parser_unittest.cc b/components/payments/content/utility/payment_manifest_parser_unittest.cc index de80499..f1d9391e 100644 --- a/components/payments/content/utility/payment_manifest_parser_unittest.cc +++ b/components/payments/content/utility/payment_manifest_parser_unittest.cc
@@ -11,109 +11,230 @@ // Payment method manifest parsing: +void ExpectUnableToParsePaymentMethodManifest(const std::string& input) { + std::vector<GURL> actual_web_app_urls; + std::vector<url::Origin> actual_supported_origins; + bool actual_all_origins_supported = false; + + PaymentManifestParser::ParsePaymentMethodManifestIntoVectors( + input, &actual_web_app_urls, &actual_supported_origins, + &actual_all_origins_supported); + + EXPECT_TRUE(actual_web_app_urls.empty()); + EXPECT_TRUE(actual_supported_origins.empty()); + EXPECT_FALSE(actual_all_origins_supported); +} + +void ExpectParsedPaymentMethodManifest( + const std::string& input, + const std::vector<GURL>& expected_web_app_urls, + const std::vector<url::Origin>& expected_supported_origins, + bool expected_all_origins_supported) { + std::vector<GURL> actual_web_app_urls; + std::vector<url::Origin> actual_supported_origins; + bool actual_all_origins_supported = false; + + PaymentManifestParser::ParsePaymentMethodManifestIntoVectors( + input, &actual_web_app_urls, &actual_supported_origins, + &actual_all_origins_supported); + + EXPECT_EQ(expected_web_app_urls, actual_web_app_urls); + EXPECT_EQ(expected_supported_origins, actual_supported_origins); + EXPECT_EQ(expected_all_origins_supported, actual_all_origins_supported); +} + TEST(PaymentManifestParserTest, NullPaymentMethodManifestIsMalformed) { - EXPECT_TRUE( - PaymentManifestParser::ParsePaymentMethodManifestIntoVector(std::string()) - .empty()); + ExpectUnableToParsePaymentMethodManifest(std::string()); } TEST(PaymentManifestParserTest, NonJsonPaymentMethodManifestIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "this is not json") - .empty()); + ExpectUnableToParsePaymentMethodManifest("this is not json"); } TEST(PaymentManifestParserTest, StringPaymentMethodManifestIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "\"this is a string\"") - .empty()); + ExpectUnableToParsePaymentMethodManifest("\"this is a string\""); } TEST(PaymentManifestParserTest, EmptyDictionaryPaymentMethodManifestIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector("{}") - .empty()); + ExpectUnableToParsePaymentMethodManifest("{}"); } TEST(PaymentManifestParserTest, NullDefaultApplicationIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": null}") - .empty()); + ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": null}"); } TEST(PaymentManifestParserTest, NumberDefaultApplicationIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": 0}") - .empty()); + ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": 0}"); } TEST(PaymentManifestParserTest, ListOfNumbersDefaultApplicationIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": [0]}") - .empty()); + ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": [0]}"); } TEST(PaymentManifestParserTest, EmptyListOfDefaultApplicationsIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": []}") - .empty()); + ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": []}"); } TEST(PaymentManifestParserTest, ListOfEmptyDefaultApplicationsIsMalformed) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": [\"\"]}") - .empty()); + ExpectUnableToParsePaymentMethodManifest( + "{\"default_applications\": [\"\"]}"); } TEST(PaymentManifestParserTest, DefaultApplicationsShouldNotHaveNulCharacters) { - EXPECT_TRUE( - PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": [\"https://bobpay.com/app\0json\"]}") - .empty()); + ExpectUnableToParsePaymentMethodManifest( + "{\"default_applications\": [\"https://bobpay.com/app\0json\"]}"); } TEST(PaymentManifestParserTest, DefaultApplicationKeyShouldBeLowercase) { - EXPECT_TRUE( - PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"Default_Applications\": [\"https://bobpay.com/app.json\"]}") - .empty()); + ExpectUnableToParsePaymentMethodManifest( + "{\"Default_Applications\": [\"https://bobpay.com/app.json\"]}"); } TEST(PaymentManifestParserTest, DefaultApplicationsShouldBeAbsoluteUrls) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": [" - "\"https://bobpay.com/app.json\"," - "\"app.json\"]}") - .empty()); + ExpectUnableToParsePaymentMethodManifest( + "{\"default_applications\": [" + "\"https://bobpay.com/app.json\"," + "\"app.json\"]}"); } TEST(PaymentManifestParserTest, DefaultApplicationsShouldBeHttps) { - EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": [" - "\"https://bobpay.com/app.json\"," - "\"http://alicepay.com/app.json\"]}") - .empty()); + ExpectUnableToParsePaymentMethodManifest( + "{\"default_applications\": [" + "\"https://bobpay.com/app.json\"," + "\"http://alicepay.com/app.json\"]}"); } -TEST(PaymentManifestParserTest, WellFormedPaymentMethodManifest) { - std::vector<GURL> expected = {GURL("https://bobpay.com/app.json"), - GURL("https://alicepay.com/app.json")}; - EXPECT_EQ(expected, - PaymentManifestParser::ParsePaymentMethodManifestIntoVector( - "{\"default_applications\": [" - "\"https://bobpay.com/app.json\"," - "\"https://alicepay.com/app.json\"]}")); +TEST(PaymentManifestParserTest, NullSupportedOriginsIsMalformed) { + ExpectUnableToParsePaymentMethodManifest("{\"supported_origins\": null}"); +} + +TEST(PaymentManifestParserTest, NumberSupportedOriginsIsMalformed) { + ExpectUnableToParsePaymentMethodManifest("{\"supported_origins\": 0}"); +} + +TEST(PaymentManifestParserTest, EmptyListSupportedOriginsIsMalformed) { + ExpectUnableToParsePaymentMethodManifest("{\"supported_origins\": []}"); +} + +TEST(PaymentManifestParserTest, ListOfNumbersSupportedOriginsIsMalformed) { + ExpectUnableToParsePaymentMethodManifest("{\"supported_origins\": [0]}"); +} + +TEST(PaymentManifestParserTest, ListOfEmptySupportedOriginsIsMalformed) { + ExpectUnableToParsePaymentMethodManifest("{\"supported_origins\": [\"\"]}"); +} + +TEST(PaymentManifestParserTest, SupportedOriginsShouldNotHaveNulCharacters) { + ExpectUnableToParsePaymentMethodManifest( + "{\"supported_origins\": [\"https://bob\0pay.com\"]}"); +} + +TEST(PaymentManifestParserTest, SupportedOriginsShouldBeHttps) { + ExpectUnableToParsePaymentMethodManifest( + "{\"supported_origins\": [\"http://bobpay.com\"]}"); +} + +TEST(PaymentManifestParserTest, SupportedOriginsShouldNotHavePath) { + ExpectUnableToParsePaymentMethodManifest( + "{\"supported_origins\": [\"https://bobpay.com/webpay\"]}"); +} + +TEST(PaymentManifestParserTest, SupportedOriginsShouldNotHaveQuery) { + ExpectUnableToParsePaymentMethodManifest( + "{\"supported_origins\": [\"https://bobpay.com/?action=webpay\"]}"); +} + +TEST(PaymentManifestParserTest, SupportedOriginsShouldNotHaveRef) { + ExpectUnableToParsePaymentMethodManifest( + "{\"supported_origins\": [\"https://bobpay.com/#webpay\"]}"); +} + +TEST(PaymentManifestParserTest, SupportedOriginsShouldBeList) { + ExpectUnableToParsePaymentMethodManifest( + "{\"supported_origins\": \"https://bobpay.com\"}"); +} + +TEST(PaymentManifestParserTest, WellFormedPaymentMethodManifestWithApps) { + ExpectParsedPaymentMethodManifest( + "{\"default_applications\": [" + "\"https://bobpay.com/app.json\"," + "\"https://alicepay.com/app.json\"]}", + {GURL("https://bobpay.com/app.json"), + GURL("https://alicepay.com/app.json")}, + std::vector<url::Origin>(), false); +} + +TEST(PaymentManifestParserTest, + WellFormedPaymentMethodManifestWithAppsAndAllSupportedOrigins) { + ExpectParsedPaymentMethodManifest( + "{\"default_applications\": [\"https://bobpay.com/app.json\", " + "\"https://alicepay.com/app.json\"], \"supported_origins\": \"*\"}", + {GURL("https://bobpay.com/app.json"), + GURL("https://alicepay.com/app.json")}, + std::vector<url::Origin>(), true); +} + +TEST(PaymentManifestParserTest, AllOriginsSupported) { + ExpectParsedPaymentMethodManifest("{\"supported_origins\": \"*\"}", + std::vector<GURL>(), + std::vector<url::Origin>(), true); +} + +TEST(PaymentManifestParserTest, + InvalidDefaultAppsWillPreventParsingSupportedOrigins) { + ExpectUnableToParsePaymentMethodManifest( + "{\"default_applications\": [\"http://bobpay.com/app.json\"], " + "\"supported_origins\": \"*\"}"); +} + +TEST(PaymentManifestParserTest, + InvalidSupportedOriginsWillPreventParsingDefaultApps) { + ExpectUnableToParsePaymentMethodManifest( + "{\"default_applications\": [\"https://bobpay.com/app.json\"], " + "\"supported_origins\": \"+\"}"); +} + +TEST(PaymentManifestParserTest, + WellFormedPaymentMethodManifestWithAppsAndSomeSupportedOrigins) { + ExpectParsedPaymentMethodManifest( + "{\"default_applications\": [\"https://bobpay.com/app.json\", " + "\"https://alicepay.com/app.json\"], \"supported_origins\": " + "[\"https://charliepay.com\", \"https://evepay.com\"]}", + {GURL("https://bobpay.com/app.json"), + GURL("https://alicepay.com/app.json")}, + {url::Origin(GURL("https://charliepay.com")), + url::Origin(GURL("https://evepay.com"))}, + false); +} + +TEST(PaymentManifestParserTest, + WellFormedPaymentMethodManifestWithSomeSupportedOrigins) { + ExpectParsedPaymentMethodManifest( + "{\"supported_origins\": [\"https://charliepay.com\", " + "\"https://evepay.com\"]}", + std::vector<GURL>(), + {url::Origin(GURL("https://charliepay.com")), + url::Origin(GURL("https://evepay.com"))}, + false); +} + +TEST(PaymentManifestParserTest, + WellFormedPaymentMethodManifestWithAllSupportedOrigins) { + ExpectParsedPaymentMethodManifest("{\"supported_origins\": \"*\"}", + std::vector<GURL>(), + std::vector<url::Origin>(), true); } // Web app manifest parsing: -void ExpectUnableToParse(const std::string& input) { +void ExpectUnableToParseWebAppManifest(const std::string& input) { std::vector<mojom::WebAppManifestSectionPtr> actual_output = PaymentManifestParser::ParseWebAppManifestIntoVector(input); EXPECT_TRUE(actual_output.empty()); } -void ExpectParsed( +void ExpectParsedWebAppManifest( const std::string& input, const std::string& expected_id, int64_t expected_min_version, @@ -127,41 +248,41 @@ } TEST(PaymentManifestParserTest, NullContentIsMalformed) { - ExpectUnableToParse(std::string()); + ExpectUnableToParseWebAppManifest(std::string()); } TEST(PaymentManifestParserTest, NonJsonContentIsMalformed) { - ExpectUnableToParse("this is not json"); + ExpectUnableToParseWebAppManifest("this is not json"); } TEST(PaymentManifestParserTest, StringContentIsMalformed) { - ExpectUnableToParse("\"this is a string\""); + ExpectUnableToParseWebAppManifest("\"this is a string\""); } TEST(PaymentManifestParserTest, EmptyDictionaryIsMalformed) { - ExpectUnableToParse("{}"); + ExpectUnableToParseWebAppManifest("{}"); } TEST(PaymentManifestParserTest, NullRelatedApplicationsSectionIsMalformed) { - ExpectUnableToParse("{\"related_applications\": null}"); + ExpectUnableToParseWebAppManifest("{\"related_applications\": null}"); } TEST(PaymentManifestParserTest, NumberRelatedApplicationsectionIsMalformed) { - ExpectUnableToParse("{\"related_applications\": 0}"); + ExpectUnableToParseWebAppManifest("{\"related_applications\": 0}"); } TEST(PaymentManifestParserTest, ListOfNumbersRelatedApplicationsSectionIsMalformed) { - ExpectUnableToParse("{\"related_applications\": [0]}"); + ExpectUnableToParseWebAppManifest("{\"related_applications\": [0]}"); } TEST(PaymentManifestParserTest, ListOfEmptyDictionariesRelatedApplicationsSectionIsMalformed) { - ExpectUnableToParse("{\"related_applications\": [{}]}"); + ExpectUnableToParseWebAppManifest("{\"related_applications\": [{}]}"); } TEST(PaymentManifestParserTest, NoPlayPlatformIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"id\": \"com.bobpay.app\", " @@ -176,7 +297,7 @@ } TEST(PaymentManifestParserTest, NoPackageNameIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -191,7 +312,7 @@ } TEST(PaymentManifestParserTest, NoVersionIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -206,7 +327,7 @@ } TEST(PaymentManifestParserTest, NoFingerprintIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -217,7 +338,7 @@ } TEST(PaymentManifestParserTest, EmptyFingerprintsIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -229,7 +350,7 @@ } TEST(PaymentManifestParserTest, EmptyFingerprintsDictionaryIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -241,7 +362,7 @@ } TEST(PaymentManifestParserTest, NoFingerprintTypeIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -256,7 +377,7 @@ } TEST(PaymentManifestParserTest, NoFingerprintValueIsMalformed) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -270,7 +391,7 @@ } TEST(PaymentManifestParserTest, PlatformShouldNotHaveNullCharacters) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"pl\0ay\", " @@ -286,7 +407,7 @@ } TEST(PaymentManifestParserTest, PackageNameShouldNotHaveNullCharacters) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -302,7 +423,7 @@ } TEST(PaymentManifestParserTest, VersionShouldNotHaveNullCharacters) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -318,7 +439,7 @@ } TEST(PaymentManifestParserTest, FingerprintTypeShouldNotHaveNullCharacters) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -334,7 +455,7 @@ } TEST(PaymentManifestParserTest, FingerprintValueShouldNotHaveNullCharacters) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -351,7 +472,7 @@ } TEST(PaymentManifestParserTest, KeysShouldBeLowerCase) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"Related_applications\": [{" " \"Platform\": \"play\", " @@ -367,7 +488,7 @@ } TEST(PaymentManifestParserTest, FingerprintsShouldBeSha256) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -383,7 +504,7 @@ } TEST(PaymentManifestParserTest, FingerprintBytesShouldBeColonSeparated) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -391,15 +512,15 @@ " \"min_version\": \"1\", " " \"fingerprints\": [{" " \"type\": \"sha256_cert\", " - " \"value\" \"00010203040506070809A0A1A2A3A4A5A6A7A8A9B0B1B2B3B4B5B6" - "B7B8B9C0C1\"" + " \"value\": \"000010020030040050060070080090A00A10A20A30A40A50A60A7" + "0A80A90B00B10B20B30B40B50B60B70B80B90C00C1\"" " }]" " }]" "}"); } TEST(PaymentManifestParserTest, FingerprintBytesShouldBeUpperCase) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -415,7 +536,7 @@ } TEST(PaymentManifestParserTest, FingerprintsShouldContainsThirtyTwoBytes) { - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -428,7 +549,7 @@ " }]" " }]" "}"); - ExpectUnableToParse( + ExpectUnableToParseWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -444,7 +565,7 @@ } TEST(PaymentManifestParserTest, WellFormed) { - ExpectParsed( + ExpectParsedWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", " @@ -464,7 +585,7 @@ } TEST(PaymentManifestParserTest, DuplicateSignaturesWellFormed) { - ExpectParsed( + ExpectParsedWebAppManifest( "{" " \"related_applications\": [{" " \"platform\": \"play\", "
diff --git a/components/payments/mojom/BUILD.gn b/components/payments/mojom/BUILD.gn index 2f529d48..740c592f 100644 --- a/components/payments/mojom/BUILD.gn +++ b/components/payments/mojom/BUILD.gn
@@ -11,5 +11,6 @@ public_deps = [ "//url/mojo:url_mojom_gurl", + "//url/mojo:url_mojom_origin", ] }
diff --git a/components/payments/mojom/payment_manifest_parser.mojom b/components/payments/mojom/payment_manifest_parser.mojom index 96c3d3c..b99828e 100644 --- a/components/payments/mojom/payment_manifest_parser.mojom +++ b/components/payments/mojom/payment_manifest_parser.mojom
@@ -5,6 +5,7 @@ [JavaPackage="org.chromium.payments.mojom"] module payments.mojom; +import "url/mojo/origin.mojom"; import "url/mojo/url.mojom"; struct WebAppManifestSection { @@ -19,7 +20,9 @@ interface PaymentManifestParser { ParsePaymentMethodManifest(string content) - => (array<url.mojom.Url> webAppManifestUrls); + => (array<url.mojom.Url> web_app_manifest_urls, + array<url.mojom.Origin> supported_origins, + bool all_origins_supported); ParseWebAppManifest(string content) => (array<WebAppManifestSection> manifest); };
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn deleted file mode 100644 index e703006..0000000 --- a/components/viz/common/BUILD.gn +++ /dev/null
@@ -1,36 +0,0 @@ -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -source_set("common") { - sources = [ - "server_gpu_memory_buffer_manager.cc", - "server_gpu_memory_buffer_manager.h", - ] - - deps = [ - "//gpu/ipc/client", - "//gpu/ipc/common", - "//services/ui/gpu/interfaces", - ] - - public_deps = [ - "//gpu/command_buffer/client", - "//gpu/ipc/host", - "//ui/gfx", - ] -} - -source_set("unit_tests") { - testonly = true - sources = [ - "server_gpu_memory_buffer_manager_unittest.cc", - ] - - deps = [ - ":common", - "//base/test:test_support", - "//services/ui/gpu/interfaces", - "//testing/gtest", - ] -}
diff --git a/components/viz/common/DEPS b/components/viz/common/DEPS deleted file mode 100644 index f3d7ee5..0000000 --- a/components/viz/common/DEPS +++ /dev/null
@@ -1,9 +0,0 @@ -include_rules = [ - "+services/ui/gpu/interfaces", -] - -specific_include_rules = { - "server_gpu_memory_buffer_manager_unittest\.cc": [ - "+ui/gfx", - ] -}
diff --git a/components/viz/host/BUILD.gn b/components/viz/host/BUILD.gn index 53a3de2a3..e928add 100644 --- a/components/viz/host/BUILD.gn +++ b/components/viz/host/BUILD.gn
@@ -9,6 +9,8 @@ "frame_sink_observer.h", "host_frame_sink_manager.cc", "host_frame_sink_manager.h", + "server_gpu_memory_buffer_manager.cc", + "server_gpu_memory_buffer_manager.h", "viz_host_export.h", ] @@ -16,6 +18,14 @@ "//base", "//cc/ipc:interfaces", "//cc/surfaces", + "//gpu/ipc/client", + "//gpu/ipc/common", + "//services/ui/gpu/interfaces", + ] + + public_deps = [ + "//gpu/command_buffer/client", + "//gpu/ipc/host", ] } @@ -24,15 +34,18 @@ sources = [ "host_frame_sink_manager_unittests.cc", + "server_gpu_memory_buffer_manager_unittest.cc", ] deps = [ + ":host", "//base", "//base/test:test_support", "//cc/ipc:interfaces", "//cc/surfaces", - "//components/viz/host", + "//gpu/ipc/host", "//mojo/public/cpp/bindings", + "//services/ui/gpu/interfaces", "//testing/gmock", "//testing/gtest", ]
diff --git a/components/viz/host/DEPS b/components/viz/host/DEPS index 7245cd4..c4eca43 100644 --- a/components/viz/host/DEPS +++ b/components/viz/host/DEPS
@@ -1,4 +1,11 @@ include_rules = [ "+cc/ipc", "+cc/surfaces", + "+services/ui/gpu/interfaces", ] + +specific_include_rules = { + "server_gpu_memory_buffer_manager_unittest\.cc": [ + "+ui/gfx", + ] +}
diff --git a/components/viz/common/server_gpu_memory_buffer_manager.cc b/components/viz/host/server_gpu_memory_buffer_manager.cc similarity index 98% rename from components/viz/common/server_gpu_memory_buffer_manager.cc rename to components/viz/host/server_gpu_memory_buffer_manager.cc index 8b31b11..460cbf6 100644 --- a/components/viz/common/server_gpu_memory_buffer_manager.cc +++ b/components/viz/host/server_gpu_memory_buffer_manager.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 "components/viz/common/server_gpu_memory_buffer_manager.h" +#include "components/viz/host/server_gpu_memory_buffer_manager.h" #include "base/logging.h" #include "base/threading/sequenced_task_runner_handle.h"
diff --git a/components/viz/common/server_gpu_memory_buffer_manager.h b/components/viz/host/server_gpu_memory_buffer_manager.h similarity index 88% rename from components/viz/common/server_gpu_memory_buffer_manager.h rename to components/viz/host/server_gpu_memory_buffer_manager.h index f546bc7..2ee15b6 100644 --- a/components/viz/common/server_gpu_memory_buffer_manager.h +++ b/components/viz/host/server_gpu_memory_buffer_manager.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 COMPONENTS_VIZ_COMMON_SERVER_GPU_MEMORY_BUFFER_MANAGER_H_ -#define COMPONENTS_VIZ_COMMON_SERVER_GPU_MEMORY_BUFFER_MANAGER_H_ +#ifndef COMPONENTS_VIZ_HOST_SERVER_GPU_MEMORY_BUFFER_MANAGER_H_ +#define COMPONENTS_VIZ_HOST_SERVER_GPU_MEMORY_BUFFER_MANAGER_H_ #include <memory> @@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" #include "base/synchronization/waitable_event.h" +#include "components/viz/host/viz_host_export.h" #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "gpu/ipc/host/gpu_memory_buffer_support.h" @@ -18,7 +19,7 @@ namespace mojom { class GpuService; } -} +} // namespace ui namespace viz { @@ -26,7 +27,8 @@ // from the gpu process over the mojom.GpuService api. // Note that |CreateGpuMemoryBuffer()| can be called on any thread. All the rest // of the functions must be called on the thread this object is created on. -class ServerGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager { +class VIZ_HOST_EXPORT ServerGpuMemoryBufferManager + : public gpu::GpuMemoryBufferManager { public: ServerGpuMemoryBufferManager(ui::mojom::GpuService* gpu_service, int client_id); @@ -81,4 +83,4 @@ } // namespace viz -#endif // COMPONENTS_VIZ_COMMON_SERVER_GPU_MEMORY_BUFFER_MANAGER_H_ +#endif // COMPONENTS_VIZ_HOST_SERVER_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/components/viz/common/server_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc similarity index 98% rename from components/viz/common/server_gpu_memory_buffer_manager_unittest.cc rename to components/viz/host/server_gpu_memory_buffer_manager_unittest.cc index fdf7e3f..5d5e60b2 100644 --- a/components/viz/common/server_gpu_memory_buffer_manager_unittest.cc +++ b/components/viz/host/server_gpu_memory_buffer_manager_unittest.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 "components/viz/common/server_gpu_memory_buffer_manager.h" +#include "components/viz/host/server_gpu_memory_buffer_manager.h" #include "base/test/scoped_task_environment.h" #include "gpu/ipc/host/gpu_memory_buffer_support.h"
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 003339c..3849406 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc
@@ -208,7 +208,6 @@ : WebContentsObserver(web_contents), java_ref_(env, obj), web_contents_(static_cast<WebContentsImpl*>(web_contents)), - page_scale_(1), dpi_scale_(dpi_scale), device_orientation_(0) { GetViewAndroid()->SetLayer(cc::Layer::Create()); @@ -402,10 +401,9 @@ if (obj.is_null() || !GetWindowAndroid()) return; - GetViewAndroid()->set_content_offset(content_offset); - GetViewAndroid()->set_viewport_size(viewport_size); - - page_scale_ = page_scale_factor; + GetViewAndroid()->UpdateFrameInfo({ + viewport_size, page_scale_factor, content_offset, + }); Java_ContentViewCore_updateFrameInfo( env, obj, scroll_offset.x(), scroll_offset.y(), page_scale_factor,
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index cb7e7a4..48c93b14 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h
@@ -343,9 +343,6 @@ // display in the ContentViewCore. WebContentsImpl* web_contents_; - // Page scale factor. - float page_scale_; - // Device scale factor. float dpi_scale_;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 9d0d0d4..5efa919 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -119,6 +119,7 @@ #include "skia/ext/event_tracer_impl.h" #include "skia/ext/skia_memory_dump_provider.h" #include "sql/sql_memory_dump_provider.h" +#include "third_party/boringssl/src/include/openssl/evp.h" #include "ui/base/clipboard/clipboard.h" #include "ui/gfx/switches.h" @@ -874,6 +875,9 @@ RenderProcessHost::SetRunRendererInProcess(true); #endif + EVP_set_buggy_rsa_parser( + base::FeatureList::IsEnabled(features::kBuggyRSAParser)); + return result_code_; }
diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc index 3a00577..6ecc1be4 100644 --- a/content/browser/devtools/devtools_http_handler.cc +++ b/content/browser/devtools/devtools_http_handler.cc
@@ -20,6 +20,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread.h" #include "base/values.h" #include "build/build_config.h" @@ -170,20 +171,18 @@ // Thread and ServerWrapper lifetime management ------------------------------ -void TerminateOnUI(base::Thread* thread, - ServerWrapper* server_wrapper, - DevToolsSocketFactory* socket_factory) { +void TerminateOnUI(std::unique_ptr<base::Thread> thread, + std::unique_ptr<ServerWrapper> server_wrapper, + std::unique_ptr<DevToolsSocketFactory> socket_factory) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (server_wrapper) { - DCHECK(thread); - thread->task_runner()->DeleteSoon(FROM_HERE, server_wrapper); - } - if (socket_factory) { - DCHECK(thread); - thread->task_runner()->DeleteSoon(FROM_HERE, socket_factory); - } + if (server_wrapper) + thread->task_runner()->DeleteSoon(FROM_HERE, std::move(server_wrapper)); + if (socket_factory) + thread->task_runner()->DeleteSoon(FROM_HERE, std::move(socket_factory)); if (thread) { - BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, thread); + base::PostTaskWithTraits( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, + BindOnce([](std::unique_ptr<base::Thread>) {}, std::move(thread))); } } @@ -194,28 +193,33 @@ std::unique_ptr<net::IPEndPoint> ip_address) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (handler && thread && server_wrapper) { - handler->ServerStarted(thread, server_wrapper, socket_factory, - std::move(ip_address)); + handler->ServerStarted( + std::unique_ptr<base::Thread>(thread), + std::unique_ptr<ServerWrapper>(server_wrapper), + std::unique_ptr<DevToolsSocketFactory>(socket_factory), + std::move(ip_address)); } else { - TerminateOnUI(thread, server_wrapper, socket_factory); + TerminateOnUI(std::unique_ptr<base::Thread>(thread), + std::unique_ptr<ServerWrapper>(server_wrapper), + std::unique_ptr<DevToolsSocketFactory>(socket_factory)); } } void StartServerOnHandlerThread( base::WeakPtr<DevToolsHttpHandler> handler, - base::Thread* thread, - DevToolsSocketFactory* socket_factory, + std::unique_ptr<base::Thread> thread, + std::unique_ptr<DevToolsSocketFactory> socket_factory, const base::FilePath& output_directory, const base::FilePath& frontend_dir, bool bundles_resources) { DCHECK(thread->task_runner()->BelongsToCurrentThread()); - ServerWrapper* server_wrapper = nullptr; + std::unique_ptr<ServerWrapper> server_wrapper; std::unique_ptr<net::ServerSocket> server_socket = socket_factory->CreateForHttpServer(); std::unique_ptr<net::IPEndPoint> ip_address(new net::IPEndPoint); if (server_socket) { - server_wrapper = new ServerWrapper(handler, std::move(server_socket), - frontend_dir, bundles_resources); + server_wrapper.reset(new ServerWrapper(handler, std::move(server_socket), + frontend_dir, bundles_resources)); if (!output_directory.empty()) server_wrapper->WriteActivePortToUserProfile(output_directory); @@ -225,34 +229,11 @@ ip_address.reset(); LOG(ERROR) << "Cannot start http server for devtools. Stop devtools."; } - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&ServerStartedOnUI, - handler, - thread, - server_wrapper, - socket_factory, - base::Passed(&ip_address))); -} - -void StartServerOnFile( - base::WeakPtr<DevToolsHttpHandler> handler, - DevToolsSocketFactory* socket_factory, - const base::FilePath& output_directory, - const base::FilePath& frontend_dir, - bool bundles_resources) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - std::unique_ptr<base::Thread> thread( - new base::Thread(kDevToolsHandlerThreadName)); - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; - if (thread->StartWithOptions(options)) { - base::MessageLoop* message_loop = thread->message_loop(); - message_loop->task_runner()->PostTask( - FROM_HERE, - base::Bind(&StartServerOnHandlerThread, handler, - base::Unretained(thread.release()), socket_factory, - output_directory, frontend_dir, bundles_resources)); - } + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::BindOnce(&ServerStartedOnUI, std::move(handler), thread.release(), + server_wrapper.release(), socket_factory.release(), + std::move(ip_address))); } // DevToolsAgentHostClientImpl ----------------------------------------------- @@ -328,7 +309,8 @@ // DevToolsHttpHandler ------------------------------------------------------- DevToolsHttpHandler::~DevToolsHttpHandler() { - TerminateOnUI(thread_, server_wrapper_, socket_factory_); + TerminateOnUI(std::move(thread_), std::move(server_wrapper_), + std::move(socket_factory_)); } static std::string PathWithoutParams(const std::string& path) { @@ -653,9 +635,9 @@ response.SetBody(json_protocol, "application/json; charset=UTF-8"); thread_->task_runner()->PostTask( - FROM_HERE, - base::Bind(&ServerWrapper::SendResponse, - base::Unretained(server_wrapper_), connection_id, response)); + FROM_HERE, base::BindOnce(&ServerWrapper::SendResponse, + base::Unretained(server_wrapper_.get()), + connection_id, response)); } void DevToolsHttpHandler::RespondToJsonList( @@ -695,9 +677,9 @@ DevToolsAgentHost::CreateForBrowser( thread_->task_runner(), base::Bind(&DevToolsSocketFactory::CreateForTethering, - base::Unretained(socket_factory_))); + base::Unretained(socket_factory_.get()))); connection_to_client_[connection_id].reset(new DevToolsAgentHostClientImpl( - thread_->message_loop(), server_wrapper_, connection_id, + thread_->message_loop(), server_wrapper_.get(), connection_id, browser_agent)); AcceptWebSocket(connection_id, request); return; @@ -724,7 +706,7 @@ } connection_to_client_[connection_id].reset(new DevToolsAgentHostClientImpl( - thread_->message_loop(), server_wrapper_, connection_id, agent)); + thread_->message_loop(), server_wrapper_.get(), connection_id, agent)); AcceptWebSocket(connection_id, request); } @@ -750,37 +732,38 @@ const base::FilePath& debug_frontend_dir, const std::string& product_name, const std::string& user_agent) - : thread_(nullptr), - frontend_url_(frontend_url), + : frontend_url_(frontend_url), product_name_(product_name), user_agent_(user_agent), - server_wrapper_(nullptr), delegate_(delegate), - socket_factory_(nullptr), weak_factory_(this) { bool bundles_resources = frontend_url_.empty(); if (frontend_url_.empty()) frontend_url_ = "/devtools/inspector.html"; - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&StartServerOnFile, - weak_factory_.GetWeakPtr(), - socket_factory.release(), - output_directory, - debug_frontend_dir, - bundles_resources)); + std::unique_ptr<base::Thread> thread( + new base::Thread(kDevToolsHandlerThreadName)); + base::Thread::Options options; + options.message_loop_type = base::MessageLoop::TYPE_IO; + if (thread->StartWithOptions(options)) { + base::TaskRunner* task_runner = thread->task_runner().get(); + task_runner->PostTask( + FROM_HERE, base::BindOnce(&StartServerOnHandlerThread, + weak_factory_.GetWeakPtr(), std::move(thread), + std::move(socket_factory), output_directory, + debug_frontend_dir, bundles_resources)); + } } void DevToolsHttpHandler::ServerStarted( - base::Thread* thread, - ServerWrapper* server_wrapper, - DevToolsSocketFactory* socket_factory, + std::unique_ptr<base::Thread> thread, + std::unique_ptr<ServerWrapper> server_wrapper, + std::unique_ptr<DevToolsSocketFactory> socket_factory, std::unique_ptr<net::IPEndPoint> ip_address) { - thread_ = thread; - server_wrapper_ = server_wrapper; - socket_factory_ = socket_factory; - server_ip_address_.swap(ip_address); + thread_ = std::move(thread); + server_wrapper_ = std::move(server_wrapper); + socket_factory_ = std::move(socket_factory); + server_ip_address_ = std::move(ip_address); } void ServerWrapper::WriteActivePortToUserProfile( @@ -824,9 +807,9 @@ response.SetBody(json_value + message, "application/json; charset=UTF-8"); thread_->task_runner()->PostTask( - FROM_HERE, - base::Bind(&ServerWrapper::SendResponse, - base::Unretained(server_wrapper_), connection_id, response)); + FROM_HERE, base::Bind(&ServerWrapper::SendResponse, + base::Unretained(server_wrapper_.get()), + connection_id, response)); } void DevToolsHttpHandler::Send200(int connection_id, @@ -835,17 +818,18 @@ if (!thread_) return; thread_->task_runner()->PostTask( - FROM_HERE, - base::Bind(&ServerWrapper::Send200, base::Unretained(server_wrapper_), - connection_id, data, mime_type)); + FROM_HERE, base::BindOnce(&ServerWrapper::Send200, + base::Unretained(server_wrapper_.get()), + connection_id, data, mime_type)); } void DevToolsHttpHandler::Send404(int connection_id) { if (!thread_) return; thread_->task_runner()->PostTask( - FROM_HERE, base::Bind(&ServerWrapper::Send404, - base::Unretained(server_wrapper_), connection_id)); + FROM_HERE, + base::BindOnce(&ServerWrapper::Send404, + base::Unretained(server_wrapper_.get()), connection_id)); } void DevToolsHttpHandler::Send500(int connection_id, @@ -853,9 +837,9 @@ if (!thread_) return; thread_->task_runner()->PostTask( - FROM_HERE, - base::Bind(&ServerWrapper::Send500, base::Unretained(server_wrapper_), - connection_id, message)); + FROM_HERE, base::BindOnce(&ServerWrapper::Send500, + base::Unretained(server_wrapper_.get()), + connection_id, message)); } void DevToolsHttpHandler::AcceptWebSocket( @@ -864,9 +848,9 @@ if (!thread_) return; thread_->task_runner()->PostTask( - FROM_HERE, - base::Bind(&ServerWrapper::AcceptWebSocket, - base::Unretained(server_wrapper_), connection_id, request)); + FROM_HERE, base::BindOnce(&ServerWrapper::AcceptWebSocket, + base::Unretained(server_wrapper_.get()), + connection_id, request)); } std::unique_ptr<base::DictionaryValue> DevToolsHttpHandler::SerializeDescriptor(
diff --git a/content/browser/devtools/devtools_http_handler.h b/content/browser/devtools/devtools_http_handler.h index 72836212..4ef44136 100644 --- a/content/browser/devtools/devtools_http_handler.h +++ b/content/browser/devtools/devtools_http_handler.h
@@ -80,9 +80,9 @@ void OnWebSocketMessage(int connection_id, const std::string& data); void OnClose(int connection_id); - void ServerStarted(base::Thread* thread, - ServerWrapper* server_wrapper, - DevToolsSocketFactory* socket_factory, + void ServerStarted(std::unique_ptr<base::Thread> thread, + std::unique_ptr<ServerWrapper> server_wrapper, + std::unique_ptr<DevToolsSocketFactory> socket_factory, std::unique_ptr<net::IPEndPoint> ip_address); void SendJson(int connection_id, @@ -109,17 +109,17 @@ const std::string& host); // The thread used by the devtools handler to run server socket. - base::Thread* thread_; + std::unique_ptr<base::Thread> thread_; std::string frontend_url_; std::string product_name_; std::string user_agent_; - ServerWrapper* server_wrapper_; + std::unique_ptr<ServerWrapper> server_wrapper_; std::unique_ptr<net::IPEndPoint> server_ip_address_; using ConnectionToClientMap = std::map<int, std::unique_ptr<DevToolsAgentHostClientImpl>>; ConnectionToClientMap connection_to_client_; DevToolsManagerDelegate* delegate_; - DevToolsSocketFactory* socket_factory_; + std::unique_ptr<DevToolsSocketFactory> socket_factory_; base::WeakPtrFactory<DevToolsHttpHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(DevToolsHttpHandler);
diff --git a/content/browser/devtools/devtools_http_handler_unittest.cc b/content/browser/devtools/devtools_http_handler_unittest.cc index a4ad827e..7232833 100644 --- a/content/browser/devtools/devtools_http_handler_unittest.cc +++ b/content/browser/devtools/devtools_http_handler_unittest.cc
@@ -158,10 +158,8 @@ // Our dummy socket factory will post a quit message once the server will // become ready. run_loop.Run(); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) RunAllPendingInMessageLoop(BrowserThread::UI); - RunAllPendingInMessageLoop(BrowserThread::FILE); - } DevToolsAgentHost::StopRemoteDebuggingServer(); // Make sure the handler actually stops. run_loop_2.Run();
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 77970a32..81331a5 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1470,8 +1470,8 @@ UpdateBackgroundColor(is_transparent ? SK_ColorTRANSPARENT : frame_metadata.root_background_color); - view_.set_content_offset(top_content_offset); - view_.set_viewport_size(frame_metadata.scrollable_viewport_size); + view_.UpdateFrameInfo({frame_metadata.scrollable_viewport_size, + frame_metadata.page_scale_factor, top_content_offset}); bool top_changed = !FloatEquals(top_shown_pix, prev_top_shown_pix_); if (top_changed) {
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 62ea43e..7f74100 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -39,6 +39,13 @@ const base::Feature kBrowserSideNavigation{"browser-side-navigation", base::FEATURE_DISABLED_BY_DEFAULT}; +// Toggles whether the buggy RSA parser is used. +// +// TODO(davidben): Remove this after Chrome 61 is released to +// stable. https://crbug.com/735616. +const base::Feature kBuggyRSAParser{"BuggyRSAParser", + base::FEATURE_DISABLED_BY_DEFAULT}; + // If Canvas2D Image Chromium is allowed, this feature controls whether it is // enabled. const base::Feature kCanvas2DImageChromium{"Canvas2DImageChromium",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 6627473..0417803 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -23,6 +23,7 @@ CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources; CONTENT_EXPORT extern const base::Feature kBrotliEncoding; CONTENT_EXPORT extern const base::Feature kBrowserSideNavigation; +CONTENT_EXPORT extern const base::Feature kBuggyRSAParser; CONTENT_EXPORT extern const base::Feature kCanvas2DImageChromium; CONTENT_EXPORT extern const base::Feature kCheckerImaging; CONTENT_EXPORT extern const base::Feature kCompositeOpaqueFixedPosition;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 1cae4a69..1058781 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -173,6 +173,7 @@ #include "third_party/WebKit/public/web/WebScriptController.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "third_party/WebKit/public/web/WebView.h" +#include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/skia/include/core/SkGraphics.h" #include "ui/base/layout.h" #include "ui/base/ui_base_switches.h" @@ -945,6 +946,9 @@ if (!command_line.HasSwitch(switches::kSingleProcess)) base::SequencedWorkerPool::EnableForProcess(); + EVP_set_buggy_rsa_parser( + base::FeatureList::IsEnabled(features::kBuggyRSAParser)); + GetConnector()->BindInterface(mojom::kBrowserServiceName, mojo::MakeRequest(&frame_sink_provider_)); }
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn index eceffc1d..2a0443ee 100644 --- a/content/shell/android/BUILD.gn +++ b/content/shell/android/BUILD.gn
@@ -15,22 +15,10 @@ ] } -generate_jni_registration("content_shell_jni_registration") { - testonly = true - target = ":content_shell_apk" - output = "$root_gen_dir/content/shell/android/${target_name}.h" - exception_files = [ - "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - ] -} - shared_library("libcontent_shell_content_view") { testonly = true deps = [ ":content_shell_jni_headers", - ":content_shell_jni_registration", "//build/config:exe_and_shlib_deps", "//components/crash/content/browser", "//content/shell:content_shell_lib", @@ -38,17 +26,6 @@ "//media", "//skia", ] - - # Explicit dependency required for JNI registration to be able to - # find the native side functions. - if (is_component_build) { - deps += [ - "//device/gamepad", - "//device/generic_sensor", - "//device/sensors", - "//media/midi", - ] - } sources = [ "shell_library_loader.cc", ] @@ -265,7 +242,6 @@ deps = [ ":linker_test_jni_headers", - ":linker_test_jni_registration", "//build/config:exe_and_shlib_deps", "//content/shell:content_shell_lib", @@ -274,17 +250,6 @@ "//skia", "//third_party/re2", ] - - # Explicit dependency required for JNI registration to be able to - # find the native side functions. - if (is_component_build) { - deps += [ - "//device/gamepad", - "//device/generic_sensor", - "//device/sensors", - "//media/midi", - ] - } } generate_jni("linker_test_jni_headers") { @@ -294,18 +259,6 @@ "linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java", ] } - - generate_jni_registration("linker_test_jni_registration") { - testonly = true - target = ":chromium_linker_test_apk__apk" - output = - "$root_gen_dir/content/shell/android/linker_test_apk/${target_name}.h" - exception_files = [ - "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - ] - } } android_library("content_shell_browsertests_java") {
diff --git a/content/shell/android/linker_test_apk/chromium_linker_test_android.cc b/content/shell/android/linker_test_apk/chromium_linker_test_android.cc index 310bb2a..19f9c47 100644 --- a/content/shell/android/linker_test_apk/chromium_linker_test_android.cc +++ b/content/shell/android/linker_test_apk/chromium_linker_test_android.cc
@@ -9,7 +9,6 @@ #include "content/public/app/content_main.h" #include "content/public/browser/android/compositor.h" #include "content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.h" -#include "content/shell/android/linker_test_apk/linker_test_jni_registration.h" #include "content/shell/android/shell_jni_registrar.h" #include "content/shell/app/shell_main_delegate.h" @@ -41,11 +40,6 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { base::android::InitVM(vm); JNIEnv* env = base::android::AttachCurrentThread(); - if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { - return -1; - } - // TODO(agrieve): Delete this block, this is a no-op now. - // https://crbug.com/683256. if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || !NativeInit()) { return -1;
diff --git a/content/shell/android/shell_library_loader.cc b/content/shell/android/shell_library_loader.cc index 8cd2e99..dc88bd67 100644 --- a/content/shell/android/shell_library_loader.cc +++ b/content/shell/android/shell_library_loader.cc
@@ -8,7 +8,6 @@ #include "content/public/app/content_jni_onload.h" #include "content/public/app/content_main.h" #include "content/public/browser/android/compositor.h" -#include "content/shell/android/content_shell_jni_registration.h" #include "content/shell/android/shell_jni_registrar.h" #include "content/shell/app/shell_main_delegate.h" @@ -34,12 +33,6 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { base::android::InitVM(vm); JNIEnv* env = base::android::AttachCurrentThread(); - if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { - return -1; - } - - // TODO(agrieve): Delete this block, this is a no-op now. - // https://crbug.com/683256. if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || !NativeInit()) { return -1;
diff --git a/extensions/common/url_pattern_unittest.cc b/extensions/common/url_pattern_unittest.cc index bd60583..f504a8d8 100644 --- a/extensions/common/url_pattern_unittest.cc +++ b/extensions/common/url_pattern_unittest.cc
@@ -9,6 +9,7 @@ #include <memory> #include "base/macros.h" +#include "extensions/common/constants.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -258,7 +259,7 @@ EXPECT_TRUE(pattern.MatchesScheme("https")); EXPECT_TRUE(pattern.MatchesScheme("file")); EXPECT_TRUE(pattern.MatchesScheme("filesystem")); - EXPECT_TRUE(pattern.MatchesScheme("chrome-extension")); + EXPECT_TRUE(pattern.MatchesScheme(extensions::kExtensionScheme)); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_TRUE(pattern.match_effective_tld()); EXPECT_TRUE(pattern.match_all_urls()); @@ -294,7 +295,7 @@ EXPECT_TRUE(pattern.MatchesScheme("javascript")); EXPECT_TRUE(pattern.MatchesScheme("data")); EXPECT_TRUE(pattern.MatchesScheme("about")); - EXPECT_TRUE(pattern.MatchesScheme("chrome-extension")); + EXPECT_TRUE(pattern.MatchesScheme(extensions::kExtensionScheme)); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_TRUE(pattern.match_effective_tld()); EXPECT_TRUE(pattern.match_all_urls()); @@ -435,7 +436,7 @@ URLPattern pattern(URLPattern::SCHEME_EXTENSION); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("chrome-extension://ftw/*")); - EXPECT_EQ("chrome-extension", pattern.scheme()); + EXPECT_EQ(extensions::kExtensionScheme, pattern.scheme()); EXPECT_EQ("ftw", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls());
diff --git a/ios/chrome/browser/payments/test_payment_request.h b/ios/chrome/browser/payments/test_payment_request.h index abfbca5..1ced6fb 100644 --- a/ios/chrome/browser/payments/test_payment_request.h +++ b/ios/chrome/browser/payments/test_payment_request.h
@@ -28,7 +28,9 @@ // |personal_data_manager| should not be null and should outlive this object. TestPaymentRequest(const web::PaymentRequest& web_payment_request, autofill::PersonalDataManager* personal_data_manager) - : PaymentRequest(web_payment_request, personal_data_manager) {} + : PaymentRequest(web_payment_request, personal_data_manager), + region_data_loader_(nullptr), + profile_comparator_(nullptr) {} ~TestPaymentRequest() override {}
diff --git a/ios/chrome/browser/payments/test_payment_request.mm b/ios/chrome/browser/payments/test_payment_request.mm index 336d45f..be46d8a 100644 --- a/ios/chrome/browser/payments/test_payment_request.mm +++ b/ios/chrome/browser/payments/test_payment_request.mm
@@ -26,9 +26,13 @@ } autofill::RegionDataLoader* TestPaymentRequest::GetRegionDataLoader() { - return region_data_loader_; + if (region_data_loader_) + return region_data_loader_; + return PaymentRequest::GetRegionDataLoader(); } payments::PaymentsProfileComparator* TestPaymentRequest::profile_comparator() { - return profile_comparator_; + if (profile_comparator_) + return profile_comparator_; + return PaymentRequest::profile_comparator(); }
diff --git a/ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm b/ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm index 25c87728..ca00dd30 100644 --- a/ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm +++ b/ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm
@@ -379,6 +379,9 @@ // Test that related text DOM mutation prevents contextual search. TEST_F(ContextualSearchJsTest, TestHighlightRelatedDOMMutationText) { + // TODO(crbug.com/736989): Test failures in GetMutatedNodeCount. + if (base::ios::IsRunningOnIOS11OrLater()) + return; LoadHtml(kHTMLWithRelatedTextMutation); ExecuteJavaScript(@"document.getElementById('test').innerText = 'mutated';"); ASSERT_EQ(1, GetMutatedNodeCount());
diff --git a/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm index 0abd0549..15c77b4 100644 --- a/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm
@@ -9,9 +9,13 @@ #include "base/test/ios/wait_util.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/autofill_type.h" +#include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/test_personal_data_manager.h" -#include "ios/chrome/browser/payments/payment_request.h" +#include "components/autofill/core/browser/test_region_data_loader.h" +#include "components/prefs/pref_service.h" #include "ios/chrome/browser/payments/payment_request_test_util.h" +#include "ios/chrome/browser/payments/test_payment_request.h" #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -27,13 +31,24 @@ protected: PaymentRequestBillingAddressSelectionCoordinatorTest() : autofill_profile1_(autofill::test::GetFullProfile()), - autofill_profile2_(autofill::test::GetFullProfile2()) { - // Add testing profiles to autofill::TestPersonalDataManager. + autofill_profile2_(autofill::test::GetFullProfile2()), + pref_service_(autofill::test::PrefServiceForTesting()) { + personal_data_manager_.SetTestingPrefService(pref_service_.get()); + // Add testing profiles to autofill::TestPersonalDataManager. Make the less + // frequently used one incomplete. + autofill_profile1_.set_use_count(10U); personal_data_manager_.AddTestingProfile(&autofill_profile1_); + autofill_profile2_.set_use_count(5U); + autofill_profile2_.SetInfo( + autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), + base::string16(), "en-US"); personal_data_manager_.AddTestingProfile(&autofill_profile2_); - payment_request_ = base::MakeUnique<PaymentRequest>( + payment_request_ = base::MakeUnique<TestPaymentRequest>( payment_request_test_util::CreateTestWebPaymentRequest(), &personal_data_manager_); + + test_region_data_loader_.set_synchronous_callback(true); + payment_request_->SetRegionDataLoader(&test_region_data_loader_); } void SetUp() override { @@ -46,6 +61,10 @@ [coordinator_ setPaymentRequest:payment_request_.get()]; } + void TearDown() override { + personal_data_manager_.SetTestingPrefService(nullptr); + } + UINavigationController* GetNavigationController() { return navigation_controller_; } @@ -57,8 +76,10 @@ autofill::AutofillProfile autofill_profile1_; autofill::AutofillProfile autofill_profile2_; + std::unique_ptr<PrefService> pref_service_; autofill::TestPersonalDataManager personal_data_manager_; - std::unique_ptr<PaymentRequest> payment_request_; + autofill::TestRegionDataLoader test_region_data_loader_; + std::unique_ptr<TestPaymentRequest> payment_request_; }; // Tests that invoking start and stop on the coordinator presents and dismisses @@ -84,15 +105,20 @@ // Tests that calling the view controller delegate method which notifies the // delegate about selection of a billing address invokes the corresponding -// coordinator delegate method. +// coordinator delegate method, only if the payment method is complete. TEST_F(PaymentRequestBillingAddressSelectionCoordinatorTest, SelectedBillingAddress) { // Mock the coordinator delegate. id delegate = [OCMockObject mockForProtocol:@protocol(BillingAddressSelectionCoordinatorDelegate)]; - autofill::AutofillProfile* profile = payment_request_->billing_profiles()[1]; - [[delegate expect] billingAddressSelectionCoordinator:GetCoordinator() - didSelectBillingAddress:profile]; + [[delegate expect] + billingAddressSelectionCoordinator:GetCoordinator() + didSelectBillingAddress:payment_request_ + ->billing_profiles()[0]]; + [[delegate reject] + billingAddressSelectionCoordinator:GetCoordinator() + didSelectBillingAddress:payment_request_ + ->billing_profiles()[1]]; [GetCoordinator() setDelegate:delegate]; EXPECT_EQ(1u, GetNavigationController().viewControllers.count); @@ -102,13 +128,16 @@ base::test::ios::SpinRunLoopWithMaxDelay(base::TimeDelta::FromSecondsD(1.0)); EXPECT_EQ(2u, GetNavigationController().viewControllers.count); - // Call the controller delegate method. + // Call the controller delegate method for both selectable items. PaymentRequestSelectorViewController* view_controller = base::mac::ObjCCastStrict<PaymentRequestSelectorViewController>( GetNavigationController().visibleViewController); [GetCoordinator() paymentRequestSelectorViewController:view_controller + didSelectItemAtIndex:0]; + // Wait for the coordinator delegate to be notified. + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.5)); + [GetCoordinator() paymentRequestSelectorViewController:view_controller didSelectItemAtIndex:1]; - // Wait for the coordinator delegate to be notified. base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.5));
diff --git a/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm index 3eb3d51..a9c3bdb 100644 --- a/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm
@@ -9,9 +9,13 @@ #include "base/test/ios/wait_util.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/autofill_type.h" +#include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/test_personal_data_manager.h" -#include "ios/chrome/browser/payments/payment_request.h" +#include "components/autofill/core/browser/test_region_data_loader.h" +#include "components/prefs/pref_service.h" #include "ios/chrome/browser/payments/payment_request_test_util.h" +#include "ios/chrome/browser/payments/test_payment_request.h" #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -27,19 +31,36 @@ protected: PaymentRequestShippingAddressSelectionCoordinatorTest() : autofill_profile1_(autofill::test::GetFullProfile()), - autofill_profile2_(autofill::test::GetFullProfile2()) { - // Add testing profiles to autofill::TestPersonalDataManager. + autofill_profile2_(autofill::test::GetFullProfile2()), + pref_service_(autofill::test::PrefServiceForTesting()) { + personal_data_manager_.SetTestingPrefService(pref_service_.get()); + // Add testing profiles to autofill::TestPersonalDataManager. Make the less + // frequently used one incomplete. + autofill_profile1_.set_use_count(10U); personal_data_manager_.AddTestingProfile(&autofill_profile1_); + autofill_profile2_.set_use_count(5U); + autofill_profile2_.SetInfo( + autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), + base::string16(), "en-US"); personal_data_manager_.AddTestingProfile(&autofill_profile2_); - payment_request_ = base::MakeUnique<PaymentRequest>( + payment_request_ = base::MakeUnique<TestPaymentRequest>( payment_request_test_util::CreateTestWebPaymentRequest(), &personal_data_manager_); + + test_region_data_loader_.set_synchronous_callback(true); + payment_request_->SetRegionDataLoader(&test_region_data_loader_); + } + + void TearDown() override { + personal_data_manager_.SetTestingPrefService(nullptr); } autofill::AutofillProfile autofill_profile1_; autofill::AutofillProfile autofill_profile2_; + std::unique_ptr<PrefService> pref_service_; autofill::TestPersonalDataManager personal_data_manager_; - std::unique_ptr<PaymentRequest> payment_request_; + autofill::TestRegionDataLoader test_region_data_loader_; + std::unique_ptr<TestPaymentRequest> payment_request_; }; // Tests that invoking start and stop on the coordinator presents and dismisses @@ -75,7 +96,7 @@ // Tests that calling the view controller delegate method which notifies the // delegate about selection of a shipping address invokes the corresponding -// coordinator delegate method. +// coordinator delegate method, only if the payment method is complete. TEST_F(PaymentRequestShippingAddressSelectionCoordinatorTest, SelectedShippingAddress) { UIViewController* base_view_controller = [[UIViewController alloc] init]; @@ -91,9 +112,14 @@ // Mock the coordinator delegate. id delegate = [OCMockObject mockForProtocol:@protocol(ShippingAddressSelectionCoordinatorDelegate)]; - autofill::AutofillProfile* profile = payment_request_->shipping_profiles()[1]; - [[delegate expect] shippingAddressSelectionCoordinator:coordinator - didSelectShippingAddress:profile]; + [[delegate expect] + shippingAddressSelectionCoordinator:coordinator + didSelectShippingAddress:payment_request_ + ->shipping_profiles()[0]]; + [[delegate reject] + shippingAddressSelectionCoordinator:coordinator + didSelectShippingAddress:payment_request_ + ->shipping_profiles()[1]]; [coordinator setDelegate:delegate]; EXPECT_EQ(1u, navigation_controller.viewControllers.count); @@ -103,13 +129,16 @@ base::test::ios::SpinRunLoopWithMaxDelay(base::TimeDelta::FromSecondsD(1.0)); EXPECT_EQ(2u, navigation_controller.viewControllers.count); - // Call the controller delegate method. + // Call the controller delegate method for both selectable items. PaymentRequestSelectorViewController* view_controller = base::mac::ObjCCastStrict<PaymentRequestSelectorViewController>( navigation_controller.visibleViewController); [coordinator paymentRequestSelectorViewController:view_controller + didSelectItemAtIndex:0]; + // Wait for the coordinator delegate to be notified. + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.5)); + [coordinator paymentRequestSelectorViewController:view_controller didSelectItemAtIndex:1]; - // Wait for the coordinator delegate to be notified. base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.5));
diff --git a/media/audio/audio_system_impl.cc b/media/audio/audio_system_impl.cc index 42d0bb7..87d39a90 100644 --- a/media/audio/audio_system_impl.cc +++ b/media/audio/audio_system_impl.cc
@@ -163,9 +163,17 @@ // TODO(olka): remove this when AudioManager::GetInputStreamParameters() // returns invalid parameters if the device is not found. - if (!audio_manager->HasAudioInputDevices()) - return AudioParameters(); - + if (device_id.compare(AudioDeviceDescription::kLoopbackInputDeviceId) == 0 || + device_id.compare(AudioDeviceDescription::kLoopbackWithMuteDeviceId) == + 0) { + // For system audio capture, we need an output device (namely speaker) + // instead of an input device (namely microphone) to work. + if (!audio_manager->HasAudioOutputDevices()) + return AudioParameters(); + } else { + if (!audio_manager->HasAudioInputDevices()) + return AudioParameters(); + } return audio_manager->GetInputStreamParameters(device_id); }
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index d83849f78..79e561da 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn
@@ -192,6 +192,7 @@ "video/chromeos/camera_device_context.cc", "video/chromeos/camera_device_delegate.cc", "video/chromeos/camera_hal_delegate.cc", + "video/chromeos/camera_hal_dispatcher_impl.cc", "video/chromeos/camera_metadata_utils.cc", "video/chromeos/display_rotation_observer.cc", "video/chromeos/pixel_format_utils.cc", @@ -249,6 +250,7 @@ sources += [ "video/chromeos/camera_device_delegate_unittest.cc", "video/chromeos/camera_hal_delegate_unittest.cc", + "video/chromeos/camera_hal_dispatcher_impl_unittest.cc", "video/chromeos/mock_camera_module.cc", "video/chromeos/mock_video_capture_client.cc", "video/chromeos/stream_buffer_manager_unittest.cc",
diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc index e31963dc..46aaade 100644 --- a/media/capture/video/chromeos/camera_device_delegate_unittest.cc +++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
@@ -126,7 +126,7 @@ hal_delegate_thread_.Start(); camera_hal_delegate_ = new CameraHalDelegate(hal_delegate_thread_.task_runner()); - camera_hal_delegate_->StartForTesting( + camera_hal_delegate_->SetCameraModule( mock_camera_module_.GetInterfacePtrInfo()); ResetCaptureClient();
diff --git a/media/capture/video/chromeos/camera_hal_delegate.cc b/media/capture/video/chromeos/camera_hal_delegate.cc index 6f050c1..b4932c9 100644 --- a/media/capture/video/chromeos/camera_hal_delegate.cc +++ b/media/capture/video/chromeos/camera_hal_delegate.cc
@@ -13,16 +13,10 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/strings/string_piece.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" #include "media/capture/video/chromeos/camera_metadata_utils.h" #include "media/capture/video/chromeos/pixel_format_utils.h" #include "media/capture/video/chromeos/video_capture_device_arc_chromeos.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/incoming_broker_client_invitation.h" -#include "mojo/edk/embedder/named_platform_handle.h" -#include "mojo/edk/embedder/named_platform_handle_utils.h" -#include "mojo/edk/embedder/platform_channel_pair.h" -#include "mojo/edk/embedder/platform_channel_utils_posix.h" -#include "mojo/edk/embedder/platform_handle_vector.h" namespace media { @@ -33,11 +27,29 @@ const base::TimeDelta kEventWaitTimeoutMs = base::TimeDelta::FromMilliseconds(3000); +class LocalCameraClientObserver : public CameraClientObserver { + public: + explicit LocalCameraClientObserver( + scoped_refptr<CameraHalDelegate> camera_hal_delegate) + : camera_hal_delegate_(std::move(camera_hal_delegate)) {} + + void OnChannelCreated(arc::mojom::CameraModulePtr camera_module) override { + camera_hal_delegate_->SetCameraModule(camera_module.PassInterface()); + } + + private: + scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + DISALLOW_IMPLICIT_CONSTRUCTORS(LocalCameraClientObserver); +}; + } // namespace CameraHalDelegate::CameraHalDelegate( scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) - : builtin_camera_info_updated_( + : camera_module_has_been_set_( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED), + builtin_camera_info_updated_( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED), num_builtin_cameras_(0), @@ -48,62 +60,16 @@ CameraHalDelegate::~CameraHalDelegate() {} -bool CameraHalDelegate::StartCameraModuleIpc() { - // Non-blocking socket handle. - mojo::edk::ScopedPlatformHandle socket_handle = mojo::edk::CreateClientHandle( - mojo::edk::NamedPlatformHandle(kArcCamera3SocketPath)); +void CameraHalDelegate::RegisterCameraClient() { + CameraHalDispatcherImpl::GetInstance()->AddClientObserver( + base::MakeUnique<LocalCameraClientObserver>(this)); +} - // Set socket to blocking - int flags = HANDLE_EINTR(fcntl(socket_handle.get().handle, F_GETFL)); - if (flags == -1) { - PLOG(ERROR) << "fcntl(F_GETFL) failed: "; - return false; - } - if (HANDLE_EINTR(fcntl(socket_handle.get().handle, F_SETFL, - flags & ~O_NONBLOCK)) == -1) { - PLOG(ERROR) << "fcntl(F_SETFL) failed: "; - return false; - } - - const size_t kTokenSize = 32; - char token[kTokenSize] = {}; - std::deque<mojo::edk::PlatformHandle> platform_handles; - ssize_t ret = mojo::edk::PlatformChannelRecvmsg( - socket_handle.get(), token, sizeof(token), &platform_handles, true); - if (ret == -1) { - PLOG(ERROR) << "PlatformChannelRecvmsg failed: "; - return false; - } - if (platform_handles.size() != 1) { - LOG(ERROR) << "Unexpected number of handles received, expected 1: " - << platform_handles.size(); - return false; - } - mojo::edk::ScopedPlatformHandle parent_pipe(platform_handles.back()); - platform_handles.pop_back(); - if (!parent_pipe.is_valid()) { - LOG(ERROR) << "Invalid parent pipe"; - return false; - } - std::unique_ptr<mojo::edk::IncomingBrokerClientInvitation> invitation = - mojo::edk::IncomingBrokerClientInvitation::Accept( - mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy, - std::move(parent_pipe))); - mojo::ScopedMessagePipeHandle child_pipe = - invitation->ExtractMessagePipe(token); - if (!child_pipe.is_valid()) { - LOG(ERROR) << "Invalid child pipe"; - return false; - } - - camera_module_ = - mojo::MakeProxy(mojo::InterfacePtrInfo<arc::mojom::CameraModule>( - std::move(child_pipe), 0u), - ipc_task_runner_); - - VLOG(1) << "Camera module IPC connection established"; - - return true; +void CameraHalDelegate::SetCameraModule( + arc::mojom::CameraModulePtrInfo camera_module_ptr_info) { + ipc_task_runner_->PostTask( + FROM_HERE, base::Bind(&CameraHalDelegate::SetCameraModuleOnIpcThread, + this, base::Passed(&camera_module_ptr_info))); } void CameraHalDelegate::Reset() { @@ -233,8 +199,10 @@ void CameraHalDelegate::GetCameraInfo(int32_t camera_id, const GetCameraInfoCallback& callback) { - // This method may be called on any thread. Currently this method is used by - // CameraDeviceDelegate to query camera info. + DCHECK(!ipc_task_runner_->BelongsToCurrentThread()); + // This method may be called on any thread except |ipc_task_runner_|. + // Currently this method is used by CameraDeviceDelegate to query camera info. + camera_module_has_been_set_.Wait(); ipc_task_runner_->PostTask( FROM_HERE, base::Bind(&CameraHalDelegate::GetCameraInfoOnIpcThread, this, camera_id, callback)); @@ -244,16 +212,28 @@ int32_t camera_id, arc::mojom::Camera3DeviceOpsRequest device_ops_request, const OpenDeviceCallback& callback) { - // This method may be called on any thread. Currently this method is used by - // CameraDeviceDelegate to open a camera device. + DCHECK(!ipc_task_runner_->BelongsToCurrentThread()); + // This method may be called on any thread except |ipc_task_runner_|. + // Currently this method is used by CameraDeviceDelegate to open a camera + // device. + camera_module_has_been_set_.Wait(); ipc_task_runner_->PostTask( FROM_HERE, base::Bind(&CameraHalDelegate::OpenDeviceOnIpcThread, this, camera_id, base::Passed(&device_ops_request), callback)); } -void CameraHalDelegate::StartForTesting(arc::mojom::CameraModulePtrInfo info) { - camera_module_.Bind(std::move(info), ipc_task_runner_); +void CameraHalDelegate::SetCameraModuleOnIpcThread( + arc::mojom::CameraModulePtrInfo camera_module_ptr_info) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + if (camera_module_.is_bound()) { + LOG(ERROR) << "CameraModule is already bound"; + return; + } + camera_module_ = mojo::MakeProxy(std::move(camera_module_ptr_info)); + camera_module_.set_connection_error_handler( + base::Bind(&CameraHalDelegate::ResetMojoInterfaceOnIpcThread, this)); + camera_module_has_been_set_.Signal(); } void CameraHalDelegate::ResetMojoInterfaceOnIpcThread() { @@ -262,10 +242,15 @@ if (camera_module_callbacks_.is_bound()) { camera_module_callbacks_.Close(); } + builtin_camera_info_updated_.Reset(); + camera_module_has_been_set_.Reset(); } bool CameraHalDelegate::UpdateBuiltInCameraInfo() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!ipc_task_runner_->BelongsToCurrentThread()); + + camera_module_has_been_set_.Wait(); if (builtin_camera_info_updated_.IsSignaled()) { return true; }
diff --git a/media/capture/video/chromeos/camera_hal_delegate.h b/media/capture/video/chromeos/camera_hal_delegate.h index 15637825..44f10ec 100644 --- a/media/capture/video/chromeos/camera_hal_delegate.h +++ b/media/capture/video/chromeos/camera_hal_delegate.h
@@ -36,9 +36,10 @@ explicit CameraHalDelegate( scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner); - // Establishes the Mojo IPC channel to the camera HAL adapter. This method - // should be called before any other methods of CameraHalDelegate is called. - bool StartCameraModuleIpc(); + // Registers the camera client observer to the CameraHalDispatcher instance. + void RegisterCameraClient(); + + void SetCameraModule(arc::mojom::CameraModulePtrInfo camera_module_ptr_info); // Resets |camera_module_| and |camera_module_callbacks_|. void Reset(); @@ -75,9 +76,8 @@ ~CameraHalDelegate() final; - friend class CameraHalDelegateTest; - friend class CameraDeviceDelegateTest; - void StartForTesting(arc::mojom::CameraModulePtrInfo info); + void SetCameraModuleOnIpcThread( + arc::mojom::CameraModulePtrInfo camera_module_ptr_info); // Resets the Mojo interface and bindings. void ResetMojoInterfaceOnIpcThread(); @@ -112,6 +112,8 @@ int32_t camera_id, arc::mojom::CameraDeviceStatus new_status) final; + base::WaitableEvent camera_module_has_been_set_; + // Signaled when |num_builtin_cameras_| and |camera_info_| are updated. // Queried and waited by UpdateBuiltInCameraInfo, signaled by // OnGotCameraInfoOnIpcThread.
diff --git a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc index 242182bef6..06f4e61 100644 --- a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc +++ b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc
@@ -33,7 +33,7 @@ hal_delegate_thread_.Start(); camera_hal_delegate_ = new CameraHalDelegate(hal_delegate_thread_.task_runner()); - camera_hal_delegate_->StartForTesting( + camera_hal_delegate_->SetCameraModule( mock_camera_module_.GetInterfacePtrInfo()); }
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc new file mode 100644 index 0000000..06bdfb3f --- /dev/null +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -0,0 +1,361 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" + +#include <fcntl.h> +#include <grp.h> +#include <poll.h> +#include <sys/uio.h> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/posix/eintr_wrapper.h" +#include "base/single_thread_task_runner.h" +#include "base/synchronization/waitable_event.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/named_platform_handle.h" +#include "mojo/edk/embedder/named_platform_handle_utils.h" +#include "mojo/edk/embedder/outgoing_broker_client_invitation.h" +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/platform_channel_utils_posix.h" +#include "mojo/edk/embedder/platform_handle_vector.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" + +namespace media { + +namespace { + +const base::FilePath::CharType kArcCamera3SocketPath[] = + "/var/run/camera/camera3.sock"; +const char kArcCameraGroup[] = "arc-camera"; + +// Creates a pipe. Returns true on success, otherwise false. +// On success, |read_fd| will be set to the fd of the read side, and +// |write_fd| will be set to the one of write side. +bool CreatePipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) { + int fds[2]; + if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) { + PLOG(ERROR) << "pipe2()"; + return false; + } + + read_fd->reset(fds[0]); + write_fd->reset(fds[1]); + return true; +} + +// Waits until |raw_socket_fd| is readable. We signal |raw_cancel_fd| when we +// want to cancel the blocking wait and stop serving connections on +// |raw_socket_fd|. To notify such a situation, |raw_cancel_fd| is also passed +// to here, and the write side will be closed in such a case. +bool WaitForSocketReadable(int raw_socket_fd, int raw_cancel_fd) { + struct pollfd fds[2] = { + {raw_socket_fd, POLLIN, 0}, {raw_cancel_fd, POLLIN, 0}, + }; + + if (HANDLE_EINTR(poll(fds, arraysize(fds), -1)) <= 0) { + PLOG(ERROR) << "poll()"; + return false; + } + + if (fds[1].revents) { + VLOG(1) << "Stop() was called"; + return false; + } + + DCHECK(fds[0].revents); + return true; +} + +class MojoCameraClientObserver : public CameraClientObserver { + public: + explicit MojoCameraClientObserver(arc::mojom::CameraHalClientPtr client) + : client_(std::move(client)) {} + + void OnChannelCreated(arc::mojom::CameraModulePtr camera_module) override { + client_->SetUpChannel(std::move(camera_module)); + } + + arc::mojom::CameraHalClientPtr& client() { return client_; } + + private: + arc::mojom::CameraHalClientPtr client_; + DISALLOW_IMPLICIT_CONSTRUCTORS(MojoCameraClientObserver); +}; + +} // namespace + +CameraClientObserver::~CameraClientObserver() {} + +// static +CameraHalDispatcherImpl* CameraHalDispatcherImpl::GetInstance() { + return base::Singleton<CameraHalDispatcherImpl>::get(); +} + +bool CameraHalDispatcherImpl::StartThreads() { + DCHECK(!proxy_thread_.IsRunning()); + DCHECK(!blocking_io_thread_.IsRunning()); + + if (!proxy_thread_.Start()) { + LOG(ERROR) << "Failed to start proxy thread"; + return false; + } + if (!blocking_io_thread_.Start()) { + LOG(ERROR) << "Failed to start blocking IO thread"; + proxy_thread_.Stop(); + return false; + } + proxy_task_runner_ = proxy_thread_.task_runner(); + blocking_io_task_runner_ = blocking_io_thread_.task_runner(); + return true; +} + +bool CameraHalDispatcherImpl::Start() { + if (!StartThreads()) { + return false; + } + base::WaitableEvent started(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + blocking_io_task_runner_->PostTask( + FROM_HERE, + base::Bind(&CameraHalDispatcherImpl::CreateSocket, base::Unretained(this), + base::Unretained(&started))); + started.Wait(); + return IsStarted(); +} + +void CameraHalDispatcherImpl::AddClientObserver( + std::unique_ptr<CameraClientObserver> observer) { + // If |proxy_thread_| fails to start in Start() then CameraHalDelegate will + // not be created, and this function will not be called. + DCHECK(proxy_thread_.IsRunning()); + proxy_thread_.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&CameraHalDispatcherImpl::AddClientObserverOnProxyThread, + base::Unretained(this), base::Passed(&observer))); +} + +bool CameraHalDispatcherImpl::IsStarted() { + return proxy_thread_.IsRunning() && blocking_io_thread_.IsRunning() && + proxy_fd_.is_valid(); +} + +CameraHalDispatcherImpl::CameraHalDispatcherImpl() + : proxy_thread_("CameraProxyThread"), + blocking_io_thread_("CameraBlockingIOThread") {} + +CameraHalDispatcherImpl::~CameraHalDispatcherImpl() { + VLOG(1) << "Stopping CameraHalDispatcherImpl..."; + if (proxy_thread_.IsRunning()) { + proxy_thread_.task_runner()->PostTask( + FROM_HERE, base::Bind(&CameraHalDispatcherImpl::StopOnProxyThread, + base::Unretained(this))); + proxy_thread_.Stop(); + } + blocking_io_thread_.Stop(); + VLOG(1) << "CameraHalDispatcherImpl stopped"; +} + +void CameraHalDispatcherImpl::RegisterServer( + arc::mojom::CameraHalServerPtr camera_hal_server) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + + if (camera_hal_server_) { + LOG(ERROR) << "Camera HAL server is already registered"; + return; + } + camera_hal_server.set_connection_error_handler( + base::Bind(&CameraHalDispatcherImpl::OnCameraHalServerConnectionError, + base::Unretained(this))); + camera_hal_server_ = std::move(camera_hal_server); + VLOG(1) << "Camera HAL server registered"; + + // Set up the Mojo channels for clients which registered before the server + // registers. + for (auto& client_observer : client_observers_) { + EstablishMojoChannel(client_observer.get()); + } +} + +void CameraHalDispatcherImpl::RegisterClient( + arc::mojom::CameraHalClientPtr client) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + auto client_observer = + base::MakeUnique<MojoCameraClientObserver>(std::move(client)); + client_observer->client().set_connection_error_handler(base::Bind( + &CameraHalDispatcherImpl::OnCameraHalClientConnectionError, + base::Unretained(this), base::Unretained(client_observer.get()))); + AddClientObserver(std::move(client_observer)); + VLOG(1) << "Camera HAL client registered"; +} + +void CameraHalDispatcherImpl::CreateSocket(base::WaitableEvent* started) { + DCHECK(blocking_io_task_runner_->BelongsToCurrentThread()); + + base::FilePath socket_path(kArcCamera3SocketPath); + mojo::edk::ScopedPlatformHandle socket_fd = mojo::edk::CreateServerHandle( + mojo::edk::NamedPlatformHandle(socket_path.value())); + if (!socket_fd.is_valid()) { + LOG(ERROR) << "Failed to create the socket file: " << kArcCamera3SocketPath; + started->Signal(); + return; + } + + // Change permissions on the socket. + struct group arc_camera_group; + struct group* result = nullptr; + char buf[1024]; + if (HANDLE_EINTR(getgrnam_r(kArcCameraGroup, &arc_camera_group, buf, + sizeof(buf), &result)) < 0) { + PLOG(ERROR) << "getgrnam_r()"; + started->Signal(); + return; + } + + if (!result) { + LOG(ERROR) << "Group '" << kArcCameraGroup << "' not found"; + started->Signal(); + return; + } + + if (HANDLE_EINTR(chown(kArcCamera3SocketPath, -1, arc_camera_group.gr_gid)) < + 0) { + PLOG(ERROR) << "chown()"; + started->Signal(); + return; + } + + if (!base::SetPosixFilePermissions(socket_path, 0660)) { + PLOG(ERROR) << "Could not set permissions: " << socket_path.value(); + started->Signal(); + return; + } + + blocking_io_task_runner_->PostTask( + FROM_HERE, base::Bind(&CameraHalDispatcherImpl::StartServiceLoop, + base::Unretained(this), base::Passed(&socket_fd), + base::Unretained(started))); +} + +void CameraHalDispatcherImpl::StartServiceLoop( + mojo::edk::ScopedPlatformHandle socket_fd, + base::WaitableEvent* started) { + DCHECK(blocking_io_task_runner_->BelongsToCurrentThread()); + DCHECK(!proxy_fd_.is_valid()); + DCHECK(!cancel_pipe_.is_valid()); + DCHECK(socket_fd.is_valid()); + + base::ScopedFD cancel_fd; + if (!CreatePipe(&cancel_fd, &cancel_pipe_)) { + started->Signal(); + LOG(ERROR) << "Failed to create cancel pipe"; + return; + } + + proxy_fd_ = std::move(socket_fd); + started->Signal(); + VLOG(1) << "CameraHalDispatcherImpl started; waiting for incoming connection"; + + while (true) { + if (!WaitForSocketReadable(proxy_fd_.get().handle, cancel_fd.get())) { + VLOG(1) << "Quit CameraHalDispatcherImpl IO thread"; + return; + } + + mojo::edk::ScopedPlatformHandle accepted_fd; + if (mojo::edk::ServerAcceptConnection(proxy_fd_.get(), &accepted_fd, + false) && + accepted_fd.is_valid()) { + VLOG(1) << "Accepted a connection"; + // Hardcode pid 0 since it is unused in mojo. + const base::ProcessHandle kUnusedChildProcessHandle = 0; + mojo::edk::PlatformChannelPair channel_pair; + mojo::edk::OutgoingBrokerClientInvitation invitation; + + std::string token = mojo::edk::GenerateRandomToken(); + mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe(token); + + invitation.Send( + kUnusedChildProcessHandle, + mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy, + channel_pair.PassServerHandle())); + + mojo::edk::ScopedPlatformHandleVectorPtr handles( + new mojo::edk::PlatformHandleVector{ + channel_pair.PassClientHandle().release()}); + + struct iovec iov = {const_cast<char*>(token.c_str()), token.length()}; + ssize_t result = mojo::edk::PlatformChannelSendmsgWithHandles( + accepted_fd.get(), &iov, 1, handles->data(), handles->size()); + if (result == -1) { + PLOG(ERROR) << "sendmsg()"; + } else { + proxy_task_runner_->PostTask( + FROM_HERE, base::Bind(&CameraHalDispatcherImpl::OnPeerConnected, + base::Unretained(this), base::Passed(&pipe))); + } + } + } +} + +void CameraHalDispatcherImpl::AddClientObserverOnProxyThread( + std::unique_ptr<CameraClientObserver> observer) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + if (camera_hal_server_) { + EstablishMojoChannel(observer.get()); + } + client_observers_.insert(std::move(observer)); +} + +void CameraHalDispatcherImpl::EstablishMojoChannel( + CameraClientObserver* client_observer) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + arc::mojom::CameraModulePtr camera_module_ptr; + arc::mojom::CameraModuleRequest camera_module_request = + mojo::MakeRequest(&camera_module_ptr); + camera_hal_server_->CreateChannel(std::move(camera_module_request)); + client_observer->OnChannelCreated(std::move(camera_module_ptr)); +} + +void CameraHalDispatcherImpl::OnPeerConnected( + mojo::ScopedMessagePipeHandle message_pipe) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + binding_set_.AddBinding( + this, arc::mojom::CameraHalDispatcherRequest(std::move(message_pipe))); + VLOG(1) << "New CameraHalDispatcher binding added"; +} + +void CameraHalDispatcherImpl::OnCameraHalServerConnectionError() { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + VLOG(1) << "Camera HAL server connection lost"; + camera_hal_server_.reset(); +} + +void CameraHalDispatcherImpl::OnCameraHalClientConnectionError( + CameraClientObserver* client_observer) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + for (auto& it : client_observers_) { + if (it.get() == client_observer) { + client_observers_.erase(it); + VLOG(1) << "Camera HAL client connection lost"; + break; + } + } +} + +void CameraHalDispatcherImpl::StopOnProxyThread() { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + if (!base::DeleteFile(base::FilePath(kArcCamera3SocketPath), + /* recursive */ false)) { + LOG(ERROR) << "Failed to delete " << kArcCamera3SocketPath; + } + // Close |cancel_pipe_| to quit the loop in WaitForIncomingConnection. + cancel_pipe_.reset(); + client_observers_.clear(); + camera_hal_server_.reset(); + binding_set_.CloseAllBindings(); +} + +} // namespace media
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h new file mode 100644 index 0000000..f5da5a5 --- /dev/null +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
@@ -0,0 +1,111 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_HAL_DISPATCHER_IMPL_H_ +#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_HAL_DISPATCHER_IMPL_H_ + +#include <memory> +#include <set> + +#include "base/memory/singleton.h" +#include "base/threading/thread.h" +#include "media/capture/capture_export.h" +#include "media/capture/video/chromeos/mojo/arc_camera3_service.mojom.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/interface_ptr_set.h" + +namespace base { + +class SingleThreadTaskRunner; +class WaitableEvent; + +} // namespace base + +namespace media { + +class CAPTURE_EXPORT CameraClientObserver { + public: + virtual ~CameraClientObserver(); + virtual void OnChannelCreated(arc::mojom::CameraModulePtr camera_module) = 0; +}; + +// The CameraHalDispatcherImpl hosts and waits on the unix domain socket +// /var/run/camera3.sock. CameraHalServer and CameraHalClients connect to the +// unix domain socket to create the initial Mojo connections with the +// CameraHalDisptcherImpl, and CameraHalDispatcherImpl then creates and +// dispaches the Mojo channels between CameraHalServer and CameraHalClients to +// establish direct Mojo connections between the CameraHalServer and the +// CameraHalClients. +// +// For general documentation about the CameraHalDispater Mojo interface see the +// comments in mojo/arc_camera3_service.mojom. +class CAPTURE_EXPORT CameraHalDispatcherImpl final + : public arc::mojom::CameraHalDispatcher { + public: + static CameraHalDispatcherImpl* GetInstance(); + + bool Start(); + + void AddClientObserver(std::unique_ptr<CameraClientObserver> observer); + + bool IsStarted(); + + // CameraHalDispatcher implementations. + void RegisterServer(arc::mojom::CameraHalServerPtr server) final; + void RegisterClient(arc::mojom::CameraHalClientPtr client) final; + + private: + friend struct base::DefaultSingletonTraits<CameraHalDispatcherImpl>; + // Allow the test to construct the class directly. + friend class CameraHalDispatcherImplTest; + + CameraHalDispatcherImpl(); + ~CameraHalDispatcherImpl() final; + + bool StartThreads(); + + // Creates the unix domain socket for the camera client processes and the + // camera HALv3 adapter process to connect. + void CreateSocket(base::WaitableEvent* started); + + // Waits for incoming connections (from HAL process or from client processes). + // Runs on |blocking_io_thread_|. + void StartServiceLoop(mojo::edk::ScopedPlatformHandle socket_fd, + base::WaitableEvent* started); + + void AddClientObserverOnProxyThread( + std::unique_ptr<CameraClientObserver> observer); + + void EstablishMojoChannel(CameraClientObserver* client_observer); + + // Handler for incoming Mojo connection on the unix domain socket. + void OnPeerConnected(mojo::ScopedMessagePipeHandle message_pipe); + + // Mojo connection error handlers. + void OnCameraHalServerConnectionError(); + void OnCameraHalClientConnectionError(CameraClientObserver* client); + + void StopOnProxyThread(); + + mojo::edk::ScopedPlatformHandle proxy_fd_; + base::ScopedFD cancel_pipe_; + + base::Thread proxy_thread_; + base::Thread blocking_io_thread_; + scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> blocking_io_task_runner_; + + mojo::BindingSet<arc::mojom::CameraHalDispatcher> binding_set_; + + arc::mojom::CameraHalServerPtr camera_hal_server_; + + std::set<std::unique_ptr<CameraClientObserver>> client_observers_; + + DISALLOW_COPY_AND_ASSIGN(CameraHalDispatcherImpl); +}; + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_ARC_CAMERA3_SERVICE_H_
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc new file mode 100644 index 0000000..fa00667 --- /dev/null +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
@@ -0,0 +1,216 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" + +#include <memory> +#include <utility> + +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "media/capture/video/chromeos/mojo/arc_camera3_service.mojom.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::InvokeWithoutArgs; + +namespace media { +namespace { + +class MockCameraHalServer : public arc::mojom::CameraHalServer { + public: + MockCameraHalServer() : binding_(this) {} + + ~MockCameraHalServer() {} + + void CreateChannel( + arc::mojom::CameraModuleRequest camera_module_request) override { + DoCreateChannel(camera_module_request); + } + MOCK_METHOD1(DoCreateChannel, + void(arc::mojom::CameraModuleRequest& camera_module_request)); + + arc::mojom::CameraHalServerPtr GetInterfacePtr( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + arc::mojom::CameraHalServerPtr camera_hal_server_ptr; + arc::mojom::CameraHalServerRequest camera_hal_server_request = + mojo::MakeRequest(&camera_hal_server_ptr, std::move(task_runner)); + binding_.Bind(std::move(camera_hal_server_request)); + return camera_hal_server_ptr; + } + + private: + mojo::Binding<arc::mojom::CameraHalServer> binding_; + DISALLOW_COPY_AND_ASSIGN(MockCameraHalServer); +}; + +class MockCameraHalClient : public arc::mojom::CameraHalClient { + public: + MockCameraHalClient() : binding_(this) {} + + ~MockCameraHalClient() {} + + void SetUpChannel(arc::mojom::CameraModulePtr camera_module_ptr) override { + DoSetUpChannel(camera_module_ptr); + } + MOCK_METHOD1(DoSetUpChannel, + void(arc::mojom::CameraModulePtr& camera_module_ptr)); + + arc::mojom::CameraHalClientPtr GetInterfacePtr( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + arc::mojom::CameraHalClientPtr camera_hal_client_ptr; + arc::mojom::CameraHalClientRequest camera_hal_client_request = + mojo::MakeRequest(&camera_hal_client_ptr, std::move(task_runner)); + binding_.Bind(std::move(camera_hal_client_request)); + return camera_hal_client_ptr; + } + + private: + mojo::Binding<arc::mojom::CameraHalClient> binding_; + DISALLOW_COPY_AND_ASSIGN(MockCameraHalClient); +}; + +} // namespace + +class CameraHalDispatcherImplTest : public ::testing::Test { + public: + CameraHalDispatcherImplTest() {} + + ~CameraHalDispatcherImplTest() override {} + + void SetUp() override { + dispatcher_ = new CameraHalDispatcherImpl(); + EXPECT_TRUE(dispatcher_->StartThreads()); + } + + void TearDown() override { delete dispatcher_; } + + scoped_refptr<base::SingleThreadTaskRunner> GetProxyTaskRunner() { + return dispatcher_->proxy_task_runner_; + } + + void DoLoop() { + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + } + + void QuitRunLoop() { + if (run_loop_) { + run_loop_->Quit(); + } + } + + protected: + // We can't use std::unique_ptr here because the constructor and destructor of + // CameraHalDispatcherImpl are private. + CameraHalDispatcherImpl* dispatcher_; + + private: + base::test::ScopedTaskEnvironment scoped_task_environment_; + std::unique_ptr<base::RunLoop> run_loop_; + DISALLOW_COPY_AND_ASSIGN(CameraHalDispatcherImplTest); +}; + +// Test that the CameraHalDisptcherImpl correctly re-establishes a Mojo channel +// for the client when the server crashes. +TEST_F(CameraHalDispatcherImplTest, ServerConnectionError) { + // First verify that a the CameraHalDispatcherImpl establishes a Mojo channel + // between the server and the client. + auto mock_server = base::MakeUnique<MockCameraHalServer>(); + auto mock_client = base::MakeUnique<MockCameraHalClient>(); + + EXPECT_CALL(*mock_server, DoCreateChannel(_)).Times(1); + EXPECT_CALL(*mock_client, DoSetUpChannel(_)) + .Times(1) + .WillOnce( + InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); + + auto server_ptr = mock_server->GetInterfacePtr(GetProxyTaskRunner()); + GetProxyTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CameraHalDispatcherImpl::RegisterServer, + base::Unretained(dispatcher_), base::Passed(&server_ptr))); + auto client_ptr = mock_client->GetInterfacePtr(GetProxyTaskRunner()); + GetProxyTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CameraHalDispatcherImpl::RegisterClient, + base::Unretained(dispatcher_), base::Passed(&client_ptr))); + + // Wait until the client gets the established Mojo channel. + DoLoop(); + + // Re-create a new server to simulate a server crash. + mock_server = base::MakeUnique<MockCameraHalServer>(); + + // Make sure we creates a new Mojo channel from the new server to the same + // client. + EXPECT_CALL(*mock_server, DoCreateChannel(_)).Times(1); + EXPECT_CALL(*mock_client, DoSetUpChannel(_)) + .Times(1) + .WillOnce( + InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); + + server_ptr = mock_server->GetInterfacePtr(GetProxyTaskRunner()); + GetProxyTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CameraHalDispatcherImpl::RegisterServer, + base::Unretained(dispatcher_), base::Passed(&server_ptr))); + + // Wait until the clients gets the newly established Mojo channel. + DoLoop(); +}; + +// Test that the CameraHalDisptcherImpl correctly re-establishes a Mojo channel +// for the client when the client reconnects after crash. +TEST_F(CameraHalDispatcherImplTest, ClientConnectionError) { + // First verify that a the CameraHalDispatcherImpl establishes a Mojo channel + // between the server and the client. + auto mock_server = base::MakeUnique<MockCameraHalServer>(); + auto mock_client = base::MakeUnique<MockCameraHalClient>(); + + EXPECT_CALL(*mock_server, DoCreateChannel(_)).Times(1); + EXPECT_CALL(*mock_client, DoSetUpChannel(_)) + .Times(1) + .WillOnce( + InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); + + auto server_ptr = mock_server->GetInterfacePtr(GetProxyTaskRunner()); + GetProxyTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CameraHalDispatcherImpl::RegisterServer, + base::Unretained(dispatcher_), base::Passed(&server_ptr))); + auto client_ptr = mock_client->GetInterfacePtr(GetProxyTaskRunner()); + GetProxyTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CameraHalDispatcherImpl::RegisterClient, + base::Unretained(dispatcher_), base::Passed(&client_ptr))); + + // Wait until the client gets the established Mojo channel. + DoLoop(); + + // Re-create a new server to simulate a server crash. + mock_client = base::MakeUnique<MockCameraHalClient>(); + + // Make sure we re-create the Mojo channel from the same server to the new + // client. + EXPECT_CALL(*mock_server, DoCreateChannel(_)).Times(1); + EXPECT_CALL(*mock_client, DoSetUpChannel(_)) + .Times(1) + .WillOnce( + InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); + + client_ptr = mock_client->GetInterfacePtr(GetProxyTaskRunner()); + GetProxyTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CameraHalDispatcherImpl::RegisterClient, + base::Unretained(dispatcher_), base::Passed(&client_ptr))); + + // Wait until the clients gets the newly established Mojo channel. + DoLoop(); +}; + +} // namespace media
diff --git a/media/capture/video/chromeos/mojo/BUILD.gn b/media/capture/video/chromeos/mojo/BUILD.gn index cf4e480..78dee7c8 100644 --- a/media/capture/video/chromeos/mojo/BUILD.gn +++ b/media/capture/video/chromeos/mojo/BUILD.gn
@@ -8,6 +8,7 @@ sources = [ "arc_camera3.mojom", "arc_camera3_metadata.mojom", + "arc_camera3_service.mojom", "camera_metadata_tags.mojom", ] }
diff --git a/media/capture/video/chromeos/mojo/arc_camera3_service.mojom b/media/capture/video/chromeos/mojo/arc_camera3_service.mojom new file mode 100644 index 0000000..1261d3d --- /dev/null +++ b/media/capture/video/chromeos/mojo/arc_camera3_service.mojom
@@ -0,0 +1,48 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module arc.mojom; + +import "arc_camera3.mojom"; + +// The ARC++ camera HAL v3 Mojo dispatcher. The dispatcher acts as a proxy and +// waits for the server and the clients to register. There can only be one +// server registered, with multiple clients requesting connections to the +// server. For each client, the dispatcher is responsible for creating a Mojo +// channel to the server and pass the established Mojo channel to the client in +// order to set up a Mojo channel between the client and the server. +// +// The CameraHalDispatcher is designed to help the server and the clients to +// recover from errors easily. For example, when the camera HAL process crashes +// the CameraHalDispatcher can still hold the connections of the clients. When +// the camera HAL reconnects the CameraHalDispatcher can then quickly restore +// the Mojo channels between the clients and the camera HAL process by calling +// CameraHalClient::SetUpChannel() in RegiserServer(). +interface CameraHalDispatcher { + // A CameraHalServer calls RegisterServer to register itself with the + // dispatcher. + RegisterServer@0(CameraHalServer server); + + // A CameraHalClient calls RegisterClient to register itself with the + // dispatcher. + RegisterClient@1(CameraHalClient client); +}; + +// The ARC++ camera HAL v3 Mojo server. +interface CameraHalServer { + // A caller calls CreateChannel to create a new Mojo channel to the camera + // HAL v3 adapter. Upon successfully binding of |camera_module_request|, the + // caller will have a established Mojo channel to the camera HAL v3 adapter + // process. + CreateChannel@0(CameraModule& camera_module_request); +}; + +// The ARC++ camera HAL v3 Mojo client. +interface CameraHalClient { + // A caller calls SetUpChannel to dispatch the established Mojo channel + // |camera_module_ptr| to the client. The CameraHalClient can create a + // Mojo channel to the camera HAL v3 adapter process with |camera_module_ptr|. + // SetUpChannel may be called multiple times. + SetUpChannel@0(CameraModule camera_module_ptr); +};
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc index 275d98c..83e4041 100644 --- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc +++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
@@ -6,6 +6,7 @@ #include "base/files/file_util.h" #include "base/memory/ptr_util.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" #include "media/capture/video/linux/video_capture_device_factory_linux.h" namespace media { @@ -25,9 +26,17 @@ LOG(ERROR) << "Module thread failed to start"; return false; } + + if (!CameraHalDispatcherImpl::GetInstance()->IsStarted() && + !CameraHalDispatcherImpl::GetInstance()->Start()) { + LOG(ERROR) << "Failed to start CameraHalDispatcherImpl"; + return false; + } + camera_hal_delegate_ = new CameraHalDelegate(camera_hal_ipc_thread_.task_runner()); - return camera_hal_delegate_->StartCameraModuleIpc(); + camera_hal_delegate_->RegisterCameraClient(); + return true; } std::unique_ptr<VideoCaptureDevice>
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc index ce27a07c..c6fb6f0 100644 --- a/media/capture/video/win/video_capture_device_win.cc +++ b/media/capture/video/win/video_capture_device_win.cc
@@ -465,44 +465,6 @@ client_->OnStarted(); state_ = kCapturing; - - base::win::ScopedComPtr<IKsTopologyInfo> info; - hr = capture_filter_.CopyTo(info.GetAddressOf()); - if (FAILED(hr)) { - SetErrorState(FROM_HERE, "Failed to obtain the topology info.", hr); - return; - } - - DWORD num_nodes = 0; - hr = info->get_NumNodes(&num_nodes); - if (FAILED(hr)) { - SetErrorState(FROM_HERE, "Failed to obtain the number of nodes.", hr); - return; - } - - // Every UVC camera is expected to have a single ICameraControl and a single - // IVideoProcAmp nodes, and both are needed; ignore any unlikely later ones. - GUID node_type; - for (size_t i = 0; i < num_nodes; i++) { - info->get_NodeType(i, &node_type); - if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_CAMERA_TERMINAL)) { - hr = info->CreateNodeInstance(i, IID_PPV_ARGS(&camera_control_)); - if (SUCCEEDED(hr)) - break; - SetErrorState(FROM_HERE, "Failed to retrieve the ICameraControl.", hr); - return; - } - } - for (size_t i = 0; i < num_nodes; i++) { - info->get_NodeType(i, &node_type); - if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_PROCESSING)) { - hr = info->CreateNodeInstance(i, IID_PPV_ARGS(&video_control_)); - if (SUCCEEDED(hr)) - break; - SetErrorState(FROM_HERE, "Failed to retrieve the IVideoProcAmp.", hr); - return; - } - } } void VideoCaptureDeviceWin::StopAndDeAllocate() { @@ -535,8 +497,10 @@ void VideoCaptureDeviceWin::GetPhotoState(GetPhotoStateCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - if (!camera_control_ || !video_control_) - return; + if (!camera_control_ || !video_control_) { + if (!InitializeVideoAndCameraControls()) + return; + } auto photo_capabilities = mojom::PhotoState::New(); @@ -627,8 +591,10 @@ VideoCaptureDevice::SetPhotoOptionsCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - if (!camera_control_ || !video_control_) - return; + if (!camera_control_ || !video_control_) { + if (!InitializeVideoAndCameraControls()) + return; + } HRESULT hr; @@ -710,6 +676,48 @@ callback.Run(true); } + +bool VideoCaptureDeviceWin::InitializeVideoAndCameraControls() { + base::win::ScopedComPtr<IKsTopologyInfo> info; + HRESULT hr = capture_filter_.CopyTo(info.GetAddressOf()); + if (FAILED(hr)) { + SetErrorState(FROM_HERE, "Failed to obtain the topology info.", hr); + return false; + } + + DWORD num_nodes = 0; + hr = info->get_NumNodes(&num_nodes); + if (FAILED(hr)) { + SetErrorState(FROM_HERE, "Failed to obtain the number of nodes.", hr); + return false; + } + + // Every UVC camera is expected to have a single ICameraControl and a single + // IVideoProcAmp nodes, and both are needed; ignore any unlikely later ones. + GUID node_type; + for (size_t i = 0; i < num_nodes; i++) { + info->get_NodeType(i, &node_type); + if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_CAMERA_TERMINAL)) { + hr = info->CreateNodeInstance(i, IID_PPV_ARGS(&camera_control_)); + if (SUCCEEDED(hr)) + break; + SetErrorState(FROM_HERE, "Failed to retrieve the ICameraControl.", hr); + return false; + } + } + for (size_t i = 0; i < num_nodes; i++) { + info->get_NodeType(i, &node_type); + if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_PROCESSING)) { + hr = info->CreateNodeInstance(i, IID_PPV_ARGS(&video_control_)); + if (SUCCEEDED(hr)) + break; + SetErrorState(FROM_HERE, "Failed to retrieve the IVideoProcAmp.", hr); + return false; + } + } + return camera_control_ && video_control_; +} + // Implements SinkFilterObserver::SinkFilterObserver. void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer, int length,
diff --git a/media/capture/video/win/video_capture_device_win.h b/media/capture/video/win/video_capture_device_win.h index 8a2ed6cc..7ae6a710 100644 --- a/media/capture/video/win/video_capture_device_win.h +++ b/media/capture/video/win/video_capture_device_win.h
@@ -89,6 +89,8 @@ // User needs to recover by destroying the object. }; + bool InitializeVideoAndCameraControls(); + // Implements SinkFilterObserver. void FrameReceived(const uint8_t* buffer, int length,
diff --git a/mojo/android/BUILD.gn b/mojo/android/BUILD.gn index 179eb6f..525e7fc 100644 --- a/mojo/android/BUILD.gn +++ b/mojo/android/BUILD.gn
@@ -140,8 +140,6 @@ "//mojo/public/cpp/test_support:test_utils", ] defines = [ "UNIT_TEST" ] - configs -= [ "//build/config/android:hide_all_but_jni_onload" ] - configs += [ "//build/config/android:hide_all_but_jni" ] } instrumentation_test_apk("mojo_test_apk") {
diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn index 8ef6f7c..f855f47 100644 --- a/net/android/BUILD.gn +++ b/net/android/BUILD.gn
@@ -109,9 +109,6 @@ ":java_test_native_support", "//net:test_support", ] - - configs -= [ "//build/config/android:hide_all_but_jni_onload" ] - configs += [ "//build/config/android:hide_all_but_jni" ] } android_apk("net_test_support_apk") {
diff --git a/net/base/network_change_notifier_mac.cc b/net/base/network_change_notifier_mac.cc index dc6430f1a..e66d87a 100644 --- a/net/base/network_change_notifier_mac.cc +++ b/net/base/network_change_notifier_mac.cc
@@ -8,6 +8,7 @@ #include <resolv.h> #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/threading/thread.h" #include "base/threading/thread_restrictions.h" @@ -48,10 +49,10 @@ connection_type_initialized_(false), initial_connection_type_cv_(&connection_type_lock_), forwarder_(this), - dns_config_service_thread_(new DnsConfigServiceThread()) { + dns_config_service_thread_(base::MakeUnique<DnsConfigServiceThread>()) { // Must be initialized after the rest of this object, as it may call back into // SetInitialConnectionType(). - config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); + config_watcher_ = base::MakeUnique<NetworkConfigWatcherMac>(&forwarder_); dns_config_service_thread_->StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); } @@ -104,16 +105,15 @@ NetworkChangeNotifierMac::CalculateConnectionType( SCNetworkConnectionFlags flags) { bool reachable = CalculateReachability(flags); - if (reachable) { -#if defined(OS_IOS) - return (flags & kSCNetworkReachabilityFlagsIsWWAN) ? CONNECTION_3G - : CONNECTION_WIFI; -#else - return ConnectionTypeFromInterfaces(); -#endif // defined(OS_IOS) - } else { + if (!reachable) return CONNECTION_NONE; - } + +#if defined(OS_IOS) + return (flags & kSCNetworkReachabilityFlagsIsWWAN) ? CONNECTION_3G + : CONNECTION_WIFI; +#else + return ConnectionTypeFromInterfaces(); +#endif } void NetworkChangeNotifierMac::Forwarder::StartReachabilityNotifications() {
diff --git a/net/cert/x509_util_ios.cc b/net/cert/x509_util_ios.cc index 18d33151..3f87720d5 100644 --- a/net/cert/x509_util_ios.cc +++ b/net/cert/x509_util_ios.cc
@@ -11,25 +11,6 @@ namespace x509_util { -namespace { - -// Returns true if a given |cert_handle| is actually a valid X.509 certificate -// handle. -// -// SecCertificateCreateFromData() does not always force the immediate parsing of -// the certificate, and as such, may return a SecCertificateRef for an -// invalid/unparsable certificate. Force parsing to occur to ensure that the -// SecCertificateRef is correct. On later versions where -// SecCertificateCreateFromData() immediately parses, rather than lazily, this -// call is cheap, as the subject is cached. -bool IsValidSecCertificate(SecCertificateRef cert_handle) { - base::ScopedCFTypeRef<CFStringRef> sanity_check( - SecCertificateCopySubjectSummary(cert_handle)); - return sanity_check != nullptr; -} - -} // namespace - base::ScopedCFTypeRef<SecCertificateRef> CreateSecCertificateFromBytes( const uint8_t* data, size_t length) { @@ -39,14 +20,8 @@ if (!cert_data) return base::ScopedCFTypeRef<SecCertificateRef>(); - base::ScopedCFTypeRef<SecCertificateRef> cert_handle( + return base::ScopedCFTypeRef<SecCertificateRef>( SecCertificateCreateWithData(nullptr, cert_data)); - if (!cert_handle) - return base::ScopedCFTypeRef<SecCertificateRef>(); - - if (!IsValidSecCertificate(cert_handle.get())) - return base::ScopedCFTypeRef<SecCertificateRef>(); - return cert_handle; } base::ScopedCFTypeRef<SecCertificateRef>
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index c5a32fe..b258621 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -9237,7 +9237,7 @@ session->http_server_properties(); AlternativeService alternative_service(kProtoHTTP2, "", 444); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort("https", "host.with.alternate", 443), alternative_service, expiration); @@ -10196,7 +10196,7 @@ AlternativeService alternative_service(kProtoHTTP2, "different.example.org", 444); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(request.url), alternative_service, expiration); HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); @@ -10235,7 +10235,7 @@ session->http_server_properties(); AlternativeService alternative_service(kProtoHTTP2, "", 444); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(request.url), alternative_service, expiration); HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); @@ -10254,8 +10254,9 @@ url::SchemeHostPort test_server("https", "www.example.org", 443); AlternativeService alternative_service(kProtoQUIC, "", 80); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( - test_server, alternative_service, expiration); + http_server_properties->SetQuicAlternativeService( + test_server, alternative_service, expiration, + session->params().quic_supported_versions); EXPECT_EQ( 1u, http_server_properties->GetAlternativeServiceInfos(test_server).size()); @@ -10397,8 +10398,9 @@ session->http_server_properties(); AlternativeService alternative_service(kProtoQUIC, alternative); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService(server, alternative_service, - expiration); + http_server_properties->SetQuicAlternativeService( + server, alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); // Mark the QUIC alternative service as broken. http_server_properties->MarkAlternativeServiceBroken(alternative_service); @@ -10458,13 +10460,15 @@ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); AlternativeService alternative_service1(kProtoQUIC, alternative1); - AlternativeServiceInfo alternative_service_info1(alternative_service1, - expiration); - alternative_service_info_vector.push_back(alternative_service_info1); + alternative_service_info_vector.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service1, expiration, + session->params().quic_supported_versions)); AlternativeService alternative_service2(kProtoQUIC, alternative2); - AlternativeServiceInfo alternative_service_info2(alternative_service2, - expiration); - alternative_service_info_vector.push_back(alternative_service_info2); + alternative_service_info_vector.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service2, expiration, + session->params().quic_supported_versions)); http_server_properties->SetAlternativeServices( server, alternative_service_info_vector); @@ -10516,12 +10520,12 @@ const url::SchemeHostPort server(request.url); // Port must be < 1024, or the header will be ignored (since initial port was // port 80 (another restricted port). - const AlternativeService alternative_service( - kProtoHTTP2, "www.example.org", - 666); // Port is ignored by MockConnect anyway. + // Port is ignored by MockConnect anyway. + const AlternativeService alternative_service(kProtoHTTP2, "www.example.org", + 666); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService(server, alternative_service, - expiration); + http_server_properties->SetHttp2AlternativeService( + server, alternative_service, expiration); HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); TestCompletionCallback callback; @@ -10583,7 +10587,7 @@ AlternativeService alternative_service(kProtoHTTP2, "www.example.org", kUnrestrictedAlternatePort); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(restricted_port_request.url), alternative_service, expiration); @@ -10633,7 +10637,7 @@ AlternativeService alternative_service(kProtoHTTP2, "www.example.org", kUnrestrictedAlternatePort); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(restricted_port_request.url), alternative_service, expiration); @@ -10682,7 +10686,7 @@ AlternativeService alternative_service(kProtoHTTP2, "www.example.org", kRestrictedAlternatePort); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(restricted_port_request.url), alternative_service, expiration); @@ -10731,7 +10735,7 @@ AlternativeService alternative_service(kProtoHTTP2, "www.example.org", kRestrictedAlternatePort); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(unrestricted_port_request.url), alternative_service, expiration); @@ -10780,7 +10784,7 @@ AlternativeService alternative_service(kProtoHTTP2, "www.example.org", kUnrestrictedAlternatePort); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(unrestricted_port_request.url), alternative_service, expiration); @@ -10821,7 +10825,7 @@ AlternativeService alternative_service(kProtoHTTP2, "www.example.org", kUnsafePort); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService( + http_server_properties->SetHttp2AlternativeService( url::SchemeHostPort(request.url), alternative_service, expiration); HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); @@ -11181,8 +11185,8 @@ HostPortPair alternative("www.example.com", 443); AlternativeService alternative_service(kProtoHTTP2, alternative); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService(server, alternative_service, - expiration); + http_server_properties->SetHttp2AlternativeService( + server, alternative_service, expiration); // Non-alternative job should hang. MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); @@ -14065,8 +14069,8 @@ session->http_server_properties(); AlternativeService alternative_service(kProtoHTTP2, alternative); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService(server, alternative_service, - expiration); + http_server_properties->SetHttp2AlternativeService( + server, alternative_service, expiration); HttpRequestInfo request; HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); @@ -14132,8 +14136,8 @@ session->http_server_properties(); AlternativeService alternative_service(kProtoHTTP2, alternative); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService(server, alternative_service, - expiration); + http_server_properties->SetHttp2AlternativeService( + server, alternative_service, expiration); HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get()); HttpRequestInfo request1; @@ -14239,8 +14243,8 @@ session->http_server_properties(); AlternativeService alternative_service(kProtoHTTP2, alternative); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties->SetAlternativeService(server, alternative_service, - expiration); + http_server_properties->SetHttp2AlternativeService( + server, alternative_service, expiration); // First transaction to alternative to open an HTTP/1.1 socket. HttpRequestInfo request1;
diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc index 15947b2..a1289cae 100644 --- a/net/http/http_server_properties.cc +++ b/net/http/http_server_properties.cc
@@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" +#include "net/http/http_network_session.h" #include "net/socket/ssl_client_socket.h" #include "net/ssl/ssl_config.h" @@ -78,18 +79,40 @@ return false; } +// static +AlternativeServiceInfo +AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + const AlternativeService& alternative_service, + base::Time expiration) { + DCHECK_EQ(alternative_service.protocol, kProtoHTTP2); + return AlternativeServiceInfo(alternative_service, expiration, + QuicVersionVector()); +} + +// static +AlternativeServiceInfo AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + const AlternativeService& alternative_service, + base::Time expiration, + const QuicVersionVector& advertised_versions) { + DCHECK_EQ(alternative_service.protocol, kProtoQUIC); + return AlternativeServiceInfo(alternative_service, expiration, + advertised_versions); +} + AlternativeServiceInfo::AlternativeServiceInfo() : alternative_service_() {} +AlternativeServiceInfo::~AlternativeServiceInfo() {} + AlternativeServiceInfo::AlternativeServiceInfo( const AlternativeService& alternative_service, - base::Time expiration) - : alternative_service_(alternative_service), expiration_(expiration) {} - -AlternativeServiceInfo::AlternativeServiceInfo(NextProto protocol, - const std::string& host, - uint16_t port, - base::Time expiration) - : alternative_service_(protocol, host, port), expiration_(expiration) {} + base::Time expiration, + const QuicVersionVector& advertised_versions) + : alternative_service_(alternative_service), expiration_(expiration) { + if (alternative_service_.protocol == kProtoQUIC) { + advertised_versions_ = advertised_versions; + std::sort(advertised_versions_.begin(), advertised_versions_.end()); + } +} AlternativeServiceInfo::AlternativeServiceInfo( const AlternativeServiceInfo& alternative_service_info) = default;
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h index c521148b..a11d80222 100644 --- a/net/http/http_server_properties.h +++ b/net/http/http_server_properties.h
@@ -20,6 +20,7 @@ #include "net/base/net_export.h" #include "net/quic/core/quic_bandwidth.h" #include "net/quic/core/quic_server_id.h" +#include "net/quic/core/quic_versions.h" #include "net/socket/next_proto.h" #include "net/spdy/core/spdy_framer.h" // TODO(willchan): Reconsider this. #include "net/spdy/core/spdy_protocol.h" @@ -116,24 +117,28 @@ class NET_EXPORT_PRIVATE AlternativeServiceInfo { public: + static AlternativeServiceInfo CreateHttp2AlternativeServiceInfo( + const AlternativeService& alternative_service, + base::Time expiration); + + static AlternativeServiceInfo CreateQuicAlternativeServiceInfo( + const AlternativeService& alternative_service, + base::Time expiration, + const QuicVersionVector& advertised_versions); + AlternativeServiceInfo(); - - AlternativeServiceInfo(const AlternativeService& alternative_service, - base::Time expiration); - - AlternativeServiceInfo(NextProto protocol, - const std::string& host, - uint16_t port, - base::Time expiration); + ~AlternativeServiceInfo(); AlternativeServiceInfo( const AlternativeServiceInfo& alternative_service_info); + AlternativeServiceInfo& operator=( const AlternativeServiceInfo& alternative_service_info); bool operator==(const AlternativeServiceInfo& other) const { return alternative_service_ == other.alternative_service() && - expiration_ == other.expiration(); + expiration_ == other.expiration() && + advertised_versions_ == other.advertised_versions(); } bool operator!=(const AlternativeServiceInfo& other) const { @@ -158,15 +163,37 @@ expiration_ = expiration; } + void set_advertised_versions(const QuicVersionVector& advertised_versions) { + if (alternative_service_.protocol != kProtoQUIC) + return; + + advertised_versions_ = advertised_versions; + std::sort(advertised_versions_.begin(), advertised_versions_.end()); + } + const AlternativeService& alternative_service() const { return alternative_service_; } base::Time expiration() const { return expiration_; } + const QuicVersionVector& advertised_versions() const { + return advertised_versions_; + } + private: + AlternativeServiceInfo(const AlternativeService& alternative_service, + base::Time expiration, + const QuicVersionVector& advertised_versions); + AlternativeService alternative_service_; base::Time expiration_; + + // Lists all the QUIC versions that are advertised by the server and supported + // by Chrome. If empty, defaults to versions used by the current instance of + // the netstack. + // This list MUST be sorted in ascending order. + QuicVersionVector advertised_versions_; }; struct NET_EXPORT SupportsQuic { @@ -270,15 +297,26 @@ virtual AlternativeServiceInfoVector GetAlternativeServiceInfos( const url::SchemeHostPort& origin) = 0; - // Set a single alternative service for |origin|. Previous alternative + // Set a single HTTP/2 alternative service for |origin|. Previous + // alternative services for |origin| are discarded. + // |alternative_service.host| may be empty. + // Return true if |alternative_service_map_| has changed significantly enough + // that it should be persisted to disk. + virtual bool SetHttp2AlternativeService( + const url::SchemeHostPort& origin, + const AlternativeService& alternative_service, + base::Time expiration) = 0; + + // Set a single QUIC alternative service for |origin|. Previous alternative // services for |origin| are discarded. // |alternative_service.host| may be empty. // Return true if |alternative_service_map_| has changed significantly enough // that it should be persisted to disk. - virtual bool SetAlternativeService( + virtual bool SetQuicAlternativeService( const url::SchemeHostPort& origin, const AlternativeService& alternative_service, - base::Time expiration) = 0; + base::Time expiration, + const QuicVersionVector& advertised_versions) = 0; // Set alternative services for |origin|. Previous alternative services for // |origin| are discarded.
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc index b96a4b27..843a017 100644 --- a/net/http/http_server_properties_impl.cc +++ b/net/http/http_server_properties_impl.cc
@@ -287,8 +287,16 @@ ++it; continue; } - valid_alternative_service_infos.push_back( - AlternativeServiceInfo(alternative_service, it->expiration())); + if (alternative_service.protocol == kProtoQUIC) { + valid_alternative_service_infos.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service, it->expiration(), + it->advertised_versions())); + } else { + valid_alternative_service_infos.push_back( + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service, it->expiration())); + } ++it; } if (map_it->second.empty()) { @@ -323,8 +331,16 @@ ++it; continue; } - valid_alternative_service_infos.push_back( - AlternativeServiceInfo(alternative_service, it->expiration())); + if (alternative_service.protocol == kProtoQUIC) { + valid_alternative_service_infos.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service, it->expiration(), + it->advertised_versions())); + } else { + valid_alternative_service_infos.push_back( + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service, it->expiration())); + } ++it; } if (map_it->second.empty()) { @@ -333,14 +349,31 @@ return valid_alternative_service_infos; } -bool HttpServerPropertiesImpl::SetAlternativeService( +bool HttpServerPropertiesImpl::SetHttp2AlternativeService( const url::SchemeHostPort& origin, const AlternativeService& alternative_service, base::Time expiration) { + DCHECK_EQ(alternative_service.protocol, kProtoHTTP2); + return SetAlternativeServices( origin, AlternativeServiceInfoVector( - /*size=*/1, AlternativeServiceInfo(alternative_service, expiration))); + /*size=*/1, AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service, expiration))); +} + +bool HttpServerPropertiesImpl::SetQuicAlternativeService( + const url::SchemeHostPort& origin, + const AlternativeService& alternative_service, + base::Time expiration, + const QuicVersionVector& advertised_versions) { + DCHECK(alternative_service.protocol == kProtoQUIC); + + return SetAlternativeServices( + origin, AlternativeServiceInfoVector( + /*size=*/1, + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service, expiration, advertised_versions))); } bool HttpServerPropertiesImpl::SetAlternativeServices( @@ -380,6 +413,12 @@ changed = true; break; } + // Also persist to disk if new entry has a different list of advertised + // versions. + if (old.advertised_versions() != new_it->advertised_versions()) { + changed = true; + break; + } ++new_it; } }
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h index 74516758..c8c42325 100644 --- a/net/http/http_server_properties_impl.h +++ b/net/http/http_server_properties_impl.h
@@ -81,9 +81,14 @@ SSLConfig* ssl_config) override; AlternativeServiceInfoVector GetAlternativeServiceInfos( const url::SchemeHostPort& origin) override; - bool SetAlternativeService(const url::SchemeHostPort& origin, - const AlternativeService& alternative_service, - base::Time expiration) override; + bool SetHttp2AlternativeService(const url::SchemeHostPort& origin, + const AlternativeService& alternative_service, + base::Time expiration) override; + bool SetQuicAlternativeService( + const url::SchemeHostPort& origin, + const AlternativeService& alternative_service, + base::Time expiration, + const QuicVersionVector& advertised_versions) override; bool SetAlternativeServices(const url::SchemeHostPort& origin, const AlternativeServiceInfoVector& alternative_service_info_vector) override;
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc index 31a6074..163ced1 100644 --- a/net/http/http_server_properties_impl_unittest.cc +++ b/net/http/http_server_properties_impl_unittest.cc
@@ -13,6 +13,7 @@ #include "base/values.h" #include "net/base/host_port_pair.h" #include "net/base/ip_address.h" +#include "net/http/http_network_session.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -78,7 +79,14 @@ const AlternativeService& alternative_service) { const base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - return impl_.SetAlternativeService(origin, alternative_service, expiration); + if (alternative_service.protocol == kProtoQUIC) { + return impl_.SetQuicAlternativeService( + origin, alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); + } else { + return impl_.SetHttp2AlternativeService(origin, alternative_service, + expiration); + } } void MarkBrokenAndLetExpireAlternativeServiceNTimes( @@ -368,20 +376,25 @@ AlternativeServiceInfoVector alternative_service_info_vector; base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); // Same hostname, same port, TCP: should be ignored. - AlternativeServiceInfo alternative_service_info1(kProtoHTTP2, "foo", 443, - expiration); + AlternativeServiceInfo alternative_service_info1 = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + AlternativeService(kProtoHTTP2, "foo", 443), expiration); alternative_service_info_vector.push_back(alternative_service_info1); // Different hostname: GetAlternativeServiceInfos should return this one. - AlternativeServiceInfo alternative_service_info2(kProtoHTTP2, "bar", 443, - expiration); + AlternativeServiceInfo alternative_service_info2 = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + AlternativeService(kProtoHTTP2, "bar", 443), expiration); alternative_service_info_vector.push_back(alternative_service_info2); // Different port: GetAlternativeServiceInfos should return this one too. - AlternativeServiceInfo alternative_service_info3(kProtoHTTP2, "foo", 80, - expiration); + AlternativeServiceInfo alternative_service_info3 = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + AlternativeService(kProtoHTTP2, "foo", 80), expiration); alternative_service_info_vector.push_back(alternative_service_info3); // QUIC: GetAlternativeServices should return this one too. - AlternativeServiceInfo alternative_service_info4(kProtoQUIC, "foo", 443, - expiration); + AlternativeServiceInfo alternative_service_info4 = + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + AlternativeService(kProtoQUIC, "foo", 443), expiration, + HttpNetworkSession::Params().quic_supported_versions); alternative_service_info_vector.push_back(alternative_service_info4); url::SchemeHostPort test_server("https", "foo", 443); @@ -405,7 +418,8 @@ const base::Time now = base::Time::Now(); base::Time expiration1 = now + base::TimeDelta::FromDays(1); // 1st entry in the memory. - impl_.SetAlternativeService(test_server1, alternative_service1, expiration1); + impl_.SetHttp2AlternativeService(test_server1, alternative_service1, + expiration1); // |test_server2| has an alternative service, which will be // overwritten by SetAlternativeServiceServers(), because @@ -415,7 +429,8 @@ const AlternativeService alternative_service2(kProtoHTTP2, "bar2", 443); base::Time expiration2 = now + base::TimeDelta::FromDays(2); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service2, expiration2)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service2, expiration2)); url::SchemeHostPort test_server2("http", "foo2", 80); // 0th entry in the memory. impl_.SetAlternativeServices(test_server2, alternative_service_info_vector); @@ -427,8 +442,9 @@ AlternativeServiceMap::NO_AUTO_EVICT); const AlternativeService alternative_service3(kProtoHTTP2, "bar3", 123); base::Time expiration3 = now + base::TimeDelta::FromDays(3); - const AlternativeServiceInfo alternative_service_info1(alternative_service3, - expiration3); + const AlternativeServiceInfo alternative_service_info1 = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service3, expiration3); // Simulate updating data for 0th entry with data from Preferences. alternative_service_map->Put( test_server2, @@ -437,8 +453,9 @@ url::SchemeHostPort test_server3("http", "foo3", 80); const AlternativeService alternative_service4(kProtoHTTP2, "bar4", 1234); base::Time expiration4 = now + base::TimeDelta::FromDays(4); - const AlternativeServiceInfo alternative_service_info2(alternative_service4, - expiration4); + const AlternativeServiceInfo alternative_service_info2 = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service4, expiration4); // Add an old entry from Preferences, this will be added to end of recency // list. alternative_service_map->Put( @@ -502,8 +519,9 @@ url::SchemeHostPort server("https", "foo", 443); const AlternativeService alternative_service(kProtoHTTP2, "bar", 443); base::Time expiration = base::Time::Now() - base::TimeDelta::FromDays(1); - const AlternativeServiceInfo alternative_service_info(alternative_service, - expiration); + const AlternativeServiceInfo alternative_service_info = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service, expiration); std::unique_ptr<AlternativeServiceMap> alternative_service_map = base::MakeUnique<AlternativeServiceMap>( AlternativeServiceMap::NO_AUTO_EVICT); @@ -536,8 +554,9 @@ url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); const AlternativeService alternative_service(kProtoHTTP2, "", 443); base::Time expiration = base::Time::Now() - base::TimeDelta::FromDays(1); - const AlternativeServiceInfo alternative_service_info(alternative_service, - expiration); + const AlternativeServiceInfo alternative_service_info = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service, expiration); std::unique_ptr<AlternativeServiceMap> alternative_service_map = base::MakeUnique<AlternativeServiceMap>( AlternativeServiceMap::NO_AUTO_EVICT); @@ -571,8 +590,10 @@ url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); const AlternativeService alternative_service(kProtoQUIC, "", 443); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - const AlternativeServiceInfo alternative_service_info(alternative_service, - expiration); + const AlternativeServiceInfo alternative_service_info = + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); impl_.SetAlternativeServices( canonical_server, @@ -646,10 +667,12 @@ AlternativeServiceInfoVector alternative_service_info_vector2; base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); alternative_service_info_vector2.push_back( - AlternativeServiceInfo(alternative_service1, expiration)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service1, expiration)); const AlternativeService alternative_service2(kProtoHTTP2, "foo", 1234); alternative_service_info_vector2.push_back( - AlternativeServiceInfo(alternative_service2, expiration)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service2, expiration)); impl_.SetAlternativeServices(test_server, alternative_service_info_vector2); alternative_service_info_vector = impl_.GetAlternativeServiceInfos(test_server); @@ -680,13 +703,15 @@ // GetAlternativeServiceInfos(). const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service1, now - one_day)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service1, now - one_day)); // Second alterrnative service will expire one day from now, should be // returned by GetAlternativeSerices(). const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service2, now + one_day)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service2, now + one_day)); url::SchemeHostPort test_server("http", "foo", 80); impl_.SetAlternativeServices(test_server, alternative_service_info_vector); @@ -707,13 +732,15 @@ // GetAlternativeServiceInfos(). const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service1, now - one_day)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service1, now - one_day)); // Second alterrnative service will expire one day from now, should be // returned by GetAlternativeSerices(). const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service2, now + one_day)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service2, now + one_day)); url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); impl_.SetAlternativeServices(canonical_server, @@ -732,10 +759,12 @@ const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service1, expiration)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service1, expiration)); const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service2, expiration)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service2, expiration)); // Set Alt-Svc list for |http_server|. url::SchemeHostPort http_server("http", "foo", 80); impl_.SetAlternativeServices(http_server, alternative_service_info_vector); @@ -768,10 +797,12 @@ const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service1, expiration)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service1, expiration)); const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service2, expiration)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service2, expiration)); url::SchemeHostPort test_server("http", "foo", 80); impl_.SetAlternativeServices(test_server, alternative_service_info_vector); @@ -857,10 +888,13 @@ kProtoQUIC, "bar.c.youtube.com", 1234); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back( - AlternativeServiceInfo(canonical_alternative_service1, expiration)); + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + canonical_alternative_service1, expiration, + HttpNetworkSession::Params().quic_supported_versions)); const AlternativeService canonical_alternative_service2(kProtoHTTP2, "", 443); alternative_service_info_vector.push_back( - AlternativeServiceInfo(canonical_alternative_service2, expiration)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + canonical_alternative_service2, expiration)); impl_.SetAlternativeServices(canonical_server, alternative_service_info_vector);
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc index d348d199..00a82ed 100644 --- a/net/http/http_server_properties_manager.cc +++ b/net/http/http_server_properties_manager.cc
@@ -62,6 +62,7 @@ const char kHostKey[] = "host"; const char kPortKey[] = "port"; const char kExpirationKey[] = "expiration"; +const char kAdvertisedVersionsKey[] = "advertised_versions"; const char kNetworkStatsKey[] = "network_stats"; const char kSrttKey[] = "srtt"; @@ -211,12 +212,12 @@ return http_server_properties_impl_->GetAlternativeServiceInfos(origin); } -bool HttpServerPropertiesManager::SetAlternativeService( +bool HttpServerPropertiesManager::SetHttp2AlternativeService( const url::SchemeHostPort& origin, const AlternativeService& alternative_service, base::Time expiration) { DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); - const bool changed = http_server_properties_impl_->SetAlternativeService( + const bool changed = http_server_properties_impl_->SetHttp2AlternativeService( origin, alternative_service, expiration); if (changed) { ScheduleUpdatePrefsOnNetworkSequence(SET_ALTERNATIVE_SERVICES); @@ -224,6 +225,20 @@ return changed; } +bool HttpServerPropertiesManager::SetQuicAlternativeService( + const url::SchemeHostPort& origin, + const AlternativeService& alternative_service, + base::Time expiration, + const QuicVersionVector& advertised_versions) { + DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); + const bool changed = http_server_properties_impl_->SetQuicAlternativeService( + origin, alternative_service, expiration, advertised_versions); + if (changed) { + ScheduleUpdatePrefsOnNetworkSequence(SET_ALTERNATIVE_SERVICES); + } + return changed; +} + bool HttpServerPropertiesManager::SetAlternativeServices( const url::SchemeHostPort& origin, const AlternativeServiceInfoVector& alternative_service_info_vector) { @@ -636,22 +651,48 @@ } std::string expiration_string; - if (alternative_service_dict.GetStringWithoutPathExpansion( + if (!alternative_service_dict.GetStringWithoutPathExpansion( kExpirationKey, &expiration_string)) { - int64_t expiration_int64 = 0; - if (!base::StringToInt64(expiration_string, &expiration_int64)) { - DVLOG(1) << "Malformed alternative service expiration for server: " + DVLOG(1) << "Malformed alternative service expiration for server: " + << server_str; + return false; + } + + int64_t expiration_int64 = 0; + if (!base::StringToInt64(expiration_string, &expiration_int64)) { + DVLOG(1) << "Malformed alternative service expiration for server: " + << server_str; + return false; + } + alternative_service_info->set_expiration( + base::Time::FromInternalValue(expiration_int64)); + + // Advertised versions list is optional. + if (!alternative_service_dict.HasKey(kAdvertisedVersionsKey)) + return true; + + const base::ListValue* versions_list = nullptr; + if (!alternative_service_dict.GetListWithoutPathExpansion( + kAdvertisedVersionsKey, &versions_list)) { + DVLOG(1) + << "Malformed alternative service advertised versions list for server: " + << server_str; + return false; + } + + QuicVersionVector advertised_versions; + for (const auto& value : *versions_list) { + int version; + if (!value.GetAsInteger(&version)) { + DVLOG(1) << "Malformed alternative service version for server: " << server_str; return false; } - alternative_service_info->set_expiration( - base::Time::FromInternalValue(expiration_int64)); - return true; + advertised_versions.push_back(QuicVersion(version)); } + alternative_service_info->set_advertised_versions(advertised_versions); - DVLOG(1) << "Malformed alternative service expiration for server: " - << server_str; - return false; + return true; } bool HttpServerPropertiesManager::AddToAlternativeServiceMap( @@ -1121,6 +1162,13 @@ kExpirationKey, base::Int64ToString( alternative_service_info.expiration().ToInternalValue())); + std::unique_ptr<base::ListValue> advertised_versions_list = + base::MakeUnique<base::ListValue>(); + for (const auto& version : alternative_service_info.advertised_versions()) { + advertised_versions_list->AppendInteger(version); + } + alternative_service_dict->SetList(kAdvertisedVersionsKey, + std::move(advertised_versions_list)); alternative_service_list->Append(std::move(alternative_service_dict)); } if (alternative_service_list->GetSize() == 0)
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h index a2a753ac..bb2132f90 100644 --- a/net/http/http_server_properties_manager.h +++ b/net/http/http_server_properties_manager.h
@@ -129,9 +129,14 @@ SSLConfig* ssl_config) override; AlternativeServiceInfoVector GetAlternativeServiceInfos( const url::SchemeHostPort& origin) override; - bool SetAlternativeService(const url::SchemeHostPort& origin, - const AlternativeService& alternative_service, - base::Time expiration) override; + bool SetHttp2AlternativeService(const url::SchemeHostPort& origin, + const AlternativeService& alternative_service, + base::Time expiration) override; + bool SetQuicAlternativeService( + const url::SchemeHostPort& origin, + const AlternativeService& alternative_service, + base::Time expiration, + const QuicVersionVector& advertised_versions) override; bool SetAlternativeServices(const url::SchemeHostPort& origin, const AlternativeServiceInfoVector& alternative_service_info_vector) override; @@ -246,6 +251,8 @@ FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest, AddToAlternativeServiceMap); FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest, + ReadAdvertisedVersionsFromPref); + FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest, DoNotLoadAltSvcForInsecureOrigins); FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest, DoNotLoadExpiredAlternativeService);
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc index d8dada1..7d7158a9 100644 --- a/net/http/http_server_properties_manager_unittest.cc +++ b/net/http/http_server_properties_manager_unittest.cc
@@ -22,6 +22,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "net/base/ip_address.h" +#include "net/http/http_network_session.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -164,6 +165,7 @@ void SetUp() override { one_day_from_now_ = base::Time::Now() + base::TimeDelta::FromDays(1); + advertised_versions_ = HttpNetworkSession::Params().quic_supported_versions; pref_delegate_ = new MockPrefDelegate; http_server_props_manager_.reset( new StrictMock<TestingHttpServerPropertiesManager>( @@ -239,6 +241,7 @@ std::unique_ptr<TestingHttpServerPropertiesManager> http_server_props_manager_; base::Time one_day_from_now_; + QuicVersionVector advertised_versions_; // Overrides the main thread's message loop with a mock tick clock. Making the // main thread the |pref_test_task_runner_| matches expectations better than @@ -708,10 +711,10 @@ EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com", 443); - http_server_props_manager_->SetAlternativeService( + http_server_props_manager_->SetHttp2AlternativeService( spdy_server_mail, alternative_service, one_day_from_now_); // ExpectScheduleUpdatePrefsOnNetworkSequence() should be called only once. - http_server_props_manager_->SetAlternativeService( + http_server_props_manager_->SetHttp2AlternativeService( spdy_server_mail, alternative_service, one_day_from_now_); // Run the task. @@ -742,11 +745,13 @@ const AlternativeService alternative_service1(kProtoHTTP2, "mail.google.com", 443); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service1, one_day_from_now_)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service1, one_day_from_now_)); const AlternativeService alternative_service2(kProtoQUIC, "mail.google.com", 1234); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service2, one_day_from_now_)); + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service2, one_day_from_now_, advertised_versions_)); http_server_props_manager_->SetAlternativeServices( spdy_server_mail, alternative_service_info_vector); // ExpectScheduleUpdatePrefsOnNetworkSequence() should be called only once. @@ -804,7 +809,7 @@ AlternativeService(kProtoHTTP2, "mail.google.com", 443); ExpectScheduleUpdatePrefsOnNetworkSequence(); - http_server_props_manager_->SetAlternativeService( + http_server_props_manager_->SetHttp2AlternativeService( spdy_server_mail, alternative_service, one_day_from_now_); EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken( @@ -977,7 +982,7 @@ http_server_props_manager_->SetSupportsSpdy(spdy_server, true); AlternativeService alternative_service(kProtoHTTP2, "mail.google.com", 1234); - http_server_props_manager_->SetAlternativeService( + http_server_props_manager_->SetHttp2AlternativeService( spdy_server, alternative_service, one_day_from_now_); http_server_props_manager_->SetSupportsQuic(true, actual_address); ServerNetworkStats stats; @@ -1149,20 +1154,23 @@ base::Time expiration1; ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); alternative_service_info_vector.push_back( - AlternativeServiceInfo(www_alternative_service1, expiration1)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + www_alternative_service1, expiration1)); + AlternativeService www_alternative_service2(kProtoHTTP2, "www.google.com", 1234); base::Time expiration2; ASSERT_TRUE(base::Time::FromUTCString("2036-12-31 10:00:00", &expiration2)); alternative_service_info_vector.push_back( - AlternativeServiceInfo(www_alternative_service2, expiration2)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + www_alternative_service2, expiration2)); ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices( server_www, alternative_service_info_vector)); AlternativeService mail_alternative_service(kProtoHTTP2, "foo.google.com", 444); base::Time expiration3 = base::Time::Max(); - ASSERT_TRUE(http_server_props_manager_->SetAlternativeService( + ASSERT_TRUE(http_server_props_manager_->SetHttp2AlternativeService( server_mail, mail_alternative_service, expiration3)); // #3: Set ServerNetworkStats. @@ -1194,17 +1202,15 @@ const char expected_json[] = "{\"quic_servers\":{\"https://" "mail.google.com:80\":{\"server_info\":\"quic_server_info1\"}}," - "\"servers\":[" - "{\"https://www.google.com:80\":{" - "\"alternative_service\":[{\"expiration\":\"13756212000000000\"," - "\"port\":443,\"protocol_str\":\"h2\"}," - "{\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\"," - "\"port\":1234,\"protocol_str\":\"h2\"}]}}," + "\"servers\":[{\"https://www.google.com:80\":{" + "\"alternative_service\":[{\"advertised_versions\":[],\"expiration\":" + "\"13756212000000000\",\"port\":443,\"protocol_str\":\"h2\"}," + "{\"advertised_versions\":[],\"expiration\":\"13758804000000000\"," + "\"host\":\"www.google.com\",\"port\":1234,\"protocol_str\":\"h2\"}]}}," "{\"https://mail.google.com:80\":{\"alternative_service\":[{" - "\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\"," - "\"port\":444,\"protocol_str\":\"h2\"}]," - "\"network_stats\":{\"srtt\":42}}}" - "]," + "\"advertised_versions\":[],\"expiration\":\"9223372036854775807\"," + "\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"h2\"}]," + "\"network_stats\":{\"srtt\":42}}}]," "\"supports_quic\":{\"address\":\"127.0.0.1\",\"used_quic\":true}," "\"version\":5}"; @@ -1337,7 +1343,8 @@ const base::Time time_one_day_later = base::Time::Now() + base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back( - AlternativeServiceInfo(broken_alternative_service, time_one_day_later)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + broken_alternative_service, time_one_day_later)); // #1: MarkAlternativeServiceBroken(). http_server_props_manager_->MarkAlternativeServiceBroken( broken_alternative_service); @@ -1347,15 +1354,17 @@ const base::Time time_one_day_ago = base::Time::Now() - base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back( - AlternativeServiceInfo(expired_alternative_service, time_one_day_ago)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + expired_alternative_service, time_one_day_ago)); const AlternativeService valid_alternative_service( kProtoHTTP2, "valid.example.com", 443); alternative_service_info_vector.push_back( - AlternativeServiceInfo(valid_alternative_service, time_one_day_later)); + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + valid_alternative_service, time_one_day_later)); const url::SchemeHostPort server("https", "www.example.com", 443); - // #2: SetAlternativeService(). + // #2: SetAlternativeServices(). ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices( server, alternative_service_info_vector)); } @@ -1550,4 +1559,237 @@ EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); } +TEST_P(HttpServerPropertiesManagerTest, PersistAdvertisedVersionsToPref) { + ExpectScheduleUpdatePrefsOnNetworkSequenceRepeatedly(5); + + const url::SchemeHostPort server_www("https", "www.google.com", 80); + const url::SchemeHostPort server_mail("https", "mail.google.com", 80); + + // #1 & #2: Set alternate protocol. + AlternativeServiceInfoVector alternative_service_info_vector; + // Quic alternative service set with two advertised QUIC versions. + AlternativeService quic_alternative_service1(kProtoQUIC, "", 443); + base::Time expiration1; + ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); + QuicVersionVector advertised_versions = {QUIC_VERSION_37, QUIC_VERSION_35}; + alternative_service_info_vector.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + quic_alternative_service1, expiration1, advertised_versions)); + // HTTP/2 alternative service should not set any advertised version. + AlternativeService h2_alternative_service(kProtoHTTP2, "www.google.com", + 1234); + base::Time expiration2; + ASSERT_TRUE(base::Time::FromUTCString("2036-12-31 10:00:00", &expiration2)); + alternative_service_info_vector.push_back( + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + h2_alternative_service, expiration2)); + ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices( + server_www, alternative_service_info_vector)); + + // Set another QUIC alternative service with a single advertised QUIC version. + AlternativeService mail_alternative_service(kProtoQUIC, "foo.google.com", + 444); + base::Time expiration3 = base::Time::Max(); + ASSERT_TRUE(http_server_props_manager_->SetQuicAlternativeService( + server_mail, mail_alternative_service, expiration3, + advertised_versions_)); + // #3: Set ServerNetworkStats. + ServerNetworkStats stats; + stats.srtt = base::TimeDelta::FromInternalValue(42); + http_server_props_manager_->SetServerNetworkStats(server_mail, stats); + + // #4: Set quic_server_info string. + QuicServerId mail_quic_server_id("mail.google.com", 80); + std::string quic_server_info1("quic_server_info1"); + http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id, + quic_server_info1); + + // #5: Set SupportsQuic. + IPAddress actual_address(127, 0, 0, 1); + http_server_props_manager_->SetSupportsQuic(true, actual_address); + + // Update Prefs. + ExpectPrefsUpdate(1); + EXPECT_TRUE(net_test_task_runner_->HasPendingTask()); + EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); + net_test_task_runner_->FastForwardUntilNoTasksRemain(); + EXPECT_TRUE(pref_test_task_runner_->HasPendingTask()); + pref_test_task_runner_->FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(net_test_task_runner_->HasPendingTask()); + EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); + + // Verify preferences with correct advertised version field. + const char expected_json[] = + "{\"quic_servers\":{\"https://mail.google.com:80\":{" + "\"server_info\":\"quic_server_info1\"}},\"servers\":[" + "{\"https://www.google.com:80\":{\"alternative_service\":[{" + "\"advertised_versions\":[35,37],\"expiration\":\"13756212000000000\"," + "\"port\":443,\"protocol_str\":\"quic\"},{\"advertised_versions\":[]," + "\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\"," + "\"port\":1234,\"protocol_str\":\"h2\"}]}}," + "{\"https://mail.google.com:80\":{\"alternative_service\":[{" + "\"advertised_versions\":[37],\"expiration\":\"9223372036854775807\"," + "\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"quic\"}]," + "\"network_stats\":{\"srtt\":42}}}],\"supports_quic\":{" + "\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}"; + + const base::Value* http_server_properties = + &pref_delegate_->GetServerProperties(); + std::string preferences_json; + EXPECT_TRUE( + base::JSONWriter::Write(*http_server_properties, &preferences_json)); + EXPECT_EQ(expected_json, preferences_json); +} + +TEST_P(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) { + std::unique_ptr<base::Value> server_value = base::JSONReader::Read( + "{\"alternative_service\":[" + "{\"port\":443,\"protocol_str\":\"quic\"}," + "{\"port\":123,\"protocol_str\":\"quic\"," + "\"expiration\":\"9223372036854775807\"," + "\"advertised_versions\":[37,35]}]}"); + ASSERT_TRUE(server_value); + base::DictionaryValue* server_dict; + ASSERT_TRUE(server_value->GetAsDictionary(&server_dict)); + + const url::SchemeHostPort server("https", "example.com", 443); + AlternativeServiceMap alternative_service_map(/*max_size=*/5); + EXPECT_TRUE(http_server_props_manager_->AddToAlternativeServiceMap( + server, *server_dict, &alternative_service_map)); + + AlternativeServiceMap::iterator it = alternative_service_map.Get(server); + ASSERT_NE(alternative_service_map.end(), it); + AlternativeServiceInfoVector alternative_service_info_vector = it->second; + ASSERT_EQ(2u, alternative_service_info_vector.size()); + + // Verify the first alternative service with no advertised version listed. + EXPECT_EQ(kProtoQUIC, + alternative_service_info_vector[0].alternative_service().protocol); + EXPECT_EQ("", alternative_service_info_vector[0].alternative_service().host); + EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port); + // Expiration defaults to one day from now, testing with tolerance. + const base::Time now = base::Time::Now(); + const base::Time expiration = alternative_service_info_vector[0].expiration(); + EXPECT_LE(now + base::TimeDelta::FromHours(23), expiration); + EXPECT_GE(now + base::TimeDelta::FromDays(1), expiration); + EXPECT_TRUE(alternative_service_info_vector[0].advertised_versions().empty()); + + // Verify the second alterntaive service with two advertised versions. + EXPECT_EQ(kProtoQUIC, + alternative_service_info_vector[1].alternative_service().protocol); + EXPECT_EQ("", alternative_service_info_vector[1].alternative_service().host); + EXPECT_EQ(123, alternative_service_info_vector[1].alternative_service().port); + EXPECT_EQ(base::Time::Max(), alternative_service_info_vector[1].expiration()); + // Verify advertised versions. + const QuicVersionVector loaded_advertised_versions = + alternative_service_info_vector[1].advertised_versions(); + EXPECT_EQ(2u, loaded_advertised_versions.size()); + EXPECT_EQ(QUIC_VERSION_35, loaded_advertised_versions[0]); + EXPECT_EQ(QUIC_VERSION_37, loaded_advertised_versions[1]); +} + +TEST_P(HttpServerPropertiesManagerTest, + UpdatePrefWhenAdvertisedVersionsChange) { + ExpectScheduleUpdatePrefsOnNetworkSequenceRepeatedly(4); + + const url::SchemeHostPort server_www("https", "www.google.com", 80); + + // #1: Set alternate protocol. + AlternativeServiceInfoVector alternative_service_info_vector; + // Quic alternative service set with a single QUIC version: QUIC_VERSION_37. + AlternativeService quic_alternative_service1(kProtoQUIC, "", 443); + base::Time expiration1; + ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); + alternative_service_info_vector.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + quic_alternative_service1, expiration1, advertised_versions_)); + ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices( + server_www, alternative_service_info_vector)); + + // Set quic_server_info string. + QuicServerId mail_quic_server_id("mail.google.com", 80); + std::string quic_server_info1("quic_server_info1"); + http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id, + quic_server_info1); + + // Set SupportsQuic. + IPAddress actual_address(127, 0, 0, 1); + http_server_props_manager_->SetSupportsQuic(true, actual_address); + + // Update Prefs. + ExpectPrefsUpdate(1); + EXPECT_TRUE(net_test_task_runner_->HasPendingTask()); + EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); + net_test_task_runner_->FastForwardUntilNoTasksRemain(); + EXPECT_TRUE(pref_test_task_runner_->HasPendingTask()); + pref_test_task_runner_->FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(net_test_task_runner_->HasPendingTask()); + EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); + + // Verify preferences with correct advertised version field. + const char expected_json[] = + "{\"quic_servers\":{\"https://mail.google.com:80\":" + "{\"server_info\":\"quic_server_info1\"}},\"servers\":[" + "{\"https://www.google.com:80\":" + "{\"alternative_service\":[{\"advertised_versions\":[37]," + "\"expiration\":\"13756212000000000\",\"port\":443," + "\"protocol_str\":\"quic\"}]}}],\"supports_quic\":" + "{\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}"; + + const base::Value* http_server_properties = + &pref_delegate_->GetServerProperties(); + std::string preferences_json; + EXPECT_TRUE( + base::JSONWriter::Write(*http_server_properties, &preferences_json)); + EXPECT_EQ(expected_json, preferences_json); + + // #2: Set AlternativeService with different advertised_versions for the same + // AlternativeService. + AlternativeServiceInfoVector alternative_service_info_vector_2; + // Quic alternative service set with two advertised QUIC versions. + QuicVersionVector advertised_versions = {QUIC_VERSION_37, QUIC_VERSION_35}; + alternative_service_info_vector_2.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + quic_alternative_service1, expiration1, advertised_versions)); + ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices( + server_www, alternative_service_info_vector_2)); + + // Update Prefs. + ExpectPrefsUpdate(1); + EXPECT_TRUE(net_test_task_runner_->HasPendingTask()); + EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); + net_test_task_runner_->FastForwardUntilNoTasksRemain(); + EXPECT_TRUE(pref_test_task_runner_->HasPendingTask()); + pref_test_task_runner_->FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(net_test_task_runner_->HasPendingTask()); + EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); + + // Verify preferences updated with new advertised versions. + const char expected_json_updated[] = + "{\"quic_servers\":{\"https://mail.google.com:80\":" + "{\"server_info\":\"quic_server_info1\"}},\"servers\":[" + "{\"https://www.google.com:80\":" + "{\"alternative_service\":[{\"advertised_versions\":[35,37]," + "\"expiration\":\"13756212000000000\",\"port\":443," + "\"protocol_str\":\"quic\"}]}}],\"supports_quic\":" + "{\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}"; + EXPECT_TRUE( + base::JSONWriter::Write(*http_server_properties, &preferences_json)); + EXPECT_EQ(expected_json_updated, preferences_json); + + // #3: Set AlternativeService with same advertised_versions. + AlternativeServiceInfoVector alternative_service_info_vector_3; + // A same set of QUIC versions but listed in a different order. + QuicVersionVector advertised_versions_2 = {QUIC_VERSION_35, QUIC_VERSION_37}; + alternative_service_info_vector_3.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + quic_alternative_service1, expiration1, advertised_versions_2)); + ASSERT_FALSE(http_server_props_manager_->SetAlternativeServices( + server_www, alternative_service_info_vector_3)); + + // No Prefs update. + EXPECT_FALSE(net_test_task_runner_->HasPendingTask()); + EXPECT_FALSE(pref_test_task_runner_->HasPendingTask()); +} + } // namespace net
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index 2c7eed6..4c21ffce 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc
@@ -51,19 +51,17 @@ !IsPortValid(alternative_service_entry.port)) { continue; } - // Check if QUIC version is supported. + // Check if QUIC version is supported. Filter supported QUIC versions. + QuicVersionVector advertised_versions; if (protocol == kProtoQUIC && !alternative_service_entry.version.empty()) { bool match_found = false; for (QuicVersion supported : session->params().quic_supported_versions) { for (uint16_t advertised : alternative_service_entry.version) { if (supported == advertised) { match_found = true; - break; + advertised_versions.push_back(supported); } } - if (match_found) { - break; - } } if (!match_found) { continue; @@ -75,8 +73,16 @@ base::Time expiration = base::Time::Now() + base::TimeDelta::FromSeconds(alternative_service_entry.max_age); - AlternativeServiceInfo alternative_service_info(alternative_service, - expiration); + AlternativeServiceInfo alternative_service_info; + if (protocol == kProtoQUIC) { + alternative_service_info = + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service, expiration, advertised_versions); + } else { + alternative_service_info = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service, expiration); + } alternative_service_info_vector.push_back(alternative_service_info); }
diff --git a/net/http/http_stream_factory_impl_job_controller_unittest.cc b/net/http/http_stream_factory_impl_job_controller_unittest.cc index 42b823e..1a46a95 100644 --- a/net/http/http_stream_factory_impl_job_controller_unittest.cc +++ b/net/http/http_stream_factory_impl_job_controller_unittest.cc
@@ -157,10 +157,20 @@ HttpStreamFactoryImpl::JobController* job_controller) { return job_controller->main_job_is_blocked_; } + static bool main_job_is_resumed( HttpStreamFactoryImpl::JobController* job_controller) { return job_controller->main_job_is_resumed_; } + + static AlternativeServiceInfo GetAlternativeServiceInfoFor( + HttpStreamFactoryImpl::JobController* job_controller, + const HttpRequestInfo& request_info, + HttpStreamRequest::Delegate* delegate, + HttpStreamRequest::StreamType stream_type) { + return job_controller->GetAlternativeServiceInfoFor(request_info, delegate, + stream_type); + } }; class HttpStreamFactoryImplJobControllerTest : public ::testing::Test { @@ -253,8 +263,14 @@ HostPortPair host_port_pair = HostPortPair::FromURL(request_info.url); url::SchemeHostPort server(request_info.url); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - session_->http_server_properties()->SetAlternativeService( - server, alternative_service, expiration); + if (alternative_service.protocol == kProtoQUIC) { + session_->http_server_properties()->SetQuicAlternativeService( + server, alternative_service, expiration, + session_->params().quic_supported_versions); + } else { + session_->http_server_properties()->SetHttp2AlternativeService( + server, alternative_service, expiration); + } } void VerifyBrokenAlternateProtocolMapping(const HttpRequestInfo& request_info, @@ -2069,6 +2085,57 @@ EXPECT_TRUE(HttpStreamFactoryImplPeer::IsJobControllerDeleted(factory_)); } +// Test that GetAlternativeServiceInfoFor will include a list of advertised +// versions. Returns an empty list if advertised versions are missing in +// HttpServerProperties. +TEST_F(HttpStreamFactoryImplJobControllerTest, GetAlternativeServiceInfoFor) { + HttpRequestInfo request_info; + request_info.method = "GET"; + request_info.url = GURL("https://www.google.com"); + + Initialize(request_info); + url::SchemeHostPort server(request_info.url); + AlternativeService alternative_service(kProtoQUIC, server.host(), 443); + HostPortPair host_port_pair = HostPortPair::FromURL(request_info.url); + base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); + + // Set alternative service with no advertised version. + session_->http_server_properties()->SetQuicAlternativeService( + server, alternative_service, expiration, QuicVersionVector()); + + AlternativeServiceInfo alt_svc_info = + JobControllerPeer::GetAlternativeServiceInfoFor( + job_controller_, request_info, &request_delegate_, + HttpStreamRequest::HTTP_STREAM); + // Verify that JobController get an empty list of supported QUIC versions. + EXPECT_TRUE(alt_svc_info.advertised_versions().empty()); + + // Set alternative service for the same server with QUIC_VERSION_39 specified. + ASSERT_TRUE(session_->http_server_properties()->SetQuicAlternativeService( + server, alternative_service, expiration, {QUIC_VERSION_39})); + + alt_svc_info = JobControllerPeer::GetAlternativeServiceInfoFor( + job_controller_, request_info, &request_delegate_, + HttpStreamRequest::HTTP_STREAM); + EXPECT_EQ(1u, alt_svc_info.advertised_versions().size()); + // Verify that JobController returns the single version specified in set. + EXPECT_EQ(QUIC_VERSION_39, alt_svc_info.advertised_versions()[0]); + + // Set alternative service for the same server with two QUIC versions: + // QUIC_VERSION_35, QUIC_VERSION_39. + ASSERT_TRUE(session_->http_server_properties()->SetQuicAlternativeService( + server, alternative_service, expiration, + {QUIC_VERSION_35, QUIC_VERSION_39})); + + alt_svc_info = JobControllerPeer::GetAlternativeServiceInfoFor( + job_controller_, request_info, &request_delegate_, + HttpStreamRequest::HTTP_STREAM); + EXPECT_EQ(2u, alt_svc_info.advertised_versions().size()); + // Verify that JobController returns the list of versions specified in set. + EXPECT_EQ(QUIC_VERSION_35, alt_svc_info.advertised_versions()[0]); + EXPECT_EQ(QUIC_VERSION_39, alt_svc_info.advertised_versions()[1]); +} + } // namespace test } // namespace net
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc index a78660f..0941fdc9 100644 --- a/net/http/http_stream_factory_impl_unittest.cc +++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -1109,20 +1109,6 @@ for (int num_streams = 1; num_streams < 3; ++num_streams) { GURL url = GURL("https://www.google.com"); - // Set up QUIC as alternative_service. - HttpServerPropertiesImpl http_server_properties; - const AlternativeService alternative_service(kProtoQUIC, url.host().c_str(), - url.IntPort()); - AlternativeServiceInfoVector alternative_service_info_vector; - base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service, expiration)); - HostPortPair host_port_pair(alternative_service.host_port_pair()); - url::SchemeHostPort server("https", host_port_pair.host(), - host_port_pair.port()); - http_server_properties.SetAlternativeServices( - server, alternative_service_info_vector); - SpdySessionDependencies session_deps( ProxyService::CreateFixed("http_proxy")); @@ -1131,6 +1117,18 @@ SpdySessionDependencies::CreateSessionParams(&session_deps); session_params.enable_quic = true; + // Set up QUIC as alternative_service. + HttpServerPropertiesImpl http_server_properties; + const AlternativeService alternative_service(kProtoQUIC, url.host().c_str(), + url.IntPort()); + base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); + HostPortPair host_port_pair(alternative_service.host_port_pair()); + url::SchemeHostPort server("https", host_port_pair.host(), + host_port_pair.port()); + http_server_properties.SetQuicAlternativeService( + server, alternative_service, expiration, + session_params.quic_supported_versions); + HttpNetworkSession::Context session_context = SpdySessionDependencies::CreateSessionContext(&session_deps); session_context.http_server_properties = &http_server_properties; @@ -2272,12 +2270,10 @@ void AddQuicAlternativeService() { const AlternativeService alternative_service(kProtoQUIC, "www.example.org", 443); - AlternativeServiceInfoVector alternative_service_info_vector; base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service, expiration)); - http_server_properties_.SetAlternativeServices( - url::SchemeHostPort(default_url_), alternative_service_info_vector); + http_server_properties_.SetQuicAlternativeService( + url::SchemeHostPort(default_url_), alternative_service, expiration, + session_->params().quic_supported_versions); } test::QuicTestPacketMaker& client_packet_maker() { @@ -2352,8 +2348,8 @@ socket_factory().AddSSLSocketDataProvider(&ssl_data); // Set up QUIC as alternative_service. - AddQuicAlternativeService(); Initialize(); + AddQuicAlternativeService(); // Now request a stream. SSLConfig ssl_config; @@ -2416,9 +2412,9 @@ socket_factory().AddSSLSocketDataProvider(&ssl_data); // Set up QUIC as alternative_service. - AddQuicAlternativeService(); DisableQuicBidirectionalStream(); Initialize(); + AddQuicAlternativeService(); // Now request a stream. SSLConfig ssl_config; @@ -2478,8 +2474,8 @@ socket_factory().AddSSLSocketDataProvider(&ssl_data); // Set up QUIC as alternative_service. - AddQuicAlternativeService(); Initialize(); + AddQuicAlternativeService(); // Now request a stream. SSLConfig ssl_config;
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc index 5afabad..9548757 100644 --- a/net/quic/chromium/quic_network_transaction_unittest.cc +++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -14,6 +14,7 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/test/histogram_tester.h" #include "net/base/chunked_upload_data_stream.h" @@ -127,6 +128,17 @@ DestinationType destination_type; }; +std::string GenerateQuicVersionsListForAltSvcHeader( + const QuicVersionVector& versions) { + std::string result = ""; + for (const QuicVersion& version : versions) { + if (!result.empty()) + result.append(","); + result.append(base::IntToString(version)); + } + return result; +} + std::vector<PoolingTestParams> GetPoolingTestParams() { std::vector<PoolingTestParams> params; QuicVersionVector all_supported_versions = AllSupportedVersions(); @@ -499,9 +511,9 @@ std::move(headers), offset); } - void CreateSession() { + void CreateSession(const QuicVersionVector& supported_versions) { session_params_.enable_quic = true; - session_params_.quic_supported_versions = SupportedVersions(version_); + session_params_.quic_supported_versions = supported_versions; session_context_.quic_clock = &clock_; session_context_.quic_random = &random_generator_; @@ -526,6 +538,8 @@ session_->quic_stream_factory()->set_require_confirmation(false); } + void CreateSession() { return CreateSession(SupportedVersions(version_)); } + void CheckWasQuicResponse(HttpNetworkTransaction* trans) { const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != nullptr); @@ -611,8 +625,9 @@ url::SchemeHostPort server(request_.url); AlternativeService alternative_service(kProtoQUIC, server.host(), 443); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties_.SetAlternativeService(server, alternative_service, - expiration); + http_server_properties_.SetQuicAlternativeService( + server, alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); } void AddQuicRemoteAlternativeServiceMapping( @@ -623,8 +638,9 @@ AlternativeService alternative_service(kProtoQUIC, alternative.host(), alternative.port()); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties_.SetAlternativeService(server, alternative_service, - expiration); + http_server_properties_.SetQuicAlternativeService( + server, alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); } void ExpectBrokenAlternateProtocolMapping() { @@ -1187,8 +1203,9 @@ AlternativeService alternative_service(kProtoQUIC, kDefaultServerHostName, 443); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties_.SetAlternativeService(server, alternative_service, - expiration); + http_server_properties_.SetQuicAlternativeService( + server, alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); // First try: The alternative job uses QUIC and reports an HTTP 421 // Misdirected Request error. The main job uses TCP, but |http_data| below is @@ -1448,6 +1465,74 @@ SendRequestAndExpectHttpResponse("hello world"); } +TEST_P(QuicNetworkTransactionTest, + StoreMutuallySupportedVersionsWhenProcessAltSvc) { + std::string advertised_versions_list_str = + GenerateQuicVersionsListForAltSvcHeader(AllSupportedVersions()); + std::string altsvc_header = + base::StringPrintf("Alt-Svc: quic=\":443\"; v=\"%s\"\r\n\r\n", + advertised_versions_list_str.c_str()); + MockRead http_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), MockRead(altsvc_header.c_str()), + MockRead("hello world"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK)}; + + StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr, + 0); + socket_factory_.AddSocketDataProvider(&http_data); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + MockQuicData mock_quic_data; + QuicStreamOffset header_stream_offset = 0; + mock_quic_data.AddWrite( + ConstructInitialSettingsPacket(1, &header_stream_offset)); + mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( + 2, GetNthClientInitiatedStreamId(0), true, true, + GetRequestHeaders("GET", "https", "/"), &header_stream_offset)); + mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( + 1, GetNthClientInitiatedStreamId(0), false, false, + GetResponseHeaders("200 OK"))); + mock_quic_data.AddRead(ConstructServerDataPacket( + 2, GetNthClientInitiatedStreamId(0), false, true, 0, "hello!")); + mock_quic_data.AddWrite(ConstructClientAckPacket(3, 2, 1, 1)); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data.AddRead(ASYNC, 0); // EOF + + mock_quic_data.AddSocketDataToFactory(&socket_factory_); + + AddHangingNonAlternateProtocolSocketData(); + + // Generate a list of QUIC versions suppored by netstack. + QuicVersionVector current_supported_versions = SupportedVersions(version_); + if (version_ != QUIC_VERSION_40) { + current_supported_versions.push_back(QUIC_VERSION_40); + } else { + current_supported_versions.push_back(QUIC_VERSION_37); + } + + CreateSession(current_supported_versions); + + SendRequestAndExpectHttpResponse("hello world"); + SendRequestAndExpectQuicResponse("hello!"); + + // Check alternative service is set with only mutually supported versions. + const url::SchemeHostPort https_server(request_.url); + const AlternativeServiceInfoVector alt_svc_info_vector = + session_->http_server_properties()->GetAlternativeServiceInfos( + https_server); + EXPECT_EQ(1u, alt_svc_info_vector.size()); + EXPECT_EQ(kProtoQUIC, alt_svc_info_vector[0].alternative_service().protocol); + EXPECT_EQ(2u, alt_svc_info_vector[0].advertised_versions().size()); + // Advertised versions will be lised in a sorted order. + std::sort(current_supported_versions.begin(), + current_supported_versions.end()); + EXPECT_EQ(current_supported_versions[0], + alt_svc_info_vector[0].advertised_versions()[0]); + EXPECT_EQ(current_supported_versions[1], + alt_svc_info_vector[0].advertised_versions()[1]); +} + TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceAllSupportedVersion) { std::string altsvc_header = base::StringPrintf("Alt-Svc: quic=\":443\"; v=\"%u\"\r\n\r\n", version_); @@ -2777,15 +2862,17 @@ // Set up alternative service for |origin1|. base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties_.SetAlternativeService( + http_server_properties_.SetQuicAlternativeService( url::SchemeHostPort(origin1), - AlternativeService(kProtoQUIC, "mail.example.com", 443), expiration); + AlternativeService(kProtoQUIC, "mail.example.com", 443), expiration, + HttpNetworkSession::Params().quic_supported_versions); // Set up alternative service for |origin2|. AlternativeServiceInfoVector alternative_services; - http_server_properties_.SetAlternativeService( + http_server_properties_.SetQuicAlternativeService( url::SchemeHostPort(origin2), - AlternativeService(kProtoQUIC, "www.example.com", 443), expiration); + AlternativeService(kProtoQUIC, "www.example.com", 443), expiration, + HttpNetworkSession::Params().quic_supported_versions); // First request opens connection to |destination1| // with QuicServerId.host() == origin1.host(). SendRequestAndExpectQuicResponse("hello!"); @@ -3008,16 +3095,18 @@ url::SchemeHostPort server(request_.url); AlternativeService alternative_service(kProtoQUIC, destination1, 443); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties_.SetAlternativeService(server, alternative_service, - expiration); + http_server_properties_.SetQuicAlternativeService( + server, alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); // First request opens connection to |destination1| // with QuicServerId.host() == kDefaultServerHostName. SendRequestAndExpectQuicResponse("hello!"); // Set up alternative service entry to a different destination. alternative_service = AlternativeService(kProtoQUIC, destination2, 443); - http_server_properties_.SetAlternativeService(server, alternative_service, - expiration); + http_server_properties_.SetQuicAlternativeService( + server, alternative_service, expiration, + HttpNetworkSession::Params().quic_supported_versions); // Second request pools to existing connection with same QuicServerId, // even though alternative service destination is different. SendRequestAndExpectQuicResponse("hello!"); @@ -3080,8 +3169,9 @@ // Set up alternative service for |origin1|. AlternativeService alternative_service1(kProtoQUIC, destination1, 443); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties_.SetAlternativeService( - url::SchemeHostPort(origin1), alternative_service1, expiration); + http_server_properties_.SetQuicAlternativeService( + url::SchemeHostPort(origin1), alternative_service1, expiration, + HttpNetworkSession::Params().quic_supported_versions); // Set up multiple alternative service entries for |origin2|, // the first one with a different destination as for |origin1|, @@ -3090,9 +3180,13 @@ AlternativeService alternative_service2(kProtoQUIC, destination2, 443); AlternativeServiceInfoVector alternative_services; alternative_services.push_back( - AlternativeServiceInfo(alternative_service2, expiration)); + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service2, expiration, + session_->params().quic_supported_versions)); alternative_services.push_back( - AlternativeServiceInfo(alternative_service1, expiration)); + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service1, expiration, + session_->params().quic_supported_versions)); http_server_properties_.SetAlternativeServices(url::SchemeHostPort(origin2), alternative_services); // First request opens connection to |destination1| @@ -4653,7 +4747,7 @@ session_.reset(); } - void SetAlternativeService(const std::string& origin) { + void SetQuicAlternativeService(const std::string& origin) { HostPortPair destination; switch (destination_type_) { case SAME_AS_FIRST: @@ -4668,9 +4762,9 @@ } AlternativeService alternative_service(kProtoQUIC, destination); base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); - http_server_properties_.SetAlternativeService( + http_server_properties_.SetQuicAlternativeService( url::SchemeHostPort("https", origin, 443), alternative_service, - expiration); + expiration, session_->params().quic_supported_versions); } std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket( @@ -4841,7 +4935,7 @@ // is valid for the hostname of the alternative service. origin2_ = "mail.example.org"; - SetAlternativeService(origin1_); + SetQuicAlternativeService(origin1_); scoped_refptr<X509Certificate> cert( ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); @@ -4879,8 +4973,8 @@ origin1_ = "mail.example.org"; origin2_ = "news.example.org"; - SetAlternativeService(origin1_); - SetAlternativeService(origin2_); + SetQuicAlternativeService(origin1_); + SetQuicAlternativeService(origin2_); scoped_refptr<X509Certificate> cert( ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); @@ -4951,8 +5045,8 @@ origin1_ = "news.example.org"; origin2_ = "mail.example.com"; - SetAlternativeService(origin1_); - SetAlternativeService(origin2_); + SetQuicAlternativeService(origin1_); + SetQuicAlternativeService(origin2_); scoped_refptr<X509Certificate> cert1( ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc index 8973f83..d97c7ce 100644 --- a/net/quic/chromium/quic_stream_factory_test.cc +++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -487,7 +487,8 @@ AlternativeServiceInfoVector alternative_service_info_vector; base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service1, expiration)); + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service1, expiration, {version_})); http_server_properties_.SetAlternativeServices( url::SchemeHostPort(url_), alternative_service_info_vector); @@ -497,7 +498,8 @@ kProtoQUIC, host_port_pair2.host(), host_port_pair2.port()); AlternativeServiceInfoVector alternative_service_info_vector2; alternative_service_info_vector2.push_back( - AlternativeServiceInfo(alternative_service2, expiration)); + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service2, expiration, {version_})); http_server_properties_.SetAlternativeServices( server2, alternative_service_info_vector2);
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc index 8f2921c..f8bb219 100644 --- a/net/spdy/chromium/spdy_session.cc +++ b/net/spdy/chromium/spdy_session.cc
@@ -3024,19 +3024,17 @@ // so that SpdySession::OnAltSvc and // HttpStreamFactory::ProcessAlternativeServices // could use the the same function. - // Check if QUIC version is supported. + // Check if QUIC version is supported. Filter supported QUIC versions. + QuicVersionVector advertised_versions; if (protocol == kProtoQUIC && !altsvc.version.empty()) { bool match_found = false; for (const QuicVersion& supported : quic_supported_versions_) { for (const uint16_t& advertised : altsvc.version) { if (supported == advertised) { match_found = true; - break; + advertised_versions.push_back(supported); } } - if (match_found) { - break; - } } if (!match_found) { continue; @@ -3047,9 +3045,19 @@ altsvc.port); const base::Time expiration = now + base::TimeDelta::FromSeconds(altsvc.max_age); - alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service, expiration)); + AlternativeServiceInfo alternative_service_info; + if (protocol == kProtoQUIC) { + alternative_service_info = + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + alternative_service, expiration, advertised_versions); + } else { + alternative_service_info = + AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( + alternative_service, expiration); + } + alternative_service_info_vector.push_back(alternative_service_info); } + http_server_properties_->SetAlternativeServices( scheme_host_port, alternative_service_info_vector); }
diff --git a/net/ssl/openssl_ssl_util.cc b/net/ssl/openssl_ssl_util.cc index 21b2b565..a51063d 100644 --- a/net/ssl/openssl_ssl_util.cc +++ b/net/ssl/openssl_ssl_util.cc
@@ -173,26 +173,26 @@ return ERR_FAILED; case SSL_ERROR_SSL: // Walk down the error stack to find an SSL or net error. - uint32_t error_code; - const char* file; - int line; - do { - error_code = ERR_get_error_line(&file, &line); - if (ERR_GET_LIB(error_code) == ERR_LIB_SSL) { - out_error_info->error_code = error_code; - out_error_info->file = file; - out_error_info->line = line; - return MapOpenSSLErrorSSL(error_code); - } else if (ERR_GET_LIB(error_code) == OpenSSLNetErrorLib()) { - out_error_info->error_code = error_code; - out_error_info->file = file; - out_error_info->line = line; + while (true) { + OpenSSLErrorInfo error_info; + error_info.error_code = + ERR_get_error_line(&error_info.file, &error_info.line); + if (error_info.error_code == 0) { + // Map errors to ERR_SSL_PROTOCOL_ERROR by default, reporting the most + // recent error in |*out_error_info|. + return ERR_SSL_PROTOCOL_ERROR; + } + + *out_error_info = error_info; + if (ERR_GET_LIB(error_info.error_code) == ERR_LIB_SSL) { + return MapOpenSSLErrorSSL(error_info.error_code); + } + if (ERR_GET_LIB(error_info.error_code) == OpenSSLNetErrorLib()) { // Net error codes are negative but encoded in OpenSSL as positive // numbers. - return -ERR_GET_REASON(error_code); + return -ERR_GET_REASON(error_info.error_code); } - } while (error_code != 0); - return ERR_FAILED; + } default: // TODO(joth): Implement full mapping. LOG(WARNING) << "Unknown OpenSSL error " << err;
diff --git a/remoting/android/BUILD.gn b/remoting/android/BUILD.gn index 07cbe53..248c1ea0 100644 --- a/remoting/android/BUILD.gn +++ b/remoting/android/BUILD.gn
@@ -20,16 +20,6 @@ jni_package = "remoting" } -generate_jni_registration("remoting_jni_registration") { - target = ":remoting_apk" - output = "$root_gen_dir/remoting/client/${target_name}.h" - exception_files = [ - "//base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "//base/android/java/src/org/chromium/base/library_loader/Linker.java", - "//base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - ] -} - _raw_resources_base_dir = "$target_gen_dir/credits_resources_raw/res" # The target is named this way, instead of "..._raw_resources", specifically
diff --git a/remoting/client/jni/BUILD.gn b/remoting/client/jni/BUILD.gn index 6f10926..f0f8082 100644 --- a/remoting/client/jni/BUILD.gn +++ b/remoting/client/jni/BUILD.gn
@@ -19,7 +19,6 @@ shared_library("remoting_client_jni") { deps = [ "//remoting/android:jni_headers", - "//remoting/android:remoting_jni_registration", "//remoting/base", "//remoting/client", "//remoting/client/display",
diff --git a/remoting/client/jni/remoting_jni_onload.cc b/remoting/client/jni/remoting_jni_onload.cc index dd1a283d..9db79a8 100644 --- a/remoting/client/jni/remoting_jni_onload.cc +++ b/remoting/client/jni/remoting_jni_onload.cc
@@ -11,7 +11,6 @@ #include "base/macros.h" #include "net/android/net_jni_registrar.h" #include "remoting/client/jni/remoting_jni_registrar.h" -#include "remoting/client/remoting_jni_registration.h" #include "ui/gfx/android/gfx_jni_registrar.h" namespace { @@ -33,12 +32,6 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { base::android::InitVM(vm); JNIEnv* env = base::android::AttachCurrentThread(); - if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { - return -1; - } - - // TODO(agrieve): Delete this block, this is a no-op now. - // https://crbug.com/683256. if (!RegisterJNI(env) || !base::android::OnJNIOnLoadInit()) { return -1; }
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn index 8aef9f1..5052a44 100644 --- a/services/ui/ws/BUILD.gn +++ b/services/ui/ws/BUILD.gn
@@ -121,7 +121,7 @@ ] deps = [ - "//components/viz/common", + "//components/viz/host", "//gpu/command_buffer/client", "//gpu/command_buffer/client:gles2_interface", "//gpu/ipc/client",
diff --git a/services/ui/ws/DEPS b/services/ui/ws/DEPS index 7d99cf9..d714e80d 100644 --- a/services/ui/ws/DEPS +++ b/services/ui/ws/DEPS
@@ -1,5 +1,5 @@ include_rules = [ - "+components/viz/common", + "+components/viz/host", "+gpu/command_buffer/client", "+gpu/config", "+gpu/ipc/client",
diff --git a/services/ui/ws/gpu_client.cc b/services/ui/ws/gpu_client.cc index 72e1e4a..94f38c42 100644 --- a/services/ui/ws/gpu_client.cc +++ b/services/ui/ws/gpu_client.cc
@@ -4,7 +4,7 @@ #include "services/ui/ws/gpu_client.h" -#include "components/viz/common/server_gpu_memory_buffer_manager.h" +#include "components/viz/host/server_gpu_memory_buffer_manager.h" #include "services/ui/gpu/interfaces/gpu_service.mojom.h" namespace {
diff --git a/services/ui/ws/gpu_host.cc b/services/ui/ws/gpu_host.cc index 466c1ef0..0b6d0e6 100644 --- a/services/ui/ws/gpu_host.cc +++ b/services/ui/ws/gpu_host.cc
@@ -9,7 +9,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" -#include "components/viz/common/server_gpu_memory_buffer_manager.h" +#include "components/viz/host/server_gpu_memory_buffer_manager.h" #include "gpu/ipc/client/gpu_channel_host.h" #include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h" #include "mojo/public/cpp/bindings/strong_binding.h"
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 5783190..dcc693ff 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -198,6 +198,10 @@ # define SK_SUPPORT_LEGACY_ANISOTROPIC_MIPMAP_SCALE #endif +#ifndef SK_SUPPORT_BLITV_FOR_BLUR_NINE +#define SK_SUPPORT_BLITV_FOR_BLUR_NINE +#endif + // Remove this after we fixed all the issues related to the new SDF algorithm // (https://codereview.chromium.org/1643143002) #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/MainRunner.java b/testing/android/native_test/java/src/org/chromium/native_test/MainRunner.java index 94aaeef12..cbebb0f 100644 --- a/testing/android/native_test/java/src/org/chromium/native_test/MainRunner.java +++ b/testing/android/native_test/java/src/org/chromium/native_test/MainRunner.java
@@ -14,14 +14,13 @@ */ @JNINamespace("testing::android") public final class MainRunner { - // Prevent instanciation. + // Prevents instantiation. private MainRunner() { } // Maps the file descriptors and executes the main method with the passed in command line. - public static int runMain(String[] commandLine, int[] fdsToMapKeys, int[] fdsToMapFds) { - return nativeRunMain(commandLine, fdsToMapKeys, fdsToMapFds); + public static int runMain(String[] commandLine) { + return nativeRunMain(commandLine); } - private static native int nativeRunMain( - String[] commandLine, int[] fdsToMapKeys, int[] fdsToMapFds); + private static native int nativeRunMain(String[] commandLine); } \ No newline at end of file
diff --git a/testing/android/native_test/main_runner.cc b/testing/android/native_test/main_runner.cc index 2dc41f3..fc993eb 100644 --- a/testing/android/native_test/main_runner.cc +++ b/testing/android/native_test/main_runner.cc
@@ -6,7 +6,6 @@ #include "base/android/jni_array.h" #include "base/logging.h" -#include "base/posix/global_descriptors.h" #include "jni/MainRunner_jni.h" #include "testing/android/native_test/native_test_util.h" @@ -22,9 +21,7 @@ static jint RunMain( JNIEnv* env, const base::android::JavaParamRef<jclass>& jcaller, - const base::android::JavaParamRef<jobjectArray>& command_line, - const base::android::JavaParamRef<jintArray>& fds_to_map_keys, - const base::android::JavaParamRef<jintArray>& fds_to_map_fds) { + const base::android::JavaParamRef<jobjectArray>& command_line) { // Guards against process being reused. // In most cases, running main again will cause problems (static variables, // singletons, lazy instances won't be in the same state as a clean run). @@ -32,16 +29,6 @@ CHECK(!alreadyRun); alreadyRun = true; - std::vector<int> keys; - base::android::JavaIntArrayToIntVector(env, fds_to_map_keys, &keys); - std::vector<int> fds; - base::android::JavaIntArrayToIntVector(env, fds_to_map_fds, &fds); - CHECK_EQ(keys.size(), fds.size()); - - for (size_t i = 0; i < keys.size(); i++) { - base::GlobalDescriptors::GetInstance()->Set(keys[i], fds[i]); - } - std::vector<std::string> cpp_command_line; AppendJavaStringArrayToStringVector(env, command_line, &cpp_command_line);
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index f305fcf..4b9eca3d 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -159,6 +159,15 @@ "-v", ], }, + "vrcore_fps_test": { + "label": "//chrome/test/vr/perf:vrcore_fps_test", + "type": "script", + "script": "//chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py", + "args": [ + "--output-dir=${ISOLATED_OUTDIR}", + "-v", + ], + }, "base_junit_tests": { "label": "//base:base_junit_tests", "type": "junit_test",
diff --git a/testing/buildbot/manage.py b/testing/buildbot/manage.py index e733af78..8751b30 100755 --- a/testing/buildbot/manage.py +++ b/testing/buildbot/manage.py
@@ -185,6 +185,7 @@ 'net_junit_tests', 'service_junit_tests', 'ui_junit_tests', + 'vrcore_fps_test', 'webapk_client_junit_tests', 'webapk_shell_apk_junit_tests',
diff --git a/testing/test.gni b/testing/test.gni index 64619b3..36e0d91 100644 --- a/testing/test.gni +++ b/testing/test.gni
@@ -63,7 +63,7 @@ # the default shared_library configs rather than executable configs. configs -= [ "//build/config:shared_library_config", - "//build/config/android:hide_all_but_jni", + "//build/config/android:hide_all_but_jni_onload", ] configs += [ "//build/config:executable_config" ] @@ -321,8 +321,6 @@ set_defaults("test") { if (is_android) { configs = default_shared_library_configs - configs -= [ "//build/config/android:hide_all_but_jni_onload" ] - configs += [ "//build/config/android:hide_all_but_jni" ] } else { configs = default_executable_configs }
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index 452e975c..b2fefadb 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -1801,7 +1801,6 @@ crbug.com/591099 css3/flexbox/child-overflow.html [ Failure Pass ] crbug.com/591099 css3/flexbox/crash-removing-out-of-flow-child.html [ Failure ] crbug.com/591099 css3/flexbox/css-properties.html [ Failure ] -crbug.com/591099 css3/flexbox/definite-cross-sizes.html [ Failure ] crbug.com/591099 css3/flexbox/display-flexbox-set-get.html [ Crash ] crbug.com/591099 css3/flexbox/flex-algorithm-with-margins.html [ Failure ] crbug.com/591099 css3/flexbox/flex-algorithm.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service index ae4c9ff..bce3d22 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -2666,6 +2666,7 @@ Bug(none) inspector-protocol/accessibility/accessibility-nameSources-buttons.js [ Timeout ] Bug(none) inspector-protocol/css/css-get-background-colors.html [ Timeout ] Bug(none) inspector-protocol/css/cssom-modify-rule-and-get-rule-list.html [ Timeout ] +Bug(none) inspector-protocol/dom/dom-request-document-with-child-nodes.js [ Failure ] Bug(none) inspector-protocol/heap-profiler/heap-samples-in-snapshot.html [ Failure ] Bug(none) inspector-protocol/heap-profiler/heap-snapshot-with-active-dom-object.html [ Failure ] Bug(none) inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/fixed-element-in-isolated-composited-ancestor-expected.html b/third_party/WebKit/LayoutTests/compositing/overflow/fixed-element-in-isolated-composited-ancestor-expected.html new file mode 100644 index 0000000..6710eba --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/fixed-element-in-isolated-composited-ancestor-expected.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<style> +body { + margin: 0px; +} + +.scroller { + overflow: scroll; + width: 200px; + height: 600px; +} + +.box { + background: rgba(0, 255, 0, 0.9); + position: relative; + width: 185px; + height: 50px; + top: 200px; +} + +.indicator { + position: absolute; + width: 185px; + height: 50px; + background: red; /* covered up by .box when working */ +} + +.container { + width: 100%; + height: 1000px; + background: grey; +} +</style> + +<div id="scroller" class="scroller"> + <div class="container"> + <div class="indicator"></div> + <div class="box"></div> + </div> +</div> + +<script> + let scroller = document.getElementById('scroller'); + scroller.scrollTop = 200; +</script>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/fixed-element-in-isolated-composited-ancestor.html b/third_party/WebKit/LayoutTests/compositing/overflow/fixed-element-in-isolated-composited-ancestor.html new file mode 100644 index 0000000..e532a68 --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/fixed-element-in-isolated-composited-ancestor.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<style> +body { + margin: 0px; +} + +.scroller { + overflow: scroll; + width: 200px; + height: 600px; +} + +.composited { + backface-visibility: hidden; + isolation: isolate; +} + +.box { + background: rgba(0, 255, 0, 0.9); + position: fixed; + width: 185px; + height: 50px; + top: 0px; +} + +.indicator { + position: absolute; + width: 185px; + height: 50px; + background: red; /* covered up by .box when working */ +} + +.container { + width: 100%; + height: 1000px; + background: grey; +} +</style> + +<div id="scroller" class="scroller"> + <div class="composited container"> + <div class="indicator"></div> + <div class="box"></div> + </div> +</div> + +<script> + if (window.testRunner) + testRunner.waitUntilDone() + + function doTest() { + let scroller = document.getElementById('scroller'); + window.requestAnimationFrame(function() { + scroller.scrollTop = 200; + if (window.testRunner) + testRunner.notifyDone(); + }); + } + + window.addEventListener('load', function() { + window.requestAnimationFrame(function() { + window.requestAnimationFrame(doTest); + }) + }); +</script> +
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/definite-cross-sizes.html b/third_party/WebKit/LayoutTests/css3/flexbox/definite-cross-sizes.html deleted file mode 100644 index 9ab6f07..0000000 --- a/third_party/WebKit/LayoutTests/css3/flexbox/definite-cross-sizes.html +++ /dev/null
@@ -1,130 +0,0 @@ -<!DOCTYPE html> - -<title>CSS Flexbox: Definite cross sizes</title> - -<style> -.rect { - width: 50px; - height: 50px; - background-color: green; -} - -.flexbox { - width: 50px; - outline: 3px solid black; -} - -.flexbox > div > div { - overflow: hidden; -} -</style> - -<link rel="stylesheet" href="resources/flexbox.css"> -<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#definite-sizes"> -<link rel="author" title="Google Inc." href="https://www.google.com/"> - -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../../resources/check-layout-th.js"></script> - -<body onload="checkLayout('.flexbox')" style="height: 800px;"> -<div id=log></div> - -<p>This test verifies that we consider flex items' cross sizes to be definite -if the align value is stretch (the default)</p> - -<p>Tests that we get a definite size in the simple case.</p> -<div class="flexbox" data-expected-height="50"> - <div data-expected-height="50"> - <div style="height: 50%" data-expected-height="25"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> -</div> - -<p>Tests that we get an definite size in a wrapping flexbox</p> -<div class="flexbox wrap" style="height: 50px;" data-expected-height="50"> - <div data-expected-height="50"> - <div style="height: 50%" data-expected-height="25"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> -</div> - -<p>Tests that we get an indefinite size when not stretch-aligning</p> -<div class="flexbox wrap" style="height: 50px;" data-expected-height="50"> - <div class="align-self-flex-start" data-expected-height="50"> - <div style="height: 50%" data-expected-height="50"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> -</div> - -<p>Tests that we get an definite size in a definite-height flexbox</p> -<div class="flexbox" style="height: 50px;" data-expected-height="50"> - <div data-expected-height="50"> - <div style="height: 50%" data-expected-height="25"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> -</div> - -<p>Tests that we get an definite size in a nested flexbox where only the outer one has an explicit height</p> -<div class="flexbox" style="height: 50px;" data-expected-height="50"> - <div class="flexbox" data-expected-height="50"> - <div data-expected-height="50"> - <div style="height: 50%" data-expected-height="25"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> - </div> -</div> - -<p>Tests that we get an definite size in a nested flexbox where only the outer one has an explicit height and has an opposite direction.</p> -<div class="flexbox" style="height: 50px;" data-expected-height="50"> - <div class="flexbox column" data-expected-height="50"> - <div class="flex-one" data-expected-height="50"> - <div style="height: 50%" data-expected-height="25"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> - </div> -</div> - -<p>Tests that we respect min-height</p> -<div class="flexbox" style="height: 50px;" data-expected-height="50"> - <div data-expected-height="50"> - <div style="height: 50%; min-height: 30px;" data-expected-height="30"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> -</div> - -<p>Tests that percentage sizes can also be definite</p> -<div class="flexbox" style="height: 10%;" data-expected-height="80"> - <div data-expected-height="80"> - <div style="height: 50%" data-expected-height="40"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> -</div> - -<p>Tests that we use a definite size even when a percentage size is not definite</p> -<div> - <div class="flexbox" style="height: 10%;" data-expected-height="50"> - <div data-expected-height="50"> - <div style="height: 50%" data-expected-height="25"> - <div class="rect" data-expected-height="50"></div> - </div> - </div> - </div> -</div> - -<p>Tests that we don't mix up widths and heights</p> -<div class="flexbox" style="height: 50px; width: 100px;" data-expected-height="50"> - <div style="width: 100px;" data-expected-height="50" data-expected-width="100"> - <div style="width: 50%" data-expected-width="50"> - <div class="rect" data-expected-height="50" data-expected-width="50"></div> - </div> - </div> -</div>
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json index dc0dd2e..46c04fc7 100644 --- a/third_party/WebKit/Source/core/inspector/browser_protocol.json +++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -2834,7 +2834,7 @@ { "domain": "CSS", "experimental": true, - "description": "This domain exposes CSS read/write operations. All CSS objects (stylesheets, rules, and styles) have an associated <code>id</code> used in subsequent operations on the related object. Each object type has a specific <code>id</code> structure, and those are not interchangeable between objects of different kinds. CSS objects can be loaded using the <code>get*ForNode()</code> calls (which accept a DOM node id). A client can also discover all the existing stylesheets with the <code>getAllStyleSheets()</code> method (or keeping track of the <code>styleSheetAdded</code>/<code>styleSheetRemoved</code> events) and subsequently load the required stylesheet contents using the <code>getStyleSheet[Text]()</code> methods.", + "description": "This domain exposes CSS read/write operations. All CSS objects (stylesheets, rules, and styles) have an associated <code>id</code> used in subsequent operations on the related object. Each object type has a specific <code>id</code> structure, and those are not interchangeable between objects of different kinds. CSS objects can be loaded using the <code>get*ForNode()</code> calls (which accept a DOM node id). A client can also keep track of stylesheets via the <code>styleSheetAdded</code>/<code>styleSheetRemoved</code> events and subsequently load the required stylesheet contents using the <code>getStyleSheet[Text]()</code> methods.", "dependencies": ["DOM"], "types": [ {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp index 77745e18..a749b9a9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -1083,54 +1083,6 @@ : LayoutBlockFlow::BorderAfter(); } -unsigned LayoutTableCell::CollapsedBorderHalfLeft(bool outer) const { - const ComputedStyle& style_for_cell_order = TableStyle(); - if (style_for_cell_order.IsHorizontalWritingMode()) { - return style_for_cell_order.IsLeftToRightDirection() - ? CollapsedBorderHalfStart(outer) - : CollapsedBorderHalfEnd(outer); - } - return style_for_cell_order.IsFlippedBlocksWritingMode() - ? CollapsedBorderHalfAfter(outer) - : CollapsedBorderHalfBefore(outer); -} - -unsigned LayoutTableCell::CollapsedBorderHalfRight(bool outer) const { - const ComputedStyle& style_for_cell_order = TableStyle(); - if (style_for_cell_order.IsHorizontalWritingMode()) { - return style_for_cell_order.IsLeftToRightDirection() - ? CollapsedBorderHalfEnd(outer) - : CollapsedBorderHalfStart(outer); - } - return style_for_cell_order.IsFlippedBlocksWritingMode() - ? CollapsedBorderHalfBefore(outer) - : CollapsedBorderHalfAfter(outer); -} - -unsigned LayoutTableCell::CollapsedBorderHalfTop(bool outer) const { - const ComputedStyle& style_for_cell_order = TableStyle(); - if (style_for_cell_order.IsHorizontalWritingMode()) { - return style_for_cell_order.IsFlippedBlocksWritingMode() - ? CollapsedBorderHalfAfter(outer) - : CollapsedBorderHalfBefore(outer); - } - return style_for_cell_order.IsLeftToRightDirection() - ? CollapsedBorderHalfStart(outer) - : CollapsedBorderHalfEnd(outer); -} - -unsigned LayoutTableCell::CollapsedBorderHalfBottom(bool outer) const { - const ComputedStyle& style_for_cell_order = TableStyle(); - if (style_for_cell_order.IsHorizontalWritingMode()) { - return style_for_cell_order.IsFlippedBlocksWritingMode() - ? CollapsedBorderHalfBefore(outer) - : CollapsedBorderHalfAfter(outer); - } - return style_for_cell_order.IsLeftToRightDirection() - ? CollapsedBorderHalfEnd(outer) - : CollapsedBorderHalfStart(outer); -} - unsigned LayoutTableCell::CollapsedBorderHalfStart(bool outer) const { UpdateCollapsedBorderValues(); const auto* collapsed_border_values = this->GetCollapsedBorderValues();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.h b/third_party/WebKit/Source/core/layout/LayoutTableCell.h index 32e7ed1..72a17e8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCell.h +++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
@@ -33,6 +33,7 @@ #include "core/layout/LayoutTableRow.h" #include "core/layout/LayoutTableSection.h" #include "platform/LengthFunctions.h" +#include "platform/text/WritingModeUtils.h" namespace blink { @@ -359,10 +360,26 @@ void ComputeOverflow(LayoutUnit old_client_after_edge, bool recompute_floats = false) override; - unsigned CollapsedBorderHalfLeft(bool outer) const; - unsigned CollapsedBorderHalfRight(bool outer) const; - unsigned CollapsedBorderHalfTop(bool outer) const; - unsigned CollapsedBorderHalfBottom(bool outer) const; + LogicalToPhysical<unsigned> LogicalCollapsedBorderHalfToPhysical( + bool outer) const { + return LogicalToPhysical<unsigned>( + TableStyle().GetWritingMode(), TableStyle().Direction(), + CollapsedBorderHalfStart(outer), CollapsedBorderHalfEnd(outer), + CollapsedBorderHalfBefore(outer), CollapsedBorderHalfAfter(outer)); + } + + unsigned CollapsedBorderHalfLeft(bool outer) const { + return LogicalCollapsedBorderHalfToPhysical(outer).Left(); + } + unsigned CollapsedBorderHalfRight(bool outer) const { + return LogicalCollapsedBorderHalfToPhysical(outer).Right(); + } + unsigned CollapsedBorderHalfTop(bool outer) const { + return LogicalCollapsedBorderHalfToPhysical(outer).Top(); + } + unsigned CollapsedBorderHalfBottom(bool outer) const { + return LogicalCollapsedBorderHalfToPhysical(outer).Bottom(); + } // For the following methods, the 'start', 'end', 'before', 'after' directions // are all in the table's inline and block directions.
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp index 661ba01b6..afd9277 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -877,6 +877,16 @@ subpixel_accumulation = offset_from_composited_ancestor - snapped_offset_from_composited_ancestor; } + + // Invalidate the whole layer when subpixel accumulation changes, since + // the previous subpixel accumulation is baked into the dispay list. + // However, don't do so for directly composited layers, to avoid impacting + // performance. + if (subpixel_accumulation != owning_layer_.SubpixelAccumulation() && + !(owning_layer_.GetCompositingReasons() & + kCompositingReasonComboAllDirectReasons)) + SetContentsNeedDisplay(); + // Otherwise discard the sub-pixel remainder because paint offset can't be // transformed by a non-translation transform. owning_layer_.SetSubpixelAccumulation(subpixel_accumulation);
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp index 8f6387e..5ffe801 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
@@ -74,6 +74,50 @@ INSTANTIATE_TEST_CASE_P(All, CompositedLayerMappingTest, ::testing::Bool()); +TEST_P(CompositedLayerMappingTest, SubpixelAccumulationChange) { + SetBodyInnerHTML( + "<div id='target' style='will-change: transform; background: lightblue; " + "position: relative; left: 0.4px; width: 100px; height: 100px'>"); + + Element* target = GetDocument().getElementById("target"); + target->SetInlineStyleProperty(CSSPropertyLeft, "0.6px"); + + GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(); + + PaintLayer* paint_layer = + ToLayoutBoxModelObject(target->GetLayoutObject())->Layer(); + // Directly composited layers are not invalidated on subpixel accumulation + // change. + EXPECT_FALSE(paint_layer->GraphicsLayerBacking() + ->GetPaintController() + .GetPaintArtifact() + .IsEmpty()); +} + +TEST_P(CompositedLayerMappingTest, + SubpixelAccumulationChangeIndirectCompositing) { + SetBodyInnerHTML( + "<div style='position; relative; width: 100px; height: 100px;" + " background: lightgray; will-change: transform'></div>" + "<div id='target' style='background: lightblue; " + " position: relative; top: -10px; left: 0.4px; width: 100px;" + " height: 100px'></div>"); + + Element* target = GetDocument().getElementById("target"); + target->SetInlineStyleProperty(CSSPropertyLeft, "0.6px"); + + GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(); + + PaintLayer* paint_layer = + ToLayoutBoxModelObject(target->GetLayoutObject())->Layer(); + // The PaintArtifact should have been deleted because paint was + // invalidated for subpixel accumulation change. + EXPECT_FALSE(paint_layer->GraphicsLayerBacking() + ->GetPaintController() + .GetPaintArtifact() + .IsEmpty()); +} + TEST_P(CompositedLayerMappingTest, SimpleInterestRect) { SetBodyInnerHTML( "<div id='target' style='width: 200px; height: 200px; will-change: "
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp index 1bb99f9..e680fee 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp +++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -1853,128 +1853,6 @@ unvisited_color.Alpha()); } -BorderValue ComputedStyle::BorderBeforeUsing(const ComputedStyle& other) const { - switch (other.GetWritingMode()) { - case WritingMode::kHorizontalTb: - return BorderTop(); - case WritingMode::kVerticalLr: - return BorderLeft(); - case WritingMode::kVerticalRl: - return BorderRight(); - } - NOTREACHED(); - return BorderTop(); -} - -BorderValue ComputedStyle::BorderAfterUsing(const ComputedStyle& other) const { - switch (other.GetWritingMode()) { - case WritingMode::kHorizontalTb: - return BorderBottom(); - case WritingMode::kVerticalLr: - return BorderRight(); - case WritingMode::kVerticalRl: - return BorderLeft(); - } - NOTREACHED(); - return BorderBottom(); -} - -BorderValue ComputedStyle::BorderStartUsing(const ComputedStyle& other) const { - if (other.IsHorizontalWritingMode()) - return other.IsLeftToRightDirection() ? BorderLeft() : BorderRight(); - return other.IsLeftToRightDirection() ? BorderTop() : BorderBottom(); -} - -BorderValue ComputedStyle::BorderEndUsing(const ComputedStyle& other) const { - if (other.IsHorizontalWritingMode()) - return other.IsLeftToRightDirection() ? BorderRight() : BorderLeft(); - return other.IsLeftToRightDirection() ? BorderBottom() : BorderTop(); -} - -float ComputedStyle::BorderBeforeWidth() const { - switch (GetWritingMode()) { - case WritingMode::kHorizontalTb: - return BorderTopWidth(); - case WritingMode::kVerticalLr: - return BorderLeftWidth(); - case WritingMode::kVerticalRl: - return BorderRightWidth(); - } - NOTREACHED(); - return BorderTopWidth(); -} - -float ComputedStyle::BorderAfterWidth() const { - switch (GetWritingMode()) { - case WritingMode::kHorizontalTb: - return BorderBottomWidth(); - case WritingMode::kVerticalLr: - return BorderRightWidth(); - case WritingMode::kVerticalRl: - return BorderLeftWidth(); - } - NOTREACHED(); - return BorderBottomWidth(); -} - -float ComputedStyle::BorderStartWidth() const { - if (IsHorizontalWritingMode()) - return IsLeftToRightDirection() ? BorderLeftWidth() : BorderRightWidth(); - return IsLeftToRightDirection() ? BorderTopWidth() : BorderBottomWidth(); -} - -float ComputedStyle::BorderEndWidth() const { - if (IsHorizontalWritingMode()) - return IsLeftToRightDirection() ? BorderRightWidth() : BorderLeftWidth(); - return IsLeftToRightDirection() ? BorderBottomWidth() : BorderTopWidth(); -} - -float ComputedStyle::BorderOverWidth() const { - return IsHorizontalWritingMode() ? BorderTopWidth() : BorderRightWidth(); -} - -float ComputedStyle::BorderUnderWidth() const { - return IsHorizontalWritingMode() ? BorderBottomWidth() : BorderLeftWidth(); -} - -EBorderStyle ComputedStyle::BorderBeforeStyle() const { - switch (GetWritingMode()) { - case WritingMode::kHorizontalTb: - return BorderTopStyle(); - case WritingMode::kVerticalLr: - return BorderLeftStyle(); - case WritingMode::kVerticalRl: - return BorderRightStyle(); - } - NOTREACHED(); - return BorderTopStyle(); -} - -EBorderStyle ComputedStyle::BorderAfterStyle() const { - switch (GetWritingMode()) { - case WritingMode::kHorizontalTb: - return BorderBottomStyle(); - case WritingMode::kVerticalLr: - return BorderRightStyle(); - case WritingMode::kVerticalRl: - return BorderLeftStyle(); - } - NOTREACHED(); - return BorderBottomStyle(); -} - -EBorderStyle ComputedStyle::BorderStartStyle() const { - if (IsHorizontalWritingMode()) - return IsLeftToRightDirection() ? BorderLeftStyle() : BorderRightStyle(); - return IsLeftToRightDirection() ? BorderTopStyle() : BorderBottomStyle(); -} - -EBorderStyle ComputedStyle::BorderEndStyle() const { - if (IsHorizontalWritingMode()) - return IsLeftToRightDirection() ? BorderRightStyle() : BorderLeftStyle(); - return IsLeftToRightDirection() ? BorderBottomStyle() : BorderTopStyle(); -} - void ComputedStyle::SetMarginStart(const Length& margin) { if (IsHorizontalWritingMode()) { if (IsLeftToRightDirection())
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index c553c43..9958459 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -75,6 +75,7 @@ #include "platform/text/TabSize.h" #include "platform/text/TextDirection.h" #include "platform/text/UnicodeBidi.h" +#include "platform/text/WritingModeUtils.h" #include "platform/transforms/TransformOperations.h" #include "platform/wtf/Forward.h" #include "platform/wtf/LeakAnnotations.h" @@ -1552,28 +1553,22 @@ const Length& MarginStart() const { return MarginStartUsing(this); } const Length& MarginEnd() const { return MarginEndUsing(this); } const Length& MarginOver() const { - return LengthBox::Over(GetWritingMode(), MarginTop(), MarginRight()); + return PhysicalMarginToLogical(*this).Over(); } const Length& MarginUnder() const { - return LengthBox::Under(GetWritingMode(), MarginBottom(), MarginLeft()); + return PhysicalMarginToLogical(*this).Under(); } const Length& MarginStartUsing(const ComputedStyle* other) const { - return LengthBox::Start(other->GetWritingMode(), other->Direction(), - MarginTop(), MarginLeft(), MarginRight(), - MarginBottom()); + return PhysicalMarginToLogical(*other).Start(); } const Length& MarginEndUsing(const ComputedStyle* other) const { - return LengthBox::End(other->GetWritingMode(), other->Direction(), - MarginTop(), MarginLeft(), MarginRight(), - MarginBottom()); + return PhysicalMarginToLogical(*other).End(); } const Length& MarginBeforeUsing(const ComputedStyle* other) const { - return LengthBox::Before(other->GetWritingMode(), MarginTop(), MarginLeft(), - MarginRight()); + return PhysicalMarginToLogical(*other).Before(); } const Length& MarginAfterUsing(const ComputedStyle* other) const { - return LengthBox::After(other->GetWritingMode(), MarginBottom(), - MarginLeft(), MarginRight()); + return PhysicalMarginToLogical(*other).After(); } void SetMarginStart(const Length&); void SetMarginEnd(const Length&); @@ -1586,26 +1581,20 @@ // Padding utility functions. const Length& PaddingBefore() const { - return LengthBox::Before(GetWritingMode(), PaddingTop(), PaddingLeft(), - PaddingRight()); + return PhysicalPaddingToLogical().Before(); } const Length& PaddingAfter() const { - return LengthBox::After(GetWritingMode(), PaddingBottom(), PaddingLeft(), - PaddingRight()); + return PhysicalPaddingToLogical().After(); } const Length& PaddingStart() const { - return LengthBox::Start(GetWritingMode(), Direction(), PaddingTop(), - PaddingLeft(), PaddingRight(), PaddingBottom()); + return PhysicalPaddingToLogical().Start(); } - const Length& PaddingEnd() const { - return LengthBox::End(GetWritingMode(), Direction(), PaddingTop(), - PaddingLeft(), PaddingRight(), PaddingBottom()); - } + const Length& PaddingEnd() const { return PhysicalPaddingToLogical().End(); } const Length& PaddingOver() const { - return LengthBox::Over(GetWritingMode(), PaddingTop(), PaddingRight()); + return PhysicalPaddingToLogical().Over(); } const Length& PaddingUnder() const { - return LengthBox::Under(GetWritingMode(), PaddingBottom(), PaddingLeft()); + return PhysicalPaddingToLogical().Under(); } bool HasPadding() const { return !PaddingLeft().IsZero() || !PaddingRight().IsZero() || @@ -1669,27 +1658,53 @@ BorderBottomWidthInternal() == o.BorderBottomWidthInternal(); } - BorderValue BorderBeforeUsing(const ComputedStyle& other) const; - BorderValue BorderAfterUsing(const ComputedStyle& other) const; - BorderValue BorderStartUsing(const ComputedStyle& other) const; - BorderValue BorderEndUsing(const ComputedStyle& other) const; + BorderValue BorderBeforeUsing(const ComputedStyle& other) const { + return PhysicalBorderToLogical(other).Before(); + } + BorderValue BorderAfterUsing(const ComputedStyle& other) const { + return PhysicalBorderToLogical(other).After(); + } + BorderValue BorderStartUsing(const ComputedStyle& other) const { + return PhysicalBorderToLogical(other).Start(); + } + BorderValue BorderEndUsing(const ComputedStyle& other) const { + return PhysicalBorderToLogical(other).End(); + } BorderValue BorderBefore() const { return BorderBeforeUsing(*this); } BorderValue BorderAfter() const { return BorderAfterUsing(*this); } BorderValue BorderStart() const { return BorderStartUsing(*this); } BorderValue BorderEnd() const { return BorderEndUsing(*this); } - float BorderAfterWidth() const; - float BorderBeforeWidth() const; - float BorderEndWidth() const; - float BorderStartWidth() const; - float BorderOverWidth() const; - float BorderUnderWidth() const; + float BorderAfterWidth() const { + return PhysicalBorderWidthToLogical().After(); + } + float BorderBeforeWidth() const { + return PhysicalBorderWidthToLogical().Before(); + } + float BorderEndWidth() const { return PhysicalBorderWidthToLogical().End(); } + float BorderStartWidth() const { + return PhysicalBorderWidthToLogical().Start(); + } + float BorderOverWidth() const { + return PhysicalBorderWidthToLogical().Over(); + } + float BorderUnderWidth() const { + return PhysicalBorderWidthToLogical().Under(); + } - EBorderStyle BorderAfterStyle() const; - EBorderStyle BorderBeforeStyle() const; - EBorderStyle BorderEndStyle() const; - EBorderStyle BorderStartStyle() const; + EBorderStyle BorderAfterStyle() const { + return PhysicalBorderStyleToLogical().After(); + } + EBorderStyle BorderBeforeStyle() const { + return PhysicalBorderStyleToLogical().Before(); + } + EBorderStyle BorderEndStyle() const { + return PhysicalBorderStyleToLogical().End(); + } + EBorderStyle BorderStartStyle() const { + return PhysicalBorderStyleToLogical().Start(); + } bool HasBorderFill() const { return BorderImage().HasImage() && BorderImage().Fill(); @@ -1950,16 +1965,16 @@ // Offset utility functions. // Accessors for positioned object edges that take into account writing mode. const Length& LogicalLeft() const { - return LengthBox::LogicalLeft(GetWritingMode(), Left(), Top()); + return PhysicalBoundsToLogical().LineLeft(); } const Length& LogicalRight() const { - return LengthBox::LogicalRight(GetWritingMode(), Right(), Bottom()); + return PhysicalBoundsToLogical().LineRight(); } const Length& LogicalTop() const { - return LengthBox::Before(GetWritingMode(), Top(), Left(), Right()); + return PhysicalBoundsToLogical().Before(); } const Length& LogicalBottom() const { - return LengthBox::After(GetWritingMode(), Bottom(), Left(), Right()); + return PhysicalBoundsToLogical().After(); } bool OffsetEqual(const ComputedStyle& other) const { return Left() == other.Left() && Right() == other.Right() && @@ -2574,6 +2589,43 @@ StyleInheritedVariables& MutableInheritedVariables(); StyleNonInheritedVariables& MutableNonInheritedVariables(); + PhysicalToLogical<const Length&> PhysicalMarginToLogical( + const ComputedStyle& other) const { + return PhysicalToLogical<const Length&>( + other.GetWritingMode(), other.Direction(), MarginTop(), MarginRight(), + MarginBottom(), MarginLeft()); + } + + PhysicalToLogical<const Length&> PhysicalPaddingToLogical() const { + return PhysicalToLogical<const Length&>(GetWritingMode(), Direction(), + PaddingTop(), PaddingRight(), + PaddingBottom(), PaddingLeft()); + } + + PhysicalToLogical<BorderValue> PhysicalBorderToLogical( + const ComputedStyle& other) const { + return PhysicalToLogical<BorderValue>( + other.GetWritingMode(), other.Direction(), BorderTop(), BorderRight(), + BorderBottom(), BorderLeft()); + } + + PhysicalToLogical<float> PhysicalBorderWidthToLogical() const { + return PhysicalToLogical<float>(GetWritingMode(), Direction(), + BorderTopWidth(), BorderRightWidth(), + BorderBottomWidth(), BorderLeftWidth()); + } + + PhysicalToLogical<EBorderStyle> PhysicalBorderStyleToLogical() const { + return PhysicalToLogical<EBorderStyle>( + GetWritingMode(), Direction(), BorderTopStyle(), BorderRightStyle(), + BorderBottomStyle(), BorderLeftStyle()); + } + + PhysicalToLogical<const Length&> PhysicalBoundsToLogical() const { + return PhysicalToLogical<const Length&>(GetWritingMode(), Direction(), + Top(), Right(), Bottom(), Left()); + } + FRIEND_TEST_ALL_PREFIXES( ComputedStyleTest, UpdatePropertySpecificDifferencesRespectsTransformAnimation);
diff --git a/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp b/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp index 7a57419..92534667 100644 --- a/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp +++ b/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp
@@ -231,9 +231,13 @@ if (parameters.IsEmpty()) return nullptr; - const char** parameter_array = static_cast<const char**>( - WTF::Partitions::FastMalloc(((parameters.size() * 2) + 1) * sizeof(char*), - WTF_HEAP_PROFILER_TYPE_NAME(XSLTProcessor))); + WTF::CheckedSizeT size = parameters.size(); + size *= 2; + ++size; + size *= sizeof(char*); + const char** parameter_array = + static_cast<const char**>(WTF::Partitions::FastMalloc( + size.ValueOrDie(), WTF_HEAP_PROFILER_TYPE_NAME(XSLTProcessor))); unsigned index = 0; for (auto& parameter : parameters) {
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index c806f30..26d5a58 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -276,7 +276,6 @@ "LayoutUnit.h", "Length.cpp", "Length.h", - "LengthBox.cpp", "LengthBox.h", "LengthFunctions.cpp", "LengthFunctions.h", @@ -1470,6 +1469,7 @@ "text/WebEntities.cpp", "text/WebEntities.h", "text/WritingMode.h", + "text/WritingModeUtils.h", "text/linux/HyphenationLinux.cpp", "text/mac/HyphenationMac.cpp", "text/win/HyphenationWin.cpp", @@ -1958,6 +1958,7 @@ "text/TextBreakIteratorTest.cpp", "text/TextEncodingDetectorTest.cpp", "text/UnicodeUtilitiesTest.cpp", + "text/WritingModeUtilsTest.cpp", "threading/BackgroundTaskRunnerTest.cpp", "transforms/AffineTransformTest.cpp", "transforms/RotationTest.cpp",
diff --git a/third_party/WebKit/Source/platform/LengthBox.cpp b/third_party/WebKit/Source/platform/LengthBox.cpp deleted file mode 100644 index 2dede65..0000000 --- a/third_party/WebKit/Source/platform/LengthBox.cpp +++ /dev/null
@@ -1,113 +0,0 @@ -/* - * Copyright (c) 2012, Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "platform/LengthBox.h" - -namespace blink { - -const Length& LengthBox::LogicalLeft(WritingMode writing_mode, - const Length& left, - const Length& top) { - return IsHorizontalWritingMode(writing_mode) ? left : top; -} - -const Length& LengthBox::LogicalRight(WritingMode writing_mode, - const Length& right, - const Length& bottom) { - return IsHorizontalWritingMode(writing_mode) ? right : bottom; -} - -const Length& LengthBox::Before(WritingMode writing_mode, - const Length& top, - const Length& left, - const Length& right) { - switch (writing_mode) { - case WritingMode::kHorizontalTb: - return top; - case WritingMode::kVerticalLr: - return left; - case WritingMode::kVerticalRl: - return right; - } - NOTREACHED(); - return top; -} - -const Length& LengthBox::After(WritingMode writing_mode, - const Length& bottom, - const Length& left, - const Length& right) { - switch (writing_mode) { - case WritingMode::kHorizontalTb: - return bottom; - case WritingMode::kVerticalLr: - return right; - case WritingMode::kVerticalRl: - return left; - } - NOTREACHED(); - return bottom; -} - -const Length& LengthBox::Start(WritingMode writing_mode, - TextDirection direction, - const Length& top, - const Length& left, - const Length& right, - const Length& bottom) { - if (IsHorizontalWritingMode(writing_mode)) - return IsLtr(direction) ? left : right; - return IsLtr(direction) ? top : bottom; -} - -const Length& LengthBox::End(WritingMode writing_mode, - TextDirection direction, - const Length& top, - const Length& left, - const Length& right, - const Length& bottom) { - if (IsHorizontalWritingMode(writing_mode)) - return IsLtr(direction) ? right : left; - return IsLtr(direction) ? bottom : top; -} - -const Length& LengthBox::Over(WritingMode writing_mode, - const Length& top, - const Length& right) { - return IsHorizontalWritingMode(writing_mode) ? top : right; -} - -const Length& LengthBox::Under(WritingMode writing_mode, - const Length& bottom, - const Length& left) { - return IsHorizontalWritingMode(writing_mode) ? bottom : left; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/LengthBox.h b/third_party/WebKit/Source/platform/LengthBox.h index 4fb231c..95077619 100644 --- a/third_party/WebKit/Source/platform/LengthBox.h +++ b/third_party/WebKit/Source/platform/LengthBox.h
@@ -53,40 +53,6 @@ top_(Length(t, kFixed)), bottom_(Length(b, kFixed)) {} - // For use in ComputedStyle.h - static const Length& LogicalLeft(WritingMode, - const Length& left, - const Length& top); - static const Length& LogicalRight(WritingMode, - const Length& right, - const Length& bottom); - static const Length& Before(WritingMode, - const Length& top, - const Length& left, - const Length& right); - static const Length& After(WritingMode, - const Length& bottom, - const Length& left, - const Length& right); - static const Length& Start(WritingMode, - TextDirection, - const Length& top, - const Length& left, - const Length& right, - const Length& bottom); - static const Length& End(WritingMode, - TextDirection, - const Length& top, - const Length& left, - const Length& right, - const Length& bottom); - static const Length& Over(WritingMode, - const Length& top, - const Length& right); - static const Length& Under(WritingMode, - const Length& bottom, - const Length& left); - const Length& Left() const { return left_; } const Length& Right() const { return right_; } const Length& Top() const { return top_; }
diff --git a/third_party/WebKit/Source/platform/heap/TraceTraits.h b/third_party/WebKit/Source/platform/heap/TraceTraits.h index 98273c4..28c1af7 100644 --- a/third_party/WebKit/Source/platform/heap/TraceTraits.h +++ b/third_party/WebKit/Source/platform/heap/TraceTraits.h
@@ -204,8 +204,11 @@ private: static const T* ToWrapperTracingType(const void* t) { + static_assert(sizeof(T), "type needs to be defined"); static_assert(!NeedsAdjustAndMark<T>::value, "wrapper tracing is not supported within mixins"); + static_assert(IsGarbageCollectedType<T>::value, + "only objects deriving from GarbageCollected can be used"); #if DCHECK_IS_ON() HeapObjectHeader::CheckFromPayload(t); #endif
diff --git a/third_party/WebKit/Source/platform/text/WritingModeUtils.h b/third_party/WebKit/Source/platform/text/WritingModeUtils.h new file mode 100644 index 0000000..f4d680e --- /dev/null +++ b/third_party/WebKit/Source/platform/text/WritingModeUtils.h
@@ -0,0 +1,142 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license thaT can be +// found in the LICENSE file. + +#ifndef WritingModeUtils_h +#define WritingModeUtils_h + +#include "platform/text/TextDirection.h" +#include "platform/text/WritingMode.h" +#include "platform/wtf/Allocator.h" + +namespace blink { + +template <typename T> +class PhysicalToLogical { + STACK_ALLOCATED(); + + public: + PhysicalToLogical(WritingMode writing_mode, + TextDirection direction, + T top, + T right, + T bottom, + T left) + : writing_mode_(writing_mode), + direction_(direction), + top_(top), + right_(right), + bottom_(bottom), + left_(left) {} + + T InlineStart() const { + if (IsHorizontalWritingMode(writing_mode_)) + return IsLtr(direction_) ? left_ : right_; + return IsLtr(direction_) ? top_ : bottom_; + } + + T InlineEnd() const { + if (IsHorizontalWritingMode(writing_mode_)) + return IsLtr(direction_) ? right_ : left_; + return IsLtr(direction_) ? bottom_ : top_; + } + + T BlockStart() const { + if (IsHorizontalWritingMode(writing_mode_)) + return top_; + return IsFlippedBlocksWritingMode(writing_mode_) ? right_ : left_; + } + + T BlockEnd() const { + if (IsHorizontalWritingMode(writing_mode_)) + return bottom_; + return IsFlippedBlocksWritingMode(writing_mode_) ? left_ : right_; + } + + T Over() const { + return IsHorizontalWritingMode(writing_mode_) ? top_ : right_; + } + + T Under() const { + return IsHorizontalWritingMode(writing_mode_) ? bottom_ : left_; + } + + T LineLeft() const { + return IsHorizontalWritingMode(writing_mode_) ? left_ : top_; + } + + T LineRight() const { + return IsHorizontalWritingMode(writing_mode_) ? right_ : bottom_; + } + + // Legacy logical directions. + T Start() const { return InlineStart(); } + T End() const { return InlineEnd(); } + T Before() const { return BlockStart(); } + T After() const { return BlockEnd(); } + + private: + WritingMode writing_mode_; + TextDirection direction_; + T top_; + T right_; + T bottom_; + T left_; +}; + +template <typename T> +class LogicalToPhysical { + STACK_ALLOCATED(); + + public: + LogicalToPhysical(WritingMode writing_mode, + TextDirection direction, + T inline_start, + T inline_end, + T block_start, + T block_end) + : writing_mode_(writing_mode), + direction_(direction), + inline_start_(inline_start), + inline_end_(inline_end), + block_start_(block_start), + block_end_(block_end) {} + + T Left() const { + if (IsHorizontalWritingMode(writing_mode_)) + return IsLtr(direction_) ? inline_start_ : inline_end_; + return IsFlippedBlocksWritingMode(writing_mode_) ? block_end_ + : block_start_; + } + + T Right() const { + if (IsHorizontalWritingMode(writing_mode_)) + return IsLtr(direction_) ? inline_end_ : inline_start_; + return IsFlippedBlocksWritingMode(writing_mode_) ? block_start_ + : block_end_; + } + + T Top() const { + if (IsHorizontalWritingMode(writing_mode_)) + return block_start_; + return IsLtr(direction_) ? inline_start_ : inline_end_; + } + + T Bottom() const { + if (IsHorizontalWritingMode(writing_mode_)) + return block_end_; + return IsLtr(direction_) ? inline_end_ : inline_start_; + } + + private: + WritingMode writing_mode_; + TextDirection direction_; + T inline_start_; // a.k.a. start + T inline_end_; // a.k.a. end + T block_start_; // a.k.a. before + T block_end_; // a.k.a. after +}; + +} // namespace blink + +#endif // WritingModeUtils_h
diff --git a/third_party/WebKit/Source/platform/text/WritingModeUtilsTest.cpp b/third_party/WebKit/Source/platform/text/WritingModeUtilsTest.cpp new file mode 100644 index 0000000..6683fefc --- /dev/null +++ b/third_party/WebKit/Source/platform/text/WritingModeUtilsTest.cpp
@@ -0,0 +1,176 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/text/WritingModeUtils.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +namespace { + +enum { kTop, kRight, kBottom, kLeft }; + +void CheckLegacyLogicalDirections(PhysicalToLogical<int> converter) { + EXPECT_EQ(converter.InlineStart(), converter.Start()); + EXPECT_EQ(converter.InlineEnd(), converter.End()); + EXPECT_EQ(converter.BlockStart(), converter.Before()); + EXPECT_EQ(converter.BlockEnd(), converter.After()); +} + +TEST(WritingModeUtilsTest, PhysicalToLogicalHorizontalLtr) { + PhysicalToLogical<int> converter(WritingMode::kHorizontalTb, + TextDirection::kLtr, kTop, kRight, kBottom, + kLeft); + EXPECT_EQ(kLeft, converter.InlineStart()); + EXPECT_EQ(kRight, converter.InlineEnd()); + EXPECT_EQ(kTop, converter.BlockStart()); + EXPECT_EQ(kBottom, converter.BlockEnd()); + EXPECT_EQ(kLeft, converter.LineLeft()); + EXPECT_EQ(kRight, converter.LineRight()); + EXPECT_EQ(kTop, converter.Over()); + EXPECT_EQ(kBottom, converter.Under()); + CheckLegacyLogicalDirections(converter); +} + +TEST(WritingModeUtilsTest, PhysicalToLogicalHorizontalRtl) { + PhysicalToLogical<int> converter(WritingMode::kHorizontalTb, + TextDirection::kRtl, kTop, kRight, kBottom, + kLeft); + EXPECT_EQ(kRight, converter.InlineStart()); + EXPECT_EQ(kLeft, converter.InlineEnd()); + EXPECT_EQ(kTop, converter.BlockStart()); + EXPECT_EQ(kBottom, converter.BlockEnd()); + EXPECT_EQ(kLeft, converter.LineLeft()); + EXPECT_EQ(kRight, converter.LineRight()); + EXPECT_EQ(kTop, converter.Over()); + EXPECT_EQ(kBottom, converter.Under()); + CheckLegacyLogicalDirections(converter); +} + +TEST(WritingModeUtilsTest, PhysicalToLogicalVlrLtr) { + PhysicalToLogical<int> converter(WritingMode::kVerticalLr, + TextDirection::kLtr, kTop, kRight, kBottom, + kLeft); + EXPECT_EQ(kTop, converter.InlineStart()); + EXPECT_EQ(kBottom, converter.InlineEnd()); + EXPECT_EQ(kLeft, converter.BlockStart()); + EXPECT_EQ(kRight, converter.BlockEnd()); + EXPECT_EQ(kTop, converter.LineLeft()); + EXPECT_EQ(kBottom, converter.LineRight()); + EXPECT_EQ(kRight, converter.Over()); + EXPECT_EQ(kLeft, converter.Under()); + CheckLegacyLogicalDirections(converter); +} + +TEST(WritingModeUtilsTest, PhysicalToLogicalVlrRtl) { + PhysicalToLogical<int> converter(WritingMode::kVerticalLr, + TextDirection::kRtl, kTop, kRight, kBottom, + kLeft); + EXPECT_EQ(kBottom, converter.InlineStart()); + EXPECT_EQ(kTop, converter.InlineEnd()); + EXPECT_EQ(kLeft, converter.BlockStart()); + EXPECT_EQ(kRight, converter.BlockEnd()); + EXPECT_EQ(kTop, converter.LineLeft()); + EXPECT_EQ(kBottom, converter.LineRight()); + EXPECT_EQ(kRight, converter.Over()); + EXPECT_EQ(kLeft, converter.Under()); + CheckLegacyLogicalDirections(converter); +} + +TEST(WritingModeUtilsTest, PhysicalToLogicalVrlLtr) { + PhysicalToLogical<int> converter(WritingMode::kVerticalRl, + TextDirection::kLtr, kTop, kRight, kBottom, + kLeft); + EXPECT_EQ(kTop, converter.InlineStart()); + EXPECT_EQ(kBottom, converter.InlineEnd()); + EXPECT_EQ(kRight, converter.BlockStart()); + EXPECT_EQ(kLeft, converter.BlockEnd()); + EXPECT_EQ(kTop, converter.LineLeft()); + EXPECT_EQ(kBottom, converter.LineRight()); + EXPECT_EQ(kRight, converter.Over()); + EXPECT_EQ(kLeft, converter.Under()); + CheckLegacyLogicalDirections(converter); +} + +TEST(WritingModeUtilsTest, PhysicalToLogicalVrlRtl) { + PhysicalToLogical<int> converter(WritingMode::kVerticalRl, + TextDirection::kRtl, kTop, kRight, kBottom, + kLeft); + EXPECT_EQ(kBottom, converter.InlineStart()); + EXPECT_EQ(kTop, converter.InlineEnd()); + EXPECT_EQ(kRight, converter.BlockStart()); + EXPECT_EQ(kLeft, converter.BlockEnd()); + EXPECT_EQ(kTop, converter.LineLeft()); + EXPECT_EQ(kBottom, converter.LineRight()); + EXPECT_EQ(kRight, converter.Over()); + EXPECT_EQ(kLeft, converter.Under()); + CheckLegacyLogicalDirections(converter); +} + +enum { kInlineStart, kInlineEnd, kBlockStart, kBlockEnd }; + +TEST(WritingModeUtilsTest, LogicalToPhysicalHorizontalLtr) { + LogicalToPhysical<int> converter(WritingMode::kHorizontalTb, + TextDirection::kLtr, kInlineStart, + kInlineEnd, kBlockStart, kBlockEnd); + EXPECT_EQ(kInlineStart, converter.Left()); + EXPECT_EQ(kInlineEnd, converter.Right()); + EXPECT_EQ(kBlockStart, converter.Top()); + EXPECT_EQ(kBlockEnd, converter.Bottom()); +} + +TEST(WritingModeUtilsTest, LogicalToPhysicalHorizontalRtl) { + LogicalToPhysical<int> converter(WritingMode::kHorizontalTb, + TextDirection::kRtl, kInlineStart, + kInlineEnd, kBlockStart, kBlockEnd); + EXPECT_EQ(kInlineEnd, converter.Left()); + EXPECT_EQ(kInlineStart, converter.Right()); + EXPECT_EQ(kBlockStart, converter.Top()); + EXPECT_EQ(kBlockEnd, converter.Bottom()); +} + +TEST(WritingModeUtilsTest, LogicalToPhysicalVlrLtr) { + LogicalToPhysical<int> converter(WritingMode::kVerticalLr, + TextDirection::kLtr, kInlineStart, + kInlineEnd, kBlockStart, kBlockEnd); + EXPECT_EQ(kBlockStart, converter.Left()); + EXPECT_EQ(kBlockEnd, converter.Right()); + EXPECT_EQ(kInlineStart, converter.Top()); + EXPECT_EQ(kInlineEnd, converter.Bottom()); +} + +TEST(WritingModeUtilsTest, LogicalToPhysicalVlrRtl) { + LogicalToPhysical<int> converter(WritingMode::kVerticalLr, + TextDirection::kRtl, kInlineStart, + kInlineEnd, kBlockStart, kBlockEnd); + EXPECT_EQ(kBlockStart, converter.Left()); + EXPECT_EQ(kBlockEnd, converter.Right()); + EXPECT_EQ(kInlineEnd, converter.Top()); + EXPECT_EQ(kInlineStart, converter.Bottom()); +} + +TEST(WritingModeUtilsTest, LogicalToPhysicalVrlLtr) { + LogicalToPhysical<int> converter(WritingMode::kVerticalRl, + TextDirection::kLtr, kInlineStart, + kInlineEnd, kBlockStart, kBlockEnd); + EXPECT_EQ(kBlockEnd, converter.Left()); + EXPECT_EQ(kBlockStart, converter.Right()); + EXPECT_EQ(kInlineStart, converter.Top()); + EXPECT_EQ(kInlineEnd, converter.Bottom()); +} + +TEST(WritingModeUtilsTest, LogicalToPhysicalVrlRtl) { + LogicalToPhysical<int> converter(WritingMode::kVerticalRl, + TextDirection::kRtl, kInlineStart, + kInlineEnd, kBlockStart, kBlockEnd); + EXPECT_EQ(kBlockEnd, converter.Left()); + EXPECT_EQ(kBlockStart, converter.Right()); + EXPECT_EQ(kInlineEnd, converter.Top()); + EXPECT_EQ(kInlineStart, converter.Bottom()); +} + +} // namespace + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/wtf/allocator/Partitions.h b/third_party/WebKit/Source/platform/wtf/allocator/Partitions.h index f24d4b4..11713aa9b 100644 --- a/third_party/WebKit/Source/platform/wtf/allocator/Partitions.h +++ b/third_party/WebKit/Source/platform/wtf/allocator/Partitions.h
@@ -173,6 +173,8 @@ using base::PartitionBucketMemoryStats; using base::PartitionAllocHooks; +using CheckedSizeT = base::CheckedNumeric<size_t>; + } // namespace WTF #endif // Partitions_h
diff --git a/third_party/leveldatabase/OWNERS b/third_party/leveldatabase/OWNERS index f0cb1cf..80cd612 100644 --- a/third_party/leveldatabase/OWNERS +++ b/third_party/leveldatabase/OWNERS
@@ -1,7 +1,9 @@ +# Primary for bugs, reviews: +pwnall@chromium.org + +# Secondary: cmumford@chromium.org jsbell@chromium.org -kinuko@chromium.org -michaeln@chromium.org # TEAM: storage-dev@chromium.org # COMPONENT: Blink>Storage
diff --git a/tools/gn/visual_studio_writer.cc b/tools/gn/visual_studio_writer.cc index eede7f4..9f72a6f 100644 --- a/tools/gn/visual_studio_writer.cc +++ b/tools/gn/visual_studio_writer.cc
@@ -89,6 +89,9 @@ const char kConfigurationName[] = "GN"; +const char kCharSetUnicode[] = "_UNICODE"; +const char kCharSetMultiByte[] = "_MBCS"; + std::string GetWindowsKitsIncludeDirs(const std::string& win_kit) { std::string kits_path; @@ -223,6 +226,18 @@ return true; } +bool UnicodeTarget(const Target* target) { + for (ConfigValuesIterator it(target); !it.done(); it.Next()) { + for (const std::string& define : it.cur().defines()) { + if (define == kCharSetUnicode) + return true; + if (define == kCharSetMultiByte) + return false; + } + } + return true; +} + } // namespace VisualStudioWriter::SolutionEntry::SolutionEntry(const std::string& _name, @@ -454,7 +469,9 @@ { std::unique_ptr<XmlElementWriter> configuration = project.SubElement( "PropertyGroup", XmlAttributes("Label", "Configuration")); - configuration->SubElement("CharacterSet")->Text("Unicode"); + bool unicode_target = UnicodeTarget(target); + configuration->SubElement("CharacterSet") + ->Text(unicode_target ? "Unicode" : "MultiByte"); std::string configuration_type = GetConfigurationType(target, err); if (configuration_type.empty()) return false;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index afd63ffe..fa221c9 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -22024,7 +22024,7 @@ from previous Chrome versions. --> - <summary>Chrome flags that lead to chrome restart on ChromeOS.</summary> + <summary>Chrome flags that lead to Chrome restart on Chrome OS.</summary> <int value="-2146613579" label="V8Future:disabled"/> <int value="-2143961262" label="D3DVsync:disabled"/> <int value="-2143328006" @@ -22073,6 +22073,7 @@ <int value="-2035126988" label="enabled-new-style-notification"/> <int value="-2033225430" label="NTPMostLikelyFaviconsFromServer:disabled"/> <int value="-2029912304" label="StaleWhileRevalidate2:enabled"/> + <int value="-2028232016" label="spurious-power-button-lid-angle-change"/> <int value="-2025367104" label="enable-material-design-ntp"/> <int value="-2020721975" label="smart-virtual-keyboard"/> <int value="-2020024440" label="scroll-end-effect"/> @@ -22136,6 +22137,7 @@ <int value="-1872867546" label="EnumerateAudioDevices:disabled"/> <int value="-1870961970" label="enable-filemanager-mtp"/> <int value="-1869845022" label="force-show-update-menu-item"/> + <int value="-1868978829" label="spurious-power-button-accel-count"/> <int value="-1867382602" label="WebRTC-H264WithOpenH264FFmpeg:enabled"/> <int value="-1867342522" label="MaterialDesignHistory:enabled"/> <int value="-1861814223" label="MidiManagerDynamicInstantiation:enabled"/> @@ -22992,6 +22994,7 @@ <int value="1211284676" label="V8NoTurbo:enabled"/> <int value="1214455758" label="VideoRotateToFullscreen:disabled"/> <int value="1215531732" label="OmniboxUIExperiments:disabled"/> + <int value="1217907443" label="spurious-power-button-keyboard-accel"/> <int value="1219628795" label="PrintScaling:disabled"/> <int value="1219826373" label="ServiceWorkerNavigationPreload:enabled"/> <int value="1220171692" label="SpeculativeLaunchServiceWorker:enabled"/> @@ -23007,6 +23010,7 @@ <int value="1250071868" label="disable-timezone-tracking-option"/> <int value="1253698118" label="ash-disable-stable-overview-order"/> <int value="1257980502" label="disable-accelerated-video-decode"/> + <int value="1260186484" label="spurious-power-button-screen-accel"/> <int value="1268470658" label="disable-android-password-link"/> <int value="1269940659" label="EnumerateAudioDevices:enabled"/> <int value="1269952439" label="AndroidAIAFetching:disabled"/> @@ -23120,6 +23124,7 @@ <int value="1658644418" label="disable-app-list-voice-search"/> <int value="1661925474" label="silent-debugger-extension-api"/> <int value="1664401033" label="ColorCorrectRendering:enabled"/> + <int value="1665349789" label="spurious-power-button-window"/> <int value="1668611601" label="enable-encrypted-media"/> <int value="1673427566" label="ChromeHomeExpandButton:disabled"/> <int value="1689123607" label="enable-app-link"/>
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py index 69b96ef8..3f02a94 100644 --- a/tools/perf/benchmarks/system_health_smoke_test.py +++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -34,8 +34,6 @@ _DISABLED_TESTS = frozenset({ # crbug.com/733427 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_mobile.browse:news:cnn', # pylint: disable=line-too-long - # cburg.com/721549 - 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_mobile.browse:news:toi', # pylint: disable=line-too-long # crbug.com/702455 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:media:youtube', # pylint: disable=line-too-long # crbug.com/637230
diff --git a/tools/perf/page_sets/data/system_health_mobile.json b/tools/perf/page_sets/data/system_health_mobile.json index 51130058..978bf8c 100644 --- a/tools/perf/page_sets/data/system_health_mobile.json +++ b/tools/perf/page_sets/data/system_health_mobile.json
@@ -58,7 +58,7 @@ "DEFAULT": "system_health_mobile_027.wpr" }, "browse:news:toi": { - "DEFAULT": "system_health_mobile_055.wpr" + "DEFAULT": "system_health_mobile_064.wpr" }, "browse:news:washingtonpost": { "DEFAULT": "system_health_mobile_021.wpr" @@ -234,4 +234,4 @@ }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", "platform_specific": true -} +} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/system_health_mobile_064.wpr.sha1 b/tools/perf/page_sets/data/system_health_mobile_064.wpr.sha1 new file mode 100644 index 0000000..a81ab3f5 --- /dev/null +++ b/tools/perf/page_sets/data/system_health_mobile_064.wpr.sha1
@@ -0,0 +1 @@ +bb16e24570463f2cd0077e83debd47282835d8c3 \ No newline at end of file
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py index fd16b9e6..69bc896 100644 --- a/tools/perf/page_sets/system_health/expectations.py +++ b/tools/perf/page_sets/system_health/expectations.py
@@ -82,8 +82,6 @@ [expectations.ALL_ANDROID], 'crbug.com/726301') self.DisableStory('long_running:tools:gmail-foreground', [expectations.ALL_ANDROID], 'crbug.com/726301') - self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID], - 'crbug.com/728081') self.DisableStory('browse:social:facebook_infinite_scroll', [expectations.ALL], 'crbug.com/728152') self.DisableStory('browse:media:flickr_infinite_scroll', @@ -118,8 +116,6 @@ [expectations.ALL_ANDROID], 'crbug.com/726301') self.DisableStory('long_running:tools:gmail-foreground', [expectations.ALL_ANDROID], 'crbug.com/726301') - self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID], - 'crbug.com/728081') self.DisableStory('browse:social:facebook_infinite_scroll', [expectations.ALL], 'crbug.com/728152') self.DisableStory('browse:media:flickr_infinite_scroll', @@ -199,8 +195,6 @@ 'crbug.com/708300') self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID], 'crbug.com/714650') - self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID], - 'crbug.com/728081') self.DisableStory('browse:social:facebook_infinite_scroll', [expectations.ALL], 'crbug.com/728152') self.DisableStory('browse:media:flickr_infinite_scroll',
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc index 7dbe2b1c..f2d1486d 100644 --- a/ui/android/view_android.cc +++ b/ui/android/view_android.cc
@@ -100,6 +100,10 @@ delegate_ = JavaObjectWeakGlobalRef(env, delegate); } +void ViewAndroid::UpdateFrameInfo(const FrameInfo& frame_info) { + frame_info_ = frame_info; +} + float ViewAndroid::GetDipScale() { return ui::GetScaleFactorForNativeView(this); }
diff --git a/ui/android/view_android.h b/ui/android/view_android.h index c88d878..a988054 100644 --- a/ui/android/view_android.h +++ b/ui/android/view_android.h
@@ -25,6 +25,16 @@ class ViewClient; class WindowAndroid; +// View-related parameters from frame updates. +struct FrameInfo { + gfx::SizeF viewport_size; // In CSS pixels. + float page_scale; + + // Content offset from the top. Used to translate snapshots to + // the correct part of the view. In CSS pixels. + float content_offset; +}; + // A simple container for a UI layer. // At the root of the hierarchy is a WindowAndroid, when attached. // Dispatches input/view events coming from Java layer. Hit testing against @@ -95,12 +105,10 @@ ViewAndroid(); virtual ~ViewAndroid(); - // The content offset is in CSS pixels, and is used to translate - // snapshots to the correct part of the view. - void set_content_offset(float content_offset) { - content_offset_ = content_offset; - } - float content_offset() const { return content_offset_; } + void UpdateFrameInfo(const FrameInfo& frame_info); + float content_offset() const { return frame_info_.content_offset; } + float page_scale() const { return frame_info_.page_scale; } + gfx::SizeF viewport_size() const { return frame_info_.viewport_size; } // Returns the window at the root of this hierarchy, or |null| // if disconnected. @@ -141,10 +149,6 @@ void OnBottomControlsChanged(float bottom_controls_offset, float bottom_content_offset); int GetSystemWindowInsetBottom(); - void set_viewport_size(const gfx::SizeF& viewport_size) { - viewport_size_ = viewport_size; - } - gfx::SizeF viewport_size() const { return viewport_size_; } ScopedAnchorView AcquireAnchorView(); void SetAnchorRect(const base::android::JavaRef<jobject>& anchor, @@ -223,9 +227,7 @@ // In physical pixel. gfx::Size physical_size_; - // In CSS pixel. - gfx::SizeF viewport_size_; // viewport size from frame update. - float content_offset_; // y content offset from the top. + FrameInfo frame_info_; std::unique_ptr<EventForwarder> event_forwarder_;
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn index 27b8fb68..f8a373b 100644 --- a/ui/app_list/BUILD.gn +++ b/ui/app_list/BUILD.gn
@@ -165,6 +165,8 @@ "views/speech_view.h", "views/start_page_view.cc", "views/start_page_view.h", + "views/suggestions_container_view.cc", + "views/suggestions_container_view.h", "views/tile_item_view.cc", "views/tile_item_view.h", "views/top_icon_animation_view.cc",
diff --git a/ui/app_list/views/apps_container_view.h b/ui/app_list/views/apps_container_view.h index dc56ff1..c249ef6 100644 --- a/ui/app_list/views/apps_container_view.h +++ b/ui/app_list/views/apps_container_view.h
@@ -106,8 +106,8 @@ void PrepareToShowApps(AppListFolderItem* folder_item); - AppsGridView* apps_grid_view_; // Owned by views hierarchy. - AppListFolderView* app_list_folder_view_; // Owned by views hierarchy. + AppsGridView* apps_grid_view_; // Owned by views hierarchy. + AppListFolderView* app_list_folder_view_; // Owned by views hierarchy. FolderBackgroundView* folder_background_view_; // Owned by views hierarchy. ShowState show_state_;
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc index ed255d7..e29b41e 100644 --- a/ui/app_list/views/start_page_view.cc +++ b/ui/app_list/views/start_page_view.cc
@@ -27,6 +27,7 @@ #include "ui/app_list/views/search_box_view.h" #include "ui/app_list/views/search_result_container_view.h" #include "ui/app_list/views/search_result_tile_item_view.h" +#include "ui/app_list/views/suggestions_container_view.h" #include "ui/app_list/views/tile_item_view.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/canvas.h" @@ -37,7 +38,6 @@ #include "ui/views/controls/label.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/layout/box_layout.h" -#include "ui/views/layout/grid_layout.h" #include "ui/views/widget/widget.h" namespace app_list { @@ -56,12 +56,6 @@ constexpr int kWebViewWidth = 700; constexpr int kWebViewHeight = 224; -// Tile container constants. -constexpr int kTileSpacing = 7; -constexpr int kNumStartPageTilesCols = 5; -constexpr int kTilesHorizontalMarginLeft = 145; -constexpr int kCenterColumnOfStartPageAppGrid = 3; - constexpr int kLauncherPageBackgroundWidth = 400; } // namespace @@ -98,184 +92,6 @@ DISALLOW_COPY_AND_ASSIGN(CustomLauncherPageBackgroundView); }; -// A container that holds the start page recommendation tiles and the all apps -// tile. -class StartPageView::StartPageTilesContainer - : public SearchResultContainerView { - public: - StartPageTilesContainer(ContentsView* contents_view, - AllAppsTileItemView* all_apps_button, - AppListViewDelegate* view_delegate); - ~StartPageTilesContainer() override; - - TileItemView* GetTileItemView(int index); - - const std::vector<SearchResultTileItemView*>& tile_views() const { - return search_result_tile_views_; - } - - AllAppsTileItemView* all_apps_button() { return all_apps_button_; } - - // Overridden from SearchResultContainerView: - int DoUpdate() override; - void UpdateSelectedIndex(int old_selected, int new_selected) override; - void OnContainerSelected(bool from_bottom, - bool directional_movement) override; - void NotifyFirstResultYIndex(int y_index) override; - int GetYSize() override; - - private: - void CreateAppsGrid(int apps_num); - - ContentsView* contents_view_; - AppListViewDelegate* view_delegate_; - - std::vector<SearchResultTileItemView*> search_result_tile_views_; - AllAppsTileItemView* all_apps_button_; - - DISALLOW_COPY_AND_ASSIGN(StartPageTilesContainer); -}; - -StartPageView::StartPageTilesContainer::StartPageTilesContainer( - ContentsView* contents_view, - AllAppsTileItemView* all_apps_button, - AppListViewDelegate* view_delegate) - : contents_view_(contents_view), - view_delegate_(view_delegate), - all_apps_button_(all_apps_button) { - SetBackground(views::CreateSolidBackground(kLabelBackgroundColor)); - all_apps_button_->SetHoverStyle(TileItemView::HOVER_STYLE_ANIMATE_SHADOW); - all_apps_button_->SetParentBackgroundColor(kLabelBackgroundColor); - - CreateAppsGrid(features::IsFullscreenAppListEnabled() - ? kNumStartPageTilesFullscreen - : kNumStartPageTiles); -} - -StartPageView::StartPageTilesContainer::~StartPageTilesContainer() { -} - -TileItemView* StartPageView::StartPageTilesContainer::GetTileItemView( - int index) { - DCHECK_GT(num_results(), index); - if (index == num_results() - 1) - return all_apps_button_; - - return search_result_tile_views_[index]; -} - -int StartPageView::StartPageTilesContainer::DoUpdate() { - // Ignore updates and disable buttons when transitioning to a different - // state. - if (contents_view_->GetActiveState() != AppListModel::STATE_START) { - for (auto* view : search_result_tile_views_) - view->SetEnabled(false); - - return num_results(); - } - - std::vector<SearchResult*> display_results = - AppListModel::FilterSearchResultsByDisplayType( - results(), SearchResult::DISPLAY_RECOMMENDATION, - features::IsFullscreenAppListEnabled() ? kNumStartPageTilesFullscreen - : kNumStartPageTiles); - if (display_results.size() != search_result_tile_views_.size()) { - // We should recreate the grid layout in this case. - for (size_t i = 0; i < search_result_tile_views_.size(); ++i) - delete search_result_tile_views_[i]; - search_result_tile_views_.clear(); - RemoveChildView(all_apps_button_); - - CreateAppsGrid(features::IsFullscreenAppListEnabled() - ? kNumStartPageTilesFullscreen - : std::min(kNumStartPageTiles, display_results.size())); - } - - // Update the tile item results. - for (size_t i = 0; i < search_result_tile_views_.size(); ++i) { - SearchResult* item = nullptr; - if (i < display_results.size()) - item = display_results[i]; - search_result_tile_views_[i]->SetSearchResult(item); - search_result_tile_views_[i]->SetEnabled(true); - } - - parent()->Layout(); - // Add 1 to the results size to account for the all apps button. - return display_results.size() + 1; -} - -void StartPageView::StartPageTilesContainer::UpdateSelectedIndex( - int old_selected, - int new_selected) { - if (old_selected >= 0 && old_selected < num_results()) - GetTileItemView(old_selected)->SetSelected(false); - - if (new_selected >= 0 && new_selected < num_results()) - GetTileItemView(new_selected)->SetSelected(true); -} - -void StartPageView::StartPageTilesContainer::OnContainerSelected( - bool /*from_bottom*/, - bool /*directional_movement*/) { - NOTREACHED(); -} - -void StartPageView::StartPageTilesContainer::NotifyFirstResultYIndex( - int /*y_index*/) { - NOTREACHED(); -} - -int StartPageView::StartPageTilesContainer::GetYSize() { - NOTREACHED(); - return 0; -} - -void StartPageView::StartPageTilesContainer::CreateAppsGrid(int apps_num) { - DCHECK(search_result_tile_views_.empty()); - views::GridLayout* tiles_layout_manager = new views::GridLayout(this); - SetLayoutManager(tiles_layout_manager); - - views::ColumnSet* column_set = tiles_layout_manager->AddColumnSet(0); - column_set->AddPaddingColumn(0, kTilesHorizontalMarginLeft); - for (int col = 0; col < kNumStartPageTilesCols; ++col) { - column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, - views::GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, kTileSpacing); - } - - // Add SearchResultTileItemViews to the container. - int i = 0; - search_result_tile_views_.reserve(apps_num); - for (; i < apps_num; ++i) { - SearchResultTileItemView* tile_item = - new SearchResultTileItemView(this, view_delegate_); - if (i % kNumStartPageTilesCols == 0) - tiles_layout_manager->StartRow(0, 0); - tiles_layout_manager->AddView(tile_item); - AddChildView(tile_item); - tile_item->SetParentBackgroundColor(kLabelBackgroundColor); - tile_item->SetHoverStyle(TileItemView::HOVER_STYLE_ANIMATE_SHADOW); - search_result_tile_views_.emplace_back(tile_item); - } - - all_apps_button_->UpdateIcon(); - if (features::IsFullscreenAppListEnabled()) { - // Also add a special "all apps" button to the middle of the next row of the - // container. - tiles_layout_manager->StartRow(0, 0); - tiles_layout_manager->SkipColumns(kCenterColumnOfStartPageAppGrid); - } else { - // Also add a special "all apps" button to the end of the next row of the - // container. - if (i % kNumStartPageTilesCols == 0) - tiles_layout_manager->StartRow(0, 0); - } - - tiles_layout_manager->AddView(all_apps_button_); - AddChildView(all_apps_button_); -} - //////////////////////////////////////////////////////////////////////////////// // StartPageView implementation: StartPageView::StartPageView(AppListMainView* app_list_main_view, @@ -287,11 +103,10 @@ instant_container_(new views::View), custom_launcher_page_background_(new CustomLauncherPageBackgroundView( view_delegate_->GetModel()->custom_launcher_page_name())), - tiles_container_(new StartPageTilesContainer( + suggestions_container_(new SuggestionsContainerView( app_list_main_view->contents_view(), new AllAppsTileItemView(app_list_main_view_->contents_view(), - app_list_view), - view_delegate)), + app_list_view))), is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) { search_box_spacer_view_->SetPreferredSize(gfx::Size( is_fullscreen_app_list_enabled_ ? kStartPageSearchBoxWidthFullscreen @@ -309,10 +124,10 @@ } // The view containing the start page tiles. - AddChildView(tiles_container_); + AddChildView(suggestions_container_); AddChildView(custom_launcher_page_background_); - tiles_container_->SetResults(view_delegate_->GetModel()->results()); + suggestions_container_->SetResults(view_delegate_->GetModel()->results()); } StartPageView::~StartPageView() = default; @@ -362,20 +177,20 @@ } void StartPageView::Reset() { - tiles_container_->Update(); + suggestions_container_->Update(); } void StartPageView::UpdateForTesting() { - tiles_container_->Update(); + suggestions_container_->Update(); } const std::vector<SearchResultTileItemView*>& StartPageView::tile_views() const { - return tiles_container_->tile_views(); + return suggestions_container_->tile_views(); } TileItemView* StartPageView::all_apps_button() const { - return tiles_container_->all_apps_button(); + return suggestions_container_->all_apps_button(); } void StartPageView::OnShown() { @@ -387,8 +202,8 @@ custom_page_view->SetVisible( app_list_main_view_->ShouldShowCustomLauncherPage()); } - tiles_container_->ClearSelectedIndex(); - tiles_container_->Update(); + suggestions_container_->ClearSelectedIndex(); + suggestions_container_->Update(); custom_launcher_page_background_->SetSelected(false); } @@ -422,8 +237,8 @@ indicator_->SetBoundsRect(indicator_rect); bounds.Inset(0, indicator_->GetPreferredSize().height(), 0, 0); } - bounds.set_height(tiles_container_->GetHeightForWidth(bounds.width())); - tiles_container_->SetBoundsRect(bounds); + bounds.set_height(suggestions_container_->GetHeightForWidth(bounds.width())); + suggestions_container_->SetBoundsRect(bounds); CustomLauncherPageView* custom_launcher_page_view = app_list_main_view_->contents_view()->custom_page_view(); @@ -441,10 +256,10 @@ bool StartPageView::OnKeyPressed(const ui::KeyEvent& event) { const int forward_dir = base::i18n::IsRTL() ? -1 : 1; - int selected_index = tiles_container_->selected_index(); + int selected_index = suggestions_container_->selected_index(); if (custom_launcher_page_background_->selected()) { - selected_index = tiles_container_->num_results(); + selected_index = suggestions_container_->num_results(); switch (event.key_code()) { case ui::VKEY_RETURN: MaybeOpenCustomLauncherPage(); @@ -453,7 +268,7 @@ break; } } else if (selected_index >= 0 && - tiles_container_->GetTileItemView(selected_index) + suggestions_container_->GetTileItemView(selected_index) ->OnKeyPressed(event)) { return true; } @@ -465,7 +280,7 @@ break; case ui::VKEY_RIGHT: // Don't go to the custom launcher page from the All apps tile. - if (selected_index != tiles_container_->num_results() - 1) + if (selected_index != suggestions_container_->num_results() - 1) dir = forward_dir; break; case ui::VKEY_UP: @@ -479,8 +294,8 @@ // Down selects the first tile if nothing is selected. dir = 1; // If something is selected, select the custom launcher page. - if (tiles_container_->IsValidSelectionIndex(selected_index)) - selected_index = tiles_container_->num_results() - 1; + if (suggestions_container_->IsValidSelectionIndex(selected_index)) + selected_index = suggestions_container_->num_results() - 1; break; case ui::VKEY_TAB: dir = event.IsShiftDown() ? -1 : 1; @@ -494,27 +309,28 @@ if (selected_index == -1) { custom_launcher_page_background_->SetSelected(false); - tiles_container_->SetSelectedIndex( - dir == -1 ? tiles_container_->num_results() - 1 : 0); + suggestions_container_->SetSelectedIndex( + dir == -1 ? suggestions_container_->num_results() - 1 : 0); return true; } int selection_index = selected_index + dir; - if (tiles_container_->IsValidSelectionIndex(selection_index)) { + if (suggestions_container_->IsValidSelectionIndex(selection_index)) { custom_launcher_page_background_->SetSelected(false); - tiles_container_->SetSelectedIndex(selection_index); + suggestions_container_->SetSelectedIndex(selection_index); return true; } - if (selection_index == tiles_container_->num_results() && + if (selection_index == suggestions_container_->num_results() && app_list_main_view_->ShouldShowCustomLauncherPage()) { custom_launcher_page_background_->SetSelected(true); - tiles_container_->ClearSelectedIndex(); + suggestions_container_->ClearSelectedIndex(); return true; } if (event.key_code() == ui::VKEY_TAB && selection_index == -1) - tiles_container_->ClearSelectedIndex(); // ContentsView will handle focus. + suggestions_container_ + ->ClearSelectedIndex(); // ContentsView will handle focus. return false; } @@ -566,7 +382,7 @@ } TileItemView* StartPageView::GetTileItemView(size_t index) { - return tiles_container_->GetTileItemView(index); + return suggestions_container_->GetTileItemView(index); } } // namespace app_list
diff --git a/ui/app_list/views/start_page_view.h b/ui/app_list/views/start_page_view.h index 21c51ff..0c4aef3c 100644 --- a/ui/app_list/views/start_page_view.h +++ b/ui/app_list/views/start_page_view.h
@@ -21,6 +21,7 @@ class CustomLauncherPageBackgroundView; class IndicatorChipView; class SearchResultTileItemView; +class SuggestionsContainerView; class TileItemView; // The start page for the app list. @@ -54,8 +55,6 @@ void OnScrollEvent(ui::ScrollEvent* event) override; private: - class StartPageTilesContainer; - void InitInstantContainer(); void MaybeOpenCustomLauncherPage(); @@ -76,9 +75,10 @@ views::View* instant_container_; // Owned by views hierarchy. CustomLauncherPageBackgroundView* - custom_launcher_page_background_; // Owned by views hierarchy. - IndicatorChipView* indicator_ = nullptr; // Owned by views hierarchy. - StartPageTilesContainer* tiles_container_; // Owned by views hierarchy. + custom_launcher_page_background_; // Owned by views hierarchy. + IndicatorChipView* indicator_ = nullptr; // Owned by views hierarchy. + SuggestionsContainerView* + suggestions_container_; // Owned by views hierarchy. const bool is_fullscreen_app_list_enabled_;
diff --git a/ui/app_list/views/suggestions_container_view.cc b/ui/app_list/views/suggestions_container_view.cc new file mode 100644 index 0000000..21ac77fa --- /dev/null +++ b/ui/app_list/views/suggestions_container_view.cc
@@ -0,0 +1,169 @@ +// Copyright 2014 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 "ui/app_list/views/suggestions_container_view.h" + +#include "ui/app_list/app_list_constants.h" +#include "ui/app_list/app_list_features.h" +#include "ui/app_list/views/all_apps_tile_item_view.h" +#include "ui/app_list/views/app_list_main_view.h" +#include "ui/app_list/views/contents_view.h" +#include "ui/app_list/views/search_result_tile_item_view.h" +#include "ui/views/background.h" +#include "ui/views/layout/grid_layout.h" + +namespace app_list { + +namespace { + +constexpr int kTileSpacing = 7; +constexpr int kNumTilesCols = 5; +constexpr int kTilesHorizontalMarginLeft = 145; +constexpr int kCenterColumnOfStartPageAppGrid = 3; + +} // namespace + +SuggestionsContainerView::SuggestionsContainerView( + ContentsView* contents_view, + AllAppsTileItemView* all_apps_button) + : contents_view_(contents_view), + all_apps_button_(all_apps_button), + is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) { + DCHECK(contents_view); + view_delegate_ = contents_view_->app_list_main_view()->view_delegate(); + SetBackground(views::CreateSolidBackground(kLabelBackgroundColor)); + if (all_apps_button_) { + all_apps_button_->SetHoverStyle(TileItemView::HOVER_STYLE_ANIMATE_SHADOW); + all_apps_button_->SetParentBackgroundColor(kLabelBackgroundColor); + } + + CreateAppsGrid(is_fullscreen_app_list_enabled_ ? kNumStartPageTilesFullscreen + : kNumStartPageTiles); +} + +SuggestionsContainerView::~SuggestionsContainerView() = default; + +TileItemView* SuggestionsContainerView::GetTileItemView(int index) { + DCHECK_GT(num_results(), index); + if (all_apps_button_ && index == num_results() - 1) + return all_apps_button_; + + return search_result_tile_views_[index]; +} + +int SuggestionsContainerView::DoUpdate() { + // Ignore updates and disable buttons when transitioning to a different + // state. + if (contents_view_->GetActiveState() != AppListModel::STATE_START) { + for (auto* view : search_result_tile_views_) + view->SetEnabled(false); + + return num_results(); + } + + std::vector<SearchResult*> display_results = + AppListModel::FilterSearchResultsByDisplayType( + results(), SearchResult::DISPLAY_RECOMMENDATION, + is_fullscreen_app_list_enabled_ ? kNumStartPageTilesFullscreen + : kNumStartPageTiles); + if (display_results.size() != search_result_tile_views_.size()) { + // We should recreate the grid layout in this case. + for (size_t i = 0; i < search_result_tile_views_.size(); ++i) + delete search_result_tile_views_[i]; + search_result_tile_views_.clear(); + if (all_apps_button_) + RemoveChildView(all_apps_button_); + + CreateAppsGrid(is_fullscreen_app_list_enabled_ + ? kNumStartPageTilesFullscreen + : std::min(kNumStartPageTiles, display_results.size())); + } + + // Update the tile item results. + for (size_t i = 0; i < search_result_tile_views_.size(); ++i) { + SearchResult* item = nullptr; + if (i < display_results.size()) + item = display_results[i]; + search_result_tile_views_[i]->SetSearchResult(item); + search_result_tile_views_[i]->SetEnabled(true); + } + + parent()->Layout(); + // Add 1 to the results size to account for the all apps button. + return display_results.size() + 1; +} + +void SuggestionsContainerView::UpdateSelectedIndex(int old_selected, + int new_selected) { + if (old_selected >= 0 && old_selected < num_results()) + GetTileItemView(old_selected)->SetSelected(false); + + if (new_selected >= 0 && new_selected < num_results()) + GetTileItemView(new_selected)->SetSelected(true); +} + +void SuggestionsContainerView::OnContainerSelected( + bool /*from_bottom*/, + bool /*directional_movement*/) { + NOTREACHED(); +} + +void SuggestionsContainerView::NotifyFirstResultYIndex(int /*y_index*/) { + NOTREACHED(); +} + +int SuggestionsContainerView::GetYSize() { + NOTREACHED(); + return 0; +} + +void SuggestionsContainerView::CreateAppsGrid(int apps_num) { + DCHECK(search_result_tile_views_.empty()); + views::GridLayout* tiles_layout_manager = new views::GridLayout(this); + SetLayoutManager(tiles_layout_manager); + + views::ColumnSet* column_set = tiles_layout_manager->AddColumnSet(0); + column_set->AddPaddingColumn(0, kTilesHorizontalMarginLeft); + for (int col = 0; col < kNumTilesCols; ++col) { + column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, + views::GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kTileSpacing); + } + + // Add SearchResultTileItemViews to the container. + int i = 0; + search_result_tile_views_.reserve(apps_num); + for (; i < apps_num; ++i) { + SearchResultTileItemView* tile_item = + new SearchResultTileItemView(this, view_delegate_); + if (i % kNumTilesCols == 0) + tiles_layout_manager->StartRow(0, 0); + tiles_layout_manager->AddView(tile_item); + AddChildView(tile_item); + tile_item->SetParentBackgroundColor(kLabelBackgroundColor); + tile_item->SetHoverStyle(TileItemView::HOVER_STYLE_ANIMATE_SHADOW); + search_result_tile_views_.emplace_back(tile_item); + } + + if (all_apps_button_) + all_apps_button_->UpdateIcon(); + if (is_fullscreen_app_list_enabled_) { + // Also add a special "all apps" button to the middle of the next row of the + // container. + tiles_layout_manager->StartRow(0, 0); + tiles_layout_manager->SkipColumns(kCenterColumnOfStartPageAppGrid); + } else { + // Also add a special "all apps" button to the end of the next row of the + // container. + if (i % kNumTilesCols == 0) + tiles_layout_manager->StartRow(0, 0); + } + + if (all_apps_button_) { + tiles_layout_manager->AddView(all_apps_button_); + AddChildView(all_apps_button_); + } +} + +} // namespace app_list
diff --git a/ui/app_list/views/suggestions_container_view.h b/ui/app_list/views/suggestions_container_view.h new file mode 100644 index 0000000..498d6b9 --- /dev/null +++ b/ui/app_list/views/suggestions_container_view.h
@@ -0,0 +1,60 @@ +// Copyright 2014 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 UI_APP_LIST_VIEWS_SUGGESTIONS_CONTAINER_VIEW_H_ +#define UI_APP_LIST_VIEWS_SUGGESTIONS_CONTAINER_VIEW_H_ + +#include <vector> + +#include "base/macros.h" +#include "ui/app_list/views/search_result_container_view.h" + +namespace app_list { + +class AllAppsTileItemView; +class AppListViewDelegate; +class ContentsView; +class SearchResultTileItemView; +class TileItemView; + +// A container that holds the suggested app tiles and the all apps tile. +class SuggestionsContainerView : public SearchResultContainerView { + public: + SuggestionsContainerView(ContentsView* contents_view, + AllAppsTileItemView* all_apps_button); + ~SuggestionsContainerView() override; + + TileItemView* GetTileItemView(int index); + + const std::vector<SearchResultTileItemView*>& tile_views() const { + return search_result_tile_views_; + } + + AllAppsTileItemView* all_apps_button() { return all_apps_button_; } + + // Overridden from SearchResultContainerView: + int DoUpdate() override; + void UpdateSelectedIndex(int old_selected, int new_selected) override; + void OnContainerSelected(bool from_bottom, + bool directional_movement) override; + void NotifyFirstResultYIndex(int y_index) override; + int GetYSize() override; + + private: + void CreateAppsGrid(int apps_num); + + ContentsView* contents_view_ = nullptr; + AppListViewDelegate* view_delegate_ = nullptr; + + std::vector<SearchResultTileItemView*> search_result_tile_views_; + AllAppsTileItemView* all_apps_button_ = nullptr; + + const bool is_fullscreen_app_list_enabled_; + + DISALLOW_COPY_AND_ASSIGN(SuggestionsContainerView); +}; + +} // namespace app_list + +#endif // UI_APP_LIST_VIEWS_SUGGESTIONS_CONTAINER_VIEW_H_
diff --git a/ui/base/ime/chromeos/input_method_manager.h b/ui/base/ime/chromeos/input_method_manager.h index 2ad022dd..be32e0d 100644 --- a/ui/base/ime/chromeos/input_method_manager.h +++ b/ui/base/ime/chromeos/input_method_manager.h
@@ -19,7 +19,6 @@ class Profile; namespace ui { -class Accelerator; class IMEEngineHandlerInterface; } // namespace ui @@ -185,11 +184,6 @@ const std::string& locale, const std::string& layout) = 0; - // Returns whether the input method (or keyboard layout) can be switched - // to the next or previous one. Returns false if only one input method is - // enabled. - virtual bool CanCycleInputMethod() = 0; - // Switches the current input method (or keyboard layout) to the next one. virtual void SwitchToNextInputMethod() = 0; @@ -197,14 +191,6 @@ // one. virtual void SwitchToPreviousInputMethod() = 0; - // Returns true if the input method can be switched to the input method - // associated with |accelerator|. - virtual bool CanSwitchInputMethod(const ui::Accelerator& accelerator) = 0; - - // Switches to an input method (or keyboard layout) which is associated with - // the |accelerator|. - virtual void SwitchInputMethod(const ui::Accelerator& accelerator) = 0; - // Gets the descriptor of the input method which is currently selected. virtual InputMethodDescriptor GetCurrentInputMethod() const = 0;
diff --git a/ui/base/ime/chromeos/mock_input_method_manager.cc b/ui/base/ime/chromeos/mock_input_method_manager.cc index a28f490e..f40d0798 100644 --- a/ui/base/ime/chromeos/mock_input_method_manager.cc +++ b/ui/base/ime/chromeos/mock_input_method_manager.cc
@@ -71,22 +71,10 @@ const std::string& locale, const std::string& layout) {} -bool MockInputMethodManager::State::CanCycleInputMethod() { - return true; -} - void MockInputMethodManager::State::SwitchToNextInputMethod() {} void MockInputMethodManager::State::SwitchToPreviousInputMethod() {} -bool MockInputMethodManager::State::CanSwitchInputMethod( - const ui::Accelerator& accelerator) { - return true; -} - -void MockInputMethodManager::State::SwitchInputMethod( - const ui::Accelerator& accelerator) {} - InputMethodDescriptor MockInputMethodManager::State::GetCurrentInputMethod() const { InputMethodDescriptor descriptor;
diff --git a/ui/base/ime/chromeos/mock_input_method_manager.h b/ui/base/ime/chromeos/mock_input_method_manager.h index 946e129..62ae04c 100644 --- a/ui/base/ime/chromeos/mock_input_method_manager.h +++ b/ui/base/ime/chromeos/mock_input_method_manager.h
@@ -46,11 +46,8 @@ void SetInputMethodLoginDefault() override; void SetInputMethodLoginDefaultFromVPD(const std::string& locale, const std::string& layout) override; - bool CanCycleInputMethod() override; void SwitchToNextInputMethod() override; void SwitchToPreviousInputMethod() override; - bool CanSwitchInputMethod(const ui::Accelerator& accelerator) override; - void SwitchInputMethod(const ui::Accelerator& accelerator) override; InputMethodDescriptor GetCurrentInputMethod() const override; bool ReplaceEnabledInputMethods( const std::vector<std::string>& new_active_input_method_ids) override;
diff --git a/ui/display/manager/managed_display_info.cc b/ui/display/manager/managed_display_info.cc index c1fc554..850aa54 100644 --- a/ui/display/manager/managed_display_info.cc +++ b/ui/display/manager/managed_display_info.cc
@@ -393,6 +393,12 @@ UpdateDisplaySize(); } +float ManagedDisplayInfo::GetDensityRatio() const { + if (Use125DSFForUIScaling() && device_scale_factor_ == 1.25f) + return 1.0f; + return device_scale_factor_; +} + float ManagedDisplayInfo::GetEffectiveDeviceScaleFactor() const { if (Use125DSFForUIScaling() && device_scale_factor_ == 1.25f) return (configured_ui_scale_ == 0.8f) ? 1.25f : 1.0f;
diff --git a/ui/display/manager/managed_display_info.h b/ui/display/manager/managed_display_info.h index 0a2863a..e52e05e 100644 --- a/ui/display/manager/managed_display_info.h +++ b/ui/display/manager/managed_display_info.h
@@ -227,6 +227,10 @@ // Returns the rotation set by a given |source|. Display::Rotation GetRotation(Display::RotationSource source) const; + // Returns a measure of density relative to a display with 1.0 DSF. Unlike the + // effective DSF, this is independent from the UI scale. + float GetDensityRatio() const; + // Returns the ui scale and device scale factor actually used to create // display that chrome sees. This can be different from one obtained // from dispaly or one specified by a user in following situation.