Index: app/surface/transport_dib_win.cc |
diff --git a/app/surface/transport_dib_win.cc b/app/surface/transport_dib_win.cc |
index f7746e34d875ad6354327e1ca1ee8115fd4b0653..f1707862a5a9b49921fad40e373f1fc8f75abb48 100644 |
--- a/app/surface/transport_dib_win.cc |
+++ b/app/surface/transport_dib_win.cc |
@@ -2,15 +2,74 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include <limits> |
#include <windows.h> |
+#include <limits> |
+ |
#include "app/surface/transport_dib.h" |
#include "base/logging.h" |
+#include "base/scoped_handle_win.h" |
#include "base/scoped_ptr.h" |
#include "base/sys_info.h" |
#include "skia/ext/platform_canvas.h" |
+TransportDIB::Handle TransportDIB::Handle::DupForProcess( |
+ base::ProcessHandle new_owner_process) const { |
+ base::ProcessId new_owner_id = ::GetProcessId(new_owner_process); |
+ if (!new_owner_id) { |
+ LOG(WARNING) << "Could not get process id from handle" |
+ << " handle:" << new_owner_process |
+ << " error:" << ::GetLastError(); |
+ return Handle(); |
+ } |
+ HANDLE owner_process = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE, owner_id_); |
+ if (!owner_process) { |
+ LOG(WARNING) << "Could not open process" |
+ << " id:" << owner_id_ |
+ << " error:" << ::GetLastError(); |
+ return Handle(); |
+ } |
+ ::ScopedHandle scoped_owner_process(owner_process); |
+ HANDLE new_section = NULL; |
+ ::DuplicateHandle(owner_process, section_, |
+ new_owner_process, &new_section, |
+ STANDARD_RIGHTS_REQUIRED | FILE_MAP_ALL_ACCESS, |
+ FALSE, 0); |
+ if (!new_section) { |
+ LOG(WARNING) << "Could not duplicate handle for process" |
+ << " error:" << ::GetLastError(); |
+ return Handle(); |
+ } |
+ return Handle(new_section, new_owner_id, false); |
+} |
+ |
+void TransportDIB::Handle::Close() const { |
+ // Do not close this handle if it is invalid, or it has not been duped yet. |
+ if (!is_valid() || should_dup_on_map_) |
+ return; |
+ |
+ // The handle was already duped for a target process, so we should close it. |
+ // The target process may not have been us, so close using |
+ // |::DuplicateHandle|. |
+ HANDLE owner_process = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE, owner_id_); |
+ if (!owner_process) { |
+ LOG(WARNING) << "Could not open process" |
+ << " id:" << owner_id_ |
+ << " error:" << ::GetLastError(); |
+ return; |
+ } |
+ if (!::DuplicateHandle(owner_process, section_, |
+ NULL, NULL, |
+ DUPLICATE_CLOSE_SOURCE, |
+ FALSE, 0)) { |
+ NOTREACHED() << "Handle could not be closed: " << ::GetLastError(); |
+ } |
+} |
+ |
+void TransportDIB::ScopedHandle::Close() { |
+ handle_.Close(); |
+} |
+ |
TransportDIB::TransportDIB() { |
} |
@@ -42,44 +101,73 @@ TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) { |
} |
// static |
-TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) { |
- TransportDIB* dib = new TransportDIB(handle); |
- if (!dib->shared_memory_.Map(0 /* map whole shared memory segment */)) { |
- LOG(ERROR) << "Failed to map transport DIB" |
- << " handle:" << handle |
- << " error:" << GetLastError(); |
- delete dib; |
+TransportDIB* TransportDIB::Map(Handle handle) { |
+ scoped_ptr<TransportDIB> dib(CreateWithHandle(handle)); |
+ if (!dib->Map()) |
return NULL; |
- } |
- |
- // There doesn't seem to be any way to find the size of the shared memory |
- // region! GetFileSize indicates that the handle is invalid. Thus, we |
- // conservatively set the size to the maximum and hope that the renderer |
- // isn't about to ask us to read off the end of the array. |
- dib->size_ = std::numeric_limits<size_t>::max(); |
+ return dib.release(); |
+} |
- return dib; |
+// static |
+TransportDIB* TransportDIB::CreateWithHandle(Handle handle) { |
+ // It is not sufficient to compare the current process ID and the ID in the |
+ // handle here to see if a duplication is required because they will always |
+ // be the same in single process mode. |
+ if (handle.should_dup_on_map()) |
+ handle = handle.DupForProcess(::GetCurrentProcess()); |
+ return new TransportDIB(handle.section()); |
} |
+// static |
bool TransportDIB::is_valid(Handle dib) { |
- return dib != NULL; |
+ return dib.is_valid(); |
} |
skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) { |
+ // This DIB already mapped the file into this process, but PlatformCanvas |
+ // will map it again. |
+ DCHECK(!memory()) << "Mapped file twice in the same process."; |
+ |
scoped_ptr<skia::PlatformCanvas> canvas(new skia::PlatformCanvas); |
- if (!canvas->initialize(w, h, true, handle())) |
+ if (!canvas->initialize(w, h, true, shared_memory_.handle())) |
return NULL; |
return canvas.release(); |
} |
+bool TransportDIB::Map() { |
+ if (memory()) |
+ return true; |
+ |
+ if (!shared_memory_.Map(0 /* map whole shared memory segment */)) { |
+ LOG(ERROR) << "Failed to map transport DIB" |
+ << " handle:" << shared_memory_.handle() |
+ << " error:" << ::GetLastError(); |
+ return false; |
+ } |
+ |
+ // There doesn't seem to be any way to find the size of the shared memory |
+ // region! GetFileSize indicates that the handle is invalid. Thus, we |
+ // conservatively set the size to the maximum and hope that the renderer |
+ // isn't about to ask us to read off the end of the array. |
+ size_ = std::numeric_limits<size_t>::max(); |
+ return true; |
+} |
+ |
+TransportDIB::Handle TransportDIB::GetHandleForProcess( |
+ base::ProcessHandle process_handle) const { |
+ return handle().DupForProcess(process_handle); |
+} |
+ |
void* TransportDIB::memory() const { |
return shared_memory_.memory(); |
} |
TransportDIB::Handle TransportDIB::handle() const { |
- return shared_memory_.handle(); |
+ return TransferrableSectionHandle(shared_memory_.handle(), |
+ ::GetCurrentProcessId(), |
+ true); |
} |
TransportDIB::Id TransportDIB::id() const { |
- return Id(shared_memory_.handle(), sequence_num_); |
+ return sequence_num_; |
} |