| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_ |
| #define MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_ |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/shared_memory.h" |
| #include "base/memory/shared_memory_handle.h" |
| #include "base/synchronization/lock.h" |
| #include "base/unguessable_token.h" |
| #include "mojo/edk/embedder/scoped_platform_handle.h" |
| #include "mojo/edk/system/system_impl_export.h" |
| |
| namespace mojo { |
| namespace edk { |
| |
| class PlatformSharedBufferMapping; |
| |
| // |PlatformSharedBuffer| is a thread-safe, ref-counted wrapper around |
| // OS-specific shared memory. It has the following features: |
| // - A |PlatformSharedBuffer| simply represents a piece of shared memory that |
| // *may* be mapped and *may* be shared to another process. |
| // - A single |PlatformSharedBuffer| may be mapped multiple times. The |
| // lifetime of the mapping (owned by |PlatformSharedBufferMapping|) is |
| // separate from the lifetime of the |PlatformSharedBuffer|. |
| // - Sizes/offsets (of the shared memory and mappings) are arbitrary, and not |
| // restricted by page size. However, more memory may actually be mapped than |
| // requested. |
| class MOJO_SYSTEM_IMPL_EXPORT PlatformSharedBuffer |
| : public base::RefCountedThreadSafe<PlatformSharedBuffer> { |
| public: |
| // Creates a shared buffer of size |num_bytes| bytes (initially zero-filled). |
| // |num_bytes| must be nonzero. Returns null on failure. |
| static PlatformSharedBuffer* Create(size_t num_bytes); |
| |
| // Creates a shared buffer of size |num_bytes| from the existing platform |
| // handle |platform_handle|. Returns null on failure. |
| static PlatformSharedBuffer* CreateFromPlatformHandle( |
| size_t num_bytes, |
| bool read_only, |
| const base::UnguessableToken& guid, |
| ScopedPlatformHandle platform_handle); |
| |
| // Creates a shared buffer of size |num_bytes| from the existing pair of |
| // read/write and read-only handles |rw_platform_handle| and |
| // |ro_platform_handle|. Returns null on failure. |
| static PlatformSharedBuffer* CreateFromPlatformHandlePair( |
| size_t num_bytes, |
| const base::UnguessableToken& guid, |
| ScopedPlatformHandle rw_platform_handle, |
| ScopedPlatformHandle ro_platform_handle); |
| |
| // Creates a shared buffer of size |num_bytes| from the existing shared memory |
| // handle |handle|. |
| static PlatformSharedBuffer* CreateFromSharedMemoryHandle( |
| size_t num_bytes, |
| bool read_only, |
| base::SharedMemoryHandle handle); |
| |
| // Gets the size of shared buffer (in number of bytes). |
| size_t GetNumBytes() const; |
| |
| // Returns whether this shared buffer is read-only. |
| bool IsReadOnly() const; |
| |
| // Returns a GUID which uniquely identifies the underlying shared buffer |
| // object. |
| base::UnguessableToken GetGUID() const; |
| |
| // Maps (some) of the shared buffer into memory; [|offset|, |offset + length|] |
| // must be contained in [0, |num_bytes|], and |length| must be at least 1. |
| // Returns null on failure. |
| std::unique_ptr<PlatformSharedBufferMapping> Map(size_t offset, |
| size_t length); |
| |
| // Checks if |offset| and |length| are valid arguments. |
| bool IsValidMap(size_t offset, size_t length); |
| |
| // Like |Map()|, but doesn't check its arguments (which should have been |
| // preflighted using |IsValidMap()|). |
| std::unique_ptr<PlatformSharedBufferMapping> MapNoCheck(size_t offset, |
| size_t length); |
| |
| // Duplicates the underlying platform handle and passes it to the caller. |
| ScopedPlatformHandle DuplicatePlatformHandle(); |
| |
| // Duplicate the underlying platform handle and passes it to the caller, |
| // for the purpose of serialization / IPC. The difference with |
| // DuplicatePlatformHandle() is that this also seals read-only regions |
| // on Android to ensure the receiver cannot map them writable. |
| ScopedPlatformHandle DuplicatePlatformHandleForIPC(); |
| |
| // Duplicates the underlying shared memory handle and passes it to the caller. |
| base::SharedMemoryHandle DuplicateSharedMemoryHandle(); |
| |
| // Passes the underlying platform handle to the caller. This should only be |
| // called if there's a unique reference to this object (owned by the caller). |
| // After calling this, this object should no longer be used, but should only |
| // be disposed of. |
| ScopedPlatformHandle PassPlatformHandle(); |
| |
| // Create and return a read-only duplicate of this shared buffer. If this |
| // shared buffer isn't capable of returning a read-only duplicate, then |
| // nullptr will be returned. |
| PlatformSharedBuffer* CreateReadOnlyDuplicate(); |
| |
| private: |
| friend class base::RefCountedThreadSafe<PlatformSharedBuffer>; |
| |
| PlatformSharedBuffer(size_t num_bytes, bool read_only); |
| ~PlatformSharedBuffer(); |
| |
| // This is called by |Create()| before this object is given to anyone. |
| bool Init(); |
| |
| // This is like |Init()|, but for |CreateFromPlatformHandle()|. (Note: It |
| // should verify that |platform_handle| is an appropriate handle for the |
| // claimed |num_bytes_|.) |
| bool InitFromPlatformHandle(const base::UnguessableToken& guid, |
| ScopedPlatformHandle platform_handle); |
| |
| bool InitFromPlatformHandlePair(const base::UnguessableToken& guid, |
| ScopedPlatformHandle rw_platform_handle, |
| ScopedPlatformHandle ro_platform_handle); |
| |
| void InitFromSharedMemoryHandle(base::SharedMemoryHandle handle); |
| |
| const size_t num_bytes_; |
| const bool read_only_; |
| |
| base::Lock lock_; |
| std::unique_ptr<base::SharedMemory> shared_memory_; |
| |
| // A separate read-only shared memory for platforms that need it (i.e. Linux |
| // with sync broker). |
| std::unique_ptr<base::SharedMemory> ro_shared_memory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PlatformSharedBuffer); |
| }; |
| |
| // A mapping of a |PlatformSharedBuffer| (compararable to a "file view" in |
| // Windows); see above. Created by |PlatformSharedBuffer::Map()|. Automatically |
| // unmaps memory on destruction. |
| // |
| // Mappings are NOT thread-safe. |
| // |
| // Note: This is an entirely separate class (instead of |
| // |PlatformSharedBuffer::Mapping|) so that it can be forward-declared. |
| class MOJO_SYSTEM_IMPL_EXPORT PlatformSharedBufferMapping { |
| public: |
| ~PlatformSharedBufferMapping(); |
| |
| void* GetBase() const; |
| size_t GetLength() const; |
| |
| private: |
| friend class PlatformSharedBuffer; |
| |
| PlatformSharedBufferMapping(base::SharedMemoryHandle handle, |
| bool read_only, |
| size_t offset, |
| size_t length) |
| : offset_(offset), |
| length_(length), |
| base_(nullptr), |
| shared_memory_(handle, read_only) {} |
| |
| bool Map(); |
| void Unmap(); |
| |
| const size_t offset_; |
| const size_t length_; |
| void* base_; |
| |
| // Since mapping life cycles are separate from PlatformSharedBuffer and a |
| // buffer can be mapped multiple times, we have our own SharedMemory object |
| // created from a duplicate handle. |
| base::SharedMemory shared_memory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PlatformSharedBufferMapping); |
| }; |
| |
| } // namespace edk |
| } // namespace mojo |
| |
| #endif // MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_ |