| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/renderer/gamepad_shared_memory_reader.h" | |
| 6 | |
| 7 #include "base/metrics/histogram_macros.h" | |
| 8 #include "base/trace_event/trace_event.h" | |
| 9 #include "content/public/renderer/render_thread.h" | |
| 10 #include "content/renderer/renderer_blink_platform_impl.h" | |
| 11 #include "ipc/ipc_sync_message_filter.h" | |
| 12 #include "services/service_manager/public/cpp/interface_provider.h" | |
| 13 #include "third_party/WebKit/public/platform/WebGamepadListener.h" | |
| 14 #include "third_party/WebKit/public/platform/WebPlatformEventListener.h" | |
| 15 | |
| 16 namespace content { | |
| 17 | |
| 18 GamepadSharedMemoryReader::GamepadSharedMemoryReader(RenderThread* thread) | |
| 19 : RendererGamepadProvider(thread), | |
| 20 gamepad_hardware_buffer_(NULL), | |
| 21 ever_interacted_with_(false), | |
| 22 binding_(this) { | |
| 23 if (thread) { | |
| 24 thread->GetRemoteInterfaces()->GetInterface( | |
| 25 mojo::GetProxy(&gamepad_monitor_)); | |
| 26 gamepad_monitor_->SetObserver(binding_.CreateInterfacePtrAndBind()); | |
| 27 } | |
| 28 } | |
| 29 | |
| 30 void GamepadSharedMemoryReader::SendStartMessage() { | |
| 31 if (gamepad_monitor_) { | |
| 32 gamepad_monitor_->GamepadStartPolling(&renderer_shared_buffer_handle_); | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 void GamepadSharedMemoryReader::SendStopMessage() { | |
| 37 if (gamepad_monitor_) { | |
| 38 gamepad_monitor_->GamepadStopPolling(); | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 void GamepadSharedMemoryReader::Start( | |
| 43 blink::WebPlatformEventListener* listener) { | |
| 44 PlatformEventObserver::Start(listener); | |
| 45 | |
| 46 // If we don't get a valid handle from the browser, don't try to Map (we're | |
| 47 // probably out of memory or file handles). | |
| 48 bool valid_handle = renderer_shared_buffer_handle_.is_valid(); | |
| 49 UMA_HISTOGRAM_BOOLEAN("Gamepad.ValidSharedMemoryHandle", valid_handle); | |
| 50 if (!valid_handle) | |
| 51 return; | |
| 52 | |
| 53 renderer_shared_buffer_mapping_ = | |
| 54 renderer_shared_buffer_handle_->Map(sizeof(GamepadHardwareBuffer)); | |
| 55 CHECK(renderer_shared_buffer_mapping_); | |
| 56 void* memory = renderer_shared_buffer_mapping_.get(); | |
| 57 CHECK(memory); | |
| 58 gamepad_hardware_buffer_ = | |
| 59 static_cast<GamepadHardwareBuffer*>(memory); | |
| 60 } | |
| 61 | |
| 62 void GamepadSharedMemoryReader::SampleGamepads(blink::WebGamepads& gamepads) { | |
| 63 // Blink should have started observing at that point. | |
| 64 CHECK(is_observing()); | |
| 65 | |
| 66 // ========== | |
| 67 // DANGER | |
| 68 // ========== | |
| 69 // | |
| 70 // This logic is duplicated in Pepper as well. If you change it, that also | |
| 71 // needs to be in sync. See ppapi/proxy/gamepad_resource.cc. | |
| 72 blink::WebGamepads read_into; | |
| 73 TRACE_EVENT0("GAMEPAD", "SampleGamepads"); | |
| 74 | |
| 75 if (!renderer_shared_buffer_handle_.is_valid()) | |
| 76 return; | |
| 77 | |
| 78 // Only try to read this many times before failing to avoid waiting here | |
| 79 // very long in case of contention with the writer. TODO(scottmg) Tune this | |
| 80 // number (as low as 1?) if histogram shows distribution as mostly | |
| 81 // 0-and-maximum. | |
| 82 const int kMaximumContentionCount = 10; | |
| 83 int contention_count = -1; | |
| 84 base::subtle::Atomic32 version; | |
| 85 do { | |
| 86 version = gamepad_hardware_buffer_->seqlock.ReadBegin(); | |
| 87 memcpy(&read_into, &gamepad_hardware_buffer_->data, sizeof(read_into)); | |
| 88 ++contention_count; | |
| 89 if (contention_count == kMaximumContentionCount) | |
| 90 break; | |
| 91 } while (gamepad_hardware_buffer_->seqlock.ReadRetry(version)); | |
| 92 UMA_HISTOGRAM_COUNTS("Gamepad.ReadContentionCount", contention_count); | |
| 93 | |
| 94 if (contention_count >= kMaximumContentionCount) { | |
| 95 // We failed to successfully read, presumably because the hardware | |
| 96 // thread was taking unusually long. Don't copy the data to the output | |
| 97 // buffer, and simply leave what was there before. | |
| 98 return; | |
| 99 } | |
| 100 | |
| 101 // New data was read successfully, copy it into the output buffer. | |
| 102 memcpy(&gamepads, &read_into, sizeof(gamepads)); | |
| 103 | |
| 104 if (!ever_interacted_with_) { | |
| 105 // Clear the connected flag if the user hasn't interacted with any of the | |
| 106 // gamepads to prevent fingerprinting. The actual data is not cleared. | |
| 107 // WebKit will only copy out data into the JS buffers for connected | |
| 108 // gamepads so this is sufficient. | |
| 109 for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; i++) | |
| 110 gamepads.items[i].connected = false; | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 GamepadSharedMemoryReader::~GamepadSharedMemoryReader() { | |
| 115 StopIfObserving(); | |
| 116 } | |
| 117 | |
| 118 void GamepadSharedMemoryReader::GamepadConnected( | |
| 119 int index, | |
| 120 const blink::WebGamepad& gamepad) { | |
| 121 // The browser already checks if the user actually interacted with a device. | |
| 122 ever_interacted_with_ = true; | |
| 123 | |
| 124 if (listener()) | |
| 125 listener()->didConnectGamepad(index, gamepad); | |
| 126 } | |
| 127 | |
| 128 void GamepadSharedMemoryReader::GamepadDisconnected( | |
| 129 int index, | |
| 130 const blink::WebGamepad& gamepad) { | |
| 131 if (listener()) | |
| 132 listener()->didDisconnectGamepad(index, gamepad); | |
| 133 } | |
| 134 | |
| 135 } // namespace content | |
| OLD | NEW |