Friday, July 17, 2015

JNI Error: Local reference table overflow


If you are working on JNI, you may have faced issue:

"Local reference table overflow 512 entries"

Say you have following code, you will immediately get this issue.

void methodOne()
{
for(int i = 0 ; i < 1000 ; i++)
{
jobject localReferenceOne = ...;
methodTwo(localReferenceOne);
}
}

void methodTwo(jobject parameter)
{
jobejct localReferenceTwo = ...;
}

First You should delete all local reference once you are done with that.

void methodOne()
{
for(int i = 0 ; i < 1000 ; i++)
{
jobject localReferenceOne = ...;
methodTwo(localReferenceOne);
env->DeleteLocalRef(localReferenceOne);
}
}

void methodTwo(jobject parameter)
{
jobejct localReferenceTwo = ...;
...
env->DeleteLocalRef(localReferenceOne);
}

But you will still faces the issue. This is because parameter also local reference. You cannot delete the parameter using DeleteLocalRef. To delete parameter local reference you need to call PushLocalFrame and PopLocalFrame before and after method call.

void methodOne()
{
for(int i = 0 ; i < 1000 ; i++)
{
env->PushLocalFrame(0);
jobject localReferenceOne = ...;
methodTwo(localReferenceOne);
env->DeleteLocalRef(localReferenceOne);
env->PopLocalFrame(0);
}
}

void methodTwo(jobject parameter)
{
jobejct localReferenceTwo = ...;
...
env->DeleteLocalRef(localReferenceOne);
}

Tuesday, April 15, 2014

Android JNI Call back


In the above images shows all possible scenarios of Android JNI calls and its call backs.

Android UI mostly implemented in Java, then if needed there will be C++ implementation to  perform low level operations. In this case JNI is used.

1. Java to C++ calls :
First UI will need to make some call to C++, for example start engine etc.

In Java:
1.1. Need to write a native method:
package demo;
class Service{
     public static native doSomething();
}
1.2. Call this method to invoke/access the low level.
....
//Somewhere
Service.doSomething();
....

In C++:
1.2. Need to write the implementation for above native method:
JNIEXPORT jint JNICALL Java_demo_Service_doSomeThing(JNIEnv * env, jobject ){
..............
..............
}

2. C++ to Java Call
There may be some cases C++ Implementation may need to call back UI, for example inform the progress update.
This can happen from the same thread which the initial called made from Java or C++ may have created a new thread and may call from there.

In Java: Write a Observer to receive those call backs.
package demo;
class Service{
     public static void onCallBack(){
          ............
          //add implementation to handle call back
          ...............
     }
}

Any callback from C++ to Java need to be implemented using given JNI refection APIs.

jclass jcls = env->FindClass("dem/Service");
jmethodID mid = env->GetStaticMethodID(jcls,"onCallBack","....");
env->CallStaticVoidMethod(jcls,mid);

This will perform what we want, but we will need some more extra implementation to make it work in caseof concurrent access from c++.

2.1 Calling from same thread.
In this case, the above listing will work without any issue. We can use the same JNIEnv which passed in Java_demo_Service_doSomeThing call above 1.2

2.2 Calling from other thread 
In this case we cannot use the above env passed with Java_demo_Service_doSomeThing   as it is invalid in other threads.
So We have to create a new JNIEnv using JavaVM, which is passed in JNI_OnLoad.
So,
2.2.1 Write a JNI_OnLoad in your native c++ code:

static JavaVM * s_Jvm;

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
        s_Jvm = vm;//Keep for future use.
return JNI_VERSION_1_6;

}

2.2.2 Attach Current Thread to create JNIEnv:
JNIEnv * env;
s_Jvm->AttachCurrentThread(&env,NULL);

2.2.3 If you try FindClass with this JNIEnv it will return NULL in Android since uses special Class Loader in Java and in New thread which created in C++ will use the

jclass jcls = env->FindClass("dem/Service");

2.2.4 So this should be done inside OnLoad method : (code are in bold) and assign to global reference to use in future.

jclass s_jcls;

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
        s_Jvm = vm;//Keep for future use.
        s_jcls =  env->NewGlobalRef(env->FindClass("dem/Service"));
return JNI_VERSION_1_6;

}

2.2.5 Now you can use this s_jcls to make any call backs

GetStaticMethodID
CallStaticObjectMethod

etc...


Saturday, January 25, 2014

Visio: Adding New Connection Points to Shape

Step 1: Click on the X icon next to connection icon

 Step 2: Press Ctrl and click on the Shape where you want the new connection point.



Tuesday, October 8, 2013

Eclipse, Ant, CVS with Windows 7

I got a new machine with Windows 7, and started to setup my build environment.

We have an ant script to update from CVS and tag and etc...

Simply adding following ant task I could do this.

<target name="cvs_update">
<cvs command="update -dP">
</cvs>
</target>
<target name="cvs_tag">
<cvs command="tag ABC_${build_time}">
</cvs>
</target>

But, we should install WinCVS/CVSNT to run this task.

In Windows 7 I got a first issue, ant couldn't find the cvs.exe even if the cvs.exe in PATH variable. And if you check the in command prompt by type cvs it will run. But in Eclipse when you run above ant task it will keep saying application cvs not found.

[cvs] Caught exception: Cannot run program "cvs": CreateProcess error=2, The system cannot find the file specified

Only solution I found is:
uninstall and install CVSNT into a folder, which name doesn't have any spaces (Example Program_Files_(x86))

The 2nd I faced in login

 [cvs] cvs update: Empty password used - try 'cvs login' with a real password [cvs]

The only solution I found is:
Run CVSNT Password Agent.

Saturday, May 18, 2013

Eclipse, Java : Inserting Single line "if block"

If we run our program after completing coding, those will not as excepted mostly, or at-least in testing we will find places where we have missed some null check or etc. So we may have to add a if condition to check and to avoid those Exceptions. Mostly those will be a single line "if blocks".

I am talking about cases like below. Say you have following line:

myObject.myMethod();

Here we got a NullPointerException because myObject is null, I wanted added a null check before this:

if(myObject!=null)
     myObject.myMethod();

This is correct, but I mostly don't like this, for future coding and because of the readability, I prefer to add a block as follows. Sometime reader will think that, all the statements which following the above statement also inside the if condition.

if(myObject!=null){
     myObject.myMethod();
}

It was hard for me always, because I had to write if block and copy paste the statement inside. But i found a method to do in Eclipse without  doing  copy paste.

Just go infront of the statement and start typing your if condition and write up to { and press enter key, then you will get what you want.

if(myObject!=null){|myObject.myMethod(); <-- font="">Keep the curser at the | position and press enter.

Okey now you try and let me know your comments.

Wednesday, January 30, 2013

Part 2:Useful Eclipse Templates for Android Development

Part 1:Useful Eclipse Templates for Android Development

Weak Reference for Views in Activity.

Inside onCreate of each Android Activity we used to setContentView with layout xml. Then to access each view from the activity we use:

View view = findViewById(R.id..........);

to avoid calling  findViewById multiple time,  call this only in onCreate and keep this view as member variable inside activity.

View mView

.....

mView = findViewById(R.id..........);

Then, question is why we need to overload the onCreate method, we call findViewById only when needed and keep as member variable. So introduce following get method.

View getView(){
     if(mView==null){
         mView = findViewById(R.id..........);
     }
     return mView;
}

But in some cases, to avoid memory leakage issues, we need to remove all view from content view and need to null all these references in activity. But rather find each reference and assign to null, if we make a weak reference then it should all clear as we remove view from activity. For Example:


private WeakReference mView;
public View getView() {
if(!(mView!=null && mView.get()!=null)){
mView = new WeakReference((View) findViewById(R.id.....));
}
return mFrameAddStyleView.get();
}
Now, Let see how to write a Eclipse template to auto generate this:

Eclipse - > Windows -> Preferences -> Java -> Editor -> Templates -> New ...
Name:- wfind
Pattern:-
private WeakReference<${type}> m${new_name};
public ${type} get${new_name}() {
if(!(m${new_name}!=null && m${new_name}.get()!=null)){
m${new_name} = new WeakReference<${type}>((${type}) findViewById(R.id.${cursor}));
}
return m${new_name}.get();
}


Now go to your activity class and type wfind and press Ctrl+Space you will get what you want.

Thursday, November 15, 2012

Android: UI Automator Viewer (uiautomatorviewer) - issue in landscape screen

If you are ttrying to use UI Testing tools introduced in Android SDK Tools, Revision 21  you will see a port-tailed image in uiautomatorviewer capture for landscape activities.
Hover over selection and uix file will perform properly, but only issue will be the image will not be aligned properly.
I found a possible workaround, just close the file (note down the location) and got the folder, you will see a image, please rotate accordingly.
Then come back and reopen the uix, it will ask for the screen slot, just show the rotated screen.