diff options
author | ben <ben@chromium.org> | 2016-03-16 21:40:00 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-17 04:41:55 +0000 |
commit | d146bb0affa82f8a910fe99d23845ed542395ebe (patch) | |
tree | ef0e5ee6480b11d0fe2d74d3fc4fe1cc00e9e2bf /mojo | |
parent | 2e0ba7b22dc533d059da03dbee4824e036754b2a (diff) | |
download | chromium_src-d146bb0affa82f8a910fe99d23845ed542395ebe.zip chromium_src-d146bb0affa82f8a910fe99d23845ed542395ebe.tar.gz chromium_src-d146bb0affa82f8a910fe99d23845ed542395ebe.tar.bz2 |
Cascade shutdown of instances
BUG=
Review URL: https://codereview.chromium.org/1810713002
Cr-Commit-Position: refs/heads/master@{#381660}
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/services/catalog/manifest.json | 7 | ||||
-rw-r--r-- | mojo/services/tracing/manifest.json | 7 | ||||
-rw-r--r-- | mojo/shell/manifest.json | 6 | ||||
-rw-r--r-- | mojo/shell/shell.cc | 97 | ||||
-rw-r--r-- | mojo/shell/shell.h | 16 | ||||
-rw-r--r-- | mojo/shell/tests/connect/BUILD.gn | 19 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test_app_manifest.json | 2 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test_singleton_app.cc | 36 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test_singleton_app_manifest.json | 10 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_unittest.cc | 19 | ||||
-rw-r--r-- | mojo/shell/tests/lifecycle/BUILD.gn | 22 | ||||
-rw-r--r-- | mojo/shell/tests/lifecycle/app_client.cc | 4 | ||||
-rw-r--r-- | mojo/shell/tests/lifecycle/app_client.h | 1 | ||||
-rw-r--r-- | mojo/shell/tests/lifecycle/lifecycle_unittest.cc | 29 | ||||
-rw-r--r-- | mojo/shell/tests/lifecycle/lifecycle_unittest.mojom | 9 | ||||
-rw-r--r-- | mojo/shell/tests/lifecycle/parent.cc | 80 | ||||
-rw-r--r-- | mojo/shell/tests/lifecycle/parent_manifest.json | 12 |
17 files changed, 327 insertions, 49 deletions
diff --git a/mojo/services/catalog/manifest.json b/mojo/services/catalog/manifest.json index 0fa970d..770cc26 100644 --- a/mojo/services/catalog/manifest.json +++ b/mojo/services/catalog/manifest.json @@ -1,5 +1,10 @@ { + "manifest_version": 1, "name": "mojo:catalog", "display_name": "Catalog", - "capabilities": {} + "capabilities": { + "required": { + "mojo:shell": { "classes": [ "all_users" ] } + } + } } diff --git a/mojo/services/tracing/manifest.json b/mojo/services/tracing/manifest.json index 30d9371..adbdc58 100644 --- a/mojo/services/tracing/manifest.json +++ b/mojo/services/tracing/manifest.json @@ -1,5 +1,10 @@ { + "manifest_version": 1, "name": "mojo:tracing", "display_name": "Tracing Collector", - "capabilities": {} + "capabilities": { + "required": { + "mojo:shell": { "classes": [ "all_users" ] } + } + } } diff --git a/mojo/shell/manifest.json b/mojo/shell/manifest.json index 7d006e6..24a6f77 100644 --- a/mojo/shell/manifest.json +++ b/mojo/shell/manifest.json @@ -6,7 +6,11 @@ "provided": { "user_id": [ ], "client_process": [ ], - "instance_name": [ ] + "instance_name": [ ], + "all_users": [ ] + }, + "required": { + "mojo:shell": { "classes": [ "all_users" ] } } } } diff --git a/mojo/shell/shell.cc b/mojo/shell/shell.cc index 4cefbc3..1fb16b6 100644 --- a/mojo/shell/shell.cc +++ b/mojo/shell/shell.cc @@ -129,28 +129,25 @@ class Shell::Instance : public mojom::Connector, DCHECK_NE(mojom::kInvalidInstanceID, id_); } - ~Instance() override {} - - void OnShellClientLost() { - shell_client_.reset(); - OnConnectionLost(); + ~Instance() override { + if (parent_) + parent_->RemoveChild(this); + // |children_| will be modified during destruction. + std::set<Instance*> children = children_; + for (auto child : children) + shell_->OnInstanceError(child); } - void OnConnectionLost() { - // Any time a Connector is lost or we lose the ShellClient connection, it - // may have been the last pipe using this Instance. If so, clean up. - if (connectors_.empty() && !shell_client_) { - // Deletes |this|. - shell_->OnInstanceError(this); - } + Instance* parent() { return parent_; } + void AddChild(Instance* child) { + children_.insert(child); + child->parent_ = this; } - - void OnInitializeResponse(mojom::ConnectorRequest connector_request) { - if (connector_request.is_pending()) { - connectors_.AddBinding(this, std::move(connector_request)); - connectors_.set_connection_error_handler( - base::Bind(&Instance::OnConnectionLost, base::Unretained(this))); - } + void RemoveChild(Instance* child) { + auto it = children_.find(child); + DCHECK(it != children_.end()); + children_.erase(it); + child->parent_ = nullptr; } void ConnectToClient(scoped_ptr<ConnectParams> params) { @@ -176,7 +173,8 @@ class Shell::Instance : public mojom::Connector, CHECK(!shell_client_); shell_client_ = std::move(client); shell_client_.set_connection_error_handler( - base::Bind(&Instance::OnShellClientLost, base::Unretained(this))); + base::Bind(&Instance::OnShellClientLost, base::Unretained(this), + shell_->GetWeakPtr())); shell_client_->Initialize(mojom::Identity::From(identity_), id_, base::Bind(&Instance::OnInitializeResponse, base::Unretained(this))); @@ -384,6 +382,29 @@ class Shell::Instance : public mojom::Connector, shell_->NotifyPIDAvailable(id_, pid_); } + void OnShellClientLost(base::WeakPtr<mojo::shell::Shell> shell) { + shell_client_.reset(); + OnConnectionLost(shell); + } + + void OnConnectionLost(base::WeakPtr<mojo::shell::Shell> shell) { + // Any time a Connector is lost or we lose the ShellClient connection, it + // may have been the last pipe using this Instance. If so, clean up. + if (shell && connectors_.empty() && !shell_client_) { + // Deletes |this|. + shell->OnInstanceError(this); + } + } + + void OnInitializeResponse(mojom::ConnectorRequest connector_request) { + if (connector_request.is_pending()) { + connectors_.AddBinding(this, std::move(connector_request)); + connectors_.set_connection_error_handler( + base::Bind(&Instance::OnConnectionLost, base::Unretained(this), + shell_->GetWeakPtr())); + } + } + mojo::shell::Shell* const shell_; // An id that identifies this instance. Distinct from pid, as a single process @@ -399,6 +420,8 @@ class Shell::Instance : public mojom::Connector, BindingSet<mojom::Shell> shell_bindings_; NativeRunner* runner_ = nullptr; base::ProcessId pid_ = base::kNullProcessId; + Instance* parent_ = nullptr; + std::set<Instance*> children_; base::WeakPtrFactory<Instance> weak_factory_; DISALLOW_COPY_AND_ASSIGN(Instance); @@ -425,9 +448,10 @@ Shell::Shell(scoped_ptr<NativeRunnerFactory> native_runner_factory, weak_ptr_factory_(this) { mojom::ShellClientPtr client; mojom::ShellClientRequest request = GetProxy(&client); - Instance* instance = CreateInstance(CreateShellIdentity(), + Instance* instance = CreateInstance(Identity(), CreateShellIdentity(), GetPermissiveCapabilities()); instance->StartWithClient(std::move(client)); + singletons_.insert(kShellName); shell_connection_.reset(new ShellConnection(this, std::move(request))); if (catalog) @@ -467,7 +491,7 @@ mojom::ShellClientRequest Shell::InitInstanceForEmbedder( void Shell::SetLoaderForName(scoped_ptr<Loader> loader, const std::string& name) { - NameToLoaderMap::iterator it = name_to_loader_.find(name); + auto it = name_to_loader_.find(name); if (it != name_to_loader_.end()) delete it->second; name_to_loader_[name] = loader.release(); @@ -496,8 +520,10 @@ bool Shell::AcceptConnection(Connection* connection) { // Shell, private: void Shell::InitCatalog(mojom::ShellClientPtr catalog) { - Instance* instance = - CreateInstance(CreateCatalogIdentity(), CapabilitySpec()); + Instance* instance = CreateInstance(CreateShellIdentity(), + CreateCatalogIdentity(), + CapabilitySpec()); + singletons_.insert(kCatalogName); instance->StartWithClient(std::move(catalog)); // TODO(beng): this doesn't work anymore. @@ -509,7 +535,9 @@ void Shell::InitCatalog(mojom::ShellClientPtr catalog) { } void Shell::TerminateShellConnections() { - STLDeleteValues(&identity_to_instance_); + Instance* instance = GetExistingInstance(CreateShellIdentity()); + DCHECK(instance); + OnInstanceError(instance); } void Shell::OnInstanceError(Instance* instance) { @@ -588,12 +616,16 @@ bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { return !!instance; } -Shell::Instance* Shell::CreateInstance(const Identity& target, +Shell::Instance* Shell::CreateInstance(const Identity& source, + const Identity& target, const CapabilitySpec& spec) { CHECK(target.user_id() != mojom::kInheritUserID); Instance* instance = new Instance(this, target, spec); DCHECK(identity_to_instance_.find(target) == identity_to_instance_.end()); + Instance* source_instance = GetExistingInstance(source); + if (source_instance) + source_instance->AddChild(instance); identity_to_instance_[target] = instance; mojom::InstanceInfoPtr info = instance->CreateInstanceInfo(); instance_listeners_.ForAllPtrs( @@ -678,13 +710,16 @@ void Shell::OnGotResolvedName(mojom::ShellResolverPtr resolver, capabilities = capabilities_ptr.To<CapabilitySpec>(); // Clients that request "all_users" class from the shell are allowed to - // field connection requests from any user. - if (HasClass(capabilities, kCapabilityClass_AllUsers)) + // field connection requests from any user. They also run with a synthetic + // user id generated here. The user id provided via Connect() is ignored. + if (HasClass(capabilities, kCapabilityClass_AllUsers)) { singletons_.insert(target.name()); + target.set_user_id(base::GenerateGUID()); + } mojom::ClientProcessConnectionPtr client_process_connection = params->TakeClientProcessConnection(); - Instance* instance = CreateInstance(target, capabilities); + Instance* instance = CreateInstance(params->source(), target, capabilities); // Below are various paths through which a new Instance can be bound to a // ShellClient proxy. @@ -736,6 +771,10 @@ Loader* Shell::GetLoaderForName(const std::string& name) { return default_loader_.get(); } +base::WeakPtr<Shell> Shell::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + void Shell::CleanupRunner(NativeRunner* runner) { for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) { if (it->get() == runner) { diff --git a/mojo/shell/shell.h b/mojo/shell/shell.h index 8b9f975..c060518 100644 --- a/mojo/shell/shell.h +++ b/mojo/shell/shell.h @@ -87,11 +87,6 @@ class Shell : public ShellClient { private: class Instance; - using IdentityToInstanceMap = std::map<Identity, Instance*>; - using NameToLoaderMap = std::map<std::string, Loader*>; - using IdentityToShellClientFactoryMap = - std::map<Identity, mojom::ShellClientFactoryPtr>; - // ShellClient: bool AcceptConnection(Connection* connection) override; @@ -125,7 +120,8 @@ class Shell : public ShellClient { // and this function returns true. bool ConnectToExistingInstance(scoped_ptr<ConnectParams>* params); - Instance* CreateInstance(const Identity& target, + Instance* CreateInstance(const Identity& source, + const Identity& target, const CapabilitySpec& spec); // Called from the instance implementing mojom::Shell. @@ -168,20 +164,22 @@ class Shell : public ShellClient { // is no loader configured for the name. Loader* GetLoaderForName(const std::string& name); + base::WeakPtr<Shell> GetWeakPtr(); + void CleanupRunner(NativeRunner* runner); // Loader management. // Loaders are chosen in the order they are listed here. - NameToLoaderMap name_to_loader_; + std::map<std::string, Loader*> name_to_loader_; scoped_ptr<Loader> default_loader_; - IdentityToInstanceMap identity_to_instance_; + std::map<Identity, Instance*> identity_to_instance_; // Tracks the names of instances that are allowed to field connection requests // from all users. std::set<std::string> singletons_; - IdentityToShellClientFactoryMap shell_client_factories_; + std::map<Identity, mojom::ShellClientFactoryPtr> shell_client_factories_; // Counter used to assign ids to client factories. uint32_t shell_client_factory_id_counter_; diff --git a/mojo/shell/tests/connect/BUILD.gn b/mojo/shell/tests/connect/BUILD.gn index 48c19a15..fc70dd0 100644 --- a/mojo/shell/tests/connect/BUILD.gn +++ b/mojo/shell/tests/connect/BUILD.gn @@ -24,6 +24,7 @@ source_set("connect") { data_deps = [ ":connect_test_app", ":connect_test_class_app", + ":connect_test_singleton_app", ":connect_test_driver", ":connect_test_exe", ":connect_test_package", @@ -123,6 +124,24 @@ mojo_application_manifest("connect_test_class_app_manifest") { source = "connect_test_class_app_manifest.json" } +mojo_native_application("connect_test_singleton_app") { + testonly = true + sources = [ + "connect_test_singleton_app.cc", + ] + deps = [ + ":connect_test_singleton_app_manifest", + "//base", + "//mojo/common:common_base", + "//mojo/shell/public/cpp:sources", + ] +} + +mojo_application_manifest("connect_test_singleton_app_manifest") { + application_name = "connect_test_singleton_app" + source = "connect_test_singleton_app_manifest.json" +} + executable("connect_test_driver") { testonly = true diff --git a/mojo/shell/tests/connect/connect_test_app_manifest.json b/mojo/shell/tests/connect/connect_test_app_manifest.json index 93b9782..7c45922 100644 --- a/mojo/shell/tests/connect/connect_test_app_manifest.json +++ b/mojo/shell/tests/connect/connect_test_app_manifest.json @@ -9,7 +9,7 @@ "classes": [ "class" ], "interfaces": ["mojo::shell::test::mojom::ConnectTestService"] }, - "mojo:shell": { "classes": [ "user_id", "all_users" ] } + "mojo:shell": { "classes": [ "user_id" ] } } } } diff --git a/mojo/shell/tests/connect/connect_test_singleton_app.cc b/mojo/shell/tests/connect/connect_test_singleton_app.cc new file mode 100644 index 0000000..1ee8cbd --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_singleton_app.cc @@ -0,0 +1,36 @@ +// Copyright 2016 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. + +#include "base/macros.h" +#include "mojo/public/c/system/main.h" +#include "mojo/shell/public/cpp/application_runner.h" +#include "mojo/shell/public/cpp/shell_client.h" + +namespace mojo { +namespace shell { + +class ConnectTestSingletonApp : public ShellClient { + public: + ConnectTestSingletonApp() {} + ~ConnectTestSingletonApp() override {} + + private: + // mojo::ShellClient: + void Initialize(Connector* connector, const Identity& identity, + uint32_t id) override {} + bool AcceptConnection(Connection* connection) override { + return true; + } + + DISALLOW_COPY_AND_ASSIGN(ConnectTestSingletonApp); +}; + +} // namespace shell +} // namespace mojo + + +MojoResult MojoMain(MojoHandle shell_handle) { + return mojo::ApplicationRunner( + new mojo::shell::ConnectTestSingletonApp).Run(shell_handle); +} diff --git a/mojo/shell/tests/connect/connect_test_singleton_app_manifest.json b/mojo/shell/tests/connect/connect_test_singleton_app_manifest.json new file mode 100644 index 0000000..550314d --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_singleton_app_manifest.json @@ -0,0 +1,10 @@ +{ + "manifest_version": 1, + "name": "mojo:connect_test_singleton_app", + "display_name": "Connect Test Singleton App", + "capabilities": { + "required": { + "mojo:shell": { "classes": [ "all_users" ] } + } + } +} diff --git a/mojo/shell/tests/connect/connect_unittest.cc b/mojo/shell/tests/connect/connect_unittest.cc index 9cfb0a7..355f6bac 100644 --- a/mojo/shell/tests/connect/connect_unittest.cc +++ b/mojo/shell/tests/connect/connect_unittest.cc @@ -30,6 +30,7 @@ const char kTestAppName[] = "mojo:connect_test_app"; const char kTestAppAName[] = "mojo:connect_test_a"; const char kTestAppBName[] = "mojo:connect_test_b"; const char kTestClassAppName[] = "mojo:connect_test_class_app"; +const char kTestSingletonAppName[] = "mojo:connect_test_singleton_app"; const char kTestDriverName[] = "exe:connect_test_driver"; void ReceiveOneString(std::string* out_string, @@ -355,26 +356,30 @@ TEST_F(ConnectTest, ConnectToClientProcess_Blocked) { // Verifies that a client with the "all_users" capability class can receive // connections from clients run as other users. TEST_F(ConnectTest, AllUsersSingleton) { - // Connect to an instance with an explicitly different user_id. + // Connect to an instance with an explicitly different user_id. This supplied + // user id should be ignored by the shell (which will generate its own + // synthetic user id for all-user singleton instances). const std::string singleton_userid = base::GenerateGUID(); - Connector::ConnectParams params(Identity(kTestAppName, singleton_userid)); + Connector::ConnectParams params( + Identity(kTestSingletonAppName, singleton_userid)); scoped_ptr<Connection> connection = connector()->Connect(¶ms); { base::RunLoop loop; connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop)); loop.Run(); - EXPECT_EQ(connection->GetRemoteIdentity().user_id(), singleton_userid); + EXPECT_NE(connection->GetRemoteIdentity().user_id(), singleton_userid); } - // This connects using the current client's user_id, but should be bound to - // the instance run as |singleton_userid|. + // This connects using the current client's user_id. It should be bound to the + // same service started above, with the same shell-generated user id. scoped_ptr<Connection> inherit_connection = - connector()->Connect(kTestAppName); + connector()->Connect(kTestSingletonAppName); { base::RunLoop loop; inherit_connection->AddConnectionCompletedClosure( base::Bind(&QuitLoop, &loop)); loop.Run(); - EXPECT_EQ(connection->GetRemoteIdentity().user_id(), singleton_userid); + EXPECT_EQ(inherit_connection->GetRemoteIdentity().user_id(), + connection->GetRemoteIdentity().user_id()); } } diff --git a/mojo/shell/tests/lifecycle/BUILD.gn b/mojo/shell/tests/lifecycle/BUILD.gn index 34b0a64..fbc2ac7 100644 --- a/mojo/shell/tests/lifecycle/BUILD.gn +++ b/mojo/shell/tests/lifecycle/BUILD.gn @@ -25,6 +25,7 @@ source_set("lifecycle") { data_deps = [ ":lifecycle_unittest_app", + ":lifecycle_unittest_parent", ":lifecycle_unittest_exe", ":lifecycle_unittest_package", ":manifest", @@ -115,6 +116,27 @@ mojo_application_manifest("lifecycle_unittest_app_manifest") { source = "app_manifest.json" } +mojo_native_application("lifecycle_unittest_parent") { + testonly = true + sources = [ + "parent.cc", + ] + deps = [ + ":interfaces", + "//base", + "//mojo/shell/public/cpp:sources", + ] + + data_deps = [ + ":lifecycle_unittest_parent_manifest", + ] +} + +mojo_application_manifest("lifecycle_unittest_parent_manifest") { + application_name = "lifecycle_unittest_parent" + source = "parent_manifest.json" +} + executable("lifecycle_unittest_exe") { testonly = true sources = [ diff --git a/mojo/shell/tests/lifecycle/app_client.cc b/mojo/shell/tests/lifecycle/app_client.cc index 657d967..a2400ec 100644 --- a/mojo/shell/tests/lifecycle/app_client.cc +++ b/mojo/shell/tests/lifecycle/app_client.cc @@ -20,6 +20,10 @@ bool AppClient::AcceptConnection(mojo::Connection* connection) { return true; } +void AppClient::ShellConnectionLost() { + GracefulQuit(); +} + void AppClient::Create(mojo::Connection* connection, LifecycleControlRequest request) { bindings_.AddBinding(this, std::move(request)); diff --git a/mojo/shell/tests/lifecycle/app_client.h b/mojo/shell/tests/lifecycle/app_client.h index 5a7d5e6..d389f20 100644 --- a/mojo/shell/tests/lifecycle/app_client.h +++ b/mojo/shell/tests/lifecycle/app_client.h @@ -37,6 +37,7 @@ class AppClient : public ShellClient, // ShellClient: bool AcceptConnection(Connection* connection) override; + void ShellConnectionLost() override; // InterfaceFactory<LifecycleControl>: void Create(Connection* connection, LifecycleControlRequest request) override; diff --git a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc b/mojo/shell/tests/lifecycle/lifecycle_unittest.cc index fd34f11..27e068f 100644 --- a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc +++ b/mojo/shell/tests/lifecycle/lifecycle_unittest.cc @@ -18,6 +18,7 @@ namespace shell { namespace { const char kTestAppName[] = "mojo:lifecycle_unittest_app"; +const char kTestParentName[] = "mojo:lifecycle_unittest_parent"; const char kTestExeName[] = "exe:lifecycle_unittest_exe"; const char kTestPackageName[] = "mojo:lifecycle_unittest_package"; const char kTestPackageAppNameA[] = "mojo:lifecycle_unittest_package_app_a"; @@ -438,6 +439,34 @@ TEST_F(LifecycleTest, Exe_TerminateProcess) { EXPECT_EQ(0u, instances()->GetNewInstanceCount()); } +TEST_F(LifecycleTest, ShutdownTree) { + // Verifies that Instances are destroyed when their creator is. + scoped_ptr<Connection> parent_connection = + connector()->Connect(kTestParentName); + test::mojom::ParentPtr parent; + parent_connection->GetInterface(&parent); + + // This asks kTestParentName to open a connection to kTestAppName and blocks + // on a response from a Ping(). + { + base::RunLoop loop; + parent->ConnectToChild(base::Bind(&QuitLoop, &loop)); + loop.Run(); + } + + // Should now have two new instances (parent and child). + EXPECT_EQ(2u, instances()->GetNewInstanceCount()); + EXPECT_TRUE(instances()->HasInstanceForName(kTestParentName)); + EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName)); + + parent->Quit(); + + // Quitting the parent should cascade-quit the child. + WaitForInstanceDestruction(); + EXPECT_EQ(0u, instances()->GetNewInstanceCount()); + EXPECT_FALSE(instances()->HasInstanceForName(kTestParentName)); + EXPECT_FALSE(instances()->HasInstanceForName(kTestAppName)); +} } // namespace shell } // namespace mojo diff --git a/mojo/shell/tests/lifecycle/lifecycle_unittest.mojom b/mojo/shell/tests/lifecycle/lifecycle_unittest.mojom index 1ae54e8..2197e3b 100644 --- a/mojo/shell/tests/lifecycle/lifecycle_unittest.mojom +++ b/mojo/shell/tests/lifecycle/lifecycle_unittest.mojom @@ -21,3 +21,12 @@ interface LifecycleControl { // longer tracking this application. CloseShellConnection(); }; + +// Implemented by an app that connects to another app, thereby creating an +// instance for it in the shell. +interface Parent { + // Connects to another app and runs the callback when that app has acked a + // Ping. + ConnectToChild() => (); + Quit(); +}; diff --git a/mojo/shell/tests/lifecycle/parent.cc b/mojo/shell/tests/lifecycle/parent.cc new file mode 100644 index 0000000..27b2099 --- /dev/null +++ b/mojo/shell/tests/lifecycle/parent.cc @@ -0,0 +1,80 @@ +// Copyright 2016 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. + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "mojo/public/c/system/main.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/shell/public/cpp/application_runner.h" +#include "mojo/shell/public/cpp/connector.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/tests/lifecycle/lifecycle_unittest.mojom.h" + +namespace { + +void QuitLoop(base::RunLoop* loop) { + loop->Quit(); +} + +class Parent + : public mojo::ShellClient, + public mojo::InterfaceFactory<mojo::shell::test::mojom::Parent>, + public mojo::shell::test::mojom::Parent { + public: + Parent() {} + ~Parent() override { + connector_ = nullptr; + child_connection_.reset(); + parent_bindings_.CloseAllBindings(); + } + + private: + // ShellClient: + void Initialize(mojo::Connector* connector, const mojo::Identity& identity, + uint32_t id) override { + connector_ = connector; + } + bool AcceptConnection(mojo::Connection* connection) override { + connection->AddInterface<mojo::shell::test::mojom::Parent>(this); + return true; + } + + // InterfaceFactory<mojo::shell::test::mojom::Parent>: + void Create(mojo::Connection* connection, + mojo::shell::test::mojom::ParentRequest request) override { + parent_bindings_.AddBinding(this, std::move(request)); + } + + // Parent: + void ConnectToChild(const ConnectToChildCallback& callback) override { + child_connection_ = connector_->Connect("mojo:lifecycle_unittest_app"); + mojo::shell::test::mojom::LifecycleControlPtr lifecycle; + child_connection_->GetInterface(&lifecycle); + { + base::RunLoop loop; + lifecycle->Ping(base::Bind(&QuitLoop, &loop)); + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + loop.Run(); + } + callback.Run(); + } + void Quit() override { + base::MessageLoop::current()->QuitWhenIdle(); + } + + mojo::Connector* connector_; + scoped_ptr<mojo::Connection> child_connection_; + mojo::BindingSet<mojo::shell::test::mojom::Parent> parent_bindings_; + + DISALLOW_COPY_AND_ASSIGN(Parent); +}; + +} // namespace + +MojoResult MojoMain(MojoHandle shell_handle) { + Parent* parent = new Parent; + return mojo::ApplicationRunner(parent).Run(shell_handle); +} diff --git a/mojo/shell/tests/lifecycle/parent_manifest.json b/mojo/shell/tests/lifecycle/parent_manifest.json new file mode 100644 index 0000000..25191c8 --- /dev/null +++ b/mojo/shell/tests/lifecycle/parent_manifest.json @@ -0,0 +1,12 @@ +{ + "manifest_version": 1, + "name": "mojo:lifecycle_unittest_parent", + "display_name": "Lifecycle Unittest Parent", + "capabilities": { + "required": { + "mojo:lifecycle_unittest_app": { + "interfaces": [ "mojo::shell::test::mojom::LifecycleControl" ] + } + } + } +} |