• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <fidl/fuchsia.logger/cpp/wire.h>
7 #include <lib/syslog/structured_backend/cpp/fuchsia_syslog.h>
8 #include <lib/zx/channel.h>
9 #include <lib/zx/socket.h>
10 #include <lib/zxio/zxio.h>
11 #include <unistd.h>
12 #include <zircon/system/public/zircon/process.h>
13 
14 #include <cstdarg>
15 
16 #include "ResourceTracker.h"
17 #include "TraceProviderFuchsia.h"
18 #include "services/service_connector.h"
19 
20 namespace {
21 
22 zx::socket g_log_socket = zx::socket(ZX_HANDLE_INVALID);
23 
24 typedef VkResult(VKAPI_PTR* PFN_vkOpenInNamespaceAddr)(const char* pName, uint32_t handle);
25 
26 PFN_vkOpenInNamespaceAddr g_vulkan_connector;
27 
GetKoid(zx_handle_t handle)28 zx_koid_t GetKoid(zx_handle_t handle) {
29     zx_info_handle_basic_t info;
30     zx_status_t status =
31         zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
32     return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
33 }
34 
35 static zx_koid_t pid = GetKoid(zx_process_self());
36 
37 static thread_local zx_koid_t tid = GetKoid(zx_thread_self());
38 
CStringToStringView(const char * cstr)39 cpp17::optional<cpp17::string_view> CStringToStringView(const char* cstr) {
40     if (!cstr) {
41         return cpp17::nullopt;
42     }
43     return cstr;
44 }
45 
StripDots(const char * path)46 const char* StripDots(const char* path) {
47     while (strncmp(path, "../", 3) == 0) {
48         path += 3;
49     }
50     return path;
51 }
52 
StripPath(const char * path)53 const char* StripPath(const char* path) {
54     auto p = strrchr(path, '/');
55     if (p) {
56         return p + 1;
57     } else {
58         return path;
59     }
60 }
61 
StripFile(const char * file,FuchsiaLogSeverity severity)62 const char* StripFile(const char* file, FuchsiaLogSeverity severity) {
63     return severity > FUCHSIA_LOG_INFO ? StripDots(file) : StripPath(file);
64 }
65 
gfxstream_fuchsia_log(int8_t severity,const char * tag,const char * file,int line,const char * format,va_list va)66 extern "C" void gfxstream_fuchsia_log(int8_t severity, const char* tag, const char* file, int line,
67                                       const char* format, va_list va) {
68     if (!g_log_socket.is_valid()) {
69         abort();
70     }
71     fuchsia_syslog::LogBuffer buffer;
72     constexpr size_t kFormatStringLength = 1024;
73     char fmt_string[kFormatStringLength];
74     fmt_string[kFormatStringLength - 1] = 0;
75     int n = kFormatStringLength;
76     // Format
77     // Number of bytes written not including null terminator
78     int count = vsnprintf(fmt_string, n, format, va) + 1;
79     if (count < 0) {
80         // No message to write.
81         return;
82     }
83 
84     if (count >= n) {
85         // truncated
86         constexpr char kEllipsis[] = "...";
87         constexpr size_t kEllipsisSize = sizeof(kEllipsis);
88         snprintf(fmt_string + kFormatStringLength - 1 - kEllipsisSize, kEllipsisSize, kEllipsis);
89     }
90 
91     if (file) {
92         file = StripFile(file, severity);
93     }
94     buffer.BeginRecord(severity, CStringToStringView(file), line, fmt_string, g_log_socket.borrow(),
95                        0, pid, tid);
96     if (tag) {
97         buffer.WriteKeyValue("tag", tag);
98     }
99     buffer.FlushRecord();
100 }
101 
LocalConnectToServiceFunction(const char * pName)102 zx_handle_t LocalConnectToServiceFunction(const char* pName) {
103     zx::channel remote_endpoint, local_endpoint;
104     zx_status_t status;
105     if ((status = zx::channel::create(0, &remote_endpoint, &local_endpoint)) != ZX_OK) {
106         ALOGE("zx::channel::create failed: %d", status);
107         return ZX_HANDLE_INVALID;
108     }
109     if ((status = g_vulkan_connector(pName, remote_endpoint.release())) != ZX_OK) {
110         ALOGE("vulkan_connector failed: %d", status);
111         return ZX_HANDLE_INVALID;
112     }
113     return local_endpoint.release();
114 }
115 
116 }  // namespace
117 
118 class VulkanDevice {
119    public:
VulkanDevice()120     VulkanDevice() : mHostSupportsGoldfish(IsAccessible(QEMU_PIPE_PATH)) {
121         InitTraceProvider();
122         gfxstream::vk::ResourceTracker::get();
123     }
124 
125     static void InitLogger();
126 
IsAccessible(const char * name)127     static bool IsAccessible(const char* name) {
128         zx_handle_t handle = GetConnectToServiceFunction()(name);
129         if (handle == ZX_HANDLE_INVALID) return false;
130 
131         zxio_storage_t io_storage;
132         zx_status_t status = zxio_create(handle, &io_storage);
133         if (status != ZX_OK) return false;
134 
135         status = zxio_close(&io_storage.io, /*should_wait=*/true);
136         if (status != ZX_OK) return false;
137 
138         return true;
139     }
140 
GetInstance()141     static VulkanDevice& GetInstance() {
142         static VulkanDevice g_instance;
143         return g_instance;
144     }
145 
146    private:
147     void InitTraceProvider();
148 
149     TraceProviderFuchsia mTraceProvider;
150     const bool mHostSupportsGoldfish;
151 };
152 
InitLogger()153 void VulkanDevice::InitLogger() {
154     auto log_socket = ([]() -> std::optional<zx::socket> {
155         fidl::ClientEnd<fuchsia_logger::LogSink> channel{
156             zx::channel{GetConnectToServiceFunction()("/svc/fuchsia.logger.LogSink")}};
157         if (!channel.is_valid()) return std::nullopt;
158 
159         zx::socket local_socket, remote_socket;
160         zx_status_t status = zx::socket::create(ZX_SOCKET_DATAGRAM, &local_socket, &remote_socket);
161         if (status != ZX_OK) return std::nullopt;
162 
163         auto result = fidl::WireCall(channel)->ConnectStructured(std::move(remote_socket));
164 
165         if (!result.ok()) return std::nullopt;
166 
167         return local_socket;
168     })();
169     if (!log_socket) return;
170 
171     g_log_socket = std::move(*log_socket);
172 }
173 
InitTraceProvider()174 void VulkanDevice::InitTraceProvider() {
175     if (!mTraceProvider.Initialize()) {
176         ALOGE("Trace provider failed to initialize");
177     }
178 }
179 
vk_icdInitializeOpenInNamespaceCallback(PFN_vkOpenInNamespaceAddr callback)180 extern "C" __attribute__((visibility("default"))) void vk_icdInitializeOpenInNamespaceCallback(
181     PFN_vkOpenInNamespaceAddr callback) {
182     g_vulkan_connector = callback;
183     SetConnectToServiceFunction(&LocalConnectToServiceFunction);
184 
185     VulkanDevice::InitLogger();
186 
187     ALOGV("Gfxstream on Fuchsia initialized");
188 }
189