Home | History | Annotate | Download | only in renderer
      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/debug/trace_event.h"
      8 #include "base/metrics/histogram.h"
      9 #include "content/common/gamepad_messages.h"
     10 #include "content/common/gamepad_user_gesture.h"
     11 #include "content/public/renderer/render_thread.h"
     12 #include "content/common/gamepad_hardware_buffer.h"
     13 #include "ipc/ipc_sync_message_filter.h"
     14 
     15 namespace content {
     16 
     17 GamepadSharedMemoryReader::GamepadSharedMemoryReader()
     18     : gamepad_hardware_buffer_(NULL),
     19       ever_interacted_with_(false) {
     20   CHECK(RenderThread::Get()->Send(new GamepadHostMsg_StartPolling(
     21       &renderer_shared_memory_handle_)));
     22   // If we don't get a valid handle from the browser, don't try to Map (we're
     23   // probably out of memory or file handles).
     24   bool valid_handle = base::SharedMemory::IsHandleValid(
     25       renderer_shared_memory_handle_);
     26   UMA_HISTOGRAM_BOOLEAN("Gamepad.ValidSharedMemoryHandle", valid_handle);
     27   if (!valid_handle)
     28     return;
     29   renderer_shared_memory_.reset(
     30       new base::SharedMemory(renderer_shared_memory_handle_, true));
     31   CHECK(renderer_shared_memory_->Map(sizeof(GamepadHardwareBuffer)));
     32   void *memory = renderer_shared_memory_->memory();
     33   CHECK(memory);
     34   gamepad_hardware_buffer_ =
     35       static_cast<GamepadHardwareBuffer*>(memory);
     36 }
     37 
     38 void GamepadSharedMemoryReader::SampleGamepads(WebKit::WebGamepads& gamepads) {
     39   // ==========
     40   //   DANGER
     41   // ==========
     42   //
     43   // This logic is duplicated in Pepper as well. If you change it, that also
     44   // needs to be in sync. See ppapi/proxy/gamepad_resource.cc.
     45   WebKit::WebGamepads read_into;
     46   TRACE_EVENT0("GAMEPAD", "SampleGamepads");
     47 
     48   if (!base::SharedMemory::IsHandleValid(renderer_shared_memory_handle_))
     49     return;
     50 
     51   // Only try to read this many times before failing to avoid waiting here
     52   // very long in case of contention with the writer. TODO(scottmg) Tune this
     53   // number (as low as 1?) if histogram shows distribution as mostly
     54   // 0-and-maximum.
     55   const int kMaximumContentionCount = 10;
     56   int contention_count = -1;
     57   base::subtle::Atomic32 version;
     58   do {
     59     version = gamepad_hardware_buffer_->sequence.ReadBegin();
     60     memcpy(&read_into, &gamepad_hardware_buffer_->buffer, sizeof(read_into));
     61     ++contention_count;
     62     if (contention_count == kMaximumContentionCount)
     63       break;
     64   } while (gamepad_hardware_buffer_->sequence.ReadRetry(version));
     65   UMA_HISTOGRAM_COUNTS("Gamepad.ReadContentionCount", contention_count);
     66 
     67   if (contention_count >= kMaximumContentionCount) {
     68     // We failed to successfully read, presumably because the hardware
     69     // thread was taking unusually long. Don't copy the data to the output
     70     // buffer, and simply leave what was there before.
     71     return;
     72   }
     73 
     74   // New data was read successfully, copy it into the output buffer.
     75   memcpy(&gamepads, &read_into, sizeof(gamepads));
     76 
     77   if (!ever_interacted_with_) {
     78     if (GamepadsHaveUserGesture(gamepads)) {
     79       ever_interacted_with_ = true;
     80     } else {
     81       // Clear the connected flag if the user hasn't interacted with any of the
     82       // gamepads to prevent fingerprinting. The actual data is not cleared.
     83       // WebKit will only copy out data into the JS buffers for connected
     84       // gamepads so this is sufficient.
     85       for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; i++)
     86         gamepads.items[i].connected = false;
     87     }
     88   }
     89 }
     90 
     91 GamepadSharedMemoryReader::~GamepadSharedMemoryReader() {
     92   RenderThread::Get()->Send(new GamepadHostMsg_StopPolling());
     93 }
     94 
     95 } // namespace content
     96