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