Issues after the Change of Java Activity to Native Activity for Android

848 views
Skip to first unread message

James Chen

unread,
Aug 19, 2013, 9:57:20 AM8/19/13
to folecr, cocos2d-...@googlegroups.com

Hi Surith,
Cocos2d-x android port is using native activity instead of Java activity.
Thanks to this improvement, the performance of render loop has been
increased a lot. But there are two problems those cause compatibility issues.

1) How to pass an activity instance ( context argument ) to Java ?

Most of third party SDKs for android are written in Java, the question is
how to integrate these SDKs to cocos2d-x games after this change.
What I found was that the instance of native activity was passed to
"org/cocos2dx/lib/Cocos2dxHelper/init" method, the third party sdk could get
the context through Cocos2dxHelper.getActivity.

2) How to get response of system events in Java

Some third party SDKs like analysis alway need hack the onPause(onStop)
and onResume(onStart), so I think java also should get responses from
nativeactivity.cpp when these events happen.
Pseudo codes may be:

public class Cocos2dxHelper {
...

// jni method called from native
public static void onPause() {
// The codes for the third party sdk need to be inserted here.
    MobclickAgent.onPause(mContext);
}

// jni method called from native
public static void onResume() {
// The codes for the third party sdk need to be inserted here.
// And the context argument is needed.
    MobclickAgent.onResume(mContext);
}
...
}

Maybe you know that our Plugin-X has integrated lots of third party SDKs.
After this change, all the plugins in Plugin-X were broken.
So we need to fix this issue before the next release.

However, I don’t know whether what I mentioned above are the best ways to
resolve the issues.
Could you help to resolve the issues or give us some suggestions? Thanks.

Best Regards
James

folec r

unread,
Aug 19, 2013, 2:56:49 PM8/19/13
to James Chen, cocos2d-...@googlegroups.com
On Mon, Aug 19, 2013 at 6:57 AM, James Chen <jianhu...@cocos2d-x.org> wrote:

Hi Surith,
Cocos2d-x android port is using native activity instead of Java activity.
Thanks to this improvement, the performance of render loop has been
increased a lot. But there are two problems those cause compatibility issues.


Great! I think that the rendering performance has improved slightly. However the response time to user events (like touch) has improved a LOT. This allows Cocos games to be much more responsive. You can easily see this with SimpleGame - a user can shoot way more bullets in the same amount of time as compared to the earlier, slower Java based port.
 

1) How to pass an activity instance ( context argument ) to Java ?

Most of third party SDKs for android are written in Java, the question is
how to integrate these SDKs to cocos2d-x games after this change.
What I found was that the instance of native activity was passed to
"org/cocos2dx/lib/Cocos2dxHelper/init" method, the third party sdk could get
the context through Cocos2dxHelper.getActivity.

Yes. This works. (Please let me know if this answers your question.)

2) How to get response of system events in Java

Some third party SDKs like analysis alway need hack the onPause(onStop)
and onResume(onStart), so I think java also should get responses from
nativeactivity.cpp when these events happen.
Pseudo codes may be:

public class Cocos2dxHelper {
...

// jni method called from native
public static void onPause() {
// The codes for the third party sdk need to be inserted here.
    MobclickAgent.onPause(mContext);
}

// jni method called from native
public static void onResume() {
// The codes for the third party sdk need to be inserted here.
// And the context argument is needed.
    MobclickAgent.onResume(mContext);
}
...
}

Maybe you know that our Plugin-X has integrated lots of third party SDKs.
After this change, all the plugins in Plugin-X were broken.
So we need to fix this issue before the next release.

However, I don’t know whether what I mentioned above are the best ways to
resolve the issues.
Could you help to resolve the issues or give us some suggestions? Thanks.

I can think of two ways to do this :

1. Subclass NativeActivity in Java

One could subclass this to be modified from Java

2. Make JNI calls from C code

Use the callbacks defined in <android-ndk>/platforms/android-9/arch_[arm|x86|mips]/usr/include/native_activity.h
    void (*onPause)(ANativeActivity* activity);
    void (*onResume)(ANativeActivity* activity);
    etc...

I prefer (2) Why?
  1. Third party SDKs are often buggy and cause game crashes. It is good to be able to disable calling into these SDKs from game code so that the developer can isolate issues. It is much easier to isolate issues without Java subclassing and XML modifications.
  2. Game code is more readable when plugins are not in the main application lifecycle. i.e. entire game lifecycle is in C/C++ and Java/JNI calls are only made for non-game processing.
When I am done with my current work of fixing bugs in the Android rendering my plan is to update one of the plugin samples. It would be great if you get a chance to try it out before I do!

Thanks,
 Surith

Best Regards
James

--
You received this message because you are subscribed to the Google Groups "cocos2d JS development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cocos2d-js-dev...@googlegroups.com.
To post to this group, send email to cocos2d-...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

James Chen

unread,
Aug 20, 2013, 10:39:51 AM8/20/13
to folec r, cocos2d-...@googlegroups.com, zhangbin
Great! I think that the rendering performance has improved slightly. However the response time to user events (like touch) has improved a LOT. This allows Cocos games to be much more responsive. You can easily see this with SimpleGame - a user can shoot way more bullets in the same amount of time as compared to the earlier, slower Java based port.

I tested SimpleGame project with v2.1.4 and develop branch on the github.
But I could not figure out how much responsive after using native activity since the result seems be the same.
The android device I used was MX2 android4.1, 2.0G CPU, 2G RAM.

Use the callbacks defined in /platforms/android–9/arch_[arm|x86|mips]/usr/include/native_activity.h

void (onPause)(ANativeActivity activity);

void (onResume)(ANativeActivity activity);

etc…

I prefer (2) Why?
Third party SDKs are often buggy and cause game crashes. It is good to be able to disable calling into these SDKs from game code so that the developer can isolate issues. It is much easier to isolate issues without Java subclassing and XML modifications.

Yep, I prefer 2) too. Plugin-x also needs to provide c++ interfaces too.

Game code is more readable when plugins are not in the main application lifecycle. i.e. entire game lifecycle is in C/C++ and Java/JNI calls are only made for non-game processing.

That seems to be great. But there are some questions:

(1) Is the native activity running on UI Thread or GL Thread like before?

In Plugin-x, all JNI invocations of Java API should be run on UI thread.
In that case, we got a method like runOnUIThread to post events to UI thread and
call the third party API in UI thread.

I don’t know how to do that since there aren’t any Java codes now.

(2) Could JNI_OnLoad works now ?

Before, we have in SomeGame/proj.android/jni/main.cpp

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JniHelper::setJavaVM(vm);
    PluginJniHelper::setJavaVM(vm);  // Pass VM argument to Plugin which is for JNI interactions.
    return JNI_VERSION_1_4;
}

Now, we get this:

void cocos_android_app_init (void) {
    LOGD("cocos_android_app_init");
    AppDelegate *pAppDelegate = new AppDelegate();
}

In order to set vm to plugin, we need to insert codes as follows:

void cocos_android_app_init (void) {
    LOGD("cocos_android_app_init");
    PluginJniHelper::setJavaVM(JniHelper::getJavaVM()); // Set vm for plugin here.
    AppDelegate *pAppDelegate = new AppDelegate();
}

Since cocos_android_app_init is done in game code, it’s the entry developer could see.
All initalization of third party SDKs need to be done here.
One thing we have to know is Plugin-x doesn’t depend on cocos2d-x, so any plugin
codes should not be placed in engine. Therefore, in plugin codes in Java should not
invoke Cocos2dxHelper.getActivity directly.

Solution:

I think the arguments of cocos_android_app_init
should not be void. It should contain an activity at least.
Thing may go to in this way:

void cocos_android_app_init (sometype nativeApp) {
    LOGD("cocos_android_app_init");
    PluginJniHelper::setJavaVM(nativeApp->activity->vm);// set vm for plugin here.
    initPluginMananger(nativeApp->activity); // Set the context for plugin
    AppDelegate *pAppDelegate = new AppDelegate();
}
When I am done with my current work of fixing bugs in the Android rendering my plan is to update one of the plugin samples. It would be great if you get a chance to try it out before I do!

@ZhangBin, who is the maintainer of plugin-x, will try to fix the broken issue.

We will let you know our progress.

Could you help us figure out the two problems I mentioned above?

Regards
James

folecr

unread,
Aug 20, 2013, 7:26:04 PM8/20/13
to cocos2d-...@googlegroups.com, folec r, zhangbin


On Tuesday, August 20, 2013 7:39:51 AM UTC-7, jianhua.chen wrote:
Great! I think that the rendering performance has improved slightly. However the response time to user events (like touch) has improved a LOT. This allows Cocos games to be much more responsive. You can easily see this with SimpleGame - a user can shoot way more bullets in the same amount of time as compared to the earlier, slower Java based port.

I tested SimpleGame project with v2.1.4 and develop branch on the github.
But I could not figure out how much responsive after using native activity since the result seems be the same.
The android device I used was MX2 android4.1, 2.0G CPU, 2G RAM.

I am using an LG Nexus 4/Android 4.3. Could you please let me know what benchmark you are using? Thanks.
1. The native activity has it's own thread and runs android_main() in it https://github.com/cocos2d/cocos2d-x/blob/develop/cocos2dx/platform/android/nativeactivity.cpp#L466
This is registered with the EGL interface so that rendering may be done from within this thread

2. The VM and the pointer to the current Android Application Context is available from struct android_app* app.
This can be easily referenced to set the VM and to obtain an Application Context as the plugin requires.

The relevant headers are in the android-ndk
<android-ndk>/platforms/android-9/arch-arm/usr/include/android/native_activity.h
<android-ndk>/sources/android/native_app_glue/android_native_app_glue.h

Please let me know if this helps. I'll take a look at the cocos2d-x plugin interface too.

Thanks,
Surith

Regards
James

James Chen

unread,
Aug 20, 2013, 10:10:51 PM8/20/13
to folecr, cocos2d-...@googlegroups.com, zhangbin
Red comments below are my reply. :)

On Aug 21, 2013, at 7:26 AM, folecr <fol...@gmail.com> wrote:



On Tuesday, August 20, 2013 7:39:51 AM UTC-7, jianhua.chen wrote:
Great! I think that the rendering performance has improved slightly. However the response time to user events (like touch) has improved a LOT. This allows Cocos games to be much more responsive. You can easily see this with SimpleGame - a user can shoot way more bullets in the same amount of time as compared to the earlier, slower Java based port.

I tested SimpleGame project with v2.1.4 and develop branch on the github.
But I could not figure out how much responsive after using native activity since the result seems be the same.
The android device I used was MX2 android4.1, 2.0G CPU, 2G RAM.

I am using an LG Nexus 4/Android 4.3. Could you please let me know what benchmark you are using? Thanks.

Sorry, I didn't use a benchmark to test the response time of user events.  I just touch the touch by hand with fast speed. :)
Could you tell me which benchmark are you using? I will be glad to test it again.
So are all events pushed to native activity's thread?  We recommend all third party SDK APIs are invoked on UI thread. How to achieve that?
How to post events from native thread to UI thread after a JNI invocation in JAVA since there is not any handler created in UI thread.

Before, we could create an UI handler when initialize Java Activity, if there is an event need to be post to UI thread, we will do

public static void init(Context context)
{
sContext = context;
if (null == sMainThreadHandler) {
sMainThreadHandler = new Handler();
}
}

public static void runOnGLThread(Runnable r) {
if (null != sGLSurfaceView) {
sGLSurfaceView.queueEvent(r); // Using GLSurfaceView to post events from UI thread to GL thread( cocos2d-x thread).
} else {
Log.i(TAG, "runOnGLThread sGLSurfaceView is null");
r.run();
}
}

public static void runOnMainThread(Runnable r) {
if (null == sMainThreadHandler) return;
sMainThreadHandler.post(r); // Post events from GL thread to UI thread (Main thread).
}

There is also a problem how to post events from UI thread to GL thread?


2. The VM and the pointer to the current Android Application Context is available from struct android_app* app.
This can be easily referenced to set the VM and to obtain an Application Context as the plugin requires.

The relevant headers are in the android-ndk
<android-ndk>/platforms/android-9/arch-arm/usr/include/android/native_activity.h
<android-ndk>/sources/android/native_app_glue/android_native_app_glue.h


Therefore, do you agree that cocos_android_app_init should take an argument( nativeApp) ?

folec r

unread,
Aug 21, 2013, 2:42:37 AM8/21/13
to James Chen, cocos2d-...@googlegroups.com, zhangbin
@ZhangBin, @dumganahar,

Could you prototype this for one plugin (maybe an important one) and make a pull request on github? It would be more efficient to discuss it there. It doesn't have to be 100% perfect but good enough for discussion.

Many plugins are unfortunately not designed correctly so impose unreasonable requirements... perhaps we need to subclass NativeActivity... perhaps we could in some cases convince the plugin authors to rewrite plugins... perhaps we could show a transparent Activity over the cocos activity... There are quite a few documented cases of using NativeActivity with some of these plugins - even plugins that have been designed badly - so it is certainly possible.

I'll take a look at one of the plugins too.

Thanks,
 Surith

James Chen

unread,
Aug 21, 2013, 5:46:47 AM8/21/13
to zhangbin, folec r, cocos2d-...@googlegroups.com
That will be great. :)

On Aug 21, 2013, at 5:39 PM, zhangbin <zhan...@cocos2d-x.org> wrote:

Hi, Surith.

It's really a good idea. I will modify the code of sample project in plugin and send a pull request.

Then we can discuss the problems on the pull request.

I will finish this work in 1 or 2 days. Thanks for your suggestion!

Best Regards!
----------------------------------------------------------
Bill Zhang

folec r

unread,
Aug 21, 2013, 5:04:25 PM8/21/13
to James Chen, zhangbin, cocos2d-...@googlegroups.com
It's been a while since I looked at the various SDKs so I'll try them out too.

Thanks,
 Surith



zhangbin

unread,
Aug 23, 2013, 3:01:26 AM8/23/13
to folec r, James Chen, cocos2d-...@googlegroups.com
@Surith

Here is my pull request:

There are two things I did in the pull request:
1. Add an interface in class PluginUtils to init the variable activity in PluginWrapper.java
2. Modify the implementation of method getClassID() in class PluginJniHelper

Now the code can be compiled successfully. 
But I encounter a problem:
In java class PluginWrapper, the method init() need new a handler to handle the messages on UI thread.
Now it's invoked from JNI.  Then the sample is crashed.

The java code of PluginWrapper:

I think it's a problem of thread. I don't know how to invoke the init() method from JNI & UI thread.

Hope for your help! Thank you very much!

Best Regards!
----------------------------------------------------------
Bill Zhang

folec r

unread,
Aug 25, 2013, 12:19:44 PM8/25/13
to zhangbin, James Chen, cocos2d-...@googlegroups.com
@zhangbin

Thanks! The modifications to android_app_init() to take the Activity pointer look good!

I added comments on the pull request. Activity.runOnUiThread() should be the method to call to schedule Runnable's on the UI thread. And since you have modified the code to take the pointer to the Acitivity you can call this method from Java code.


Let's discuss further on github.
Reply all
Reply to author
Forward
0 new messages