diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 98ffe9d89b53ac56c9c1b88aca7a00db5b4526f1..b95b5ba16ff8b8f25cb2bf0236a6d46f896761b5 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="net.i2p.router"
+      package="net.i2p.android.router"
       android.versionCode="0"
       android.versionName="0.0.0"
       android:installLocation="preferExternal"
@@ -11,8 +11,12 @@
     <!-- 3 required for NDK -->
     <uses-sdk android:minSdkVersion="3" />
 
-    <application android:label="@string/app_name">
-        <activity android:name="I2PAndroid"
+    <application android:label="@string/app_name"
+               android:icon="@drawable/ic_launcher_itoopie" >
+        <service android:name=".service.RouterService"
+                  android:label="@string/app_name"
+                  android:icon="@drawable/ic_launcher_itoopie" />
+        <activity android:name=".activity.MainActivity"
                   android:label="@string/app_name"
                   android:icon="@drawable/ic_launcher_itoopie"
                   android:launchMode="singleTask" >
diff --git a/android/res/raw/router_config b/android/res/raw/router_config
index 227cd06e1a42cede283a6c5a71d640a47193474b..5fa8dcc1013a45fd8d0513f20e101041676a1b3e 100644
--- a/android/res/raw/router_config
+++ b/android/res/raw/router_config
@@ -16,15 +16,30 @@ time.disabled=true
 i2p.dummyClientFacade=true
 i2cp.disableInterface=true
 #
+##### Tunnels
+#
+router.inboundPool.backupQuantity=0
+router.inboundPool.length=2
+router.inboundPool.lengthVariance=0
+router.inboundPool.quantity=2
+router.outboundPool.backupQuantity=0
+router.outboundPool.length=2
+router.outboundPool.lengthVariance=0
+router.outboundPool.quantity=2
+router.maxParticipatingTunnels=0
+router.sharePercentage=10
+#
 ##### Transport
 #
+i2np.bandwidth.inboundKBytesPerSecond=100
+i2np.bandwidth.outboundKBytesPerSecond=30
 #
 # NTCP
 #
 #i2np.ntcp.enable=false
-i2np.ntcp.maxConnections=8
+i2np.ntcp.maxConnections=12
 #
-# UDP crashes the JVM, don't know why
+# UDP disabled for now
 #
 i2np.udp.enable=false
 i2np.udp.maxConnections=12
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 983a304b91143c9280066744db4c5523523ae886..d1ab96508e6091b8634eb9c74ce5dc8d58ab8692 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <string name="app_name">I2PAndroid</string>
+    <string name="app_name">I2P</string>
 </resources>
diff --git a/android/src/net/i2p/android/router/activity/I2PActivityBase.java b/android/src/net/i2p/android/router/activity/I2PActivityBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..180f289abe10b8b08edf4c51f1026bc35f3e1b56
--- /dev/null
+++ b/android/src/net/i2p/android/router/activity/I2PActivityBase.java
@@ -0,0 +1,65 @@
+package net.i2p.android.router.activity;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+
+public abstract class I2PActivityBase extends Activity {
+    protected String _myDir;
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        _myDir = getFilesDir().getAbsolutePath();
+    }
+
+    @Override
+    public void onRestart()
+    {
+        System.err.println(this + " onRestart called");
+        super.onRestart();
+    }
+
+    @Override
+    public void onStart()
+    {
+        System.err.println(this + " onStart called");
+        super.onStart();
+        Intent intent = new Intent();
+        intent.setClassName(this, "net.i2p.android.router.service.RouterService");
+        System.err.println(this + " calling startService");
+        ComponentName name = startService(intent);
+        System.err.println(this + " got from startService: " + name);
+    }
+
+    @Override
+    public void onResume()
+    {
+        System.err.println(this + " onResume called");
+        super.onResume();
+    }
+
+    @Override
+    public void onPause()
+    {
+        System.err.println(this + " onPause called");
+        super.onPause();
+    }
+
+    @Override
+    public void onStop()
+    {
+        System.err.println(this + " onStop called");
+        super.onStop();
+    }
+
+    @Override
+    public void onDestroy()
+    {
+        System.err.println(this + "onDestroy called");
+        super.onDestroy();
+    }
+}
diff --git a/android/src/net/i2p/android/router/activity/MainActivity.java b/android/src/net/i2p/android/router/activity/MainActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..d16d49635062699817c05d38876f949df9b30145
--- /dev/null
+++ b/android/src/net/i2p/android/router/activity/MainActivity.java
@@ -0,0 +1,16 @@
+package net.i2p.android.router.activity;
+
+import android.os.Bundle;
+
+import net.i2p.android.router.R;
+
+public class MainActivity extends I2PActivityBase {
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+}
diff --git a/android/src/net/i2p/router/I2PAndroid.java b/android/src/net/i2p/android/router/service/Init.java
similarity index 58%
rename from android/src/net/i2p/router/I2PAndroid.java
rename to android/src/net/i2p/android/router/service/Init.java
index 5210193a95f0bccd7ae6ef29b609d2cf8c277052..8928385e3d0f8eb4d53ee027b8e6e4817c886b04 100644
--- a/android/src/net/i2p/router/I2PAndroid.java
+++ b/android/src/net/i2p/android/router/service/Init.java
@@ -1,13 +1,11 @@
-package net.i2p.router;
+package net.i2p.android.router.service;
 
-import android.app.Activity;
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.os.Build;
-import android.os.Bundle;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -16,88 +14,25 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Properties;
 
+import net.i2p.android.router.R;
 import net.i2p.data.DataHelper;
 import net.i2p.router.Router;
+import net.i2p.router.RouterContext;
 import net.i2p.router.RouterLaunch;
 import net.i2p.util.OrderedProperties;
 import net.i2p.util.NativeBigInteger;
 
-public class I2PAndroid extends Activity
-{
-    static Context _context;
-    private String _myDir;
+class Init {
 
-    /** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState)
-    {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
+    private final Context ctx;
+    private final String myDir;
 
-        _context = this;  // Activity extends Context
-        _myDir = getFilesDir().getAbsolutePath();
-        debugStuff();
-        initialize();
-        // 300ms per run on emulator on eeepc
-        // 5x slower than java on my server and 50x slower than native on my server
-        // 33 ms native 29 ms java moto droid 2.2.2
-        NativeBigInteger.main(null);
+    public Init(Context c) {
+        ctx = c;
+        myDir = c.getFilesDir().getAbsolutePath();
     }
 
-    public void onRestart()
-    {
-        System.err.println("onRestart called");
-        super.onRestart();
-    }
-
-    public void onStart()
-    {
-        System.err.println("onStart called");
-        super.onStart();
-//      net.i2p.crypto.DSAEngine.main(null);
-        RouterLaunch.main(null);
-        System.err.println("Router.main finished");
-    }
-
-    public void onResume()
-    {
-        System.err.println("onResume called");
-        super.onResume();
-    }
-
-    public void onPause()
-    {
-        System.err.println("onPause called");
-        super.onPause();
-    }
-
-    public void onStop()
-    {
-        System.err.println("onStop called");
-        super.onStop();
-
-        // from routerconsole ContextHelper
-        List contexts = RouterContext.listContexts();
-        if ( (contexts == null) || (contexts.isEmpty()) ) 
-            throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down.");
-        RouterContext ctx = (RouterContext)contexts.get(0);
-
-        // shutdown() doesn't return so use shutdownGracefully()
-        ctx.router().shutdownGracefully(Router.EXIT_HARD);
-        System.err.println("shutdown complete");
-    }
-
-    public void onDestroy()
-    {
-        System.err.println("onDestroy called");
-        super.onDestroy();
-    }
-
-    public static Context getContext() {
-        return _context;
-    }
-
-    private void debugStuff() {
+    void debugStuff() {
         System.err.println("java.io.tmpdir" + ": " + System.getProperty("java.io.tmpdir"));
         System.err.println("java.vendor" + ": " + System.getProperty("java.vendor"));
         System.err.println("java.version" + ": " + System.getProperty("java.version"));
@@ -107,8 +42,8 @@ public class I2PAndroid extends Activity
         System.err.println("user.dir" + ": " + System.getProperty("user.dir"));
         System.err.println("user.home" + ": " + System.getProperty("user.home"));
         System.err.println("user.name" + ": " + System.getProperty("user.name"));
-        System.err.println("getFilesDir()" + ": " + _myDir);
-        System.err.println("Package" + ": " + getPackageName());
+        System.err.println("getFilesDir()" + ": " + myDir);
+        System.err.println("Package" + ": " + ctx.getPackageName());
         System.err.println("Version" + ": " + getOurVersion());
         System.err.println("MODEL" + ": " + Build.MODEL);
         System.err.println("DISPLAY" + ": " + Build.DISPLAY);
@@ -117,8 +52,8 @@ public class I2PAndroid extends Activity
     }
 
     private String getOurVersion() {
-        PackageManager pm = getPackageManager();
-        String us = getPackageName();
+        PackageManager pm = ctx.getPackageManager();
+        String us = ctx.getPackageName();
         try {
             PackageInfo pi = pm.getPackageInfo(us, 0);
             System.err.println("VersionCode" + ": " + pi.versionCode);
@@ -128,15 +63,15 @@ public class I2PAndroid extends Activity
         return "??";
     }
 
-    private void initialize() {
+    void initialize() {
         mergeResourceToFile(R.raw.router_config, "router.config");
         mergeResourceToFile(R.raw.logger_config, "logger.config");
         copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt");
 
         // Set up the locations so Router and WorkingDir can find them
-        System.setProperty("i2p.dir.base", _myDir);
-        System.setProperty("i2p.dir.config", _myDir);
-        System.setProperty("wrapper.logfile", _myDir + "/wrapper.log");
+        System.setProperty("i2p.dir.base", myDir);
+        System.setProperty("i2p.dir.config", myDir);
+        System.setProperty("wrapper.logfile", myDir + "/wrapper.log");
     }
 
     private void copyResourceToFile(int resID, String f) {
@@ -147,8 +82,8 @@ public class I2PAndroid extends Activity
         byte buf[] = new byte[4096];
         try {
             // Context methods
-            in = getResources().openRawResource(resID);
-            out = openFileOutput(f, 0);
+            in = ctx.getResources().openRawResource(resID);
+            out = ctx.openFileOutput(f, 0);
             
             int read = 0;
             while ( (read = in.read(buf)) != -1)
@@ -174,12 +109,11 @@ public class I2PAndroid extends Activity
         byte buf[] = new byte[4096];
         try {
             Properties props = new OrderedProperties();
-            // Context methods
-            in = getResources().openRawResource(resID);
+            in = ctx.getResources().openRawResource(resID);
             DataHelper.loadProps(props,  in);
             
             try {
-                fin = openFileInput(f);
+                fin = ctx.openFileInput(f);
                 DataHelper.loadProps(props,  fin);
                 System.err.println("Merging resource into file " + f);
             } catch (IOException ioe) {
@@ -188,7 +122,7 @@ public class I2PAndroid extends Activity
                 if (fin != null) try { fin.close(); } catch (IOException ioe) {}
             }
 
-            DataHelper.storeProps(props, getFileStreamPath(f));
+            DataHelper.storeProps(props, ctx.getFileStreamPath(f));
         } catch (IOException ioe) {
         } catch (Resources.NotFoundException nfe) {
         } finally {
diff --git a/android/src/net/i2p/android/router/service/RouterService.java b/android/src/net/i2p/android/router/service/RouterService.java
new file mode 100644
index 0000000000000000000000000000000000000000..50d7cf644a268deb4b9283602199cdad11c4fc10
--- /dev/null
+++ b/android/src/net/i2p/android/router/service/RouterService.java
@@ -0,0 +1,137 @@
+package net.i2p.android.router.service;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+import java.util.List;
+
+import net.i2p.android.router.R;
+import net.i2p.router.Router;
+import net.i2p.router.RouterContext;
+import net.i2p.router.RouterLaunch;
+import net.i2p.util.NativeBigInteger;
+
+/**
+ *  Runs the router
+ */
+public class RouterService extends Service {
+    private RouterContext _context;
+    private String _myDir;
+    private int _state;
+    private Thread _starterThread;
+    private StatusBar _statusBar;
+    private final Object _stateLock = new Object();
+
+    private static final int STATE_INIT = 0;
+    private static final int STATE_STARTING  = 1;
+    private static final int STATE_RUNNING = 2;
+    private static final int STATE_STOPPING = 3;
+    private static final int STATE_STOPPED = 4;
+
+    private static final String MARKER = "**************************************  ";
+
+    @Override
+    public void onCreate() {
+        System.err.println(this + " onCreate called" +
+                           " Current state is: " + _state);
+
+        _myDir = getFilesDir().getAbsolutePath();
+        Init init = new Init(this);
+        init.debugStuff();
+        init.initialize();
+        _statusBar = new StatusBar(this);
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        System.err.println(this + " onStart called" +
+                           "Current state is: " + _state);
+        synchronized (_stateLock) {
+            if (_state != STATE_INIT)
+                return START_STICKY;
+            _statusBar.update("I2P is starting up");
+            _state = STATE_STARTING;
+            _starterThread = new Thread(new Starter());
+            _starterThread.start();
+        }
+        return START_STICKY;
+    }
+
+    private class Starter implements Runnable {
+        public void run() {
+            System.err.println(MARKER + this + " starter thread");
+            NativeBigInteger.main(null);
+            RouterLaunch.main(null);
+            synchronized (_stateLock) {
+                if (_state != STATE_STARTING)
+                    return;
+                _state = STATE_RUNNING;
+                List contexts = RouterContext.listContexts();
+                if ( (contexts == null) || (contexts.isEmpty()) ) 
+                      throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down.");
+                _statusBar.update("I2P is running");
+                _context = (RouterContext)contexts.get(0);
+                _context.router().setKillVMOnEnd(false);
+                _context.addShutdownTask(new ShutdownHook());
+                _starterThread = null;
+            }
+            System.err.println("Router.main finished");
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent)
+    {
+        System.err.println("onBind called" +
+                           "Current state is: " + _state);
+        return null;
+    }
+
+    @Override
+    public void onDestroy() {
+        System.err.println("onDestroy called" +
+                           "Current state is: " + _state);
+        synchronized (_stateLock) {
+            if (_state == STATE_STARTING)
+                _starterThread.interrupt();
+            if (_state == STATE_STARTING || _state == STATE_RUNNING) {
+                _state = STATE_STOPPING;
+              // should this be in a thread?
+                _statusBar.update("I2P is stopping");
+                Thread stopperThread = new Thread(new Stopper());
+                stopperThread.start();
+            } else if (_state != STATE_STOPPING) {
+                _statusBar.off(this);
+            }
+        }
+    }
+
+    private class Stopper implements Runnable {
+        public void run() {
+            System.err.println(MARKER + this + " stopper thread");
+            _context.router().shutdown(Router.EXIT_HARD);
+            _statusBar.off(RouterService.this);
+            System.err.println("shutdown complete");
+            synchronized (_stateLock) {
+                _state = STATE_STOPPED;
+            }
+        }
+    }
+
+    private class ShutdownHook implements Runnable {
+        public void run() {
+            System.err.println(this + " shutdown hook" +
+                               "Current state is: " + _state);
+            synchronized (_stateLock) {
+                if (_state == STATE_STARTING || _state == STATE_RUNNING) {
+                    _state = STATE_STOPPED;
+                    _statusBar.off(RouterService.this);
+                    stopSelf();
+                }
+            }
+        }
+    }
+}
diff --git a/android/src/net/i2p/android/router/service/StatusBar.java b/android/src/net/i2p/android/router/service/StatusBar.java
new file mode 100644
index 0000000000000000000000000000000000000000..08b473fd696324316e0a0b3b3844983090992d67
--- /dev/null
+++ b/android/src/net/i2p/android/router/service/StatusBar.java
@@ -0,0 +1,45 @@
+package net.i2p.android.router.service;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+import net.i2p.android.router.R;
+import net.i2p.android.router.activity.MainActivity;
+
+public class StatusBar {
+
+    private final Context ctx;
+    private final Intent intent;
+    private final Notification notif;
+    private final NotificationManager mgr;
+
+    private static final int ID = 1;
+
+    StatusBar(Context cx) {
+        ctx = cx;
+        String ns = Context.NOTIFICATION_SERVICE;
+        mgr = (NotificationManager)ctx.getSystemService(ns);
+
+        int icon = R.drawable.ic_launcher_itoopie;
+        String text = "Starting I2P";
+        long now = System.currentTimeMillis();
+        notif = new Notification(icon, text, now);
+        notif.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
+        intent = new Intent(ctx, MainActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    }
+
+    public void update(String details) {
+        String title = "I2P Status";
+        PendingIntent pi = PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        notif.setLatestEventInfo(ctx, title, details, pi);
+        mgr.notify(ID, notif);
+    }
+
+    public void off(Context ctx) {
+        mgr.cancel(ID);
+    }
+}