load entropy data at boot.  Periodically write entropy data to disk.
diff --git a/services/java/com/android/server/EntropyService.java b/services/java/com/android/server/EntropyService.java
new file mode 100644
index 0000000..e51a0af
--- /dev/null
+++ b/services/java/com/android/server/EntropyService.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.os.Binder;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * A service designed to load and periodically save "randomness"
+ * for the Linux kernel.
+ *
+ * <p>When a Linux system starts up, the entropy pool associated with
+ * {@code /dev/random} may be in a fairly predictable state.  Applications which
+ * depend strongly on randomness may find {@code /dev/random} or
+ * {@code /dev/urandom} returning predictable data.  In order to counteract
+ * this effect, it's helpful to carry the entropy pool information across
+ * shutdowns and startups.
+ *
+ * <p>This class was modeled after the script in
+ * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">man
+ * 4 random</a>.
+ *
+ * <p>TODO: Investigate attempting to write entropy data at shutdown time
+ * instead of periodically.
+ */
+public class EntropyService extends Binder {
+    private static final String ENTROPY_FILENAME = getSystemDir() + "/entropy.dat";
+    private static final String TAG = "EntropyService";
+    private static final int ENTROPY_WHAT = 1;
+    private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000;  // 3 hrs
+    private static final String RANDOM_DEV = "/dev/urandom";
+
+    /**
+     * Handler that periodically updates the entropy on disk.
+     */
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what != ENTROPY_WHAT) {
+                Log.e(TAG, "Will not process invalid message");
+                return;
+            }
+            writeEntropy();
+            scheduleEntropyWriter();
+        }
+    };
+
+    public EntropyService() {
+        loadInitialEntropy();
+        writeEntropy();
+        scheduleEntropyWriter();
+    }
+
+    private void scheduleEntropyWriter() {
+        mHandler.removeMessages(ENTROPY_WHAT);
+        mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD);
+    }
+
+    private void loadInitialEntropy() {
+        try {
+            RandomBlock.fromFile(ENTROPY_FILENAME).toFile(RANDOM_DEV);
+        } catch (IOException e) {
+            Log.w(TAG, "unable to load initial entropy (first boot?)", e);
+        }
+    }
+
+    private void writeEntropy() {
+        try {
+            RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
+        } catch (IOException e) {
+            Log.e(TAG, "unable to write entropy", e);
+        }
+    }
+
+    private static String getSystemDir() {
+        File dataDir = Environment.getDataDirectory();
+        File systemDir = new File(dataDir, "system");
+        systemDir.mkdirs();
+        return systemDir.toString();
+    }
+}
diff --git a/services/java/com/android/server/RandomBlock.java b/services/java/com/android/server/RandomBlock.java
new file mode 100644
index 0000000..c08761e
--- /dev/null
+++ b/services/java/com/android/server/RandomBlock.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A 4k block of random {@code byte}s.
+ */
+class RandomBlock {
+
+    private static final String TAG = "RandomBlock";
+    private static final int BLOCK_SIZE = 4096;
+    private byte[] block = new byte[BLOCK_SIZE];
+
+    private RandomBlock() { }
+
+    static RandomBlock fromFile(String filename) throws IOException {
+        Log.v(TAG, "reading from file " + filename);
+        InputStream stream = null;
+        try {
+            stream = new FileInputStream(filename);
+            return fromStream(stream);
+        } finally {
+            close(stream);
+        }
+    }
+
+    private static RandomBlock fromStream(InputStream in) throws IOException {
+        RandomBlock retval = new RandomBlock();
+        int total = 0;
+        while(total < BLOCK_SIZE) {
+            int result = in.read(retval.block, total, BLOCK_SIZE - total);
+            if (result == -1) {
+                throw new EOFException();
+            }
+            total += result;
+        }
+        return retval;
+    }
+
+    void toFile(String filename) throws IOException {
+        Log.v(TAG, "writing to file " + filename);
+        OutputStream out = null;
+        try {
+            // TODO: Investigate using RandomAccessFile
+            out = new FileOutputStream(filename);
+            toStream(out);
+        } finally {
+            close(out);
+        }
+    }
+
+    private void toStream(OutputStream out) throws IOException {
+        out.write(block);
+    }
+
+    private static void close(Closeable c) {
+        try {
+            if (c == null) {
+                return;
+            }
+            c.close();
+        } catch (IOException e) {
+            Log.w(TAG, "IOException thrown while closing Closeable", e);
+        }
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f6c1525..3e4d5f9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -97,6 +97,9 @@
 
         // Critical services...
         try {
+            Log.i(TAG, "Starting Entropy Service.");
+            ServiceManager.addService("entropy", new EntropyService());
+
             Log.i(TAG, "Starting Power Manager.");
             power = new PowerManagerService();
             ServiceManager.addService(Context.POWER_SERVICE, power);