Flutter Engine
mapped_resource.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "mapped_resource.h"
6 
7 #include <dlfcn.h>
8 #include <fcntl.h>
9 #include <fuchsia/io/cpp/fidl.h>
10 #include <fuchsia/mem/cpp/fidl.h>
11 #include <lib/fdio/directory.h>
12 #include <lib/fdio/io.h>
13 #include <lib/syslog/global.h>
14 #include <lib/trace/event.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <zircon/dlfcn.h>
19 #include <zircon/status.h>
20 
21 #include "third_party/dart/runtime/include/dart_api.h"
22 
23 #include "inlines.h"
24 #include "logging.h"
25 #include "vmo.h"
26 
27 namespace dart_utils {
28 
29 static bool OpenVmo(fuchsia::mem::Buffer* resource_vmo,
30  fdio_ns_t* namespc,
31  const std::string& path,
32  bool executable) {
33  TRACE_DURATION("dart", "LoadFromNamespace", "path", path);
34 
35  if (namespc == nullptr) {
36  // Opening a file in the root namespace expects an absolute path.
37  dart_utils::Check(path[0] == '/', LOG_TAG);
38  if (!VmoFromFilename(path, executable, resource_vmo)) {
39  return false;
40  }
41  } else {
42  // openat of a path with a leading '/' ignores the namespace fd.
43  // require a relative path.
44  dart_utils::Check(path[0] != '/', LOG_TAG);
45 
46  auto root_dir = fdio_ns_opendir(namespc);
47  if (root_dir < 0) {
48  FX_LOG(ERROR, LOG_TAG, "Failed to open namespace directory");
49  return false;
50  }
51 
52  bool result =
53  dart_utils::VmoFromFilenameAt(root_dir, path, executable, resource_vmo);
54  close(root_dir);
55  if (!result) {
56  return result;
57  }
58  }
59 
60  return true;
61 }
62 
63 bool MappedResource::LoadFromNamespace(fdio_ns_t* namespc,
64  const std::string& path,
65  MappedResource& resource,
66  bool executable) {
67  fuchsia::mem::Buffer resource_vmo;
68  return OpenVmo(&resource_vmo, namespc, path, executable) &&
69  LoadFromVmo(path, std::move(resource_vmo), resource, executable);
70 }
71 
72 bool MappedResource::LoadFromVmo(const std::string& path,
73  fuchsia::mem::Buffer resource_vmo,
74  MappedResource& resource,
75  bool executable) {
76  if (resource_vmo.size == 0) {
77  return true;
78  }
79 
80  uint32_t flags = ZX_VM_PERM_READ;
81  if (executable) {
82  flags |= ZX_VM_PERM_EXECUTE;
83  }
84  uintptr_t addr;
85  zx_status_t status = zx::vmar::root_self()->map(flags, 0, resource_vmo.vmo, 0,
86  resource_vmo.size, &addr);
87  if (status != ZX_OK) {
88  FX_LOGF(ERROR, LOG_TAG, "Failed to map: %s", zx_status_get_string(status));
89  return false;
90  }
91 
92  resource.address_ = reinterpret_cast<void*>(addr);
93  resource.size_ = resource_vmo.size;
94  return true;
95 }
96 
98  if (address_ != nullptr) {
99  zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(address_), size_);
100  address_ = nullptr;
101  size_ = 0;
102  }
103 }
104 
105 static int OpenFdExec(const std::string& path, int dirfd) {
106  int fd = -1;
107  zx_status_t result;
108  if (dirfd == AT_FDCWD) {
109  // fdio_open_fd_at does not support AT_FDCWD, by design. Use fdio_open_fd
110  // and expect an absolute path for that usage pattern.
111  dart_utils::Check(path[0] == '/', LOG_TAG);
112  result = fdio_open_fd(
113  path.c_str(),
114  fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_EXECUTABLE,
115  &fd);
116  } else {
117  dart_utils::Check(path[0] != '/', LOG_TAG);
118  result = fdio_open_fd_at(
119  dirfd, path.c_str(),
120  fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_EXECUTABLE,
121  &fd);
122  }
123  if (result != ZX_OK) {
124  FX_LOGF(ERROR, LOG_TAG, "fdio_open_fd_at(%s) failed: %s", path.c_str(),
125  zx_status_get_string(result));
126  return -1;
127  }
128  return fd;
129 }
130 
131 bool ElfSnapshot::Load(fdio_ns_t* namespc, const std::string& path) {
132  int root_dir = -1;
133  if (namespc == nullptr) {
134  root_dir = AT_FDCWD;
135  } else {
136  root_dir = fdio_ns_opendir(namespc);
137  if (root_dir < 0) {
138  FX_LOG(ERROR, LOG_TAG, "Failed to open namespace directory");
139  return false;
140  }
141  }
142  return Load(root_dir, path);
143 }
144 
145 bool ElfSnapshot::Load(int dirfd, const std::string& path) {
146  const int fd = OpenFdExec(path, dirfd);
147  if (fd < 0) {
148  FX_LOGF(ERROR, LOG_TAG, "Failed to open VMO for %s from dir.",
149  path.c_str());
150  return false;
151  }
152  return Load(fd);
153 }
154 
155 bool ElfSnapshot::Load(int fd) {
156  const char* error;
157  handle_ = Dart_LoadELF_Fd(fd, 0, &error, &vm_data_, &vm_instrs_,
158  &isolate_data_, &isolate_instrs_);
159  if (handle_ == nullptr) {
160  FX_LOGF(ERROR, LOG_TAG, "Failed load ELF: %s", error);
161  return false;
162  }
163  return true;
164 }
165 
167  Dart_UnloadELF(handle_);
168 }
169 
170 } // namespace dart_utils
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
const uint8_t uint32_t uint32_t GError ** error
static bool OpenVmo(fuchsia::mem::Buffer *resource_vmo, fdio_ns_t *namespc, const std::string &path, bool executable)
GAsyncResult * result
bool VmoFromFilenameAt(int dirfd, const std::string &filename, bool executable, fuchsia::mem::Buffer *buffer)
Definition: vmo.cc:76
FlutterSemanticsFlag flags
static bool LoadFromNamespace(fdio_ns_t *namespc, const std::string &path, MappedResource &resource, bool executable=false)
static bool LoadFromVmo(const std::string &path, fuchsia::mem::Buffer resource_vmo, MappedResource &resource, bool executable=false)
void Check(bool condition, const char *tag, const char *message="")
Definition: inlines.h:12
bool Load(fdio_ns_t *namespc, const std::string &path)
#define LOG_TAG
Definition: logging.h:11
bool VmoFromFilename(const std::string &filename, bool executable, fuchsia::mem::Buffer *buffer)
Definition: vmo.cc:54
static int OpenFdExec(const std::string &path, int dirfd)