Announcements
The Scaleform forum is now read-only. Please head to the Gamedev site for product support.
Scaleform Forum (Read Only)
Scaleform enables developers to leverage the power of the Adobe® Flash® tool set to create powerful user interface environments for video games.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Android Lollipop crash on startup :´-(

2 REPLIES 2
SOLVED
Reply
Message 1 of 3
Azicuetano
1090 Views, 2 Replies

Android Lollipop crash on startup :´-(

Hello everyone,
We recently developed a game with Scaleform Mobile for iOS and Android. I'm not going to lie, this development has cost us a lot of effort, and we had to overcome many problems and inconveniences that have overcome thanks to dedicate many hours of work and the help of members of this forum like @FrankFloor84 and @jdnm.

Finally everything went perfect. We have made our application to work stable in IOS as Android, and now is under review by Apple.

But a few days ago we found a problem that has left us completely devastated: Our app does not work on Android 5 Lollipop. Moreover, we have not gotten it to work even the simplest example in a terminal with Android Lollipop. The result is always the same: The app starts and immediately aborts and exits.

We have tried everything, but without success. I explain the most important details:
1) We have the license Scaleform Consumer Mobile SDK 4.2.24.
2) We are compiling with Android SDK 2.3.3. We have not found another Android SDK to create a project that then work on an Android terminal.
3) We tried to use the NDK r8e and NKD R9D without success.
4) We have never managed to make any project in the Android emulator for PC. All our tests have always been to create the APK and then send it to a physical mobile device to test.
5) Neither we managed to run the FxPlayerMobile.apk on an Android device Lollipop.


And these are the questions that I pose:
1) Any admin to confirm whether Scaleform 4.2.24 works Lollipop or a new version of Scaleform will be published soon?
2) Has anyone managed to run a project in Android Lollipop? Perhaps with the commercial license?
3) Have you got compile a project with a different SDK to Android SDK 2.3.3?
4) What version of NDK do you use?
5) Does your project well in PC Android emulator?
6) What new test could do to try to fix this?

Thank you all for your help. I am quite concerned with this topic. :'- (

- Developer at Grupo Enfoca -
Tags (2)
2 REPLIES 2
Message 2 of 3
dani_mrquez
in reply to: Azicuetano

Okay the solution is relatively simple and is caused by an old JNI code.

The problem is, in older versions of Android, the jni let the native code handle the pointers to jvm objects (jobjects) directly so you could store a reference just writing something like this:

 

ActivityClass = jenv->GetObjectClass(MainActivity);

Which is fine as long as the GC doesn't change the location of variables BUT since ICS this feature was incorporated (but for some reason they still let this code works fine until Lollipop). So now, instead of direct pointers you have some indirect references and the previous code it's no longer safe.

(for a much better explanation, you can read this article)

 

The most straightforward solution is to locate the assignment of the global references in the native code and add a

NewGlobalRef(...)

call before it.

 

The first part is in the Platform_Android header 

 

// Platform_Android.h

extern "C" JNIEXPORT void JNICALL Java_##Package##_##Activity##_NativeCacheObject(JNIEnv * env, jobject obj) \ { \ SF_DEBUG_MESSAGE(1, #Activity " CacheObject START"); \ jobject globRefObj = env->NewGlobalRef(obj); \ pImpl->JObj = globRefObj; \ pImpl->OnNativeCacheObject( env ); \ SF_DEBUG_MESSAGE(1, #Activity " CacheObject END"); \ } \ \ extern "C" JNIEXPORT void JNICALL Java_##Package##_##Activity##_NativeClearObject(JNIEnv * env, jobject obj) \ { \ SF_DEBUG_MESSAGE(1, #Activity " ClearObject START"); \ if((pImpl->JObj)) \ env->DeleteGlobalRef(pImpl->JObj); \ pImpl->JObj = NULL; \ pImpl->OnNativeClearObject( env ); \ SF_DEBUG_MESSAGE(1, #Activity " ClearObject END"); \ } \ \ extern "C" JNIEXPORT void JNICALL Java_##Package##_##Activity##_NativeOnCreate(JNIEnv * env, jobject obj) \ { \ SF_DEBUG_MESSAGE(1, #Activity " NativeOnCreate START"); \ pImpl->MainActivity = obj; \ pImpl->SetupFiles(); \ SF_DEBUG_MESSAGE(1, #Activity " NativeOnCreate END"); \ }

 Notice that I left

pImpl->MainActivity = obj;

as it on purpose, because I chose to keep the

pImpl->jObj

 (you'll see then why) instead (yes, they point the same object) for future uses apart from the inmediate SetupFiles, OnNativeCacheObject and OnNativeClearObject.

 

Now in the Platform_Android_GL.cpp

 

//Platform_Android_GL.cpp

void AppImpl::SetupFiles() { if (!SetupFilesComplete) { // Only proceed if we have a valid JNI environment // (NativeAppInit has completed) JNIEnv* jenv; if (!pJVM || pJVM->GetEnv((void**)&jenv, JNI_VERSION_1_6) < 0) { SF_DEBUG_ERROR(1, "SetupFiles: Cannot get jni env"); return; } // We are still in the jni call scope so we can use MainActivity ActivityClass = jenv->GetObjectClass(MainActivity); // set the global ref ActivityClass = (jclass)jenv->NewGlobalRef(ActivityClass); jmethodID getAssets = jenv->GetMethodID(ActivityClass, "getAssets", "()Landroid/content/res/AssetManager;"); AssetManager = jenv->CallObjectMethod(MainActivity, getAssets); // set the global ref AssetManager = jenv->NewGlobalRef(AssetManager); AssetManagerClass = jenv->GetObjectClass(AssetManager); // set the global ref AssetManagerClass = (jclass)jenv->NewGlobalRef(AssetManagerClass); jmethodID getFilesDir = jenv->GetMethodID(ActivityClass, "getFilesDir", "()Ljava/io/File;"); jobject filesDirH = jenv->CallObjectMethod(MainActivity, getFilesDir); jclass FileClass = jenv->GetObjectClass(filesDirH); jmethodID getAbsPath = jenv->GetMethodID(FileClass, "getAbsolutePath", "()Ljava/lang/String;"); jstring filesDir = (jstring) jenv->CallObjectMethod(filesDirH, getAbsPath); jboolean copy; const char* fs = jenv->GetStringUTFChars(filesDir, &copy); // Does not exist by default. mkdir(fs, 0700); FilesDir = fs; FilesDir += "/"; SF_DEBUG_MESSAGE1(1, "Files dir: %s", fs); jenv->ReleaseStringUTFChars(filesDir, fs); jmethodID getCacheDir = jenv->GetMethodID(ActivityClass, "getCacheDir", "()Ljava/io/File;"); jobject cacheDirH = jenv->CallObjectMethod(MainActivity, getCacheDir); jstring cacheDir = (jstring) jenv->CallObjectMethod(cacheDirH, getAbsPath); const char* fcs = jenv->GetStringUTFChars(cacheDir, &copy); // Does not exist by default. mkdir(fcs, 0755); CacheDir = fcs; CacheDir += "/"; SF_DEBUG_MESSAGE1(1, "Cache dir: %s", fcs); jenv->ReleaseStringUTFChars(cacheDir, fcs); SetupFilesComplete = true; } } void AppImpl::OnNativeCacheObject( JNIEnv * jenv ) { SF_DEBUG_MESSAGE(1, "OnNativeCacheObject"); // This call is made from onStart, so there are two cases in which this call is made
// 1) When running the application for the first time or after destroying it (onDestroy call). In that case we have already cached the fields
// Or 2) When we resume the application (onRestart). In that case we have to cache the objects if ( !ActivityClass ) { ActivityClass = jenv->GetObjectClass(JObj); // set the global ref ActivityClass = (jclass)jenv->NewGlobalRef(ActivityClass); } if ( !AssetManager ) { jmethodID getAssets = jenv->GetMethodID(ActivityClass, "getAssets", "()Landroid/content/res/AssetManager;"); AssetManager = jenv->CallObjectMethod(JObj, getAssets); // set the global ref AssetManager = jenv->NewGlobalRef(AssetManager); } if ( !AssetManagerClass ) { AssetManagerClass = jenv->GetObjectClass(AssetManager); // set the global ref AssetManagerClass = (jclass)jenv->NewGlobalRef(AssetManagerClass); } } void AppImpl::OnNativeClearObject( JNIEnv *jenv ) { SF_DEBUG_MESSAGE(1, "OnNativeClearObject"); if( ActivityClass ) { jenv->DeleteGlobalRef( ActivityClass ); ActivityClass = 0; } if ( AssetManager ) { jenv->DeleteGlobalRef( AssetManager ); AssetManager = 0; } if( AssetManagerClass ) { jenv->DeleteGlobalRef( AssetManagerClass ); AssetManagerClass = 0; } }

This is the simplest solution, you can tidy it up a little bit by eliminating the variable duplication (for example) or even writing some jobject wrapper, but I guess that's the bare minimum changes you need to make.*

 

Hope it's clear!

 

PS: Perhaps I forgot some other parts in which changes are necessary (I can't tell for sure) but I think you get the idea.

Message 3 of 3
adjm
in reply to: dani_mrquez

Hi Guys,

 

I can confirm dani_mrquez's fix.  This issue was addressed long ago within our codebase, but unfortunately did not make it over to the consumer side until the recent release of the Scaleform 4.4 Mobile SDK:

 

http://forums.autodesk.com/t5/scaleform-mobile-development/scaleform-4-4-mobile-sdk-has-been-release...

 

Please try updating to this version if you haven't already and let us know if you continue to have issues.

 

Thanks,

 

Jeremy

Scaleform Support

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report