Android: fix few crashes

master
Maksim 2022-05-16 16:31:30 +03:00
parent ffeaa84f04
commit e66d7fd516
8 changed files with 59 additions and 44 deletions

View File

@ -4,7 +4,7 @@ apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 32 compileSdkVersion 32
buildToolsVersion '32.0.0' buildToolsVersion '32.0.0'
ndkVersion '23.1.7779620' ndkVersion '23.2.8568313'
defaultConfig { defaultConfig {
applicationId 'com.multicraft.game' applicationId 'com.multicraft.game'
minSdkVersion 21 minSdkVersion 21
@ -61,7 +61,6 @@ android {
} }
} }
import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os import org.apache.tools.ant.taskdefs.condition.Os
task prepareAssetsFiles() { task prepareAssetsFiles() {
@ -125,7 +124,7 @@ def abiCodes = ['armeabi-v7a': 0, 'arm64-v8a': 1]
android.applicationVariants.all { variant -> android.applicationVariants.all { variant ->
variant.outputs.each { variant.outputs.each {
output -> output ->
def abiName = output.getFilter(OutputFile.ABI) def abiName = output.filters[0].identifier
output.versionCodeOverride = abiCodes.get(abiName, 0) + variant.versionCode output.versionCodeOverride = abiCodes.get(abiName, 0) + variant.versionCode
} }
} }
@ -135,9 +134,9 @@ dependencies {
implementation project(':native') implementation project(':native')
/* Third-party libraries */ /* Third-party libraries */
implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.appcompat:appcompat-resources:1.4.1' implementation 'androidx.appcompat:appcompat-resources:1.4.2'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation 'androidx.work:work-runtime-ktx:2.7.1' implementation 'androidx.work:work-runtime-ktx:2.7.1'
implementation 'com.google.android.material:material:1.5.0' implementation 'com.google.android.material:material:1.6.1'
} }

View File

@ -30,7 +30,7 @@ class WorkerViewModelFactory(
private val zips: Array<String> private val zips: Array<String>
) : ) :
ViewModelProvider.Factory { ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(WorkerViewModel::class.java)) { if (modelClass.isAssignableFrom(WorkerViewModel::class.java)) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return WorkerViewModel(application, zips) as T return WorkerViewModel(application, zips) as T

View File

@ -15,9 +15,10 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.1.2' classpath 'com.android.tools.build:gradle:7.2.1'
//noinspection GradleDependency
classpath 'de.undercouch:gradle-download-task:4.1.2' classpath 'de.undercouch:gradle-download-task:4.1.2'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
} }

View File

@ -1,6 +1,6 @@
#Fri Feb 11 12:29:43 EET 2022 #Wed May 25 12:00:00 EET 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -4,7 +4,7 @@ apply plugin: 'de.undercouch.download'
android { android {
compileSdkVersion 32 compileSdkVersion 32
buildToolsVersion '32.0.0' buildToolsVersion '32.0.0'
ndkVersion '23.1.7779620' ndkVersion '23.2.8568313'
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 32 targetSdkVersion 32
@ -92,3 +92,7 @@ task getIconv(dependsOn: downloadIconv, type: Copy) {
preBuild.dependsOn getDeps preBuild.dependsOn getDeps
preBuild.dependsOn getIconv preBuild.dependsOn getIconv
android.defaultConfig.externalNativeBuild.ndkBuild {
arguments 'prebuilt=$(if $(strip $(wildcard $(prebuilt_path))),$(prebuilt_path),.)'
}

View File

@ -279,7 +279,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
#endif #endif
#if defined(__ANDROID__) || defined(__IOS__) #if defined(__ANDROID__) || defined(__IOS__)
porting::notifyExitGame(); if (!g_gamecallback->shutdown_requested)
porting::notifyExitGame();
#endif #endif
} //try } //try

View File

@ -1,6 +1,7 @@
/* /*
Minetest Minetest
Copyright (C) 2014 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2014 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2014-2022 Maksim Gamarnik [MoNTE48] Maksym48@pm.me
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
@ -29,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h" #include "filesys.h"
#include "log.h" #include "log.h"
#include <atomic>
#include <sstream> #include <sstream>
#include <exception> #include <exception>
#include <cstdlib> #include <cstdlib>
@ -40,8 +42,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
extern int main(int argc, char *argv[]); extern int main(int argc, char *argv[]);
extern "C" void external_pause_game(); extern "C" void external_pause_game();
static std::atomic<bool> ran = {false};
jmethodID notifyExit;
void android_main(android_app *app) void android_main(android_app *app)
{ {
if (ran.exchange(true)) {
errorstream << "Caught second android_main execution in a process" << std::endl;
return;
}
porting::app_global = app; porting::app_global = app;
Thread::setName("Main"); Thread::setName("Main");
@ -58,9 +69,9 @@ void android_main(android_app *app)
porting::finishGame("Unknown error"); porting::finishGame("Unknown error");
} }
porting::cleanupAndroid();
infostream << "Shutting down." << std::endl; infostream << "Shutting down." << std::endl;
exit(0); porting::cleanupAndroid();
_Exit(0);
} }
/** /**
@ -69,13 +80,6 @@ void android_main(android_app *app)
* ToDo: this doesn't work as expected, there's a workaround for it right now * ToDo: this doesn't work as expected, there's a workaround for it right now
*/ */
extern "C" { extern "C" {
JNIEXPORT void JNICALL Java_com_multicraft_game_GameActivity_putMessageBoxResult(
JNIEnv *env, jclass thiz, jstring text)
{
errorstream <<
"Java_com_multicraft_game_GameActivity_putMessageBoxResult got: " <<
std::string((const char*) env->GetStringChars(text, nullptr)) << std::endl;
}
JNIEXPORT void JNICALL Java_com_multicraft_game_GameActivity_pauseGame( JNIEXPORT void JNICALL Java_com_multicraft_game_GameActivity_pauseGame(
JNIEnv *env, jclass clazz) JNIEnv *env, jclass clazz)
{ {
@ -93,6 +97,7 @@ namespace porting {
android_app *app_global; android_app *app_global;
JNIEnv *jnienv; JNIEnv *jnienv;
jclass nativeActivity; jclass nativeActivity;
jobject activityObj;
jclass findClass(const std::string &classname) jclass findClass(const std::string &classname)
{ {
@ -102,8 +107,7 @@ jclass findClass(const std::string &classname)
jclass nativeactivity = jnienv->FindClass("android/app/NativeActivity"); jclass nativeactivity = jnienv->FindClass("android/app/NativeActivity");
jmethodID getClassLoader = jnienv->GetMethodID( jmethodID getClassLoader = jnienv->GetMethodID(
nativeactivity, "getClassLoader", "()Ljava/lang/ClassLoader;"); nativeactivity, "getClassLoader", "()Ljava/lang/ClassLoader;");
jobject cls = jnienv->CallObjectMethod( jobject cls = jnienv->CallObjectMethod(activityObj, getClassLoader);
app_global->activity->clazz, getClassLoader);
jclass classLoader = jnienv->FindClass("java/lang/ClassLoader"); jclass classLoader = jnienv->FindClass("java/lang/ClassLoader");
jmethodID findClass = jnienv->GetMethodID(classLoader, "loadClass", jmethodID findClass = jnienv->GetMethodID(classLoader, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;"); "(Ljava/lang/String;)Ljava/lang/Class;");
@ -119,6 +123,7 @@ void initAndroid()
lJavaVMAttachArgs.version = JNI_VERSION_1_6; lJavaVMAttachArgs.version = JNI_VERSION_1_6;
lJavaVMAttachArgs.name = PROJECT_NAME_C "NativeThread"; lJavaVMAttachArgs.name = PROJECT_NAME_C "NativeThread";
lJavaVMAttachArgs.group = nullptr; lJavaVMAttachArgs.group = nullptr;
activityObj = app_global->activity->clazz;
if (jvm->AttachCurrentThread(&porting::jnienv, &lJavaVMAttachArgs) == JNI_ERR) { if (jvm->AttachCurrentThread(&porting::jnienv, &lJavaVMAttachArgs) == JNI_ERR) {
errorstream << "Failed to attach native thread to jvm" << std::endl; errorstream << "Failed to attach native thread to jvm" << std::endl;
@ -131,6 +136,10 @@ void initAndroid()
"porting::initAndroid unable to find java native activity class" << "porting::initAndroid unable to find java native activity class" <<
std::endl; std::endl;
notifyExit = jnienv->GetMethodID(nativeActivity, "notifyExitGame", "()V");
FATAL_ERROR_IF(notifyExit == nullptr,
"porting::initAndroid unable to find java notifyExit method");
#ifdef GPROF #ifdef GPROF
// in the start-up code // in the start-up code
__android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME_C, __android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME_C,
@ -149,6 +158,7 @@ void cleanupAndroid()
JavaVM *jvm = app_global->activity->vm; JavaVM *jvm = app_global->activity->vm;
jvm->DetachCurrentThread(); jvm->DetachCurrentThread();
ANativeActivity_finish(porting::app_global->activity);
} }
static std::string javaStringToUTF8(jstring js) static std::string javaStringToUTF8(jstring js)
@ -198,14 +208,14 @@ void initializePathsAndroid()
"getAbsolutePath", "()Ljava/lang/String;"); "getAbsolutePath", "()Ljava/lang/String;");
std::string path_storage = getAndroidPath(cls_Env, nullptr, std::string path_storage = getAndroidPath(cls_Env, nullptr,
mt_getAbsPath, "getExternalStorageDirectory"); mt_getAbsPath, "getExternalStorageDirectory");
std::string path_data = getAndroidPath(nativeActivity, app_global->activity->clazz, mt_getAbsPath, std::string path_data = getAndroidPath(nativeActivity, activityObj, mt_getAbsPath,
"getFilesDir"); "getFilesDir");
path_user = path_storage + DIR_DELIM + "Android/data/com.multicraft.game/files"; path_user = path_storage + DIR_DELIM + "Android/data/com.multicraft.game/files";
path_share = path_data; path_share = path_data;
path_locale = path_data + DIR_DELIM + "locale"; path_locale = path_data + DIR_DELIM + "locale";
path_cache = getAndroidPath(nativeActivity, path_cache = getAndroidPath(nativeActivity,
app_global->activity->clazz, mt_getAbsPath, "getCacheDir"); activityObj, mt_getAbsPath, "getCacheDir");
} }
void showInputDialog(const std::string &acceptButton, const std::string &hint, void showInputDialog(const std::string &acceptButton, const std::string &hint,
@ -222,7 +232,7 @@ void showInputDialog(const std::string &acceptButton, const std::string &hint,
jstring jcurrent = jnienv->NewStringUTF(current.c_str()); jstring jcurrent = jnienv->NewStringUTF(current.c_str());
jint jeditType = editType; jint jeditType = editType;
jnienv->CallVoidMethod(app_global->activity->clazz, showdialog, jnienv->CallVoidMethod(activityObj, showdialog,
jacceptButton, jhint, jcurrent, jeditType); jacceptButton, jhint, jcurrent, jeditType);
} }
@ -235,7 +245,7 @@ void openURIAndroid(const std::string &url)
"porting::openURIAndroid unable to find java openURI method"); "porting::openURIAndroid unable to find java openURI method");
jstring jurl = jnienv->NewStringUTF(url.c_str()); jstring jurl = jnienv->NewStringUTF(url.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl); jnienv->CallVoidMethod(activityObj, url_open, jurl);
} }
int getInputDialogState() int getInputDialogState()
@ -246,7 +256,7 @@ int getInputDialogState()
FATAL_ERROR_IF(dialogstate == nullptr, FATAL_ERROR_IF(dialogstate == nullptr,
"porting::getInputDialogState unable to find java dialog state method"); "porting::getInputDialogState unable to find java dialog state method");
return jnienv->CallIntMethod(app_global->activity->clazz, dialogstate); return jnienv->CallIntMethod(activityObj, dialogstate);
} }
std::string getInputDialogValue() std::string getInputDialogValue()
@ -257,8 +267,7 @@ std::string getInputDialogValue()
FATAL_ERROR_IF(dialogvalue == nullptr, FATAL_ERROR_IF(dialogvalue == nullptr,
"porting::getInputDialogValue unable to find java dialog value method"); "porting::getInputDialogValue unable to find java dialog value method");
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, jobject result = jnienv->CallObjectMethod(activityObj, dialogvalue);
dialogvalue);
const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr); const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr);
std::string text(javachars); std::string text(javachars);
@ -272,7 +281,7 @@ float getTotalSystemMemory()
long pages = sysconf(_SC_PHYS_PAGES); long pages = sysconf(_SC_PHYS_PAGES);
long page_size = sysconf(_SC_PAGE_SIZE); long page_size = sysconf(_SC_PAGE_SIZE);
int divisor = 1024 * 1024 * 1024; int divisor = 1024 * 1024 * 1024;
return pages * page_size / (float) divisor; return (float) (pages * page_size) / (float) divisor;
} }
bool hasRealKeyboard() bool hasRealKeyboard()
@ -290,7 +299,7 @@ void handleError(const std::string &errType, const std::string &err)
std::string errorMessage = errType + ": " + err; std::string errorMessage = errType + ": " + err;
jstring jerr = porting::getJniString(errorMessage); jstring jerr = porting::getJniString(errorMessage);
jnienv->CallVoidMethod(app_global->activity->clazz, report_err, jerr); jnienv->CallVoidMethod(activityObj, report_err, jerr);
} }
void notifyServerConnect(bool is_multiplayer) void notifyServerConnect(bool is_multiplayer)
@ -303,18 +312,18 @@ void notifyServerConnect(bool is_multiplayer)
auto param = (jboolean) is_multiplayer; auto param = (jboolean) is_multiplayer;
jnienv->CallVoidMethod(app_global->activity->clazz, notifyConnect, param); jnienv->CallVoidMethod(activityObj, notifyConnect, param);
} }
void notifyExitGame() void notifyExitGame()
{ {
jmethodID notifyExit = jnienv->GetMethodID(nativeActivity, if (jnienv == nullptr || activityObj == nullptr || notifyExit == nullptr)
"notifyExitGame", "()V"); return;
FATAL_ERROR_IF(notifyExit == nullptr, jnienv->CallVoidMethod(activityObj, notifyExit);
"porting::notifyExit unable to find java notifyExit method");
jnienv->CallVoidMethod(app_global->activity->clazz, notifyExit); if (jnienv->ExceptionOccurred())
jnienv->ExceptionClear();
} }
#ifndef SERVER #ifndef SERVER
@ -330,7 +339,7 @@ float getDisplayDensity()
FATAL_ERROR_IF(getDensity == nullptr, FATAL_ERROR_IF(getDensity == nullptr,
"porting::getDisplayDensity unable to find java getDensity method"); "porting::getDisplayDensity unable to find java getDensity method");
value = jnienv->CallFloatMethod(app_global->activity->clazz, getDensity); value = jnienv->CallFloatMethod(activityObj, getDensity);
firstrun = false; firstrun = false;
} }
return value; return value;
@ -355,7 +364,7 @@ void finishGame(const std::string &exc)
exit(-1); exit(-1);
jstring jexc = jnienv->NewStringUTF(exc.c_str()); jstring jexc = jnienv->NewStringUTF(exc.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, finishMe, jexc); jnienv->CallVoidMethod(activityObj, finishMe, jexc);
exit(0); exit(0);
} }
@ -366,13 +375,13 @@ jstring getJniString(const std::string &message)
jbyteArray bytes = jnienv->NewByteArray(byteCount); jbyteArray bytes = jnienv->NewByteArray(byteCount);
jnienv->SetByteArrayRegion(bytes, 0, byteCount, pNativeMessage); jnienv->SetByteArrayRegion(bytes, 0, byteCount, pNativeMessage);
jclass charsetClass = jnienv->FindClass("java/nio/charset/Charset"); jclass charsetClass = findClass("java/nio/charset/Charset");
jmethodID forName = jnienv->GetStaticMethodID( jmethodID forName = jnienv->GetStaticMethodID(
charsetClass, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;"); charsetClass, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
jstring utf8 = jnienv->NewStringUTF("UTF-8"); jstring utf8 = jnienv->NewStringUTF("UTF-8");
jobject charset = jnienv->CallStaticObjectMethod(charsetClass, forName, utf8); jobject charset = jnienv->CallStaticObjectMethod(charsetClass, forName, utf8);
jclass stringClass = jnienv->FindClass("java/lang/String"); jclass stringClass = findClass("java/lang/String");
jmethodID ctor = jnienv->GetMethodID( jmethodID ctor = jnienv->GetMethodID(
stringClass, "<init>", "([BLjava/nio/charset/Charset;)V"); stringClass, "<init>", "([BLjava/nio/charset/Charset;)V");
@ -390,6 +399,6 @@ void upgrade(const std::string &item)
"porting::upgradeGame unable to find java upgrade method"); "porting::upgradeGame unable to find java upgrade method");
jstring jitem = jnienv->NewStringUTF(item.c_str()); jstring jitem = jnienv->NewStringUTF(item.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, upgradeGame, jitem); jnienv->CallVoidMethod(activityObj, upgradeGame, jitem);
} }
} }

View File

@ -1,6 +1,7 @@
/* /*
Minetest Minetest
Copyright (C) 2014 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2014 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2014-2022 Maksim Gamarnik [MoNTE48] Maksym48@pm.me
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by