diff --git a/android/android_studio_project/app/build.gradle b/android/android_studio_project/app/build.gradle index 972b76641..d199beaa1 100644 --- a/android/android_studio_project/app/build.gradle +++ b/android/android_studio_project/app/build.gradle @@ -9,6 +9,7 @@ android { defaultConfig { applicationId "jp.xenia.emulator" + // 24 (7.0) - Vulkan. minSdkVersion 24 targetSdkVersion 30 versionCode 1 diff --git a/android/android_studio_project/app/src/main/AndroidManifest.xml b/android/android_studio_project/app/src/main/AndroidManifest.xml index 43e557eaf..c5c7c703f 100644 --- a/android/android_studio_project/app/src/main/AndroidManifest.xml +++ b/android/android_studio_project/app/src/main/AndroidManifest.xml @@ -2,6 +2,14 @@ + + + + + + + + #include #include +#include "xenia/base/math.h" +#include "xenia/base/platform.h" +#include "xenia/base/string.h" + +#if XE_PLATFORM_ANDROID +#include +#include +#include + +#include "xenia/base/platform_android.h" +#endif + namespace xe { namespace memory { @@ -70,6 +81,31 @@ bool QueryProtect(void* base_address, size_t& length, PageAccess& access_out) { FileMappingHandle CreateFileMappingHandle(const std::filesystem::path& path, size_t length, PageAccess access, bool commit) { +#if XE_PLATFORM_ANDROID + if (xe::platform::android::api_level() >= 26) { + // TODO(Triang3l): Check if memfd can be used instead on API 30+. + int sharedmem_fd = + xe::platform::android::api_functions().api_26.ASharedMemory_create( + path.c_str(), length); + return sharedmem_fd >= 0 ? sharedmem_fd : kFileMappingHandleInvalid; + } + + // Use /dev/ashmem on API versions below 26, which added ASharedMemory. + // /dev/ashmem was disabled on API 29 for apps targeting it. + // https://chromium.googlesource.com/chromium/src/+/master/third_party/ashmem/ashmem-dev.c + int ashmem_fd = open("/" ASHMEM_NAME_DEF, O_RDWR); + if (ashmem_fd < 0) { + return kFileMappingHandleInvalid; + } + char ashmem_name[ASHMEM_NAME_LEN]; + strlcpy(ashmem_name, path.c_str(), xe::countof(ashmem_name)); + if (ioctl(ashmem_fd, ASHMEM_SET_NAME, ashmem_name) < 0 || + ioctl(ashmem_fd, ASHMEM_SET_SIZE, length) < 0) { + close(ashmem_fd); + return kFileMappingHandleInvalid; + } + return ashmem_fd; +#else int oflag; switch (access) { case PageAccess::kNoAccess: @@ -94,13 +130,16 @@ FileMappingHandle CreateFileMappingHandle(const std::filesystem::path& path, } ftruncate64(ret, length); return ret; +#endif } void CloseFileMappingHandle(FileMappingHandle handle, const std::filesystem::path& path) { close(handle); +#if !XE_PLATFORM_ANDROID auto full_path = "/" / path; shm_unlink(full_path.c_str()); +#endif } void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, diff --git a/src/xenia/base/platform_android.cc b/src/xenia/base/platform_android.cc new file mode 100644 index 000000000..177eb8dfe --- /dev/null +++ b/src/xenia/base/platform_android.cc @@ -0,0 +1,60 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/platform_android.h" + +#include +#include + +#include "xenia/base/assert.h" + +namespace xe { +namespace platform { +namespace android { + +static bool initialized = false; + +static int32_t api_level_ = __ANDROID_API__; + +static ApiFunctions api_functions_; + +void Initialize(const ANativeActivity* activity) { + if (initialized) { + return; + } + + AConfiguration* configuration = AConfiguration_new(); + AConfiguration_fromAssetManager(configuration, activity->assetManager); + api_level_ = AConfiguration_getSdkVersion(configuration); + AConfiguration_delete(configuration); + + if (api_level_ >= 26) { + // Leaked intentionally, already loaded into the address space. + // https://chromium.googlesource.com/chromium/src/+/master/third_party/ashmem/ashmem-dev.c#201 + void* libandroid = dlopen("libandroid.so", RTLD_NOW); + assert_not_null(libandroid); +#define XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(name, api) \ + api_functions_.api_##api.name = \ + reinterpret_cast( \ + dlsym(libandroid, #name)); \ + assert_not_null(api_functions_.api_##api.name); + XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(ASharedMemory_create, 26); +#undef XE_PLATFORM_ANDROID_LOAD_API_FUNCTION + } + + initialized = true; +} + +int32_t api_level() { return api_level_; } + +const ApiFunctions& api_functions() { return api_functions_; } + +} // namespace android +} // namespace platform +} // namespace xe diff --git a/src/xenia/base/platform_android.h b/src/xenia/base/platform_android.h new file mode 100644 index 000000000..1aa549aca --- /dev/null +++ b/src/xenia/base/platform_android.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_BASE_PLATFORM_ANDROID_H_ +#define XENIA_BASE_PLATFORM_ANDROID_H_ + +// NOTE: if you're including this file it means you are explicitly depending +// on Android-specific headers. This is bad for portability and should be +// avoided! + +#include +#include +#include + +namespace xe { +namespace platform { +namespace android { + +// Must be called in onCreate of the first activity. +void Initialize(const ANativeActivity* activity); + +// Returns the device API level - if not initialized, will return the minimum +// level supported by Xenia. +int32_t api_level(); + +// Android API functions added after the minimum supported API version. +struct ApiFunctions { + struct { + int (*ASharedMemory_create)(const char* name, size_t size); + } api_26; +}; +const ApiFunctions& api_functions(); + +} // namespace android +} // namespace platform +} // namespace xe + +#endif // XENIA_BASE_PLATFORM_ANDROID_H_