summaryrefslogtreecommitdiffstats
path: root/mojo/shell/dynamic_service_loader.cc
blob: da87453ec827ebf934ef863ed5d53f45df5987aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// 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.

#include "mojo/shell/dynamic_service_loader.h"

#include "base/command_line.h"
#include "base/location.h"
#include "mojo/shell/context.h"
#include "mojo/shell/keep_alive.h"
#include "mojo/shell/switches.h"

namespace mojo {
namespace shell {

namespace {

std::string MakeSharedLibraryName(const std::string& file_name) {
#if defined(OS_WIN)
  return file_name + ".dll";
#elif defined(OS_LINUX)
  return "lib" + file_name + ".so";
#elif defined(OS_MACOSX)
  return "lib" + file_name + ".dylib";
#else
  NOTREACHED() << "dynamic loading of services not supported";
  return std::string();
#endif
}

}  // namespace

class DynamicServiceLoader::LoadContext : public mojo::shell::Loader::Delegate {
 public:
  LoadContext(DynamicServiceLoader* loader,
              const GURL& url,
              ScopedShellHandle service_handle,
              scoped_ptr<DynamicServiceRunner> runner)
      : loader_(loader),
        url_(url),
        service_handle_(service_handle.Pass()),
        runner_(runner.Pass()),
        keep_alive_(loader->context_) {
    GURL url_to_load;

    if (url.SchemeIs("mojo")) {
      std::string origin =
          CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
              switches::kOrigin);
      std::string lib = MakeSharedLibraryName(url.ExtractFileName());
      url_to_load = GURL(origin + "/" + lib);
    } else {
      url_to_load = url;
    }

    request_ = loader_->context_->loader()->Load(url_to_load, this);
  }

  virtual ~LoadContext() {
  }

 private:
  // |Loader::Delegate| method:
  virtual void DidCompleteLoad(const GURL& app_url,
                               const base::FilePath& app_path,
                               const std::string* mime_type) OVERRIDE {
    DVLOG(2) << "Completed load of " << app_url << " (" << url_ << ") to "
             << app_path.value();
    DCHECK(loader_->context_->task_runners()->ui_runner()->
               BelongsToCurrentThread());

    runner_->Start(
        app_path,
        service_handle_.Pass(),
        base::Bind(&DynamicServiceLoader::AppCompleted,
                   base::Unretained(loader_), url_));
  }

  DynamicServiceLoader* const loader_;
  const GURL url_;
  scoped_ptr<mojo::shell::Loader::Job> request_;
  ScopedShellHandle service_handle_;
  scoped_ptr<DynamicServiceRunner> runner_;
  KeepAlive keep_alive_;

  DISALLOW_COPY_AND_ASSIGN(LoadContext);
};

DynamicServiceLoader::DynamicServiceLoader(
    Context* context,
    scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
    : context_(context),
      runner_factory_(runner_factory.Pass()) {
}

DynamicServiceLoader::~DynamicServiceLoader() {
  DCHECK(url_to_load_context_.empty());
}

void DynamicServiceLoader::LoadService(ServiceManager* manager,
                                       const GURL& url,
                                       ScopedShellHandle service_handle) {
  DCHECK(url_to_load_context_.find(url) == url_to_load_context_.end());
  url_to_load_context_[url] = new LoadContext(
      this, url, service_handle.Pass(), runner_factory_->Create(context_));
}

void DynamicServiceLoader::OnServiceError(ServiceManager* manager,
                                          const GURL& url) {
}

void DynamicServiceLoader::AppCompleted(const GURL& url) {
  DCHECK(context_->task_runners()->ui_runner()->BelongsToCurrentThread());
  DVLOG(2) << "App completed (url: " << url << ")";

  LoadContextMap::iterator it = url_to_load_context_.find(url);
  DCHECK(it != url_to_load_context_.end()) << url;

  LoadContext* doomed = it->second;
  url_to_load_context_.erase(it);

  delete doomed;
}

}  // namespace shell
}  // namespace mojo