diff --git a/history.txt b/history.txt
index 74dc5e5dcb9aaba78b22f340ca5f56344aebc058..8d49bd5ff20e7dc29cd711d677c22853a6e61a8e 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,15 @@
+2011-06-04 zzz
+    * NBigI: Recognize Android
+    * KeyGenerator: Restore old return type to not break ABI (thx kytv)
+    * Router:
+      - Add a lock for reading/writing the router.info file
+      - Check our RouterInfo validity after reading and before saving,
+        to catch fatal errors sooner
+
+2011-06-03 zzz
+    * Android: More build updates, start working on JNI for GMP
+    * Build: Fix dependency issue cause by misspelled file name
+
 2011-06-02 zzz
     * Android: Build fixes
     * Crypto:
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 1245a6208605d2b497d70e4fec0f511d24c78cb2..6fb67b53b91532ed0413ef9ac7f82fe95619a76b 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -63,6 +63,7 @@ public class Router {
     /** full path */
     private String _configFilename;
     private RouterInfo _routerInfo;
+    public final Object routerInfoFileLock = new Object();
     private long _started;
     private boolean _higherVersionSeen;
     //private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
@@ -312,6 +313,9 @@ public class Router {
     
     public RouterInfo getRouterInfo() { return _routerInfo; }
 
+    /**
+     *  Caller must ensure info is valid - no validation done here
+     */
     public void setRouterInfo(RouterInfo info) { 
         _routerInfo = info; 
         if (_log.shouldLog(Log.INFO))
@@ -452,6 +456,8 @@ public class Router {
             }
             ri.sign(key);
             setRouterInfo(ri);
+            if (!ri.isValid())
+                throw new DataFormatException("Our RouterInfo has a bad signature");
             Republish r = new Republish();
             if (blockingRebuild)
                 r.timeReached();
@@ -1582,13 +1588,14 @@ private static class ShutdownHook extends Thread {
 
 /** update the router.info file whenever its, er, updated */
 private static class PersistRouterInfoJob extends JobImpl {
-    private Log _log;
     public PersistRouterInfoJob(RouterContext ctx) { 
         super(ctx); 
     }
+
     public String getName() { return "Persist Updated Router Information"; }
+
     public void runJob() {
-        _log = getContext().logManager().getLog(PersistRouterInfoJob.class);
+        Log _log = getContext().logManager().getLog(PersistRouterInfoJob.class);
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Persisting updated router info");
 
@@ -1598,15 +1605,17 @@ private static class PersistRouterInfoJob extends JobImpl {
         RouterInfo info = getContext().router().getRouterInfo();
 
         FileOutputStream fos = null;
-        try {
-            fos = new SecureFileOutputStream(infoFile);
-            info.writeBytes(fos);
-        } catch (DataFormatException dfe) {
-            _log.error("Error rebuilding the router information", dfe);
-        } catch (IOException ioe) {
-            _log.error("Error writing out the rebuilt router information", ioe);
-        } finally {
-            if (fos != null) try { fos.close(); } catch (IOException ioe) {}
+        synchronized (getContext().router().routerInfoFileLock) {
+            try {
+                fos = new SecureFileOutputStream(infoFile);
+                info.writeBytes(fos);
+            } catch (DataFormatException dfe) {
+                _log.error("Error rebuilding the router information", dfe);
+            } catch (IOException ioe) {
+                _log.error("Error writing out the rebuilt router information", ioe);
+            } finally {
+                if (fos != null) try { fos.close(); } catch (IOException ioe) {}
+            }
         }
     }
 }
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index e1f87e077ded8c1235896b49923811522eadbbfe..8ab24107c98197555eefc67083d312bbe5d8ab93 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,7 +18,7 @@ public class RouterVersion {
     /** deprecated */
     public final static String ID = "Monotone";
     public final static String VERSION = CoreVersion.VERSION;
-    public final static long BUILD = 16;
+    public final static long BUILD = 17;
 
     /** for example "-test" */
     public final static String EXTRA = "";
diff --git a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
index 36b989bc7761609ab28b9bf3d83a3b994432d27a..011152caf0f0d3d3c446897eba106cd53f6dec5c 100644
--- a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
@@ -31,7 +31,7 @@ import net.i2p.util.SecureFileOutputStream;
 
 public class CreateRouterInfoJob extends JobImpl {
     private static Log _log = new Log(CreateRouterInfoJob.class);
-    private Job _next;
+    private final Job _next;
     
     public CreateRouterInfoJob(RouterContext ctx, Job next) {
         super(ctx);
@@ -43,10 +43,15 @@ public class CreateRouterInfoJob extends JobImpl {
     public void runJob() {
         _log.debug("Creating the new router info");
         // create a new router info and store it where LoadRouterInfoJob looks
-        createRouterInfo();
+        synchronized (getContext().router().routerInfoFileLock) {
+            createRouterInfo();
+        }
         getContext().jobQueue().addJob(_next);
     }
     
+    /**
+     *  Caller must hold Router.routerInfoFileLock
+     */
     RouterInfo createRouterInfo() {
         RouterInfo info = new RouterInfo();
         FileOutputStream fos1 = null;
@@ -78,6 +83,9 @@ public class CreateRouterInfoJob extends JobImpl {
             info.setIdentity(ident);
             
             info.sign(signingPrivKey);
+
+            if (!info.isValid())
+                throw new DataFormatException("RouterInfo we just built is invalid: " + info);
             
             String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
             File ifile = new File(getContext().getRouterDir(), infoFilename);
diff --git a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
index 94b4f1d2eda8bc2227827cd91ae2299b4ba6c48a..9b484fc5ce3a96c3051ed0c4687808e4fb9a0f3c 100644
--- a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
@@ -24,7 +24,7 @@ import net.i2p.router.RouterContext;
 import net.i2p.util.Log;
 
 public class LoadRouterInfoJob extends JobImpl {
-    private Log _log;
+    private final Log _log;
     private boolean _keysExist;
     private boolean _infoExists;
     private RouterInfo _us;
@@ -37,7 +37,9 @@ public class LoadRouterInfoJob extends JobImpl {
     public String getName() { return "Load Router Info"; }
     
     public void runJob() {
-        loadRouterInfo();
+        synchronized (getContext().router().routerInfoFileLock) {
+            loadRouterInfo();
+        }
         if (_us == null) {
             RebuildRouterInfoJob r = new RebuildRouterInfoJob(getContext());
             r.rebuildRouterInfo(false);
@@ -78,7 +80,11 @@ public class LoadRouterInfoJob extends JobImpl {
                 fis1 = new FileInputStream(rif);
                 info = new RouterInfo();
                 info.readBytes(fis1);
-                _log.debug("Reading in routerInfo from " + rif.getAbsolutePath() + " and it has " + info.getAddresses().size() + " addresses");
+                // Catch this here before it all gets worse
+                if (!info.isValid())
+                    throw new DataFormatException("Our RouterInfo has a bad signature");
+                if (_log.shouldLog(Log.DEBUG))
+                    _log.debug("Reading in routerInfo from " + rif.getAbsolutePath() + " and it has " + info.getAddresses().size() + " addresses");
                 _us = info;
             }
             
diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
index b417c32bbb3343ed72f34dae41f0d7399a32343c..045542a1a43167ad79d4be11c1d37a6164095cd1 100644
--- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
@@ -45,7 +45,7 @@ import net.i2p.util.SecureFileOutputStream;
  *
  */
 public class RebuildRouterInfoJob extends JobImpl {
-    private Log _log;
+    private final Log _log;
     
     private final static long REBUILD_DELAY = 45*1000; // every 30 seconds
     
@@ -133,17 +133,24 @@ public class RebuildRouterInfoJob extends JobImpl {
                 _log.log(Log.CRIT, "Error rebuilding the new router info", dfe);
                 return;
             }
-            
+
+            if (!info.isValid()) {
+                _log.log(Log.CRIT, "RouterInfo we just built is invalid: " + info, new Exception());
+                return;
+            }
+
             FileOutputStream fos = null;
-            try {
-                fos = new SecureFileOutputStream(infoFile);
-                info.writeBytes(fos);
-            } catch (DataFormatException dfe) {
-                _log.log(Log.CRIT, "Error rebuilding the router information", dfe);
-            } catch (IOException ioe) {
-                _log.log(Log.CRIT, "Error writing out the rebuilt router information", ioe);
-            } finally {
-                if (fos != null) try { fos.close(); } catch (IOException ioe) {}
+            synchronized (getContext().router().routerInfoFileLock) {
+                try {
+                    fos = new SecureFileOutputStream(infoFile);
+                    info.writeBytes(fos);
+                } catch (DataFormatException dfe) {
+                    _log.log(Log.CRIT, "Error rebuilding the router information", dfe);
+                } catch (IOException ioe) {
+                    _log.log(Log.CRIT, "Error writing out the rebuilt router information", ioe);
+                } finally {
+                    if (fos != null) try { fos.close(); } catch (IOException ioe) {}
+                }
             }
             
         } else {