August 22, 2009

The basis of the Android runtime graphics and UI functionality is the Skia graphics library and the SurfaceFlinger client/server architecture which are implemented in C/C++. In the case of the graphics functionality a large proportion of the classes in the android.graphics package are effectively Java wrappers around the equivalent C++ classes in Skia.

There is no direct equivalent to either Skia or the SurfaceFlinger in standard Java but there is sufficient graphics functionality available to substitute for enough of the functionality of Skia and the SurfaceFinger to produce at least basic UIs.

This is the standard locked screen showing the StatusBar and the KeyGuard. The resources, that is, the colours, drawables, and layouts used to produce them are unchanged, as are the fonts, and all the UI code involved. The battery charging animation works, as does the updating of the dates in the StatusBar and the KeyGuard. The only difference is that the rendering is being done in Java, as is the the composition. The top-level window is a java.awt.Frame

This is HelloWorld, Comparison with the emulator shows that is not quite right. Some of the padding in the title bar seems to have gone astray. This is probably down to the replacement resource handling code not doing the right thing.

One of the things that there is no support for in standard Java, not suprisingly, is the NinePatchDrawable. This is a specialized form of PNG. As both the StatusBar and the Activity title bar use them they have to be supported. The 9-patch specific information is contained a specialized chunk within the PNG the format. To make life interesting the exact format of this chunk is not documented, but it is possible to work out what it is with the aid of the source code.

Whichever way HelloWorld gets launched there is a point at which the runtime will start to execute the code in the HelloWorld package HelloWorld.apk. Which is a problem. HelloWorld.apk is a standard Android package built using the Android development tools so what is in it, as you might expect, is a classes.dex file, which is nice if you are the Dalvik VM but not so great if you are another kind of JVM that does not talk Dalvik bytecode, and ours does not.

So why not put the class files in the package when its being built and use them ? Where’s the fun in that ? The contents of classes.dex started out as some class files, so lets turn it back into the class files on demand !

To do this we need a specialized ClassLoader which is pretty simple, in this case at least, a Dex loader, likewise, and a DVM to JVM bytecode compiler, which is a bit trickier. Fortunately the HelloWorld application is doing nothing much at all so there are not a large number or variety of instructions to compile.

Loading the Dex file and compiling the code back into JVM bytecode on-the-fly is not necessarily how you would solve this problem for real but it will work in this case.

Compiling is not the most visual of activities so instead here is the trace from the compiler which is invoked by the ClassLoader when the first class in the HelloWorld application is accessed by the runtime. To make life simpler at this point we load the entire Dex file and compile everything in sight, which is not a lot as you can see. The compiler is printing each DVM instruction as it compiles it.

There is a considerably easier way of getting an application launched and that is to make it the home application. This can be done by modifying the application manifest, which is rather simpler than modifying the internals of the ActivityManagerService.

The standard home application is the Launcher which you can find here

$(ANDROID_SRC)/packages/apps/Launcher

If you look at the application manifest (the file AndroidManifest.xml) you will see two category elements in the intent-filter of the activity, one named

android.intent.category.HOME

and the other

android.intent.category.DEFAULT

It is the presence of those two category elements which make the Launcher the home application.

Adding these to the HelloWorld application manifest gives us the following

But of course we can’t do that because to run it we would have to launch the application containing the code to do the launching which is what we are trying to do in the first place.

Still we have a functioning IPC mechanism which we can use to get a Binder for the ActivityManager and which we can subsequently use to do the invocation so we can launch the application from outside so to speak. Except that we can’t. The ActivityManager, as you might expect, does not take kindly to applications being launched by things Android knows nothing about. Here is part of the code from the ActivityManagerService method startActivityLocked(). Its the variant with rather too many parameters for comfort starting at line 3003.

It turns out that an application can be installed, such that it can subsequently be run, simply by placing the package containing it in the data app directory. On a device this would usually be the directory

/data/app

When it is started by the SystemServer the PackageManagerService will scan this directory and find the package containing the application. It will then ask the Installer to install the application.

The Installer in the SystemServer is simply a proxy for the installd process which can be found here

$(ANDROID_SRC)/frameworks/base/cmds/installd

It is responsible for creating the directories for the application being installed and for changing their ownership to that of the application. This requires root privilege or something like it which is why it is being done by a standlone process rather than in the context of the SystemServer process.

The proxy in the SystemServer communicates with installd using local sockets. Neither local sockets nor some of the functionality required by installd are available in standard Java but we can mimic enough that the installation of the application succeeds.

August 20, 2009

One piece of functionality which elements of the SystemServer require but which is not present is the ContentProvider responsible for content with the following URIs

content://settings/bookmark

content://settings/gservices

content://settings/secure

content://settings/system

This is because we are running without any of the system supplied applications or content providers, and all of these content URIs are handled by the SettingsProvider application which can be found in

$(ANDROID_SRC)/frameworks/base/packages/SettingsProvider

Since various things fall-over more or less badly if some of these settings are not available we provide a dummy ContentProvider, which when queried returns a Cursor capable of returning some appropriate hardwired values. We install this ContentProvider by hand in the method

Interestingly it turns out that the SystemServer has a number of associated UI elements, for example the Status Bar (see below) which is an instance of StatusBarView and is owned by the StatusBarService, and like much of the UI in Android they are constructed using resources,

The StatusBar Which Is Owned By The StatusBarService In The SystemServer

Resources are handled, like the binary XML with which they are often associated, largely in native code. The three files of most interest are the previously mentioned ResourceTypes.h, ResourceTypes.cpp which can be found in

$(ANDROID_SRC)/frameworks/base/libs/utils

and android_util_AssetManager.cpp which can be found in

$(ANDROID_SRC)/frameworks/base/core/jni

There is quite a bit of resource handling code, ResourceTypes.cpp is approximately 4000 lines, and android_util_AssetManager.cpp approximately 1500, and it is somewhat opaque to say the least, but the functionality it implements can actually be replicated in Java, ‘tho possibly rather imperfectly, its very difficult to tell.

During development XML is used for specifying Android manifests and resources. Both manifests and resources are subsequently accessed by the runtime.

In the case of the SystemServer, it is actually the PackageManagerService which first accesses a manifest as it scans the framework directory (on a device this would be /system/framework but in our case isn’t) and encounters the

framework-res.apk

package.

It creates an instance of android.content.res.PackageParser to parse the package, and this in turn calls the android.content.res.AssetManager method

This is a problem for us, because, yes you’ve guessed it, its a native method. Not much of a problem surely ? Java XML parsers are two a penny. True, but by the time the runtime encounters an XML file it is no longer in the de-facto XML format, it has in fact been transformed into a form of binary XML.

Fortunately the format is specified in the file

$(ANDROID_SRC)/frameworks/base/include/utils/ResourceTypes.h

along with a bunch of other stuff which we will be making use of later on.

At this point the interesting stuff starts at line 467. To begin with its not entirely obvious what’s going on, but after a litle bit of experimentation it becomes clear.

The SystemServer needs a functioning Binder so that services can be added to, and retrieved from, the ServiceManager as it starts up.

A service is added as a name/Binder pair using the android.os.ServiceManager

public static void addService(String name, IBinder service)

method.

A service is retrieved by name using the android.os.ServiceManager

public static IBinder getService(String name)

If it is found then the corresponding Binder registerd with the ServiceManager is returned, which can then be used to access the functionality of the named service.

The ServiceManager server implementation can be found in

$(ANDROID_SRC)/frameworks/base/cmds/servicemanager

It is implemented in C, so sticking with the no native code policy, a new one needs to be implemented in Java. As we have a functioning Binder implementation written in Java this is fairly simple. All it needs to do is handle invocations and hold a map of name/Binder pairs.

The Android runtime uses the ServiceManager to add services, and to find them, but the ServiceManager itself is accessed via a Binder. It cannot be used to find itself so how is this Binder obtained ? This is the standard bootstrap problem, and can be solved in the usual way, that is, by making the ServiceManager a special case whose location is determined in some other way, for example, hard-wiring.

Here’s what the initial stages of the start-up of the SystemServer looks like from the point of view of the ServiceManager.

The triple on the left of each line is the pseudo pid/gid/uid of the process making the call. When a service is found the triple after the service name shows the same information for the process where the Binder is located. At this point only the SystemServer is running so its the only process you can see the triple for.

Note that all of the services being added have been persuaded to run one way or another at this point, which is not the same as saying they actually do anything.