diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | src/common/dynamic_library.cpp | 2 | ||||
| -rw-r--r-- | src/common/dynamic_library.h | 3 | ||||
| -rw-r--r-- | src/common/error.cpp | 3 | ||||
| -rw-r--r-- | src/common/fs/file.cpp | 38 | ||||
| -rw-r--r-- | src/common/fs/fs_android.cpp | 98 | ||||
| -rw-r--r-- | src/common/fs/fs_android.h | 62 | ||||
| -rw-r--r-- | src/common/fs/path_util.cpp | 26 | ||||
| -rw-r--r-- | src/common/fs/path_util.h | 8 | ||||
| -rw-r--r-- | src/common/host_memory.cpp | 12 | ||||
| -rw-r--r-- | src/common/logging/backend.cpp | 26 | ||||
| -rw-r--r-- | src/common/logging/text_formatter.cpp | 35 | ||||
| -rw-r--r-- | src/common/logging/text_formatter.h | 2 |
13 files changed, 322 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) |
| 156 | endif() | 156 | endif() |
| 157 | 157 | ||
| 158 | if(ANDROID) | ||
| 159 | target_sources(common | ||
| 160 | PRIVATE | ||
| 161 | fs/fs_android.cpp | ||
| 162 | fs/fs_android.h | ||
| 163 | ) | ||
| 164 | endif() | ||
| 165 | |||
| 158 | if(ARCHITECTURE_x86_64) | 166 | if(ARCHITECTURE_x86_64) |
| 159 | target_sources(common | 167 | target_sources(common |
| 160 | PRIVATE | 168 | PRIVATE |
| @@ -194,6 +202,11 @@ create_target_directory_groups(common) | |||
| 194 | target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile Threads::Threads) | 202 | target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile Threads::Threads) |
| 195 | target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) | 203 | target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) |
| 196 | 204 | ||
| 205 | if (ANDROID) | ||
| 206 | # For ASharedMemory_create | ||
| 207 | target_link_libraries(common PRIVATE android) | ||
| 208 | endif() | ||
| 209 | |||
| 197 | if (YUZU_USE_PRECOMPILED_HEADERS) | 210 | if (YUZU_USE_PRECOMPILED_HEADERS) |
| 198 | target_precompile_headers(common PRIVATE precompiled_headers.h) | 211 | target_precompile_headers(common PRIVATE precompiled_headers.h) |
| 199 | endif() | 212 | endif() |
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 | ||
| 25 | DynamicLibrary::DynamicLibrary(void* handle_) : handle{handle_} {} | ||
| 26 | |||
| 25 | DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept | 27 | DynamicLibrary::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 | |||
| 6 | namespace Common::FS::Android { | ||
| 7 | |||
| 8 | JNIEnv* 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 | |||
| 27 | void 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 | |||
| 44 | void 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 | |||
| 55 | bool 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 | |||
| 64 | int 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 | } | ||
| 94 | ANDROID_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 | |||
| 17 | namespace Common::FS::Android { | ||
| 18 | |||
| 19 | static JavaVM* g_jvm = nullptr; | ||
| 20 | static 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; | ||
| 25 | ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR) | ||
| 26 | ANDROID_STORAGE_FUNCTIONS(FS) | ||
| 27 | #undef F | ||
| 28 | #undef FS | ||
| 29 | #undef FR | ||
| 30 | |||
| 31 | enum class OpenMode { | ||
| 32 | Read, | ||
| 33 | Write, | ||
| 34 | ReadWrite, | ||
| 35 | WriteAppend, | ||
| 36 | WriteTruncate, | ||
| 37 | ReadWriteAppend, | ||
| 38 | ReadWriteTruncate, | ||
| 39 | Never | ||
| 40 | }; | ||
| 41 | |||
| 42 | void RegisterCallbacks(JNIEnv* env, jclass clazz); | ||
| 43 | |||
| 44 | void UnRegisterCallbacks(); | ||
| 45 | |||
| 46 | bool 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; | ||
| 51 | ANDROID_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); | ||
| 58 | ANDROID_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 | ||
| 83 | private: | 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 | ||
| 130 | private: | ||
| 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 | ||
| 223 | void SetAppDirectory(const std::string& app_directory) { | ||
| 224 | PathManagerImpl::GetInstance().Reinitialize(app_directory); | ||
| 225 | } | ||
| 226 | |||
| 213 | const fs::path& GetYuzuPath(YuzuPath yuzu_path) { | 227 | const 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 | ||
| 351 | std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { | 365 | std::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 | */ | ||
| 189 | void 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 01457d8c6..ba22595e0 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -11,6 +11,10 @@ | |||
| 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 |
| @@ -367,17 +371,20 @@ public: | |||
| 367 | } | 371 | } |
| 368 | 372 | ||
| 369 | // Backing memory initialization | 373 | // Backing memory initialization |
| 370 | #if defined(__FreeBSD__) && __FreeBSD__ < 13 | 374 | #ifdef ANDROID |
| 375 | fd = ASharedMemory_create("HostMemory", backing_size); | ||
| 376 | #elif defined(__FreeBSD__) && __FreeBSD__ < 13 | ||
| 371 | // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 | 377 | // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 |
| 372 | fd = shm_open(SHM_ANON, O_RDWR, 0600); | 378 | fd = shm_open(SHM_ANON, O_RDWR, 0600); |
| 373 | #else | 379 | #else |
| 374 | fd = memfd_create("HostMemory", 0); | 380 | fd = memfd_create("HostMemory", 0); |
| 375 | #endif | 381 | #endif |
| 376 | if (fd == -1) { | 382 | if (fd < 0) { |
| 377 | LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); | 383 | LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); |
| 378 | throw std::bad_alloc{}; | 384 | throw std::bad_alloc{}; |
| 379 | } | 385 | } |
| 380 | 386 | ||
| 387 | #ifndef ANDROID | ||
| 381 | // Defined to extend the file with zeros | 388 | // Defined to extend the file with zeros |
| 382 | int ret = ftruncate(fd, backing_size); | 389 | int ret = ftruncate(fd, backing_size); |
| 383 | if (ret != 0) { | 390 | if (ret != 0) { |
| @@ -385,6 +392,7 @@ public: | |||
| 385 | strerror(errno)); | 392 | strerror(errno)); |
| 386 | throw std::bad_alloc{}; | 393 | throw std::bad_alloc{}; |
| 387 | } | 394 | } |
| 395 | #endif | ||
| 388 | 396 | ||
| 389 | backing_base = static_cast<u8*>( | 397 | backing_base = static_cast<u8*>( |
| 390 | 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)); |
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 | */ | ||
| 162 | class LogcatBackend : public Backend { | ||
| 163 | public: | ||
| 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 | |||
| 158 | bool initialization_in_progress_suppress_logging = true; | 178 | bool 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 | |||
| 114 | void 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); | |||
| 15 | void PrintMessage(const Entry& entry); | 15 | void 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. |
| 17 | void PrintColoredMessage(const Entry& entry); | 17 | void PrintColoredMessage(const Entry& entry); |
| 18 | /// Formats and prints a log entry to the android logcat. | ||
| 19 | void PrintMessageToLogcat(const Entry& entry); | ||
| 18 | } // namespace Common::Log | 20 | } // namespace Common::Log |