getDeviceId causes a crash

717 views
Skip to first unread message

ezmora

unread,
May 11, 2011, 10:01:31 AM5/11/11
to android-ndk
I would appreciate if one of the google folks could comment on this
one.
I'm trying to get the device id using the following code:

contextCls=(*env)->FindClass(env, "android/content/Context")
telephonyServiceFieldId = (*env)->GetStaticFieldID(env,
contextCls,
"TELEPHONY_SERVICE", "Ljava/lang/String;");
telephonyService = (*env)->GetStaticObjectField(env, contextCls,
telephonyServiceFieldId);
getSystemServiceMethodId = (*env)-
>GetMethodID(env,contextCls,"getSystemService","(Ljava/lang/String;)
Ljava/lang/Object;");
telephonyManagerObj = (*env)->CallObjectMethod(env,
cached_java_object, getSystemServiceMethodId,
telephonyService);
telephonyManagerCls = (*env)->FindClass(env, "android/telephony/
TelephonyManager");
getDeviceIdMethodId = (*env)-
>GetMethodID(env,telephonyManagerCls,"getDeviceId","()Ljava/lang/
String;");
imeiStr = (jstring)(*env)->CallObjectMethod(env, telephonyManagerObj,
getDeviceIdMethodId);

This code runs fine on a device with mobile capabilities, but when I
run it on the emulator or on a device which does not have a IMEI
(Nook), the application crashes.

The line of code that causes the crash is:
imeiStr = (jstring)(*env)->CallObjectMethod(env, telephonyManagerObj,
getDeviceIdMethodId);
I verified that none of the parameters are null. They are all valid,
yet still the application crashes.

I would assume that in case that IMEI does not exist, the call to the
above method would return NULL and not crash.

Any ideas?

Olivier Guilyardi

unread,
May 11, 2011, 10:31:55 AM5/11/11
to andro...@googlegroups.com

Whenever you call a JNI method, here FindClass(), GetMethodID(),
CallObjectMethod(), etc.. an exception may occur, in which case the method will
return NULL. If this occurs, the VM enters a special state, and you must not
call any other JNI method (apart from a very few one) until the exception gets
cleared. If you don't respect this rule, unexpected problems may happen.

http://java.sun.com/docs/books/jni/html/exceptions.html#26383
http://java.sun.com/docs/books/jni/html/design.html#2193

The fact that none of the CallObjectMethod() parameters are NULL doesn't
necessarily means that none of the previous calls returned NULL. Remember, if
you don't check for NULL result at every step, unexpected stuff may happen.

Adding such proper error checking is the first thing to do here IMO.

--
Olivier

alan

unread,
May 11, 2011, 11:17:09 AM5/11/11
to andro...@googlegroups.com

eyal zmora

unread,
May 11, 2011, 2:11:53 PM5/11/11
to andro...@googlegroups.com
I eliminated all method return checks from the mail to simplify the problem, but of course I check all return values in my code. If any of the methods return NULL, I simply exit. So if the method execution got that far, no NULLs were returned.

According to the documentation, if a JNI method returned NULL, an exception was thrown and needs to be cleared.
But, is it possible that no NULLs are returned yet still an Exception is thrown?



2011/5/11 Olivier Guilyardi <li...@samalyse.com>



--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.

Olivier Guilyardi

unread,
May 11, 2011, 2:30:30 PM5/11/11
to andro...@googlegroups.com
On 05/11/2011 08:11 PM, eyal zmora wrote:
> I eliminated all method return checks from the mail to simplify the
> problem, but of course I check all return values in my code. If any of
> the methods return NULL, I simply exit. So if the method execution got
> that far, no NULLs were returned.

I see.

>
> According to the documentation, if a JNI method returned NULL, an
> exception was thrown and needs to be cleared.
> But, is it possible that no NULLs are returned yet still an Exception is
> thrown?

http://java.sun.com/docs/books/jni/html/exceptions.html#26379

Notice the "Most":

"Most JNI functions use a distinct return value (such as NULL) to indicate that
an error has occurred."

And then:

"When using a JNI function whose return value cannot flag that an error has
occurred, native code must rely on the raised exception to do error checks. The
JNI function that performs checks for a pending exception in the current thread
is ExceptionOccurred. (ExceptionCheck was also added in Java 2 SDK release 1.2.)"

But unless I'm wrong, all functions that you are using can return NULL. You
don't call say a method returning jint.

I have used getDeviceId() a lot in Java, plenty of users, plenty of devices,
including many tablets. It doesn't crash AFAIK. I can't remember any feedback
from a Nook user though.

If you do the same thing in Java, does it crash?

Also, what is this cached_java_object exactly? An Activity, right? Do you
properly hold a global reference on it? Do you use it in the same thread where
it was instantiated (the main loop that is) ?

Have you checked the bug mentioned by alan?

--
Olivier

eyal zmora

unread,
May 11, 2011, 3:23:46 PM5/11/11
to andro...@googlegroups.com
I noticed the "most", but I also noticed the "instead":
When the JNI function returns a distinct error code, the native code may still check for exceptions explicitly by calling, for example, ExceptionCheck. However, it is more efficient to check for the distinct error return value instead. 

When I do the same thing in Java I get "000000".
cached_java_object is a global reference to an Activity, and no, it is used in another thread, but as far as I know this is allowed. You can access global referenced variables from different threads.

I haven't checked Alan's bug yet, but will do.

2011/5/11 Olivier Guilyardi <li...@samalyse.com>

--
 Olivier

Olivier Guilyardi

unread,
May 12, 2011, 7:48:16 AM5/12/11
to andro...@googlegroups.com
On 05/11/2011 09:23 PM, eyal zmora wrote:
> I noticed the "most", but I also noticed the "instead":
> When the JNI function returns a distinct error code, the native code may
> still check for exceptions explicitly by calling, for
> example, |ExceptionCheck|. However, it is more efficient to check for

> the distinct error return value instead.

Yes, ExceptionCheck() is only useful when you deal with functions which can't
return NULL, such a those which return an integer. But it's indeed not the
problem here. I just mentioned this for clarification.

By the way, I should have asked about this first, but what do you get in logcat?

A stack trace could help. IIRC, I once understood a weird crash by running the
NDK's addr2line on libdvm.so.

> When I do the same thing in Java I get "000000".

So, it doesn't crash in Java.

According to what alan mentioned and a bit of intuition, here's what I would try
here: create say a PlatformUtil class in Java, and add a getDeviceId(Context)
static method in there which hides the details of accessing the TelephonyManager
and returns the id string or NULL. And call that method with JNI.

I know it sounds like a workaround, but it could also help understand things I
guess.

> cached_java_object is a global reference to an Activity, and no, it is
> used in another thread, but as far as I know this is allowed. You can
> access global referenced variables from different threads.

Yes, as long as the thread is attached to the VM:
http://android.git.kernel.org/?p=platform/dalvik.git;a=blob_plain;f=docs/jni-tips.html;hb=HEAD#Threads

Olivier

eyal zmora

unread,
May 15, 2011, 3:01:25 AM5/15/11
to andro...@googlegroups.com
Thanks for your help Olivier.
I'll try both of your advices.

2011/5/12 Olivier Guilyardi <li...@samalyse.com>

Olivier

Reply all
Reply to author
Forward
0 new messages