How Android Executes Your Code

While Android developers use Java, the Android platform does not include a Java Virtual Machine (VM) for executing code. Instead, applications are compiled into Dalvik bytecode, and Android uses its Dalvik VM to execute it. The Java code is still compiled into Java bytecode, but this Java bytecode is then compiled into Dalvik bytecode by the dex compiler, dx (an SDK tool). Ultimately, your application will contain only the Dalvik bytecode, not the Java bytecode.

For example, an implementation of a method that computes the nth term of the Fibonacci series is shown in Listing 1–1 together with the class definition. The Fibonacci series is defined as follows:

F0 = 0
F1 = 1
Fn = Fn-2 + Fn-1 for n greater than 1

Listing 1–1. Naïve Recursive Implementation of Fibonacci Series

public class Fibonacci {
    public static long computeRecursively (int n)
    {
        if (n > 1) return computeRecursively(n-2) + computeRecursively(n-1);
        return n;
    }
}

NOTE: A trivial optimization was done by returning n when n equals 0 or 1 instead of adding another “if” statement to check whether n equals 0 or 1.

An Android application is referred to as an APK since applications are compiled into a file with the apk extension (for example, APress.apk), which is simply an archive file. One of the files in the archive is classes.dex, which contains the application's bytecode. The Android toolchain provides a tool, dexdump, which can convert the binary form of the code (contained in the APK's classes.dex file) into human-readable format.

TIP: Because an apk file is simply a ZIP archive, you can use common archive tools such as WinZip or 7-Zip to inspect the content of an apk file..

Listing 1–2 shows the matching Dalvik bytecode.

Listing 1–2. Human-Readable Dalvik Bytecode of Fibonacci.computeRecursively

002548:                 |[002548] com.apress.proandroid.Fibonacci.computeRecursively:(I)J
002558: 1212            |0000: const/4 v2, #int 1 // #1
00255a: 3724 1100       |0001: if-le v4, v2, 0012 // +0011
00255e: 1220            |0003: const/4 v0, #int 2 // #2
002560: 9100 0400       |0004: sub-int v0, v4, v0
002564: 7110 3d00 0000  |0006: invoke-static {v0},
    Lcom/apress/proandroid/Fibonacci;.computeRecursively:(I)J
00256a: 0b00            |0009: move-result-wide v0
00256c: 9102 0402       |000a: sub-int v2, v4, v2
002570: 7110 3d00 0200  |000c: invoke-static {v2},
    Lcom/apress/proandroid/Fibonacci;.computeRecursively:(I)J
002576: 0b02            |000f: move-result-wide v2
002578: bb20            |0010: add-long/2addr v0, v2
00257a: 1000            |0011: return-wide v0
00257c: 8140            |0012: int-to-long v0, v4
00257e: 28fe            |0013: goto 0011 // -0002

The first number on each line specifies the absolute position of the code within the file. Except on the very first line (which shows the method name), it is then followed by one or more 16-bit bytecode units, followed by the position of the code within the method itself (relative position, or label), the opcode mnemonic and finally the opcode's parameter(s). For example, the two bytecode units 3724 1100 at address 0×00255a translate to “if-le v4, v2, 0012 // +0011”, which basically means “if content of virtual register v4 is less than or equal to content of virtual register v2 then go to label 0×0012 by skipping 17 bytecode units” (1710 equals 1116). The term “virtual register” refers to the fact that these are not actual hardware registers but instead the registers used by the Dalvik virtual machine.

Typically, you would not need to look at your application's bytecode. This is especially true with Android 2.2 (codename Froyo) and later versions since a Just-In-Time (JIT) compiler was introduced in Android 2.2. The Dalvik JIT compiler compiles the Dalvik bytecode into native code, which can execute significantly faster. A JIT compiler (sometimes referred to simply as a JIT) improves performance dramatically because:

  • Native code is directly executed by the CPU without having to be interpreted by a virtual machine.
  • Native code can be optimized for a specific architecture.

Benchmarks done by Google showed code executes 2 to 5 times faster with Android 2.2 than Android 2.1. While the results may vary depending on what your code does, you can expect a significant increase in speed when using Android 2.2 and later versions.

The absence of a JIT compiler in Android 2.1 and earlier versions may affect your optimization strategy significantly. If you intend to target devices running Android 1.5 (codename Cupcake), 1.6 (codename Donut), or 2.1 (codename Éclair), most likely you will need to review more carefully what you want or need to provide in your application. Moreover, devices running these earlier Android versions are older devices, which are less powerful than newer ones. While the market share of Android 2.1 and earlier devices is shrinking, they still represent about 12% as of December 2011). Possible strategies are:

  • Don't optimize at all. Your application could be quite slow on these older devices.
  • Require minimum API level 8 in your application, which can then be installed only on Android 2.2 or later versions.
  • Optimize for older devices to offer a good user experience even when no JIT compiler is present. This could mean disabling features that are too CPU-heavy.

TIP: Use android:vmSafeMode in your application's manifest to enable or disable the JIT compiler. It is enabled by default (if it is available on the platform). This attribute was introduced in Android 2.2.

Now it is time to run the code on an actual platform and see how it performs. If you are familiar with recursion and the Fibonacci series, you might guess that it is going to be slow. And you would be right. On a Samsung Galaxy Tab 10.1, computing the thirtieth Fibonacci number takes about 370 milliseconds. With the JIT compiler disabled, it takes about 440 milliseconds. If you decide to include that function in a Calculator application, users will become frustrated because the results cannot be computed “immediately.” From a user's point of view, results appear instantaneous if they can be computed in 100 milliseconds or less. Such a response time guarantees a very good user experience, so this is what we are going to target.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.226.239