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