Hi All!
For the past few days I’ve been pulling my hair, trying to find what causes a problem with a pretty simple plugin.
So here comes the explanation:
I am trying to create a simple plugin, that just starts a native android activity. The activity is to be transparent, because I do not really want to display anything to the user. Now, you may say that I should use a Service if I want no GUI, but just a background execution. Well, in my defense, I will say that I need it to be an activity so that I can start another activity for result. For now, I will just stick to the main native activity( skipping the one for result ) because the problem comes from it.
Here we begin:
- Entry point for the communication → getting an instance of the java class.
Well, here is how I create the connection:
public class SamplePlugin {
private static SampleUnity mInstance;
public static SampleUnity GetInstance() {
if(mInstance == null) {
mInstance = new SampleUnity(UnityPlayer.currentActivity);
}
//Log.i("GET INSTANCE", "GET INSTANCE");
return mInstance;
}
}
This way I get the instance of SampleUnity class:
public class SampleUnity {
private Activity mActivity;
public SampleUnity( final Activity activity ) {
this.mActivity = activity;
}
public void StartNewActivity( ) {
Intent intent = new Intent(mActivity, NewActivity.class);
mActivity.startActivity(intent);
}
}
Now let’s look at the new activity:
public class NewActivity extends Activity{
@Override
public void onCreate(final Bundle mSavedInstanceState) {
super.onCreate(mSavedInstanceState);
// Can go with or without this contentView( I do not really need it ).
Resources res = getResources();
setContentView( res.getIdentifier("new_activity", "layout", this.getPackageName()));
//Just for now, I use finish(), but actually startActivityForResult goes here.
finish();
}
}
Ewww, what? A whole new activity just to close it? Well…I want to just hit you in the face with new window…
Okay so, this activity lifecycle goes as ----> onCreate() ->onDestroy()
Now the activity disappears and I am back in the game.
Now how a look at the C# part in Unity:
public class SamplePlugin {
private static AndroidJavaObject _plugin;
static SamplePlugin() {
if( Application.platform != RuntimePlatform.Android )
return;
// find the plugin instance
using( AndroidJavaClass pluginClass = new AndroidJavaClass( "com.me.unity.myplugin.SamplePlugin" ) )
_plugin = pluginClass.CallStatic<AndroidJavaObject>( "GetInstance" );
}
public static void StartNewActivity( ) {
if( Application.platform != RuntimePlatform.Android )
return;
_plugin.Call( "StartNewActivity");
}
}
And I put these lines in the manifest:
<activity android:name="com.me.unity.myplugin.NewActivity" >
</activity>
And now, when I click the big red button in game, the magic happens:::: my new activity is launched
and immediately destroyed( “adb shell dumpsys activity” confirmed that! ).
Here comes the BOOM:
Now … the real part of the problem.
When I am back in my game, I quit the game as soon as possible( using Application.Quit() ).
“Oh, mah game is closed.” - my first thought after that.
Well… I tried launching the game again and the big bad dump hit me in the face:
ActivityManager(498): Displayed com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity: +869ms (total +9s448ms)
DEBUG(26059): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
DEBUG(26059): Build fingerprint: 'google/nakasi/grouper:4.4/KRT16S/920375:user/release-keys'
DEBUG(26059): Revision: '0'
DEBUG(26059): pid: 11354, tid: 11443, name: Thread-1060 >>> com.me.myunitygame <<<
DEBUG(26059): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
DEBUG(26059): r0 00000000 r1 6abd28d0 r2 00000001 r3 00000000
DEBUG(26059): r4 00010000 r5 6acd0810 r6 6abd28d0 r7 6b055fbc
DEBUG(26059): r8 6b153b10 r9 6b055fb4 sl 6d01a9b8 fp 6b153b24
DEBUG(26059): ip 00000001 sp 6b1539f0 lr 401672c7 pc 6a259b00 cpsr 20000010
DEBUG(26059): d0 0000001c00000010 d1 0000000000000000
DEBUG(26059): d2 0000000000000000 d3 0000000000000000
DEBUG(26059): d4 0000000000000000 d5 00000494e2000000
DEBUG(26059): d6 4492800044480000 d7 3f8000003f800000
DEBUG(26059): d8 0000000000000000 d9 0000000000000000
DEBUG(26059): d10 0000000000000000 d11 0000000000000000
DEBUG(26059): d12 0000000000000000 d13 0000000000000000
DEBUG(26059): d14 0000000000000000 d15 0000000000000000
DEBUG(26059): d16 000000000000001c d17 223d656d616e206c
DEBUG(26059): d18 00328c7400316d3c d19 0034cae40033abac
DEBUG(26059): d20 0008f9c00008f9c0 d21 0008f9c00008f9c0
DEBUG(26059): d22 0000000100000001 d23 0000000100000001
DEBUG(26059): d24 0000002a00000029 d25 0000002c0000002b
DEBUG(26059): d26 00944026008fc024 d27 009d40280098c027
DEBUG(26059): d28 0000002900000028 d29 0000002b0000002a
DEBUG(26059): d30 00a6402a00a1c029 d31 00af402c00aac02b
DEBUG(26059): scr 80000010
DEBUG(26059): backtrace:
DEBUG(26059): #00 pc 000b6b00 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): #01 pc 0027a088 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): #02 pc 003a26b4 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): #03 pc 003a3084 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): #04 pc 003a3210 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): #05 pc 0001dbcc /system/lib/libdvm.so (dvmPlatformInvoke+112)
DEBUG(26059): #06 pc 0004e123 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398)
DEBUG(26059): #07 pc 00026fe0 /system/lib/libdvm.so
DEBUG(26059): #08 pc 0002dfa0 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
DEBUG(26059): #09 pc 0002b638 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
DEBUG(26059): #10 pc 00060581 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+336)
DEBUG(26059): #11 pc 000605a5 /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+20)
DEBUG(26059): #12 pc 0005528b /system/lib/libdvm.so
DEBUG(26059): #13 pc 0000d228 /system/lib/libc.so (__thread_entry+72)
DEBUG(26059): #14 pc 0000d3c0 /system/lib/libc.so (pthread_create+240)
DEBUG(26059): stack:
DEBUG(26059): 6b1539b0 00000010
DEBUG(26059): 6b1539b4 401672c7 /system/lib/libc.so
DEBUG(26059): 6b1539b8 00010000
DEBUG(26059): 6b1539bc 6abd28d0
DEBUG(26059): 6b1539c0 6abd28d0
DEBUG(26059): 6b1539c4 6b055fbc
DEBUG(26059): 6b1539c8 6b153b10
DEBUG(26059): 6b1539cc 40163d01 /system/lib/libc.so (memalign+12)
DEBUG(26059): 6b1539d0 6abaeb38 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): 6b1539d4 6a2580d0 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): 6b1539d8 00010000
DEBUG(26059): 6b1539dc 6a258118 /data/app-lib/com.me.myunitygame-1/libunity.so
DEBUG(26059): 6b1539e0 00010000
And 1 more kilometer of DEBUG log which I am going to paste here…
After that the exceptions come( obviously because the process gets killed, duh ) :
ActivityManager(498): Force finishing activity com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity
InputDispatcher(498): channel '42893930 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x9
InputDispatcher(498): channel '42893930 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
InputDispatcher(498): channel '428c0080 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x9
InputDispatcher(498): channel '428c0080 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
Zygote(123): Process 11354 terminated by signal (11)
dalvikvm(498): GC_FOR_ALLOC freed 1007K, 19% free 18269K/22344K, paused 77ms, total 77ms
WindowState(498): WIN DEATH: Window{428d6f08 u0 SurfaceView}
dalvikvm(498): GC_FOR_ALLOC freed 589K, 19% free 18178K/22344K, paused 65ms, total 65ms
InputDispatcher(498): Attempted to unregister already unregistered input channel '42893930 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity (server)'
WindowState(498): WIN DEATH: Window{42893930 u0 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity}
InputDispatcher(498): Attempted to unregister already unregistered input channel '428c0080 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity (server)'
WindowState(498): WIN DEATH: Window{42b55ac0 u0 SurfaceView}
WindowState(498): WIN DEATH: Window{428c0080 u0 com.me.myunitygame/com.unity3d.player.UnityPlayerNativeActivity}
ActivityManager(498): Exception thrown during pause
ActivityManager(498): android.os.DeadObjectException
ActivityManager(498): at android.os.BinderProxy.transact(Native Method)
ActivityManager(498): at android.app.ApplicationThreadProxy.schedulePauseActivity(ApplicationThreadNative.java:660)
ActivityManager(498): at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:755)
ActivityManager(498): at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:2408)
ActivityManager(498): at com.android.server.am.ActivityStack.finishTopRunningActivityLocked(ActivityStack.java:2279)
ActivityManager(498): at com.android.server.am.ActivityStackSupervisor.finishTopRunningActivityLocked(ActivityStackSupervisor.java:2018)
ActivityManager(498): at com.android.server.am.ActivityManagerService.handleAppCrashLocked(ActivityManagerService.java:9389)
ActivityManager(498): at com.android.server.am.ActivityManagerService.makeAppCrashingLocked(ActivityManagerService.java:9284)
ActivityManager(498): at com.android.server.am.ActivityManagerService.crashApplication(ActivityManagerService.java:9926)
ActivityManager(498): at com.android.server.am.ActivityManagerService.handleApplicationCrashInner(ActivityManagerService.java:9478)
ActivityManager(498): at com.android.server.am.NativeCrashListener$NativeCrashReporter.run(NativeCrashListener.java:86)
ActivityManager(498): Process com.me.myunitygame (pid 11354) has died.
And one NullPointerException , or two…
So. After the process is killed I can launch my game again.
Remember when I said that I wanted to make my activity transparent? Well, yeah, I just add a theme to my activity in the manifest:
<activity android:name="com.me.unity.myplugin.NewActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
</activity>
or
<activity android:name="com.me.unity.myplugin.NewActivity"
android:theme="@android:style/Theme.NoDisplay">
</activity>
This does the trick.
So…here are some different scenarios :
-
When I launch the native activity, it executes and finishes. Then I am back in my game. If I minimize the game, then open it again( its state is restored ) and THEN I quit it, it quits as it should. No problems occur.
-
When I launch the native activity, it executes and finishes. Then I am back in my game. Sometimes(not always) if I wait a few seconds before I quit it, it quits normally. No problems occur( sometimes ).
-
When I put Theme.NoDisplay on my activity, after it finishes and I am back in the game, I quit the game and the problem I mentioned happens( 100% ).
-
I put Theme.Translucent.NoTitleBar.Fullscreen on my activity. After it finishes, I am back in the game. I wait a few seconds and quit the game. Sometimes the problem occurs, sometimes not. ( 50% ).
-
I put no theme on my activity. After it finishes, I am back in the game. I wait a few seconds( less than when I put Translucent theme), I quit the game and usually there is not problem. If I quit the game too fast, the problem occurs.
-
Setting content view in my activity ( setContentView ) makes the game more likely to quit without problem. But still, the problem occurs sometimes.
-
I tried with BroadcastReceiver from which I launch the new activity → same behaviour.
-
I cannot confirm 100% but if I let my activity go through all of its states when created( not call finish in onCreate ) , the problem does not occur( or may happen but really rarely ).
-
I tried putting a timer in onCreate, which executes finish() on my activity ( through a handler - on the main thread ) when it finishes. I tested it a few times, and when the native activity is closed and I quit the game, there is not problem.
When the problem occurs, I usually execute the “adb shell dump sys activity” in the terminal, and I see that UnityPlayerNativeActivity is in the state: Activities Waiting to Stop.
Soooo I smell there is some background dark magic going on, which somehow keeps the process alive.
So these are the scenarios I can think of ( that I have tested ). There may be 1 or 2 I am missing but I tested tons of different options, and nothing helped at 100%.
To me, this behaviour is pretty much UNKNOWN. So I hope there is somebody who can tell me where I go wrong, or what option can I try to solve the issue.
Oh… and I hope I did not forget to show any important part of the project.
Here comes my apology:
- Sorry if I misconstructed, misspelled or anything similar with the English language.
- Sorry for burning your eyes with the long post.
- I want to apologize to myself for creating a big bald spot on the back of my head.