出门莫恨无人随,书中车马多如簇。这篇文章主要讲述Android NDK抛出信号SIGSEGV:通过JNI获取Activity中的GoogleSignInClient后无效的地址相关的知识,希望能为你提供帮助。
我正在开发L?VE2D游戏框架的android端口的附加组件,以通过游戏代码提供与Google Play游戏服务的连接。框架的大部分内容都是用C ++编写的。它具有LuaVM,简化了与SDL2的桥接,可以访问所需的任何内容。
要从LuaVM中运行的Lua代码访问Google Play游戏服务,我必须添加包含入口点和包装类的本机C ++模块。从那里我将调用重定向到android.cpp,我必须使用JNI来访问我的主Activity中的函数,因为我必须使用java包com.google.android.gms.auth.api.signin
登录播放器。
这座桥按预期工作。当应用程序加载时,我将其初始化为:
love2d丰富功能的Android /爱情/ src目录/ JNI /爱情/ src目录/模块/ mobsvc / config_MobSvc.h:
static const bool MOBSVC_REQUIRED = false;
// Force login into Google Play Games Services
love2d丰富功能的Android /爱情/ src目录/ JNI /爱情/ src目录/模块/ mobsvc / MobSvc.cpp:
MobSvc::MobSvc()
{
love::android::mobSvcInit(MOBSVC_REQUIRED);
}
^- 该模块将在应用程序启动时构建。
love2d丰富功能的Android /爱情/ src目录/ JNI /爱情/ src目录/普通/ android.h:
void mobSvcInit(bool required);
love2d丰富功能的Android /爱情/ src目录/ JNI /爱情/ src目录/普通/ android.cpp:
void mobSvcInit(bool required)
{
bool inp1 = required;
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz (env->
GetObjectClass(activity));
jmethodID methodID = env->
GetMethodID(clazz, "mobSvcInit", "(Z)V");
jboolean jinp1 = (jboolean) inp1;
env->
CallVoidMethod(activity, methodID, jinp1);
env->
DeleteLocalRef(activity);
env->
DeleteLocalRef(clazz);
}
love2d丰富功能的Android /爱情/ src目录/主/ JAVA /组织/ love2d /安卓/ RichGameActivity.java:
public void mobSvcInit(boolean required) {
// Specify if skipping of the login should be impossible.
mobSvcRequired = required;
// Determine if Google Play Games Services is installed on the device.
PackageManager pm = context.getPackageManager();
boolean isKindle = (Build.MANUFACTURER.equals("Amazon") &
&
Build.MODEL.equals("Kindle Fire")) || Build.MODEL.startsWith("KF");
try
{
PackageInfo info = pm.getPackageInfo(!isKindle ? "com.android.vending" : "com.amazon.venezia", PackageManager.GET_ACTIVITIES);
String label = (String) info.applicationInfo.loadLabel(pm);
mobSvcAvailable = (label != null &
&
!label.equals("Market"));
}
catch (PackageManager.NameNotFoundException e)
{
mobSvcAvailable = false;
}// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
.requestEmail()
.build();
// Build a GoogleSignInClient with the options specified by gso.
mobSvcSignInClient = GoogleSignIn.getClient(this, gso);
Log.d("RichGameActivity","Play Games Services initialised.");
}
代码将通过,它将被执行。然而,行
mobSvcSignInClient = GoogleSignIn.getClient(this, gso);
导致它在文件ANativeWindow_fromSurface(env, s);
中的函数Android_JNI_GetNativeWindow
中的love2d-rich-android/love/src/jni/SDL2-2.0.5/src/core/android/SDL_android.c
上崩溃,之后,这是由SDL2框架完成的JNI操作:文章图片
【Android NDK抛出信号SIGSEGV(通过JNI获取Activity中的GoogleSignInClient后无效的地址)】如果删除该行,一切都会继续运行而不会出现问题。如需进一步检查,可在此处获取存储库:https://bitbucket.org/MartyMaro/love2d-rich-android/src/c5ad59b16a8b7f9fcc267a9f56e03de959c30b05/?at=MobSvc
我认为这个问题与SDL2不相关,因为在后面的步骤中我继续尝试确保在UI线程上调用代码。在不深入了解LuaVM和L?VE框架如何工作的情况下,我已经为模块实现了桥接,因此我可以从Lua本身触发上面的代码。因此,调用事物的方式是相同的,但是当VM已经运行并且所有L?VE模块都已初始化并且代码在UI线程中执行时,代码的执行会更晚。
现在异常在NDK包的jni.h(
~/Library/Android/sdk/ndk-bundle/sysroot/usr/include/jni.h
)中:文章图片
故障地址似乎是相同的,JNI(因此NDK)在两种情况下都起作用,因此我认为获取Google的登录客户端会导致NDK在下一次JNI操作时失败。我需要一种正确的方法来处理这种情况而不会引起任何问题。我很高兴有任何想法如何解决这个问题。
答案所以我将我的代码移动到我的Activity的onStart,以摆脱整个NDK依赖,只是为了发现我在运行时得到了
NoClassDefFoundError
异常。在玩完之后,我看到我在gradle文件中实现了旧版本的auth。将其更改为我的gradle文件中的最近一个:
api 'com.google.android.gms:play-services-auth:16.0.0'
而且没有抛出异常。之后,我的JNI呼叫确实有效。事实证明,我的堆栈中的异常更高,并且NDK无法正确处理此异常,因此我只得到一个常见的无效地址异常。
如果您遇到类似问题,请在尝试其他方法之前尝试获取最新的库。
推荐阅读
- 如何在init.rc文件中完全禁用Android L中的SELinux()
- Android NDK(找不到平台文件(标题和库))
- 在android ndk中使用ubuntu header lib
- 构建使用协议缓冲区的Android可执行gRPC服务器(不使用APK)
- Android studio 3.1.3创建新项目,c ++支持同步失败
- 在没有Android Studio的情况下为Android创建(Cmake)C / C ++库
- Android NDK“ndk-build”被识别为内部或外部命令批处理文件
- 将cpp类添加到android项目中
- 如何使用Android.mk为不同的平台指定不同的CFLAGS