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