diff options
author | viettrungluu <viettrungluu@chromium.org> | 2015-02-09 18:03:35 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-10 02:04:27 +0000 |
commit | 17e878ce6362ffe65a0893b601960f86556d6237 (patch) | |
tree | 4699c82c1395d5fbc33063c932522bd3f03f53d1 /third_party/mojo | |
parent | c2a67e9610872a125819c8d4544b720606346a94 (diff) | |
download | chromium_src-17e878ce6362ffe65a0893b601960f86556d6237.zip chromium_src-17e878ce6362ffe65a0893b601960f86556d6237.tar.gz chromium_src-17e878ce6362ffe65a0893b601960f86556d6237.tar.bz2 |
Update mojo sdk to rev 8af2ccff2eee4bfca1043015abee30482a030b30
Also apply mojo 8fda9302f51f99dc25e6e0c95cfd0a04e1adc802 (https://codereview.chromium.org/902783004/).
Also apply mojo e62ed5fbf8bb4d7cfa87f499b1d1b50bdf8e0b3b (https://codereview.chromium.org/905253005/).
Also apply dcf5a5e1dbccb91f774d545b5f31d06042d8a8e3 (https://codereview.chromium.org/909903003/).
Also apply 9f87aeadbda22441b7d469e596f7bd7d0d73e2a8 (https://codereview.chromium.org/908973002/).
(Reland of https://crrev.com/2e86fb9356e3a693762d3c86c70e63951bd9d1be a.k.a. refs/heads/master@{#315432}.)
TBR=jamesr@chromium.org
NOPRESUBMIT=true
CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win8_chromium_gn_dbg,win8_chromium_gn_rel
Review URL: https://codereview.chromium.org/910883002
Cr-Commit-Position: refs/heads/master@{#315471}
Diffstat (limited to 'third_party/mojo')
66 files changed, 1475 insertions, 401 deletions
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.cc b/third_party/mojo/src/mojo/edk/embedder/embedder.cc index 0150dcb..d0a5135 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder.cc +++ b/third_party/mojo/src/mojo/edk/embedder/embedder.cc @@ -13,7 +13,6 @@ #include "mojo/edk/embedder/embedder_internal.h" #include "mojo/edk/embedder/platform_support.h" #include "mojo/edk/system/channel.h" -#include "mojo/edk/system/channel_endpoint.h" #include "mojo/edk/system/channel_manager.h" #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/core.h" @@ -55,9 +54,15 @@ namespace internal { PlatformSupport* g_platform_support = nullptr; system::Core* g_core = nullptr; system::ChannelManager* g_channel_manager = nullptr; +MasterProcessDelegate* g_master_process_delegate = nullptr; +SlaveProcessDelegate* g_slave_process_delegate = nullptr; } // namespace internal +Configuration* GetConfiguration() { + return system::GetMutableConfiguration(); +} + void Init(scoped_ptr<PlatformSupport> platform_support) { DCHECK(platform_support); @@ -72,8 +77,27 @@ void Init(scoped_ptr<PlatformSupport> platform_support) { new system::ChannelManager(internal::g_platform_support); } -Configuration* GetConfiguration() { - return system::GetMutableConfiguration(); +void InitMaster(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, + MasterProcessDelegate* master_process_delegate, + scoped_refptr<base::TaskRunner> io_thread_task_runner) { + // |Init()| must have already been called. + DCHECK(internal::g_core); + + // TODO(vtl): This is temporary. We really want to construct a + // |MasterConnectionManager| here, which will in turn hold on to the delegate. + internal::g_master_process_delegate = master_process_delegate; +} + +void InitSlave(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, + SlaveProcessDelegate* slave_process_delegate, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + ScopedPlatformHandle platform_handle) { + // |Init()| must have already been called. + DCHECK(internal::g_core); + + // TODO(vtl): This is temporary. We really want to construct a + // |SlaveConnectionManager| here, which will in turn hold on to the delegate. + internal::g_slave_process_delegate = slave_process_delegate; } // TODO(vtl): Write tests for this. @@ -83,18 +107,16 @@ ScopedMessagePipeHandle CreateChannelOnIOThread( DCHECK(platform_handle.is_valid()); DCHECK(channel_info); - scoped_refptr<system::ChannelEndpoint> channel_endpoint; + *channel_info = new ChannelInfo(MakeChannelId()); scoped_refptr<system::MessagePipeDispatcher> dispatcher = - system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint); + internal::g_channel_manager->CreateChannelOnIOThread( + (*channel_info)->channel_id, platform_handle.Pass()); - DCHECK(internal::g_core); ScopedMessagePipeHandle rv( MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); - - *channel_info = new ChannelInfo(MakeChannelId()); - internal::g_channel_manager->CreateChannelOnIOThread( - (*channel_info)->channel_id, platform_handle.Pass(), channel_endpoint); - + CHECK(rv.is_valid()); + // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it + // once that's fixed. return rv.Pass(); } @@ -107,31 +129,19 @@ ScopedMessagePipeHandle CreateChannel( DCHECK(io_thread_task_runner); DCHECK(!callback.is_null()); - scoped_refptr<system::ChannelEndpoint> channel_endpoint; + system::ChannelId channel_id = MakeChannelId(); + scoped_ptr<ChannelInfo> channel_info(new ChannelInfo(channel_id)); scoped_refptr<system::MessagePipeDispatcher> dispatcher = - system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint); + internal::g_channel_manager->CreateChannel( + channel_id, platform_handle.Pass(), io_thread_task_runner, + base::Bind(callback, base::Unretained(channel_info.release())), + callback_thread_task_runner); - DCHECK(internal::g_core); ScopedMessagePipeHandle rv( MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); - - // We'll have to set |channel_info->channel_id| on the I/O thread. - scoped_ptr<ChannelInfo> channel_info(new ChannelInfo()); - - if (rv.is_valid()) { - system::ChannelId channel_id = MakeChannelId(); - channel_info->channel_id = channel_id; - internal::g_channel_manager->CreateChannel( - channel_id, platform_handle.Pass(), channel_endpoint, - io_thread_task_runner, - base::Bind(callback, base::Unretained(channel_info.release())), - callback_thread_task_runner); - } else { - (callback_thread_task_runner ? callback_thread_task_runner - : io_thread_task_runner) - ->PostTask(FROM_HERE, base::Bind(callback, channel_info.release())); - } - + CHECK(rv.is_valid()); + // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it + // once that's fixed. return rv.Pass(); } diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.h b/third_party/mojo/src/mojo/edk/embedder/embedder.h index cc0ad26..4898ae1 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder.h +++ b/third_party/mojo/src/mojo/edk/embedder/embedder.h @@ -18,15 +18,42 @@ namespace mojo { namespace embedder { struct Configuration; +class MasterProcessDelegate; class PlatformSupport; +class SlaveProcessDelegate; + +// Returns the global configuration. In general, you should not need to change +// the configuration, but if you do you must do it before calling |Init()|. +MOJO_SYSTEM_IMPL_EXPORT Configuration* GetConfiguration(); // Must be called first, or just after setting configuration parameters, to // initialize the (global, singleton) system. MOJO_SYSTEM_IMPL_EXPORT void Init(scoped_ptr<PlatformSupport> platform_support); -// Returns the global configuration. In general, you should not need to change -// the configuration, but if you do you must do it before calling |Init()|. -MOJO_SYSTEM_IMPL_EXPORT Configuration* GetConfiguration(); +// Initializes a master process. To be called after |Init()|. +// |master_process_delegate| should live forever (or until after +// |mojo::embedder::test::Shutdown()|); its methods will be called using +// |delegate_thread_task_runner|, which must be the task runner for the thread +// calling |InitMaster()|. |io_thread_task_runner| should be the task runner for +// some I/O thread; this should be the same as that provided to +// |CreateChannel()| (or on which |CreateChannelOnIOThread()| is called). +// TODO(vtl): Remove the |io_thread_task_runner| argument from +// |CreateChannel()| (and eventually |CreateChannel()| altogether) and require +// that either this or |InitSlave()| be called. Currently, |CreateChannel()| can +// be used with different I/O threads, but this capability will be removed. +MOJO_SYSTEM_IMPL_EXPORT void InitMaster( + scoped_refptr<base::TaskRunner> delegate_thread_task_runner, + MasterProcessDelegate* master_process_delegate, + scoped_refptr<base::TaskRunner> io_thread_task_runner); + +// Initializes a slave process. Similar to |InitMaster()| (see above). +// |platform_handle| should be connected to the handle passed to |AddSlave()|. +// TODO(vtl): |AddSlave()| doesn't exist yet. +MOJO_SYSTEM_IMPL_EXPORT void InitSlave( + scoped_refptr<base::TaskRunner> delegate_thread_task_runner, + SlaveProcessDelegate* slave_process_delegate, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + ScopedPlatformHandle platform_handle); // A "channel" is a connection on top of an OS "pipe", on top of which Mojo // message pipes (etc.) can be multiplexed. It must "live" on some I/O thread. diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h b/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h index 536e0db..7d90148 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h +++ b/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h @@ -26,6 +26,9 @@ typedef uint64_t ChannelId; namespace embedder { class PlatformSupport; +// TODO(vtl): Remove these (see below). +class MasterProcessDelegate; +class SlaveProcessDelegate; // This is a type that's opaque to users of the embedder API (which only // gives/takes |ChannelInfo*|s). We make it a struct to make it @@ -49,6 +52,12 @@ extern system::Core* g_core; // (|mojo::embedder::CreateChannel()|, etc.). extern system::ChannelManager* g_channel_manager; +// TODO(vtl): Remove these: We'll eventually really want to hold on to a +// |MasterConnectionManager*| or a |SlaveConnectionManager*|. For now, keep +// these around as globals to avoid triggering leak detectors. +extern MasterProcessDelegate* g_master_process_delegate; +extern SlaveProcessDelegate* g_slave_process_delegate; + } // namespace internal } // namepace embedder diff --git a/third_party/mojo/src/mojo/edk/js/BUILD.gn b/third_party/mojo/src/mojo/edk/js/BUILD.gn index 9a066d3..ed1b81f 100644 --- a/third_party/mojo/src/mojo/edk/js/BUILD.gn +++ b/third_party/mojo/src/mojo/edk/js/BUILD.gn @@ -4,6 +4,20 @@ import("../mojo_edk.gni") +# TODO(hansmuller): The organization of tests in this directory is weird: +# * Really, js_unittests tests public stuff, so that should live in public +# and be reworked as some sort of apptest. +# * Both js_unittests and js_integration_tests should auto-generate their +# tests somehow. The .cc files are just test runner stubs, including +# explicit lists of .js files. +group("tests") { + testonly = true + deps = [ + "test:js_unittests", + "test:js_integration_tests", + ] +} + mojo_edk_source_set("js") { sources = [ "core.cc", @@ -50,7 +64,5 @@ mojo_edk_source_set("js_unittests") { "mojo/edk/test:test_support", ] - mojo_sdk_deps = [ - "mojo/public/cpp/system", - ] + mojo_sdk_deps = [ "mojo/public/cpp/system" ] } diff --git a/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc b/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc index 8ef1f40..0e071d8 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc @@ -82,8 +82,8 @@ void ChannelEndpoint::AttachAndRun(Channel* channel, remote_id_ = remote_id; while (!channel_message_queue_.IsEmpty()) { - LOG_IF(WARNING, !WriteMessageNoLock(channel_message_queue_.GetMessage())) - << "Failed to write enqueue message to channel"; + bool ok = WriteMessageNoLock(channel_message_queue_.GetMessage()); + LOG_IF(WARNING, !ok) << "Failed to write enqueue message to channel"; } if (!client_) { diff --git a/third_party/mojo/src/mojo/edk/system/channel_info.cc b/third_party/mojo/src/mojo/edk/system/channel_info.cc index 6d23215..e2c69e6 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_info.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_info.cc @@ -6,6 +6,9 @@ #include <algorithm> +#include "base/task_runner.h" +#include "mojo/edk/system/channel.h" + namespace mojo { namespace system { diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager.cc b/third_party/mojo/src/mojo/edk/system/channel_manager.cc index c2fe8a5..634accc 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_manager.cc @@ -9,6 +9,9 @@ #include "base/location.h" #include "base/message_loop/message_loop_proxy.h" #include "base/task_runner.h" +#include "mojo/edk/system/channel.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/message_pipe_dispatcher.h" namespace mojo { namespace system { @@ -38,33 +41,21 @@ ChannelManager::~ChannelManager() { ShutdownChannelHelper(map_elem.second); } -void ChannelManager::CreateChannelOnIOThread( +scoped_refptr<MessagePipeDispatcher> ChannelManager::CreateChannelOnIOThread( ChannelId channel_id, - embedder::ScopedPlatformHandle platform_handle, - scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint) { - DCHECK_NE(channel_id, kInvalidChannelId); - DCHECK(platform_handle.is_valid()); - DCHECK(bootstrap_channel_endpoint); - - // Create and initialize a |system::Channel|. - scoped_refptr<system::Channel> channel = - new system::Channel(platform_support_); - channel->Init(system::RawChannel::Create(platform_handle.Pass())); - channel->SetBootstrapEndpoint(bootstrap_channel_endpoint); - - { - base::AutoLock locker(lock_); - CHECK(channel_infos_.find(channel_id) == channel_infos_.end()); - channel_infos_[channel_id] = - ChannelInfo(channel, base::MessageLoopProxy::current()); - } - channel->SetChannelManager(this); + embedder::ScopedPlatformHandle platform_handle) { + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint; + scoped_refptr<system::MessagePipeDispatcher> dispatcher = + system::MessagePipeDispatcher::CreateRemoteMessagePipe( + &bootstrap_channel_endpoint); + CreateChannelOnIOThreadHelper(channel_id, platform_handle.Pass(), + bootstrap_channel_endpoint); + return dispatcher; } -void ChannelManager::CreateChannel( +scoped_refptr<MessagePipeDispatcher> ChannelManager::CreateChannel( ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, - scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, scoped_refptr<base::TaskRunner> io_thread_task_runner, base::Closure callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner) { @@ -72,12 +63,17 @@ void ChannelManager::CreateChannel( DCHECK(!callback.is_null()); // (|callback_thread_task_runner| may be null.) + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint; + scoped_refptr<system::MessagePipeDispatcher> dispatcher = + system::MessagePipeDispatcher::CreateRemoteMessagePipe( + &bootstrap_channel_endpoint); io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&ChannelManager::CreateChannelHelper, base::Unretained(this), channel_id, base::Passed(&platform_handle), bootstrap_channel_endpoint, callback, callback_thread_task_runner)); + return dispatcher; } scoped_refptr<Channel> ChannelManager::GetChannel(ChannelId channel_id) const { @@ -103,14 +99,37 @@ void ChannelManager::ShutdownChannel(ChannelId channel_id) { ShutdownChannelHelper(channel_info); } +void ChannelManager::CreateChannelOnIOThreadHelper( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint) { + DCHECK_NE(channel_id, kInvalidChannelId); + DCHECK(platform_handle.is_valid()); + DCHECK(bootstrap_channel_endpoint); + + // Create and initialize a |system::Channel|. + scoped_refptr<system::Channel> channel = + new system::Channel(platform_support_); + channel->Init(system::RawChannel::Create(platform_handle.Pass())); + channel->SetBootstrapEndpoint(bootstrap_channel_endpoint); + + { + base::AutoLock locker(lock_); + CHECK(channel_infos_.find(channel_id) == channel_infos_.end()); + channel_infos_[channel_id] = + ChannelInfo(channel, base::MessageLoopProxy::current()); + } + channel->SetChannelManager(this); +} + void ChannelManager::CreateChannelHelper( ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, base::Closure callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner) { - CreateChannelOnIOThread(channel_id, platform_handle.Pass(), - bootstrap_channel_endpoint); + CreateChannelOnIOThreadHelper(channel_id, platform_handle.Pass(), + bootstrap_channel_endpoint); if (callback_thread_task_runner) callback_thread_task_runner->PostTask(FROM_HERE, callback); else diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager.h b/third_party/mojo/src/mojo/edk/system/channel_manager.h index 35a4f27..da3e030 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager.h +++ b/third_party/mojo/src/mojo/edk/system/channel_manager.h @@ -7,12 +7,12 @@ #include <stdint.h> +#include "base/callback_forward.h" #include "base/containers/hash_tables.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" #include "mojo/edk/embedder/scoped_platform_handle.h" -#include "mojo/edk/system/channel.h" #include "mojo/edk/system/channel_info.h" namespace base { @@ -27,6 +27,10 @@ class PlatformSupport; namespace system { +class Channel; +class ChannelEndpoint; +class MessagePipeDispatcher; + // IDs for |Channel|s managed by a |ChannelManager|. (IDs should be thought of // as specific to a given |ChannelManager|.) 0 is never a valid ID. typedef uint64_t ChannelId; @@ -49,27 +53,21 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelManager { // TODO(vtl): Currently, this should be called on any I/O thread (which will // become the new channel's "channel thread"). Eventually, the channel manager // will have an assigned I/O thread, on which this must be called. - // TODO(vtl): Probably this should return a message pipe dispatcher (for the - // bootstrap message pipe) instead. - void CreateChannelOnIOThread( + scoped_refptr<MessagePipeDispatcher> CreateChannelOnIOThread( ChannelId channel_id, - embedder::ScopedPlatformHandle platform_handle, - scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint); + embedder::ScopedPlatformHandle platform_handle); // Like |CreateChannelOnIOThread()|, but may be called from any thread. On // completion, will call |callback| ("on" |io_thread_task_runner| if - // |callback_thread_task_runner| is null else by posting to using + // |callback_thread_task_runner| is null else by posted using // |callback_thread_task_runner|). Note: This will always post a task to the // I/O thread, even if |io_thread_task_runner| is the task runner for the // current thread. // TODO(vtl): The |io_thread_task_runner| argument is temporary (we should use // the channel manager's I/O thread). - // TODO(vtl): Probably this should return a message pipe dispatcher (for the - // bootstrap message pipe) instead. - void CreateChannel( + scoped_refptr<MessagePipeDispatcher> CreateChannel( ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, - scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, scoped_refptr<base::TaskRunner> io_thread_task_runner, base::Closure callback, scoped_refptr<base::TaskRunner> callback_thread_task_runner); @@ -92,6 +90,14 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelManager { void ShutdownChannel(ChannelId channel_id); private: + // Used by |CreateChannelOnIOThread()| and |CreateChannelHelper()|. Called on + // the I/O thread. + void CreateChannelOnIOThreadHelper( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint); + + // Used by |CreateChannel()|. Called on the I/O thread. void CreateChannelHelper( ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc index c5aa503..86ab4a0 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc @@ -48,12 +48,9 @@ TEST_F(ChannelManagerTest, Basic) { embedder::PlatformChannelPair channel_pair; - scoped_refptr<ChannelEndpoint> cep; - scoped_refptr<MessagePipeDispatcher> d = - MessagePipeDispatcher::CreateRemoteMessagePipe(&cep); const ChannelId id = 1; - cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle(), cep); - cep = nullptr; + scoped_refptr<MessagePipeDispatcher> d = + cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle()); scoped_refptr<Channel> ch = cm.GetChannel(id); EXPECT_TRUE(ch); @@ -77,19 +74,13 @@ TEST_F(ChannelManagerTest, TwoChannels) { embedder::PlatformChannelPair channel_pair; - scoped_refptr<ChannelEndpoint> cep1; - scoped_refptr<MessagePipeDispatcher> d1 = - MessagePipeDispatcher::CreateRemoteMessagePipe(&cep1); const ChannelId id1 = 1; - cm.CreateChannelOnIOThread(id1, channel_pair.PassServerHandle(), cep1); - cep1 = nullptr; + scoped_refptr<MessagePipeDispatcher> d1 = + cm.CreateChannelOnIOThread(id1, channel_pair.PassServerHandle()); - scoped_refptr<ChannelEndpoint> cep2; - scoped_refptr<MessagePipeDispatcher> d2 = - MessagePipeDispatcher::CreateRemoteMessagePipe(&cep2); const ChannelId id2 = 2; - cm.CreateChannelOnIOThread(id2, channel_pair.PassClientHandle(), cep2); - cep2 = nullptr; + scoped_refptr<MessagePipeDispatcher> d2 = + cm.CreateChannelOnIOThread(id2, channel_pair.PassClientHandle()); scoped_refptr<Channel> ch1 = cm.GetChannel(id1); EXPECT_TRUE(ch1); @@ -173,12 +164,9 @@ TEST_F(ChannelManagerTest, CallsFromOtherThread) { embedder::PlatformChannelPair channel_pair; - scoped_refptr<ChannelEndpoint> cep; - scoped_refptr<MessagePipeDispatcher> d = - MessagePipeDispatcher::CreateRemoteMessagePipe(&cep); const ChannelId id = 1; - cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle(), cep); - cep = nullptr; + scoped_refptr<MessagePipeDispatcher> d = + cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle()); base::RunLoop run_loop; OtherThread thread(base::MessageLoopProxy::current(), &cm, id, diff --git a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc index 2894c65..f1939a0 100644 --- a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc @@ -87,7 +87,8 @@ void ConnectSlave(MasterConnectionManager* master, embedder::PlatformChannelPair platform_channel_pair; master->AddSlave(make_scoped_ptr(new TestSlaveInfo(slave_name)), platform_channel_pair.PassServerHandle()); - slave->Init(slave_process_delegate, platform_channel_pair.PassClientHandle()); + slave->Init(base::MessageLoop::current()->task_runner(), + slave_process_delegate, platform_channel_pair.PassClientHandle()); } class MockMasterProcessDelegate : public embedder::MasterProcessDelegate { @@ -191,7 +192,8 @@ class ConnectionManagerTest : public testing::Test { TEST_F(ConnectionManagerTest, BasicConnectSlaves) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave1_process_delegate; SlaveConnectionManager slave1; @@ -250,7 +252,8 @@ TEST_F(ConnectionManagerTest, BasicConnectSlaves) { TEST_F(ConnectionManagerTest, ShutdownMasterBeforeSlave) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave_process_delegate; SlaveConnectionManager slave; @@ -277,7 +280,8 @@ TEST_F(ConnectionManagerTest, ShutdownMasterBeforeSlave) { TEST_F(ConnectionManagerTest, SlaveCancelConnect) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave1_process_delegate; SlaveConnectionManager slave1; @@ -306,7 +310,8 @@ TEST_F(ConnectionManagerTest, SlaveCancelConnect) { // Tests that pending connections are removed on error. TEST_F(ConnectionManagerTest, ErrorRemovePending) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave1_process_delegate; SlaveConnectionManager slave1; @@ -340,7 +345,8 @@ TEST_F(ConnectionManagerTest, ErrorRemovePending) { TEST_F(ConnectionManagerTest, ConnectSlaveToSelf) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave_process_delegate; SlaveConnectionManager slave; @@ -371,7 +377,8 @@ TEST_F(ConnectionManagerTest, ConnectSlaveToSelf) { TEST_F(ConnectionManagerTest, ConnectSlavesTwice) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave1_process_delegate; SlaveConnectionManager slave1; @@ -422,7 +429,8 @@ TEST_F(ConnectionManagerTest, ConnectSlavesTwice) { TEST_F(ConnectionManagerTest, ConnectMasterToSlave) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave_process_delegate; SlaveConnectionManager slave; @@ -452,7 +460,8 @@ TEST_F(ConnectionManagerTest, ConnectMasterToSlave) { TEST_F(ConnectionManagerTest, ConnectMasterToSelf) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); ConnectionIdentifier connection_id = ConnectionIdentifier::Generate(); EXPECT_TRUE(master.AllowConnect(connection_id)); @@ -478,7 +487,8 @@ TEST_F(ConnectionManagerTest, ConnectMasterToSelf) { TEST_F(ConnectionManagerTest, MasterCancelConnect) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave_process_delegate; SlaveConnectionManager slave; @@ -501,7 +511,8 @@ TEST_F(ConnectionManagerTest, MasterCancelConnect) { TEST_F(ConnectionManagerTest, AddSlaveThenImmediateShutdown) { MasterConnectionManager master; - master.Init(&master_process_delegate()); + master.Init(base::MessageLoop::current()->task_runner(), + &master_process_delegate()); MockSlaveProcessDelegate slave_process_delegate; SlaveConnectionManager slave; diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc index 4d7deae..b401bcd 100644 --- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc @@ -220,16 +220,13 @@ struct MasterConnectionManager::PendingConnectionInfo { // MasterConnectionManager ----------------------------------------------------- MasterConnectionManager::MasterConnectionManager() - : creation_thread_task_runner_(base::MessageLoop::current()->task_runner()), - master_process_delegate_(), + : master_process_delegate_(), private_thread_("MasterConnectionManagerPrivateThread"), next_process_identifier_(kFirstSlaveProcessIdentifier) { - DCHECK(creation_thread_task_runner_); - AssertOnCreationThread(); // Just make sure this assertion works correctly. } MasterConnectionManager::~MasterConnectionManager() { - AssertOnCreationThread(); + DCHECK(!delegate_thread_task_runner_); DCHECK(!master_process_delegate_); DCHECK(!private_thread_.message_loop()); DCHECK(helpers_.empty()); @@ -237,19 +234,23 @@ MasterConnectionManager::~MasterConnectionManager() { } void MasterConnectionManager::Init( + scoped_refptr<base::TaskRunner> delegate_thread_task_runner, embedder::MasterProcessDelegate* master_process_delegate) { - AssertOnCreationThread(); + DCHECK(delegate_thread_task_runner); DCHECK(master_process_delegate); + DCHECK(!delegate_thread_task_runner_); DCHECK(!master_process_delegate_); DCHECK(!private_thread_.message_loop()); + delegate_thread_task_runner_ = delegate_thread_task_runner; + AssertOnDelegateThread(); master_process_delegate_ = master_process_delegate; CHECK(private_thread_.StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); } void MasterConnectionManager::Shutdown() { - AssertOnCreationThread(); + AssertOnDelegateThread(); DCHECK(master_process_delegate_); DCHECK(private_thread_.message_loop()); @@ -261,6 +262,7 @@ void MasterConnectionManager::Shutdown() { DCHECK(helpers_.empty()); DCHECK(pending_connections_.empty()); master_process_delegate_ = nullptr; + delegate_thread_task_runner_ = nullptr; } void MasterConnectionManager::AddSlave( @@ -547,16 +549,16 @@ void MasterConnectionManager::CallOnSlaveDisconnect( scoped_ptr<embedder::SlaveInfo> slave_info) { AssertOnPrivateThread(); DCHECK(master_process_delegate_); - creation_thread_task_runner_->PostTask( + delegate_thread_task_runner_->PostTask( FROM_HERE, base::Bind(&embedder::MasterProcessDelegate::OnSlaveDisconnect, base::Unretained(master_process_delegate_), base::Passed(&slave_info))); } -void MasterConnectionManager::AssertOnCreationThread() const { +void MasterConnectionManager::AssertOnDelegateThread() const { DCHECK(base::MessageLoop::current()); DCHECK_EQ(base::MessageLoop::current()->task_runner(), - creation_thread_task_runner_); + delegate_thread_task_runner_); } void MasterConnectionManager::AssertNotOnPrivateThread() const { diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h index 978d9fe..5bdb810 100644 --- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h +++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h @@ -35,10 +35,10 @@ const ProcessIdentifier kMasterProcessIdentifier = 1; // The |ConnectionManager| implementation for the master process. // -// Objects of this class must be created, initialized (via |Init()|), shut down -// (via |Shutdown()|), and destroyed on the same thread (the "creation thread"). -// Otherwise, its public methods are thread-safe (except that they may not be -// called from its internal, private thread). +// Objects of this class may be created and destroyed on any thread. However, +// |Init()| and |Shutdown()| must be called on the "delegate thread". Otherwise, +// its public methods are thread-safe (except that they may not be called from +// its internal, private thread). class MOJO_SYSTEM_IMPL_EXPORT MasterConnectionManager : public ConnectionManager { public: @@ -48,10 +48,11 @@ class MOJO_SYSTEM_IMPL_EXPORT MasterConnectionManager ~MasterConnectionManager() override; // No other methods may be called until after this has been called. - // |master_process_delegate| must stay alive at least until after |Shutdown()| - // has been called; its methods will be called on this object's creation - // thread. - void Init(embedder::MasterProcessDelegate* master_process_delegate); + // |delegate_thread_task_runner| should be the task runner for the "delegate + // thread", on which |master_process_delegate|'s methods will be called. Both + // must stay alive at least until after |Shutdown()| has been called. + void Init(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, + embedder::MasterProcessDelegate* master_process_delegate); // No other methods may be called after this is (or while it is being) called. void Shutdown(); @@ -96,10 +97,10 @@ class MOJO_SYSTEM_IMPL_EXPORT MasterConnectionManager // Posts a call to |master_process_delegate_->OnSlaveDisconnect()|. void CallOnSlaveDisconnect(scoped_ptr<embedder::SlaveInfo> slave_info); - // Asserts that the current thread is the creation thread. (This actually - // checks the current message loop, which is what we depend on, not the thread - // per se.) - void AssertOnCreationThread() const; + // Asserts that the current thread is the delegate thread. (This actually + // checks the current message loop.) + // TODO(vtl): Probably we should actually check the thread. + void AssertOnDelegateThread() const; // Asserts that the current thread is *not* |private_thread_| (no-op if // DCHECKs are not enabled). This should only be called while @@ -111,12 +112,11 @@ class MOJO_SYSTEM_IMPL_EXPORT MasterConnectionManager // (i.e., after |Init()| but before |Shutdown()|). void AssertOnPrivateThread() const; - const scoped_refptr<base::TaskRunner> creation_thread_task_runner_; - - // This is set in |Init()| before |private_thread_| exists and only cleared in - // |Shutdown()| after |private_thread_| is dead. Thus it's safe to "use" on + // These are set in |Init()| before |private_thread_| exists and only cleared + // in |Shutdown()| after |private_thread_| is dead. Thus it's safe to "use" on // |private_thread_|. (Note that |master_process_delegate_| may only be called - // from the creation thread.) + // from the delegate thread.) + scoped_refptr<base::TaskRunner> delegate_thread_task_runner_; embedder::MasterProcessDelegate* master_process_delegate_; // This is a private I/O thread on which this class does the bulk of its work. diff --git a/third_party/mojo/src/mojo/edk/system/proxy_message_pipe_endpoint.cc b/third_party/mojo/src/mojo/edk/system/proxy_message_pipe_endpoint.cc index 5f0f2e9..ce96f24 100644 --- a/third_party/mojo/src/mojo/edk/system/proxy_message_pipe_endpoint.cc +++ b/third_party/mojo/src/mojo/edk/system/proxy_message_pipe_endpoint.cc @@ -46,8 +46,8 @@ bool ProxyMessagePipeEndpoint::OnPeerClose() { void ProxyMessagePipeEndpoint::EnqueueMessage( scoped_ptr<MessageInTransit> message) { DCHECK(channel_endpoint_); - LOG_IF(WARNING, !channel_endpoint_->EnqueueMessage(message.Pass())) - << "Failed to write enqueue message to channel"; + bool ok = channel_endpoint_->EnqueueMessage(message.Pass()); + LOG_IF(WARNING, !ok) << "Failed to write enqueue message to channel"; } void ProxyMessagePipeEndpoint::Close() { diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc index 2427823..de8d17f 100644 --- a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc @@ -17,20 +17,17 @@ namespace system { // SlaveConnectionManager ------------------------------------------------------ SlaveConnectionManager::SlaveConnectionManager() - : creation_thread_task_runner_(base::MessageLoop::current()->task_runner()), - slave_process_delegate_(), + : slave_process_delegate_(), private_thread_("SlaveConnectionManagerPrivateThread"), awaiting_ack_type_(NOT_AWAITING_ACK), ack_result_(), ack_peer_process_identifier_(), ack_platform_handle_(), event_(false, false) { // Auto-reset, not initially signalled. - DCHECK(creation_thread_task_runner_); - AssertOnCreationThread(); // Just make sure this assertion works correctly. } SlaveConnectionManager::~SlaveConnectionManager() { - AssertOnCreationThread(); + DCHECK(!delegate_thread_task_runner_); DCHECK(!slave_process_delegate_); DCHECK(!private_thread_.message_loop()); DCHECK_EQ(awaiting_ack_type_, NOT_AWAITING_ACK); @@ -40,14 +37,18 @@ SlaveConnectionManager::~SlaveConnectionManager() { } void SlaveConnectionManager::Init( + scoped_refptr<base::TaskRunner> delegate_thread_task_runner, embedder::SlaveProcessDelegate* slave_process_delegate, embedder::ScopedPlatformHandle platform_handle) { - AssertOnCreationThread(); + DCHECK(delegate_thread_task_runner); DCHECK(slave_process_delegate); DCHECK(platform_handle.is_valid()); + DCHECK(!delegate_thread_task_runner_); DCHECK(!slave_process_delegate_); DCHECK(!private_thread_.message_loop()); + delegate_thread_task_runner_ = delegate_thread_task_runner; + AssertOnDelegateThread(); slave_process_delegate_ = slave_process_delegate; CHECK(private_thread_.StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); @@ -59,7 +60,7 @@ void SlaveConnectionManager::Init( } void SlaveConnectionManager::Shutdown() { - AssertOnCreationThread(); + AssertOnDelegateThread(); DCHECK(slave_process_delegate_); DCHECK(private_thread_.message_loop()); @@ -69,6 +70,7 @@ void SlaveConnectionManager::Shutdown() { base::Unretained(this))); private_thread_.Stop(); slave_process_delegate_ = nullptr; + delegate_thread_task_runner_ = nullptr; } bool SlaveConnectionManager::AllowConnect( @@ -287,15 +289,15 @@ void SlaveConnectionManager::OnError(Error error) { raw_channel_.reset(); DCHECK(slave_process_delegate_); - creation_thread_task_runner_->PostTask( + delegate_thread_task_runner_->PostTask( FROM_HERE, base::Bind(&embedder::SlaveProcessDelegate::OnMasterDisconnect, base::Unretained(slave_process_delegate_))); } -void SlaveConnectionManager::AssertOnCreationThread() const { +void SlaveConnectionManager::AssertOnDelegateThread() const { DCHECK(base::MessageLoop::current()); DCHECK_EQ(base::MessageLoop::current()->task_runner(), - creation_thread_task_runner_); + delegate_thread_task_runner_); } void SlaveConnectionManager::AssertNotOnPrivateThread() const { diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h index e773448..731d9db 100644 --- a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h +++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h @@ -31,10 +31,10 @@ namespace system { // The |ConnectionManager| implementation for slave processes. // -// Objects of this class must created, initialized (via |Init()|), shut down -// (via |Shutdown()|), and destroyed on the same thread (the "creation thread"). -// Otherwise, its public methods are thread-safe (except that they may not be -// called from its internal, private thread). +// Objects of this class may be created and destroyed on any thread. However, +// |Init()| and |Shutdown()| must be called on the "delegate thread". Otherwise, +// its public methods are thread-safe (except that they may not be called from +// its internal, private thread). class MOJO_SYSTEM_IMPL_EXPORT SlaveConnectionManager : public ConnectionManager, public RawChannel::Delegate { @@ -45,10 +45,11 @@ class MOJO_SYSTEM_IMPL_EXPORT SlaveConnectionManager ~SlaveConnectionManager() override; // No other methods may be called until after this has been called. - // |slave_process_delegate| must stay alive at least until after |Shutdown()| - // has been called; its methods will be called on this object's creation - // thread. - void Init(embedder::SlaveProcessDelegate* slave_process_delegate, + // |delegate_thread_task_runner| should be the task runner for the "delegate + // thread", on which |slave_process_delegate|'s methods will be called. Both + // must stay alive at least until after |Shutdown()| has been called. + void Init(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, + embedder::SlaveProcessDelegate* slave_process_delegate, embedder::ScopedPlatformHandle platform_handle); // No other methods may be called after this is (or while it is being) called. @@ -80,10 +81,10 @@ class MOJO_SYSTEM_IMPL_EXPORT SlaveConnectionManager embedder::ScopedPlatformHandleVectorPtr platform_handles) override; void OnError(Error error) override; - // Asserts that the current thread is the creation thread. (This actually - // checks the current message loop, which is what we depend on, not the thread - // per se.) - void AssertOnCreationThread() const; + // Asserts that the current thread is the delegate thread. (This actually + // checks the current message loop.) + // TODO(vtl): Probably we should actually check the thread. + void AssertOnDelegateThread() const; // Asserts that the current thread is *not* |private_thread_| (no-op if // DCHECKs are not enabled). This should only be called while @@ -95,12 +96,11 @@ class MOJO_SYSTEM_IMPL_EXPORT SlaveConnectionManager // (i.e., after |Init()| but before |Shutdown()|). void AssertOnPrivateThread() const; - const scoped_refptr<base::TaskRunner> creation_thread_task_runner_; - - // These is set in |Init()| before |private_thread_| exists and only cleared + // These are set in |Init()| before |private_thread_| exists and only cleared // in |Shutdown()| after |private_thread_| is dead. Thus it's safe to "use" on // |private_thread_|. (Note that |slave_process_delegate_| may only be called - // from the creation thread.) + // from the delegate thread.) + scoped_refptr<base::TaskRunner> delegate_thread_task_runner_; embedder::SlaveProcessDelegate* slave_process_delegate_; // This is a private I/O thread on which this class does the bulk of its work. diff --git a/third_party/mojo/src/mojo/public/VERSION b/third_party/mojo/src/mojo/public/VERSION index 63d6820..58655cc 100644 --- a/third_party/mojo/src/mojo/public/VERSION +++ b/third_party/mojo/src/mojo/public/VERSION @@ -1 +1 @@ -8d45c89c30b230843c5bd6dd0693a555750946c0
\ No newline at end of file +8af2ccff2eee4bfca1043015abee30482a030b30
\ No newline at end of file diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.cc b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.cc index b065d90..d1d723a 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.cc @@ -42,6 +42,8 @@ const char* ValidationErrorToString(ValidationError error) { return "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID"; case VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP: return "VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP"; + case VALIDATION_ERROR_UNKOWN_UNION_TAG: + return "VALIDATION_ERROR_UNKOWN_UNION_TAG"; } return "Unknown error"; diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h index 2abb1b7..4facf6e 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/lib/validation_errors.h @@ -46,7 +46,9 @@ enum ValidationError { VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID, // Two parallel arrays which are supposed to represent a map have different // lengths. - VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP + VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP, + // Attempted to deserialize a tagged union with an unknown tag. + VALIDATION_ERROR_UNKOWN_UNION_TAG }; const char* ValidationErrorToString(ValidationError error); diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/BUILD.gn b/third_party/mojo/src/mojo/public/cpp/bindings/tests/BUILD.gn index 0051270..b267e4e 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/BUILD.gn +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/BUILD.gn @@ -24,6 +24,7 @@ mojo_sdk_source_set("tests") { "string_unittest.cc", "struct_unittest.cc", "type_conversion_unittest.cc", + "union_unittest.cc", "validation_unittest.cc", ] diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc index 4359be8..f2e693d 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc @@ -46,6 +46,18 @@ class SerializationWarningTest : public testing::Test { template <typename T> void TestWarning(StructPtr<T> obj, mojo::internal::ValidationError expected_warning) { + TestStructWarningImpl<T>(obj.Pass(), expected_warning); + } + + template <typename T> + void TestWarning(InlinedStructPtr<T> obj, + mojo::internal::ValidationError expected_warning) { + TestStructWarningImpl<T>(obj.Pass(), expected_warning); + } + + template <typename T, typename TPtr> + void TestStructWarningImpl(TPtr obj, + mojo::internal::ValidationError expected_warning) { warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); mojo::internal::FixedBuffer buf(GetSerializedSize_(obj)); diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc b/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc index a8d8a95..f811a22 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc +++ b/third_party/mojo/src/mojo/public/cpp/bindings/tests/union_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/string.h" #include "mojo/public/cpp/environment/environment.h" @@ -118,19 +119,79 @@ TEST(UnionTest, SerializationPod) { EXPECT_EQ(pod2->which(), PodUnion::Tag::F_INT8); } -TEST(UnionTest, StringGetterSetter) { +TEST(UnionTest, ValidationJustWorksPod) { PodUnionPtr pod(PodUnion::New()); + pod->set_f_int8(10); + + size_t size = GetSerializedSize_(pod); + EXPECT_EQ(16U, size); + + mojo::internal::FixedBuffer buf(size); + internal::PodUnion_Data* data; + Serialize_(pod.Pass(), &buf, &data); + void* raw_buf = buf.Leak(); + mojo::internal::BoundsChecker bounds_checker(data, size, 0); + EXPECT_TRUE(internal::PodUnion_Data::Validate(raw_buf, &bounds_checker)); + free(raw_buf); +} + +TEST(UnionTest, NullValidation) { + void* buf = nullptr; + mojo::internal::BoundsChecker bounds_checker(buf, 0, 0); + EXPECT_TRUE(internal::PodUnion_Data::Validate(buf, &bounds_checker)); +} + +TEST(UnionTest, OutOfAlignmentValidation) { + Environment environment; + size_t size = sizeof(internal::PodUnion_Data); + // Get an aligned object and shift the alignment. + mojo::internal::FixedBuffer aligned_buf(size + 1); + void* raw_buf = aligned_buf.Leak(); + char* buf = reinterpret_cast<char*>(raw_buf) + 1; + + internal::PodUnion_Data* data = + reinterpret_cast<internal::PodUnion_Data*>(buf); + mojo::internal::BoundsChecker bounds_checker(data, size, 0); + EXPECT_FALSE(internal::PodUnion_Data::Validate(buf, &bounds_checker)); + free(raw_buf); +} + +TEST(UnionTest, OOBValidation) { + Environment environment; + size_t size = sizeof(internal::PodUnion_Data) - 1; + mojo::internal::FixedBuffer buf(size); + internal::PodUnion_Data* data = internal::PodUnion_Data::New(&buf); + mojo::internal::BoundsChecker bounds_checker(data, size, 0); + void* raw_buf = buf.Leak(); + EXPECT_FALSE(internal::PodUnion_Data::Validate(raw_buf, &bounds_checker)); + free(raw_buf); +} + +TEST(UnionTest, UnknownTagValidation) { + Environment environment; + size_t size = sizeof(internal::PodUnion_Data); + mojo::internal::FixedBuffer buf(size); + internal::PodUnion_Data* data = internal::PodUnion_Data::New(&buf); + data->tag = static_cast<internal::PodUnion_Data::PodUnion_Tag>(0xFFFFFF); + mojo::internal::BoundsChecker bounds_checker(data, size, 0); + void* raw_buf = buf.Leak(); + EXPECT_FALSE(internal::PodUnion_Data::Validate(raw_buf, &bounds_checker)); + free(raw_buf); +} + +TEST(UnionTest, StringGetterSetter) { + ObjectUnionPtr pod(ObjectUnion::New()); String hello("hello world"); pod->set_f_string(hello); EXPECT_EQ(hello, pod->get_f_string()); EXPECT_TRUE(pod->is_f_string()); - EXPECT_EQ(pod->which(), PodUnion::Tag::F_STRING); + EXPECT_EQ(pod->which(), ObjectUnion::Tag::F_STRING); } TEST(UnionTest, StringEquals) { - PodUnionPtr pod1(PodUnion::New()); - PodUnionPtr pod2(PodUnion::New()); + ObjectUnionPtr pod1(ObjectUnion::New()); + ObjectUnionPtr pod2(ObjectUnion::New()); pod1->set_f_string("hello world"); pod2->set_f_string("hello world"); @@ -141,32 +202,77 @@ TEST(UnionTest, StringEquals) { } TEST(UnionTest, StringClone) { - PodUnionPtr pod(PodUnion::New()); + ObjectUnionPtr pod(ObjectUnion::New()); String hello("hello world"); pod->set_f_string(hello); - PodUnionPtr pod_clone = pod.Clone(); + ObjectUnionPtr pod_clone = pod.Clone(); EXPECT_EQ(hello, pod_clone->get_f_string()); EXPECT_TRUE(pod_clone->is_f_string()); - EXPECT_EQ(pod_clone->which(), PodUnion::Tag::F_STRING); + EXPECT_EQ(pod_clone->which(), ObjectUnion::Tag::F_STRING); } TEST(UnionTest, StringSerialization) { - PodUnionPtr pod1(PodUnion::New()); + ObjectUnionPtr pod1(ObjectUnion::New()); String hello("hello world"); pod1->set_f_string(hello); size_t size = GetSerializedSize_(pod1); mojo::internal::FixedBuffer buf(size); - internal::PodUnion_Data* data; + internal::ObjectUnion_Data* data; Serialize_(pod1.Pass(), &buf, &data); - PodUnionPtr pod2; + ObjectUnionPtr pod2; Deserialize_(data, &pod2); EXPECT_EQ(hello, pod2->get_f_string()); EXPECT_TRUE(pod2->is_f_string()); - EXPECT_EQ(pod2->which(), PodUnion::Tag::F_STRING); + EXPECT_EQ(pod2->which(), ObjectUnion::Tag::F_STRING); +} + +TEST(UnionTest, StringValidationNull) { + Environment environment; + size_t size = sizeof(internal::ObjectUnion_Data); + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = internal::ObjectUnion_Data::New(&buf); + data->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; + data->data.unknown = 0x0; + mojo::internal::BoundsChecker bounds_checker(data, size, 0); + void* raw_buf = buf.Leak(); + EXPECT_FALSE(internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker)); + free(raw_buf); +} + +TEST(UnionTest, StringValidationPointerOverflow) { + Environment environment; + size_t size = sizeof(internal::ObjectUnion_Data); + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = internal::ObjectUnion_Data::New(&buf); + data->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; + data->data.unknown = 0xFFFFFFFFFFFFFFFF; + mojo::internal::BoundsChecker bounds_checker(data, size, 0); + void* raw_buf = buf.Leak(); + EXPECT_FALSE(internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker)); + free(raw_buf); +} + +TEST(UnionTest, StringValidationValidateString) { + Environment environment; + size_t size = 32; + mojo::internal::FixedBuffer buf(size); + internal::ObjectUnion_Data* data = internal::ObjectUnion_Data::New(&buf); + data->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; + + data->data.f_f_string = 8; + char* ptr = reinterpret_cast<char*>(&data->data.f_f_string); + mojo::internal::ArrayHeader* array_header = + reinterpret_cast<mojo::internal::ArrayHeader*>(ptr + *ptr); + array_header->num_bytes = 20; // This should go out of bounds. + array_header->num_elements = 20; + mojo::internal::BoundsChecker bounds_checker(data, 32, 0); + void* raw_buf = buf.Leak(); + EXPECT_FALSE(internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker)); + free(raw_buf); } } // namespace test } // namespace mojo diff --git a/third_party/mojo/src/mojo/public/go/system/core.go b/third_party/mojo/src/mojo/public/go/system/core.go index e1b8cd4..da6313e 100644 --- a/third_party/mojo/src/mojo/public/go/system/core.go +++ b/third_party/mojo/src/mojo/public/go/system/core.go @@ -9,6 +9,7 @@ package system import "C" import ( "reflect" + "sync" "unsafe" ) @@ -57,8 +58,21 @@ type Core interface { // coreImpl is an implementation of the Mojo system APIs. type coreImpl struct { + // Protects from making parallel non-blocking mojo cgo calls. + mu sync.Mutex } +// GetCore returns singleton instance of the Mojo system APIs implementation. +// +// The implementation uses cgo to call native mojo APIs implementation. Each cgo +// call uses a separate thread for execution. To limit the number of used +// threads all non-blocking system calls (i.e. all system calls except |Wait| +// and |WaitMany|) on this implementation and on handles returned by this +// implementation are protected by a mutex so that if you make two parallel +// system calls one will wait for another to finish before executing. +// However, |Wait| and |WaitMany| are not protected by a mutex and each parallel +// call will use a separate thread. To reduce number of threads used for |Wait| +// calls prefer to use |WaitMany|. func GetCore() Core { return &core } @@ -68,10 +82,13 @@ func (impl *coreImpl) acquireCHandle(handle C.MojoHandle) UntypedHandle { } func (impl *coreImpl) AcquireNativeHandle(handle MojoHandle) UntypedHandle { - return &untypedHandleImpl{baseHandle{handle}} + return &untypedHandleImpl{baseHandle{impl, handle}} } func (impl *coreImpl) GetTimeTicksNow() MojoTimeTicks { + impl.mu.Lock() + defer impl.mu.Unlock() + return MojoTimeTicks(C.MojoGetTimeTicksNow()) } @@ -108,6 +125,9 @@ func (impl *coreImpl) WaitMany(handles []Handle, signals []MojoHandleSignals, de } func (impl *coreImpl) CreateDataPipe(opts *DataPipeOptions) (MojoResult, ProducerHandle, ConsumerHandle) { + impl.mu.Lock() + defer impl.mu.Unlock() + cParams := C.MallocCreateDataPipeParams() defer C.FreeCreateDataPipeParams(cParams) result := C.MojoCreateDataPipe(opts.cValue(cParams.opts), cParams.producer, cParams.consumer) @@ -117,6 +137,9 @@ func (impl *coreImpl) CreateDataPipe(opts *DataPipeOptions) (MojoResult, Produce } func (impl *coreImpl) CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, MessagePipeHandle, MessagePipeHandle) { + impl.mu.Lock() + defer impl.mu.Unlock() + cParams := C.MallocCreateMessagePipeParams() defer C.FreeCreateMessagePipeParams(cParams) result := C.MojoCreateMessagePipe(opts.cValue(cParams.opts), cParams.handle0, cParams.handle1) @@ -126,6 +149,9 @@ func (impl *coreImpl) CreateMessagePipe(opts *MessagePipeOptions) (MojoResult, M } func (impl *coreImpl) CreateSharedBuffer(opts *SharedBufferOptions, numBytes uint64) (MojoResult, SharedBufferHandle) { + impl.mu.Lock() + defer impl.mu.Unlock() + cParams := C.MallocCreateSharedBufferParams() defer C.FreeCreateSharedBufferParams(cParams) result := C.MojoCreateSharedBuffer(opts.cValue(cParams.opts), C.uint64_t(numBytes), cParams.handle) diff --git a/third_party/mojo/src/mojo/public/go/system/data_pipe.go b/third_party/mojo/src/mojo/public/go/system/data_pipe.go index b79a1e0..a433074 100644 --- a/third_party/mojo/src/mojo/public/go/system/data_pipe.go +++ b/third_party/mojo/src/mojo/public/go/system/data_pipe.go @@ -86,6 +86,9 @@ type dataPipeConsumer struct { } func (h *dataPipeConsumer) ReadData(flags MojoReadDataFlags) (MojoResult, []byte) { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cParams := C.MallocReadDataParams() defer C.FreeReadDataParams(cParams) *cParams.num_bytes = 0 @@ -103,6 +106,9 @@ func (h *dataPipeConsumer) ReadData(flags MojoReadDataFlags) (MojoResult, []byte } func (h *dataPipeConsumer) BeginReadData(numBytes int, flags MojoReadDataFlags) (MojoResult, []byte) { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cParams := C.MallocTwoPhaseActionParams() defer C.FreeTwoPhaseActionParams(cParams) *cParams.num_bytes = C.uint32_t(numBytes) @@ -112,6 +118,9 @@ func (h *dataPipeConsumer) BeginReadData(numBytes int, flags MojoReadDataFlags) } func (h *dataPipeConsumer) EndReadData(numBytesRead int) MojoResult { + h.core.mu.Lock() + defer h.core.mu.Unlock() + return MojoResult(C.MojoEndReadData(h.mojoHandle.cValue(), C.uint32_t(numBytesRead))) } @@ -120,6 +129,9 @@ type dataPipeProducer struct { } func (h *dataPipeProducer) WriteData(data []byte, flags MojoWriteDataFlags) (MojoResult, int) { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cParams := C.MallocWriteDataParams(C.uint32_t(len(data))) defer C.FreeWriteDataParams(cParams) *cParams.num_bytes = C.uint32_t(len(data)) @@ -130,6 +142,9 @@ func (h *dataPipeProducer) WriteData(data []byte, flags MojoWriteDataFlags) (Moj } func (h *dataPipeProducer) BeginWriteData(numBytes int, flags MojoWriteDataFlags) (MojoResult, []byte) { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cParams := C.MallocTwoPhaseActionParams() defer C.FreeTwoPhaseActionParams(cParams) *cParams.num_bytes = C.uint32_t(numBytes) @@ -139,5 +154,8 @@ func (h *dataPipeProducer) BeginWriteData(numBytes int, flags MojoWriteDataFlags } func (h *dataPipeProducer) EndWriteData(numBytesWritten int) MojoResult { + h.core.mu.Lock() + defer h.core.mu.Unlock() + return MojoResult(C.MojoEndWriteData(h.mojoHandle.cValue(), C.uint32_t(numBytesWritten))) } diff --git a/third_party/mojo/src/mojo/public/go/system/handle.go b/third_party/mojo/src/mojo/public/go/system/handle.go index 6f020cf..189c8dd1 100644 --- a/third_party/mojo/src/mojo/public/go/system/handle.go +++ b/third_party/mojo/src/mojo/public/go/system/handle.go @@ -61,6 +61,7 @@ type UntypedHandle interface { } type baseHandle struct { + core *coreImpl mojoHandle MojoHandle } @@ -69,6 +70,9 @@ func (h *baseHandle) invalidate() { } func (h *baseHandle) Close() MojoResult { + h.core.mu.Lock() + defer h.core.mu.Unlock() + mojoHandle := h.mojoHandle h.invalidate() return MojoResult(C.MojoClose(mojoHandle.cValue())) diff --git a/third_party/mojo/src/mojo/public/go/system/message_pipe.go b/third_party/mojo/src/mojo/public/go/system/message_pipe.go index 3188ecf..79f0ae9 100644 --- a/third_party/mojo/src/mojo/public/go/system/message_pipe.go +++ b/third_party/mojo/src/mojo/public/go/system/message_pipe.go @@ -32,6 +32,9 @@ type messagePipe struct { } func (h *messagePipe) ReadMessage(flags MojoReadMessageFlags) (MojoResult, []byte, []UntypedHandle) { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cParams := C.MallocReadMessageParams() defer C.FreeReadMessageParams(cParams) *cParams.num_bytes = 0 @@ -52,12 +55,15 @@ func (h *messagePipe) ReadMessage(flags MojoReadMessageFlags) (MojoResult, []byt cHandles := *(*[]MojoHandle)(newUnsafeSlice(unsafe.Pointer(cArrays.handles), handlesLen)) handles := []UntypedHandle{} for i := 0; i < handlesLen; i++ { - handles = append(handles, &untypedHandleImpl{baseHandle{cHandles[i]}}) + handles = append(handles, h.core.AcquireNativeHandle(cHandles[i])) } return MojoResult(result), bytes, handles } func (h *messagePipe) WriteMessage(bytes []byte, handles []UntypedHandle, flags MojoWriteMessageFlags) MojoResult { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cArrays := C.MallocMessageArrays(C.uint32_t(len(bytes)), C.uint32_t(len(handles))) defer C.FreeMessageArrays(cArrays) cBytes := *(*[]byte)(newUnsafeSlice(unsafe.Pointer(cArrays.bytes), len(bytes))) diff --git a/third_party/mojo/src/mojo/public/go/system/mojo_types.go b/third_party/mojo/src/mojo/public/go/system/mojo_types.go index 9ed47b0..afb9df3 100644 --- a/third_party/mojo/src/mojo/public/go/system/mojo_types.go +++ b/third_party/mojo/src/mojo/public/go/system/mojo_types.go @@ -36,43 +36,43 @@ const ( MOJO_DEADLINE_INDEFINITE MojoDeadline = math.MaxUint64 MOJO_HANDLE_INVALID MojoHandle = 0 MOJO_RESULT_OK MojoResult = 0 - MOJO_RESULT_CANCELLED = -1 - MOJO_RESULT_UNKNOWN = -2 - MOJO_RESULT_INVALID_ARGUMENT = -3 - MOJO_RESULT_DEADLINE_EXCEEDED = -4 - MOJO_RESULT_NOT_FOUND = -5 - MOJO_RESULT_ALREADY_EXISTS = -6 - MOJO_RESULT_PERMISSION_DENIED = -7 - MOJO_RESULT_RESOURCE_EXHAUSTED = -8 - MOJO_RESULT_FAILED_PRECONDITION = -9 - MOJO_RESULT_ABORTED = -10 - MOJO_RESULT_OUT_OF_RANGE = -11 - MOJO_RESULT_UNIMPLEMENTED = -12 - MOJO_RESULT_INTERNAL = -13 - MOJO_RESULT_UNAVAILABLE = -14 - MOJO_RESULT_DATA_LOSS = -15 - MOJO_RESULT_BUSY = -16 - MOJO_RESULT_SHOULD_WAIT = -17 + MOJO_RESULT_CANCELLED MojoResult = -1 + MOJO_RESULT_UNKNOWN MojoResult = -2 + MOJO_RESULT_INVALID_ARGUMENT MojoResult = -3 + MOJO_RESULT_DEADLINE_EXCEEDED MojoResult = -4 + MOJO_RESULT_NOT_FOUND MojoResult = -5 + MOJO_RESULT_ALREADY_EXISTS MojoResult = -6 + MOJO_RESULT_PERMISSION_DENIED MojoResult = -7 + MOJO_RESULT_RESOURCE_EXHAUSTED MojoResult = -8 + MOJO_RESULT_FAILED_PRECONDITION MojoResult = -9 + MOJO_RESULT_ABORTED MojoResult = -10 + MOJO_RESULT_OUT_OF_RANGE MojoResult = -11 + MOJO_RESULT_UNIMPLEMENTED MojoResult = -12 + MOJO_RESULT_INTERNAL MojoResult = -13 + MOJO_RESULT_UNAVAILABLE MojoResult = -14 + MOJO_RESULT_DATA_LOSS MojoResult = -15 + MOJO_RESULT_BUSY MojoResult = -16 + MOJO_RESULT_SHOULD_WAIT MojoResult = -17 MOJO_HANDLE_SIGNAL_NONE MojoHandleSignals = 0 - MOJO_HANDLE_SIGNAL_READABLE = 1 << 0 - MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1 - MOJO_HANDLE_SIGNAL_PEER_CLOSED = 1 << 2 + MOJO_HANDLE_SIGNAL_READABLE MojoHandleSignals = 1 << 0 + MOJO_HANDLE_SIGNAL_WRITABLE MojoHandleSignals = 1 << 1 + MOJO_HANDLE_SIGNAL_PEER_CLOSED MojoHandleSignals = 1 << 2 MOJO_WRITE_MESSAGE_FLAG_NONE MojoWriteMessageFlags = 0 MOJO_READ_MESSAGE_FLAG_NONE MojoReadMessageFlags = 0 - MOJO_READ_MESSAGE_FLAG_MAY_DISCARD = 1 << 0 + MOJO_READ_MESSAGE_FLAG_MAY_DISCARD MojoReadMessageFlags = 1 << 0 MOJO_READ_DATA_FLAG_NONE MojoReadDataFlags = 0 - MOJO_READ_DATA_FLAG_ALL_OR_NONE = 1 << 0 - MOJO_READ_DATA_FLAG_DISCARD = 1 << 1 - MOJO_READ_DATA_FLAG_QUERY = 1 << 2 - MOJO_READ_DATA_FLAG_PEEK = 1 << 3 + MOJO_READ_DATA_FLAG_ALL_OR_NONE MojoReadDataFlags = 1 << 0 + MOJO_READ_DATA_FLAG_DISCARD MojoReadDataFlags = 1 << 1 + MOJO_READ_DATA_FLAG_QUERY MojoReadDataFlags = 1 << 2 + MOJO_READ_DATA_FLAG_PEEK MojoReadDataFlags = 1 << 3 MOJO_WRITE_DATA_FLAG_NONE MojoWriteDataFlags = 0 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE MojoWriteDataFlags = 1 << 0 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE MojoCreateDataPipeOptionsFlags = 0 - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD = 1 << 0 + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD MojoCreateDataPipeOptionsFlags = 1 << 0 MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE MojoCreateMessagePipeOptionsFlags = 0 MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE MojoCreateSharedBufferOptionsFlags = 0 diff --git a/third_party/mojo/src/mojo/public/go/system/shared_buffer.go b/third_party/mojo/src/mojo/public/go/system/shared_buffer.go index a8bdbfa..927c7ea 100644 --- a/third_party/mojo/src/mojo/public/go/system/shared_buffer.go +++ b/third_party/mojo/src/mojo/public/go/system/shared_buffer.go @@ -31,6 +31,9 @@ type sharedBuffer struct { } func (h *sharedBuffer) DuplicateBufferHandle(opts *DuplicateBufferHandleOptions) (MojoResult, SharedBufferHandle) { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cParams := C.MallocDuplicateBufferHandleParams() defer C.FreeDuplicateBufferHandleParams(cParams) result := C.MojoDuplicateBufferHandle(h.mojoHandle.cValue(), opts.cValue(cParams.opts), cParams.duplicate) @@ -38,6 +41,9 @@ func (h *sharedBuffer) DuplicateBufferHandle(opts *DuplicateBufferHandleOptions) } func (h *sharedBuffer) MapBuffer(offset uint64, numBytes int, flags MojoMapBufferFlags) (MojoResult, []byte) { + h.core.mu.Lock() + defer h.core.mu.Unlock() + cParams := C.MallocMapBufferParams() defer C.FreeMapBufferParams(cParams) result := C.MojoMapBuffer(h.mojoHandle.cValue(), C.uint64_t(offset), C.uint64_t(numBytes), cParams.buffer, flags.cValue()) @@ -48,5 +54,8 @@ func (h *sharedBuffer) MapBuffer(offset uint64, numBytes int, flags MojoMapBuffe } func (h *sharedBuffer) UnmapBuffer(buffer []byte) MojoResult { + h.core.mu.Lock() + defer h.core.mu.Unlock() + return MojoResult(C.MojoUnmapBuffer(unsafe.Pointer(&buffer[0]))) } diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn index 2b99728..f68b113 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/BUILD.gn @@ -19,6 +19,7 @@ mojom("test_interfaces") { "sample_service.mojom", "serialization_test_structs.mojom", "test_structs.mojom", + "test_unions.mojom", "validation_test_interfaces.mojom", ] } diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom index 5f50ccd..eae8ce6 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_unions.mojom @@ -17,9 +17,9 @@ union PodUnion { float f_float; double f_double; bool f_bool; - string f_string; }; -struct SomeStruct { +union ObjectUnion { + int8 f_int8; string f_string; }; diff --git a/third_party/mojo/src/mojo/public/js/connection.js b/third_party/mojo/src/mojo/public/js/connection.js index 223e711..4a7a8b8 100644 --- a/third_party/mojo/src/mojo/public/js/connection.js +++ b/third_party/mojo/src/mojo/public/js/connection.js @@ -140,10 +140,13 @@ define("mojo/public/js/connection", [ } // Return a handle for a message pipe that's connected to a stub for - // localInterface. The stub delegates to impl. Used by generated code for - // outgoing interface parameters: the caller specifies impl, and the generated - // code sends the handle returned by this function. - function bindImpl(impl, localInterface) { + // localInterface. Used by generated code for outgoing interface + // parameters: the caller is given the generated stub via + // |stubCallback(stub)| and the generated code sends the handle + // returned by this function. The caller is responsible for managing + // the lifetime of the stub and for setting it's implementation + // delegate with: StubBindings(stub).delegate = myImpl; + function bindImpl(stubCallback, localInterface) { var messagePipe = core.createMessagePipe(); if (messagePipe.result != core.RESULT_OK) throw new Error("createMessagePipe failed " + messagePipe.result); @@ -152,8 +155,8 @@ define("mojo/public/js/connection", [ var router = new Router(messagePipe.handle0); var connection = new BaseConnection(stub, undefined, router); StubBindings(stub).connection = connection; - if (impl) - StubBindings(stub).delegate = impl; + if (stubCallback) + stubCallback(stub); return messagePipe.handle1; } diff --git a/third_party/mojo/src/mojo/public/mojo_application.gni b/third_party/mojo/src/mojo/public/mojo_application.gni index 19abf74..7661c88 100644 --- a/third_party/mojo/src/mojo/public/mojo_application.gni +++ b/third_party/mojo/src/mojo/public/mojo_application.gni @@ -74,16 +74,14 @@ template("mojo_native_application") { } # Copy the prebuilt mojo_shell if using it. - if (defined(invoker.datadeps)) { - datadeps = invoker.datadeps + if (defined(invoker.data_deps)) { + data_deps = invoker.data_deps if (use_prebuilt_mojo_shell) { - datadeps += [ copy_mojo_shell ] + data_deps += [ copy_mojo_shell ] } } else { if (use_prebuilt_mojo_shell) { - datadeps = [ - copy_mojo_shell, - ] + data_deps = [ copy_mojo_shell ] } } deps = rebase_path([ diff --git a/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py b/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py index 7b8edf6..35b8ff2 100644 --- a/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py +++ b/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py @@ -146,7 +146,6 @@ class MojoInterfaceType(type): class MyInterface(object): __metaclass__ = MojoInterfaceType DESCRIPTOR = { - 'client': MyInterfaceClient, 'methods': [ { 'name': 'FireAndForget', @@ -181,13 +180,10 @@ class MojoInterfaceType(type): methods = [_MethodDescriptor(x) for x in descriptor.get('methods', [])] for method in methods: dictionary[method.name] = _NotImplemented - client_class_getter = descriptor.get('client', None) fully_qualified_name = descriptor['fully_qualified_name'] - interface_manager = InterfaceManager(fully_qualified_name, methods, - client_class_getter) + interface_manager = InterfaceManager(fully_qualified_name, methods) dictionary.update({ - 'client': None, 'manager': None, '_interface_manager': interface_manager, }) @@ -244,24 +240,13 @@ class InterfaceManager(object): over a pipe. """ - def __init__(self, name, methods, client_class_getter): + def __init__(self, name, methods): self.name = name self.methods = methods self.interface_class = None - self._client_class_getter = client_class_getter - self._client_manager = None - self._client_manager_computed = False self._proxy_class = None self._stub_class = None - @property - def client_manager(self): - if not self._client_manager_computed: - self._client_manager_computed = True - if self._client_class_getter: - self._client_manager = self._client_class_getter().manager - return self._client_manager - def Proxy(self, handle): router = messaging.Router(handle) error_handler = _ProxyErrorHandler() @@ -282,9 +267,6 @@ class InterfaceManager(object): retainer.release() error_handler.AddCallback(Cleanup) - if self.client_manager: - impl.client = self.client_manager._InternalProxy(router, error_handler) - # Give an instance manager to the implementation to allow it to close # the connection. impl.manager = InstanceManager(router, error_handler) @@ -292,15 +274,14 @@ class InterfaceManager(object): router.Start() def _InternalProxy(self, router, error_handler): + if error_handler is None: + error_handler = _ProxyErrorHandler() + if not self._proxy_class: dictionary = { '__module__': __name__, '__init__': _ProxyInit, } - if self.client_manager: - dictionary['client'] = property(_ProxyGetClient, _ProxySetClient) - dictionary['manager'] = None - dictionary['_client_manager'] = self.client_manager for method in self.methods: dictionary[method.name] = _ProxyMethodCall(method) self._proxy_class = type('%sProxy' % self.name, @@ -335,15 +316,18 @@ class InstanceManager(object): def __init__(self, router, error_handler): self._router = router self._error_handler = error_handler + assert self._error_handler is not None def Close(self): + self._error_handler.OnClose() self._router.Close() def PassMessagePipe(self): + self._error_handler.OnClose() return self._router.PassMessagePipe() def AddOnErrorCallback(self, callback): - self._error_handler.AddCallback(lambda _: callback()) + self._error_handler.AddCallback(lambda _: callback(), False) class _MethodDescriptor(object): @@ -373,21 +357,32 @@ def _ConstructParameterStruct(descriptor, name, suffix): class _ProxyErrorHandler(messaging.ConnectionErrorHandler): def __init__(self): messaging.ConnectionErrorHandler.__init__(self) - self._callbacks = set() + self._callbacks = dict() def OnError(self, result): + if self._callbacks is None: + return exception = messaging.MessagingException('Mojo error: %d' % result) - for callback in list(self._callbacks): + for (callback, _) in self._callbacks.iteritems(): callback(exception) self._callbacks = None - def AddCallback(self, callback): + def OnClose(self): + if self._callbacks is None: + return + exception = messaging.MessagingException('Router has been closed.') + for (callback, call_on_close) in self._callbacks.iteritems(): + if call_on_close: + callback(exception) + self._callbacks = None + + def AddCallback(self, callback, call_on_close=True): if self._callbacks is not None: - self._callbacks.add(callback) + self._callbacks[callback] = call_on_close def RemoveCallback(self, callback): if self._callbacks: - self._callbacks.remove(callback) + del self._callbacks[callback] class _Retainer(object): @@ -457,19 +452,6 @@ def _StructNe(self, other): def _ProxyInit(self, router, error_handler): self._router = router self._error_handler = error_handler - self._client = None - - -# pylint: disable=W0212 -def _ProxyGetClient(self): - return self._client - - -# pylint: disable=W0212 -def _ProxySetClient(self, client): - self._client = client - stub = self._client_manager._Stub(client) - self._router.SetIncomingMessageReceiver(stub) # pylint: disable=W0212 diff --git a/third_party/mojo/src/mojo/public/tools/BUILD.gn b/third_party/mojo/src/mojo/public/tools/BUILD.gn index 12cca6d..103c259 100644 --- a/third_party/mojo/src/mojo/public/tools/BUILD.gn +++ b/third_party/mojo/src/mojo/public/tools/BUILD.gn @@ -10,11 +10,20 @@ if (use_prebuilt_mojo_shell) { if (is_win) { filename += ".exe" } + if (is_android) { + filename = "MojoShell.apk" + } sources = [ "prebuilt/$filename", ] - outputs = [ - "$root_out_dir/$filename", - ] + if (is_android) { + outputs = [ + "$root_out_dir/apks/$filename", + ] + } else { + outputs = [ + "$root_out_dir/$filename", + ] + } } } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl index 116e86a..d9a398a 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl @@ -32,6 +32,11 @@ namespace {{namespace}} { class {{struct.name}}; {%- endfor %} +{#--- Wrapper forward declarations for unions #} +{% for union in unions %} +class {{union.name}}; +{%- endfor %} + namespace internal { {#--- Internal forward declarations #} @@ -39,6 +44,10 @@ namespace internal { class {{struct.name}}_Data; {%- endfor %} +{% for union in unions %} +class {{union.name}}_Data; +{%- endfor %} + #pragma pack(push, 1) {#--- Class declarations #} @@ -46,6 +55,10 @@ class {{struct.name}}_Data; {% include "struct_declaration.tmpl" %} {%- endfor %} +{% for union in unions %} +{% include "union_declaration.tmpl" %} +{%- endfor %} + #pragma pack(pop) } // namespace internal diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl index 1ddcc45..863d18f 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl @@ -8,6 +8,7 @@ #elif defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4056) +#pragma warning(disable:4065) #pragma warning(disable:4756) #endif @@ -63,6 +64,11 @@ const uint32_t {{method_name}} = {{method.ordinal}}; {%- include "struct_definition.tmpl" %} {%- endfor %} +{#--- Union definitions #} +{% for union in unions %} +{%- include "union_definition.tmpl" %} +{%- endfor %} + } // namespace internal {#--- Struct Constants #} @@ -77,6 +83,11 @@ const {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}} = {{cons {%- include "wrapper_class_definition.tmpl" %} {%- endfor %} +{#--- Union builder definitions #} +{%- for union in unions %} +{%- include "wrapper_union_class_definition.tmpl" %} +{%- endfor %} + {#--- Interface definitions #} {%- for interface in interfaces %} {%- include "interface_definition.tmpl" %} @@ -87,6 +98,11 @@ const {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}} = {{cons {%- include "struct_serialization_definition.tmpl" %} {%- endfor %} +{#--- Union Serialization Helpers #} +{%- for union in unions %} +{%- include "union_serialization_definition.tmpl" %} +{%- endfor %} + {%- for namespace in namespaces_as_array|reverse %} } // namespace {{namespace}} {%- endfor %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl index 25449b7..0312002 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl @@ -53,6 +53,16 @@ using {{struct.name}}Ptr = mojo::StructPtr<{{struct.name}}>; {% endif %} {% endfor %} +{#--- Union Forward Declarations -#} +{% for union in unions %} +class {{union.name}}; +{% if union|should_inline_union %} +typedef mojo::InlinedStructPtr<{{union.name}}> {{union.name}}Ptr; +{% else %} +typedef mojo::StructPtr<{{union.name}}> {{union.name}}Ptr; +{% endif %} +{%- endfor %} + {#--- NOTE: Non-inlined structs may have pointers to inlined structs, so we #} {#--- need to fully define inlined structs ahead of the others. #} @@ -70,6 +80,11 @@ using {{struct.name}}Ptr = mojo::StructPtr<{{struct.name}}>; {% endif %} {%- endfor %} +{#--- Unions #} +{% for union in unions %} +{% include "wrapper_union_class_declaration.tmpl" %} +{%- endfor %} + {#--- Interfaces -#} {% for interface in interfaces %} {% include "interface_declaration.tmpl" %} @@ -95,10 +110,18 @@ using {{struct.name}}Ptr = mojo::StructPtr<{{struct.name}}>; {% include "interface_response_validator_declaration.tmpl" %} {%- endfor %} +{%- import "serialization_macros.tmpl" as serialization_macros %} {#--- Struct Serialization Helpers -#} {% if structs %} {% for struct in structs %} -{% include "struct_serialization_declaration.tmpl" %} +{{ serialization_macros.declare_serialization(struct.name) }} +{%- endfor %} +{%- endif %} + +{#--- Union Serialization Helpers -#} +{% if unions %} +{% for union in unions %} +{{ serialization_macros.declare_serialization(union.name) }} {%- endfor %} {%- endif %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl index 5de77d3..0892b64 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl @@ -29,5 +29,5 @@ class {{class_name}} { header_.num_fields = {{struct.packed.packed_fields|length}}; } }; -static_assert(sizeof({{class_name}}) == {{struct.packed|struct_size}}, +static_assert(sizeof({{class_name}}) == {{struct.versions[-1].num_bytes}}, "Bad sizeof({{class_name}})"); diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/serialization_macros.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/serialization_macros.tmpl new file mode 100644 index 0000000..2be038c --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/serialization_macros.tmpl @@ -0,0 +1,7 @@ +{%- macro declare_serialization(name) %} +size_t GetSerializedSize_(const {{name}}Ptr& input); +void Serialize_({{name}}Ptr input, mojo::internal::Buffer* buffer, + internal::{{name}}_Data** output); +void Deserialize_(internal::{{name}}_Data* input, + {{name}}Ptr* output); +{%- endmacro %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl index 34c0f11..ee8934e 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl @@ -18,5 +18,5 @@ class {{class_name}} { {{class_name}}(); ~{{class_name}}() = delete; }; -static_assert(sizeof({{class_name}}) == {{struct.packed|struct_size}}, +static_assert(sizeof({{class_name}}) == {{struct.versions[-1].num_bytes}}, "Bad sizeof({{class_name}})"); diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl deleted file mode 100644 index 604be86..0000000 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -size_t GetSerializedSize_(const {{struct.name}}Ptr& input); -void Serialize_({{struct.name}}Ptr input, mojo::internal::Buffer* buffer, - internal::{{struct.name}}_Data** output); -void Deserialize_(internal::{{struct.name}}_Data* input, - {{struct.name}}Ptr* output); diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl new file mode 100644 index 0000000..6e6fe95 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl @@ -0,0 +1,50 @@ +{%- set class_name = union.name ~ "_Data" -%} +{%- set enum_name = union.name ~ "_Tag" -%} +{%- import "struct_macros.tmpl" as struct_macros %} + +class {{class_name}} { + public: + static {{class_name}}* New(mojo::internal::Buffer* buf); + + static bool Validate(const void* data, + mojo::internal::BoundsChecker* bounds_checker); + + enum class {{enum_name}} : uint32_t { +{% for field in union.fields %} + {{field.name|upper}}, +{%- endfor %} + }; + + // A note on layout: + // "Each non-static data member is allocated as if it were the sole member of + // a struct." - Section 9.5.2 ISO/IEC 14882:2011 (The C++ Spec) + union MOJO_ALIGNAS(8) Union_ { +{%- for field in union.fields %} +{%- if field.kind|is_string_kind %} + uint64_t f_{{field.name}}; +{%- elif field.kind.spec == 'b' %} + uint8_t f_{{field.name}} : 1; +{%- elif field.kind|is_enum_kind %} + int32_t f_{{field.name}}; +{%- else %} + {{field.kind|cpp_pod_type}} f_{{field.name}}; +{%- endif %} +{%- endfor %} + uint64_t unknown; + }; + + uint32_t reserved; + {{enum_name}} tag; + Union_ data; + + void EncodePointersAndHandles(std::vector<mojo::Handle>* handles); + void DecodePointersAndHandles(std::vector<mojo::Handle>* handles); + + private: + {{class_name}}(); + ~{{class_name}}() = delete; +}; +static_assert(sizeof({{class_name}}) == 16, + "Bad sizeof({{class_name}})"); +static_assert(sizeof({{class_name}}::Union_) == 8, + "Bad sizeof({{class_name}}::Union_)"); diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl new file mode 100644 index 0000000..9f6f02f --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl @@ -0,0 +1,54 @@ +{%- import "validation_macros.tmpl" as validation_macros %} +{%- set class_name = union.name ~ "_Data" %} +{%- set enum_name = union.name ~ "_Tag" -%} + +// static +{{class_name}}* {{class_name}}::New(mojo::internal::Buffer* buf) { + return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}(); +} + +// static +bool {{class_name}}::Validate(const void* data, + mojo::internal::BoundsChecker* bounds_checker) { + if (!data) { + return true; + } + + if (!mojo::internal::IsAligned(data)) { + ReportValidationError(mojo::internal::VALIDATION_ERROR_MISALIGNED_OBJECT); + return false; + } + + if (!bounds_checker->ClaimMemory(data, sizeof({{class_name}}))) { + ReportValidationError( + mojo::internal::VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + const {{class_name}}* object = static_cast<const {{class_name}}*>(data); + MOJO_ALLOW_UNUSED_LOCAL(object); + + switch (object->tag) { +{% for field in union.fields %} + case {{enum_name}}::{{field.name|upper}}: +{{ validation_macros.validate_union_field(field, union)|indent(6) }} +{%- endfor %} + default: + ReportValidationError( + mojo::internal::VALIDATION_ERROR_UNKOWN_UNION_TAG, + "unknown tag in {{union.name}}"); + return false; + } +} + +{{class_name}}::{{class_name}}() { +} + +void {{class_name}}::EncodePointersAndHandles( + std::vector<mojo::Handle>* handles) { + // TODO(azani): Implement pointers and handles. +} + +void {{class_name}}::DecodePointersAndHandles( + std::vector<mojo::Handle>* handles) { + // TODO(azani): Implement pointers and handles. +} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl index a29df07..8b82f7f 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl @@ -30,9 +30,10 @@ void Serialize_({{union.name}}Ptr input, mojo::internal::Buffer* buf, {% for field in union.fields %} case {{union.name}}::Tag::{{field.name|upper}}: {% if field.kind|is_string_kind %} - Serialize_(input_acc.data()->{{field.name}}, buf, &result->data.{{field.name}}.ptr); + {{field.kind|cpp_field_type}}* {{field.name}}_ptr = reinterpret_cast<{{field.kind|cpp_field_type}}*>(&result->data.f_{{field.name}}); + Serialize_(*(input_acc.data()->{{field.name}}), buf, &{{field.name}}_ptr->ptr); {% else %} - result->data.{{field.name}} = input_acc.data()->{{field.name}}; + result->data.f_{{field.name}} = input_acc.data()->{{field.name}}; {%- endif %} break; {%- endfor %} @@ -53,9 +54,10 @@ void Deserialize_(internal::{{union.name}}_Data* input, case {{union.name}}::Tag::{{field.name|upper}}: {% if field.kind|is_string_kind %} result_acc.SwitchActive({{union.name}}::Tag::{{field.name|upper}}); - Deserialize_(input->data.{{field.name}}.ptr, &result_acc.data()->{{field.name}}); + {{field.kind|cpp_field_type}}* {{field.name}}_ptr = reinterpret_cast<{{field.kind|cpp_field_type}}*>(&input->data.f_{{field.name}}); + Deserialize_({{field.name}}_ptr->ptr, result_acc.data()->{{field.name}}); {% else %} - result->set_{{field.name}}(input->data.{{field.name}}); + result->set_{{field.name}}(input->data.f_{{field.name}}); {%- endif %} break; {%- endfor %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl new file mode 100644 index 0000000..5a328f9 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/validation_macros.tmpl @@ -0,0 +1,43 @@ +{%- macro validate_not_null_ptr(field_expr, field, object_name) %} +if (!{{field_expr}}->offset) { + ReportValidationError( + mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + "null {{field.name}} field in {{object_name}}"); + return false; +} +{%- endmacro %} + +{%- macro validate_encoded_ptr(field_expr) %} +if (!mojo::internal::ValidateEncodedPointer(&{{field_expr}}->offset)) { + ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_POINTER); + return false; +} +{%- endmacro %} + +{%- macro validate_array_or_string(field_expr, field) -%} +if (!{{field.kind|cpp_wrapper_type}}::Data_::Validate< + {{field.kind|get_array_validate_params}}>( + mojo::internal::DecodePointerRaw(&{{field_expr}}->offset), + bounds_checker)) { + return false; +} +{%- endmacro %} + +{%- macro validate_union_field(field, union) %} +{%- set field_expr = "(reinterpret_cast<const " + ~ field.kind|cpp_field_type + ~ "*>(&object->data.f_" + ~ field.name + ~ "))" -%} +{%- if field.kind|is_object_kind -%} +{%- if not field.kind|is_nullable_kind -%} +{{ validate_not_null_ptr(field_expr, field, union.name) }} +{%- endif %} +{{ validate_encoded_ptr(field_expr) }} +{%- endif %} + +{%- if field.kind|is_array_kind or field.kind|is_string_kind -%} +{{ validate_array_or_string(field_expr, field) }} +{%- endif %} +return true; +{%- endmacro %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl index 0420c8d..107de09 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl @@ -39,7 +39,11 @@ class {{union.name}} { Union_() {} ~Union_() {} {% for field in union.fields %} +{% if field.kind|is_object_kind -%} + {{field.kind|cpp_wrapper_type}}* {{field.name}}; +{% else -%} {{field.kind|cpp_wrapper_type}} {{field.name}}; +{% endif -%} {%- endfor %} }; void SwitchActive(Tag new_active); diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl index bab528c..b5e9c23 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl @@ -21,7 +21,11 @@ switch (tag_) { {% for field in union.fields %} case Tag::{{field.name|upper}}: +{% if field.kind|is_object_kind %} + rv->set_{{field.name}}(*(data_.{{field.name}})); +{%- else %} rv->set_{{field.name}}(data_.{{field.name}}); +{%- endif %} break; {%- endfor %} }; @@ -37,7 +41,11 @@ bool {{union.name}}::Equals(const {{union.name}}& other) const { switch (tag_) { {% for field in union.fields %} case Tag::{{field.name|upper}}: - return mojo::internal::ValueTraits<{{field.kind|cpp_wrapper_type}}>::Equals(data_.{{field.name}}, other.get_{{field.name}}()); +{% if field.kind|is_object_kind %} + return mojo::internal::ValueTraits<{{field.kind|cpp_wrapper_type}}>::Equals(*(data_.{{field.name}}), *(other.data_.{{field.name}})); +{%- else %} + return mojo::internal::ValueTraits<{{field.kind|cpp_wrapper_type}}>::Equals(data_.{{field.name}}, other.data_.{{field.name}}); +{%- endif %} {%- endfor %} }; @@ -51,12 +59,20 @@ bool {{union.name}}::is_{{field.name}}() const { {{field.kind|cpp_result_type}} {{union.name}}::get_{{field.name}}() const { MOJO_DCHECK(tag_ == Tag::{{field.name|upper}}); +{% if field.kind|is_object_kind %} + return *(data_.{{field.name}}); +{%- else %} return data_.{{field.name}}; +{%- endif %} } void {{union.name}}::set_{{field.name}}({{field.kind|cpp_const_wrapper_type}} {{field.name}}) { SwitchActive(Tag::{{field.name|upper}}); +{% if field.kind|is_string_kind %} + *(data_.{{field.name}}) = {{field.name}}; +{%- else %} data_.{{field.name}} = {{field.name}}; +{%- endif %} } {%- endfor %} @@ -74,7 +90,7 @@ void {{union.name}}::SetActive(Tag new_active) { {% for field in union.fields %} case Tag::{{field.name|upper}}: {% if field.kind|is_string_kind %} - new (&data_.{{field.name}}) String(); + data_.{{field.name}} = new String(); {%- endif %} break; {%- endfor %} @@ -88,7 +104,7 @@ void {{union.name}}::DestroyActive() { {% for field in union.fields %} case Tag::{{field.name|upper}}: {% if field.kind|is_string_kind %} - data_.{{field.name}}.~String(); + delete data_.{{field.name}}; {%- endif %} break; {%- endfor %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl index f65298f..93a3e42 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl @@ -74,7 +74,7 @@ if (decoder{{level+1}} == null) { {%- macro struct_def(struct) %} class {{struct|name}} extends bindings.Struct { - static const int kStructSize = {{struct.packed|struct_size}}; + static const int kStructSize = {{struct.versions[-1].num_bytes}}; static const bindings.DataHeader kDefaultStructInfo = const bindings.DataHeader(kStructSize, {{struct.packed.packed_fields|length}}); diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/enum.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/enum.tmpl new file mode 100644 index 0000000..8bc882f --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/enum.tmpl @@ -0,0 +1,20 @@ +// Copyright 2015 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. + +{% macro define(enum) %} +type {{enum|name}} int32 + +const ( +{% for field in enum.fields %} +{% if field.value %} + {{enum|name}}_{{field|name}} = {{field.value|expression_to_text}} +{% elif loop.first %} + {{enum|name}}_{{field|name}} = 0 +{% else %} + {{enum|name}}_{{field|name}} = {{enum|name}}_{{enum.fields[loop.index0 - 1]|name}} + 1; +{% endif %} +{% endfor %} +) + +{% endmacro %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl new file mode 100644 index 0000000..484845d --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/interface.tmpl @@ -0,0 +1,14 @@ +// Copyright 2015 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. + +{% import "struct.tmpl" as struct_macros %} + +{% macro define(interface) %} +{% for method in interface.methods %} +{{struct_macros.define(method|struct_from_method, False)}} +{%- if method.response_parameters %} +{{struct_macros.define(method|response_struct_from_method, False)}} +{% endif %} +{% endfor %} +{% endmacro %}
\ No newline at end of file diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl index 8c58c4c..3769585 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl @@ -9,3 +9,33 @@ // package {{package}} + +import ( + "fmt" + + "mojo/public/go/bindings" + "mojo/public/go/system" +) + +var _ = fmt.Errorf +var _ = bindings.NewEncoder +var _ = system.GetCore + +{% import "enum.tmpl" as enum_macros %} +{% import "interface.tmpl" as interface_macros %} +{% import "struct.tmpl" as struct_macros %} + +{#- Enum definitions #} +{% for enum in enums %} +{{enum_macros.define(enum)}} +{%- endfor %} + +{#- Interface definitions #} +{% for interface in interfaces %} +{{interface_macros.define(interface)}} +{%- endfor %} + +{#- Struct definitions #} +{% for struct in structs %} +{{struct_macros.define(struct)}} +{%- endfor %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl new file mode 100644 index 0000000..eb6b121 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/struct.tmpl @@ -0,0 +1,219 @@ +// Copyright 2015 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. + +{% macro define(struct, exported=True) %} +type {{struct|name(exported)}} struct { +{% for packed_field in struct.packed.packed_fields %} + {{packed_field.field|name(exported)}} {{packed_field.field.kind|go_type}} +{% endfor %} +} + +func (s *{{struct|name(exported)}}) Encode(encoder *bindings.Encoder) error { + encoder.StartStruct({{struct.versions[-1].num_bytes}}, {{struct.packed.packed_fields|length}}) +{% for byte in struct.bytes %} +{% for packed_field in byte.packed_fields %} + {{encode('s.'~packed_field.field|name(exported), packed_field.field.kind)|tab_indent()}} +{% endfor %} +{% endfor %} + if err := encoder.Finish(); err != nil { + return err + } + return nil +} + +func (s *{{struct|name(exported)}}) Decode(decoder *bindings.Decoder) error { +{% if struct.bytes %} + numFields, err := decoder.StartStruct() +{% else %} + _, err := decoder.StartStruct() +{% endif %} + if err != nil { + return err + } +{% for byte in struct.bytes %} +{% for packed_field in byte.packed_fields %} + if numFields > {{packed_field.ordinal}} { + {{decode('s.'~packed_field.field|name(exported), packed_field.field.kind)|tab_indent(2)}} + } +{% endfor %} +{% endfor %} + if err := decoder.Finish(); err != nil { + return err + } + return nil +} + +{% endmacro %} + + + +{% macro encode(value, kind, level=0) %} +{% if kind|is_nullable %} +if {{value}} == nil { +{% if kind|is_handle %} + encoder.WriteInvalidHandle() +{% else %} + encoder.WriteNullPointer() +{% endif %} +} else { + {{encodeNonNullable('(*'~value~')', kind, level)|tab_indent()}} +} +{% else -%} +{{encodeNonNullable(value, kind, level)}} +{%- endif %} +{% endmacro %} + + + +{% macro encodeNonNullable(value, kind, level=0) %} +{% if kind|is_pointer %} +if err := encoder.WritePointer(); err != nil { + return err +} +{% endif %} +{% if kind|is_struct %} +if err := {{value}}.Encode(encoder); err != nil { + return err +} +{% elif kind|is_array %} +encoder.StartArray(uint32(len({{value}})), {{kind.kind|bit_size}}) +for _, elem{{level}} := range {{value}} { + {{encode('elem'~level, kind.kind, level+1)|tab_indent()}} +} +if err := encoder.Finish(); err != nil { + return err +} +{% elif kind|is_map %} +encoder.StartMap() +{ + var keys{{level}} {{kind.key_kind|array|go_type}} + var values{{level}} {{kind.value_kind|array|go_type}} + for key{{level}}, value{{level}} := range {{value}} { + keys{{level}} = append(keys{{level}}, key{{level}}) + values{{level}} = append(values{{level}}, value{{level}}) + } + {{encode('keys'~level, kind.key_kind|array, level+1)|tab_indent()}} + {{encode('values'~level, kind.value_kind|array, level+1)|tab_indent()}} +} +if err := encoder.Finish(); err != nil { + return err +} +{% elif kind|is_enum %} +if err := encoder.WriteInt32(int32({{value}})); err != nil { + return err +} +{% else %} +if err := encoder.Write{{kind|encode_suffix}}({{value}}); err != nil { + return err +} +{% endif %} +{% endmacro %} + + + +{% macro decode(value, kind, level=0) %} +{% if kind|is_pointer %} +pointer{{level}}, err := decoder.ReadPointer() +if err != nil { + return err +} +if pointer{{level}} == 0 { +{% if kind|is_nullable %} + {{value}} = nil +} else { + {{value}} = new({{kind|go_type(False)}}) + {{decodePointerValue('(*'~value~')', kind, level)|tab_indent()}} +} +{% else %} + return fmt.Errorf("unexpected null pointer") +} else { + {{decodePointerValue(value, kind, level)|tab_indent()}} +} +{% endif %} +{% elif kind|is_handle %} +handle{{level}}, err := decoder.Read{{kind|decode_suffix}}() +if err != nil { + return err +} +if handle{{level}}.IsValid() { + {{value}} = {% if kind|is_nullable %}&{% endif %}handle{{level}} +} else { +{% if kind|is_nullable %} + {{value}} = nil +{% else %} + return fmt.Errorf("unexpected invalid handle") +{% endif %} +} +{% elif kind|is_enum %} +value{{level}}, err := decoder.Read{{kind|decode_suffix}}() +if err != nil { + return err +} +{{value}} = {% if kind|is_nullable %}&{% endif %}{{kind|go_type(False)}}(value{{level}}) +{% else %} +value{{level}}, err := decoder.Read{{kind|decode_suffix}}() +if err != nil { + return err +} +{{value}} = {% if kind|is_nullable %}&{% endif %}value{{level}} +{% endif %} +{% endmacro %} + + + +{% macro decodePointerValue(value, kind, level=0) %} +{% if kind|is_struct %} +if err := {{value}}.Decode(decoder); err != nil { + return err +} +{% elif kind|is_array %} +len{{level}}, err := decoder.StartArray({{kind.kind|bit_size}}) +if err != nil { + return err +} +{% if kind.length %} +if len{{level}} != {{kind.length}} { + return fmt.Errorf("invalid array length: expected %d, got %d", {{kind.length}}, len{{level}}) +} +{% else %} +{{value}} = make({{kind|go_type(False)}}, len{{level}}) +{% endif %} +for i{{level}} := uint32(0); i{{level}} < len{{level}}; i{{level}}++ { + {{decode(value~'[i'~level~']', kind.kind, level+1)|tab_indent()}} +} +if err := decoder.Finish(); err != nil { + return err +} +{% elif kind|is_map %} +if err := decoder.StartMap(); err != nil { + return err +} +var keys{{level}} {{kind.key_kind|array|go_type}} +{ + {{decode('keys'~level, kind.key_kind|array, level+1)|tab_indent()}} +} +var values{{level}} {{kind.value_kind|array|go_type}} +{ + {{decode('values'~level, kind.value_kind|array, level+1)|tab_indent()}} +} +if len(keys{{level}}) != len(values{{level}}) { + return fmt.Errorf("Number of keys %d is different from number of values %d", len(keys{{level}}), len(values{{level}})) +} +if err := decoder.Finish(); err != nil { + return err +} +len{{level}} := len(keys{{level}}) +map{{level}} := make({{kind|go_type(False)}}) +for i{{level}} := 0; i{{level}} < len{{level}}; i{{level}}++ { + map{{level}}[keys{{level}}[i{{level}}]] = values{{level}}[i{{level}}] +} +{{value}} = map{{level}} +{% else %} +value{{level}}, err := decoder.Read{{kind|decode_suffix}}() +if err != nil { + return err +} +{{value}} = value{{level}} +{% endif %} +{% endmacro %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl index 0abdac4..333e0da 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/java_templates/struct_definition.tmpl @@ -110,7 +110,7 @@ if (decoder{{level+1}} == null) { {% macro struct_def(struct, inner_class=False) %} {{'static' if inner_class else 'public'}} final class {{struct|name}} extends org.chromium.mojo.bindings.Struct { - private static final int STRUCT_SIZE = {{struct.packed|struct_size}}; + private static final int STRUCT_SIZE = {{struct.versions[-1].num_bytes}}; private static final DataHeader DEFAULT_STRUCT_INFO = new DataHeader(STRUCT_SIZE, {{struct.packed.packed_fields|length}}); {% for constant in struct.constants %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 34bba30..8b7e219 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_cpp_generator.py @@ -283,6 +283,9 @@ def ShouldInlineStruct(struct): return False return True +def ShouldInlineUnion(union): + return not any(mojom.IsMoveOnlyKind(field.kind) for field in union.fields) + def GetArrayValidateParams(kind): if (not mojom.IsArrayKind(kind) and not mojom.IsMapKind(kind) and not mojom.IsStringKind(kind)): @@ -314,8 +317,6 @@ def GetMapValidateParams(value_kind): 'true' if element_is_nullable else 'false', GetArrayValidateParams(value_kind)) -_HEADER_SIZE = 8 - class Generator(generator.Generator): cpp_filters = { @@ -334,6 +335,7 @@ class Generator(generator.Generator): "get_pad": pack.GetPad, "has_callbacks": mojom.HasCallbacks, "should_inline": ShouldInlineStruct, + "should_inline_union": ShouldInlineUnion, "is_array_kind": mojom.IsArrayKind, "is_cloneable_kind": mojom.IsCloneableKind, "is_enum_kind": mojom.IsEnumKind, @@ -347,11 +349,13 @@ class Generator(generator.Generator): "is_string_kind": mojom.IsStringKind, "is_struct_kind": mojom.IsStructKind, "is_struct_with_handles": IsStructWithHandles, + "is_union_kind": mojom.IsUnionKind, "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE, "struct_from_method": generator.GetStructFromMethod, "response_struct_from_method": generator.GetResponseStructFromMethod, "stylize_method": generator.StudlyCapsToCamel, "to_all_caps": generator.CamelCaseToAllCaps, + "under_to_camel": generator.UnderToCamel, } def GetJinjaExports(self): @@ -363,6 +367,7 @@ class Generator(generator.Generator): "kinds": self.module.kinds, "enums": self.module.enums, "structs": self.GetStructs(), + "unions": self.module.unions, "interfaces": self.module.interfaces, } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py index d971b53..2b562f2 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py @@ -13,8 +13,6 @@ from mojom.generate.template_expander import UseJinja GENERATOR_PREFIX = 'dart' -_HEADER_SIZE = 8 - _kind_to_dart_default_value = { mojom.BOOL: "false", mojom.INT8: "0", @@ -209,14 +207,6 @@ def GetNameForElement(element): def GetInterfaceResponseName(method): return UpperCamelCase(method.name + 'Response') -def GetResponseStructFromMethod(method): - return generator.GetDataHeader( - False, generator.GetResponseStructFromMethod(method)) - -def GetStructFromMethod(method): - return generator.GetDataHeader( - False, generator.GetStructFromMethod(method)) - def GetDartTrueFalse(value): return 'true' if value else 'false' @@ -379,9 +369,8 @@ class Generator(generator.Generator): 'dart_type': DartDeclType, 'name': GetNameForElement, 'interface_response_name': GetInterfaceResponseName, - 'response_struct_from_method': GetResponseStructFromMethod, - 'struct_from_method': GetStructFromMethod, - 'struct_size': lambda ps: ps.GetTotalSize() + _HEADER_SIZE, + 'response_struct_from_method': generator.GetResponseStructFromMethod, + 'struct_from_method': generator.GetStructFromMethod, } def GetParameters(self): diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py index 3f7c938..1196276 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py @@ -4,12 +4,148 @@ '''Generates Go source files from a mojom.Module.''' +from itertools import chain import os +import re from mojom.generate.template_expander import UseJinja import mojom.generate.generator as generator import mojom.generate.module as mojom +import mojom.generate.pack as pack + +class KindInfo(object): + def __init__(self, go_type, encode_suffix, decode_suffix, bit_size): + self.go_type = go_type + self.encode_suffix = encode_suffix + self.decode_suffix = decode_suffix + self.bit_size = bit_size + +_kind_infos = { + mojom.BOOL: KindInfo('bool', 'Bool', 'Bool', 1), + mojom.INT8: KindInfo('int8', 'Int8', 'Int8', 8), + mojom.UINT8: KindInfo('uint8', 'Uint8', 'Uint8', 8), + mojom.INT16: KindInfo('int16', 'Int16', 'Int16', 16), + mojom.UINT16: KindInfo('uint16', 'Uint16', 'Uint16', 16), + mojom.INT32: KindInfo('int32', 'Int32', 'Int32', 32), + mojom.UINT32: KindInfo('uint32', 'Uint32', 'Uint32', 32), + mojom.FLOAT: KindInfo('float32', 'Float32', 'Float32', 32), + mojom.HANDLE: KindInfo( + 'system.Handle', 'Handle', 'Handle', 32), + mojom.DCPIPE: KindInfo( + 'system.ConsumerHandle', 'Handle', 'ConsumerHandle', 32), + mojom.DPPIPE: KindInfo( + 'system.ProducerHandle', 'Handle', 'ProducerHandle', 32), + mojom.MSGPIPE: KindInfo( + 'system.MessagePipeHandle', 'Handle', 'MessagePipeHandle', 32), + mojom.SHAREDBUFFER: KindInfo( + 'system.SharedBufferHandle', 'Handle', 'SharedBufferHandle', 32), + mojom.NULLABLE_HANDLE: KindInfo( + 'system.Handle', 'Handle', 'Handle', 32), + mojom.NULLABLE_DCPIPE: KindInfo( + 'system.ConsumerHandle', 'Handle', 'ConsumerHandle', 32), + mojom.NULLABLE_DPPIPE: KindInfo( + 'system.ProducerHandle', 'Handle', 'ProducerHandle', 32), + mojom.NULLABLE_MSGPIPE: KindInfo( + 'system.MessagePipeHandle', 'Handle', 'MessagePipeHandle', 32), + mojom.NULLABLE_SHAREDBUFFER: KindInfo( + 'system.SharedBufferHandle', 'Handle', 'SharedBufferHandle', 32), + mojom.INT64: KindInfo('int64', 'Int64', 'Int64', 64), + mojom.UINT64: KindInfo('uint64', 'Uint64', 'Uint64', 64), + mojom.DOUBLE: KindInfo('float64', 'Float64', 'Float64', 64), + mojom.STRING: KindInfo('string', 'String', 'String', 64), + mojom.NULLABLE_STRING: KindInfo('string', 'String', 'String', 64), +} + +def GetBitSize(kind): + if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct)): + return 64 + if isinstance(kind, (mojom.InterfaceRequest, mojom.Interface)): + kind = mojom.MSGPIPE + if isinstance(kind, mojom.Enum): + kind = mojom.INT32 + return _kind_infos[kind].bit_size + +def GetGoType(kind, nullable = True): + if nullable and mojom.IsNullableKind(kind): + return '*%s' % GetNonNullableGoType(kind) + return GetNonNullableGoType(kind) + +def GetNonNullableGoType(kind): + if mojom.IsStructKind(kind): + return '%s' % FormatName(kind.name) + if mojom.IsArrayKind(kind): + if kind.length: + return '[%s]%s' % (kind.length, GetGoType(kind.kind)) + return '[]%s' % GetGoType(kind.kind) + if mojom.IsMapKind(kind): + return 'map[%s]%s' % (GetGoType(kind.key_kind), GetGoType(kind.value_kind)) + if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): + return GetGoType(mojom.MSGPIPE) + if mojom.IsEnumKind(kind): + return GetNameForNestedElement(kind) + return _kind_infos[kind].go_type + +def NameToComponent(name): + # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> + # HTTP_Entry2_FooBar) + name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) + # insert '_' between non upper and start of upper blocks (e.g., + # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) + name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) + return [x.lower() for x in name.split('_')] + +def UpperCamelCase(name): + return ''.join([x.capitalize() for x in NameToComponent(name)]) + +def FormatName(name, exported=True): + if exported: + return UpperCamelCase(name) + # Leave '_' symbols for unexported names. + return name[0].lower() + name[1:] + +def GetNameForNestedElement(element): + if element.parent_kind: + return "%s_%s" % (GetNameForElement(element.parent_kind), + FormatName(element.name)) + return FormatName(element.name) + +def GetNameForElement(element, exported=True): + if (mojom.IsInterfaceKind(element) or mojom.IsStructKind(element) or + isinstance(element, (mojom.EnumField, + mojom.Field, + mojom.Method, + mojom.Parameter))): + return FormatName(element.name, exported) + if isinstance(element, (mojom.Enum, + mojom.Constant, + mojom.ConstantValue)): + return GetNameForNestedElement(element) + raise Exception('Unexpected element: %s' % element) + +def ExpressionToText(token): + if isinstance(token, mojom.EnumValue): + return "%s_%s" % (GetNameForNestedElement(token.enum), + FormatName(token.name, True)) + if isinstance(token, mojom.ConstantValue): + return GetNameForNestedElement(token) + if isinstance(token, mojom.Constant): + return ExpressionToText(token.value) + return token + +def DecodeSuffix(kind): + if mojom.IsEnumKind(kind): + return DecodeSuffix(mojom.INT32) + if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): + return DecodeSuffix(mojom.MSGPIPE) + return _kind_infos[kind].decode_suffix + +def EncodeSuffix(kind): + if mojom.IsEnumKind(kind): + return EncodeSuffix(mojom.INT32) + if mojom.IsInterfaceKind(kind) or mojom.IsInterfaceRequestKind(kind): + return EncodeSuffix(mojom.MSGPIPE) + return _kind_infos[kind].encode_suffix def GetPackage(module): if module.namespace: @@ -22,12 +158,63 @@ def GetPackagePath(module): path = os.path.join(path, i) return path +def GetStructFromMethod(method): + params_class = "%s_%s_Params" % (GetNameForElement(method.interface), + GetNameForElement(method)) + struct = mojom.Struct(params_class, module=method.interface.module) + for param in method.parameters: + struct.AddField("in%s" % GetNameForElement(param), + param.kind, param.ordinal) + struct.packed = pack.PackedStruct(struct) + struct.bytes = pack.GetByteLayout(struct.packed) + struct.versions = pack.GetVersionInfo(struct.packed) + return struct + +def GetResponseStructFromMethod(method): + params_class = "%s_%s_ResponseParams" % (GetNameForElement(method.interface), + GetNameForElement(method)) + struct = mojom.Struct(params_class, module=method.interface.module) + for param in method.response_parameters: + struct.AddField("out%s" % GetNameForElement(param), + param.kind, param.ordinal) + struct.packed = pack.PackedStruct(struct) + struct.bytes = pack.GetByteLayout(struct.packed) + struct.versions = pack.GetVersionInfo(struct.packed) + return struct + class Generator(generator.Generator): - go_filters = {} + go_filters = { + 'array': lambda kind: mojom.Array(kind), + 'bit_size': GetBitSize, + 'decode_suffix': DecodeSuffix, + 'encode_suffix': EncodeSuffix, + 'go_type': GetGoType, + 'expression_to_text': ExpressionToText, + 'is_array': mojom.IsArrayKind, + 'is_enum': mojom.IsEnumKind, + 'is_handle': mojom.IsAnyHandleKind, + 'is_map': mojom.IsMapKind, + 'is_none_or_empty': lambda array: array == None or len(array) == 0, + 'is_nullable': mojom.IsNullableKind, + 'is_pointer': mojom.IsObjectKind, + 'is_struct': mojom.IsStructKind, + 'name': GetNameForElement, + 'response_struct_from_method': GetResponseStructFromMethod, + 'struct_from_method': GetStructFromMethod, + 'tab_indent': lambda s, size = 1: ('\n' + '\t' * size).join(s.splitlines()) + } + + def GetAllEnums(self): + data = [self.module] + self.GetStructs() + self.module.interfaces + enums = [x.enums for x in data] + return [i for i in chain.from_iterable(enums)] def GetParameters(self): return { + 'enums': self.GetAllEnums(), + 'interfaces': self.module.interfaces, 'package': GetPackage(self.module), + 'structs': self.GetStructs(), } @UseJinja('go_templates/source.tmpl', filters=go_filters) diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py index ad8980d..f279ef8 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py @@ -23,8 +23,6 @@ from mojom.generate.template_expander import UseJinja GENERATOR_PREFIX = 'java' -_HEADER_SIZE = 8 - _spec_to_java_type = { mojom.BOOL.spec: 'boolean', mojom.DCPIPE.spec: 'org.chromium.mojo.system.DataPipe.ConsumerHandle', @@ -348,14 +346,6 @@ def IsPointerArrayKind(kind): sub_kind = kind.kind return mojom.IsObjectKind(sub_kind) -def GetResponseStructFromMethod(method): - return generator.GetDataHeader( - False, generator.GetResponseStructFromMethod(method)) - -def GetStructFromMethod(method): - return generator.GetDataHeader( - False, generator.GetStructFromMethod(method)) - def GetConstantsMainEntityName(module): if module.attributes and 'JavaConstantsClassName' in module.attributes: return ParseStringAttribute(module.attributes['JavaConstantsClassName']) @@ -420,9 +410,8 @@ class Generator(generator.Generator): 'method_ordinal_name': GetMethodOrdinalName, 'name': GetNameForElement, 'new_array': NewArray, - 'response_struct_from_method': GetResponseStructFromMethod, - 'struct_from_method': GetStructFromMethod, - 'struct_size': lambda ps: ps.GetTotalSize() + _HEADER_SIZE, + 'response_struct_from_method': generator.GetResponseStructFromMethod, + 'struct_from_method': generator.GetStructFromMethod, } def GetJinjaExports(self): diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py index f8a7057..d4d4ed7 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_python_generator.py @@ -191,14 +191,6 @@ def GetFieldGroup(byte): assert len(byte.packed_fields) == 1 return GetFieldDescriptor(byte.packed_fields[0]) -def GetResponseStructFromMethod(method): - return generator.GetDataHeader( - False, generator.GetResponseStructFromMethod(method)) - -def GetStructFromMethod(method): - return generator.GetDataHeader( - False, generator.GetStructFromMethod(method)) - def ComputeStaticValues(module): in_progress = set() computed = set() @@ -287,8 +279,8 @@ class Generator(generator.Generator): 'field_group': GetFieldGroup, 'fully_qualified_name': GetFullyQualifiedName, 'name': GetNameForElement, - 'response_struct_from_method': GetResponseStructFromMethod, - 'struct_from_method': GetStructFromMethod, + 'response_struct_from_method': generator.GetResponseStructFromMethod, + 'struct_from_method': generator.GetStructFromMethod, } @UseJinja('python_templates/module.py.tmpl', filters=python_filters) @@ -296,7 +288,7 @@ class Generator(generator.Generator): return { 'enums': self.module.enums, 'imports': self.GetImports(), - 'interfaces': self.GetQualifiedInterfaces(), + 'interfaces': self.module.interfaces, 'module': ComputeStaticValues(self.module), 'namespace': self.module.namespace, 'structs': self.GetStructs(), @@ -312,26 +304,6 @@ class Generator(generator.Generator): each['python_module'] = MojomToPythonImport(each['module_name']) return self.module.imports - def GetQualifiedInterfaces(self): - """ - Returns the list of interfaces of the module. Each interface that has a - client will have a reference to the representation of the client interface - in the 'qualified_client' field. - """ - interfaces = self.module.interfaces - all_interfaces = [] + interfaces - for each in self.GetImports(): - all_interfaces += [data.KindFromImport(x, each) for x in - each['module'].interfaces]; - interfaces_by_name = dict((x.name, x) for x in all_interfaces) - for interface in interfaces: - if interface.client: - assert interface.client in interfaces_by_name, ( - 'Unable to find interface %s declared as client of %s.' % - (interface.client, interface.name)) - interface.qualified_client = interfaces_by_name[interface.client] - return sorted(interfaces, key=lambda i: (bool(i.client), i.name)) - def GetJinjaParameters(self): return { 'lstrip_blocks': True, diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl index 1e9f0bd..a475a58 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/python_templates/module.py.tmpl @@ -36,9 +36,6 @@ class {{struct|name}}(object): class {{interface|name}}(object): __metaclass__ = _reflection.MojoInterfaceType DESCRIPTOR = { -{% if interface.client %} - 'client': lambda: {{interface.qualified_client|fully_qualified_name}}, -{% endif %} 'fully_qualified_name': '{% if namespace %}{{namespace|replace(".","::")}}::{% endif %}{{interface|fully_qualified_name|replace(".","::")}}', 'methods': [ {% for method in interface.methods %} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni index 3e0ca4f..3b2874f 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni +++ b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni @@ -61,19 +61,28 @@ template("mojom") { "$generator_root/generators/cpp_templates/module.h.tmpl", "$generator_root/generators/cpp_templates/module-internal.h.tmpl", "$generator_root/generators/cpp_templates/params_definition.tmpl", + "$generator_root/generators/cpp_templates/serialization_macros.tmpl", "$generator_root/generators/cpp_templates/struct_declaration.tmpl", "$generator_root/generators/cpp_templates/struct_definition.tmpl", - "$generator_root/generators/cpp_templates/struct_serialization_declaration.tmpl", "$generator_root/generators/cpp_templates/struct_serialization_definition.tmpl", "$generator_root/generators/cpp_templates/struct_macros.tmpl", "$generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl", "$generator_root/generators/cpp_templates/wrapper_class_definition.tmpl", + "$generator_root/generators/cpp_templates/union_declaration.tmpl", + "$generator_root/generators/cpp_templates/union_definition.tmpl", + "$generator_root/generators/cpp_templates/union_serialization_definition.tmpl", + "$generator_root/generators/cpp_templates/validation_macros.tmpl", + "$generator_root/generators/cpp_templates/wrapper_union_class_declaration.tmpl", + "$generator_root/generators/cpp_templates/wrapper_union_class_definition.tmpl", "$generator_root/generators/dart_templates/enum_definition.tmpl", "$generator_root/generators/dart_templates/interface_definition.tmpl", "$generator_root/generators/dart_templates/module.lib.tmpl", "$generator_root/generators/dart_templates/module_definition.tmpl", "$generator_root/generators/dart_templates/struct_definition.tmpl", + "$generator_root/generators/go_templates/enum.tmpl", + "$generator_root/generators/go_templates/interface.tmpl", "$generator_root/generators/go_templates/source.tmpl", + "$generator_root/generators/go_templates/struct.tmpl", "$generator_root/generators/java_templates/constant_definition.tmpl", "$generator_root/generators/java_templates/constants.java.tmpl", "$generator_root/generators/java_templates/enum.java.tmpl", diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py index 3a41593..3d0ac2e 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py @@ -364,6 +364,7 @@ def ConstantFromData(module, data, parent_kind): scope = (module.namespace, ) # TODO(mpcomplete): maybe we should only support POD kinds. constant.kind = KindFromData(module.kinds, data['kind'], scope) + constant.parent_kind = parent_kind constant.value = FixupExpression(module, data.get('value'), scope, None) value = mojom.ConstantValue(module, parent_kind, constant) @@ -409,7 +410,7 @@ def ModuleFromData(data): module.structs = map( lambda struct: StructFromData(module, struct), data['structs']) module.unions = map( - lambda union: UnionFromData(module, struct), data.get('unions', [])) + lambda union: UnionFromData(module, union), data.get('unions', [])) module.interfaces = map( lambda interface: InterfaceFromData(module, interface), data['interfaces']) diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py index 401c399..ffb64e7 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py @@ -12,14 +12,20 @@ import module as mojom import mojom.fileutil as fileutil import pack +def _GetDataHeader(exported, struct): + struct.packed = pack.PackedStruct(struct) + struct.bytes = pack.GetByteLayout(struct.packed) + struct.versions = pack.GetVersionInfo(struct.packed) + struct.exported = exported + return struct + def GetStructFromMethod(method): """Converts a method's parameters into the fields of a struct.""" params_class = "%s_%s_Params" % (method.interface.name, method.name) struct = mojom.Struct(params_class, module=method.interface.module) for param in method.parameters: struct.AddField(param.name, param.kind, param.ordinal) - struct.packed = pack.PackedStruct(struct) - return struct + return _GetDataHeader(False, struct) def GetResponseStructFromMethod(method): """Converts a method's response_parameters into the fields of a struct.""" @@ -27,14 +33,7 @@ def GetResponseStructFromMethod(method): struct = mojom.Struct(params_class, module=method.interface.module) for param in method.response_parameters: struct.AddField(param.name, param.kind, param.ordinal) - struct.packed = pack.PackedStruct(struct) - return struct - -def GetDataHeader(exported, struct): - struct.packed = pack.PackedStruct(struct) - struct.bytes = pack.GetByteLayout(struct.packed) - struct.exported = exported - return struct + return _GetDataHeader(False, struct) def ExpectedArraySize(kind): if mojom.IsArrayKind(kind): @@ -48,6 +47,10 @@ def CamelCaseToAllCaps(camel_case): return '_'.join( word for word in re.split(r'([A-Z][^A-Z]+)', camel_case) if word).upper() +def UnderToCamel(under): + """Converts underscore_separated strings to CamelCase strings.""" + return ''.join(word.capitalize() for word in under.split('_')) + def WriteFile(contents, full_path): # Make sure the containing directory exists. full_dir = os.path.dirname(full_path) @@ -71,10 +74,10 @@ class Generator(object): result.append(GetStructFromMethod(method)) if method.response_parameters != None: result.append(GetResponseStructFromMethod(method)) - return map(partial(GetDataHeader, False), result) + return result def GetStructs(self): - return map(partial(GetDataHeader, True), self.module.structs) + return map(partial(_GetDataHeader, True), self.module.structs) # Prepend the filename with a directory that matches the directory of the # original .mojom file, relative to the import root. diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py index 8a0f56b..c2e59a6 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py @@ -171,10 +171,11 @@ class EnumValue(NamedValue): class Constant(object): - def __init__(self, name=None, kind=None, value=None): + def __init__(self, name=None, kind=None, value=None, parent_kind=None): self.name = name self.kind = kind self.value = value + self.parent_kind = parent_kind class Field(object): @@ -464,6 +465,10 @@ def IsStructKind(kind): return isinstance(kind, Struct) +def IsUnionKind(kind): + return isinstance(kind, Union) + + def IsArrayKind(kind): return isinstance(kind, Array) @@ -494,7 +499,7 @@ def IsMapKind(kind): def IsObjectKind(kind): return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind) or - IsMapKind(kind)) + IsMapKind(kind) or IsUnionKind(kind)) def IsNonInterfaceHandleKind(kind): @@ -512,7 +517,8 @@ def IsAnyHandleKind(kind): def IsMoveOnlyKind(kind): - return IsObjectKind(kind) or IsAnyHandleKind(kind) + return (not IsStringKind(kind) and IsObjectKind(kind)) or \ + IsAnyHandleKind(kind) def IsCloneableKind(kind): @@ -525,7 +531,7 @@ def IsCloneableKind(kind): return True if IsArrayKind(kind): return ContainsHandles(kind.kind, visited_kinds) - if IsStructKind(kind): + if IsStructKind(kind) or IsUnionKind(kind): for field in kind.fields: if ContainsHandles(field.kind, visited_kinds): return True diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py index 37d79eb..c67488c 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py @@ -11,6 +11,9 @@ import module as mojom # ps.packed_fields will access a list of PackedField objects, each of which # will have an offset, a size and a bit (for mojom.BOOLs). +# Size of struct header in bytes: num_bytes [4B] + version [4B]. +HEADER_SIZE = 8 + class PackedField(object): kind_to_size = { mojom.BOOL: 1, @@ -42,8 +45,8 @@ class PackedField(object): def GetSizeForKind(cls, kind): if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct)): return 8 - if isinstance(kind, mojom.Interface) or \ - isinstance(kind, mojom.InterfaceRequest): + if (isinstance(kind, mojom.Interface) or + isinstance(kind, mojom.InterfaceRequest)): kind = mojom.MSGPIPE if isinstance(kind, mojom.Enum): # TODO(mpcomplete): what about big enums? @@ -68,16 +71,16 @@ class PackedField(object): self.min_version = None -# Returns the pad necessary to reserve space for alignment of |size|. def GetPad(offset, size): + """Returns the pad necessary to reserve space for alignment of |size|.""" return (size - (offset % size)) % size -# Returns a 2-tuple of the field offset and bit (for BOOLs) def GetFieldOffset(field, last_field): - if field.field.kind == mojom.BOOL and \ - last_field.field.kind == mojom.BOOL and \ - last_field.bit < 7: + """Returns a 2-tuple of the field offset and bit (for BOOLs).""" + if (field.field.kind == mojom.BOOL and + last_field.field.kind == mojom.BOOL and + last_field.bit < 7): return (last_field.offset, last_field.bit + 1) offset = last_field.offset + last_field.size @@ -85,17 +88,32 @@ def GetFieldOffset(field, last_field): return (offset + pad, 0) +def GetPayloadSizeUpToField(field): + """Returns the payload size (not including struct header) if |field| is the + last field. + """ + if not field: + return 0 + offset = field.offset + field.size + pad = GetPad(offset, 8) + return offset + pad + + class PackedStruct(object): def __init__(self, struct): self.struct = struct + # |packed_fields| contains all the fields, in increasing offset order. self.packed_fields = [] + # |packed_fields_in_ordinal_order| refers to the same fields as + # |packed_fields|, but in ordinal order. + self.packed_fields_in_ordinal_order = [] # No fields. if (len(struct.fields) == 0): return # Start by sorting by ordinal. - src_fields = [] + src_fields = self.packed_fields_in_ordinal_order ordinal = 0 for index, field in enumerate(struct.fields): if field.ordinal is not None: @@ -148,7 +166,6 @@ class PackedStruct(object): src_field = src_fields[0] src_field.offset = 0 src_field.bit = 0 - # dst_fields will contain each of the fields, in increasing offset order. dst_fields = self.packed_fields dst_fields.append(src_field) @@ -170,14 +187,6 @@ class PackedStruct(object): src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field) dst_fields.append(src_field) - def GetTotalSize(self): - if not self.packed_fields: - return 0 - last_field = self.packed_fields[-1] - offset = last_field.offset + last_field.size - pad = GetPad(offset, 8) - return offset + pad - class ByteInfo(object): def __init__(self): @@ -186,7 +195,9 @@ class ByteInfo(object): def GetByteLayout(packed_struct): - bytes = [ByteInfo() for i in xrange(packed_struct.GetTotalSize())] + total_payload_size = GetPayloadSizeUpToField( + packed_struct.packed_fields[-1] if packed_struct.packed_fields else None) + bytes = [ByteInfo() for i in xrange(total_payload_size)] limit_of_previous_field = 0 for packed_field in packed_struct.packed_fields: @@ -203,3 +214,46 @@ def GetByteLayout(packed_struct): assert not (byte.is_padding and byte.packed_fields) return bytes + + +class VersionInfo(object): + def __init__(self, version, num_fields, num_bytes): + self.version = version + self.num_fields = num_fields + self.num_bytes = num_bytes + + +def GetVersionInfo(packed_struct): + """Get version information for a struct. + + Args: + packed_struct: A PackedStruct instance. + + Returns: + A non-empty list of VersionInfo instances, sorted by version in increasing + order. + Note: The version numbers may not be consecutive. + """ + versions = [] + last_version = 0 + last_num_fields = 0 + last_payload_size = 0 + + for packed_field in packed_struct.packed_fields_in_ordinal_order: + if packed_field.min_version != last_version: + versions.append( + VersionInfo(last_version, last_num_fields, + last_payload_size + HEADER_SIZE)) + last_version = packed_field.min_version + + last_num_fields += 1 + # The fields are iterated in ordinal order here. However, the size of a + # version is determined by the last field of that version in pack order, + # instead of ordinal order. Therefore, we need to calculate the max value. + last_payload_size = max(GetPayloadSizeUpToField(packed_field), + last_payload_size) + + assert len(versions) == 0 or last_num_fields != versions[-1].num_fields + versions.append(VersionInfo(last_version, last_num_fields, + last_payload_size + HEADER_SIZE)) + return versions diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py new file mode 100644 index 0000000..a684773 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/generator_unittest.py @@ -0,0 +1,37 @@ +# 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. + +import imp +import os.path +import sys +import unittest + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +try: + imp.find_module("mojom") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib")) +from mojom.generate import generator + + +class StringManipulationTest(unittest.TestCase): + """generator contains some string utilities, this tests only those.""" + + def testUnderToCamel(self): + """Tests UnderToCamel which converts underscore_separated to CamelCase.""" + self.assertEquals("CamelCase", generator.UnderToCamel("camel_case")) + self.assertEquals("CamelCase", generator.UnderToCamel("CAMEL_CASE")) + +if __name__ == "__main__": + unittest.main() + diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/pack_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/pack_unittest.py index 329e242..c140003 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/pack_unittest.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/pack_unittest.py @@ -52,3 +52,45 @@ class PackTest(unittest.TestCase): self.assertEquals(0, ps.packed_fields[0].min_version) self.assertEquals(1, ps.packed_fields[1].min_version) self.assertEquals(0, ps.packed_fields[2].min_version) + + def testGetVersionInfoEmptyStruct(self): + """Tests that pack.GetVersionInfo() never returns an empty list, even for + empty structs. + """ + struct = mojom.Struct('test') + ps = pack.PackedStruct(struct) + + versions = pack.GetVersionInfo(ps) + self.assertEquals(1, len(versions)) + self.assertEquals(0, versions[0].version) + self.assertEquals(0, versions[0].num_fields) + self.assertEquals(8, versions[0].num_bytes) + + def testGetVersionInfoComplexOrder(self): + """Tests pack.GetVersionInfo() using a struct whose definition order, + ordinal order and pack order for fields are all different. + """ + struct = mojom.Struct('test') + struct.AddField('field_3', mojom.BOOL, ordinal=3, + attributes={'MinVersion': 3}) + struct.AddField('field_0', mojom.INT32, ordinal=0) + struct.AddField('field_1', mojom.INT64, ordinal=1, + attributes={'MinVersion': 2}) + struct.AddField('field_2', mojom.INT64, ordinal=2, + attributes={'MinVersion': 3}) + ps = pack.PackedStruct(struct) + + versions = pack.GetVersionInfo(ps) + self.assertEquals(3, len(versions)) + + self.assertEquals(0, versions[0].version) + self.assertEquals(1, versions[0].num_fields) + self.assertEquals(16, versions[0].num_bytes) + + self.assertEquals(2, versions[1].version) + self.assertEquals(2, versions[1].num_fields) + self.assertEquals(24, versions[1].num_bytes) + + self.assertEquals(3, versions[2].version) + self.assertEquals(4, versions[2].num_fields) + self.assertEquals(32, versions[2].num_bytes) diff --git a/third_party/mojo/src/mojo/public/tools/download_shell_binary.py b/third_party/mojo/src/mojo/public/tools/download_shell_binary.py index b46139e..ee74231 100755 --- a/third_party/mojo/src/mojo/public/tools/download_shell_binary.py +++ b/third_party/mojo/src/mojo/public/tools/download_shell_binary.py @@ -10,25 +10,23 @@ import sys import tempfile import zipfile +BINARY_FOR_PLATFORM = { + "linux-x64" : "mojo_shell", + "android-arm" : "MojoShell.apk" +} + if not sys.platform.startswith("linux"): print "Not supported for your platform" sys.exit(0) +CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) +PREBUILT_FILE_PATH = os.path.join(CURRENT_PATH, "prebuilt") -def download(tools_directory): - current_path = os.path.dirname(os.path.realpath(__file__)) - find_depot_tools_path = os.path.join(current_path, tools_directory) - sys.path.insert(0, find_depot_tools_path) - # pylint: disable=F0401 - import find_depot_tools - - prebuilt_file_path = os.path.join(current_path, "prebuilt") - stamp_path = os.path.join(prebuilt_file_path, "VERSION") - depot_tools_path = find_depot_tools.add_depot_tools_to_path() - gsutil_exe = os.path.join(depot_tools_path, "third_party", "gsutil", "gsutil") +def download(tools_directory): + stamp_path = os.path.join(PREBUILT_FILE_PATH, "VERSION") - version_path = os.path.join(current_path, "../VERSION") + version_path = os.path.join(CURRENT_PATH, "../VERSION") with open(version_path) as version_file: version = version_file.read().strip() @@ -38,13 +36,27 @@ def download(tools_directory): if current_version == version: return 0 # Already have the right version. except IOError: - pass # If the stamp file does not exist we need to download a new binary. + pass # If the stamp file does not exist we need to download new binaries. - platform = "linux-x64" # TODO: configurate - basename = platform + ".zip" + for platform in ["linux-x64", "android-arm"]: + download_version_for_platform(version, platform, tools_directory) + + with open(stamp_path, 'w') as stamp_file: + stamp_file.write(version) + return 0 +def download_version_for_platform(version, platform, tools_directory): + find_depot_tools_path = os.path.join(CURRENT_PATH, tools_directory) + sys.path.insert(0, find_depot_tools_path) + # pylint: disable=F0401 + import find_depot_tools + + basename = platform + ".zip" gs_path = "gs://mojo/shell/" + version + "/" + basename + depot_tools_path = find_depot_tools.add_depot_tools_to_path() + gsutil_exe = os.path.join(depot_tools_path, "third_party", "gsutil", "gsutil") + with tempfile.NamedTemporaryFile() as temp_zip_file: # We're downloading from a public bucket which does not need authentication, # but the user might have busted credential files somewhere such as ~/.boto @@ -70,19 +82,16 @@ def download(tools_directory): print e.output sys.exit(1) + binary_name = BINARY_FOR_PLATFORM[platform] with zipfile.ZipFile(temp_zip_file.name) as z: - zi = z.getinfo("mojo_shell") + zi = z.getinfo(binary_name) mode = zi.external_attr >> 16 - z.extract(zi, prebuilt_file_path) - os.chmod(os.path.join(prebuilt_file_path, "mojo_shell"), mode) - - with open(stamp_path, 'w') as stamp_file: - stamp_file.write(version) - return 0 + z.extract(zi, PREBUILT_FILE_PATH) + os.chmod(os.path.join(PREBUILT_FILE_PATH, binary_name), mode) def main(): - parser = argparse.ArgumentParser(description="Download mojo_shell binary " + parser = argparse.ArgumentParser(description="Download mojo_shell binaries " "from google storage") parser.add_argument("--tools-directory", dest="tools_directory", |