summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt13
-rw-r--r--src/common/dynamic_library.cpp2
-rw-r--r--src/common/dynamic_library.h3
-rw-r--r--src/common/error.cpp3
-rw-r--r--src/common/fs/file.cpp38
-rw-r--r--src/common/fs/fs_android.cpp98
-rw-r--r--src/common/fs/fs_android.h62
-rw-r--r--src/common/fs/path_util.cpp26
-rw-r--r--src/common/fs/path_util.h8
-rw-r--r--src/common/host_memory.cpp34
-rw-r--r--src/common/logging/backend.cpp26
-rw-r--r--src/common/logging/text_formatter.cpp35
-rw-r--r--src/common/logging/text_formatter.h2
13 files changed, 344 insertions, 6 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 13ed68b3f..efc4a9fe9 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -155,6 +155,14 @@ if (WIN32)
155 target_link_libraries(common PRIVATE ntdll) 155 target_link_libraries(common PRIVATE ntdll)
156endif() 156endif()
157 157
158if(ANDROID)
159 target_sources(common
160 PRIVATE
161 fs/fs_android.cpp
162 fs/fs_android.h
163 )
164endif()
165
158if(ARCHITECTURE_x86_64) 166if(ARCHITECTURE_x86_64)
159 target_sources(common 167 target_sources(common
160 PRIVATE 168 PRIVATE
@@ -194,6 +202,11 @@ create_target_directory_groups(common)
194target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile Threads::Threads) 202target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile Threads::Threads)
195target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) 203target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle)
196 204
205if (ANDROID)
206 # For ASharedMemory_create
207 target_link_libraries(common PRIVATE android)
208endif()
209
197if (YUZU_USE_PRECOMPILED_HEADERS) 210if (YUZU_USE_PRECOMPILED_HEADERS)
198 target_precompile_headers(common PRIVATE precompiled_headers.h) 211 target_precompile_headers(common PRIVATE precompiled_headers.h)
199endif() 212endif()
diff --git a/src/common/dynamic_library.cpp b/src/common/dynamic_library.cpp
index 054277a2b..4fabe7e52 100644
--- a/src/common/dynamic_library.cpp
+++ b/src/common/dynamic_library.cpp
@@ -22,6 +22,8 @@ DynamicLibrary::DynamicLibrary(const char* filename) {
22 void(Open(filename)); 22 void(Open(filename));
23} 23}
24 24
25DynamicLibrary::DynamicLibrary(void* handle_) : handle{handle_} {}
26
25DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept 27DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept
26 : handle{std::exchange(rhs.handle, nullptr)} {} 28 : handle{std::exchange(rhs.handle, nullptr)} {}
27 29
diff --git a/src/common/dynamic_library.h b/src/common/dynamic_library.h
index f42bdf441..662d454d4 100644
--- a/src/common/dynamic_library.h
+++ b/src/common/dynamic_library.h
@@ -20,6 +20,9 @@ public:
20 /// Automatically loads the specified library. Call IsOpen() to check validity before use. 20 /// Automatically loads the specified library. Call IsOpen() to check validity before use.
21 explicit DynamicLibrary(const char* filename); 21 explicit DynamicLibrary(const char* filename);
22 22
23 /// Initializes the dynamic library with an already opened handle.
24 explicit DynamicLibrary(void* handle_);
25
23 /// Moves the library. 26 /// Moves the library.
24 DynamicLibrary(DynamicLibrary&&) noexcept; 27 DynamicLibrary(DynamicLibrary&&) noexcept;
25 DynamicLibrary& operator=(DynamicLibrary&&) noexcept; 28 DynamicLibrary& operator=(DynamicLibrary&&) noexcept;
diff --git a/src/common/error.cpp b/src/common/error.cpp
index ddb03bd45..1b2009db7 100644
--- a/src/common/error.cpp
+++ b/src/common/error.cpp
@@ -30,7 +30,8 @@ std::string NativeErrorToString(int e) {
30 return ret; 30 return ret;
31#else 31#else
32 char err_str[255]; 32 char err_str[255];
33#if defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) 33#if defined(ANDROID) || \
34 (defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)))
34 // Thread safe (GNU-specific) 35 // Thread safe (GNU-specific)
35 const char* str = strerror_r(e, err_str, sizeof(err_str)); 36 const char* str = strerror_r(e, err_str, sizeof(err_str));
36 return std::string(str); 37 return std::string(str);
diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp
index 656b03cc5..b0b25eb43 100644
--- a/src/common/fs/file.cpp
+++ b/src/common/fs/file.cpp
@@ -5,6 +5,9 @@
5 5
6#include "common/fs/file.h" 6#include "common/fs/file.h"
7#include "common/fs/fs.h" 7#include "common/fs/fs.h"
8#ifdef ANDROID
9#include "common/fs/fs_android.h"
10#endif
8#include "common/logging/log.h" 11#include "common/logging/log.h"
9 12
10#ifdef _WIN32 13#ifdef _WIN32
@@ -252,6 +255,23 @@ void IOFile::Open(const fs::path& path, FileAccessMode mode, FileType type, File
252 } else { 255 } else {
253 _wfopen_s(&file, path.c_str(), AccessModeToWStr(mode, type)); 256 _wfopen_s(&file, path.c_str(), AccessModeToWStr(mode, type));
254 } 257 }
258#elif ANDROID
259 if (Android::IsContentUri(path)) {
260 ASSERT_MSG(mode == FileAccessMode::Read, "Content URI file access is for read-only!");
261 const auto fd = Android::OpenContentUri(path, Android::OpenMode::Read);
262 if (fd != -1) {
263 file = fdopen(fd, "r");
264 const auto error_num = errno;
265 if (error_num != 0 && file == nullptr) {
266 LOG_ERROR(Common_Filesystem, "Error opening file: {}, error: {}", path.c_str(),
267 strerror(error_num));
268 }
269 } else {
270 LOG_ERROR(Common_Filesystem, "Error opening file: {}", path.c_str());
271 }
272 } else {
273 file = std::fopen(path.c_str(), AccessModeToStr(mode, type));
274 }
255#else 275#else
256 file = std::fopen(path.c_str(), AccessModeToStr(mode, type)); 276 file = std::fopen(path.c_str(), AccessModeToStr(mode, type));
257#endif 277#endif
@@ -372,6 +392,23 @@ u64 IOFile::GetSize() const {
372 // Flush any unwritten buffered data into the file prior to retrieving the file size. 392 // Flush any unwritten buffered data into the file prior to retrieving the file size.
373 std::fflush(file); 393 std::fflush(file);
374 394
395#if ANDROID
396 u64 file_size = 0;
397 if (Android::IsContentUri(file_path)) {
398 file_size = Android::GetSize(file_path);
399 } else {
400 std::error_code ec;
401
402 file_size = fs::file_size(file_path, ec);
403
404 if (ec) {
405 LOG_ERROR(Common_Filesystem,
406 "Failed to retrieve the file size of path={}, ec_message={}",
407 PathToUTF8String(file_path), ec.message());
408 return 0;
409 }
410 }
411#else
375 std::error_code ec; 412 std::error_code ec;
376 413
377 const auto file_size = fs::file_size(file_path, ec); 414 const auto file_size = fs::file_size(file_path, ec);
@@ -381,6 +418,7 @@ u64 IOFile::GetSize() const {
381 PathToUTF8String(file_path), ec.message()); 418 PathToUTF8String(file_path), ec.message());
382 return 0; 419 return 0;
383 } 420 }
421#endif
384 422
385 return file_size; 423 return file_size;
386} 424}
diff --git a/src/common/fs/fs_android.cpp b/src/common/fs/fs_android.cpp
new file mode 100644
index 000000000..298a79bac
--- /dev/null
+++ b/src/common/fs/fs_android.cpp
@@ -0,0 +1,98 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/fs/fs_android.h"
5
6namespace Common::FS::Android {
7
8JNIEnv* GetEnvForThread() {
9 thread_local static struct OwnedEnv {
10 OwnedEnv() {
11 status = g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
12 if (status == JNI_EDETACHED)
13 g_jvm->AttachCurrentThread(&env, nullptr);
14 }
15
16 ~OwnedEnv() {
17 if (status == JNI_EDETACHED)
18 g_jvm->DetachCurrentThread();
19 }
20
21 int status;
22 JNIEnv* env = nullptr;
23 } owned;
24 return owned.env;
25}
26
27void RegisterCallbacks(JNIEnv* env, jclass clazz) {
28 env->GetJavaVM(&g_jvm);
29 native_library = clazz;
30
31#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
32 F(JMethodID, JMethodName, Signature)
33#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \
34 F(JMethodID, JMethodName, Signature)
35#define F(JMethodID, JMethodName, Signature) \
36 JMethodID = env->GetStaticMethodID(native_library, JMethodName, Signature);
37 ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
38 ANDROID_STORAGE_FUNCTIONS(FS)
39#undef F
40#undef FS
41#undef FR
42}
43
44void UnRegisterCallbacks() {
45#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) F(JMethodID)
46#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
47#define F(JMethodID) JMethodID = nullptr;
48 ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
49 ANDROID_STORAGE_FUNCTIONS(FS)
50#undef F
51#undef FS
52#undef FR
53}
54
55bool IsContentUri(const std::string& path) {
56 constexpr std::string_view prefix = "content://";
57 if (path.size() < prefix.size()) [[unlikely]] {
58 return false;
59 }
60
61 return path.find(prefix) == 0;
62}
63
64int OpenContentUri(const std::string& filepath, OpenMode openmode) {
65 if (open_content_uri == nullptr)
66 return -1;
67
68 const char* mode = "";
69 switch (openmode) {
70 case OpenMode::Read:
71 mode = "r";
72 break;
73 default:
74 UNIMPLEMENTED();
75 return -1;
76 }
77 auto env = GetEnvForThread();
78 jstring j_filepath = env->NewStringUTF(filepath.c_str());
79 jstring j_mode = env->NewStringUTF(mode);
80 return env->CallStaticIntMethod(native_library, open_content_uri, j_filepath, j_mode);
81}
82
83#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
84 F(FunctionName, ReturnValue, JMethodID, Caller)
85#define F(FunctionName, ReturnValue, JMethodID, Caller) \
86 ReturnValue FunctionName(const std::string& filepath) { \
87 if (JMethodID == nullptr) { \
88 return 0; \
89 } \
90 auto env = GetEnvForThread(); \
91 jstring j_filepath = env->NewStringUTF(filepath.c_str()); \
92 return env->Caller(native_library, JMethodID, j_filepath); \
93 }
94ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
95#undef F
96#undef FR
97
98} // namespace Common::FS::Android
diff --git a/src/common/fs/fs_android.h b/src/common/fs/fs_android.h
new file mode 100644
index 000000000..bb8a52648
--- /dev/null
+++ b/src/common/fs/fs_android.h
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <string>
7#include <vector>
8#include <jni.h>
9
10#define ANDROID_STORAGE_FUNCTIONS(V) \
11 V(OpenContentUri, int, (const std::string& filepath, OpenMode openmode), open_content_uri, \
12 "openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I")
13
14#define ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(V) \
15 V(GetSize, std::uint64_t, get_size, CallStaticLongMethod, "getSize", "(Ljava/lang/String;)J")
16
17namespace Common::FS::Android {
18
19static JavaVM* g_jvm = nullptr;
20static jclass native_library = nullptr;
21
22#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) F(JMethodID)
23#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
24#define F(JMethodID) static jmethodID JMethodID = nullptr;
25ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
26ANDROID_STORAGE_FUNCTIONS(FS)
27#undef F
28#undef FS
29#undef FR
30
31enum class OpenMode {
32 Read,
33 Write,
34 ReadWrite,
35 WriteAppend,
36 WriteTruncate,
37 ReadWriteAppend,
38 ReadWriteTruncate,
39 Never
40};
41
42void RegisterCallbacks(JNIEnv* env, jclass clazz);
43
44void UnRegisterCallbacks();
45
46bool IsContentUri(const std::string& path);
47
48#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \
49 F(FunctionName, Parameters, ReturnValue)
50#define F(FunctionName, Parameters, ReturnValue) ReturnValue FunctionName Parameters;
51ANDROID_STORAGE_FUNCTIONS(FS)
52#undef F
53#undef FS
54
55#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
56 F(FunctionName, ReturnValue)
57#define F(FunctionName, ReturnValue) ReturnValue FunctionName(const std::string& filepath);
58ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
59#undef F
60#undef FR
61
62} // namespace Common::FS::Android
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index defa3e918..e026a13d9 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -6,6 +6,9 @@
6#include <unordered_map> 6#include <unordered_map>
7 7
8#include "common/fs/fs.h" 8#include "common/fs/fs.h"
9#ifdef ANDROID
10#include "common/fs/fs_android.h"
11#endif
9#include "common/fs/fs_paths.h" 12#include "common/fs/fs_paths.h"
10#include "common/fs/path_util.h" 13#include "common/fs/path_util.h"
11#include "common/logging/log.h" 14#include "common/logging/log.h"
@@ -80,9 +83,7 @@ public:
80 yuzu_paths.insert_or_assign(yuzu_path, new_path); 83 yuzu_paths.insert_or_assign(yuzu_path, new_path);
81 } 84 }
82 85
83private: 86 void Reinitialize(fs::path yuzu_path = {}) {
84 PathManagerImpl() {
85 fs::path yuzu_path;
86 fs::path yuzu_path_cache; 87 fs::path yuzu_path_cache;
87 fs::path yuzu_path_config; 88 fs::path yuzu_path_config;
88 89
@@ -95,6 +96,10 @@ private:
95 96
96 yuzu_path_cache = yuzu_path / CACHE_DIR; 97 yuzu_path_cache = yuzu_path / CACHE_DIR;
97 yuzu_path_config = yuzu_path / CONFIG_DIR; 98 yuzu_path_config = yuzu_path / CONFIG_DIR;
99#elif ANDROID
100 ASSERT(!yuzu_path.empty());
101 yuzu_path_cache = yuzu_path / CACHE_DIR;
102 yuzu_path_config = yuzu_path / CONFIG_DIR;
98#else 103#else
99 yuzu_path = GetCurrentDir() / PORTABLE_DIR; 104 yuzu_path = GetCurrentDir() / PORTABLE_DIR;
100 105
@@ -122,6 +127,11 @@ private:
122 GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR); 127 GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR);
123 } 128 }
124 129
130private:
131 PathManagerImpl() {
132 Reinitialize();
133 }
134
125 ~PathManagerImpl() = default; 135 ~PathManagerImpl() = default;
126 136
127 void GenerateYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) { 137 void GenerateYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) {
@@ -210,6 +220,10 @@ fs::path RemoveTrailingSeparators(const fs::path& path) {
210 return fs::path{string_path}; 220 return fs::path{string_path};
211} 221}
212 222
223void SetAppDirectory(const std::string& app_directory) {
224 PathManagerImpl::GetInstance().Reinitialize(app_directory);
225}
226
213const fs::path& GetYuzuPath(YuzuPath yuzu_path) { 227const fs::path& GetYuzuPath(YuzuPath yuzu_path) {
214 return PathManagerImpl::GetInstance().GetYuzuPathImpl(yuzu_path); 228 return PathManagerImpl::GetInstance().GetYuzuPathImpl(yuzu_path);
215} 229}
@@ -350,6 +364,12 @@ std::vector<std::string> SplitPathComponents(std::string_view filename) {
350 364
351std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { 365std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {
352 std::string path(path_); 366 std::string path(path_);
367#ifdef ANDROID
368 if (Android::IsContentUri(path)) {
369 return path;
370 }
371#endif // ANDROID
372
353 char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\'; 373 char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\';
354 char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/'; 374 char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/';
355 375
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 13d713f1e..7cfe85b70 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -181,6 +181,14 @@ template <typename Path>
181#endif 181#endif
182 182
183/** 183/**
184 * Sets the directory used for application storage. Used on Android where we do not know internal
185 * storage until informed by the frontend.
186 *
187 * @param app_directory Directory to use for application storage.
188 */
189void SetAppDirectory(const std::string& app_directory);
190
191/**
184 * Gets the filesystem path associated with the YuzuPath enum. 192 * Gets the filesystem path associated with the YuzuPath enum.
185 * 193 *
186 * @param yuzu_path YuzuPath enum 194 * @param yuzu_path YuzuPath enum
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 8e4f1f97a..ba22595e0 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -11,9 +11,14 @@
11 11
12#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv 12#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
13 13
14#ifdef ANDROID
15#include <android/sharedmem.h>
16#endif
17
14#ifndef _GNU_SOURCE 18#ifndef _GNU_SOURCE
15#define _GNU_SOURCE 19#define _GNU_SOURCE
16#endif 20#endif
21#include <boost/icl/interval_set.hpp>
17#include <fcntl.h> 22#include <fcntl.h>
18#include <sys/mman.h> 23#include <sys/mman.h>
19#include <unistd.h> 24#include <unistd.h>
@@ -366,17 +371,20 @@ public:
366 } 371 }
367 372
368 // Backing memory initialization 373 // Backing memory initialization
369#if defined(__FreeBSD__) && __FreeBSD__ < 13 374#ifdef ANDROID
375 fd = ASharedMemory_create("HostMemory", backing_size);
376#elif defined(__FreeBSD__) && __FreeBSD__ < 13
370 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 377 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30
371 fd = shm_open(SHM_ANON, O_RDWR, 0600); 378 fd = shm_open(SHM_ANON, O_RDWR, 0600);
372#else 379#else
373 fd = memfd_create("HostMemory", 0); 380 fd = memfd_create("HostMemory", 0);
374#endif 381#endif
375 if (fd == -1) { 382 if (fd < 0) {
376 LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); 383 LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno));
377 throw std::bad_alloc{}; 384 throw std::bad_alloc{};
378 } 385 }
379 386
387#ifndef ANDROID
380 // Defined to extend the file with zeros 388 // Defined to extend the file with zeros
381 int ret = ftruncate(fd, backing_size); 389 int ret = ftruncate(fd, backing_size);
382 if (ret != 0) { 390 if (ret != 0) {
@@ -384,6 +392,7 @@ public:
384 strerror(errno)); 392 strerror(errno));
385 throw std::bad_alloc{}; 393 throw std::bad_alloc{};
386 } 394 }
395#endif
387 396
388 backing_base = static_cast<u8*>( 397 backing_base = static_cast<u8*>(
389 mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); 398 mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
@@ -415,6 +424,7 @@ public:
415 madvise(virtual_base, virtual_size, MADV_HUGEPAGE); 424 madvise(virtual_base, virtual_size, MADV_HUGEPAGE);
416#endif 425#endif
417 426
427 placeholders.add({0, virtual_size});
418 good = true; 428 good = true;
419 } 429 }
420 430
@@ -423,6 +433,10 @@ public:
423 } 433 }
424 434
425 void Map(size_t virtual_offset, size_t host_offset, size_t length) { 435 void Map(size_t virtual_offset, size_t host_offset, size_t length) {
436 {
437 std::scoped_lock lock{placeholder_mutex};
438 placeholders.subtract({virtual_offset, virtual_offset + length});
439 }
426 440
427 void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE, 441 void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE,
428 MAP_SHARED | MAP_FIXED, fd, host_offset); 442 MAP_SHARED | MAP_FIXED, fd, host_offset);
@@ -433,6 +447,19 @@ public:
433 // The method name is wrong. We're still talking about the virtual range. 447 // The method name is wrong. We're still talking about the virtual range.
434 // We don't want to unmap, we want to reserve this memory. 448 // We don't want to unmap, we want to reserve this memory.
435 449
450 {
451 std::scoped_lock lock{placeholder_mutex};
452 auto it = placeholders.find({virtual_offset - 1, virtual_offset + length + 1});
453
454 if (it != placeholders.end()) {
455 size_t prev_upper = virtual_offset + length;
456 virtual_offset = std::min(virtual_offset, it->lower());
457 length = std::max(it->upper(), prev_upper) - virtual_offset;
458 }
459
460 placeholders.add({virtual_offset, virtual_offset + length});
461 }
462
436 void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE, 463 void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE,
437 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 464 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
438 ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); 465 ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
@@ -476,6 +503,9 @@ private:
476 } 503 }
477 504
478 int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create 505 int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
506
507 boost::icl::interval_set<size_t> placeholders; ///< Mapped placeholders
508 std::mutex placeholder_mutex; ///< Mutex for placeholders
479}; 509};
480 510
481#else // ^^^ Linux ^^^ vvv Generic vvv 511#else // ^^^ Linux ^^^ vvv Generic vvv
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index f96c7c222..6e8e8eb36 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -155,6 +155,26 @@ public:
155 void EnableForStacktrace() override {} 155 void EnableForStacktrace() override {}
156}; 156};
157 157
158#ifdef ANDROID
159/**
160 * Backend that writes to the Android logcat
161 */
162class LogcatBackend : public Backend {
163public:
164 explicit LogcatBackend() = default;
165
166 ~LogcatBackend() override = default;
167
168 void Write(const Entry& entry) override {
169 PrintMessageToLogcat(entry);
170 }
171
172 void Flush() override {}
173
174 void EnableForStacktrace() override {}
175};
176#endif
177
158bool initialization_in_progress_suppress_logging = true; 178bool initialization_in_progress_suppress_logging = true;
159 179
160/** 180/**
@@ -260,6 +280,9 @@ private:
260 lambda(static_cast<Backend&>(debugger_backend)); 280 lambda(static_cast<Backend&>(debugger_backend));
261 lambda(static_cast<Backend&>(color_console_backend)); 281 lambda(static_cast<Backend&>(color_console_backend));
262 lambda(static_cast<Backend&>(file_backend)); 282 lambda(static_cast<Backend&>(file_backend));
283#ifdef ANDROID
284 lambda(static_cast<Backend&>(lc_backend));
285#endif
263 } 286 }
264 287
265 static void Deleter(Impl* ptr) { 288 static void Deleter(Impl* ptr) {
@@ -272,6 +295,9 @@ private:
272 DebuggerBackend debugger_backend{}; 295 DebuggerBackend debugger_backend{};
273 ColorConsoleBackend color_console_backend{}; 296 ColorConsoleBackend color_console_backend{};
274 FileBackend file_backend; 297 FileBackend file_backend;
298#ifdef ANDROID
299 LogcatBackend lc_backend{};
300#endif
275 301
276 MPSCQueue<Entry> message_queue{}; 302 MPSCQueue<Entry> message_queue{};
277 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()}; 303 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
index 09398ea64..2c453177b 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -8,6 +8,10 @@
8#include <windows.h> 8#include <windows.h>
9#endif 9#endif
10 10
11#ifdef ANDROID
12#include <android/log.h>
13#endif
14
11#include "common/assert.h" 15#include "common/assert.h"
12#include "common/logging/filter.h" 16#include "common/logging/filter.h"
13#include "common/logging/log.h" 17#include "common/logging/log.h"
@@ -106,4 +110,35 @@ void PrintColoredMessage(const Entry& entry) {
106#undef ESC 110#undef ESC
107#endif 111#endif
108} 112}
113
114void PrintMessageToLogcat(const Entry& entry) {
115#ifdef ANDROID
116 const auto str = FormatLogMessage(entry);
117
118 android_LogPriority android_log_priority;
119 switch (entry.log_level) {
120 case Level::Trace:
121 android_log_priority = ANDROID_LOG_VERBOSE;
122 break;
123 case Level::Debug:
124 android_log_priority = ANDROID_LOG_DEBUG;
125 break;
126 case Level::Info:
127 android_log_priority = ANDROID_LOG_INFO;
128 break;
129 case Level::Warning:
130 android_log_priority = ANDROID_LOG_WARN;
131 break;
132 case Level::Error:
133 android_log_priority = ANDROID_LOG_ERROR;
134 break;
135 case Level::Critical:
136 android_log_priority = ANDROID_LOG_FATAL;
137 break;
138 case Level::Count:
139 UNREACHABLE();
140 }
141 __android_log_print(android_log_priority, "YuzuNative", "%s", str.c_str());
142#endif
143}
109} // namespace Common::Log 144} // namespace Common::Log
diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h
index 0d0ec4370..68417420b 100644
--- a/src/common/logging/text_formatter.h
+++ b/src/common/logging/text_formatter.h
@@ -15,4 +15,6 @@ std::string FormatLogMessage(const Entry& entry);
15void PrintMessage(const Entry& entry); 15void PrintMessage(const Entry& entry);
16/// Prints the same message as `PrintMessage`, but colored according to the severity level. 16/// Prints the same message as `PrintMessage`, but colored according to the severity level.
17void PrintColoredMessage(const Entry& entry); 17void PrintColoredMessage(const Entry& entry);
18/// Formats and prints a log entry to the android logcat.
19void PrintMessageToLogcat(const Entry& entry);
18} // namespace Common::Log 20} // namespace Common::Log