Index: app/surface/transport_dib.h |
diff --git a/app/surface/transport_dib.h b/app/surface/transport_dib.h |
index 6606c2b675da22a87681d513ba76e8130ba5e9f2..37a391209054027197a9cd5c3f75ea9e641c91cf 100644 |
--- a/app/surface/transport_dib.h |
+++ b/app/surface/transport_dib.h |
@@ -7,6 +7,7 @@ |
#pragma once |
#include "base/basictypes.h" |
+#include "base/process.h" |
#if defined(OS_WIN) || defined(OS_MACOSX) |
#include "base/shared_memory.h" |
@@ -31,13 +32,55 @@ class TransportDIB { |
public: |
~TransportDIB(); |
- // Two typedefs are defined. A Handle is the type which can be sent over |
- // the wire so that the remote side can map the transport DIB. The Id typedef |
- // is sufficient to identify the transport DIB when you know that the remote |
- // side already may have it mapped. |
+ // Two typedefs are defined. A |Handle| can be sent over the wire so that the |
+ // remote side can map the |TransportDIB|. These handles may be reused from |
+ // previous DIBs. An |Id| is unique and never reused, but it is not sufficient |
+ // to map the DIB. |
#if defined(OS_WIN) |
- typedef HANDLE Handle; |
- // On Windows, the Id type includes a sequence number (epoch) to solve an ABA |
+ // On Windows, a |Handle| is a combination of the section (i.e., file mapping) |
+ // handle and the ID of the corresponding process. When the DIB is mapped in |
+ // a remote process, the section handle is duplicated for use in that process. |
+ // However, if the remote process does not have permission to duplicate the |
+ // handle, the first process must duplicate the handle before sending it. |
+ // E.g., this is necessary if the DIB is created in the browser and will be |
+ // mapped in the sandboxed renderer. |
+ class TransferrableSectionHandle { |
+ public: |
+ TransferrableSectionHandle() |
+ : section_(NULL), owner_id_(NULL), should_dup_on_map_(false) { |
+ } |
+ |
+ TransferrableSectionHandle(HANDLE section, base::ProcessId owner_id, |
+ bool should_dup_on_map) |
+ : section_(section), |
+ owner_id_(owner_id), |
+ should_dup_on_map_(should_dup_on_map) { |
+ } |
+ |
+ // Duplicates the handle for use in the given process. |
+ TransferrableSectionHandle DupForProcess( |
+ base::ProcessHandle new_owner) const; |
+ |
+ // Closes this handle. This should be called if this handle was duplicated |
+ // and is not owned by a TransportDIB. |
+ void Close() const; |
+ |
+ // Returns true if this handle refers to an actual file mapping. |
+ bool is_valid() const { return section_ != NULL && owner_id_ != NULL; } |
+ |
+ HANDLE section() const { return section_; } |
+ base::ProcessId owner_id() const { return owner_id_; } |
+ bool should_dup_on_map() const { return should_dup_on_map_; } |
+ |
+ private: |
+ HANDLE section_; |
+ base::ProcessId owner_id_; |
+ // Whether the handle should be duplicated when the DIB is mapped. |
+ bool should_dup_on_map_; |
+ }; |
+ typedef TransferrableSectionHandle Handle; |
+ |
+ // On Windows, the Id type is a sequence number (epoch) to solve an ABA |
// issue: |
// 1) Process A creates a transport DIB with HANDLE=1 and sends to B. |
// 2) Process B maps the transport DIB and caches 1 -> DIB. |
@@ -45,38 +88,17 @@ class TransportDIB { |
// is also assigned HANDLE=1. |
// 4) Process A sends the Handle to B, but B incorrectly believes that it |
// already has it cached. |
- struct HandleAndSequenceNum { |
- HandleAndSequenceNum() |
- : handle(NULL), |
- sequence_num(0) { |
- } |
- |
- HandleAndSequenceNum(HANDLE h, uint32 seq_num) |
- : handle(h), |
- sequence_num(seq_num) { |
- } |
- |
- bool operator< (const HandleAndSequenceNum& other) const { |
- // Use the lexicographic order on the tuple <handle, sequence_num>. |
- if (other.handle != handle) |
- return other.handle < handle; |
- return other.sequence_num < sequence_num; |
- } |
- |
- HANDLE handle; |
- uint32 sequence_num; |
- }; |
- typedef HandleAndSequenceNum Id; |
+ typedef uint32 Id; |
// Returns a default, invalid handle, that is meant to indicate a missing |
// Transport DIB. |
- static Handle DefaultHandleValue() { return NULL; } |
+ static Handle DefaultHandleValue() { return Handle(); } |
// Returns a value that is ONLY USEFUL FOR TESTS WHERE IT WON'T BE |
// ACTUALLY USED AS A REAL HANDLE. |
static Handle GetFakeHandleForTest() { |
static int fake_handle = 10; |
- return reinterpret_cast<Handle>(fake_handle++); |
+ return Handle(reinterpret_cast<HANDLE>(fake_handle++), 1, false); |
} |
#elif defined(OS_MACOSX) |
typedef base::SharedMemoryHandle Handle; |
@@ -109,7 +131,41 @@ class TransportDIB { |
} |
#endif |
- // Create a new TransportDIB, returning NULL on failure. |
+ // When passing a TransportDIB::Handle across processes, you must always close |
+ // the handle, even if you return early, or the handle will be leaked. Typical |
+ // usage will be: |
+ // |
+ // MyIPCHandler(TransportDIB::Handle dib_handle) { |
+ // TransportDIB::ScopedHandle handle_scoper(dib_handle); |
+ // ... do some stuff, possible returning early ... |
+ // |
+ // TransportDIB* dib = TransportDIB::Map(handle_scoper.release()); |
+ // // The handle lifetime is now managed by the TransportDIB. |
+ class ScopedHandle { |
+ public: |
+ ScopedHandle() : handle_(DefaultHandleValue()) {} |
+ explicit ScopedHandle(Handle handle) : handle_(handle) {} |
+ |
+ ~ScopedHandle() { |
+ Close(); |
+ } |
+ |
+ Handle release() { |
+ Handle temp = handle_; |
+ handle_ = DefaultHandleValue(); |
+ return temp; |
+ } |
+ |
+ operator Handle() { return handle_; } |
+ |
+ private: |
+ void Close(); |
+ |
+ Handle handle_; |
+ DISALLOW_COPY_AND_ASSIGN(ScopedHandle); |
+ }; |
+ |
+ // Create a new |TransportDIB|, returning NULL on failure. |
// |
// The size is the minimum size in bytes of the memory backing the transport |
// DIB (we may actually allocate more than that to give us better reuse when |
@@ -118,12 +174,18 @@ class TransportDIB { |
// The sequence number is used to uniquely identify the transport DIB. It |
// should be unique for all transport DIBs ever created in the same |
// renderer. |
+ // |
+ // On Linux, this will also map the DIB into the current process. |
static TransportDIB* Create(size_t size, uint32 sequence_num); |
- // Map the referenced transport DIB. The caller owns the returned object. |
+ // Map the referenced transport DIB. The caller owns the returned object. |
// Returns NULL on failure. |
static TransportDIB* Map(Handle transport_dib); |
+ // Create a new |TransportDIB| with a handle to the shared memory. This |
+ // always returns a valid pointer. The DIB is not mapped. |
+ static TransportDIB* CreateWithHandle(Handle handle); |
+ |
// Returns true if the handle is valid. |
static bool is_valid(Handle dib); |
@@ -131,11 +193,31 @@ class TransportDIB { |
// pointer will be owned by the caller. The bitmap will be of the given size, |
// which should fit inside this memory. |
// |
+ // On POSIX, this |TransportDIB| will be mapped if not already. On Windows, |
+ // this |TransportDIB| will NOT be mapped and should not be mapped prior, |
+ // because PlatformCanvas will map the file internally. |
+ // |
// Will return NULL on allocation failure. This could be because the image |
// is too large to map into the current process' address space. |
skia::PlatformCanvas* GetPlatformCanvas(int w, int h); |
- // Return a pointer to the shared memory |
+ // Map the DIB into the current process if it is not already. This is used to |
+ // map a DIB that has already been created. Returns true if the DIB is mapped. |
+ bool Map(); |
+ |
+ // Return a handle for use in a specific process. On POSIX, this simply |
+ // returns the handle as in the |handle| accessor below. On Windows, this |
+ // returns a duplicate handle for use in the given process. This should be |
+ // used instead of the |handle| accessor only if the process that will map |
+ // this DIB does not have permission to duplicate the handle from the |
+ // first process. |
+ // |
+ // Note: On Windows, if the duplicated handle is not closed by the other side |
+ // (or this process fails to transmit the handle), the shared memory will be |
+ // leaked. |
+ Handle GetHandleForProcess(base::ProcessHandle process_handle) const; |
+ |
+ // Return a pointer to the shared memory. |
void* memory() const; |
// Return the maximum size of the shared memory. This is not the amount of |