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;
661 if ((
header.p_flags & PF_R) != PF_R)
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
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
#define DEFINE_FLAG(type, name, default_value, comment)
const GrXPFactory * Get(SkBlendMode mode)
constexpr intptr_t kMicrosecondsPerMillisecond
constexpr intptr_t kNanosecondsPerMicrosecond
void * malloc(size_t size)
constexpr intptr_t kNanosecondsPerSecond
std::unique_ptr< inspect::Node > TakeDartVmNode()
static const char header[]