Tuesday, 19 July 2011

Debugging Android JNI with CheckJNI

[This post is by Elliott Hughes, a Software Engineer on the Dalvik team — Tim Bray]

Although most Android apps run entirely on top of Dalvik, some use the Android NDK to include native code using JNI. Native code is harder to get right than Dalvik code, and when you have a bug, it’s often a lot harder to find and fix it. Using JNI is inherently tricky (there’s precious little help from the type system, for example), and JNI functions provide almost no run-time checking. Bear in mind also that the developer console’s crash reporting doesn’t include native crashes, so you don’t even necessarily know how often your native code is crashing.

What CheckJNI can do

To help, there’s CheckJNI. It can catch a number of common errors, and the list is continually increasing. In Gingerbread, for example, CheckJNI can catch all of the following kinds of error:

  • Arrays: attempting to allocate a negative-sized array.

  • Bad pointers: passing a bad jarray/jclass/jobject/jstring to a JNI call, or passing a NULL pointer to a JNI call with a non-nullable argument.

  • Class names: passing anything but the “java/lang/String” style of class name to a JNI call.

  • Critical calls: making a JNI call between a GetCritical and the corresponding ReleaseCritical.

  • Direct ByteBuffers: passing bad arguments to NewDirectByteBuffer.

  • Exceptions: making a JNI call while there’s an exception pending.

  • JNIEnv*s: using a JNIEnv* from the wrong thread.

  • jfieldIDs: using a NULL jfieldID, or using a jfieldID to set a field to a value of the wrong type (trying to assign a StringBuilder to a String field, say), or using a jfieldID for a static field to set an instance field or vice versa, or using a jfieldID from one class with instances of another class.

  • jmethodIDs: using the wrong kind of jmethodID when making a Call*Method JNI call: incorrect return type, static/non-static mismatch, wrong type for ‘this’ (for non-static calls) or wrong class (for static calls).

  • References: using DeleteGlobalRef/DeleteLocalRef on the wrong kind of reference.

  • Release modes: passing a bad release mode to a release call (something other than 0, JNI_ABORT, or JNI_COMMIT).

  • Type safety: returning an incompatible type from your native method (returning a StringBuilder from a method declared to return a String, say).

  • UTF-8: passing an invalid Modified UTF-8 byte sequence to a JNI call.

If you’ve written any amount of native code without CheckJNI, you’re probably already wishing you’d known about it. There’s a performance cost to using CheckJNI (which is why it isn’t on all the time for everybody), but it shouldn’t change the behavior in any other way.

Enabling CheckJNI

If you’re using the emulator, CheckJNI is on by default. If you’re working with an Android device, use the following adb command:

adb shell setprop debug.checkjni 1

This won’t affect already-running apps, but any app launched from that point on will have CheckJNI enabled. (Changing the property to any other value or simply rebooting will disable CheckJNI again.) In this case, you’ll see something like this in your logcat output the next time each app starts:

D Late-enabling CheckJNI

If you don’t see this, your app was probably already running; you just need to force stop it and start it again.

Example

Here’s the output you get if you return a byte array from a native method declared to return a String:

W JNI WARNING: method declared to return 'Ljava/lang/String;' returned '[B'
W failed in LJniTest;.exampleJniBug
I "main" prio=5 tid=1 RUNNABLE
I | group="main" sCount=0 dsCount=0 obj=0x40246f60 self=0x10538
I | sysTid=15295 nice=0 sched=0/0 cgrp=default handle=-2145061784
I | schedstat=( 398335000 1493000 253 ) utm=25 stm=14 core=0
I at JniTest.exampleJniBug(Native Method)
I at JniTest.main(JniTest.java:11)
I at dalvik.system.NativeStart.main(Native Method)
I
E VM aborting

Without CheckJNI, you’d just die via SIGSEGV, with none of this output to help you!

New JNI documentation

We’ve also recently added a page of JNI Tips that explains some of the finer points of JNI. If you write native methods, even if CheckJNI isn’t rejecting your code, you should still read that page. It covers everything from correct usage of the JavaVM and JNIEnv types, how to work with native threads, local and global references, dealing with Java exceptions in native code, and much more, including answers to frequently-asked JNI questions.

What CheckJNI can’t do

There are still classes of error that CheckJNI can’t find. Most important amongst these are misuses of local references. CheckJNI can spot if you stash a JNIEnv* somewhere and then reuse it on the wrong thread, but it can’t detect you stashing a local reference (rather than a global reference) and then reusing it in a later native method call. Doing so is invalid, but currently mostly works (at the cost of making life hard for the GC), and we’re still working on getting CheckJNI to spot these mistakes.

We’re hoping to have more checking, including for local reference misuse, in a future release of Android. Start using CheckJNI now, though, and you’ll be able to take advantage of our new checks as they’re added.

Friday, 15 July 2011

Android 3.2 Platform and Updated SDK tools

Today we are announcing the Android 3.2 platform, an incremental release that adds several new capabilities for users and developers. The new platform includes API changes and the API level is 13.

Here are some of the highlights of Android 3.2:

Optimizations for a wider range of tablets. A variety of refinements across the system ensure a great user experience on a wider range of tablet devices.

Compatibility zoom for fixed-sized apps. A new compatibility display mode gives users a new way to view these apps on larger devices. The mode provides a pixel-scaled alternative to the standard UI stretching, for apps that are not designed to run on larger screen sizes.

Media sync from SD card. On devices that support a removable SD card, users can now load media files directly from the SD card to apps that use them.

Extended screen support API. For developers who want more precise control over their UI across the range of Android-powered devices, the platform’s screen support API is extended with new resource qualifiers and manifest attributes, to also allow targeting screens by their dimensions.

For a complete overview of what’s new in the platform, see the Android 3.2 Version Notes.

We would also like to remind developers that we recently released new version of the SDK Tools (r12) and of the Eclipse plug-in (ADT 12). We have also updated the NDK to r6.

Visit the Android Developers site for more information about Android 3.2 and other platform versions. To get started developing or testing on the new platform, you can download it into your SDK using the Android SDK Manager.

Tuesday, 12 July 2011

A New Android Market for Phones

[This post is by Eric Chu, Android Developer Ecosystem. —Dirk Dougherty]

Earlier this year, we launched several important features aimed at making it easier to find great applications on Android Market on the Web. Today, we're very excited to launch a completely redesigned Android Market client that brings these and other features to phones.

The new Market client is designed to better showcase top apps and games, engage users with an improved UI, and provide a quicker path to downloading or purchasing your products. For developers, the new Android Market client means more opportunities for your products to be merchandised and purchased.

In the home screen, we've created a new promotional page that highlights top content. This page is tiled with colorful graphics that provide instant access to featured apps and games. The page also lets users find their favorite books and movies, which will help drive even more return visits to Market.

To make it fun and easy for users to explore fresh content, we've added our app lists right to the Apps and Games home pages. Users can now quickly flip through these lists by swiping right or left, checking out what other people are downloading in the Top Paid, Top Free, Top Grossing, Top New Paid, Top New Free, and Trending lists. To keep the lists fresh and relevant, we've made them country-specific for many of the top countries.


To help you convert visitors to customers, we’ve made significant changes to the app details page. We've moved the app name and price into a compact action bar at the top of the page, so that users can quickly download or purchase your app. Directly below, users can flip through screen shots by swiping right or left, or scroll down to read your app's description, what's new, reviews, and more. To help you promote your product more effectively, the page now also includes a thumbnail link to your product video which is displayed at full screen when in landscape orientation.

For users who are ready to buy, we've streamlined the click-to-purchase flow so that users can complete a purchase in two clicks from the app details page. During the purchase, users can also see a list of your other apps, to help you cross-sell your other products.

With a great new UI, easy access to app discovery lists, a convenient purchase flow, and more types of content, we believe that the new Market client will become a favorite for users and developers alike.

Watch for the new Market client coming to your phone soon. We've already begun a phased roll-out to phones running Android 2.2 or higher — the update should reach all users worldwide in the coming weeks. We encourage you to try the update as soon as you receive it. Meanwhile, check out the video below for an early look.

Monday, 11 July 2011

New Mode for Apps on Large Screens

[This post is by Scott Main, lead tech writer for developer.android.com. — Tim Bray]

Android tablets are becoming more popular, and we're pleased to note that the vast majority of apps resize to the larger screens just fine. To keep the few apps that don't resize well from frustrating users with awkward-looking apps on their tablets, Android 3.2 introduces a screen compatibility mode that makes these apps more usable on tablets. If your app is one of the many that do resize well, however, you should update your app as soon as possible to disable screen compatibility mode so that users experience your app the way you intend.

Beginning with Android 3.2, any app that does not target Android 3.0 (set either android:minSdkVersion or android:targetSdkVersion to “11” or higher) or does not explicitly set android:xlargeScreens="true" in the <supports-screens> element will include a button in the system bar that, when touched, allows users to select between two viewing modes on large-screen devices.

“Stretch to fill screen” is normal layout resizing (using your app’s alternative resources for size and density) and “Zoom to fill screen” is the new screen compatibility mode.

When the user enables this screen compatibility mode, the system no longer resizes your layout to fit the screen. Instead, it runs your app in an emulated normal/mdpi screen (approximately 320dp x 480dp) and scales that up to fill the screen---imagine viewing your app at the size of a phone screen then zooming in about 200%. The effect is that everything is bigger, but also more pixelated, because the system does not resize your layout or use your alternative resources for the current device (the system uses all resources for a normal/mdpi device). Here’s a comparison of what it looks like (screen compatibility mode enabled on the right):

In cases where an app does not properly resize for larger screens, this screen compatibility mode can improve the app’s usability by emulating the app’s phone-style look, but zoomed in to fill the screen on a tablet.

However, most apps (even those that don’t specifically target Honeycomb) look just fine on tablets without screen compatibility mode, due to the use of alternative layouts for different screen sizes and the framework’s flexibility when resizing layouts. Unfortunately, if you haven’t said so in your manifest file, the system doesn’t know that your application properly supports large screens. Thus, if you’ve developed your app against any version lower than Android 3.0 and do not declare support for large screens in your manifest, the system is going to offer users the option to enable screen compatibility mode.

So, if your app is actually designed to resize for large screens, screen compatibility mode is probably an inferior user experience for your app and you should prevent users from using it. The easiest way to make sure that users cannot enable screen compatibility mode for your app is to declare support for xlarge screens in your manifest file’s <supports-screens> element. For example:

<manifest ... >
<supports-screens android:xlargeScreens="true" />
...
</manifest>

That’s it! No more screen compatibility mode.

Note: If your app is specifically designed to support Android 3.0 and declares either android:minSdkVersion or android:targetSdkVersion with a value of “11” or greater, then your app is already in the clear and screen compatibility mode will not be offered to users, but adding this attribute certainly won’t hurt.

In conclusion, if your app has set the android:minSdkVersion and android:targetSdkVersion both with values less than “11” and you believe your app works well on large and xlarge screens (for example, you’ve tested on a Honeycomb tablet), you should make the above addition to your manifest file in order to disable the new screen compatibility mode.

If your app does not resize properly for large screens, then users might better enjoy your app using screen compatibility mode. However, please follow our guide to Supporting Multiple Screens so that you can also disable screen compatibility mode and provide a user experience that’s optimized for large-screen devices.

Followers