pnacl_resources.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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 "native_client/src/trusted/plugin/pnacl_resources.h"
6
7#include "native_client/src/include/portability_io.h"
8#include "native_client/src/shared/platform/nacl_check.h"
9#include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
10#include "native_client/src/trusted/plugin/manifest.h"
11#include "native_client/src/trusted/plugin/plugin.h"
12#include "native_client/src/trusted/plugin/pnacl_coordinator.h"
13#include "native_client/src/trusted/plugin/utility.h"
14
15#include "ppapi/c/pp_errors.h"
16
17namespace plugin {
18
19const char PnaclUrls::kExtensionOrigin[] =
20    "chrome-extension://gcodniebolpnpaiggndmcmmfpldlknih/";
21const char PnaclUrls::kPnaclComponentID[] =
22    "pnacl-component://";
23const char PnaclUrls::kLlcUrl[] = "llc";
24const char PnaclUrls::kLdUrl[] = "ld";
25
26bool PnaclUrls::UsePnaclExtension(const Plugin* plugin) {
27  // Use the chrome webstore extension for now, if --enable-pnacl is not
28  // explicitly requested.  Eventually we will always behave as if
29  // --enable-pnacl is used and not use the chrome extension.
30  // Some UI work, etc. remains before --enable-pnacl is usable:
31  // http://code.google.com/p/nativeclient/issues/detail?id=2813
32  // TODO(jvoung): re-enable the non-extension path if we decide
33  // to use that / once we have renamed and remap some of the files.
34  return true;
35  // return !(plugin->nacl_interface()->IsPnaclEnabled());
36}
37
38nacl::string PnaclUrls::GetBaseUrl(bool use_extension) {
39  if (use_extension) {
40    return nacl::string(kExtensionOrigin) + GetSandboxISA() + "/";
41  } else {
42    return nacl::string(kPnaclComponentID) + GetSandboxISA() + "/";
43  }
44}
45
46bool PnaclUrls::IsPnaclComponent(const nacl::string& full_url) {
47  return full_url.find(kPnaclComponentID, 0) == 0;
48}
49
50nacl::string PnaclUrls::StripPnaclComponentPrefix(
51    const nacl::string& full_url) {
52  return full_url.substr(nacl::string(kPnaclComponentID).length());
53}
54
55//////////////////////////////////////////////////////////////////////
56
57PnaclResources::~PnaclResources() {
58  for (std::map<nacl::string, nacl::DescWrapper*>::iterator
59           i = resource_wrappers_.begin(), e = resource_wrappers_.end();
60       i != e;
61       ++i) {
62    delete i->second;
63  }
64  resource_wrappers_.clear();
65}
66
67// static
68int32_t PnaclResources::GetPnaclFD(Plugin* plugin, const char* filename) {
69  PP_FileHandle file_handle =
70      plugin->nacl_interface()->GetReadonlyPnaclFd(filename);
71  if (file_handle == PP_kInvalidFileHandle)
72    return -1;
73
74#if NACL_WINDOWS
75  //////// Now try the posix view.
76  int32_t posix_desc = _open_osfhandle(reinterpret_cast<intptr_t>(file_handle),
77                                       _O_RDONLY | _O_BINARY);
78  if (posix_desc == -1) {
79    PLUGIN_PRINTF((
80        "PnaclResources::GetPnaclFD failed to convert HANDLE to posix\n"));
81    // Close the Windows HANDLE if it can't be converted.
82    CloseHandle(file_handle);
83  }
84  return posix_desc;
85#else
86  return file_handle;
87#endif
88}
89
90nacl::DescWrapper* PnaclResources::WrapperForUrl(const nacl::string& url) {
91  CHECK(resource_wrappers_.find(url) != resource_wrappers_.end());
92  return resource_wrappers_[url];
93}
94
95void PnaclResources::StartLoad() {
96  PLUGIN_PRINTF(("PnaclResources::StartLoad\n"));
97
98  CHECK(resource_urls_.size() > 0);
99  if (PnaclUrls::UsePnaclExtension(plugin_)) {
100    PLUGIN_PRINTF(("PnaclResources::StartLoad -- PNaCl chrome extension.\n"));
101    // Do a URL fetch.
102    // Create a counter (barrier) callback to track when all of the resources
103    // are loaded.
104    uint32_t resource_count = static_cast<uint32_t>(resource_urls_.size());
105    delayed_callback_.reset(
106        new DelayedCallback(all_loaded_callback_, resource_count));
107
108    // Schedule the downloads.
109    for (size_t i = 0; i < resource_urls_.size(); ++i) {
110      nacl::string full_url;
111      ErrorInfo error_info;
112      if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) {
113        coordinator_->ReportNonPpapiError(nacl::string("failed to resolve ") +
114                                          resource_urls_[i] + ": " +
115                                          error_info.message() + ".");
116        break;
117      }
118      pp::CompletionCallback ready_callback =
119          callback_factory_.NewCallback(
120              &PnaclResources::ResourceReady,
121              resource_urls_[i],
122              full_url);
123      if (!plugin_->StreamAsFile(full_url,
124                                 ready_callback.pp_completion_callback())) {
125        coordinator_->ReportNonPpapiError(nacl::string("failed to download ") +
126                                          resource_urls_[i] + ".");
127        break;
128      }
129    }
130  } else {
131    PLUGIN_PRINTF(("PnaclResources::StartLoad -- local install of PNaCl.\n"));
132    // Do a blocking load of each of the resources.
133    int32_t result = PP_OK;
134    for (size_t i = 0; i < resource_urls_.size(); ++i) {
135      const nacl::string& url = resource_urls_[i];
136      nacl::string full_url;
137      ErrorInfo error_info;
138      if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) {
139        coordinator_->ReportNonPpapiError(nacl::string("failed to resolve ") +
140                                          url + ": " +
141                                          error_info.message() + ".");
142        break;
143      }
144      full_url = PnaclUrls::StripPnaclComponentPrefix(full_url);
145
146      int32_t fd = PnaclResources::GetPnaclFD(plugin_, full_url.c_str());
147      if (fd < 0) {
148        coordinator_->ReportNonPpapiError(
149            nacl::string("PnaclLocalResources::StartLoad failed for: ") +
150            full_url);
151        result = PP_ERROR_FILENOTFOUND;
152        break;
153      } else {
154        resource_wrappers_[url] =
155            plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY);
156      }
157    }
158    // We're done!  Queue the callback.
159    pp::Core* core = pp::Module::Get()->core();
160    core->CallOnMainThread(0, all_loaded_callback_, result);
161  }
162}
163
164void PnaclResources::ResourceReady(int32_t pp_error,
165                                   const nacl::string& url,
166                                   const nacl::string& full_url) {
167  PLUGIN_PRINTF(("PnaclResources::ResourceReady (pp_error=%"
168                 NACL_PRId32", url=%s)\n", pp_error, url.c_str()));
169  // pp_error is checked by GetLoadedFileDesc.
170  int32_t fd = coordinator_->GetLoadedFileDesc(pp_error,
171                                               full_url,
172                                               "resource " + url);
173  if (fd < 0) {
174    coordinator_->ReportPpapiError(pp_error,
175                                   "PnaclResources::ResourceReady failed.");
176  } else {
177    resource_wrappers_[url] =
178        plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY);
179    delayed_callback_->RunIfTime();
180  }
181}
182
183}  // namespace plugin
184