Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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) {
50 Dart_FileOpenCallback file_open = Dart::file_open_callback();
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() {
61 Dart_FileCloseCallback file_close = Dart::file_close_callback();
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) {
78 Dart_FileWriteCallback file_write = Dart::file_write_callback();
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_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 int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static constexpr bool IsPowerOfTwo(T x)
Definition utils.h:61
void(* Dart_FileWriteCallback)(const void *data, intptr_t length, void *stream)
Definition dart_api.h:806
void(* Dart_FileCloseCallback)(void *stream)
Definition dart_api.h:819
void *(* Dart_FileOpenCallback)(const char *name, bool write)
Definition dart_api.h:775
#define ASSERT(E)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
const char * name
Definition fuchsia.cc:50
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
constexpr intptr_t kMicrosecondsPerMillisecond
Definition globals.h:561
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
constexpr intptr_t kNanosecondsPerSecond
Definition globals.h:567
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