| 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 |