6#if defined(DART_HOST_OS_FUCHSIA)
18#include <fuchsia/intl/cpp/fidl.h>
19#include <lib/async-loop/default.h>
20#include <lib/async-loop/loop.h>
21#include <lib/async/default.h>
22#include <lib/inspect/component/cpp/component.h>
23#include <lib/inspect/cpp/inspect.h>
24#include <lib/sys/cpp/component_context.h>
25#include <lib/sys/cpp/service_directory.h>
26#include <zircon/process.h>
27#include <zircon/syscalls.h>
28#include <zircon/syscalls/object.h>
29#include <zircon/threads.h>
30#include <zircon/time.h>
31#include <zircon/types.h>
35#include "unicode/errorcode.h"
36#include "unicode/timezone.h"
37#include "unicode/umachine.h"
56static const char kDefaultTimezone[] =
"UTC";
58static constexpr int32_t kMsPerSec = 1000;
61static constexpr char kICUTZDataDir[] =
"/config/data/tzdata/icu/44/le";
66static constexpr char kICUTZDataDir2[] =
"/config/tzdata/icu/44/le";
69static constexpr int32_t
kOk = 0;
76enum class TZDataStatus {
92 explicit InspectMetrics(std::unique_ptr<inspect::Node> vm_node)
93 : vm_node_(
std::move(vm_node)),
95 tz_data_status_(vm_node_->CreateInt(
"tz_data_status",
kUninitialized)),
96 tz_data_close_status_(
100 profiles_timezone_content_status_(
101 vm_node_->CreateInt(
"timezone_content_status",
kOk)),
102 num_get_profile_calls_(vm_node_->CreateInt(
"num_get_profile_calls", 0)),
103 num_on_change_calls_(vm_node_->CreateInt(
"num_on_change_calls", 0)),
104 num_intl_provider_errors_(
105 vm_node_->CreateInt(
"num_intl_provider_errors", 0)) {}
108 void RegisterGetProfileCall() { num_get_profile_calls_.Add(1); }
111 void RegisterOnChangeCall() { num_on_change_calls_.Add(1); }
114 void RegisterIntlProviderError() { num_intl_provider_errors_.Add(1); }
117 void SetDSTOffsetStatus(zx_status_t status) {
118 dst_status_.Set(
static_cast<int32_t
>(status));
123 void SetInitTzData(TZDataStatus
value, int32_t status) {
124 tz_data_status_.Set(
static_cast<int32_t
>(
value));
125 tz_data_close_status_.Set(status);
129 void SetProfileStatus(zx_status_t status) {
130 get_profile_status_.Set(
static_cast<int32_t
>(status));
135 void SetTimeZoneContentStatus(zx_status_t status) {
136 profiles_timezone_content_status_.Set(
static_cast<int32_t
>(status));
141 std::unique_ptr<inspect::Node> vm_node_;
144 inspect::IntProperty dst_status_;
147 inspect::IntProperty tz_data_status_;
150 inspect::IntProperty tz_data_close_status_;
154 inspect::IntProperty get_profile_status_;
159 inspect::IntProperty profiles_timezone_content_status_;
162 inspect::IntProperty num_get_profile_calls_;
165 inspect::IntProperty num_on_change_calls_;
168 inspect::IntProperty num_intl_provider_errors_;
175class TimezoneName final {
179 static std::shared_ptr<TimezoneName> New(
180 fuchsia::intl::PropertyProviderPtr proxy,
181 std::weak_ptr<InspectMetrics> metrics) {
183 std::make_shared<TimezoneName>(std::move(proxy), metrics);
184 timezone_name->InitHandlers(timezone_name);
185 return timezone_name;
188 TimezoneName(fuchsia::intl::PropertyProviderPtr proxy,
189 std::weak_ptr<InspectMetrics> metrics)
191 metrics_(
std::move(metrics)),
192 proxy_(
std::move(proxy)),
193 timezone_name_(kDefaultTimezone) {
194 ASSERT(metrics_.lock() !=
nullptr);
199 std::string
Get()
const {
200 MutexLocker lock(&m_);
202 return timezone_name_;
208 void InitHandlers(std::shared_ptr<TimezoneName> timezone_name) {
209 ASSERT(timezone_name.get() ==
this);
210 timezone_name->proxy_.set_error_handler(
212 std::weak_ptr<TimezoneName>(timezone_name)](zx_status_t status) {
213 if (!weak_this.expired()) {
214 weak_this.lock()->ErrorHandler(status);
217 timezone_name->proxy_.events().OnChange =
218 [weak_this = std::weak_ptr<TimezoneName>(timezone_name)]() {
219 if (!weak_this.expired()) {
220 weak_this.lock()->OnChangeCallback();
223 timezone_name->proxy_->GetProfile(
224 [weak_this = std::weak_ptr<TimezoneName>(timezone_name)](
225 fuchsia::intl::Profile
profile) {
226 if (!weak_this.expired()) {
227 weak_this.lock()->GetProfileCallback(std::move(
profile));
234 void ErrorHandler(zx_status_t status) {
235 MutexLocker lock(&m_);
236 WithMetrics([status](std::shared_ptr<InspectMetrics> metrics) {
237 metrics->SetProfileStatus(status);
238 metrics->RegisterIntlProviderError();
245 void OnChangeCallback() {
246 MutexLocker lock(&m_);
247 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
248 metrics->RegisterOnChangeCall();
250 proxy_->GetProfile([
this](fuchsia::intl::Profile
profile) {
251 this->GetProfileCallback(std::move(
profile));
257 void GetProfileCallback(fuchsia::intl::Profile
profile) {
258 MutexLocker lock(&m_);
259 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
260 metrics->RegisterGetProfileCall();
262 const std::vector<fuchsia::intl::TimeZoneId>& timezones =
264 if (timezones.empty()) {
265 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
266 metrics->SetTimeZoneContentStatus(U_ILLEGAL_ARGUMENT_ERROR);
270 Syslog::PrintErr(
"got empty timezone value\n");
273 WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
274 metrics->SetProfileStatus(ZX_OK);
275 metrics->SetTimeZoneContentStatus(ZX_OK);
278 timezone_name_ = timezones[0].id;
282 void WithMetrics(
std::function<
void(std::shared_ptr<InspectMetrics>
m)>
f) {
283 std::shared_ptr<InspectMetrics> l = metrics_.lock();
294 std::weak_ptr<InspectMetrics> metrics_;
297 fuchsia::intl::PropertyProviderPtr proxy_;
301 std::string timezone_name_;
305std::set<std::string> timezone_names;
308std::shared_ptr<InspectMetrics> metrics;
309std::shared_ptr<TimezoneName> timezone_name;
310async_loop_t* message_loop =
nullptr;
314bool InitializeTZData() {
315 ASSERT(metrics !=
nullptr);
321 const char* tz_dirname = kICUTZDataDir2;
322 int fd = openat(AT_FDCWD, tz_dirname, O_RDONLY);
324 tz_dirname = kICUTZDataDir;
325 fd = openat(AT_FDCWD, tz_dirname, O_RDONLY);
328 metrics->SetInitTzData(TZDataStatus::COULD_NOT_OPEN, fd);
332 setenv(
"ICU_TIMEZONE_FILES_DIR", tz_dirname, 0);
333 int32_t close_status = close(fd);
334 if (close_status != 0) {
335 metrics->SetInitTzData(TZDataStatus::COULD_NOT_CLOSE, close_status);
338 metrics->SetInitTzData(TZDataStatus::OK, 0);
342int64_t GetCurrentTimeNanos() {
344 if (timespec_get(&ts, TIME_UTC) == 0) {
345 FATAL(
"timespec_get failed");
348 return zx_time_add_duration(ZX_SEC(ts.tv_sec), ZX_NSEC(ts.tv_nsec));
358 generate_perf_events_symbols,
360 "Generate events symbols for profiling with perf");
365 return static_cast<intptr_t
>(getpid());
374static fuchsia::intl::PropertyProviderPtr property_provider;
376static zx_status_t GetLocalAndDstOffsetInSeconds(int64_t seconds_since_epoch,
377 int32_t* local_offset,
378 int32_t* dst_offset) {
380 std::unique_ptr<icu::TimeZone> timezone(
381 icu::TimeZone::createTimeZone(timezone_id));
382 UErrorCode
error = U_ZERO_ERROR;
383 const auto ms_since_epoch =
384 static_cast<UDate
>(kMsPerSec * seconds_since_epoch);
388 int32_t local_offset_ms = 0;
389 int32_t dst_offset_ms = 0;
390 timezone->getOffset(ms_since_epoch, 0, local_offset_ms,
391 dst_offset_ms,
error);
392 metrics->SetDSTOffsetStatus(
error);
393 if (
error != U_ZERO_ERROR) {
394 icu::ErrorCode icu_error;
395 icu_error.set(
error);
397 return ZX_ERR_INTERNAL;
400 *local_offset = local_offset_ms / kMsPerSec;
401 *dst_offset = dst_offset_ms / kMsPerSec;
408 ASSERT(timezone_name !=
nullptr);
416 const auto i = timezone_names.insert(timezone_name->Get());
417 ASSERT(
i.first != timezone_names.end());
418 return i.first->c_str();
422 int32_t local_offset = 0;
423 int32_t dst_offset = 0;
424 const zx_status_t status = GetLocalAndDstOffsetInSeconds(
425 seconds_since_epoch, &local_offset, &dst_offset);
426 return status == ZX_OK ? local_offset + dst_offset : 0;
430 return GetCurrentTimeNanos() / ZX_MSEC(1);
434 return GetCurrentTimeNanos() / ZX_USEC(1);
438 return zx_clock_get_monotonic();
452 zx_info_thread_stats_t
info = {};
453 zx_status_t status = zx_object_get_info(thrd_get_zx_handle(thrd_current()),
454 ZX_INFO_THREAD_STATS, &
info,
455 sizeof(
info),
nullptr,
nullptr);
460#if defined(SUPPORT_TIMELINE)
470#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
471 defined(TARGET_ARCH_ARM64)
472 const int kMinimumAlignment = 16;
473#elif defined(TARGET_ARCH_ARM)
474 const int kMinimumAlignment = 8;
476#error Unsupported architecture.
478 intptr_t alignment = kMinimumAlignment;
483 ASSERT(alignment >= kMinimumAlignment);
488 return sysconf(_SC_NPROCESSORS_CONF);
504 return reinterpret_cast<uintptr_t
>(
505 __builtin_extract_return_addr(__builtin_return_address(0)));
530 va_list measure_args;
531 va_copy(measure_args,
args);
536 if (zone !=
nullptr) {
545 va_copy(print_args,
args);
552 ASSERT(str !=
nullptr && strlen(str) > 0 &&
value !=
nullptr);
558 }
else if (str[0] ==
'+') {
561 if ((str[
i] ==
'0') && (str[
i + 1] ==
'x' || str[
i + 1] ==
'X') &&
562 (str[
i + 2] !=
'\0')) {
569 *
value =
static_cast<int64_t
>(strtoull(str, &endptr,
base));
573 return ((errno == 0) && (endptr != str) && (*endptr == 0));
578 if (FLAG_generate_perf_events_symbols) {
592 if (async_get_default_dispatcher() ==
nullptr) {
593 async_loop_create(&kAsyncLoopConfigAttachToCurrentThread, &message_loop);
594 async_set_default_dispatcher(async_loop_get_dispatcher(message_loop));
595 async_loop_start_thread(message_loop,
"Fuchsia async loop",
nullptr);
601 ASSERT(vm_node !=
nullptr);
602 metrics = std::make_shared<InspectMetrics>(std::move(vm_node));
605 auto services = sys::ServiceDirectory::CreateFromNamespace();
606 services->Connect(property_provider.NewRequest());
608 timezone_name = TimezoneName::New(std::move(property_provider), metrics);
612 if (message_loop !=
nullptr) {
613 async_loop_shutdown(message_loop);
615 timezone_name.reset();
618 if (message_loop !=
nullptr) {
620 if (async_get_default_dispatcher() ==
621 async_loop_get_dispatcher(message_loop)) {
622 async_set_default_dispatcher(
nullptr);
624 async_loop_destroy(message_loop);
625 message_loop =
nullptr;
641#if defined(ARCH_IS_64_BIT)
642#define ElfW(Type) Elf64_##Type
644#define ElfW(Type) Elf32_##Type
650 const Image instructions_image(snapshot_instructions);
651 if (
auto*
const image_build_id = instructions_image.build_id()) {
652 return {instructions_image.build_id_length(), image_build_id};
654 const uint8_t* dso_base =
GetAppDSOBase(snapshot_instructions);
655 const ElfW(Ehdr)& elf_header = *
reinterpret_cast<const ElfW(Ehdr)*
>(dso_base);
656 const ElfW(Phdr)*
const phdr_array =
657 reinterpret_cast<const ElfW(Phdr)*
>(dso_base + elf_header.e_phoff);
658 for (intptr_t
i = 0;
i < elf_header.e_phnum;
i++) {
659 const ElfW(Phdr)&
header = phdr_array[
i];
660 if (
header.p_type != PT_NOTE)
continue;
662 const uint8_t*
const note_addr = dso_base +
header.p_vaddr;
663 const Elf32_Nhdr& note_header =
664 *
reinterpret_cast<const Elf32_Nhdr*
>(note_addr);
665 if (note_header.n_type != NT_GNU_BUILD_ID)
continue;
666 const char*
const note_contents =
667 reinterpret_cast<const char*
>(note_addr +
sizeof(Elf32_Nhdr));
669 if (note_header.n_namesz != strlen(
ELF_NOTE_GNU) + 1)
continue;
670 if (strncmp(
ELF_NOTE_GNU, note_contents, note_header.n_namesz) == 0) {
671 return {
static_cast<intptr_t
>(note_header.n_descsz),
672 reinterpret_cast<const uint8_t*
>(note_contents +
673 note_header.n_namesz)};
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
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)
static int64_t GetCurrentTimeMicros()
static intptr_t ActivationFrameAlignment()
static void static void static void VFPrint(FILE *stream, const char *format, va_list args)
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 void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static constexpr bool IsPowerOfTwo(T x)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
Dart_NativeFunction function
const GrXPFactory * Get(SkBlendMode mode)
static constexpr intptr_t PF_R
static constexpr const char ELF_NOTE_GNU[]
constexpr intptr_t kMicrosecondsPerMillisecond
constexpr intptr_t kNanosecondsPerMicrosecond
void * malloc(size_t size)
constexpr intptr_t kNanosecondsPerSecond
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
std::unique_ptr< inspect::Node > TakeDartVmNode()
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
static const char header[]