Just An Application

August 22, 2009

A Standalone Android Runtime: UI And Graphics

Filed under: Android, Java, Mobile Java, Standalone Android Runtime — Tags: , , , — Simon Lewis @ 7:59 pm

,

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.

screenlocked

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

helloworld

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.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

Advertisements

A Standalone Android Runtime: Running HelloWorld The Hard Way

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.

Process[25001]: 
Process[25001]: Class standalone/helloworld/HelloWorldActivity
Process[25001]: 
Process[25001]: compiling <init>
Process[25001]: 
Process[25001]: invoke-direct Landroid/app/Activity; <init> ()V
Process[25001]: return-void
Process[25001]: 
Process[25001]: compiling onCreate
Process[25001]: 
Process[25001]: invoke-super Landroid/app/Activity; onCreate (Landroid/os/Bundle;)V
Process[25001]: const #+2130903040
Process[25001]: invoke-virtual Lstandalone/helloworld/HelloWorldActivity; setContentView (I)V
Process[25001]: return-void
Process[25001]: 
Process[25001]: 
Process[25001]: 
Process[25001]: Class standalone/helloworld/R$attr
Process[25001]: 
Process[25001]: compiling <init>
Process[25001]: 
Process[25001]: invoke-direct Ljava/lang/Object; <init> ()V
Process[25001]: return-void
Process[25001]: 
Process[25001]: 
Process[25001]: 
Process[25001]: Class standalone/helloworld/R$drawable
Process[25001]: 
Process[25001]: compiling <init>
Process[25001]: 
Process[25001]: invoke-direct Ljava/lang/Object; <init> ()V
Process[25001]: return-void
Process[25001]: 
Process[25001]: 
Process[25001]: 
Process[25001]: Class standalone/helloworld/R$layout
Process[25001]: 
Process[25001]: compiling <init>
Process[25001]: 
Process[25001]: invoke-direct Ljava/lang/Object; <init> ()V
Process[25001]: return-void
Process[25001]: 
Process[25001]: 
Process[25001]: 
Process[25001]: Class standalone/helloworld/R$string
Process[25001]: 
Process[25001]: compiling <init>
Process[25001]: 
Process[25001]: invoke-direct Ljava/lang/Object; <init> ()V
Process[25001]: return-void
Process[25001]: 
Process[25001]: 
Process[25001]: 
Process[25001]: Class standalone/helloworld/R
Process[25001]: 
Process[25001]: compiling <init>
Process[25001]: 
Process[25001]: invoke-direct Ljava/lang/Object; <init> ()V
Process[25001]: return-void


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

A Standalone Android Runtime: Launching HelloWorld The Easy Way

Filed under: Android, Java, Mobile Java, Standalone Android Runtime — Tags: , , , — Simon Lewis @ 9:03 am

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

    <?xml version="1.0" encoding="utf-8"?>
    <manifest 
          xmlns:android="http://schemas.android.com/apk/res/android"
          package="standalone.helloworld"
          android:versionCode="1"
          android:versionName="1.0">
        <application android:icon="@drawable/icon" android:label="@string/app_name">
            <activity android:name=".HelloWorldActivity"
                  android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.HOME"/>
                    <category android:name="android.intent.category.DEFAULT"/>
               </intent-filter>
            </activity>
        </application>
        <uses-sdk android:minSdkVersion="3" />
    </manifest> 

If we put the new version of the HelloWorld package in the data app directory and and start the SystemServer then HelloWorld gets launched automatically by the ActivityManager.

Here’s part of the Main log.

...

21-08-09 17:07:58: 22001: DEBUG: PowerManagerService system ready!
21-08-09 17:07:58: 22001: DEBUG: ActivityManager Start running!
21-08-09 17:07:58: 22001: INFO: ActivityManager Starting activity: Intent { ... }

Having started the ActivityManager begins launching HelloWorld as the home application . The Intent is

    {
        action=android.intent.action.MAIN 
        categories={android.intent.category.HOME} 
        flags=0x10000000 
        comp={standalone.helloworld/standalone.helloworld.HelloWorldActivity}
    }

The flag is Intent.FLAG_ACTIVITY_NEW_TASK as before.

21-08-09 17:07:59: 22001: INFO: ActivityManager Start proc standalone.helloworld for activity standalone.helloworld/.HelloWorldActivity: pid=25001 uid=10000 gids={}
21-08-09 17:07:59: 22001: WARN: ActivityManager Unable to start service Intent { ... } }: not found
21-08-09 17:07:59: 22001: ERROR: LockPatternKeyguardView Failed to bind to GLS while checking for account
21-08-09 17:07:59: 22001: WARN: StatusBar Icon not found in : 0
21-08-09 17:07:59: 22001: DEBUG: LocationManagerService PowerStateBroadcastReceiver: Battery changed
21-08-09 17:08:00: 22001: DEBUG: StatusBar updateResources
21-08-09 17:08:00: 22001: DEBUG: LocationManagerService PowerStateBroadcastReceiver: Screen on
21-08-09 17:08:00: 22001: DEBUG: LocationManagerService updateWakelockStatus(): true
21-08-09 17:08:00: 22001: DEBUG: LocationManagerService Cancelling existing alarm
21-08-09 17:08:00: 22001: DEBUG: LocationManagerService No need for alarm
21-08-09 17:08:00: 22001: DEBUG: LocationManagerService Can't release wakelock again!
21-08-09 17:08:02: 22001: INFO: ActivityManager Displayed activity standalone.helloworld/.HelloWorldActivity: 3152 ms

The rest of the log is as before at this point in the start up and then the application is running.

A section of the Event log.

21-08-09 17:07:58: 22001 11664372 boot_progress_ams_ready[3040]	time 7085 milliseconds
21-08-09 17:07:59: 22001 11664372 am_create_task[30004]         Task ID 2 
21-08-09 17:07:59: 22001 11664372 am_create_activity[30005]     Token 2412794 Task ID 2 Component Name standalone.helloworld/.HelloWorldActivity Action android.intent.action.MAIN MIME Type  URI  Flags 268435456 
21-08-09 17:07:59: 22001 11664372 am_proc_start[30014]          PID 25001 UID 10001 Process Name standalone.helloworld Type activity Component standalone.helloworld/.HelloWorldActivity 
21-08-09 17:07:59: 22001 15182069 am_proc_bound[30010]          PID 25001 Process Name standalone.helloworld 
21-08-09 17:07:59: 22001 15182069 am_restart_activity[30006]	Token 2412794 Task ID 2 Component Name standalone.helloworld/.HelloWorldActivity 
...
21-08-09 17:08:01: 25001 15069394 am_on_resume_called[30022]	Component Name standalone.helloworld.HelloWorldActivity 
21-08-09 17:08:02: 22001 8778710 activity_launch_time[30009]	Token 2412794 Component Name standalone.helloworld/.HelloWorldActivity time 3152 milliseconds 

Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

A Standalone Android Runtime: Launching HelloWorld The Hard Way

Filed under: Android, Java, Mobile Java, Standalone Android Runtime — Tags: , , — Simon Lewis @ 8:11 am

So how do we launch our newly installed HelloWorld application ? Easy, we just invoke startActivity() on the ActivityManager with the appropriate Intent.

If we were doing it from an Android application the code would look something like this.

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;

...

    void launch(Context theContext, String thePackage, String theClassName)
    {
        theContext.
            startActivity(
                new Intent(
                    Intent.ACTION_MAIN).
                setComponent(
                    new ComponentName(
                        thePackage, 
                        theClassName)).
                addFlags(
                    Intent.FLAG_ACTIVITY_NEW_TASK));
    }

...

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.


...

        ProcessRecord callerApp = null;
        if (err == START_SUCCESS && caller != null) {
            callerApp = getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                Log.w(TAG, "Unable to find app for caller " + caller
                      + " (pid=" + callingPid + ") when starting: "
                      + intent.toString());
                err = START_PERMISSION_DENIED;
            }
        }

...

This is of course exactly the right thing to do but we have an application to launch so we will simply elide that check for now,

Following this sleight of hand the application duly lauches and the main log shows the following

21-08-09 15:55:56: 22001: INFO: ActivityManager Starting activity: Intent { ... }

The Intent is

     {
         action = android.intent.action.MAIN 
         type   = 
         flags  = 0x10000000 
         comp   = {standalone.helloworld/standalone.helloworld.HelloWorldActivity}
     }

The value of flags is actually Intent.FLAG_ACTIVITY_NEW_TASK

21-08-09 15:56:01: 22001: INFO: ActivityManager Start proc standalone.helloworld for activity standalone.helloworld/.HelloWorldActivity: pid=25001 uid=10000 gids={}
21-08-09 15:56:04: 22001: INFO: ActivityManager Displayed activity standalone.helloworld/.HelloWorldActivity: 2583 ms

And the Event log shows this

21-08-09 15:56:01: 22001 2668988 am_create_task[30004]	      Task ID 2 
21-08-09 15:56:01: 22001 2668988 am_create_activity[30005]    Token 5975831 Task ID 2 Component Name standalone.helloworld/.HelloWorldActivity Action android.intent.action.MAIN MIME Type  URI  Flags 268435456 
21-08-09 15:56:01: 22001 2668988 am_proc_start[30014]	      PID 25001 UID 10001 Process Name standalone.helloworld Type activity Component standalone.helloworld/.HelloWorldActivity 
21-08-09 15:56:02: 22001 16490550 am_proc_bound[30010]        PID 25001 Process Name standalone.helloworld 
21-08-09 15:56:02: 22001 16490550 am_restart_activity[30006]  Token 5975831 Task ID 2 Component Name standalone.helloworld/.HelloWorldActivity 
21-08-09 15:56:04: 25001 7161559 am_on_resume_called[30022]   Component Name standalone.helloworld.HelloWorldActivity 
21-08-09 15:56:04: 22001 10621833 activity_launch_time[30009] Token 5975831 Component Name standalone.helloworld/.HelloWorldActivity time 2583 milliseconds 

Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

A Standalone Android Runtime: Application Installation

Filed under: Android, Java, Mobile Java, Standalone Android Runtime — Tags: , , , — Simon Lewis @ 7:25 am

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.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

August 21, 2009

A Standalone Android Runtime: SystemServer Startup

Filed under: Android, Java, Mobile Java, Standalone Android Runtime — Tags: , , , — Simon Lewis @ 11:44 am

There isn’t a great deal to show for a successful startup of the SystemServer except the contents of the logs so here they are.

The Main Log

The date at the start of each line is elided, and in some cases the time too, as it enables some long lines to just about fit.

... 09:50:31: 22001: INFO: SystemServer Entered the Android system server!
... 09:50:32: 22001: INFO: SystemServer Starting Power Manager.
... 09:50:32: 22001: INFO: SystemServer Starting Activity Manager.
... 09:50:33: 22001: INFO: SystemServer Starting telephony registry
... 09:50:33: 22001: INFO: SystemServer Starting Package Manager.

Nothing very interesting so far

... 09:50:33: 22001: WARN: PackageManager **** ro.build.version.sdk not set!

That’s because its not, but its only a warning so we won’t worry about it

... 22001: INFO: PackageManager Got library android.awt in /system/framework/android.awt.jar
... 22001: INFO: PackageManager Got library android.test.runner in /system/framework/android.test.runner.jar
... 22001: INFO: PackageManager Got library com.android.im.plugin in /system/framework/com.android.im.plugin.jar
... 09:50:33: 22001: WARN: PackageManager No BOOTCLASSPATH found!

That’s also true, but again its only a warning

... 09:50:33: 22001: DEBUG: PackageManager Scanning app dir /Users/simon/Scratch/standalone/system/framework
... 09:50:33: 22001: DEBUG: PackageManager Scanning app dir /Users/simon/Scratch/standalone/system/app
... 09:50:33: 22001: DEBUG: PackageManager Scanning app dir /Users/simon/Scratch/standalone/data/app
... 22001: WARN: PackageParser Skipping non-package file: /Users/simon/Scratch/standalone/data/app/.DS_Store

That’s MacOS X for you.

... 09:50:34: 22001: DEBUG: PackageManager Scanning app dir /Users/simon/Scratch/standalone/data/app-private
... 09:50:34: 22001: INFO: PackageManager Time to scan packages: 0.763 seconds
... 22001: WARN: PackageManager Removing dangling permission: android.permission.ACCESS_CACHE_FILESYSTEM from package null
... 09:50:34: 22001: INFO: SystemServer Starting Content Manager.
... 09:50:34: 22001: WARN: ActivityManager Unable to start service Intent { ... } }: not found
... 09:50:34: 22001: WARN: AccountMonitor Couldn't connect to Intent {  ... } } (Missing service?)

These two lines are very long indeed so they’ve been elided. The Intent being complained about is

    {
       action = android.accounts.IAccountsService
       comp   = { com.google.android.googleapps/com.google.android.googleapps.GoogleLoginService }
    }

and its true its not there. On the other hand its not there in the Emulator either.

... 09:50:34: 22001: INFO: SystemServer Starting System Content Providers.
... 09:50:34: 22001: INFO: ActivityThread Publishing provider sync: android.content.SyncProvider
... 09:50:34: 22001: INFO: ActivityThread Publishing provider settings: standalone.content.SettingsProvider

This is our substitute ContentProvider for the

    content://settings/...

URIs being started.

... 09:50:34: 22001: INFO: SystemServer Starting Battery Service.
... 09:50:34: 22001: INFO: SystemServer Starting Hardware Service.
... 09:50:34: 22001: INFO: SystemServer Starting Alarm Manager.
... 09:50:34: 22001: INFO: SystemServer Starting Sensor Service.
... 09:50:34: 22001: INFO: SystemServer Starting Window Manager.
... 09:50:35: 22001: INFO: SystemServer Starting Bluetooth Service.
... 09:50:35: 22001: INFO: SystemServer Starting Status Bar Service.
... 09:50:37: 22001: INFO: SystemServer Starting Clipboard Service.
... 09:50:37: 22001: INFO: SystemServer Starting Input Method Service.
... 09:50:37: 22001: INFO: InputManagerService Enabled input methods: null
... 09:50:37: 22001: INFO: InputManagerService Enabled input methods has not been set, enabling all
... 09:50:37: 22001: INFO: SystemServer Starting NetStat Service.
... 09:50:37: 22001: INFO: SystemServer Starting Connectivity Service.
... 09:50:37: 22001: INFO: WifiService WifiService starting up with Wi-Fi disabled
... 09:50:37: 22001: INFO: SystemServer Starting Notification Manager.
... 09:50:37: 22001: INFO: SystemServer Starting Mount Service.
... 09:50:37: 22001: INFO: SystemServer Starting DeviceStorageMonitor service
... 09:50:37: 22001: INFO: SystemServer Starting Location Manager.
... 09:50:37: 22001: INFO: SystemServer Starting Search Service.
... 09:50:37: 22001: INFO: SystemServer Starting Checkin Service.
... 09:50:37: 22001: WARN: ActivityManager Unable to start service Intent { ... }: not found

Another long line. This time the Intent is

    {
        comp = { com.google.android.server.checkin/com.google.android.server.checkin.CheckinService }
    }

Again its true its not there, and again its not there in the SDK emulator either.

... 09:50:37: 22001: WARN: SystemServer Using fallback Checkin Service.
... 09:50:37: 22001: INFO: SystemServer Starting Wallpaper Service
... 09:50:37: 22001: DEBUG: WallpaperService WallpaperService startup
... 09:50:37: 22001: INFO: SystemServer Starting Audio Service
... 22001: WARN: AudioService Soundpool could not load file: /Users/simon/Scratch/standalone/system/media/audio/ui/Effect_Tick.ogg
... 22001: WARN: AudioService Soundpool could not load file: /Users/simon/Scratch/standalone/system/media/audio/ui/KeypressStandard.ogg
... 22001: WARN: AudioService Soundpool could not load file: /Users/simon/Scratch/standalone/system/media/audio/ui/KeypressSpacebar.ogg
... 22001: WARN: AudioService Soundpool could not load file: /Users/simon/Scratch/standalone/system/media/audio/ui/KeypressDelete.ogg
... 22001: WARN: AudioService Soundpool could not load file: /Users/simon/Scratch/standalone/system/media/audio/ui/KeypressReturn.ogg

Haven’t got any of those, and neither does the Emulator.

... 09:50:37: 22001: INFO: SystemServer Starting HeadsetObserver
... 09:50:37: 22001: WARN: HeadsetObserver This kernel does not have wired headset support
... 09:50:37: 22001: INFO: SystemServer Starting AppWidget Service
... 09:50:37: 22001: INFO: WindowManager Menu key state: 0 safeMode=false
... 09:50:38: 22001: INFO: WindowManager Config changed: { scale=1.0 imsi=0/0 locale=en_US touch=1 key=1/2/2 nav=1 orien=1 }
... 09:50:38: 22001: DEBUG: PowerManagerService system ready!

We’re done.

... 09:50:38: 22001: DEBUG: ActivityManager Start running!
... 09:50:38: 22001: WARN: ActivityManager Unable to start service Intent { ... }: not found

Another missing service. The Intent is

     {
         action = android.accounts.IAccountsService 
         comp   = { com.google.android.googleapps/com.google.android.googleapps.GoogleLoginService }
     }

No we don’t have it. Neither does the Emulator.

... 09:50:38: 22001: ERROR: LockPatternKeyguardView Failed to bind to GLS while checking for account

A consequence of the previous problem. Also present in the Emulator.

... 09:50:38: 22001: WARN: StatusBar Icon not found in : 0

This looks as though it is a bug except that it happens in the Emulator as well.

... 09:50:38: 22001: DEBUG: LocationManagerService PowerStateBroadcastReceiver: Battery changed
... 09:50:38: 22001: DEBUG: StatusBar updateResources
... 09:50:38: 22001: DEBUG: LocationManagerService PowerStateBroadcastReceiver: Screen on
... 09:50:38: 22001: DEBUG: LocationManagerService updateWakelockStatus(): true
... 09:50:38: 22001: DEBUG: LocationManagerService Cancelling existing alarm
... 09:50:38: 22001: DEBUG: LocationManagerService No need for alarm
... 09:50:38: 22001: DEBUG: LocationManagerService Can't release wakelock again!

The Event Log

A very rough-and-ready formatted version of the contents of the Event log.

... 09:50:31: 22001 902782 boot_progress_system_run[3010]	time 0 milliseconds
... 09:50:33: 22001 902782 boot_progress_pms_start[3060]	time 1315 milliseconds
... 09:50:33: 22001 902782 boot_progress_pms_system_scan_start[3070]	time 1414 milliseconds
... 09:50:33: 22001 902782 boot_progress_pms_data_scan_start[3080]	time 1867 milliseconds
... 09:50:34: 22001 902782 boot_progress_pms_scan_end[3090]	time 2177 milliseconds
... 09:50:34: 22001 902782 boot_progress_pms_ready[3100]	time 2209 milliseconds
... 09:50:34: 22001 902782 battery_status[2723]	status 0 health 0 present 0 plugged 1 technology  
... 09:50:34: 22001 902782 battery_level[2722]	level 74 percent voltage 0 temperature 0 
... 09:50:34: 22001 1259814 power_screen_state[2728]	offOrOn 1 becauseOfUser 0 totalTouchDownTime 0 milliseconds touchCycles 0 
... 09:50:34: 22001 1259814 power_screen_broadcast_send[2725]	wakelockCount 1 
... 09:50:38: 22001 902782 configuration_changed[2719]	config mask 248 
... 09:50:38: 22001 902782 boot_progress_ams_ready[3040]	time 6205 milliseconds
... 09:50:38: 22001 1259814 screen_toggled[70000]	screen_state 1 
... 09:50:38: 22001 1259814 power_screen_broadcast_done[2726]	on 1 broadcastDuration 762 milliseconds wakelockCount 1 

The records were accessed using the classes in the com.android.ddmlib.log package.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

August 20, 2009

A Standalone Android Runtime: Settings

Filed under: Android, Java, Mobile Java, Standalone Android Runtime — Tags: , , , — Simon Lewis @ 8:32 pm

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

    public static final void installSystemProviders()

of the com.android.server.am.ActivityManagerService class.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

A Standalone Android Runtime: Resources

Filed under: Android, Java, Mobile Java, Standalone Android Runtime — Tags: , , , — Simon Lewis @ 6:20 pm

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,

statusbar

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.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

A Standalone Android Runtime: XML Parsing

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

    public final XmlResourceParser openXmlResourceParser(
                                       int    cookie, 
                                       String fileName) 
                                   throws 
                                       IOException

passing

    AndroidManifest.xml

as the fileName argument.

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.

For example, a start tag is represented by a

    struct ResXMLTree_node

followed by a

    struct ResXMLTree_attrExt

followed by zero or more

    struct ResXMLTree_attribute

so what it actually looks like in the file is

struct ResXMLTree_node

struct ResChunk_header

type (0x0102) uint16_t
headerSize uint16_t
size uint32_t
lineNumber uint32_t
comment uint32_t

struct ResXMLTree_attrExt

namespace uint32_t
name uint32_t
attributeStart uint16_t
attributeSize uint16_t
idAttributeIndex uint16_t
classAttributeIndex uint16_t
styleAttributeIndex uint16_t

struct ResXMLTree_attribute[0]

namespace uint32_t
name uint32_t
rawValue uint32_t
typedValue Value

Once the format is clear then the parser itself is straightforward.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

A Standalone Android Runtime: The ServiceManager

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.

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.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

Older Posts »

Create a free website or blog at WordPress.com.

%d bloggers like this: