Flutter Engine
system.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 "system.h"
6 
7 #include <array>
8 
9 #include <fcntl.h>
10 #include <lib/fdio/directory.h>
11 #include <lib/fdio/io.h>
12 #include <lib/fdio/limits.h>
13 #include <lib/fdio/namespace.h>
14 #include <lib/zx/channel.h>
15 #include <sys/stat.h>
16 #include <unistd.h>
17 #include <zircon/process.h>
18 #include <zircon/processargs.h>
19 
20 #include "flutter/fml/unique_fd.h"
23 
24 using tonic::ToDart;
25 
26 namespace zircon {
27 namespace dart {
28 
29 namespace {
30 
31 constexpr char kGetSizeResult[] = "GetSizeResult";
32 constexpr char kHandlePairResult[] = "HandlePairResult";
33 constexpr char kHandleResult[] = "HandleResult";
34 constexpr char kReadResult[] = "ReadResult";
35 constexpr char kWriteResult[] = "WriteResult";
36 constexpr char kFromFileResult[] = "FromFileResult";
37 constexpr char kMapResult[] = "MapResult";
38 
39 class ByteDataScope {
40  public:
41  explicit ByteDataScope(Dart_Handle dart_handle) : dart_handle_(dart_handle) {
42  Acquire();
43  }
44 
45  explicit ByteDataScope(size_t size) {
46  dart_handle_ = Dart_NewTypedData(Dart_TypedData_kByteData, size);
47  FML_DCHECK(!tonic::LogIfError(dart_handle_));
48  Acquire();
49  FML_DCHECK(size == size_);
50  }
51 
52  ~ByteDataScope() {
53  if (is_valid_) {
54  Release();
55  }
56  }
57 
58  void* data() const { return data_; }
59  size_t size() const { return size_; }
60  Dart_Handle dart_handle() const { return dart_handle_; }
61  bool is_valid() const { return is_valid_; }
62 
63  void Release() {
64  FML_DCHECK(is_valid_);
65  Dart_Handle result = Dart_TypedDataReleaseData(dart_handle_);
66  tonic::LogIfError(result);
67  is_valid_ = false;
68  data_ = nullptr;
69  size_ = 0;
70  }
71 
72  private:
73  void Acquire() {
74  FML_DCHECK(size_ == 0);
75  FML_DCHECK(data_ == nullptr);
76  FML_DCHECK(!is_valid_);
77 
78  Dart_TypedData_Type type;
79  intptr_t size;
80  Dart_Handle result =
81  Dart_TypedDataAcquireData(dart_handle_, &type, &data_, &size);
82  is_valid_ =
83  !tonic::LogIfError(result) && type == Dart_TypedData_kByteData && data_;
84  if (is_valid_) {
85  size_ = size;
86  } else {
87  size_ = 0;
88  }
89  }
90 
91  Dart_Handle dart_handle_;
92  bool is_valid_ = false;
93  size_t size_ = 0;
94  void* data_ = nullptr;
95 };
96 
97 Dart_Handle MakeHandleList(const std::vector<zx_handle_t>& in_handles) {
98  tonic::DartClassLibrary& class_library =
100  Dart_Handle handle_type = class_library.GetClass("zircon", "Handle");
101  Dart_Handle list = Dart_NewListOfTypeFilled(
102  handle_type, Handle::CreateInvalid(), in_handles.size());
103  if (Dart_IsError(list))
104  return list;
105  for (size_t i = 0; i < in_handles.size(); i++) {
106  Dart_Handle result =
107  Dart_ListSetAt(list, i, ToDart(Handle::Create(in_handles[i])));
108  if (Dart_IsError(result))
109  return result;
110  }
111  return list;
112 }
113 
114 template <class... Args>
115 Dart_Handle ConstructDartObject(const char* class_name, Args&&... args) {
116  tonic::DartClassLibrary& class_library =
118  Dart_Handle type =
119  Dart_HandleFromPersistent(class_library.GetClass("zircon", class_name));
121 
122  const char* cstr;
123  Dart_StringToCString(Dart_ToString(type), &cstr);
124 
125  std::array<Dart_Handle, sizeof...(Args)> args_array{
126  {std::forward<Args>(args)...}};
127  Dart_Handle object =
128  Dart_New(type, Dart_EmptyString(), sizeof...(Args), args_array.data());
129  FML_DCHECK(!tonic::LogIfError(object));
130  return object;
131 }
132 
133 fdio_ns_t* GetNamespace() {
134  // Grab the fdio_ns_t* out of the isolate.
135  Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon"));
136  FML_DCHECK(!tonic::LogIfError(zircon_lib));
137  Dart_Handle namespace_type =
138  Dart_GetType(zircon_lib, ToDart("_Namespace"), 0, nullptr);
139  FML_DCHECK(!tonic::LogIfError(namespace_type));
140  Dart_Handle namespace_field =
141  Dart_GetField(namespace_type, ToDart("_namespace"));
142  FML_DCHECK(!tonic::LogIfError(namespace_field));
143  uint64_t fdio_ns_ptr;
144  Dart_Handle result = Dart_IntegerToUint64(namespace_field, &fdio_ns_ptr);
145  FML_DCHECK(!tonic::LogIfError(result));
146 
147  return reinterpret_cast<fdio_ns_t*>(fdio_ns_ptr);
148 }
149 
150 fml::UniqueFD FdFromPath(std::string path) {
151  // Get a VMO for the file.
152  fdio_ns_t* ns = reinterpret_cast<fdio_ns_t*>(GetNamespace());
153  fml::UniqueFD dirfd(fdio_ns_opendir(ns));
154  if (!dirfd.is_valid())
155  return fml::UniqueFD();
156 
157  const char* c_path = path.c_str();
158  if (path.length() > 0 && c_path[0] == '/')
159  c_path = &c_path[1];
160  return fml::UniqueFD(openat(dirfd.get(), c_path, O_RDONLY));
161 }
162 
163 } // namespace
164 
166 
167 Dart_Handle System::ChannelCreate(uint32_t options) {
168  zx_handle_t out0 = 0, out1 = 0;
169  zx_status_t status = zx_channel_create(options, &out0, &out1);
170  if (status != ZX_OK) {
171  return ConstructDartObject(kHandlePairResult, ToDart(status));
172  } else {
173  return ConstructDartObject(kHandlePairResult, ToDart(status),
174  ToDart(Handle::Create(out0)),
175  ToDart(Handle::Create(out1)));
176  }
177 }
178 
179 zx_status_t System::ConnectToService(std::string path,
180  fml::RefPtr<Handle> channel) {
181  return fdio_ns_connect(GetNamespace(), path.c_str(),
183  channel->ReleaseHandle());
184 }
185 
186 zx::channel System::CloneChannelFromFileDescriptor(int fd) {
187  zx::handle handle;
188  zx_status_t status = fdio_fd_clone(fd, handle.reset_and_get_address());
189  if (status != ZX_OK)
190  return zx::channel();
191 
192  zx_info_handle_basic_t info = {};
193  status =
194  handle.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL);
195 
196  if (status != ZX_OK || info.type != ZX_OBJ_TYPE_CHANNEL)
197  return zx::channel();
198 
199  return zx::channel(handle.release());
200 }
201 
202 Dart_Handle System::ChannelFromFile(std::string path) {
203  fml::UniqueFD fd = FdFromPath(path);
204  if (!fd.is_valid()) {
205  return ConstructDartObject(kHandleResult, ToDart(ZX_ERR_IO));
206  }
207 
208  // Get channel from fd.
209  zx::channel channel = CloneChannelFromFileDescriptor(fd.get());
210  if (!channel) {
211  return ConstructDartObject(kHandleResult, ToDart(ZX_ERR_IO));
212  }
213 
214  return ConstructDartObject(kHandleResult, ToDart(ZX_OK),
215  ToDart(Handle::Create(channel.release())));
216 }
217 
219  const tonic::DartByteData& data,
220  std::vector<Handle*> handles) {
221  if (!channel || !channel->is_valid()) {
222  data.Release();
223  return ZX_ERR_BAD_HANDLE;
224  }
225 
226  std::vector<zx_handle_t> zx_handles;
227  for (Handle* handle : handles) {
228  zx_handles.push_back(handle->handle());
229  }
230 
231  zx_status_t status = zx_channel_write(channel->handle(), 0, data.data(),
232  data.length_in_bytes(),
233  zx_handles.data(), zx_handles.size());
234  // Handles are always consumed.
235  for (Handle* handle : handles) {
236  handle->ReleaseHandle();
237  }
238 
239  data.Release();
240  return status;
241 }
242 
244  if (!channel || !channel->is_valid()) {
245  return ConstructDartObject(kReadResult, ToDart(ZX_ERR_BAD_HANDLE));
246  }
247 
248  uint32_t actual_bytes = 0;
249  uint32_t actual_handles = 0;
250 
251  // Query the size of the next message.
252  zx_status_t status = zx_channel_read(channel->handle(), 0, nullptr, nullptr,
253  0, 0, &actual_bytes, &actual_handles);
254  if (status != ZX_ERR_BUFFER_TOO_SMALL) {
255  // An empty message or an error.
256  return ConstructDartObject(kReadResult, ToDart(status));
257  }
258 
259  // Allocate space for the bytes and handles.
260  ByteDataScope bytes(actual_bytes);
261  FML_DCHECK(bytes.is_valid());
262  std::vector<zx_handle_t> handles(actual_handles);
263 
264  // Make the call to actually get the message.
265  status = zx_channel_read(channel->handle(), 0, bytes.data(), handles.data(),
266  bytes.size(), handles.size(), &actual_bytes,
267  &actual_handles);
268  FML_DCHECK(status != ZX_OK || bytes.size() == actual_bytes);
269 
270  bytes.Release();
271 
272  if (status == ZX_OK) {
273  FML_DCHECK(handles.size() == actual_handles);
274 
275  // return a ReadResult object.
276  return ConstructDartObject(kReadResult, ToDart(status), bytes.dart_handle(),
277  ToDart(actual_bytes), MakeHandleList(handles));
278  } else {
279  return ConstructDartObject(kReadResult, ToDart(status));
280  }
281 }
282 
283 Dart_Handle System::EventpairCreate(uint32_t options) {
284  zx_handle_t out0 = 0, out1 = 0;
285  zx_status_t status = zx_eventpair_create(0, &out0, &out1);
286  if (status != ZX_OK) {
287  return ConstructDartObject(kHandlePairResult, ToDart(status));
288  } else {
289  return ConstructDartObject(kHandlePairResult, ToDart(status),
290  ToDart(Handle::Create(out0)),
291  ToDart(Handle::Create(out1)));
292  }
293 }
294 
295 Dart_Handle System::SocketCreate(uint32_t options) {
296  zx_handle_t out0 = 0, out1 = 0;
297  zx_status_t status = zx_socket_create(options, &out0, &out1);
298  if (status != ZX_OK) {
299  return ConstructDartObject(kHandlePairResult, ToDart(status));
300  } else {
301  return ConstructDartObject(kHandlePairResult, ToDart(status),
302  ToDart(Handle::Create(out0)),
303  ToDart(Handle::Create(out1)));
304  }
305 }
306 
308  const tonic::DartByteData& data,
309  int options) {
310  if (!socket || !socket->is_valid()) {
311  data.Release();
312  return ConstructDartObject(kWriteResult, ToDart(ZX_ERR_BAD_HANDLE));
313  }
314 
315  size_t actual;
316  zx_status_t status = zx_socket_write(socket->handle(), options, data.data(),
317  data.length_in_bytes(), &actual);
318  data.Release();
319  return ConstructDartObject(kWriteResult, ToDart(status), ToDart(actual));
320 }
321 
322 Dart_Handle System::SocketRead(fml::RefPtr<Handle> socket, size_t size) {
323  if (!socket || !socket->is_valid()) {
324  return ConstructDartObject(kReadResult, ToDart(ZX_ERR_BAD_HANDLE));
325  }
326 
327  ByteDataScope bytes(size);
328  size_t actual;
329  zx_status_t status =
330  zx_socket_read(socket->handle(), 0, bytes.data(), size, &actual);
331  bytes.Release();
332  if (status == ZX_OK) {
333  FML_DCHECK(actual <= size);
334  return ConstructDartObject(kReadResult, ToDart(status), bytes.dart_handle(),
335  ToDart(actual));
336  }
337 
338  return ConstructDartObject(kReadResult, ToDart(status));
339 }
340 
341 Dart_Handle System::VmoCreate(uint64_t size, uint32_t options) {
342  zx_handle_t vmo = ZX_HANDLE_INVALID;
343  zx_status_t status = zx_vmo_create(size, options, &vmo);
344  if (status != ZX_OK) {
345  return ConstructDartObject(kHandleResult, ToDart(status));
346  } else {
347  return ConstructDartObject(kHandleResult, ToDart(status),
348  ToDart(Handle::Create(vmo)));
349  }
350 }
351 
352 Dart_Handle System::VmoFromFile(std::string path) {
353  fml::UniqueFD fd = FdFromPath(path);
354  if (!fd.is_valid())
355  return ConstructDartObject(kFromFileResult, ToDart(ZX_ERR_IO));
356 
357  struct stat stat_struct;
358  if (fstat(fd.get(), &stat_struct) == -1)
359  return ConstructDartObject(kFromFileResult, ToDart(ZX_ERR_IO));
360  zx_handle_t vmo = ZX_HANDLE_INVALID;
361  zx_status_t status = fdio_get_vmo_clone(fd.get(), &vmo);
362  if (status != ZX_OK)
363  return ConstructDartObject(kFromFileResult, ToDart(status));
364 
365  return ConstructDartObject(kFromFileResult, ToDart(status),
366  ToDart(Handle::Create(vmo)),
367  ToDart(stat_struct.st_size));
368 }
369 
371  if (!vmo || !vmo->is_valid()) {
372  return ConstructDartObject(kGetSizeResult, ToDart(ZX_ERR_BAD_HANDLE));
373  }
374 
375  uint64_t size;
376  zx_status_t status = zx_vmo_get_size(vmo->handle(), &size);
377 
378  return ConstructDartObject(kGetSizeResult, ToDart(status), ToDart(size));
379 }
380 
381 zx_status_t System::VmoSetSize(fml::RefPtr<Handle> vmo, uint64_t size) {
382  if (!vmo || !vmo->is_valid()) {
383  return ZX_ERR_BAD_HANDLE;
384  }
385  return zx_vmo_set_size(vmo->handle(), size);
386 }
387 
389  uint64_t offset,
390  const tonic::DartByteData& data) {
391  if (!vmo || !vmo->is_valid()) {
392  data.Release();
393  return ZX_ERR_BAD_HANDLE;
394  }
395 
396  zx_status_t status =
397  zx_vmo_write(vmo->handle(), data.data(), offset, data.length_in_bytes());
398 
399  data.Release();
400  return status;
401 }
402 
404  uint64_t offset,
405  size_t size) {
406  if (!vmo || !vmo->is_valid()) {
407  return ConstructDartObject(kReadResult, ToDart(ZX_ERR_BAD_HANDLE));
408  }
409 
410  // TODO: constrain size?
411  ByteDataScope bytes(size);
412  zx_status_t status = zx_vmo_read(vmo->handle(), bytes.data(), offset, size);
413  bytes.Release();
414  if (status == ZX_OK) {
415  return ConstructDartObject(kReadResult, ToDart(status), bytes.dart_handle(),
416  ToDart(size));
417  }
418  return ConstructDartObject(kReadResult, ToDart(status));
419 }
420 
421 struct SizedRegion {
422  SizedRegion(void* r, size_t s) : region(r), size(s) {}
423  void* region;
424  size_t size;
425 };
426 
427 void System::VmoMapFinalizer(void* isolate_callback_data, void* peer) {
428  SizedRegion* r = reinterpret_cast<SizedRegion*>(peer);
429  zx_vmar_unmap(zx_vmar_root_self(), reinterpret_cast<uintptr_t>(r->region),
430  r->size);
431  delete r;
432 }
433 
435  if (!vmo || !vmo->is_valid())
436  return ConstructDartObject(kMapResult, ToDart(ZX_ERR_BAD_HANDLE));
437 
438  uint64_t size;
439  zx_status_t status = zx_vmo_get_size(vmo->handle(), &size);
440  if (status != ZX_OK)
441  return ConstructDartObject(kMapResult, ToDart(status));
442 
443  uintptr_t mapped_addr;
444  status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo->handle(),
445  0, size, &mapped_addr);
446  if (status != ZX_OK)
447  return ConstructDartObject(kMapResult, ToDart(status));
448 
449  void* data = reinterpret_cast<void*>(mapped_addr);
450  Dart_Handle object = Dart_NewExternalTypedData(Dart_TypedData_kUint8, data,
451  static_cast<intptr_t>(size));
452  FML_DCHECK(!tonic::LogIfError(object));
453 
454  SizedRegion* r = new SizedRegion(data, size);
455  Dart_NewFinalizableHandle(object, reinterpret_cast<void*>(r),
456  static_cast<intptr_t>(size) + sizeof(*r),
457  System::VmoMapFinalizer);
458 
459  return ConstructDartObject(kMapResult, ToDart(ZX_OK), object);
460 }
461 
462 uint64_t System::ClockGet(uint32_t clock_id) {
463  zx_time_t result = 0;
464  zx_clock_get(clock_id, &result);
465  return result;
466 }
467 
468 // clang-format: off
469 
470 #define FOR_EACH_STATIC_BINDING(V) \
471  V(System, ChannelCreate) \
472  V(System, ChannelFromFile) \
473  V(System, ChannelWrite) \
474  V(System, ChannelQueryAndRead) \
475  V(System, EventpairCreate) \
476  V(System, ConnectToService) \
477  V(System, SocketCreate) \
478  V(System, SocketWrite) \
479  V(System, SocketRead) \
480  V(System, VmoCreate) \
481  V(System, VmoFromFile) \
482  V(System, VmoGetSize) \
483  V(System, VmoSetSize) \
484  V(System, VmoRead) \
485  V(System, VmoWrite) \
486  V(System, VmoMap) \
487  V(System, ClockGet)
488 
489 // clang-format: on
490 
491 // Tonic is missing a comma.
492 #define DART_REGISTER_NATIVE_STATIC_(CLASS, METHOD) \
493  DART_REGISTER_NATIVE_STATIC(CLASS, METHOD),
494 
496 
497 void System::RegisterNatives(tonic::DartLibraryNatives* natives) {
499 }
500 
501 } // namespace dart
502 } // namespace zircon
static zx_status_t ChannelWrite(fml::RefPtr< Handle > channel, const tonic::DartByteData &data, std::vector< Handle *> handles)
Definition: system.cc:218
G_BEGIN_DECLS FlValue * args
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
static Dart_Handle EventpairCreate(uint32_t options)
Definition: system.cc:283
static Dart_Handle CreateInvalid()
Definition: handle.cc:54
Definition: handle.cc:14
const void * data() const
#define FML_DCHECK(condition)
Definition: logging.h:86
static zx_status_t VmoWrite(fml::RefPtr< Handle > vmo, uint64_t offset, const tonic::DartByteData &data)
Definition: system.cc:388
static Dart_Handle SocketWrite(fml::RefPtr< Handle > socket, const tonic::DartByteData &data, int options)
Definition: system.cc:307
Dart_PersistentHandle GetClass(const DartWrapperInfo &info)
static Dart_Handle SocketCreate(uint32_t options)
Definition: system.cc:295
static DartState * Current()
Definition: dart_state.cc:55
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
UniqueObject< int, internal::os_unix::UniqueFDTraits > UniqueFD
Definition: unique_fd.h:61
static Dart_Handle VmoFromFile(std::string path)
Definition: system.cc:352
#define ZX_FS_RIGHT_WRITABLE
Definition: system.h:23
const T & get() const
Definition: unique_object.h:87
static Dart_Handle VmoCreate(uint64_t size, uint32_t options)
Definition: system.cc:341
static fml::RefPtr< Handle > Create(zx_handle_t handle)
Definition: handle.cc:50
bool is_valid() const
Definition: unique_object.h:89
Definition: dart_vm.cc:38
static Dart_Handle ChannelQueryAndRead(fml::RefPtr< Handle > channel)
Definition: system.cc:243
#define FOR_EACH_STATIC_BINDING(V)
Definition: system.cc:470
size_t length_in_bytes() const
static zx_status_t ConnectToService(std::string path, fml::RefPtr< Handle > channel)
Definition: system.cc:179
DartClassLibrary & class_library()
Definition: dart_state.h:58
static Dart_Handle VmoMap(fml::RefPtr< Handle > vmo)
Definition: system.cc:434
SizedRegion(void *r, size_t s)
Definition: system.cc:422
#define DART_NATIVE_CALLBACK_STATIC(CLASS, METHOD)
static Dart_Handle SocketRead(fml::RefPtr< Handle > socket, size_t size)
Definition: system.cc:322
IMPLEMENT_WRAPPERTYPEINFO(zircon, Handle)
static Dart_Handle ChannelFromFile(std::string path)
Definition: system.cc:202
static Dart_Handle VmoGetSize(fml::RefPtr< Handle > vmo)
Definition: system.cc:370
static Dart_Handle VmoRead(fml::RefPtr< Handle > vmo, uint64_t offset, size_t size)
Definition: system.cc:403
Dart_Handle ToDart(const T &object)
bool LogIfError(Dart_Handle handle)
Definition: dart_error.cc:15
static Dart_Handle ChannelCreate(uint32_t options)
Definition: system.cc:167
#define DART_REGISTER_NATIVE_STATIC_(CLASS, METHOD)
Definition: system.cc:492
void Release() const
static uint64_t ClockGet(uint32_t clock_id)
Definition: system.cc:462
static zx_status_t VmoSetSize(fml::RefPtr< Handle > vmo, uint64_t size)
Definition: system.cc:381
#define ZX_FS_RIGHT_READABLE
Definition: system.h:21