1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "mojo/application/public/cpp/application_impl.h"
10 #include "base/message_loop/message_loop.h"
11 #include "mojo/application/public/cpp/application_delegate.h"
12 #include "mojo/application/public/cpp/lib/service_registry.h"
13 #include "mojo/public/cpp/bindings/interface_ptr.h"
14 #include "mojo/public/cpp/environment/logging.h"
20 void DefaultTerminationClosure() {
21 if (base::MessageLoop::current() &&
22 base::MessageLoop::current()->is_running())
23 base::MessageLoop::current()->Quit();
28 // TODO(beng): upstream this into mojo repo, array.h
29 template <typename E
, typename T
>
30 struct TypeConverter
<std::set
<E
>, Array
<T
>> {
31 static std::set
<E
> Convert(const Array
<T
>& input
) {
33 if (!input
.is_null()) {
34 for (size_t i
= 0; i
< input
.size(); ++i
)
35 result
.insert(TypeConverter
<E
, T
>::Convert(input
[i
]));
41 ApplicationImpl::ApplicationImpl(ApplicationDelegate
* delegate
,
42 InterfaceRequest
<Application
> request
)
43 : ApplicationImpl(delegate
, request
.Pass(),
44 base::Bind(&DefaultTerminationClosure
)) {
47 ApplicationImpl::ApplicationImpl(ApplicationDelegate
* delegate
,
48 InterfaceRequest
<Application
> request
,
49 const base::Closure
& termination_closure
)
50 : delegate_(delegate
),
51 binding_(this, request
.Pass()),
52 termination_closure_(termination_closure
),
53 app_lifetime_helper_(this),
54 quit_requested_(false),
55 in_destructor_(false),
59 void ApplicationImpl::ClearConnections() {
60 // Copy the ServiceRegistryLists because they will be mutated by
61 // ApplicationConnection::CloseConnection.
62 ServiceRegistryList
incoming_service_registries(incoming_service_registries_
);
63 for (internal::ServiceRegistry
* registry
: incoming_service_registries
)
64 registry
->CloseConnection();
65 DCHECK(incoming_service_registries_
.empty());
67 ServiceRegistryList
outgoing_service_registries(outgoing_service_registries_
);
68 for (internal::ServiceRegistry
* registry
: outgoing_service_registries
)
69 registry
->CloseConnection();
70 DCHECK(outgoing_service_registries_
.empty());
73 ApplicationImpl::~ApplicationImpl() {
74 DCHECK(!in_destructor_
);
75 in_destructor_
= true;
77 app_lifetime_helper_
.ApplicationTerminated();
80 ApplicationConnection
* ApplicationImpl::ConnectToApplication(
81 mojo::URLRequestPtr request
,
82 CapabilityFilterPtr filter
) {
85 ServiceProviderPtr local_services
;
86 InterfaceRequest
<ServiceProvider
> local_request
= GetProxy(&local_services
);
87 ServiceProviderPtr remote_services
;
88 std::string application_url
= request
->url
.To
<std::string
>();
89 shell_
->ConnectToApplication(request
.Pass(), GetProxy(&remote_services
),
90 local_services
.Pass(), filter
.Pass());
91 // We allow all interfaces on outgoing connections since we are presumably in
92 // a position to know who we're talking to.
93 // TODO(beng): is this a valid assumption or do we need to figure some way to
95 std::set
<std::string
> allowed
;
97 internal::ServiceRegistry
* registry
= new internal::ServiceRegistry(
98 this, application_url
, application_url
, remote_services
.Pass(),
99 local_request
.Pass(), allowed
);
100 if (!delegate_
->ConfigureOutgoingConnection(registry
)) {
101 registry
->CloseConnection();
104 outgoing_service_registries_
.push_back(registry
);
108 void ApplicationImpl::CloseConnection(ApplicationConnection
* connection
) {
110 delegate_
->OnWillCloseConnection(connection
);
111 auto outgoing_it
= std::find(outgoing_service_registries_
.begin(),
112 outgoing_service_registries_
.end(),
114 if (outgoing_it
!= outgoing_service_registries_
.end()) {
115 outgoing_service_registries_
.erase(outgoing_it
);
118 auto incoming_it
= std::find(incoming_service_registries_
.begin(),
119 incoming_service_registries_
.end(),
121 if (incoming_it
!= incoming_service_registries_
.end())
122 incoming_service_registries_
.erase(incoming_it
);
125 void ApplicationImpl::Initialize(ShellPtr shell
, const mojo::String
& url
) {
126 shell_
= shell
.Pass();
127 shell_
.set_connection_error_handler([this]() { OnConnectionError(); });
129 delegate_
->Initialize(this);
132 void ApplicationImpl::WaitForInitialize() {
134 binding_
.WaitForIncomingMethodCall();
137 void ApplicationImpl::UnbindConnections(
138 InterfaceRequest
<Application
>* application_request
,
140 *application_request
= binding_
.Unbind();
141 shell
->Bind(shell_
.PassInterface());
144 void ApplicationImpl::Terminate() {
145 // We can't quit immediately, since there could be in-flight requests from the
146 // shell. So check with it first.
148 quit_requested_
= true;
149 shell_
->QuitApplication();
155 void ApplicationImpl::QuitNow() {
157 termination_closure_
.Run();
160 void ApplicationImpl::AcceptConnection(
161 const String
& requestor_url
,
162 InterfaceRequest
<ServiceProvider
> services
,
163 ServiceProviderPtr exposed_services
,
164 Array
<String
> allowed_interfaces
,
166 internal::ServiceRegistry
* registry
= new internal::ServiceRegistry(
167 this, url
, requestor_url
, exposed_services
.Pass(), services
.Pass(),
168 allowed_interfaces
.To
<std::set
<std::string
>>());
169 if (!delegate_
->ConfigureIncomingConnection(registry
)) {
170 registry
->CloseConnection();
173 incoming_service_registries_
.push_back(registry
);
175 // If we were quitting because we thought there were no more services for this
176 // app in use, then that has changed so cancel the quit request.
178 quit_requested_
= false;
181 void ApplicationImpl::OnQuitRequested(const Callback
<void(bool)>& callback
) {
182 // If by the time we got the reply from the shell, more requests had come in
183 // then we don't want to quit the app anymore so we return false. Otherwise
184 // |quit_requested_| is true so we tell the shell to proceed with the quit.
185 callback
.Run(quit_requested_
);
190 void ApplicationImpl::OnConnectionError() {
191 base::WeakPtr
<ApplicationImpl
> ptr(weak_factory_
.GetWeakPtr());
193 // We give the delegate notice first, since it might want to do something on
194 // shell connection errors other than immediate termination of the run
195 // loop. The application might want to continue servicing connections other
196 // than the one to the shell.
197 bool quit_now
= delegate_
->OnShellConnectionError();