Home | History | Annotate | Download | only in application_manager
      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.
      4 
      5 #include "mojo/application_manager/application_manager.h"
      6 
      7 #include <stdio.h>
      8 
      9 #include "base/bind.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/logging.h"
     12 #include "base/macros.h"
     13 #include "base/stl_util.h"
     14 #include "mojo/application_manager/application_loader.h"
     15 #include "mojo/common/common_type_converters.h"
     16 #include "mojo/public/cpp/application/connect.h"
     17 #include "mojo/public/interfaces/application/application.mojom.h"
     18 #include "mojo/public/interfaces/application/shell.mojom.h"
     19 #include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
     20 
     21 namespace mojo {
     22 
     23 namespace {
     24 // Used by TestAPI.
     25 bool has_created_instance = false;
     26 
     27 class StubServiceProvider : public InterfaceImpl<ServiceProvider> {
     28  public:
     29   ServiceProvider* GetRemoteServiceProvider() { return client(); }
     30 
     31  private:
     32   virtual void ConnectToService(const String& service_name,
     33                                 ScopedMessagePipeHandle client_handle)
     34       MOJO_OVERRIDE {}
     35 };
     36 
     37 }  // namespace
     38 
     39 ApplicationManager::Delegate::~Delegate() {}
     40 
     41 class ApplicationManager::LoadCallbacksImpl
     42     : public ApplicationLoader::LoadCallbacks {
     43  public:
     44   LoadCallbacksImpl(base::WeakPtr<ApplicationManager> manager,
     45                     const GURL& requested_url,
     46                     const GURL& requestor_url,
     47                     ServiceProviderPtr service_provider)
     48       : manager_(manager),
     49         requested_url_(requested_url),
     50         requestor_url_(requestor_url),
     51         service_provider_(service_provider.Pass()) {}
     52 
     53  private:
     54   virtual ~LoadCallbacksImpl() {}
     55 
     56   // LoadCallbacks implementation
     57   virtual ScopedMessagePipeHandle RegisterApplication() OVERRIDE {
     58     ScopedMessagePipeHandle shell_handle;
     59     if (manager_) {
     60       manager_->RegisterLoadedApplication(requested_url_,
     61                                           requestor_url_,
     62                                           service_provider_.Pass(),
     63                                           &shell_handle);
     64     }
     65     return shell_handle.Pass();
     66   }
     67 
     68   virtual void LoadWithContentHandler(const GURL& content_handler_url,
     69                                       URLResponsePtr url_response) OVERRIDE {
     70     if (manager_) {
     71       manager_->LoadWithContentHandler(requested_url_,
     72                                        requestor_url_,
     73                                        content_handler_url,
     74                                        url_response.Pass(),
     75                                        service_provider_.Pass());
     76     }
     77   }
     78 
     79   base::WeakPtr<ApplicationManager> manager_;
     80   GURL requested_url_;
     81   GURL requestor_url_;
     82   ServiceProviderPtr service_provider_;
     83 };
     84 
     85 class ApplicationManager::ShellImpl : public InterfaceImpl<Shell> {
     86  public:
     87   ShellImpl(ApplicationManager* manager, const GURL& url)
     88       : manager_(manager), url_(url) {}
     89 
     90   virtual ~ShellImpl() {}
     91 
     92   void ConnectToClient(const GURL& requestor_url,
     93                        ServiceProviderPtr service_provider) {
     94     client()->AcceptConnection(String::From(requestor_url),
     95                                service_provider.Pass());
     96   }
     97 
     98   // ServiceProvider implementation:
     99   virtual void ConnectToApplication(
    100       const String& app_url,
    101       InterfaceRequest<ServiceProvider> in_service_provider) OVERRIDE {
    102     ServiceProviderPtr out_service_provider;
    103     out_service_provider.Bind(in_service_provider.PassMessagePipe());
    104     manager_->ConnectToApplication(
    105         app_url.To<GURL>(), url_, out_service_provider.Pass());
    106   }
    107 
    108   const GURL& url() const { return url_; }
    109 
    110  private:
    111   virtual void OnConnectionError() OVERRIDE {
    112     manager_->OnShellImplError(this);
    113   }
    114 
    115   ApplicationManager* const manager_;
    116   const GURL url_;
    117 
    118   DISALLOW_COPY_AND_ASSIGN(ShellImpl);
    119 };
    120 
    121 struct ApplicationManager::ContentHandlerConnection {
    122   ContentHandlerConnection(ApplicationManager* manager,
    123                            const GURL& content_handler_url) {
    124     ServiceProviderPtr service_provider;
    125     BindToProxy(&service_provider_impl, &service_provider);
    126     manager->ConnectToApplication(
    127         content_handler_url, GURL(), service_provider.Pass());
    128     mojo::ConnectToService(service_provider_impl.client(), &content_handler);
    129   }
    130 
    131   StubServiceProvider service_provider_impl;
    132   ContentHandlerPtr content_handler;
    133 };
    134 
    135 // static
    136 ApplicationManager::TestAPI::TestAPI(ApplicationManager* manager)
    137     : manager_(manager) {
    138 }
    139 
    140 ApplicationManager::TestAPI::~TestAPI() {
    141 }
    142 
    143 bool ApplicationManager::TestAPI::HasCreatedInstance() {
    144   return has_created_instance;
    145 }
    146 
    147 bool ApplicationManager::TestAPI::HasFactoryForURL(const GURL& url) const {
    148   return manager_->url_to_shell_impl_.find(url) !=
    149          manager_->url_to_shell_impl_.end();
    150 }
    151 
    152 ApplicationManager::ApplicationManager()
    153     : delegate_(NULL),
    154       interceptor_(NULL),
    155       weak_ptr_factory_(this) {
    156 }
    157 
    158 ApplicationManager::~ApplicationManager() {
    159   STLDeleteValues(&url_to_content_handler_);
    160   TerminateShellConnections();
    161   STLDeleteValues(&url_to_loader_);
    162   STLDeleteValues(&scheme_to_loader_);
    163 }
    164 
    165 void ApplicationManager::TerminateShellConnections() {
    166   STLDeleteValues(&url_to_shell_impl_);
    167 }
    168 
    169 // static
    170 ApplicationManager* ApplicationManager::GetInstance() {
    171   static base::LazyInstance<ApplicationManager> instance =
    172       LAZY_INSTANCE_INITIALIZER;
    173   has_created_instance = true;
    174   return &instance.Get();
    175 }
    176 
    177 void ApplicationManager::ConnectToApplication(
    178     const GURL& url,
    179     const GURL& requestor_url,
    180     ServiceProviderPtr service_provider) {
    181   URLToShellImplMap::const_iterator shell_it = url_to_shell_impl_.find(url);
    182   if (shell_it != url_to_shell_impl_.end()) {
    183     ConnectToClient(
    184         shell_it->second, url, requestor_url, service_provider.Pass());
    185     return;
    186   }
    187 
    188   scoped_refptr<LoadCallbacksImpl> callbacks(
    189       new LoadCallbacksImpl(weak_ptr_factory_.GetWeakPtr(),
    190                             url,
    191                             requestor_url,
    192                             service_provider.Pass()));
    193   GetLoaderForURL(url)->Load(this, url, callbacks);
    194 }
    195 
    196 void ApplicationManager::ConnectToClient(ShellImpl* shell_impl,
    197                                          const GURL& url,
    198                                          const GURL& requestor_url,
    199                                          ServiceProviderPtr service_provider) {
    200   if (interceptor_) {
    201     shell_impl->ConnectToClient(
    202         requestor_url,
    203         interceptor_->OnConnectToClient(url, service_provider.Pass()));
    204   } else {
    205     shell_impl->ConnectToClient(requestor_url, service_provider.Pass());
    206   }
    207 }
    208 
    209 void ApplicationManager::RegisterLoadedApplication(
    210     const GURL& url,
    211     const GURL& requestor_url,
    212     ServiceProviderPtr service_provider,
    213     ScopedMessagePipeHandle* shell_handle) {
    214   ShellImpl* shell_impl = NULL;
    215   URLToShellImplMap::iterator iter = url_to_shell_impl_.find(url);
    216   if (iter != url_to_shell_impl_.end()) {
    217     // This can happen because services are loaded asynchronously. So if we get
    218     // two requests for the same service close to each other, we might get here
    219     // and find that we already have it.
    220     shell_impl = iter->second;
    221   } else {
    222     MessagePipe pipe;
    223     URLToArgsMap::const_iterator args_it = url_to_args_.find(url);
    224     Array<String> args;
    225     if (args_it != url_to_args_.end())
    226       args = Array<String>::From(args_it->second);
    227     shell_impl = WeakBindToPipe(new ShellImpl(this, url), pipe.handle1.Pass());
    228     url_to_shell_impl_[url] = shell_impl;
    229     *shell_handle = pipe.handle0.Pass();
    230     shell_impl->client()->Initialize(args.Pass());
    231   }
    232 
    233   ConnectToClient(shell_impl, url, requestor_url, service_provider.Pass());
    234 }
    235 
    236 void ApplicationManager::LoadWithContentHandler(
    237     const GURL& content_url,
    238     const GURL& requestor_url,
    239     const GURL& content_handler_url,
    240     URLResponsePtr url_response,
    241     ServiceProviderPtr service_provider) {
    242   ContentHandlerConnection* connection = NULL;
    243   URLToContentHandlerMap::iterator iter =
    244       url_to_content_handler_.find(content_handler_url);
    245   if (iter != url_to_content_handler_.end()) {
    246     connection = iter->second;
    247   } else {
    248     connection = new ContentHandlerConnection(this, content_handler_url);
    249     url_to_content_handler_[content_handler_url] = connection;
    250   }
    251 
    252   InterfaceRequest<ServiceProvider> spir;
    253   spir.Bind(service_provider.PassMessagePipe());
    254   connection->content_handler->OnConnect(
    255       content_url.spec(), url_response.Pass(), spir.Pass());
    256 }
    257 
    258 void ApplicationManager::SetLoaderForURL(scoped_ptr<ApplicationLoader> loader,
    259                                          const GURL& url) {
    260   URLToLoaderMap::iterator it = url_to_loader_.find(url);
    261   if (it != url_to_loader_.end())
    262     delete it->second;
    263   url_to_loader_[url] = loader.release();
    264 }
    265 
    266 void ApplicationManager::SetLoaderForScheme(
    267     scoped_ptr<ApplicationLoader> loader,
    268     const std::string& scheme) {
    269   SchemeToLoaderMap::iterator it = scheme_to_loader_.find(scheme);
    270   if (it != scheme_to_loader_.end())
    271     delete it->second;
    272   scheme_to_loader_[scheme] = loader.release();
    273 }
    274 
    275 void ApplicationManager::SetArgsForURL(const std::vector<std::string>& args,
    276                                        const GURL& url) {
    277   url_to_args_[url] = args;
    278 }
    279 
    280 void ApplicationManager::SetInterceptor(Interceptor* interceptor) {
    281   interceptor_ = interceptor;
    282 }
    283 
    284 ApplicationLoader* ApplicationManager::GetLoaderForURL(const GURL& url) {
    285   URLToLoaderMap::const_iterator url_it = url_to_loader_.find(url);
    286   if (url_it != url_to_loader_.end())
    287     return url_it->second;
    288   SchemeToLoaderMap::const_iterator scheme_it =
    289       scheme_to_loader_.find(url.scheme());
    290   if (scheme_it != scheme_to_loader_.end())
    291     return scheme_it->second;
    292   return default_loader_.get();
    293 }
    294 
    295 void ApplicationManager::OnShellImplError(ShellImpl* shell_impl) {
    296   // Called from ~ShellImpl, so we do not need to call Destroy here.
    297   const GURL url = shell_impl->url();
    298   URLToShellImplMap::iterator it = url_to_shell_impl_.find(url);
    299   DCHECK(it != url_to_shell_impl_.end());
    300   delete it->second;
    301   url_to_shell_impl_.erase(it);
    302   ApplicationLoader* loader = GetLoaderForURL(url);
    303   if (loader)
    304     loader->OnApplicationError(this, url);
    305   if (delegate_)
    306     delegate_->OnApplicationError(url);
    307 }
    308 
    309 ScopedMessagePipeHandle ApplicationManager::ConnectToServiceByName(
    310     const GURL& application_url,
    311     const std::string& interface_name) {
    312   StubServiceProvider* stub_sp = new StubServiceProvider;
    313   ServiceProviderPtr spp;
    314   BindToProxy(stub_sp, &spp);
    315   ConnectToApplication(application_url, GURL(), spp.Pass());
    316   MessagePipe pipe;
    317   stub_sp->GetRemoteServiceProvider()->ConnectToService(interface_name,
    318                                                         pipe.handle1.Pass());
    319   return pipe.handle0.Pass();
    320 }
    321 }  // namespace mojo
    322