Flutter Engine
The Flutter Engine
os_android.cc
Go to the documentation of this file.
1// Copyright (c) 2012, 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
5#include "vm/globals.h"
6#if defined(DART_HOST_OS_ANDROID)
7
8#include "vm/os.h"
9
10#include <android/log.h> // NOLINT
11#include <dlfcn.h> // NOLINT
12#include <elf.h> // NOLINT
13#include <errno.h> // NOLINT
14#include <limits.h> // NOLINT
15#include <malloc.h> // NOLINT
16#include <sys/resource.h> // NOLINT
17#include <sys/time.h> // NOLINT
18#include <sys/types.h> // NOLINT
19#include <time.h> // NOLINT
20#include <unistd.h> // NOLINT
21
22#include "platform/utils.h"
23#include "vm/code_observers.h"
24#include "vm/dart.h"
25#include "vm/image_snapshot.h"
26#include "vm/isolate.h"
27#include "vm/timeline.h"
28#include "vm/zone.h"
29
30namespace dart {
31
32DEFINE_FLAG(bool,
33 android_log_to_stderr,
34 false,
35 "Send Dart VM logs to stdout and stderr instead of the Android "
36 "system logs.");
37
38// Android CodeObservers.
39
40#ifndef PRODUCT
41
42DEFINE_FLAG(bool,
43 generate_perf_events_symbols,
44 false,
45 "Generate events symbols for profiling with perf");
46
47class PerfCodeObserver : public CodeObserver {
48 public:
49 PerfCodeObserver() : out_file_(nullptr) {
51 if (file_open == nullptr) {
52 return;
53 }
54 intptr_t pid = getpid();
55 char* filename = OS::SCreate(nullptr, "/tmp/perf-%" Pd ".map", pid);
56 out_file_ = (*file_open)(filename, true);
57 free(filename);
58 }
59
60 ~PerfCodeObserver() {
62 if ((file_close == nullptr) || (out_file_ == nullptr)) {
63 return;
64 }
65 (*file_close)(out_file_);
66 }
67
68 virtual bool IsActive() const {
69 return FLAG_generate_perf_events_symbols && (out_file_ != nullptr);
70 }
71
72 virtual void Notify(const char* name,
73 uword base,
74 uword prologue_offset,
75 uword size,
76 bool optimized,
77 const CodeComments* comments) {
79 if ((file_write == nullptr) || (out_file_ == nullptr)) {
80 return;
81 }
82 const char* marker = optimized ? "*" : "";
83 char* buffer =
84 OS::SCreate(Thread::Current()->zone(), "%" Px " %" Px " %s%s\n", base,
85 size, marker, name);
86 (*file_write)(buffer, strlen(buffer), out_file_);
87 }
88
89 private:
90 void* out_file_;
91
92 DISALLOW_COPY_AND_ASSIGN(PerfCodeObserver);
93};
94
95#endif // !PRODUCT
96
97intptr_t OS::ProcessId() {
98 return static_cast<intptr_t>(getpid());
99}
100
101static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
102 time_t seconds = static_cast<time_t>(seconds_since_epoch);
103 if (seconds != seconds_since_epoch) return false;
104 struct tm* error_code = localtime_r(&seconds, tm_result);
105 return error_code != nullptr;
106}
107
108const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
109 tm decomposed;
110 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
111 // If unsuccessful, return an empty string like V8 does.
112 return (succeeded && (decomposed.tm_zone != nullptr)) ? decomposed.tm_zone
113 : "";
114}
115
116int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
117 tm decomposed;
118 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
119 // Even if the offset was 24 hours it would still easily fit into 32 bits.
120 // If unsuccessful, return zero like V8 does.
121 return succeeded ? static_cast<int>(decomposed.tm_gmtoff) : 0;
122}
123
124int64_t OS::GetCurrentTimeMillis() {
125 return GetCurrentTimeMicros() / 1000;
126}
127
128int64_t OS::GetCurrentTimeMicros() {
129 // gettimeofday has microsecond resolution.
130 struct timeval tv;
131 if (gettimeofday(&tv, nullptr) < 0) {
132 UNREACHABLE();
133 return 0;
134 }
135 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
136}
137
139 struct timespec ts;
140 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
141 UNREACHABLE();
142 return 0;
143 }
144 // Convert to nanoseconds.
145 int64_t result = ts.tv_sec;
147 result += ts.tv_nsec;
148 return result;
149}
150
153}
154
156 int64_t ticks = GetCurrentMonotonicTicks();
158 return ticks / kNanosecondsPerMicrosecond;
159}
160
162 struct timespec ts;
163 if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) {
164 UNREACHABLE();
165 return -1;
166 }
167 int64_t result = ts.tv_sec;
169 result += (ts.tv_nsec / kNanosecondsPerMicrosecond);
170 return result;
171}
172
174#if defined(SUPPORT_TIMELINE)
175 if (Timeline::recorder_discards_clock_values()) return -1;
177#else
178 return -1;
179#endif
180}
181
182// TODO(5411554): May need to hoist these architecture dependent code
183// into a architecture specific file e.g: os_ia32_linux.cc
185#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
186 defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_RISCV64)
187 const int kMinimumAlignment = 16;
188#elif defined(TARGET_ARCH_ARM)
189 const int kMinimumAlignment = 8;
190#else
191#error Unsupported architecture.
192#endif
193 intptr_t alignment = kMinimumAlignment;
194 // TODO(5411554): Allow overriding default stack alignment for
195 // testing purposes.
196 // Flags::DebugIsInt("stackalign", &alignment);
197 ASSERT(Utils::IsPowerOfTwo(alignment));
198 ASSERT(alignment >= kMinimumAlignment);
199 return alignment;
200}
201
203 return sysconf(_SC_NPROCESSORS_ONLN);
204}
205
206void OS::Sleep(int64_t millis) {
207 int64_t micros = millis * kMicrosecondsPerMillisecond;
208 SleepMicros(micros);
209}
210
211void OS::SleepMicros(int64_t micros) {
212 struct timespec req; // requested.
213 struct timespec rem; // remainder.
214 int64_t seconds = micros / kMicrosecondsPerSecond;
215 micros = micros - seconds * kMicrosecondsPerSecond;
216 int64_t nanos = micros * kNanosecondsPerMicrosecond;
217 req.tv_sec = seconds;
218 req.tv_nsec = nanos;
219 while (true) {
220 int r = nanosleep(&req, &rem);
221 if (r == 0) {
222 break;
223 }
224 // We should only ever see an interrupt error.
225 ASSERT(errno == EINTR);
226 // Copy remainder into requested and repeat.
227 req = rem;
228 }
229}
230
231void OS::DebugBreak() {
232 __builtin_trap();
233}
234
235DART_NOINLINE uintptr_t OS::GetProgramCounter() {
236 return reinterpret_cast<uintptr_t>(
237 __builtin_extract_return_addr(__builtin_return_address(0)));
238}
239
240void OS::Print(const char* format, ...) {
241 va_list args;
243 if (FLAG_android_log_to_stderr) {
244 vfprintf(stderr, format, args);
245 } else {
246 // Forward to the Android log for remote access.
247 __android_log_vprint(ANDROID_LOG_INFO, "DartVM", format, args);
248 }
249 va_end(args);
250}
251
252void OS::VFPrint(FILE* stream, const char* format, va_list args) {
253 vfprintf(stream, format, args);
254 fflush(stream);
255}
256
257char* OS::SCreate(Zone* zone, const char* format, ...) {
258 va_list args;
260 char* buffer = VSCreate(zone, format, args);
261 va_end(args);
262 return buffer;
263}
264
265char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
266 // Measure.
267 va_list measure_args;
268 va_copy(measure_args, args);
269 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
270 va_end(measure_args);
271
272 char* buffer;
273 if (zone) {
274 buffer = zone->Alloc<char>(len + 1);
275 } else {
276 buffer = reinterpret_cast<char*>(malloc(len + 1));
277 }
278 ASSERT(buffer != nullptr);
279
280 // Print.
281 va_list print_args;
282 va_copy(print_args, args);
283 Utils::VSNPrint(buffer, len + 1, format, print_args);
284 va_end(print_args);
285 return buffer;
286}
287
288bool OS::StringToInt64(const char* str, int64_t* value) {
289 ASSERT(str != nullptr && strlen(str) > 0 && value != nullptr);
290 int32_t base = 10;
291 char* endptr;
292 int i = 0;
293 if (str[0] == '-') {
294 i = 1;
295 } else if (str[0] == '+') {
296 i = 1;
297 }
298 if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
299 (str[i + 2] != '\0')) {
300 base = 16;
301 }
302 errno = 0;
303 if (base == 16) {
304 // Unsigned 64-bit hexadecimal integer literals are allowed but
305 // immediately interpreted as signed 64-bit integers.
306 *value = static_cast<int64_t>(strtoull(str, &endptr, base));
307 } else {
308 *value = strtoll(str, &endptr, base);
309 }
310 return ((errno == 0) && (endptr != str) && (*endptr == 0));
311}
312
314#ifndef PRODUCT
315 if (FLAG_generate_perf_events_symbols) {
316 CodeObservers::Register(new PerfCodeObserver);
317 }
318#endif // !PRODUCT
319}
320
321void OS::PrintErr(const char* format, ...) {
322 va_list args;
324 if (FLAG_android_log_to_stderr) {
325 vfprintf(stderr, format, args);
326 } else {
327 // Forward to the Android log for remote access.
328 __android_log_vprint(ANDROID_LOG_ERROR, "DartVM", format, args);
329 }
330 va_end(args);
331}
332
333void OS::Init() {}
334
335void OS::Cleanup() {}
336
337void OS::PrepareToAbort() {}
338
339void OS::Abort() {
341 abort();
342}
343
344void OS::Exit(int code) {
345 exit(code);
346}
347
348// Used to choose between Elf32/Elf64 types based on host archotecture bitsize.
349#if defined(ARCH_IS_64_BIT)
350#define ElfW(Type) Elf64_##Type
351#else
352#define ElfW(Type) Elf32_##Type
353#endif
354
355OS::BuildId OS::GetAppBuildId(const uint8_t* snapshot_instructions) {
356 // First return the build ID information from the instructions image if
357 // available.
358 const Image instructions_image(snapshot_instructions);
359 if (auto* const image_build_id = instructions_image.build_id()) {
360 return {instructions_image.build_id_length(), image_build_id};
361 }
362 const uint8_t* dso_base = GetAppDSOBase(snapshot_instructions);
363 const ElfW(Ehdr)& elf_header = *reinterpret_cast<const ElfW(Ehdr)*>(dso_base);
364 const ElfW(Phdr)* const phdr_array =
365 reinterpret_cast<const ElfW(Phdr)*>(dso_base + elf_header.e_phoff);
366 for (intptr_t i = 0; i < elf_header.e_phnum; i++) {
367 const ElfW(Phdr)& header = phdr_array[i];
368 if (header.p_type != PT_NOTE) continue;
369 if ((header.p_flags & PF_R) != PF_R) continue;
370 const uint8_t* const note_addr = dso_base + header.p_vaddr;
371 const Elf32_Nhdr& note_header =
372 *reinterpret_cast<const Elf32_Nhdr*>(note_addr);
373 if (note_header.n_type != NT_GNU_BUILD_ID) continue;
374 const char* const note_contents =
375 reinterpret_cast<const char*>(note_addr + sizeof(Elf32_Nhdr));
376 // The note name contains the null terminator as well.
377 if (note_header.n_namesz != strlen(ELF_NOTE_GNU) + 1) continue;
378 if (strncmp(ELF_NOTE_GNU, note_contents, note_header.n_namesz) == 0) {
379 return {static_cast<intptr_t>(note_header.n_descsz),
380 reinterpret_cast<const uint8_t*>(note_contents +
381 note_header.n_namesz)};
382 }
383 }
384 return {0, nullptr};
385}
386
387} // namespace dart
388
389#endif // defined(DART_HOST_OS_ANDROID)
static const char marker[]
#define UNREACHABLE()
Definition: assert.h:248
static void Register(CodeObserver *observer)
static Dart_FileWriteCallback file_write_callback()
Definition: dart.h:125
static Dart_FileOpenCallback file_open_callback()
Definition: dart.h:119
static Dart_FileCloseCallback file_close_callback()
Definition: dart.h:128
static DART_NORETURN void Exit(int code)
static int NumberOfAvailableProcessors()
static const char * GetTimeZoneName(int64_t seconds_since_epoch)
static void SleepMicros(int64_t micros)
static int64_t GetCurrentTimeMillis()
static void RegisterCodeObservers()
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void Sleep(int64_t millis)
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static bool StringToInt64(const char *str, int64_t *value)
static BuildId GetAppBuildId(const uint8_t *snapshot_instructions)
static const uint8_t * GetAppDSOBase(const uint8_t *snapshot_instructions)
Definition: os.cc:13
static void Init()
static int64_t GetCurrentTimeMicros()
static intptr_t ActivationFrameAlignment()
static void static void static void VFPrint(FILE *stream, const char *format, va_list args)
static void Cleanup()
static void DebugBreak()
static DART_NORETURN void Abort()
static char static char * VSCreate(Zone *zone, const char *format, va_list args)
static int64_t GetCurrentThreadCPUMicros()
static uintptr_t GetProgramCounter()
static intptr_t ProcessId()
static void PrepareToAbort()
static int64_t GetCurrentMonotonicFrequency()
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static int64_t GetCurrentMonotonicTicks()
static int64_t GetCurrentMonotonicMicrosForTimeline()
static int GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch)
static Thread * Current()
Definition: thread.h:362
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static constexpr bool IsPowerOfTwo(T x)
Definition: utils.h:76
void(* Dart_FileWriteCallback)(const void *data, intptr_t length, void *stream)
Definition: dart_api.h:807
void(* Dart_FileCloseCallback)(void *stream)
Definition: dart_api.h:820
void *(* Dart_FileOpenCallback)(const char *name, bool write)
Definition: dart_api.h:776
#define ASSERT(E)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
static constexpr intptr_t PF_R
Definition: elf.h:181
static constexpr const char ELF_NOTE_GNU[]
Definition: elf.h:199
Definition: dart_vm.cc:33
constexpr intptr_t kMicrosecondsPerMillisecond
Definition: globals.h:561
const char *const name
constexpr intptr_t kMicrosecondsPerSecond
Definition: globals.h:562
constexpr intptr_t kNanosecondsPerMicrosecond
Definition: globals.h:564
void * malloc(size_t size)
Definition: allocation.cc:19
uintptr_t uword
Definition: globals.h:501
constexpr intptr_t kNanosecondsPerSecond
Definition: globals.h:567
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
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
CanvasImage Image
Definition: dart_ui.cc:55
#define Px
Definition: globals.h:410
#define Pd
Definition: globals.h:408
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
static const char header[]
Definition: skpbench.cpp:88