Flutter Engine
The Flutter Engine
vmservice.cc
Go to the documentation of this file.
1// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6#include "vm/dart_api_impl.h"
7#include "vm/datastream.h"
8#include "vm/exceptions.h"
9#include "vm/flags.h"
10#include "vm/growable_array.h"
11#include "vm/kernel_isolate.h"
12#include "vm/message.h"
13#include "vm/message_handler.h"
14#include "vm/message_snapshot.h"
15#include "vm/native_entry.h"
16#include "vm/object.h"
17#include "vm/port.h"
18#include "vm/service_event.h"
19#include "vm/service_isolate.h"
20#include "vm/symbols.h"
21
22namespace dart {
23
24DECLARE_FLAG(bool, trace_service);
25
26#ifndef PRODUCT
28 public:
31 zone_(thread->zone()),
32 register_function_(Function::Handle(thread->zone())),
33 service_isolate_(thread->isolate()) {}
34
35 virtual void VisitIsolate(Isolate* isolate) {
36 isolate_ports_.Add(isolate->main_port());
37 isolate_names_.Add(&String::Handle(zone_, String::New(isolate->name())));
38 isolate->set_is_service_registered(true);
39 }
40
42 ServiceIsolate::RegisterRunningIsolates(isolate_ports_, isolate_names_);
43 }
44
45 private:
46 Zone* zone_;
47 GrowableArray<Dart_Port> isolate_ports_;
48 GrowableArray<const String*> isolate_names_;
49 Function& register_function_;
50 Isolate* service_isolate_;
51};
52#endif // !PRODUCT
53
54DEFINE_NATIVE_ENTRY(VMService_SendIsolateServiceMessage, 0, 2) {
55#ifndef PRODUCT
56 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
57 GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
58
59 // Set the type of the OOB message.
60 message.SetAt(0,
62
63 // Serialize message.
64 // TODO(turnidge): Throw an exception when the return value is false?
66 /* same_group */ false, message, sp.Id(), Message::kOOBPriority));
67 return Bool::Get(result).ptr();
68#else
69 return Object::null();
70#endif
71}
72
73DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 0, 1) {
74#ifndef PRODUCT
75 GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
77#endif
78 return Object::null();
79}
80
81DEFINE_NATIVE_ENTRY(VMService_SendObjectRootServiceMessage, 0, 1) {
82#ifndef PRODUCT
83 GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
85#endif
86 return Object::null();
87}
88
89DEFINE_NATIVE_ENTRY(VMService_OnStart, 0, 0) {
90#ifndef PRODUCT
91 if (FLAG_trace_service) {
92 OS::PrintErr("vm-service: Booting dart:vmservice library.\n");
93 }
94 // Boot the dart:vmservice library.
96 // Register running isolates with service.
97 RegisterRunningIsolatesVisitor register_isolates(thread);
98 if (FLAG_trace_service) {
99 OS::PrintErr("vm-service: Registering running isolates.\n");
100 }
101 Isolate::VisitIsolates(&register_isolates);
102 register_isolates.RegisterIsolates();
103#endif
104 return Object::null();
105}
106
107DEFINE_NATIVE_ENTRY(VMService_OnExit, 0, 0) {
108#ifndef PRODUCT
109 if (FLAG_trace_service) {
110 OS::PrintErr("vm-service: processed exit message.\n");
111 OS::PrintErr("vm-service: has live ports: %s\n",
112 isolate->HasLivePorts() ? "yes" : "no");
113 }
114#endif
115 return Object::null();
116}
117
118DEFINE_NATIVE_ENTRY(VMService_OnServerAddressChange, 0, 1) {
119#ifndef PRODUCT
120 GET_NATIVE_ARGUMENT(String, address, arguments->NativeArgAt(0));
121 if (address.IsNull()) {
123 } else {
124 ServiceIsolate::SetServerAddress(address.ToCString());
125 }
126#endif
127 return Object::null();
128}
129
130DEFINE_NATIVE_ENTRY(VMService_ListenStream, 0, 2) {
131#ifndef PRODUCT
132 GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
133 GET_NON_NULL_NATIVE_ARGUMENT(Bool, include_privates,
134 arguments->NativeArgAt(1));
135 bool result =
136 Service::ListenStream(stream_id.ToCString(), include_privates.value());
137 return Bool::Get(result).ptr();
138#else
139 return Object::null();
140#endif
141}
142
143DEFINE_NATIVE_ENTRY(VMService_CancelStream, 0, 1) {
144#ifndef PRODUCT
145 GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
146 Service::CancelStream(stream_id.ToCString());
147#endif
148 return Object::null();
149}
150
151DEFINE_NATIVE_ENTRY(VMService_RequestAssets, 0, 0) {
152#ifndef PRODUCT
153 return Service::RequestAssets();
154#else
155 return Object::null();
156#endif
157}
158
159#ifndef PRODUCT
160// TODO(25041): When reading, this class copies out the filenames and contents
161// into new buffers. It does this because the lifetime of |bytes| is uncertain.
162// If |bytes| is pinned in memory, then we could instead load up
163// |filenames_| and |contents_| with pointers into |bytes| without making
164// copies.
166 public:
167 TarArchive(uint8_t* bytes, intptr_t bytes_length)
168 : rs_(bytes, bytes_length) {}
169
170 void Read() {
171 while (HasNext()) {
172 char* filename;
173 uint8_t* data;
174 intptr_t data_length;
175 if (Next(&filename, &data, &data_length)) {
176 filenames_.Add(filename);
177 contents_.Add(data);
178 content_lengths_.Add(data_length);
179 }
180 }
181 }
182
183 char* NextFilename() { return filenames_.RemoveLast(); }
184
185 uint8_t* NextContent() { return contents_.RemoveLast(); }
186
187 intptr_t NextContentLength() { return content_lengths_.RemoveLast(); }
188
189 bool HasMore() const { return filenames_.length() > 0; }
190
191 intptr_t Length() const { return filenames_.length(); }
192
193 private:
194 enum TarHeaderFields {
195 kTarHeaderFilenameOffset = 0,
196 kTarHeaderFilenameSize = 100,
197 kTarHeaderSizeOffset = 124,
198 kTarHeaderSizeSize = 12,
199 kTarHeaderTypeOffset = 156,
200 kTarHeaderTypeSize = 1,
201 kTarHeaderSize = 512,
202 };
203
204 enum TarType {
205 kTarAregType = '\0',
206 kTarRegType = '0',
207 kTarLnkType = '1',
208 kTarSymType = '2',
209 kTarChrType = '3',
210 kTarBlkType = '4',
211 kTarDirType = '5',
212 kTarFifoType = '6',
213 kTarContType = '7',
214 kTarXhdType = 'x',
215 kTarXglType = 'g',
216 };
217
218 bool HasNext() const { return !EndOfArchive(); }
219
220 bool Next(char** filename, uint8_t** data, intptr_t* data_length) {
221 intptr_t startOfBlock = rs_.Position();
222 *filename = ReadFilename();
223 rs_.SetPosition(startOfBlock + kTarHeaderSizeOffset);
224 intptr_t size = ReadSize();
225 rs_.SetPosition(startOfBlock + kTarHeaderTypeOffset);
226 TarType type = ReadType();
227 SeekToNextBlock(kTarHeaderSize);
228 if ((type != kTarRegType) && (type != kTarAregType)) {
229 SkipContents(size);
230 return false;
231 }
232 ReadContents(data, size);
233 *data_length = size;
234 return true;
235 }
236
237 void SeekToNextBlock(intptr_t blockSize) {
238 intptr_t remainder = blockSize - (rs_.Position() % blockSize);
239 rs_.Advance(remainder);
240 }
241
242 uint8_t PeekByte(intptr_t i) const {
243 return *(rs_.AddressOfCurrentPosition() + i);
244 }
245
246 bool EndOfArchive() const {
247 if (rs_.PendingBytes() < (kTarHeaderSize * 2)) {
248 return true;
249 }
250 for (intptr_t i = 0; i < (kTarHeaderSize * 2); i++) {
251 if (PeekByte(i) != 0) {
252 return false;
253 }
254 }
255 return true;
256 }
257
258 TarType ReadType() {
259 return static_cast<TarType>(ReadStream::Raw<1, uint8_t>::Read(&rs_));
260 }
261
262 void SkipContents(intptr_t size) {
263 rs_.Advance(size);
264 SeekToNextBlock(kTarHeaderSize);
265 }
266
267 intptr_t ReadCString(char** s, intptr_t length) {
268 intptr_t to_read = Utils::Minimum(length, rs_.PendingBytes());
269 char* result = new char[to_read + 1];
270 strncpy(result,
271 reinterpret_cast<const char*>(rs_.AddressOfCurrentPosition()),
272 to_read);
273 result[to_read] = '\0';
274 rs_.SetPosition(rs_.Position() + to_read);
275 *s = result;
276 return to_read;
277 }
278
279 intptr_t ReadSize() {
280 char* octalSize;
281 unsigned int size;
282
283 ReadCString(&octalSize, kTarHeaderSizeSize);
284 int result = sscanf(octalSize, "%o", &size);
285 delete[] octalSize;
286
287 if (result != 1) {
288 return 0;
289 }
290 return size;
291 }
292
293 char* ReadFilename() {
294 char* result;
295 intptr_t result_length = ReadCString(&result, kTarHeaderFilenameSize);
296 if (result[0] == '/') {
297 return result;
298 }
299 char* fixed_result = new char[result_length + 2]; // '/' + '\0'.
300 fixed_result[0] = '/';
301 strncpy(&fixed_result[1], result, result_length);
302 fixed_result[result_length + 1] = '\0';
303 delete[] result;
304 return fixed_result;
305 }
306
307 void ReadContents(uint8_t** data, intptr_t size) {
308 uint8_t* result = new uint8_t[size];
309 rs_.ReadBytes(result, size);
310 SeekToNextBlock(kTarHeaderSize);
311 *data = result;
312 }
313
314 ReadStream rs_;
315 GrowableArray<char*> filenames_;
316 GrowableArray<uint8_t*> contents_;
317 GrowableArray<intptr_t> content_lengths_;
318
319 DISALLOW_COPY_AND_ASSIGN(TarArchive);
320};
321
322static void ContentsFinalizer(void* isolate_callback_data, void* peer) {
323 uint8_t* data = reinterpret_cast<uint8_t*>(peer);
324 delete[] data;
325}
326
327#endif
328
329DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 0, 1) {
330#ifndef PRODUCT
331 GET_NON_NULL_NATIVE_ARGUMENT(TypedData, data, arguments->NativeArgAt(0));
332 Api::Scope scope(thread);
333 Dart_Handle data_handle = Api::NewHandle(thread, data.ptr());
334 Dart_Handle result_list;
335 {
336 TransitionVMToNative transition(thread);
337
339 void* bytes;
340 intptr_t length;
341 Dart_Handle err =
342 Dart_TypedDataAcquireData(data_handle, &typ, &bytes, &length);
343 ASSERT(!Dart_IsError(err));
344
345 TarArchive archive(reinterpret_cast<uint8_t*>(bytes), length);
346 archive.Read();
347
348 err = Dart_TypedDataReleaseData(data_handle);
349 ASSERT(!Dart_IsError(err));
350
351 intptr_t archive_size = archive.Length();
352
353 result_list = Dart_NewList(2 * archive_size);
354 ASSERT(!Dart_IsError(result_list));
355
356 intptr_t idx = 0;
357 while (archive.HasMore()) {
358 char* filename = archive.NextFilename();
359 intptr_t filename_length = strlen(filename);
360 uint8_t* contents = archive.NextContent();
361 intptr_t contents_length = archive.NextContentLength();
362
363 Dart_Handle dart_filename = Dart_NewStringFromUTF8(
364 reinterpret_cast<uint8_t*>(filename), filename_length);
365 ASSERT(!Dart_IsError(dart_filename));
366
368 Dart_TypedData_kUint8, contents, contents_length, contents,
369 contents_length, ContentsFinalizer);
370 ASSERT(!Dart_IsError(dart_contents));
371
372 Dart_ListSetAt(result_list, idx, dart_filename);
373 Dart_ListSetAt(result_list, (idx + 1), dart_contents);
374 idx += 2;
375 }
376 }
377 return Api::UnwrapArrayHandle(thread->zone(), result_list).ptr();
378#else
379 return Object::null();
380#endif
381}
382
383#ifndef PRODUCT
385 public:
387 const GrowableObjectArray* user_tags,
388 bool set_streamable)
389 : IsolateVisitor(),
390 thread_(thread),
391 user_tags_(user_tags),
392 set_streamable_(set_streamable) {}
393
394 virtual void VisitIsolate(Isolate* isolate) {
395 if (Isolate::IsVMInternalIsolate(isolate)) {
396 return;
397 }
398 Zone* zone = thread_->zone();
399 UserTag& tag = UserTag::Handle(zone);
400 String& label = String::Handle(zone);
401 for (intptr_t i = 0; i < user_tags_->Length(); ++i) {
402 label ^= user_tags_->At(i);
403 tag ^= UserTag::FindTagInIsolate(isolate, thread_, label);
404 if (!tag.IsNull()) {
405 tag.set_streamable(set_streamable_);
406 }
407 }
408 }
409
410 private:
411 Thread* thread_;
412 const GrowableObjectArray* user_tags_;
413 bool set_streamable_;
414
415 DISALLOW_COPY_AND_ASSIGN(UserTagIsolatesVisitor);
416};
417#endif // !PRODUCT
418
419DEFINE_NATIVE_ENTRY(VMService_AddUserTagsToStreamableSampleList, 0, 1) {
420#ifndef PRODUCT
422 arguments->NativeArgAt(0));
423
424 Object& obj = Object::Handle();
425 for (intptr_t i = 0; i < user_tags.Length(); ++i) {
426 obj = user_tags.At(i);
428 }
429 UserTagIsolatesVisitor visitor(thread, &user_tags, true);
430 Isolate::VisitIsolates(&visitor);
431#endif
432 return Object::null();
433}
434
435DEFINE_NATIVE_ENTRY(VMService_RemoveUserTagsFromStreamableSampleList, 0, 1) {
436#ifndef PRODUCT
438 arguments->NativeArgAt(0));
439
440 Object& obj = Object::Handle();
441 for (intptr_t i = 0; i < user_tags.Length(); ++i) {
442 obj = user_tags.At(i);
444 }
445 UserTagIsolatesVisitor visitor(thread, &user_tags, false);
446 Isolate::VisitIsolates(&visitor);
447#endif
448 return Object::null();
449}
450
451} // namespace dart
GLenum type
static Dart_Handle NewHandle(Thread *thread, ObjectPtr raw)
void Add(const T &value)
intptr_t length() const
static const Bool & Get(bool value)
Definition: object.h:10801
intptr_t Length() const
Definition: object.h:11072
ObjectPtr At(intptr_t index) const
Definition: object.h:11085
static bool IsVMInternalIsolate(const Isolate *isolate)
Definition: isolate.cc:3609
static void VisitIsolates(IsolateVisitor *visitor)
Definition: isolate.cc:3531
void set_is_service_registered(bool value)
Definition: isolate.h:1388
Dart_Port main_port() const
Definition: isolate.h:1048
const char * name() const
Definition: isolate.h:1043
@ kServiceOOBMsg
Definition: message.h:41
@ kOOBPriority
Definition: message.h:29
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
virtual const char * ToCString() const
Definition: object.h:366
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static bool PostMessage(std::unique_ptr< Message > message, bool before_events=false)
Definition: port.cc:152
intptr_t Position() const
Definition: datastream.h:127
intptr_t PendingBytes() const
Definition: datastream.h:147
const uint8_t * AddressOfCurrentPosition() const
Definition: datastream.h:140
void Advance(intptr_t value)
Definition: datastream.h:142
void SetPosition(intptr_t value)
Definition: datastream.h:128
void ReadBytes(void *addr, intptr_t len)
Definition: datastream.h:90
virtual void VisitIsolate(Isolate *isolate)
Definition: vmservice.cc:35
RegisterRunningIsolatesVisitor(Thread *thread)
Definition: vmservice.cc:29
static void RegisterRunningIsolates(const GrowableArray< Dart_Port > &isolate_ports, const GrowableArray< const String * > &isolate_names)
static void SetServerAddress(const char *address)
static void BootVmServiceLibrary()
static ErrorPtr HandleRootMessage(const Array &message)
Definition: service.cc:1059
static void CancelStream(const char *stream_id)
Definition: service.cc:448
static bool ListenStream(const char *stream_id, bool include_privates)
Definition: service.cc:427
static ObjectPtr RequestAssets()
Definition: service.cc:466
static ErrorPtr HandleObjectRootMessage(const Array &message)
Definition: service.cc:1064
static SmiPtr New(intptr_t value)
Definition: object.h:10006
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
TarArchive(uint8_t *bytes, intptr_t bytes_length)
Definition: vmservice.cc:167
bool HasMore() const
Definition: vmservice.cc:189
uint8_t * NextContent()
Definition: vmservice.cc:185
char * NextFilename()
Definition: vmservice.cc:183
intptr_t Length() const
Definition: vmservice.cc:191
intptr_t NextContentLength()
Definition: vmservice.cc:187
Zone * zone() const
Definition: thread_state.h:37
virtual void VisitIsolate(Isolate *isolate)
Definition: vmservice.cc:394
UserTagIsolatesVisitor(Thread *thread, const GrowableObjectArray *user_tags, bool set_streamable)
Definition: vmservice.cc:386
void set_streamable(bool streamable)
Definition: object.h:13162
static UserTagPtr FindTagInIsolate(Isolate *isolate, Thread *thread, const String &label)
Definition: object.cc:26991
static void RemoveStreamableTagName(const char *tag)
Definition: tags.cc:163
static void AddStreamableTagName(const char *tag)
Definition: tags.cc:152
static T Minimum(T x, T y)
Definition: utils.h:36
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
Dart_TypedData_Type
Definition: dart_api.h:2612
@ Dart_TypedData_kUint8
Definition: dart_api.h:2615
#define ASSERT(E)
struct MyStruct s
GAsyncResult * result
size_t length
Win32Message message
SK_API bool Read(SkStreamSeekable *src, SkDocumentPage *dstArray, int dstArrayCount, const SkDeserialProcs *=nullptr)
Definition: dart_vm.cc:33
DART_EXPORT Dart_Handle Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type, void *data, intptr_t length, void *peer, intptr_t external_allocation_size, Dart_HandleFinalizer callback)
DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t *utf8_array, intptr_t length)
DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, Dart_TypedData_Type *type, void **data, intptr_t *len)
DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list, intptr_t index, Dart_Handle value)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
static void ContentsFinalizer(void *isolate_callback_data, void *peer)
Definition: vmservice.cc:322
DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object)
std::unique_ptr< Message > WriteMessage(bool same_group, const Object &obj, Dart_Port dest_port, Message::Priority priority)
DEFINE_NATIVE_ENTRY(List_allocate, 0, 2)
Definition: array.cc:13
DART_EXPORT Dart_Handle Dart_NewList(intptr_t length)
static int8_t data[kExtLength]
DECLARE_FLAG(bool, show_invisible_frames)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
#define GET_NATIVE_ARGUMENT(type, name, value)
Definition: native_entry.h:84
#define GET_NON_NULL_NATIVE_ARGUMENT(type, name, value)
Definition: native_entry.h:74