[Base/UI] Android globals initialization + WindowedAppContext parts
This commit is contained in:
@@ -7,4 +7,33 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/base/console_app_posix.cc"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/console_app_main.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/main_android.h"
|
||||
|
||||
extern "C" int main(int argc, char** argv) {
|
||||
xe::ConsoleAppEntryInfo entry_info = xe::GetConsoleAppEntryInfo();
|
||||
|
||||
if (!entry_info.transparent_options) {
|
||||
cvar::ParseLaunchArguments(argc, argv, entry_info.positional_usage,
|
||||
entry_info.positional_options);
|
||||
}
|
||||
|
||||
// Initialize Android globals, including logging. Needs parsed cvars.
|
||||
// TODO(Triang3l): Obtain the actual API level.
|
||||
xe::InitializeAndroidAppFromMainThread(__ANDROID_API__);
|
||||
|
||||
std::vector<std::string> args;
|
||||
for (int n = 0; n < argc; n++) {
|
||||
args.emplace_back(argv[n]);
|
||||
}
|
||||
|
||||
int result = entry_info.entry_point(args);
|
||||
|
||||
xe::ShutdownAndroidAppFromMainThread();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
66
src/xenia/base/main_android.cc
Normal file
66
src/xenia/base/main_android.cc
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2021 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/base/main_android.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/memory.h"
|
||||
#include "xenia/base/threading.h"
|
||||
|
||||
namespace xe {
|
||||
|
||||
static size_t android_initializations_ = 0;
|
||||
|
||||
static int32_t android_api_level_ = __ANDROID_API__;
|
||||
|
||||
void InitializeAndroidAppFromMainThread(int32_t api_level) {
|
||||
if (android_initializations_++) {
|
||||
// Already initialized for another component in the process.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the API level before everything else if available - may be needed by
|
||||
// subsystem initialization itself.
|
||||
android_api_level_ = api_level;
|
||||
|
||||
// Logging uses threading.
|
||||
xe::threading::AndroidInitialize();
|
||||
|
||||
// Multiple apps can be launched within one process - don't pass the actual
|
||||
// app name.
|
||||
xe::InitializeLogging("xenia");
|
||||
|
||||
xe::memory::AndroidInitialize();
|
||||
}
|
||||
|
||||
void ShutdownAndroidAppFromMainThread() {
|
||||
assert_not_zero(android_initializations_);
|
||||
if (!android_initializations_) {
|
||||
return;
|
||||
}
|
||||
if (--android_initializations_) {
|
||||
// Other components are still running.
|
||||
return;
|
||||
}
|
||||
|
||||
xe::memory::AndroidShutdown();
|
||||
|
||||
xe::ShutdownLogging();
|
||||
|
||||
xe::threading::AndroidShutdown();
|
||||
|
||||
android_api_level_ = __ANDROID_API__;
|
||||
}
|
||||
|
||||
int32_t GetAndroidApiLevel() { return android_api_level_; }
|
||||
|
||||
} // namespace xe
|
||||
40
src/xenia/base/main_android.h
Normal file
40
src/xenia/base/main_android.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2021 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_BASE_MAIN_ANDROID_H_
|
||||
#define XENIA_BASE_MAIN_ANDROID_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "xenia/base/platform.h"
|
||||
|
||||
namespace xe {
|
||||
|
||||
// In activities, these functions must be called in onCreate and onDestroy.
|
||||
//
|
||||
// Multiple components may run in the same process, and they will be
|
||||
// instantiated in the main thread, which is, for regular applications (the
|
||||
// system application exception doesn't apply to Xenia), the UI thread.
|
||||
//
|
||||
// For this reason, it's okay to call these functions multiple times if
|
||||
// different Xenia windowed applications run in one process - there is call
|
||||
// counting internally.
|
||||
//
|
||||
// In standalone console apps built with $(BUILD_EXECUTABLE), these functions
|
||||
// must be called in `main`.
|
||||
void InitializeAndroidAppFromMainThread(int32_t api_level);
|
||||
void ShutdownAndroidAppFromMainThread();
|
||||
|
||||
// May be the minimum supported level if the initialization was done without a
|
||||
// configuration.
|
||||
int32_t GetAndroidApiLevel();
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_MAIN_ANDROID_H_
|
||||
@@ -24,6 +24,11 @@
|
||||
namespace xe {
|
||||
namespace memory {
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
void AndroidInitialize();
|
||||
void AndroidShutdown();
|
||||
#endif
|
||||
|
||||
// Returns the native page size of the system, in bytes.
|
||||
// This should be ~4KiB.
|
||||
size_t page_size();
|
||||
|
||||
@@ -12,22 +12,52 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <cstddef>
|
||||
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/string.h"
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
#include <dlfcn.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "xenia/base/platform_android.h"
|
||||
#include "xenia/base/main_android.h"
|
||||
#endif
|
||||
|
||||
namespace xe {
|
||||
namespace memory {
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
// May be null if no dynamically loaded functions are required.
|
||||
static void* libandroid_;
|
||||
// API 26+.
|
||||
static int (*android_ASharedMemory_create_)(const char* name, size_t size);
|
||||
|
||||
void AndroidInitialize() {
|
||||
if (xe::GetAndroidApiLevel() >= 26) {
|
||||
libandroid_ = dlopen("libandroid.so", RTLD_NOW);
|
||||
assert_not_null(libandroid_);
|
||||
if (libandroid_) {
|
||||
android_ASharedMemory_create_ =
|
||||
reinterpret_cast<decltype(android_ASharedMemory_create_)>(
|
||||
dlsym(libandroid_, "ASharedMemory_create"));
|
||||
assert_not_null(android_ASharedMemory_create_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidShutdown() {
|
||||
android_ASharedMemory_create_ = nullptr;
|
||||
if (libandroid_) {
|
||||
dlclose(libandroid_);
|
||||
libandroid_ = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t page_size() { return getpagesize(); }
|
||||
size_t allocation_granularity() { return page_size(); }
|
||||
|
||||
@@ -86,11 +116,9 @@ 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);
|
||||
// TODO(Triang3l): Check if memfd can be used instead on API 30+.
|
||||
if (android_ASharedMemory_create_) {
|
||||
int sharedmem_fd = android_ASharedMemory_create_(path.c_str(), length);
|
||||
return sharedmem_fd >= 0 ? sharedmem_fd : kFileMappingHandleInvalid;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <android/configuration.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#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 as these will be usable anywhere, already loaded
|
||||
// into the address space as the application is linked against them.
|
||||
// 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);
|
||||
void* libc = dlopen("libc.so", RTLD_NOW);
|
||||
assert_not_null(libc);
|
||||
#define XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(lib, name, api) \
|
||||
api_functions_.api_##api.name = \
|
||||
reinterpret_cast<decltype(api_functions_.api_##api.name)>( \
|
||||
dlsym(lib, #name)); \
|
||||
assert_not_null(api_functions_.api_##api.name);
|
||||
XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(libandroid, ASharedMemory_create, 26);
|
||||
// pthreads are a part of Bionic libc on Android.
|
||||
XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(libc, pthread_getname_np, 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
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <android/native_activity.h>
|
||||
#include <pthread.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
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 {
|
||||
// libandroid
|
||||
int (*ASharedMemory_create)(const char* name, size_t size);
|
||||
// libc
|
||||
int (*pthread_getname_np)(pthread_t pthread, char* buf, size_t n);
|
||||
} api_26;
|
||||
};
|
||||
const ApiFunctions& api_functions();
|
||||
|
||||
} // namespace android
|
||||
} // namespace platform
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_PLATFORM_ANDROID_H_
|
||||
@@ -25,10 +25,16 @@
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/platform.h"
|
||||
|
||||
namespace xe {
|
||||
namespace threading {
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
void AndroidInitialize();
|
||||
void AndroidShutdown();
|
||||
#endif
|
||||
|
||||
// This is more like an Event with self-reset when returning from Wait()
|
||||
class Fence {
|
||||
public:
|
||||
|
||||
@@ -21,20 +21,51 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
#include <dlfcn.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include "xenia/base/platform_android.h"
|
||||
#include "xenia/base/main_android.h"
|
||||
#include "xenia/base/string_util.h"
|
||||
#endif
|
||||
|
||||
namespace xe {
|
||||
namespace threading {
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
// May be null if no dynamically loaded functions are required.
|
||||
static void* android_libc_;
|
||||
// API 26+.
|
||||
static int (*android_pthread_getname_np_)(pthread_t pthread, char* buf,
|
||||
size_t n);
|
||||
|
||||
void AndroidInitialize() {
|
||||
if (xe::GetAndroidApiLevel() >= 26) {
|
||||
android_libc_ = dlopen("libc.so", RTLD_NOW);
|
||||
assert_not_null(android_libc_);
|
||||
if (android_libc_) {
|
||||
android_pthread_getname_np_ =
|
||||
reinterpret_cast<decltype(android_pthread_getname_np_)>(
|
||||
dlsym(android_libc_, "pthread_getname_np"));
|
||||
assert_not_null(android_pthread_getname_np_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidShutdown() {
|
||||
android_pthread_getname_np_ = nullptr;
|
||||
if (android_libc_) {
|
||||
dlclose(android_libc_);
|
||||
android_libc_ = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline timespec DurationToTimeSpec(
|
||||
std::chrono::duration<_Rep, _Period> duration) {
|
||||
@@ -577,9 +608,9 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||
// pthread_getname_np was added in API 26 - below that, store the name in
|
||||
// this object, which may be only modified through Xenia threading, but
|
||||
// should be enough in most cases.
|
||||
if (xe::platform::android::api_level() >= 26) {
|
||||
if (xe::platform::android::api_functions().api_26.pthread_getname_np(
|
||||
thread_, result.data(), result.size() - 1) != 0) {
|
||||
if (android_pthread_getname_np_) {
|
||||
if (android_pthread_getname_np_(thread_, result.data(),
|
||||
result.size() - 1) != 0) {
|
||||
assert_always();
|
||||
}
|
||||
} else {
|
||||
@@ -608,7 +639,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
void SetAndroidPreApi26Name(const std::string_view name) {
|
||||
if (xe::platform::android::api_level() >= 26) {
|
||||
if (android_pthread_getname_np_) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(android_pre_api_26_name_mutex_);
|
||||
@@ -1145,7 +1176,7 @@ void Thread::Exit(int exit_code) {
|
||||
void set_name(const std::string_view name) {
|
||||
pthread_setname_np(pthread_self(), std::string(name).c_str());
|
||||
#if XE_PLATFORM_ANDROID
|
||||
if (xe::platform::android::api_level() < 26 && current_thread_) {
|
||||
if (!android_pthread_getname_np_ && current_thread_) {
|
||||
current_thread_->condition().SetAndroidPreApi26Name(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user