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/background_shell_application_loader.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/run_loop.h"
      9 #include "mojo/application_manager/application_manager.h"
     10 
     11 namespace mojo {
     12 
     13 class BackgroundShellApplicationLoader::BackgroundLoader {
     14  public:
     15   explicit BackgroundLoader(ApplicationLoader* loader) : loader_(loader) {}
     16   ~BackgroundLoader() {}
     17 
     18   void Load(ApplicationManager* manager,
     19             const GURL& url,
     20             ScopedMessagePipeHandle shell_handle) {
     21     scoped_refptr<LoadCallbacks> callbacks(
     22         new ApplicationLoader::SimpleLoadCallbacks(shell_handle.Pass()));
     23     loader_->Load(manager, url, callbacks);
     24   }
     25 
     26   void OnApplicationError(ApplicationManager* manager, const GURL& url) {
     27     loader_->OnApplicationError(manager, url);
     28   }
     29 
     30  private:
     31   ApplicationLoader* loader_;  // Owned by BackgroundShellApplicationLoader
     32 
     33   DISALLOW_COPY_AND_ASSIGN(BackgroundLoader);
     34 };
     35 
     36 BackgroundShellApplicationLoader::BackgroundShellApplicationLoader(
     37     scoped_ptr<ApplicationLoader> real_loader,
     38     const std::string& thread_name,
     39     base::MessageLoop::Type message_loop_type)
     40     : loader_(real_loader.Pass()),
     41       message_loop_type_(message_loop_type),
     42       thread_name_(thread_name),
     43       message_loop_created_(true, false),
     44       background_loader_(NULL) {
     45 }
     46 
     47 BackgroundShellApplicationLoader::~BackgroundShellApplicationLoader() {
     48   if (thread_)
     49     thread_->Join();
     50 }
     51 
     52 void BackgroundShellApplicationLoader::Load(
     53     ApplicationManager* manager,
     54     const GURL& url,
     55     scoped_refptr<LoadCallbacks> callbacks) {
     56   ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
     57   if (!shell_handle.is_valid())
     58     return;
     59 
     60   if (!thread_) {
     61     // TODO(tim): It'd be nice if we could just have each Load call
     62     // result in a new thread like DynamicService{Loader, Runner}. But some
     63     // loaders are creating multiple ApplicationImpls (NetworkApplicationLoader)
     64     // sharing a delegate (etc). So we have to keep it single threaded, wait
     65     // for the thread to initialize, and post to the TaskRunner for subsequent
     66     // Load calls for now.
     67     thread_.reset(new base::DelegateSimpleThread(this, thread_name_));
     68     thread_->Start();
     69     message_loop_created_.Wait();
     70     DCHECK(task_runner_.get());
     71   }
     72 
     73   task_runner_->PostTask(
     74       FROM_HERE,
     75       base::Bind(
     76           &BackgroundShellApplicationLoader::LoadOnBackgroundThread,
     77           base::Unretained(this),
     78           manager,
     79           url,
     80           base::Owned(new ScopedMessagePipeHandle(shell_handle.Pass()))));
     81 }
     82 
     83 void BackgroundShellApplicationLoader::OnApplicationError(
     84     ApplicationManager* manager,
     85     const GURL& url) {
     86   task_runner_->PostTask(FROM_HERE,
     87                          base::Bind(&BackgroundShellApplicationLoader::
     88                                         OnApplicationErrorOnBackgroundThread,
     89                                     base::Unretained(this),
     90                                     manager,
     91                                     url));
     92 }
     93 
     94 void BackgroundShellApplicationLoader::Run() {
     95   base::MessageLoop message_loop(message_loop_type_);
     96   base::RunLoop loop;
     97   task_runner_ = message_loop.task_runner();
     98   quit_closure_ = loop.QuitClosure();
     99   message_loop_created_.Signal();
    100   loop.Run();
    101 
    102   delete background_loader_;
    103   background_loader_ = NULL;
    104   // Destroy |loader_| on the thread it's actually used on.
    105   loader_.reset();
    106 }
    107 
    108 void BackgroundShellApplicationLoader::LoadOnBackgroundThread(
    109     ApplicationManager* manager,
    110     const GURL& url,
    111     ScopedMessagePipeHandle* shell_handle) {
    112   DCHECK(task_runner_->RunsTasksOnCurrentThread());
    113   if (!background_loader_)
    114     background_loader_ = new BackgroundLoader(loader_.get());
    115   background_loader_->Load(manager, url, shell_handle->Pass());
    116 }
    117 
    118 void BackgroundShellApplicationLoader::OnApplicationErrorOnBackgroundThread(
    119     ApplicationManager* manager,
    120     const GURL& url) {
    121   DCHECK(task_runner_->RunsTasksOnCurrentThread());
    122   if (!background_loader_)
    123     background_loader_ = new BackgroundLoader(loader_.get());
    124   background_loader_->OnApplicationError(manager, url);
    125 }
    126 
    127 }  // namespace mojo
    128