| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/files/scoped_temp_dir.h" | 11 #include "base/files/scoped_temp_dir.h" |
| 12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/memory/shared_memory.h" |
| 14 #include "base/memory/shared_memory_handle.h" |
| 15 #include "base/win/scoped_handle.h" |
| 13 #include "ipc/attachment_broker_privileged_win.h" | 16 #include "ipc/attachment_broker_privileged_win.h" |
| 14 #include "ipc/attachment_broker_unprivileged_win.h" | 17 #include "ipc/attachment_broker_unprivileged_win.h" |
| 15 #include "ipc/handle_attachment_win.h" | 18 #include "ipc/handle_attachment_win.h" |
| 16 #include "ipc/handle_win.h" | 19 #include "ipc/handle_win.h" |
| 17 #include "ipc/ipc_listener.h" | 20 #include "ipc/ipc_listener.h" |
| 18 #include "ipc/ipc_message.h" | 21 #include "ipc/ipc_message.h" |
| 19 #include "ipc/ipc_test_base.h" | 22 #include "ipc/ipc_test_base.h" |
| 20 #include "ipc/ipc_test_messages.h" | 23 #include "ipc/ipc_test_messages.h" |
| 21 | 24 |
| 22 namespace { | 25 namespace { |
| 23 | 26 |
| 27 using base::win::ScopedHandle; |
| 28 |
| 24 const char kDataBuffer[] = "This is some test data to write to the file."; | 29 const char kDataBuffer[] = "This is some test data to write to the file."; |
| 30 const size_t kSharedMemorySize = 20000; |
| 25 | 31 |
| 26 // Returns the contents of the file represented by |h| as a std::string. | 32 // Returns the contents of the file represented by |h| as a std::string. |
| 27 std::string ReadFromFile(HANDLE h) { | 33 std::string ReadFromFile(HANDLE h) { |
| 28 SetFilePointer(h, 0, nullptr, FILE_BEGIN); | 34 SetFilePointer(h, 0, nullptr, FILE_BEGIN); |
| 29 char buffer[100]; | 35 char buffer[100]; |
| 30 DWORD bytes_read; | 36 DWORD bytes_read; |
| 31 BOOL success = ::ReadFile(h, buffer, static_cast<DWORD>(strlen(kDataBuffer)), | 37 BOOL success = ::ReadFile(h, buffer, static_cast<DWORD>(strlen(kDataBuffer)), |
| 32 &bytes_read, nullptr); | 38 &bytes_read, nullptr); |
| 33 return success ? std::string(buffer, bytes_read) : std::string(); | 39 return success ? std::string(buffer, bytes_read) : std::string(); |
| 34 } | 40 } |
| 35 | 41 |
| 36 HANDLE GetHandleFromBrokeredAttachment( | 42 ScopedHandle GetHandleFromBrokeredAttachment( |
| 37 const scoped_refptr<IPC::BrokerableAttachment>& attachment) { | 43 const scoped_refptr<IPC::BrokerableAttachment>& attachment) { |
| 38 if (attachment->GetType() != | 44 if (attachment->GetType() != |
| 39 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) { | 45 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) { |
| 40 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT."; | 46 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT."; |
| 41 return nullptr; | 47 return ScopedHandle(nullptr); |
| 42 } | 48 } |
| 43 | 49 |
| 44 if (attachment->GetBrokerableType() != | 50 if (attachment->GetBrokerableType() != |
| 45 IPC::BrokerableAttachment::WIN_HANDLE) { | 51 IPC::BrokerableAttachment::WIN_HANDLE) { |
| 46 LOG(INFO) << "Brokerable type not WIN_HANDLE."; | 52 LOG(INFO) << "Brokerable type not WIN_HANDLE."; |
| 47 return nullptr; | 53 return ScopedHandle(nullptr); |
| 48 } | 54 } |
| 49 | 55 |
| 50 IPC::internal::HandleAttachmentWin* received_handle_attachment = | 56 IPC::internal::HandleAttachmentWin* received_handle_attachment = |
| 51 static_cast<IPC::internal::HandleAttachmentWin*>(attachment.get()); | 57 static_cast<IPC::internal::HandleAttachmentWin*>(attachment.get()); |
| 52 return received_handle_attachment->get_handle(); | 58 ScopedHandle h(received_handle_attachment->get_handle()); |
| 59 received_handle_attachment->reset_handle_ownership(); |
| 60 return h; |
| 53 } | 61 } |
| 54 | 62 |
| 55 // |message| must be deserializable as a TestHandleWinMsg. Returns the HANDLE, | 63 // |message| must be deserializable as a TestHandleWinMsg. Returns the HANDLE, |
| 56 // or nullptr if deserialization failed. | 64 // or nullptr if deserialization failed. |
| 57 HANDLE GetHandleFromTestHandleWinMsg(const IPC::Message& message) { | 65 ScopedHandle GetHandleFromTestHandleWinMsg(const IPC::Message& message) { |
| 66 // Expect a message with a brokered attachment. |
| 67 if (!message.HasBrokerableAttachments()) { |
| 68 LOG(INFO) << "Message missing brokerable attachment."; |
| 69 return ScopedHandle(nullptr); |
| 70 } |
| 71 |
| 72 TestHandleWinMsg::Schema::Param p; |
| 73 bool success = TestHandleWinMsg::Read(&message, &p); |
| 74 if (!success) { |
| 75 LOG(INFO) << "Failed to deserialize message."; |
| 76 return ScopedHandle(nullptr); |
| 77 } |
| 78 |
| 79 IPC::HandleWin handle_win = base::get<1>(p); |
| 80 return ScopedHandle(handle_win.get_handle()); |
| 81 } |
| 82 |
| 83 // Returns a mapped, shared memory region based on the handle in |message|. |
| 84 scoped_ptr<base::SharedMemory> GetSharedMemoryFromSharedMemoryHandleMsg1( |
| 85 const IPC::Message& message, |
| 86 size_t size) { |
| 58 // Expect a message with a brokered attachment. | 87 // Expect a message with a brokered attachment. |
| 59 if (!message.HasBrokerableAttachments()) { | 88 if (!message.HasBrokerableAttachments()) { |
| 60 LOG(INFO) << "Message missing brokerable attachment."; | 89 LOG(INFO) << "Message missing brokerable attachment."; |
| 61 return nullptr; | 90 return nullptr; |
| 62 } | 91 } |
| 63 | 92 |
| 64 TestHandleWinMsg::Schema::Param p; | 93 TestSharedMemoryHandleMsg1::Schema::Param p; |
| 65 bool success = TestHandleWinMsg::Read(&message, &p); | 94 bool success = TestSharedMemoryHandleMsg1::Read(&message, &p); |
| 66 if (!success) { | 95 if (!success) { |
| 67 LOG(INFO) << "Failed to deserialize message."; | 96 LOG(INFO) << "Failed to deserialize message."; |
| 68 return nullptr; | 97 return nullptr; |
| 69 } | 98 } |
| 70 | 99 |
| 71 IPC::HandleWin handle_win = base::get<1>(p); | 100 base::SharedMemoryHandle handle = base::get<0>(p); |
| 72 return handle_win.get_handle(); | 101 scoped_ptr<base::SharedMemory> shared_memory( |
| 102 new base::SharedMemory(handle, false)); |
| 103 |
| 104 shared_memory->Map(size); |
| 105 return std::move(shared_memory); |
| 73 } | 106 } |
| 74 | 107 |
| 75 // |message| must be deserializable as a TestTwoHandleWinMsg. Returns the | 108 // |message| must be deserializable as a TestTwoHandleWinMsg. Returns the |
| 76 // HANDLE, or nullptr if deserialization failed. | 109 // HANDLE, or nullptr if deserialization failed. |
| 77 HANDLE GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message, | 110 bool GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message, |
| 78 int index) { | 111 HANDLE* h1, |
| 112 HANDLE* h2) { |
| 79 // Expect a message with a brokered attachment. | 113 // Expect a message with a brokered attachment. |
| 80 if (!message.HasBrokerableAttachments()) { | 114 if (!message.HasBrokerableAttachments()) { |
| 81 LOG(INFO) << "Message missing brokerable attachment."; | 115 LOG(INFO) << "Message missing brokerable attachment."; |
| 82 return nullptr; | 116 return false; |
| 83 } | 117 } |
| 84 | 118 |
| 85 TestTwoHandleWinMsg::Schema::Param p; | 119 TestTwoHandleWinMsg::Schema::Param p; |
| 86 bool success = TestTwoHandleWinMsg::Read(&message, &p); | 120 bool success = TestTwoHandleWinMsg::Read(&message, &p); |
| 87 if (!success) { | 121 if (!success) { |
| 88 LOG(INFO) << "Failed to deserialize message."; | 122 LOG(INFO) << "Failed to deserialize message."; |
| 89 return nullptr; | 123 return false; |
| 90 } | 124 } |
| 91 | 125 |
| 92 IPC::HandleWin handle_win; | 126 IPC::HandleWin handle_win = base::get<0>(p); |
| 93 if (index == 0) | 127 *h1 = handle_win.get_handle(); |
| 94 handle_win = base::get<0>(p); | 128 handle_win = base::get<1>(p); |
| 95 else if (index == 1) | 129 *h2 = handle_win.get_handle(); |
| 96 handle_win = base::get<1>(p); | 130 return true; |
| 97 return handle_win.get_handle(); | |
| 98 } | 131 } |
| 99 | 132 |
| 100 // |message| must be deserializable as a TestHandleWinMsg. Returns true if the | 133 // |message| must be deserializable as a TestHandleWinMsg. Returns true if the |
| 101 // attached file HANDLE has contents |kDataBuffer|. | 134 // attached file HANDLE has contents |kDataBuffer|. |
| 102 bool CheckContentsOfTestMessage(const IPC::Message& message) { | 135 bool CheckContentsOfTestMessage(const IPC::Message& message) { |
| 103 HANDLE h = GetHandleFromTestHandleWinMsg(message); | 136 ScopedHandle h(GetHandleFromTestHandleWinMsg(message)); |
| 104 if (h == nullptr) { | 137 if (h.Get() == nullptr) { |
| 105 LOG(INFO) << "Failed to get handle from TestHandleWinMsg."; | 138 LOG(INFO) << "Failed to get handle from TestHandleWinMsg."; |
| 106 return false; | 139 return false; |
| 107 } | 140 } |
| 108 | 141 |
| 109 std::string contents = ReadFromFile(h); | 142 std::string contents = ReadFromFile(h.Get()); |
| 110 bool success = (contents == std::string(kDataBuffer)); | 143 bool success = (contents == std::string(kDataBuffer)); |
| 111 if (!success) { | 144 if (!success) { |
| 112 LOG(INFO) << "Expected contents: " << std::string(kDataBuffer); | 145 LOG(INFO) << "Expected contents: " << std::string(kDataBuffer); |
| 113 LOG(INFO) << "Read contents: " << contents; | 146 LOG(INFO) << "Read contents: " << contents; |
| 114 } | 147 } |
| 115 return success; | 148 return success; |
| 116 } | 149 } |
| 117 | 150 |
| 118 // Returns 0 on error. | 151 // Returns 0 on error. |
| 119 DWORD GetCurrentProcessHandleCount() { | 152 DWORD GetCurrentProcessHandleCount() { |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 HANDLE h = CreateTempFile(); | 397 HANDLE h = CreateTempFile(); |
| 365 SendMessageWithAttachment(h); | 398 SendMessageWithAttachment(h); |
| 366 base::MessageLoop::current()->Run(); | 399 base::MessageLoop::current()->Run(); |
| 367 | 400 |
| 368 // Get the received attachment. | 401 // Get the received attachment. |
| 369 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id(); | 402 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id(); |
| 370 scoped_refptr<IPC::BrokerableAttachment> received_attachment; | 403 scoped_refptr<IPC::BrokerableAttachment> received_attachment; |
| 371 get_broker()->GetAttachmentWithId(*id, &received_attachment); | 404 get_broker()->GetAttachmentWithId(*id, &received_attachment); |
| 372 ASSERT_NE(received_attachment.get(), nullptr); | 405 ASSERT_NE(received_attachment.get(), nullptr); |
| 373 | 406 |
| 374 // Check that it's the same entry in the HANDLE table. | 407 // Check that it's a different entry in the HANDLE table. |
| 375 HANDLE h2 = GetHandleFromBrokeredAttachment(received_attachment); | 408 ScopedHandle h2(GetHandleFromBrokeredAttachment(received_attachment)); |
| 376 EXPECT_EQ(h2, h); | 409 EXPECT_NE(h2.Get(), h); |
| 377 | 410 |
| 378 // And still points to the same file. | 411 // But still points to the same file. |
| 379 std::string contents = ReadFromFile(h); | 412 std::string contents = ReadFromFile(h2.Get()); |
| 380 EXPECT_EQ(contents, std::string(kDataBuffer)); | 413 EXPECT_EQ(contents, std::string(kDataBuffer)); |
| 381 | 414 |
| 382 CommonTearDown(); | 415 CommonTearDown(); |
| 383 } | 416 } |
| 384 | 417 |
| 385 // Similar to SendHandle, but sends a message with two instances of the same | 418 // Similar to SendHandle, but sends a message with two instances of the same |
| 386 // handle. | 419 // handle. |
| 387 TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendTwoHandles) { | 420 TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendTwoHandles) { |
| 388 Init("SendTwoHandles"); | 421 Init("SendTwoHandles"); |
| 389 | 422 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 base::MessageLoop::current()->Run(); | 461 base::MessageLoop::current()->Run(); |
| 429 | 462 |
| 430 // Check the result. | 463 // Check the result. |
| 431 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, | 464 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
| 432 get_proxy_listener()->get_reason()); | 465 get_proxy_listener()->get_reason()); |
| 433 ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); | 466 ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); |
| 434 | 467 |
| 435 CommonTearDown(); | 468 CommonTearDown(); |
| 436 } | 469 } |
| 437 | 470 |
| 471 // An unprivileged process makes a shared memory region and sends it to the |
| 472 // privileged process. |
| 473 TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendSharedMemoryHandle) { |
| 474 Init("SendSharedMemoryHandle"); |
| 475 |
| 476 CommonSetUp(); |
| 477 ResultListener result_listener; |
| 478 get_proxy_listener()->set_listener(&result_listener); |
| 479 |
| 480 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); |
| 481 shared_memory->CreateAndMapAnonymous(kSharedMemorySize); |
| 482 memcpy(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer)); |
| 483 sender()->Send(new TestSharedMemoryHandleMsg1(shared_memory->handle())); |
| 484 base::MessageLoop::current()->Run(); |
| 485 |
| 486 // Check the result. |
| 487 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
| 488 get_proxy_listener()->get_reason()); |
| 489 ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); |
| 490 |
| 491 CommonTearDown(); |
| 492 } |
| 493 |
| 438 using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, | 494 using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, |
| 439 const IPC::Message& message); | 495 const IPC::Message& message); |
| 440 | 496 |
| 441 int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, | 497 int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, |
| 442 const char* channel_name) { | 498 const char* channel_name) { |
| 443 LOG(INFO) << "Privileged process start."; | 499 LOG(INFO) << "Privileged process start."; |
| 444 base::MessageLoopForIO main_message_loop; | 500 base::MessageLoopForIO main_message_loop; |
| 445 ProxyListener listener; | 501 ProxyListener listener; |
| 446 | 502 |
| 447 // Set up IPC channel. | 503 // Set up IPC channel. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 474 bool success = CheckContentsOfTestMessage(message); | 530 bool success = CheckContentsOfTestMessage(message); |
| 475 SendControlMessage(sender, success); | 531 SendControlMessage(sender, success); |
| 476 } | 532 } |
| 477 | 533 |
| 478 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandle) { | 534 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandle) { |
| 479 return CommonPrivilegedProcessMain(&SendHandleCallback, "SendHandle"); | 535 return CommonPrivilegedProcessMain(&SendHandleCallback, "SendHandle"); |
| 480 } | 536 } |
| 481 | 537 |
| 482 void SendHandleWithoutPermissionsCallback(IPC::Sender* sender, | 538 void SendHandleWithoutPermissionsCallback(IPC::Sender* sender, |
| 483 const IPC::Message& message) { | 539 const IPC::Message& message) { |
| 484 HANDLE h = GetHandleFromTestHandleWinMsg(message); | 540 ScopedHandle h(GetHandleFromTestHandleWinMsg(message)); |
| 485 if (h != nullptr) { | 541 if (h.Get() != nullptr) { |
| 486 SetFilePointer(h, 0, nullptr, FILE_BEGIN); | 542 SetFilePointer(h.Get(), 0, nullptr, FILE_BEGIN); |
| 487 | 543 |
| 488 char buffer[100]; | 544 char buffer[100]; |
| 489 DWORD bytes_read; | 545 DWORD bytes_read; |
| 490 BOOL success = | 546 BOOL success = |
| 491 ::ReadFile(h, buffer, static_cast<DWORD>(strlen(kDataBuffer)), | 547 ::ReadFile(h.Get(), buffer, static_cast<DWORD>(strlen(kDataBuffer)), |
| 492 &bytes_read, nullptr); | 548 &bytes_read, nullptr); |
| 493 if (!success && GetLastError() == ERROR_ACCESS_DENIED) { | 549 if (!success && GetLastError() == ERROR_ACCESS_DENIED) { |
| 494 SendControlMessage(sender, true); | 550 SendControlMessage(sender, true); |
| 495 return; | 551 return; |
| 496 } | 552 } |
| 497 } | 553 } |
| 498 | 554 |
| 499 SendControlMessage(sender, false); | 555 SendControlMessage(sender, false); |
| 500 } | 556 } |
| 501 | 557 |
| 502 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleWithoutPermissions) { | 558 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleWithoutPermissions) { |
| 503 return CommonPrivilegedProcessMain(&SendHandleWithoutPermissionsCallback, | 559 return CommonPrivilegedProcessMain(&SendHandleWithoutPermissionsCallback, |
| 504 "SendHandleWithoutPermissions"); | 560 "SendHandleWithoutPermissions"); |
| 505 } | 561 } |
| 506 | 562 |
| 507 void SendHandleToSelfCallback(IPC::Sender* sender, const IPC::Message&) { | 563 void SendHandleToSelfCallback(IPC::Sender* sender, const IPC::Message&) { |
| 508 // Do nothing special. The default behavior already runs the | 564 // Do nothing special. The default behavior already runs the |
| 509 // AttachmentBrokerPrivilegedWin. | 565 // AttachmentBrokerPrivilegedWin. |
| 510 } | 566 } |
| 511 | 567 |
| 512 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleToSelf) { | 568 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleToSelf) { |
| 513 return CommonPrivilegedProcessMain(&SendHandleToSelfCallback, | 569 return CommonPrivilegedProcessMain(&SendHandleToSelfCallback, |
| 514 "SendHandleToSelf"); | 570 "SendHandleToSelf"); |
| 515 } | 571 } |
| 516 | 572 |
| 517 void SendTwoHandlesCallback(IPC::Sender* sender, const IPC::Message& message) { | 573 void SendTwoHandlesCallback(IPC::Sender* sender, const IPC::Message& message) { |
| 518 // Check for two handles. | 574 // Check for two handles. |
| 519 HANDLE h1 = GetHandleFromTestTwoHandleWinMsg(message, 0); | 575 HANDLE h1, h2; |
| 520 HANDLE h2 = GetHandleFromTestTwoHandleWinMsg(message, 1); | 576 EXPECT_TRUE(GetHandleFromTestTwoHandleWinMsg(message, &h1, &h2)); |
| 521 if (h1 == nullptr || h2 == nullptr) { | 577 if (h1 == nullptr || h2 == nullptr) { |
| 522 SendControlMessage(sender, false); | 578 SendControlMessage(sender, false); |
| 523 return; | 579 return; |
| 524 } | 580 } |
| 525 | 581 |
| 526 // Check that their contents are correct. | 582 // Check that their contents are correct. |
| 527 std::string contents1 = ReadFromFile(h1); | 583 std::string contents1 = ReadFromFile(h1); |
| 528 std::string contents2 = ReadFromFile(h2); | 584 std::string contents2 = ReadFromFile(h2); |
| 529 if (contents1 != std::string(kDataBuffer) || | 585 if (contents1 != std::string(kDataBuffer) || |
| 530 contents2 != std::string(kDataBuffer)) { | 586 contents2 != std::string(kDataBuffer)) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 LOG(INFO) << "Received second message."; | 628 LOG(INFO) << "Received second message."; |
| 573 SendControlMessage(sender, success); | 629 SendControlMessage(sender, success); |
| 574 } | 630 } |
| 575 } | 631 } |
| 576 | 632 |
| 577 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleTwice) { | 633 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleTwice) { |
| 578 return CommonPrivilegedProcessMain(&SendHandleTwiceCallback, | 634 return CommonPrivilegedProcessMain(&SendHandleTwiceCallback, |
| 579 "SendHandleTwice"); | 635 "SendHandleTwice"); |
| 580 } | 636 } |
| 581 | 637 |
| 638 void SendSharedMemoryHandleCallback(IPC::Sender* sender, |
| 639 const IPC::Message& message) { |
| 640 scoped_ptr<base::SharedMemory> shared_memory = |
| 641 GetSharedMemoryFromSharedMemoryHandleMsg1(message, kSharedMemorySize); |
| 642 bool success = |
| 643 memcmp(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer)) == 0; |
| 644 SendControlMessage(sender, success); |
| 645 } |
| 646 |
| 647 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) { |
| 648 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback, |
| 649 "SendSharedMemoryHandle"); |
| 650 } |
| 651 |
| 582 } // namespace | 652 } // namespace |
| OLD | NEW |