Posted by on Nov 14, 2011

“Your father’s light saber. This is the weapon of a Jedi Knight. Not as clumsy or random as a blaster; an elegant weapon for a more civilized age. For over a thousand generations, the Jedi Knights were the guardians of peace and justice in the Old Republic. Before the dark times… before the Empire.”

While the Android 4.0 SDK comes with a complete set of javadocs, the source code of the SDK is missing in the SDK distribution. This is very unfortunate, since you cannot easily debug into SDK methods (at least not without running into de-compiled code) nor can you see how things actually work.

Eclipse - Source Not Found

However, there is a quick fix to that problem. I downloaded the complete Android source including the Linux, drivers, libs, etc., like explained here: http://source.android.com/source/download.html and ran small Java program on the source tree. I used to this with a simple bash script but over the last couple of Android Releases, the java source locations got a little more diverse and I started missing a couple files. So instead, this Java program walks the source tree and looks for java source files. All those will then be copied into a new location, considering their package name. Finally, the jar tool gets called to put all the source into a single bundle for easier handling.

package com.techcasita.tools;
import java.io.*;
/**
 * Find all of Android's Java Sources, consider their package names,
 * and place it in a jar file.
 *
 * @author <a href="mailto:wolf@wolfpaulus.com">Wolf Paulus</a>
 */
public class DroidSource {
    private static String TargetPath;

    public static void main(String[] args) {
        if (args.length == 2 &amp;&amp; new File(args[0]).isDirectory()) {
            DroidSource.TargetPath = args[1];
            File t = new File(args[1]);
            if ((t.exists() &amp;&amp; t.isDirectory() &amp;&amp; t.listFiles().length == 0) || t.mkdir()) {
                traverse(new File(args[0]));
                try {
                    Runtime.getRuntime().exec("jar cf " + t.getParentFile().getAbsolutePath()
+ File.separatorChar + "android-10-src.jar -C " + TargetPath + File.separatorChar + " .");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("Usage: " + DroidSource.class.getName()
+ "  ");
                System.out.println(" should exist and be empty");
            }
        } else {
            System.out.println("Usage: " + DroidSource.class.getName()
+ "  ");
        }
    }

    static void traverse(File file) {
        if (file != null &amp;&amp; !file.isHidden()) {
            if (file.isDirectory()) {
                if (!"out".equals(file.getName())) {
                    File[] files = file.listFiles();
                    for (File f : files) {
                        traverse(f);
                    }
                }
            } else if (file.getName().endsWith("java")) {
                String path = findPackage(file);

                if (path != null) {
                    path = path.replace('.', File.separatorChar);
                    createDirs(path);
                    copyFile(file.getAbsolutePath(), TargetPath + File.separatorChar
+ path + File.separatorChar + file.getName());
                }
            }
        }
    }

    private static String findPackage(File file) {
        final String TAG0 = "package ";
        final String TAG1 = ";";
        char[] buffer = new char[2048];

        try {
            FileReader r = new FileReader(file);
            r.read(buffer);
            StringBuffer sb = new StringBuffer();
            sb.append(buffer);
            int t0 = sb.indexOf(TAG0);
            if (t0 &lt; 0) return null;
            t0 += TAG0.length();
            int t1 = sb.indexOf(TAG1, t0);
            if (t1 &lt; 0) return null;
            if (t1 &gt; sb.indexOf(" ", t0)) return null;
            return sb.substring(t0, t1);
        } catch (IOException e) {
            return null;
        }
    }

    private static void createDirs(String path) {
        String[] sa = path.split("" + File.separatorChar);
        String name = TargetPath;
        for (String s : sa) {
            name += File.separatorChar + s;
            File f = new File(name);
            if (!f.exists()) {
                f.mkdir();
            }
        }
    }

    private static void copyFile(String srFile, String dtFile) {
        try {
            File f1 = new File(srFile);
            File f2 = new File(dtFile);
            InputStream in = new FileInputStream(f1);
            OutputStream out = new FileOutputStream(f2);

            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) &gt; 0) {
                out.write(buf, 0, len);
            }
            in.close();
            out.close();
        } catch (FileNotFoundException ex) {
            System.out.println(ex.getMessage() + " in the specified directory.");
            System.exit(0);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }
}

This will generate this android-14-src.jar, (50 MB) containing all the relevant java sources and after attaching it to the SDK classes in your favorite IDE (IntelliJ in my case) you can easily step into the code, for instance during a debug session… The jar was generated from the android-4.0.1_r1 tag here http://android.git.kernel.org on Nov. 14, 2011.