auto import from //depot/cupcake/@135843
diff --git a/core/java/android/os/AsyncResult.java b/core/java/android/os/AsyncResult.java
new file mode 100644
index 0000000..5bad09d
--- /dev/null
+++ b/core/java/android/os/AsyncResult.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.os.Message;
+
+/** @hide */
+public class AsyncResult
+{
+
+    /*************************** Instance Variables **************************/
+
+    // Expect either exception or result to be null
+    public Object userObj;
+    public Throwable exception;
+    public Object result;
+
+    /***************************** Class Methods *****************************/
+
+    /** Saves and sets m.obj */
+    public static AsyncResult 
+    forMessage(Message m, Object r, Throwable ex)
+    {
+        AsyncResult ret;
+
+        ret = new AsyncResult (m.obj, r, ex);
+
+        m.obj = ret; 
+
+        return ret;
+    }
+
+    /** Saves and sets m.obj */
+    public static AsyncResult 
+    forMessage(Message m)
+    {
+        AsyncResult ret;
+
+        ret = new AsyncResult (m.obj, null, null);
+
+        m.obj = ret; 
+
+        return ret;
+    }
+
+    /** please note, this sets m.obj to be this */
+    public 
+    AsyncResult (Object uo, Object r, Throwable ex)
+    {
+        userObj = uo;
+        result = r;
+        exception = ex;
+    }
+}
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
new file mode 100644
index 0000000..ee4e897
--- /dev/null
+++ b/core/java/android/os/AsyncTask.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to
+ * perform background operations and publish results on the UI thread without
+ * having to manipulate threads and/or handlers.</p>
+ *
+ * <p>An asynchronous task is defined by a computation that runs on a background thread and
+ * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
+ * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
+ * and 4 steps, called <code>begin</code>, <code>doInBackground</code>,
+ * <code>processProgress<code> and <code>end</code>.</p>
+ *
+ * <h2>Usage</h2>
+ * <p>AsyncTask must be subclassed to be used. The subclass will override at least
+ * one method ({@link #doInBackground}), and most often will override a
+ * second one ({@link #onPostExecute}.)</p>
+ *
+ * <p>Here is an example of subclassing:</p>
+ * <pre class="prettyprint">
+ * private class DownloadFilesTask extends AsyncTask&lt;URL, Integer, Long&gt; {
+ *     protected Long doInBackground(URL... urls) {
+ *         int count = urls.length;
+ *         long totalSize = 0;
+ *         for (int i = 0; i < count; i++) {
+ *             totalSize += Downloader.downloadFile(urls[i]);
+ *             publishProgress((int) ((i / (float) count) * 100));
+ *         }
+ *         return totalSize;
+ *     }
+ *
+ *     protected void onProgressUpdate(Integer... progress) {
+ *         setProgressPercent(progress[0]);
+ *     }
+ *
+ *     protected void onPostExecute(Long result) {
+ *         showDialog("Downloaded " + result + " bytes");
+ *     }
+ * }
+ * </pre>
+ *
+ * <p>Once created, a task is executed very simply:</p>
+ * <pre class="prettyprint">
+ * new DownloadFilesTask().execute(url1, url2, url3);
+ * </pre>
+ *
+ * <h2>AsyncTask's generic types</h2>
+ * <p>The three types used by an asynchronous task are the following:</p>
+ * <ol>
+ *     <li><code>Params</code>, the type of the parameters sent to the task upon
+ *     execution.</li>
+ *     <li><code>Progress</code>, the type of the progress units published during
+ *     the background computation.</li>
+ *     <li><code>Result</code>, the type of the result of the background
+ *     computation.</li>
+ * </ol>
+ * <p>Not all types are always used by am asynchronous task. To mark a type as unused,
+ * simply use the type {@link Void}:</p>
+ * <pre>
+ * private class MyTask extends AsyncTask<Void, Void, Void) { ... }
+ * </pre>
+ *
+ * <h2>The 4 steps</h2>
+ * <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
+ * <ol>
+ *     <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task
+ *     is executed. This step is normally used to setup the task, for instance by
+ *     showing a progress bar in the user interface.</li>
+ *     <li>{@link #doInBackground}, invoked on the background thread
+ *     immediately after {@link #onPreExecute()} finishes executing. This step is used
+ *     to perform background computation that can take a long time. The parameters
+ *     of the asynchronous task are passed to this step. The result of the computation must
+ *     be returned by this step and will be passed back to the last step. This step
+ *     can also use {@link #publishProgress} to publish one or more units
+ *     of progress. These values are published on the UI thread, in the
+ *     {@link #onProgressUpdate} step.</li>
+ *     <li>{@link #onProgressUpdate}, invoked on the UI thread after a
+ *     call to {@link #publishProgress}. The timing of the execution is
+ *     undefined. This method is used to display any form of progress in the user
+ *     interface while the background computation is still executing. For instance,
+ *     it can be used to animate a progress bar or show logs in a text field.</li>
+ *     <li>{@link #onPostExecute}, invoked on the UI thread after the background
+ *     computation finishes. The result of the background computation is passed to
+ *     this step as a parameter.</li>
+ * </ol>
+ *
+ * <h2>Threading rules</h2>
+ * <p>There are a few threading rules that must be followed for this class to
+ * work properly:</p>
+ * <ul>
+ *     <li>The task instance must be created on the UI thread.</li>
+ *     <li>{@link #execute} must be invoked on the UI thread.</li>
+ *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
+ *     {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
+ *     <li>The task can be executed only once (an exception will be thrown if
+ *     a second execution is attempted.)</li>
+ * </ul>
+ */
+public abstract class AsyncTask<Params, Progress, Result> {
+    private static final String LOG_TAG = "AsyncTask";
+
+    private static final int CORE_POOL_SIZE = 1;
+    private static final int MAXIMUM_POOL_SIZE = 10;
+    private static final int KEEP_ALIVE = 10;
+
+    private static final BlockingQueue<Runnable> sWorkQueue =
+            new LinkedBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE);
+
+    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
+        private final AtomicInteger mCount = new AtomicInteger(1);
+
+        public Thread newThread(Runnable r) {
+            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
+        }
+    };
+
+    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
+            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
+
+    private static final int MESSAGE_POST_RESULT = 0x1;
+    private static final int MESSAGE_POST_PROGRESS = 0x2;
+    private static final int MESSAGE_POST_CANCEL = 0x3;
+
+    private static final InternalHandler sHandler = new InternalHandler();
+
+    private final WorkerRunnable<Params, Result> mWorker;
+    private final FutureTask<Result> mFuture;
+
+    private volatile Status mStatus = Status.PENDING;
+
+    /**
+     * Indicates the current status of the task. Each status will be set only once
+     * during the lifetime of a task.
+     */
+    public enum Status {
+        /**
+         * Indicates that the task has not been executed yet.
+         */
+        PENDING,
+        /**
+         * Indicates that the task is running.
+         */
+        RUNNING,
+        /**
+         * Indicates that {@link AsyncTask#onPostExecute} has finished.
+         */
+        FINISHED,
+    }
+
+    /**
+     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
+     */
+    public AsyncTask() {
+        mWorker = new WorkerRunnable<Params, Result>() {
+            public Result call() throws Exception {
+                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                return doInBackground(mParams);
+            }
+        };
+
+        mFuture = new FutureTask<Result>(mWorker) {
+            @Override
+            protected void done() {
+                Message message;
+                Result result = null;
+
+                try {
+                    result = get();
+                } catch (InterruptedException e) {
+                    android.util.Log.w(LOG_TAG, e);
+                } catch (ExecutionException e) {
+                    throw new RuntimeException("An error occured while executing doInBackground()",
+                            e.getCause());
+                } catch (CancellationException e) {
+                    message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
+                            new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
+                    message.sendToTarget();
+                    return;
+                } catch (Throwable t) {
+                    throw new RuntimeException("An error occured while executing "
+                            + "doInBackground()", t);
+                }
+
+                message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
+                        new AsyncTaskResult<Result>(AsyncTask.this, result));
+                message.sendToTarget();
+            }
+        };
+    }
+
+    /**
+     * Returns the current status of this task.
+     *
+     * @return The current status.
+     */
+    public final Status getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Override this method to perform a computation on a background thread. The
+     * specified parameters are the parameters passed to {@link #execute}
+     * by the caller of this task.
+     *
+     * This method can call {@link #publishProgress} to publish updates
+     * on the UI thread.
+     *
+     * @param params The parameters of the task.
+     *
+     * @return A result, defined by the subclass of this task.
+     *
+     * @see #onPreExecute()
+     * @see #onPostExecute
+     * @see #publishProgress
+     */
+    protected abstract Result doInBackground(Params... params);
+
+    /**
+     * Runs on the UI thread before {@link #doInBackground}.
+     *
+     * @see #onPostExecute
+     * @see #doInBackground
+     */
+    protected void onPreExecute() {
+    }
+
+    /**
+     * Runs on the UI thread after {@link #doInBackground}. The
+     * specified result is the value returned by {@link #doInBackground}
+     * or null if the task was cancelled or an exception occured.
+     *
+     * @param result The result of the operation computed by {@link #doInBackground}.
+     *
+     * @see #onPreExecute
+     * @see #doInBackground
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
+    protected void onPostExecute(Result result) {
+    }
+
+    /**
+     * Runs on the UI thread after {@link #publishProgress} is invoked.
+     * The specified values are the values passed to {@link #publishProgress}.
+     *
+     * @param values The values indicating progress.
+     *
+     * @see #publishProgress
+     * @see #doInBackground
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
+    protected void onProgressUpdate(Progress... values) {
+    }
+
+    /**
+     * Runs on the UI thread after {@link #cancel(boolean)} is invoked.
+     *
+     * @see #cancel(boolean)
+     * @see #isCancelled()
+     */
+    protected void onCancelled() {
+    }
+
+    /**
+     * Returns <tt>true</tt> if this task was cancelled before it completed
+     * normally.
+     *
+     * @return <tt>true</tt> if task was cancelled before it completed
+     *
+     * @see #cancel(boolean)
+     */
+    public final boolean isCancelled() {
+        return mFuture.isCancelled();
+    }
+
+    /**
+     * Attempts to cancel execution of this task.  This attempt will
+     * fail if the task has already completed, already been cancelled,
+     * or could not be cancelled for some other reason. If successful,
+     * and this task has not started when <tt>cancel</tt> is called,
+     * this task should never run.  If the task has already started,
+     * then the <tt>mayInterruptIfRunning</tt> parameter determines
+     * whether the thread executing this task should be interrupted in
+     * an attempt to stop the task.
+     *
+     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
+     *        task should be interrupted; otherwise, in-progress tasks are allowed
+     *        to complete.
+     *
+     * @return <tt>false</tt> if the task could not be cancelled,
+     *         typically because it has already completed normally;
+     *         <tt>true</tt> otherwise
+     *
+     * @see #isCancelled()
+     * @see #onCancelled()
+     */
+    public final boolean cancel(boolean mayInterruptIfRunning) {
+        return mFuture.cancel(mayInterruptIfRunning);
+    }
+
+    /**
+     * Waits if necessary for the computation to complete, and then
+     * retrieves its result.
+     *
+     * @return The computed result.
+     *
+     * @throws CancellationException If the computation was cancelled.
+     * @throws ExecutionException If the computation threw an exception.
+     * @throws InterruptedException If the current thread was interrupted
+     *         while waiting.
+     */
+    public final Result get() throws InterruptedException, ExecutionException {
+        return mFuture.get();
+    }
+
+    /**
+     * Waits if necessary for at most the given time for the computation
+     * to complete, and then retrieves its result.
+     *
+     * @param timeout Time to wait before cancelling the operation.
+     * @param unit The time unit for the timeout.
+     *
+     * @return The computed result.
+     *
+     * @throws CancellationException If the computation was cancelled.
+     * @throws ExecutionException If the computation threw an exception.
+     * @throws InterruptedException If the current thread was interrupted
+     *         while waiting.
+     * @throws TimeoutException If the wait timed out.
+     */
+    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
+            ExecutionException, TimeoutException {
+        return mFuture.get(timeout, unit);
+    }
+
+    /**
+     * Executes the task with the specified parameters. The task returns
+     * itself (this) so that the caller can keep a reference to it.
+     *
+     * This method must be invoked on the UI thread.
+     *
+     * @param params The parameters of the task.
+     *
+     * @return This instance of AsyncTask.
+     *
+     * @throws IllegalStateException If {@link #getStatus()} returns either
+     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
+     */
+    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
+        if (mStatus != Status.PENDING) {
+            switch (mStatus) {
+                case RUNNING:
+                    throw new IllegalStateException("Cannot execute task:"
+                            + " the task is already running.");
+                case FINISHED:
+                    throw new IllegalStateException("Cannot execute task:"
+                            + " the task has already been executed "
+                            + "(a task can be executed only once)");
+            }
+        }
+
+        mStatus = Status.RUNNING;
+
+        onPreExecute();
+
+        mWorker.mParams = params;
+        sExecutor.execute(mFuture);
+
+        return this;
+    }
+
+    /**
+     * This method can be invoked from {@link #doInBackground} to
+     * publish updates on the UI thread while the background computation is
+     * still running. Each call to this method will trigger the execution of
+     * {@link #onProgressUpdate} on the UI thread.
+     *
+     * @param values The progress values to update the UI with.
+     *
+     * @see #onProgressUpdate
+     * @see #doInBackground
+     */
+    protected final void publishProgress(Progress... values) {
+        sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
+                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
+    }
+
+    private void finish(Result result) {
+        onPostExecute(result);
+        mStatus = Status.FINISHED;
+    }
+
+    private static class InternalHandler extends Handler {
+        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
+        @Override
+        public void handleMessage(Message msg) {
+            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
+            switch (msg.what) {
+                case MESSAGE_POST_RESULT:
+                    // There is only one result
+                    result.mTask.finish(result.mData[0]);
+                    break;
+                case MESSAGE_POST_PROGRESS:
+                    result.mTask.onProgressUpdate(result.mData);
+                    break;
+                case MESSAGE_POST_CANCEL:
+                    result.mTask.onCancelled();
+                    break;
+            }
+        }
+    }
+
+    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
+        Params[] mParams;
+    }
+
+    @SuppressWarnings({"RawUseOfParameterizedType"})
+    private static class AsyncTaskResult<Data> {
+        final AsyncTask mTask;
+        final Data[] mData;
+
+        AsyncTaskResult(AsyncTask task, Data... data) {
+            mTask = task;
+            mData = data;
+        }
+    }
+}
diff --git a/core/java/android/os/BadParcelableException.java b/core/java/android/os/BadParcelableException.java
new file mode 100644
index 0000000..a1c5bb2
--- /dev/null
+++ b/core/java/android/os/BadParcelableException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+import android.util.AndroidRuntimeException;
+
+/**
+ * The object you are calling has died, because its hosting process
+ * no longer exists.
+ */
+public class BadParcelableException extends AndroidRuntimeException {
+    public BadParcelableException(String msg) {
+        super(msg);
+    }
+    public BadParcelableException(Exception cause) {
+        super(cause);
+    }
+}
diff --git a/core/java/android/os/Base64Utils.java b/core/java/android/os/Base64Utils.java
new file mode 100644
index 0000000..684a469
--- /dev/null
+++ b/core/java/android/os/Base64Utils.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * {@hide}
+ */
+public class Base64Utils
+{
+    // TODO add encode api here if possible
+    
+    public static byte [] decodeBase64(String data) {
+        return decodeBase64Native(data);
+    }
+    private static native byte[] decodeBase64Native(String data);
+}
+
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
new file mode 100644
index 0000000..8f1a756
--- /dev/null
+++ b/core/java/android/os/BatteryManager.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+/**
+ * The BatteryManager class contains strings and constants used for values
+ * in the ACTION_BATTERY_CHANGED Intent.
+ */
+public class BatteryManager {
+
+    // values for "status" field in the ACTION_BATTERY_CHANGED Intent
+    public static final int BATTERY_STATUS_UNKNOWN = 1;
+    public static final int BATTERY_STATUS_CHARGING = 2;
+    public static final int BATTERY_STATUS_DISCHARGING = 3;
+    public static final int BATTERY_STATUS_NOT_CHARGING = 4;
+    public static final int BATTERY_STATUS_FULL = 5;
+
+    // values for "health" field in the ACTION_BATTERY_CHANGED Intent
+    public static final int BATTERY_HEALTH_UNKNOWN = 1;
+    public static final int BATTERY_HEALTH_GOOD = 2;
+    public static final int BATTERY_HEALTH_OVERHEAT = 3;
+    public static final int BATTERY_HEALTH_DEAD = 4;
+    public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;
+    public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
+
+    // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.
+    // These must be powers of 2.
+    /** Power source is an AC charger. */
+    public static final int BATTERY_PLUGGED_AC = 1;
+    /** Power source is a USB port. */
+    public static final int BATTERY_PLUGGED_USB = 2;
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
new file mode 100644
index 0000000..7590bfe
--- /dev/null
+++ b/core/java/android/os/BatteryStats.java
@@ -0,0 +1,828 @@
+package android.os;
+
+import java.io.PrintWriter;
+import java.util.Formatter;
+import java.util.Map;
+
+import android.util.Log;
+import android.util.Printer;
+import android.util.SparseArray;
+
+/**
+ * A class providing access to battery usage statistics, including information on
+ * wakelocks, processes, packages, and services.  All times are represented in microseconds
+ * except where indicated otherwise.
+ * @hide
+ */
+public abstract class BatteryStats implements Parcelable {
+
+    private static final boolean LOCAL_LOGV = false;
+    
+    /**
+     * A constant indicating a partial wake lock timer.
+     */
+    public static final int WAKE_TYPE_PARTIAL = 0;
+
+    /**
+     * A constant indicating a full wake lock timer.
+     */
+    public static final int WAKE_TYPE_FULL = 1;
+
+    /**
+     * A constant indicating a window wake lock timer.
+     */
+    public static final int WAKE_TYPE_WINDOW = 2;
+    
+    /**
+     * A constant indicating a sensor timer.
+     * 
+     * {@hide}
+     */
+    public static final int SENSOR = 3;
+
+    /**
+     * Include all of the data in the stats, including previously saved data.
+     */
+    public static final int STATS_TOTAL = 0;
+
+    /**
+     * Include only the last run in the stats.
+     */
+    public static final int STATS_LAST = 1;
+
+    /**
+     * Include only the current run in the stats.
+     */
+    public static final int STATS_CURRENT = 2;
+
+    /**
+     * Include only the run since the last time the device was unplugged in the stats.
+     */
+    public static final int STATS_UNPLUGGED = 3;
+    
+    /**
+     * Bump the version on this if the checkin format changes.
+     */
+    private static final int BATTERY_STATS_CHECKIN_VERSION = 1;
+    
+    // TODO: Update this list if you add/change any stats above.
+    private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" };
+
+    private static final String APK_DATA = "apk";
+    private static final String PROCESS_DATA = "process";
+    private static final String SENSOR_DATA = "sensor";
+    private static final String WAKELOCK_DATA = "wakelock";
+    private static final String NETWORK_DATA = "network";
+    private static final String BATTERY_DATA = "battery";
+    private static final String MISC_DATA = "misc";
+
+    private final StringBuilder mFormatBuilder = new StringBuilder(8);
+    private final Formatter mFormatter = new Formatter(mFormatBuilder);
+
+    /**
+     * State for keeping track of timing information.
+     */
+    public static abstract class Timer {
+
+        /**
+         * Returns the count associated with this Timer for the
+         * selected type of statistics.
+         *
+         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         */
+        public abstract int getCount(int which);
+
+        /**
+         * Returns the total time in microseconds associated with this Timer for the
+         * selected type of statistics.
+         *
+         * @param batteryRealtime system realtime on  battery in microseconds
+         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         * @return a time in microseconds
+         */
+        public abstract long getTotalTime(long batteryRealtime, int which);
+        
+        /**
+         * Temporary for debugging.
+         */
+        public abstract void logState();
+    }
+
+    /**
+     * The statistics associated with a particular uid.
+     */
+    public static abstract class Uid {
+
+        /**
+         * Returns a mapping containing wakelock statistics.
+         *
+         * @return a Map from Strings to Uid.Wakelock objects.
+         */
+        public abstract Map<String, ? extends Wakelock> getWakelockStats();
+
+        /**
+         * The statistics associated with a particular wake lock.
+         */
+        public static abstract class Wakelock {
+            public abstract Timer getWakeTime(int type);
+        }
+
+        /**
+         * Returns a mapping containing sensor statistics.
+         *
+         * @return a Map from Integer sensor ids to Uid.Sensor objects.
+         */
+        public abstract Map<Integer, ? extends Sensor> getSensorStats();
+
+        /**
+         * Returns a mapping containing process statistics.
+         *
+         * @return a Map from Strings to Uid.Proc objects.
+         */
+        public abstract Map<String, ? extends Proc> getProcessStats();
+
+        /**
+         * Returns a mapping containing package statistics.
+         *
+         * @return a Map from Strings to Uid.Pkg objects.
+         */
+        public abstract Map<String, ? extends Pkg> getPackageStats();
+        
+        /**
+         * {@hide}
+         */
+        public abstract int getUid();
+        
+        /**
+         * {@hide}
+         */
+        public abstract long getTcpBytesReceived(int which);
+        
+        /**
+         * {@hide}
+         */
+        public abstract long getTcpBytesSent(int which);
+
+        public static abstract class Sensor {
+            // Magic sensor number for the GPS.
+            public static final int GPS = -10000;
+            
+            public abstract int getHandle();
+            
+            public abstract Timer getSensorTime();
+        }
+
+        /**
+         * The statistics associated with a particular process.
+         */
+        public static abstract class Proc {
+
+            /**
+             * Returns the total time (in 1/100 sec) spent executing in user code.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract long getUserTime(int which);
+
+            /**
+             * Returns the total time (in 1/100 sec) spent executing in system code.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract long getSystemTime(int which);
+
+            /**
+             * Returns the number of times the process has been started.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract int getStarts(int which);
+        }
+
+        /**
+         * The statistics associated with a particular package.
+         */
+        public static abstract class Pkg {
+
+            /**
+             * Returns the number of times this package has done something that could wake up the
+             * device from sleep.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract int getWakeups(int which);
+
+            /**
+             * Returns a mapping containing service statistics.
+             */
+            public abstract Map<String, ? extends Serv> getServiceStats();
+
+            /**
+             * The statistics associated with a particular service.
+             */
+            public abstract class Serv {
+
+                /**
+                 * Returns the amount of time spent started.
+                 *
+                 * @param batteryUptime elapsed uptime on battery in microseconds.
+                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 * @return
+                 */
+                public abstract long getStartTime(long batteryUptime, int which);
+
+                /**
+                 * Returns the total number of times startService() has been called.
+                 *
+                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 */
+                public abstract int getStarts(int which);
+
+                /**
+                 * Returns the total number times the service has been launched.
+                 *
+                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 */
+                public abstract int getLaunches(int which);
+            }
+        }
+    }
+
+    /**
+     * Returns the number of times the device has been started.
+     */
+    public abstract int getStartCount();
+    
+    /**
+     * Returns the time in milliseconds that the screen has been on while the device was
+     * running on battery.
+     * 
+     * {@hide}
+     */
+    public abstract long getScreenOnTime(long batteryRealtime, int which);
+    
+    /**
+     * Returns the time in milliseconds that the phone has been on while the device was
+     * running on battery.
+     * 
+     * {@hide}
+     */
+    public abstract long getPhoneOnTime(long batteryRealtime, int which);
+    
+    /**
+     * Return whether we are currently running on battery.
+     */
+    public abstract boolean getIsOnBattery();
+    
+    /**
+     * Returns a SparseArray containing the statistics for each uid.
+     */
+    public abstract SparseArray<? extends Uid> getUidStats();
+
+    /**
+     * Returns the current battery uptime in microseconds.
+     *
+     * @param curTime the amount of elapsed realtime in microseconds.
+     */
+    public abstract long getBatteryUptime(long curTime);
+
+    /**
+     * Returns the current battery realtime in microseconds.
+     *
+     * @param curTime the amount of elapsed realtime in microseconds.
+     */
+    public abstract long getBatteryRealtime(long curTime);
+
+    /**
+     * Returns the total, last, or current battery uptime in microseconds.
+     *
+     * @param curTime the elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeBatteryUptime(long curTime, int which);
+
+    /**
+     * Returns the total, last, or current battery realtime in microseconds.
+     *
+     * @param curTime the current elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeBatteryRealtime(long curTime, int which);
+
+    /**
+     * Returns the total, last, or current uptime in microseconds.
+     *
+     * @param curTime the current elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeUptime(long curTime, int which);
+
+    /**
+     * Returns the total, last, or current realtime in microseconds.
+     * *
+     * @param curTime the current elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeRealtime(long curTime, int which);
+
+    private final static void formatTime(StringBuilder out, long seconds) {
+        long days = seconds / (60 * 60 * 24);
+        if (days != 0) {
+            out.append(days);
+            out.append("d ");
+        }
+        long used = days * 60 * 60 * 24;
+
+        long hours = (seconds - used) / (60 * 60);
+        if (hours != 0 || used != 0) {
+            out.append(hours);
+            out.append("h ");
+        }
+        used += hours * 60 * 60;
+
+        long mins = (seconds-used) / 60;
+        if (mins != 0 || used != 0) {
+            out.append(mins);
+            out.append("m ");
+        }
+        used += mins * 60;
+
+        if (seconds != 0 || used != 0) {
+            out.append(seconds-used);
+            out.append("s ");
+        }
+    }
+
+    private final static String formatTime(long time) {
+        long sec = time / 100;
+        StringBuilder sb = new StringBuilder();
+        formatTime(sb, sec);
+        sb.append((time - (sec * 100)) * 10);
+        sb.append("ms ");
+        return sb.toString();
+    }
+
+    private final static String formatTimeMs(long time) {
+        long sec = time / 1000;
+        StringBuilder sb = new StringBuilder();
+        formatTime(sb, sec);
+        sb.append(time - (sec * 1000));
+        sb.append("ms ");
+        return sb.toString();
+    }
+
+    private final String formatRatioLocked(long num, long den) {
+        if (den == 0L) {
+            return "---%";
+        }
+        float perc = ((float)num) / ((float)den) * 100;
+        mFormatBuilder.setLength(0);
+        mFormatter.format("%.1f%%", perc);
+        return mFormatBuilder.toString();
+    }
+
+    /**
+     *
+     * @param sb a StringBuilder object.
+     * @param timer a Timer object contining the wakelock times.
+     * @param batteryRealtime the current on-battery time in microseconds.
+     * @param name the name of the wakelock.
+     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param linePrefix a String to be prepended to each line of output.
+     * @return the line prefix
+     */
+    private static final String printWakeLock(StringBuilder sb, Timer timer,
+            long batteryRealtime, String name, int which, String linePrefix) {
+        
+        if (timer != null) {
+            // Convert from microseconds to milliseconds with rounding
+            long totalTimeMicros = timer.getTotalTime(batteryRealtime, which);
+            long totalTimeMillis = (totalTimeMicros + 500) / 1000;
+            
+            int count = timer.getCount(which);
+            if (totalTimeMillis != 0) {
+                sb.append(linePrefix);
+                sb.append(formatTimeMs(totalTimeMillis));
+                sb.append(name);
+                sb.append(' ');
+                sb.append('(');
+                sb.append(count);
+                sb.append(" times)");
+                return ", ";
+            }
+        }
+        return linePrefix;
+    }
+    
+    /**
+     * Checkin version of wakelock printer. Prints simple comma-separated list.
+     * 
+     * @param sb a StringBuilder object.
+     * @param timer a Timer object contining the wakelock times.
+     * @param now the current time in microseconds.
+     * @param name the name of the wakelock.
+     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param linePrefix a String to be prepended to each line of output.
+     * @return the line prefix
+     */
+    private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now,
+        String name, int which, String linePrefix) {
+        long totalTimeMicros = 0;
+        int count = 0;
+        if (timer != null) {
+            totalTimeMicros = timer.getTotalTime(now, which);
+            count = timer.getCount(which); 
+        }
+        sb.append(linePrefix);
+        sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
+        sb.append(',');
+        sb.append(name);
+        sb.append(',');
+        sb.append(count);
+        return ",";
+    }
+    
+    /**
+     * Dump a comma-separated line of values for terse checkin mode.
+     * 
+     * @param pw the PageWriter to dump log to
+     * @param category category of data (e.g. "total", "last", "unplugged", "current" )
+     * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" ,  "process", "network")
+     * @param args type-dependent data arguments
+     */
+    private static final void dumpLine(PrintWriter pw, int uid, String category, String type, 
+           Object... args ) {
+        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+        pw.print(uid); pw.print(',');
+        pw.print(category); pw.print(',');
+        pw.print(type); 
+        
+        for (Object arg : args) {  
+            pw.print(','); 
+            pw.print(arg); 
+        }
+        pw.print('\n');
+    }
+    
+    /**
+     * Checkin server version of dump to produce more compact, computer-readable log.
+     * 
+     * NOTE: all times are expressed in 'ms'.
+     * @param fd
+     * @param pw
+     * @param which
+     */
+    private final void dumpCheckinLocked(PrintWriter pw, int which) {
+        final long rawUptime = SystemClock.uptimeMillis() * 1000;
+        final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
+        final long batteryUptime = getBatteryUptime(rawUptime);
+        final long batteryRealtime = getBatteryRealtime(rawRealtime);
+        final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
+        final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
+        final long totalRealtime = computeRealtime(rawRealtime, which);
+        final long totalUptime = computeUptime(rawUptime, which);
+        final long screenOnTime = getScreenOnTime(batteryRealtime, which);
+        final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+       
+        StringBuilder sb = new StringBuilder(128);
+        
+        String category = STAT_NAMES[which];
+        
+        // Dump "battery" stat
+        dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, 
+                which == STATS_TOTAL ? getStartCount() : "N/A",
+                whichBatteryUptime / 1000, whichBatteryRealtime / 1000, 
+                totalUptime / 1000, totalRealtime / 1000); 
+        
+        // Dump misc stats
+        dumpLine(pw, 0 /* uid */, category, MISC_DATA,
+                screenOnTime / 1000, phoneOnTime / 1000);
+        
+        SparseArray<? extends Uid> uidStats = getUidStats();
+        final int NU = uidStats.size();
+        for (int iu = 0; iu < NU; iu++) {
+            final int uid = uidStats.keyAt(iu);
+            Uid u = uidStats.valueAt(iu);
+            // Dump Network stats per uid, if any
+            long rx = u.getTcpBytesReceived(which);
+            long tx = u.getTcpBytesSent(which);
+            if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
+
+            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
+            if (wakelocks.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
+                        : wakelocks.entrySet()) {
+                    Uid.Wakelock wl = ent.getValue();
+                    String linePrefix = "";
+                    sb.setLength(0);
+                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
+                            "full", which, linePrefix);
+                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
+                            "partial", which, linePrefix);
+                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
+                            "window", which, linePrefix);
+                    
+                    // Only log if we had at lease one wakelock...
+                    if (sb.length() > 0) {
+                       dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString());
+                    }
+                }
+            }
+                
+            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+            if (sensors.size() > 0)  {
+                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
+                        : sensors.entrySet()) {
+                    Uid.Sensor se = ent.getValue();
+                    int sensorNumber = ent.getKey();
+                    Timer timer = se.getSensorTime();
+                    if (timer != null) {
+                        // Convert from microseconds to milliseconds with rounding
+                        long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
+                        int count = timer.getCount(which);
+                        if (totalTime != 0) {
+                            dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
+                        }
+                    } 
+                }
+            }
+
+            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+            if (processStats.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
+                        : processStats.entrySet()) {
+                    Uid.Proc ps = ent.getValue();
+    
+                    long userTime = ps.getUserTime(which);
+                    long systemTime = ps.getSystemTime(which);
+                    int starts = ps.getStarts(which);
+    
+                    if (userTime != 0 || systemTime != 0 || starts != 0) {
+                        dumpLine(pw, uid, category, PROCESS_DATA, 
+                                ent.getKey(), // proc
+                                userTime * 10, // cpu time in ms
+                                systemTime * 10, // user time in ms
+                                starts); // process starts
+                    }
+                }
+            }
+
+            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
+            if (packageStats.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
+                        : packageStats.entrySet()) {
+              
+                    Uid.Pkg ps = ent.getValue();
+                    int wakeups = ps.getWakeups(which);
+                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+                    for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
+                            : serviceStats.entrySet()) {
+                        BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
+                        long startTime = ss.getStartTime(batteryUptime, which);
+                        int starts = ss.getStarts(which);
+                        int launches = ss.getLaunches(which);
+                        if (startTime != 0 || starts != 0 || launches != 0) {
+                            dumpLine(pw, uid, category, APK_DATA, 
+                                    wakeups, // wakeup alarms
+                                    ent.getKey(), // Apk
+                                    sent.getKey(), // service
+                                    startTime / 1000, // time spent started, in ms
+                                    starts,
+                                    launches);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private final void dumpLocked(Printer pw, String prefix, int which) {
+        final long rawUptime = SystemClock.uptimeMillis() * 1000;
+        final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
+        final long batteryUptime = getBatteryUptime(rawUptime);
+        final long batteryRealtime = getBatteryUptime(rawRealtime);
+
+        final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
+        final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
+        final long totalRealtime = computeRealtime(rawRealtime, which);
+        final long totalUptime = computeUptime(rawUptime, which);
+        
+        StringBuilder sb = new StringBuilder(128);
+
+        pw.println(prefix
+                + "  Time on battery: " + formatTimeMs(whichBatteryUptime / 1000)
+                + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
+                + ") uptime, "
+                + formatTimeMs(whichBatteryRealtime / 1000) + "("
+                + formatRatioLocked(whichBatteryRealtime, totalRealtime)
+                + ") realtime");
+        pw.println(prefix
+                + "  Total: "
+                + formatTimeMs(totalUptime / 1000)
+                + "uptime, "
+                + formatTimeMs(totalRealtime / 1000)
+                + "realtime");
+        
+        long screenOnTime = getScreenOnTime(batteryRealtime, which);
+        long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+        pw.println(prefix
+                + "  Time with screen on: " + formatTimeMs(screenOnTime / 1000)
+                + "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime)
+                + "), time with phone on: " + formatTimeMs(phoneOnTime / 1000)
+                + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")");
+        
+        pw.println(" ");
+
+        SparseArray<? extends Uid> uidStats = getUidStats();
+        final int NU = uidStats.size();
+        for (int iu=0; iu<NU; iu++) {
+            final int uid = uidStats.keyAt(iu);
+            Uid u = uidStats.valueAt(iu);
+            pw.println(prefix + "  #" + uid + ":");
+            boolean uidActivity = false;
+            
+            long tcpReceived = u.getTcpBytesReceived(which);
+            long tcpSent = u.getTcpBytesSent(which);
+            if (tcpReceived != 0 || tcpSent != 0) {
+                pw.println(prefix + "    Network: " + tcpReceived + " bytes received, "
+                        + tcpSent + " bytes sent");
+            }
+
+            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
+            if (wakelocks.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
+                    : wakelocks.entrySet()) {
+                    Uid.Wakelock wl = ent.getValue();
+                    String linePrefix = ": ";
+                    sb.setLength(0);
+                    sb.append(prefix);
+                    sb.append("    Wake lock ");
+                    sb.append(ent.getKey());
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
+                            "full", which, linePrefix);
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
+                            "partial", which, linePrefix);
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
+                            "window", which, linePrefix);
+                    if (!linePrefix.equals(": ")) {
+                        sb.append(" realtime");
+                    } else {
+                        sb.append(": (nothing executed)");
+                    }
+                    pw.println(sb.toString());
+                    uidActivity = true;
+                }
+            }
+
+            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+            if (sensors.size() > 0) {
+                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
+                    : sensors.entrySet()) {
+                    Uid.Sensor se = ent.getValue();
+                    int sensorNumber = ent.getKey();
+                    sb.setLength(0);
+                    sb.append(prefix);
+                    sb.append("    Sensor ");
+                    int handle = se.getHandle();
+                    if (handle == Uid.Sensor.GPS) {
+                        sb.append("GPS");
+                    } else {
+                        sb.append(handle);
+                    }
+                    sb.append(": ");
+
+                    Timer timer = se.getSensorTime();
+                    if (timer != null) {
+                        // Convert from microseconds to milliseconds with rounding
+                        long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
+                        int count = timer.getCount(which);
+                        //timer.logState();
+                        if (totalTime != 0) {
+                            sb.append(formatTimeMs(totalTime));
+                            sb.append("realtime (");
+                            sb.append(count);
+                            sb.append(" times)");
+                        } else {
+                            sb.append("(not used)");
+                        }
+                    } else {
+                        sb.append("(not used)");
+                    }
+
+                    pw.println(sb.toString());
+                    uidActivity = true;
+                }
+            }
+
+            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+            if (processStats.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
+                    : processStats.entrySet()) {
+                    Uid.Proc ps = ent.getValue();
+                    long userTime;
+                    long systemTime;
+                    int starts;
+
+                    userTime = ps.getUserTime(which);
+                    systemTime = ps.getSystemTime(which);
+                    starts = ps.getStarts(which);
+
+                    if (userTime != 0 || systemTime != 0 || starts != 0) {
+                        pw.println(prefix + "    Proc " + ent.getKey() + ":");
+                        pw.println(prefix + "      CPU: " + formatTime(userTime) + "user + "
+                                + formatTime(systemTime) + "kernel");
+                        pw.println(prefix + "      " + starts + " process starts");
+                        uidActivity = true;
+                    }
+                }
+            }
+
+            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
+            if (packageStats.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
+                    : packageStats.entrySet()) {
+                    pw.println(prefix + "    Apk " + ent.getKey() + ":");
+                    boolean apkActivity = false;
+                    Uid.Pkg ps = ent.getValue();
+                    int wakeups = ps.getWakeups(which);
+                    if (wakeups != 0) {
+                        pw.println(prefix + "      " + wakeups + " wakeup alarms");
+                        apkActivity = true;
+                    }
+                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+                    if (serviceStats.size() > 0) {
+                        for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
+                                : serviceStats.entrySet()) {
+                            BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
+                            long startTime = ss.getStartTime(batteryUptime, which);
+                            int starts = ss.getStarts(which);
+                            int launches = ss.getLaunches(which);
+                            if (startTime != 0 || starts != 0 || launches != 0) {
+                                pw.println(prefix + "      Service " + sent.getKey() + ":");
+                                pw.println(prefix + "        Created for: "
+                                        + formatTimeMs(startTime / 1000)
+                                        + " uptime");
+                                pw.println(prefix + "        Starts: " + starts
+                                        + ", launches: " + launches);
+                                apkActivity = true;
+                            }
+                        }
+                    }
+                    if (!apkActivity) {
+                        pw.println(prefix + "      (nothing executed)");
+                    }
+                    uidActivity = true;
+                }
+            }
+            if (!uidActivity) {
+                pw.println(prefix + "    (nothing executed)");
+            }
+        }
+    }
+
+    /**
+     * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
+     *
+     * @param pw a Printer to receive the dump output.
+     */
+    @SuppressWarnings("unused")
+    public void dumpLocked(Printer pw) {
+        pw.println("Total Statistics (Current and Historic):");
+        pw.println("  System starts: " + getStartCount()
+                + ", currently on battery: " + getIsOnBattery());
+        dumpLocked(pw, "", STATS_TOTAL);
+        pw.println("");
+        pw.println("Last Run Statistics (Previous run of system):");
+        dumpLocked(pw, "", STATS_LAST);
+        pw.println("");
+        pw.println("Current Battery Statistics (Currently running system):");
+        dumpLocked(pw, "", STATS_CURRENT);
+        pw.println("");
+        pw.println("Unplugged Statistics (Since last unplugged from power):");
+        dumpLocked(pw, "", STATS_UNPLUGGED);
+    }
+    
+    @SuppressWarnings("unused")
+    public void dumpCheckinLocked(PrintWriter pw, String[] args) {
+        boolean isUnpluggedOnly = false;
+        
+        for (String arg : args) {
+            if ("-u".equals(arg)) {
+                if (LOCAL_LOGV) Log.v("BatteryStats", "Dumping unplugged data");
+                isUnpluggedOnly = true;
+            }
+        }
+        
+        if (isUnpluggedOnly) {
+            dumpCheckinLocked(pw, STATS_UNPLUGGED);
+        }
+        else {
+            dumpCheckinLocked(pw, STATS_TOTAL);
+            dumpCheckinLocked(pw, STATS_LAST);
+            dumpCheckinLocked(pw, STATS_UNPLUGGED);
+            dumpCheckinLocked(pw, STATS_CURRENT);
+        }
+    }
+    
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
new file mode 100644
index 0000000..df10c6a
--- /dev/null
+++ b/core/java/android/os/Binder.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.util.Config;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Modifier;
+
+/**
+ * Base class for a remotable object, the core part of a lightweight
+ * remote procedure call mechanism defined by {@link IBinder}.
+ * This class is an implementation of IBinder that provides
+ * the standard support creating a local implementation of such an object.
+ * 
+ * <p>Most developers will not implement this class directly, instead using the
+ * <a href="{@docRoot}guide/developing/tools/aidl.html">aidl</a> tool to describe the desired
+ * interface, having it generate the appropriate Binder subclass.  You can,
+ * however, derive directly from Binder to implement your own custom RPC
+ * protocol or simply instantiate a raw Binder object directly to use as a
+ * token that can be shared across processes.
+ * 
+ * @see IBinder
+ */
+public class Binder implements IBinder {
+    /*
+     * Set this flag to true to detect anonymous, local or member classes
+     * that extend this Binder class and that are not static. These kind
+     * of classes can potentially create leaks.
+     */
+    private static final boolean FIND_POTENTIAL_LEAKS = false;
+    private static final String TAG = "Binder";
+
+    private int mObject;
+    private IInterface mOwner;
+    private String mDescriptor;
+    
+    /**
+     * Return the ID of the process that sent you the current transaction
+     * that is being processed.  This pid can be used with higher-level
+     * system services to determine its identity and check permissions.
+     * If the current thread is not currently executing an incoming transaction,
+     * then its own pid is returned.
+     */
+    public static final native int getCallingPid();
+    
+    /**
+     * Return the ID of the user assigned to the process that sent you the
+     * current transaction that is being processed.  This uid can be used with
+     * higher-level system services to determine its identity and check
+     * permissions.  If the current thread is not currently executing an
+     * incoming transaction, then its own uid is returned.
+     */
+    public static final native int getCallingUid();
+    
+    /**
+     * Reset the identity of the incoming IPC to the local process.  This can
+     * be useful if, while handling an incoming call, you will be calling
+     * on interfaces of other objects that may be local to your process and
+     * need to do permission checks on the calls coming into them (so they
+     * will check the permission of your own local process, and not whatever
+     * process originally called you).
+     * 
+     * @return Returns an opaque token that can be used to restore the
+     * original calling identity by passing it to
+     * {@link #restoreCallingIdentity(long)}.
+     * 
+     * @see #getCallingPid()
+     * @see #getCallingUid()
+     * @see #restoreCallingIdentity(long)
+     */
+    public static final native long clearCallingIdentity();
+    
+    /**
+     * Restore the identity of the incoming IPC back to a previously identity
+     * that was returned by {@link #clearCallingIdentity}.
+     * 
+     * @param token The opaque token that was previously returned by
+     * {@link #clearCallingIdentity}.
+     * 
+     * @see #clearCallingIdentity
+     */
+    public static final native void restoreCallingIdentity(long token);
+    
+    /**
+     * Flush any Binder commands pending in the current thread to the kernel
+     * driver.  This can be
+     * useful to call before performing an operation that may block for a long
+     * time, to ensure that any pending object references have been released
+     * in order to prevent the process from holding on to objects longer than
+     * it needs to.
+     */
+    public static final native void flushPendingCommands();
+    
+    /**
+     * Add the calling thread to the IPC thread pool.  This function does
+     * not return until the current process is exiting.
+     */
+    public static final native void joinThreadPool();
+    
+    /**
+     * Default constructor initializes the object.
+     */
+    public Binder() {
+        init();
+
+        if (FIND_POTENTIAL_LEAKS) {
+            final Class<? extends Binder> klass = getClass();
+            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
+                    (klass.getModifiers() & Modifier.STATIC) == 0) {
+                Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
+                    klass.getCanonicalName());
+            }
+        }
+    }
+    
+    /**
+     * Convenience method for associating a specific interface with the Binder.
+     * After calling, queryLocalInterface() will be implemented for you
+     * to return the given owner IInterface when the corresponding
+     * descriptor is requested.
+     */
+    public void attachInterface(IInterface owner, String descriptor) {
+        mOwner = owner;
+        mDescriptor = descriptor;
+    }
+    
+    /**
+     * Default implementation returns an empty interface name.
+     */
+    public String getInterfaceDescriptor() {
+        return mDescriptor;
+    }
+
+    /**
+     * Default implementation always returns true -- if you got here,
+     * the object is alive.
+     */
+    public boolean pingBinder() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Note that if you're calling on a local binder, this always returns true
+     * because your process is alive if you're calling it.
+     */
+    public boolean isBinderAlive() {
+        return true;
+    }
+    
+    /**
+     * Use information supplied to attachInterface() to return the
+     * associated IInterface if it matches the requested
+     * descriptor.
+     */
+    public IInterface queryLocalInterface(String descriptor) {
+        if (mDescriptor.equals(descriptor)) {
+            return mOwner;
+        }
+        return null;
+    }
+    
+    /**
+     * Default implementation is a stub that returns false.  You will want
+     * to override this to do the appropriate unmarshalling of transactions.
+     *
+     * <p>If you want to call this, call transact().
+     */
+    protected boolean onTransact(int code, Parcel data, Parcel reply,
+            int flags) throws RemoteException {
+        if (code == INTERFACE_TRANSACTION) {
+            reply.writeString(getInterfaceDescriptor());
+            return true;
+        } else if (code == DUMP_TRANSACTION) {
+            ParcelFileDescriptor fd = data.readFileDescriptor();
+            String[] args = data.readStringArray();
+            if (fd != null) {
+                try {
+                    dump(fd.getFileDescriptor(), args);
+                } finally {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Implemented to call the more convenient version
+     * {@link #dump(FileDescriptor, PrintWriter, String[])}.
+     */
+    public void dump(FileDescriptor fd, String[] args) {
+        FileOutputStream fout = new FileOutputStream(fd);
+        PrintWriter pw = new PrintWriter(fout);
+        try {
+            dump(fd, pw, args);
+        } finally {
+            pw.flush();
+        }
+    }
+    
+    /**
+     * Print the object's state into the given stream.
+     * 
+     * @param fd The raw file descriptor that the dump is being sent to.
+     * @param fout The file to which you should dump your state.  This will be
+     * closed for you after you return.
+     * @param args additional arguments to the dump request.
+     */
+    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+    }
+
+    /**
+     * Default implementation rewinds the parcels and calls onTransact.  On
+     * the remote side, transact calls into the binder to do the IPC.
+     */
+    public final boolean transact(int code, Parcel data, Parcel reply,
+            int flags) throws RemoteException {
+        if (Config.LOGV) Log.v("Binder", "Transact: " + code + " to " + this);
+        if (data != null) {
+            data.setDataPosition(0);
+        }
+        boolean r = onTransact(code, data, reply, flags);
+        if (reply != null) {
+            reply.setDataPosition(0);
+        }
+        return r;
+    }
+    
+    /**
+     * Local implementation is a no-op.
+     */
+    public void linkToDeath(DeathRecipient recipient, int flags) {
+    }
+
+    /**
+     * Local implementation is a no-op.
+     */
+    public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
+        return true;
+    }
+    
+    protected void finalize() throws Throwable {
+        try {
+            destroy();
+        } finally {
+            super.finalize();
+        }
+    }
+    
+    private native final void init();
+    private native final void destroy();
+    private boolean execTransact(int code, int dataObj, int replyObj,
+            int flags) {
+        Parcel data = Parcel.obtain(dataObj);
+        Parcel reply = Parcel.obtain(replyObj);
+        // theoretically, we should call transact, which will call onTransact,
+        // but all that does is rewind it, and we just got these from an IPC,
+        // so we'll just call it directly.
+        boolean res;
+        try {
+            res = onTransact(code, data, reply, flags);
+        } catch (RemoteException e) {
+            reply.writeException(e);
+            res = true;
+        } catch (RuntimeException e) {
+            reply.writeException(e);
+            res = true;
+        }
+        reply.recycle();
+        data.recycle();
+        return res;
+    }
+}
+
+final class BinderProxy implements IBinder {
+    public native boolean pingBinder();
+    public native boolean isBinderAlive();
+    
+    public IInterface queryLocalInterface(String descriptor) {
+        return null;
+    }
+    
+    public native String getInterfaceDescriptor() throws RemoteException;
+    public native boolean transact(int code, Parcel data, Parcel reply,
+            int flags) throws RemoteException;
+    public native void linkToDeath(DeathRecipient recipient, int flags)
+            throws RemoteException;
+    public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
+
+    public void dump(FileDescriptor fd, String[] args) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeFileDescriptor(fd);
+        data.writeStringArray(args);
+        try {
+            transact(DUMP_TRANSACTION, data, null, 0);
+        } finally {
+            data.recycle();
+        }
+    }
+    
+    BinderProxy() {
+        mSelf = new WeakReference(this);
+    }
+    
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            destroy();
+        } finally {
+            super.finalize();
+        }
+    }
+    
+    private native final void destroy();
+    
+    private static final void sendDeathNotice(DeathRecipient recipient) {
+        if (Config.LOGV) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
+        try {
+            recipient.binderDied();
+        }
+        catch (RuntimeException exc) {
+            Log.w("BinderNative", "Uncaught exception from death notification",
+                    exc);
+        }
+    }
+    
+    final private WeakReference mSelf;
+    private int mObject;
+}
diff --git a/core/java/android/os/Broadcaster.java b/core/java/android/os/Broadcaster.java
new file mode 100644
index 0000000..96dc61a
--- /dev/null
+++ b/core/java/android/os/Broadcaster.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/** @hide */
+public class Broadcaster
+{
+    public Broadcaster()
+    {
+    }
+
+    /**
+     *  Sign up for notifications about something.
+     *
+     *  When this broadcaster pushes a message with senderWhat in the what field,
+     *  target will be sent a copy of that message with targetWhat in the what field.
+     */
+    public void request(int senderWhat, Handler target, int targetWhat)
+    {
+        synchronized (this) {
+            Registration r = null;
+            if (mReg == null) {
+                r = new Registration();
+                r.senderWhat = senderWhat;
+                r.targets = new Handler[1];
+                r.targetWhats = new int[1];
+                r.targets[0] = target;
+                r.targetWhats[0] = targetWhat;
+                mReg = r;
+                r.next = r;
+                r.prev = r;
+            } else {
+                // find its place in the map
+                Registration start = mReg;
+                r = start;
+                do {
+                    if (r.senderWhat >= senderWhat) {
+                        break;
+                    }
+                    r = r.next;
+                } while (r != start);
+                int n;
+                if (r.senderWhat != senderWhat) {
+                    // we didn't find a senderWhat match, but r is right
+                    // after where it goes
+                    Registration reg = new Registration();
+                    reg.senderWhat = senderWhat;
+                    reg.targets = new Handler[1];
+                    reg.targetWhats = new int[1];
+                    reg.next = r;
+                    reg.prev = r.prev;
+                    r.prev.next = reg;
+                    r.prev = reg;
+
+                    if (r == mReg && r.senderWhat > reg.senderWhat) {
+                        mReg = reg;
+                    }
+                    
+                    r = reg;
+                    n = 0;
+                } else {
+                    n = r.targets.length;
+                    Handler[] oldTargets = r.targets;
+                    int[] oldWhats = r.targetWhats;
+                    // check for duplicates, and don't do it if we are dup.
+                    for (int i=0; i<n; i++) {
+                        if (oldTargets[i] == target && oldWhats[i] == targetWhat) {
+                            return;
+                        }
+                    }
+                    r.targets = new Handler[n+1];
+                    System.arraycopy(oldTargets, 0, r.targets, 0, n);
+                    r.targetWhats = new int[n+1];
+                    System.arraycopy(oldWhats, 0, r.targetWhats, 0, n);
+                }
+                r.targets[n] = target;
+                r.targetWhats[n] = targetWhat;
+            }
+        }
+    }
+    
+    /**
+     * Unregister for notifications for this senderWhat/target/targetWhat tuple.
+     */
+    public void cancelRequest(int senderWhat, Handler target, int targetWhat)
+    {
+        synchronized (this) {
+            Registration start = mReg;
+            Registration r = start;
+            
+            if (r == null) {
+                return;
+            }
+            
+            do {
+                if (r.senderWhat >= senderWhat) {
+                    break;
+                }
+                r = r.next;
+            } while (r != start);
+            
+            if (r.senderWhat == senderWhat) {
+                Handler[] targets = r.targets;
+                int[] whats = r.targetWhats;
+                int oldLen = targets.length;
+                for (int i=0; i<oldLen; i++) {
+                    if (targets[i] == target && whats[i] == targetWhat) {
+                        r.targets = new Handler[oldLen-1];
+                        r.targetWhats = new int[oldLen-1];
+                        if (i > 0) {
+                            System.arraycopy(targets, 0, r.targets, 0, i);
+                            System.arraycopy(whats, 0, r.targetWhats, 0, i);
+                        }
+
+                        int remainingLen = oldLen-i-1;
+                        if (remainingLen != 0) {
+                            System.arraycopy(targets, i+1, r.targets, i,
+                                    remainingLen);
+                            System.arraycopy(whats, i+1, r.targetWhats, i,
+                                    remainingLen);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * For debugging purposes, print the registrations to System.out
+     */
+    public void dumpRegistrations()
+    {
+        synchronized (this) {
+            Registration start = mReg;
+            System.out.println("Broadcaster " + this + " {");
+            if (start != null) {
+                Registration r = start;
+                do {
+                    System.out.println("    senderWhat=" + r.senderWhat);
+                    int n = r.targets.length;
+                    for (int i=0; i<n; i++) {
+                        System.out.println("        [" + r.targetWhats[i]
+                                        + "] " + r.targets[i]);
+                    }
+                    r = r.next;
+                } while (r != start);
+            }
+            System.out.println("}");
+        }
+    }
+
+    /**
+     * Send out msg.  Anyone who has registered via the request() method will be
+     * sent the message.
+     */
+    public void broadcast(Message msg)
+    {
+        synchronized (this) {
+        	if (mReg == null) {
+        		return;
+        	}
+        	
+            int senderWhat = msg.what;
+            Registration start = mReg;
+            Registration r = start;
+            do {
+                if (r.senderWhat >= senderWhat) {
+                    break;
+                }
+                r = r.next;
+            } while (r != start);
+            if (r.senderWhat == senderWhat) {
+                Handler[] targets = r.targets;
+                int[] whats = r.targetWhats;
+                int n = targets.length;
+                for (int i=0; i<n; i++) {
+                    Handler target = targets[i];
+                    Message m = Message.obtain();
+                    m.copyFrom(msg);
+                    m.what = whats[i];
+                    target.sendMessage(m);
+                }
+            }
+        }
+    }
+
+    private class Registration
+    {
+        Registration next;
+        Registration prev;
+
+        int senderWhat;
+        Handler[] targets;
+        int[] targetWhats;
+    }
+    private Registration mReg;
+}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
new file mode 100644
index 0000000..467c17f
--- /dev/null
+++ b/core/java/android/os/Build.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+/**
+ * Information about the current build, extracted from system properties.
+ */
+public class Build {
+    /** Value used for when a build property is unknown. */
+    private static final String UNKNOWN = "unknown";
+
+    /** Either a changelist number, or a label like "M4-rc20". */
+    public static final String ID = getString("ro.build.id");
+
+    /** A build ID string meant for displaying to the user */
+    public static final String DISPLAY = getString("ro.build.display.id");
+
+    /** The name of the overall product. */
+    public static final String PRODUCT = getString("ro.product.name");
+
+    /** The name of the industrial design. */
+    public static final String DEVICE = getString("ro.product.device");
+
+    /** The name of the underlying board, like "goldfish". */
+    public static final String BOARD = getString("ro.product.board");
+
+    /** The brand (e.g., carrier) the software is customized for, if any. */
+    public static final String BRAND = getString("ro.product.brand");
+
+    /** The end-user-visible name for the end product. */
+    public static final String MODEL = getString("ro.product.model");
+
+    /** Various version strings. */
+    public static class VERSION {
+        /**
+         * The internal value used by the underlying source control to
+         * represent this build.  E.g., a perforce changelist number
+         * or a git hash.
+         */
+        public static final String INCREMENTAL = getString("ro.build.version.incremental");
+
+        /**
+         * The user-visible version string.  E.g., "1.0" or "3.4b5".
+         */
+        public static final String RELEASE = getString("ro.build.version.release");
+
+        /**
+         * The user-visible SDK version of the framework. It is an integer starting at 1.
+         */
+        public static final String SDK = getString("ro.build.version.sdk");
+    }
+
+    /** The type of build, like "user" or "eng". */
+    public static final String TYPE = getString("ro.build.type");
+
+    /** Comma-separated tags describing the build, like "unsigned,debug". */
+    public static final String TAGS = getString("ro.build.tags");
+
+    /** A string that uniquely identifies this build.  Do not attempt to parse this value. */
+    public static final String FINGERPRINT = getString("ro.build.fingerprint");
+
+    // The following properties only make sense for internal engineering builds.
+    public static final long TIME = getLong("ro.build.date.utc") * 1000;
+    public static final String USER = getString("ro.build.user");
+    public static final String HOST = getString("ro.build.host");
+
+    private static String getString(String property) {
+        return SystemProperties.get(property, UNKNOWN);
+    }
+
+    private static long getLong(String property) {
+        try {
+            return Long.parseLong(SystemProperties.get(property));
+        } catch (NumberFormatException e) {
+            return -1;
+        }
+    }
+}
diff --git a/core/java/android/os/Bundle.aidl b/core/java/android/os/Bundle.aidl
new file mode 100644
index 0000000..b9e1224
--- /dev/null
+++ b/core/java/android/os/Bundle.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/os/Bundle.aidl
+**
+** Copyright 2007, 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 android.os;
+
+parcelable Bundle;
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
new file mode 100644
index 0000000..b669fa2
--- /dev/null
+++ b/core/java/android/os/Bundle.java
@@ -0,0 +1,1452 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A mapping from String values to various Parcelable types.
+ *
+ */
+public final class Bundle implements Parcelable, Cloneable {
+    private static final String LOG_TAG = "Bundle";
+    public static final Bundle EMPTY;
+
+    static {
+        EMPTY = new Bundle();
+        EMPTY.mMap = Collections.unmodifiableMap(new HashMap<String, Object>());
+    }
+
+    // Invariant - exactly one of mMap / mParcelledData will be null
+    // (except inside a call to unparcel)
+
+    /* package */ Map<String, Object> mMap = null;
+
+    /*
+     * If mParcelledData is non-null, then mMap will be null and the
+     * data are stored as a Parcel containing a Bundle.  When the data
+     * are unparcelled, mParcelledData willbe set to null.
+     */
+    /* package */ Parcel mParcelledData = null;
+
+    private boolean mHasFds = false;
+    private boolean mFdsKnown = true;
+
+    /**
+     * The ClassLoader used when unparcelling data from mParcelledData.
+     */
+    private ClassLoader mClassLoader;
+
+    /**
+     * Constructs a new, empty Bundle.
+     */
+    public Bundle() {
+        mMap = new HashMap<String, Object>();
+        mClassLoader = getClass().getClassLoader();
+    }
+
+    /**
+     * Constructs a Bundle whose data is stored as a Parcel.  The data
+     * will be unparcelled on first contact, using the assigned ClassLoader.
+     *
+     * @param parcelledData a Parcel containing a Bundle
+     */
+    Bundle(Parcel parcelledData) {
+        readFromParcel(parcelledData);
+    }
+
+    /**
+     * Constructs a new, empty Bundle that uses a specific ClassLoader for
+     * instantiating Parcelable and Serializable objects.
+     *
+     * @param loader An explicit ClassLoader to use when instantiating objects
+     * inside of the Bundle.
+     */
+    public Bundle(ClassLoader loader) {
+        mMap = new HashMap<String, Object>();
+        mClassLoader = loader;
+    }
+
+    /**
+     * Constructs a new, empty Bundle sized to hold the given number of
+     * elements. The Bundle will grow as needed.
+     *
+     * @param capacity the initial capacity of the Bundle
+     */
+    public Bundle(int capacity) {
+        mMap = new HashMap<String, Object>(capacity);
+        mClassLoader = getClass().getClassLoader();
+    }
+
+    /**
+     * Constructs a Bundle containing a copy of the mappings from the given
+     * Bundle.
+     *
+     * @param b a Bundle to be copied.
+     */
+    public Bundle(Bundle b) {
+        if (b.mParcelledData != null) {
+            mParcelledData = Parcel.obtain();
+            mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
+            mParcelledData.setDataPosition(0);
+        } else {
+            mParcelledData = null;
+        }
+
+        if (b.mMap != null) {
+            mMap = new HashMap<String, Object>(b.mMap);
+        } else {
+            mMap = null;
+        }
+
+        mHasFds = b.mHasFds;
+        mFdsKnown = b.mFdsKnown;
+        mClassLoader = b.mClassLoader;
+    }
+
+    /**
+     * Changes the ClassLoader this Bundle uses when instantiating objects.
+     *
+     * @param loader An explicit ClassLoader to use when instantiating objects
+     * inside of the Bundle.
+     */
+    public void setClassLoader(ClassLoader loader) {
+        mClassLoader = loader;
+    }
+
+    /**
+     * Clones the current Bundle. The internal map is cloned, but the keys and
+     * values to which it refers are copied by reference.
+     */
+    @Override
+    public Object clone() {
+        return new Bundle(this);
+    }
+
+    /**
+     * If the underlying data are stored as a Parcel, unparcel them
+     * using the currently assigned class loader.
+     */
+    /* package */ synchronized void unparcel() {
+        if (mParcelledData == null) {
+            return;
+        }
+
+        mParcelledData.setDataPosition(0);
+        Bundle b = mParcelledData.readBundleUnpacked(mClassLoader);
+        mMap = b.mMap;
+
+        mHasFds = mParcelledData.hasFileDescriptors();
+        mFdsKnown = true;
+        
+        mParcelledData.recycle();
+        mParcelledData = null;
+    }
+
+    /**
+     * Returns the number of mappings contained in this Bundle.
+     *
+     * @return the number of mappings as an int.
+     */
+    public int size() {
+        unparcel();
+        return mMap.size();
+    }
+
+    /**
+     * Returns true if the mapping of this Bundle is empty, false otherwise.
+     */
+    public boolean isEmpty() {
+        unparcel();
+        return mMap.isEmpty();
+    }
+
+    /**
+     * Removes all elements from the mapping of this Bundle.
+     */
+    public void clear() {
+        unparcel();
+        mMap.clear();
+        mHasFds = false;
+        mFdsKnown = true;
+    }
+
+    /**
+     * Returns true if the given key is contained in the mapping
+     * of this Bundle.
+     *
+     * @param key a String key
+     * @return true if the key is part of the mapping, false otherwise
+     */
+    public boolean containsKey(String key) {
+        unparcel();
+        return mMap.containsKey(key);
+    }
+
+    /**
+     * Returns the entry with the given key as an object.
+     *
+     * @param key a String key
+     * @return an Object, or null
+     */
+    public Object get(String key) {
+        unparcel();
+        return mMap.get(key);
+    }
+
+    /**
+     * Removes any entry with the given key from the mapping of this Bundle.
+     *
+     * @param key a String key
+     */
+    public void remove(String key) {
+        unparcel();
+        mMap.remove(key);
+    }
+
+    /**
+     * Inserts all mappings from the given Bundle into this Bundle.
+     *
+     * @param map a Bundle
+     */
+    public void putAll(Bundle map) {
+        unparcel();
+        map.unparcel();
+        mMap.putAll(map.mMap);
+
+        // fd state is now known if and only if both bundles already knew
+        mHasFds |= map.mHasFds;
+        mFdsKnown = mFdsKnown && map.mFdsKnown;
+    }
+
+    /**
+     * Returns a Set containing the Strings used as keys in this Bundle.
+     *
+     * @return a Set of String keys
+     */
+    public Set<String> keySet() {
+        unparcel();
+        return mMap.keySet();
+    }
+
+    /**
+     * Reports whether the bundle contains any parcelled file descriptors.
+     */
+    public boolean hasFileDescriptors() {
+        if (!mFdsKnown) {
+            boolean fdFound = false;    // keep going until we find one or run out of data
+            
+            if (mParcelledData != null) {
+                if (mParcelledData.hasFileDescriptors()) {
+                    fdFound = true;
+                }
+            } else {
+                // It's been unparcelled, so we need to walk the map
+                Iterator<Map.Entry<String, Object>> iter = mMap.entrySet().iterator();
+                while (!fdFound && iter.hasNext()) {
+                    Object obj = iter.next().getValue();
+                    if (obj instanceof Parcelable) {
+                        if ((((Parcelable)obj).describeContents()
+                                & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+                            fdFound = true;
+                            break;
+                        }
+                    } else if (obj instanceof Parcelable[]) {
+                        Parcelable[] array = (Parcelable[]) obj;
+                        for (int n = array.length - 1; n >= 0; n--) {
+                            if ((array[n].describeContents()
+                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+                                fdFound = true;
+                                break;
+                            }
+                        }
+                    } else if (obj instanceof SparseArray) {
+                        SparseArray<? extends Parcelable> array =
+                                (SparseArray<? extends Parcelable>) obj;
+                        for (int n = array.size() - 1; n >= 0; n--) {
+                            if ((array.get(n).describeContents()
+                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+                                fdFound = true;
+                                break;
+                            }
+                        }
+                    } else if (obj instanceof ArrayList) {
+                        ArrayList array = (ArrayList) obj;
+                        // an ArrayList here might contain either Strings or
+                        // Parcelables; only look inside for Parcelables
+                        if ((array.size() > 0)
+                                && (array.get(0) instanceof Parcelable)) {
+                            for (int n = array.size() - 1; n >= 0; n--) {
+                                Parcelable p = (Parcelable) array.get(n);
+                                if (p != null && ((p.describeContents()
+                                        & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+                                    fdFound = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            mHasFds = fdFound;
+            mFdsKnown = true;
+        }
+        return mHasFds;
+    }
+    
+    /**
+     * Inserts a Boolean value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a Boolean, or null
+     */
+    public void putBoolean(String key, boolean value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a byte value into the mapping of this Bundle, replacing
+     * any existing value for the given key.
+     *
+     * @param key a String, or null
+     * @param value a byte
+     */
+    public void putByte(String key, byte value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a char value into the mapping of this Bundle, replacing
+     * any existing value for the given key.
+     *
+     * @param key a String, or null
+     * @param value a char, or null
+     */
+    public void putChar(String key, char value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a short value into the mapping of this Bundle, replacing
+     * any existing value for the given key.
+     *
+     * @param key a String, or null
+     * @param value a short
+     */
+    public void putShort(String key, short value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts an int value into the mapping of this Bundle, replacing
+     * any existing value for the given key.
+     *
+     * @param key a String, or null
+     * @param value an int, or null
+     */
+    public void putInt(String key, int value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a long value into the mapping of this Bundle, replacing
+     * any existing value for the given key.
+     *
+     * @param key a String, or null
+     * @param value a long
+     */
+    public void putLong(String key, long value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a float value into the mapping of this Bundle, replacing
+     * any existing value for the given key.
+     *
+     * @param key a String, or null
+     * @param value a float
+     */
+    public void putFloat(String key, float value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a double value into the mapping of this Bundle, replacing
+     * any existing value for the given key.
+     *
+     * @param key a String, or null
+     * @param value a double
+     */
+    public void putDouble(String key, double value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a String value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a String, or null
+     */
+    public void putString(String key, String value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a CharSequence value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a CharSequence, or null
+     */
+    public void putCharSequence(String key, CharSequence value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a Parcelable value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a Parcelable object, or null
+     */
+    public void putParcelable(String key, Parcelable value) {
+        unparcel();
+        mMap.put(key, value);
+        mFdsKnown = false;
+    }
+
+    /**
+     * Inserts an array of Parcelable values into the mapping of this Bundle,
+     * replacing any existing value for the given key.  Either key or value may
+     * be null.
+     *
+     * @param key a String, or null
+     * @param value an array of Parcelable objects, or null
+     */
+    public void putParcelableArray(String key, Parcelable[] value) {
+        unparcel();
+        mMap.put(key, value);
+        mFdsKnown = false;
+    }
+
+    /**
+     * Inserts a List of Parcelable values into the mapping of this Bundle,
+     * replacing any existing value for the given key.  Either key or value may
+     * be null.
+     *
+     * @param key a String, or null
+     * @param value an ArrayList of Parcelable objects, or null
+     */
+    public void putParcelableArrayList(String key,
+        ArrayList<? extends Parcelable> value) {
+        unparcel();
+        mMap.put(key, value);
+        mFdsKnown = false;
+    }
+
+    /**
+     * Inserts a SparceArray of Parcelable values into the mapping of this
+     * Bundle, replacing any existing value for the given key.  Either key
+     * or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a SparseArray of Parcelable objects, or null
+     */
+    public void putSparseParcelableArray(String key,
+            SparseArray<? extends Parcelable> value) {
+        unparcel();
+        mMap.put(key, value);
+        mFdsKnown = false;
+    }
+
+    /**
+     * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value an ArrayList<Integer> object, or null
+     */
+    public void putIntegerArrayList(String key, ArrayList<Integer> value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value an ArrayList<String> object, or null
+     */
+    public void putStringArrayList(String key, ArrayList<String> value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a Serializable value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a Serializable object, or null
+     */
+    public void putSerializable(String key, Serializable value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a boolean array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a boolean array object, or null
+     */
+    public void putBooleanArray(String key, boolean[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a byte array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a byte array object, or null
+     */
+    public void putByteArray(String key, byte[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a short array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a short array object, or null
+     */
+    public void putShortArray(String key, short[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a char array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a char array object, or null
+     */
+    public void putCharArray(String key, char[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts an int array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value an int array object, or null
+     */
+    public void putIntArray(String key, int[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a long array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a long array object, or null
+     */
+    public void putLongArray(String key, long[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a float array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a float array object, or null
+     */
+    public void putFloatArray(String key, float[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a double array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a double array object, or null
+     */
+    public void putDoubleArray(String key, double[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a String array value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a String array object, or null
+     */
+    public void putStringArray(String key, String[] value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts a Bundle value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value a Bundle object, or null
+     */
+    public void putBundle(String key, Bundle value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Inserts an IBinder value into the mapping of this Bundle, replacing
+     * any existing value for the given key.  Either key or value may be null.
+     *
+     * @param key a String, or null
+     * @param value an IBinder object, or null
+     *
+     * @deprecated
+     * @hide
+     */
+    @Deprecated
+    public void putIBinder(String key, IBinder value) {
+        unparcel();
+        mMap.put(key, value);
+    }
+
+    /**
+     * Returns the value associated with the given key, or false if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a boolean value
+     */
+    public boolean getBoolean(String key) {
+        unparcel();
+        return getBoolean(key, false);
+    }
+
+    // Log a message if the value was non-null but not of the expected type
+    private void typeWarning(String key, Object value, String className,
+        Object defaultValue, ClassCastException e) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Key ");
+        sb.append(key);
+        sb.append(" expected ");
+        sb.append(className);
+        sb.append(" but value was a ");
+        sb.append(value.getClass().getName());
+        sb.append(".  The default value ");
+        sb.append(defaultValue);
+        sb.append(" was returned.");
+        Log.w(LOG_TAG, sb.toString());
+        Log.w(LOG_TAG, "Attempt to cast generated internal exception:", e);
+    }
+
+    private void typeWarning(String key, Object value, String className,
+        ClassCastException e) {
+        typeWarning(key, value, className, "<null>", e);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a boolean value
+     */
+    public boolean getBoolean(String key, boolean defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Boolean) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Boolean", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or (byte) 0 if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a byte value
+     */
+    public byte getByte(String key) {
+        unparcel();
+        return getByte(key, (byte) 0);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a byte value
+     */
+    public Byte getByte(String key, byte defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Byte) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Byte", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or false if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a char value
+     */
+    public char getChar(String key) {
+        unparcel();
+        return getChar(key, (char) 0);
+    }
+
+    /**
+     * Returns the value associated with the given key, or (char) 0 if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a char value
+     */
+    public char getChar(String key, char defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Character) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Character", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or (short) 0 if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a short value
+     */
+    public short getShort(String key) {
+        unparcel();
+        return getShort(key, (short) 0);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a short value
+     */
+    public short getShort(String key, short defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Short) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Short", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or 0 if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return an int value
+     */
+    public int getInt(String key) {
+        unparcel();
+        return getInt(key, 0);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return an int value
+     */
+    public int getInt(String key, int defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Integer) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Integer", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or 0L if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a long value
+     */
+    public long getLong(String key) {
+        unparcel();
+        return getLong(key, 0L);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a long value
+     */
+    public long getLong(String key, long defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Long) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Long", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or 0.0f if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a float value
+     */
+    public float getFloat(String key) {
+        unparcel();
+        return getFloat(key, 0.0f);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a float value
+     */
+    public float getFloat(String key, float defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Float) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Float", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or 0.0 if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a double value
+     */
+    public double getDouble(String key) {
+        unparcel();
+        return getDouble(key, 0.0);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @return a double value
+     */
+    public double getDouble(String key, double defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (Double) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Double", defaultValue, e);
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a String value, or null
+     */
+    public String getString(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (String) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "String", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a CharSequence value, or null
+     */
+    public CharSequence getCharSequence(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (CharSequence) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "CharSequence", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a Bundle value, or null
+     */
+    public Bundle getBundle(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (Bundle) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Bundle", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a Parcelable value, or null
+     */
+    public <T extends Parcelable> T getParcelable(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (T) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Parcelable", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a Parcelable[] value, or null
+     */
+    public Parcelable[] getParcelableArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (Parcelable[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Parcelable[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return an ArrayList<T> value, or null
+     */
+    public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (ArrayList<T>) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "ArrayList", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     *
+     * @return a SparseArray of T values, or null
+     */
+    public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (SparseArray<T>) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "SparseArray", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a Serializable value, or null
+     */
+    public Serializable getSerializable(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (Serializable) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Serializable", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return an ArrayList<String> value, or null
+     */
+    public ArrayList<Integer> getIntegerArrayList(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (ArrayList<Integer>) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "ArrayList<Integer>", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return an ArrayList<String> value, or null
+     */
+    public ArrayList<String> getStringArrayList(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (ArrayList<String>) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "ArrayList<String>", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a boolean[] value, or null
+     */
+    public boolean[] getBooleanArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (boolean[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "byte[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a byte[] value, or null
+     */
+    public byte[] getByteArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (byte[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "byte[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a short[] value, or null
+     */
+    public short[] getShortArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (short[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "short[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a char[] value, or null
+     */
+    public char[] getCharArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (char[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "char[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return an int[] value, or null
+     */
+    public int[] getIntArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (int[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "int[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a long[] value, or null
+     */
+    public long[] getLongArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (long[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "long[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a float[] value, or null
+     */
+    public float[] getFloatArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (float[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "float[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a double[] value, or null
+     */
+    public double[] getDoubleArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (double[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "double[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return a String[] value, or null
+     */
+    public String[] getStringArray(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (String[]) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "String[]", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if
+     * no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key.
+     *
+     * @param key a String, or null
+     * @return an IBinder value, or null
+     *
+     * @deprecated
+     * @hide
+     */
+    @Deprecated
+    public IBinder getIBinder(String key) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (IBinder) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "IBinder", e);
+            return null;
+        }
+    }
+
+    public static final Parcelable.Creator<Bundle> CREATOR =
+        new Parcelable.Creator<Bundle>() {
+        public Bundle createFromParcel(Parcel in) {
+            return in.readBundle();
+        }
+
+        public Bundle[] newArray(int size) {
+            return new Bundle[size];
+        }
+    };
+
+    /**
+     * Report the nature of this Parcelable's contents
+     */
+    public int describeContents() {
+        int mask = 0;
+        if (hasFileDescriptors()) {
+            mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR;
+        }
+        return mask;
+    }
+    
+    /**
+     * Writes the Bundle contents to a Parcel, typically in order for
+     * it to be passed through an IBinder connection.
+     * @param parcel The parcel to copy this bundle to.
+     */
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeBundle(this);
+    }
+
+    /**
+     * Reads the Parcel contents into this Bundle, typically in order for
+     * it to be passed through an IBinder connection.
+     * @param parcel The parcel to overwrite this bundle from.
+     */
+    public void readFromParcel(Parcel parcel) {
+        mParcelledData = parcel;
+        mHasFds = mParcelledData.hasFileDescriptors();
+        mFdsKnown = true;
+    }
+
+    @Override
+    public synchronized String toString() {
+        if (mParcelledData != null) {
+            return "Bundle[mParcelledData.dataSize=" +
+                    mParcelledData.dataSize() + "]";
+        }
+        return "Bundle[" + mMap.toString() + "]";
+    }
+}
diff --git a/core/java/android/os/ConditionVariable.java b/core/java/android/os/ConditionVariable.java
new file mode 100644
index 0000000..95a9259
--- /dev/null
+++ b/core/java/android/os/ConditionVariable.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * Class that implements the condition variable locking paradigm.
+ *
+ * <p>
+ * This differs from the built-in java.lang.Object wait() and notify()
+ * in that this class contains the condition to wait on itself.  That means
+ * open(), close() and block() are sticky.  If open() is called before block(),
+ * block() will not block, and instead return immediately.
+ *
+ * <p>
+ * This class uses itself is at the object to wait on, so if you wait()
+ * or notify() on a ConditionVariable, the results are undefined.
+ */
+public class ConditionVariable
+{
+    private volatile boolean mCondition;
+
+    /**
+     * Create the ConditionVariable in the default closed state.
+     */
+    public ConditionVariable()
+    {
+        mCondition = false;
+    }
+
+    /**
+     * Create the ConditionVariable with the given state.
+     * 
+     * <p>
+     * Pass true for opened and false for closed.
+     */
+    public ConditionVariable(boolean state)
+    {
+        mCondition = state;
+    }
+
+    /**
+     * Open the condition, and release all threads that are blocked.
+     *
+     * <p>
+     * Any threads that later approach block() will not block unless close()
+     * is called.
+     */
+    public void open()
+    {
+        synchronized (this) {
+            boolean old = mCondition;
+            mCondition = true;
+            if (!old) {
+                this.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Reset the condition to the closed state.
+     *
+     * <p>
+     * Any threads that call block() will block until someone calls open.
+     */
+    public void close()
+    {
+        synchronized (this) {
+            mCondition = false;
+        }
+    }
+
+    /**
+     * Block the current thread until the condition is opened.
+     *
+     * <p>
+     * If the condition is already opened, return immediately.
+     */
+    public void block()
+    {
+        synchronized (this) {
+            while (!mCondition) {
+                try {
+                    this.wait();
+                }
+                catch (InterruptedException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Block the current thread until the condition is opened or until
+     * timeout milliseconds have passed.
+     *
+     * <p>
+     * If the condition is already opened, return immediately.
+     *
+     * @param timeout the minimum time to wait in milliseconds.
+     *
+     * @return true if the condition was opened, false if the call returns
+     * because of the timeout.
+     */
+    public boolean block(long timeout)
+    {
+        // Object.wait(0) means wait forever, to mimic this, we just
+        // call the other block() method in that case.  It simplifies
+        // this code for the common case.
+        if (timeout != 0) {
+            synchronized (this) {
+                long now = System.currentTimeMillis();
+                long end = now + timeout;
+                while (!mCondition && now < end) {
+                    try {
+                        this.wait(end-now);
+                    }
+                    catch (InterruptedException e) {
+                    }
+                    now = System.currentTimeMillis();
+                }
+                return mCondition;
+            }
+        } else {
+            this.block();
+            return true;
+        }
+    }
+}
diff --git a/core/java/android/os/CountDownTimer.java b/core/java/android/os/CountDownTimer.java
new file mode 100644
index 0000000..0c5c615
--- /dev/null
+++ b/core/java/android/os/CountDownTimer.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+import android.util.Log;
+
+/**
+ * Schedule a countdown until a time in the future, with
+ * regular notifications on intervals along the way.
+ *
+ * Example of showing a 30 second countdown in a text field:
+ *
+ * <pre class="prettyprint">
+ * new CountdownTimer(30000, 1000) {
+ *
+ *     public void onTick(long millisUntilFinished) {
+ *         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
+ *     }
+ *
+ *     public void onFinish() {
+ *         mTextField.setText("done!");
+ *     }
+ *  }.start();
+ * </pre>
+ *
+ * The calls to {@link #onTick(long)} are synchronized to this object so that
+ * one call to {@link #onTick(long)} won't ever occur before the previous
+ * callback is complete.  This is only relevant when the implementation of
+ * {@link #onTick(long)} takes an amount of time to execute that is significant
+ * compared to the countdown interval.
+ */
+public abstract class CountDownTimer {
+
+    /**
+     * Millis since epoch when alarm should stop.
+     */
+    private final long mMillisInFuture;
+
+    /**
+     * The interval in millis that the user receives callbacks
+     */
+    private final long mCountdownInterval;
+
+    private long mStopTimeInFuture;
+
+    /**
+     * @param millisInFuture The number of millis in the future from the call
+     *   to {@link #start()} until the countdown is done and {@link #onFinish()}
+     *   is called.
+     * @param countDownInterval The interval along the way to receive
+     *   {@link #onTick(long)} callbacks.
+     */
+    public CountDownTimer(long millisInFuture, long countDownInterval) {
+        mMillisInFuture = millisInFuture;
+        mCountdownInterval = countDownInterval;
+    }
+
+    /**
+     * Cancel the countdown.
+     */
+    public final void cancel() {
+        mHandler.removeMessages(MSG);
+    }
+
+    /**
+     * Start the countdown.
+     */
+    public synchronized final CountDownTimer start() {
+        if (mMillisInFuture <= 0) {
+            onFinish();
+            return this;
+        }
+        mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
+        mHandler.sendMessage(mHandler.obtainMessage(MSG));
+        return this;
+    }
+
+
+    /**
+     * Callback fired on regular interval.
+     * @param millisUntilFinished The amount of time until finished.
+     */
+    public abstract void onTick(long millisUntilFinished);
+
+    /**
+     * Callback fired when the time is up.
+     */
+    public abstract void onFinish();
+
+
+    private static final int MSG = 1;
+
+
+    // handles counting down
+    private Handler mHandler = new Handler() {
+
+        @Override
+        public void handleMessage(Message msg) {
+
+            synchronized (CountDownTimer.this) {
+                final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
+
+                if (millisLeft <= 0) {
+                    onFinish();
+                } else if (millisLeft < mCountdownInterval) {
+                    // no tick, just delay until done
+                    sendMessageDelayed(obtainMessage(MSG), millisLeft);
+                } else {
+                    long lastTickStart = SystemClock.elapsedRealtime();
+                    onTick(millisLeft);
+
+                    // take into account user's onTick taking time to execute
+                    long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
+
+                    // special case: user's onTick took more than interval to
+                    // complete, skip to next interval
+                    while (delay < 0) delay += mCountdownInterval;
+
+                    sendMessageDelayed(obtainMessage(MSG), delay);
+                }
+            }
+        }
+    };
+}
diff --git a/core/java/android/os/DeadObjectException.java b/core/java/android/os/DeadObjectException.java
new file mode 100644
index 0000000..94c5387
--- /dev/null
+++ b/core/java/android/os/DeadObjectException.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+import android.os.RemoteException;
+
+/**
+ * The object you are calling has died, because its hosting process
+ * no longer exists.
+ */
+public class DeadObjectException extends RemoteException {
+    public DeadObjectException() {
+        super();
+    }
+}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
new file mode 100644
index 0000000..950bb09
--- /dev/null
+++ b/core/java/android/os/Debug.java
@@ -0,0 +1,717 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import org.apache.harmony.dalvik.ddmc.Chunk;
+import org.apache.harmony.dalvik.ddmc.ChunkHandler;
+import org.apache.harmony.dalvik.ddmc.DdmServer;
+
+import dalvik.bytecode.Opcodes;
+import dalvik.system.VMDebug;
+
+
+/**
+ * Provides various debugging functions for Android applications, including
+ * tracing and allocation counts.
+ * <p><strong>Logging Trace Files</strong></p>
+ * <p>Debug can create log files that give details about an application, such as
+ * a call stack and start/stop times for any running methods. See <a
+href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
+ * information about reading trace files. To start logging trace files, call one
+ * of the startMethodTracing() methods. To stop tracing, call
+ * {@link #stopMethodTracing()}.
+ */
+public final class Debug
+{
+    /**
+     * Flags for startMethodTracing().  These can be ORed together.
+     *
+     * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
+     * trace key file.
+     */
+    public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
+
+    /**
+     * Flags for printLoadedClasses().  Default behavior is to only show
+     * the class name.
+     */
+    public static final int SHOW_FULL_DETAIL    = 1;
+    public static final int SHOW_CLASSLOADER    = (1 << 1);
+    public static final int SHOW_INITIALIZED    = (1 << 2);
+
+    // set/cleared by waitForDebugger()
+    private static volatile boolean mWaiting = false;
+
+    private Debug() {}
+
+    /*
+     * How long to wait for the debugger to finish sending requests.  I've
+     * seen this hit 800msec on the device while waiting for a response
+     * to travel over USB and get processed, so we take that and add
+     * half a second.
+     */
+    private static final int MIN_DEBUGGER_IDLE = 1300;      // msec
+
+    /* how long to sleep when polling for activity */
+    private static final int SPIN_DELAY = 200;              // msec
+
+    /**
+     * Default trace file path and file
+     */
+    private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/";
+    private static final String DEFAULT_TRACE_BODY = "dmtrace";
+    private static final String DEFAULT_TRACE_EXTENSION = ".trace";
+    private static final String DEFAULT_TRACE_FILE_PATH =
+        DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
+        + DEFAULT_TRACE_EXTENSION;
+
+
+    /**
+     * This class is used to retrieved various statistics about the memory mappings for this
+     * process. The returns info broken down by dalvik, native, and other. All results are in kB.
+     */
+    public static class MemoryInfo {
+        /** The proportional set size for dalvik. */
+        public int dalvikPss;
+        /** The private dirty pages used by dalvik. */
+        public int dalvikPrivateDirty;
+        /** The shared dirty pages used by dalvik. */
+        public int dalvikSharedDirty;
+
+        /** The proportional set size for the native heap. */
+        public int nativePss;
+        /** The private dirty pages used by the native heap. */
+        public int nativePrivateDirty;
+        /** The shared dirty pages used by the native heap. */
+        public int nativeSharedDirty;
+
+        /** The proportional set size for everything else. */
+        public int otherPss;
+        /** The private dirty pages used by everything else. */
+        public int otherPrivateDirty;
+        /** The shared dirty pages used by everything else. */
+        public int otherSharedDirty;
+    }
+
+
+    /**
+     * Wait until a debugger attaches.  As soon as the debugger attaches,
+     * this returns, so you will need to place a breakpoint after the
+     * waitForDebugger() call if you want to start tracing immediately.
+     */
+    public static void waitForDebugger() {
+        if (!VMDebug.isDebuggingEnabled()) {
+            //System.out.println("debugging not enabled, not waiting");
+            return;
+        }
+        if (isDebuggerConnected())
+            return;
+
+        // if DDMS is listening, inform them of our plight
+        System.out.println("Sending WAIT chunk");
+        byte[] data = new byte[] { 0 };     // 0 == "waiting for debugger"
+        Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1);
+        DdmServer.sendChunk(waitChunk);
+
+        mWaiting = true;
+        while (!isDebuggerConnected()) {
+            try { Thread.sleep(SPIN_DELAY); }
+            catch (InterruptedException ie) {}
+        }
+        mWaiting = false;
+
+        System.out.println("Debugger has connected");
+
+        /*
+         * There is no "ready to go" signal from the debugger, and we're
+         * not allowed to suspend ourselves -- the debugger expects us to
+         * be running happily, and gets confused if we aren't.  We need to
+         * allow the debugger a chance to set breakpoints before we start
+         * running again.
+         *
+         * Sit and spin until the debugger has been idle for a short while.
+         */
+        while (true) {
+            long delta = VMDebug.lastDebuggerActivity();
+            if (delta < 0) {
+                System.out.println("debugger detached?");
+                break;
+            }
+
+            if (delta < MIN_DEBUGGER_IDLE) {
+                System.out.println("waiting for debugger to settle...");
+                try { Thread.sleep(SPIN_DELAY); }
+                catch (InterruptedException ie) {}
+            } else {
+                System.out.println("debugger has settled (" + delta + ")");
+                break;
+            }
+        }
+    }
+
+    /**
+     * Returns "true" if one or more threads is waiting for a debugger
+     * to attach.
+     */
+    public static boolean waitingForDebugger() {
+        return mWaiting;
+    }
+
+    /**
+     * Determine if a debugger is currently attached.
+     */
+    public static boolean isDebuggerConnected() {
+        return VMDebug.isDebuggerConnected();
+    }
+
+    /**
+     * Change the JDWP port.
+     *
+     * @deprecated no longer needed or useful
+     */
+    @Deprecated
+    public static void changeDebugPort(int port) {}
+
+    /**
+     * This is the pathname to the sysfs file that enables and disables
+     * tracing on the qemu emulator.
+     */
+    private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state";
+
+    /**
+     * Enable qemu tracing. For this to work requires running everything inside
+     * the qemu emulator; otherwise, this method will have no effect. The trace
+     * file is specified on the command line when the emulator is started. For
+     * example, the following command line <br />
+     * <code>emulator -trace foo</code><br />
+     * will start running the emulator and create a trace file named "foo". This
+     * method simply enables writing the trace records to the trace file.
+     *
+     * <p>
+     * The main differences between this and {@link #startMethodTracing()} are
+     * that tracing in the qemu emulator traces every cpu instruction of every
+     * process, including kernel code, so we have more complete information,
+     * including all context switches. We can also get more detailed information
+     * such as cache misses. The sequence of calls is determined by
+     * post-processing the instruction trace. The qemu tracing is also done
+     * without modifying the application or perturbing the timing of calls
+     * because no instrumentation is added to the application being traced.
+     * </p>
+     *
+     * <p>
+     * One limitation of using this method compared to using
+     * {@link #startMethodTracing()} on the real device is that the emulator
+     * does not model all of the real hardware effects such as memory and
+     * bus contention.  The emulator also has a simple cache model and cannot
+     * capture all the complexities of a real cache.
+     * </p>
+     */
+    public static void startNativeTracing() {
+        // Open the sysfs file for writing and write "1" to it.
+        PrintWriter outStream = null;
+        try {
+            FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
+            outStream = new PrintWriter(new OutputStreamWriter(fos));
+            outStream.println("1");
+        } catch (Exception e) {
+        } finally {
+            if (outStream != null)
+                outStream.close();
+        }
+
+        VMDebug.startEmulatorTracing();
+    }
+
+    /**
+     * Stop qemu tracing.  See {@link #startNativeTracing()} to start tracing.
+     *
+     * <p>Tracing can be started and stopped as many times as desired.  When
+     * the qemu emulator itself is stopped then the buffered trace records
+     * are flushed and written to the trace file.  In fact, it is not necessary
+     * to call this method at all; simply killing qemu is sufficient.  But
+     * starting and stopping a trace is useful for examining a specific
+     * region of code.</p>
+     */
+    public static void stopNativeTracing() {
+        VMDebug.stopEmulatorTracing();
+
+        // Open the sysfs file for writing and write "0" to it.
+        PrintWriter outStream = null;
+        try {
+            FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
+            outStream = new PrintWriter(new OutputStreamWriter(fos));
+            outStream.println("0");
+        } catch (Exception e) {
+            // We could print an error message here but we probably want
+            // to quietly ignore errors if we are not running in the emulator.
+        } finally {
+            if (outStream != null)
+                outStream.close();
+        }
+    }
+
+    /**
+     * Enable "emulator traces", in which information about the current
+     * method is made available to the "emulator -trace" feature.  There
+     * is no corresponding "disable" call -- this is intended for use by
+     * the framework when tracing should be turned on and left that way, so
+     * that traces captured with F9/F10 will include the necessary data.
+     *
+     * This puts the VM into "profile" mode, which has performance
+     * consequences.
+     *
+     * To temporarily enable tracing, use {@link #startNativeTracing()}.
+     */
+    public static void enableEmulatorTraceOutput() {
+        VMDebug.startEmulatorTracing();
+    }
+
+    /**
+     * Start method tracing with default log name and buffer size. See <a
+href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
+     * information about reading these files. Call stopMethodTracing() to stop
+     * tracing.
+     */
+    public static void startMethodTracing() {
+        VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0);
+    }
+
+    /**
+     * Start method tracing, specifying the trace log file name.  The trace
+     * file will be put under "/sdcard" unless an absolute path is given.
+     * See <a
+       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
+     * information about reading trace files.
+     *
+     * @param traceName Name for the trace log file to create.
+     * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
+     * If the files already exist, they will be truncated.
+     * If the trace file given does not end in ".trace", it will be appended for you.
+     */
+    public static void startMethodTracing(String traceName) {
+        startMethodTracing(traceName, 0, 0);
+    }
+
+    /**
+     * Start method tracing, specifying the trace log file name and the
+     * buffer size. The trace files will be put under "/sdcard" unless an
+     * absolute path is given. See <a
+       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
+     * information about reading trace files.
+     * @param traceName    Name for the trace log file to create.
+     * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
+     * If the files already exist, they will be truncated.
+     * If the trace file given does not end in ".trace", it will be appended for you.
+     *
+     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
+     */
+    public static void startMethodTracing(String traceName, int bufferSize) {
+        startMethodTracing(traceName, bufferSize, 0);
+    }
+
+    /**
+     * Start method tracing, specifying the trace log file name and the
+     * buffer size. The trace files will be put under "/sdcard" unless an
+     * absolute path is given. See <a
+       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
+     * information about reading trace files.
+     *
+     * <p>
+     * When method tracing is enabled, the VM will run more slowly than
+     * usual, so the timings from the trace files should only be considered
+     * in relative terms (e.g. was run #1 faster than run #2).  The times
+     * for native methods will not change, so don't try to use this to
+     * compare the performance of interpreted and native implementations of the
+     * same method.  As an alternative, consider using "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
+     * </p>
+     *
+     * @param traceName    Name for the trace log file to create.
+     * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
+     * If the files already exist, they will be truncated.
+     * If the trace file given does not end in ".trace", it will be appended for you.
+     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
+     */
+    public static void startMethodTracing(String traceName, int bufferSize,
+        int flags) {
+
+        String pathName = traceName;
+        if (pathName.charAt(0) != '/')
+            pathName = DEFAULT_TRACE_PATH_PREFIX + pathName;
+        if (!pathName.endsWith(DEFAULT_TRACE_EXTENSION))
+            pathName = pathName + DEFAULT_TRACE_EXTENSION;
+
+        VMDebug.startMethodTracing(pathName, bufferSize, flags);
+    }
+
+    /**
+     * Stop method tracing.
+     */
+    public static void stopMethodTracing() {
+        VMDebug.stopMethodTracing();
+    }
+
+    /**
+     * Get an indication of thread CPU usage.  The value returned
+     * indicates the amount of time that the current thread has spent
+     * executing code or waiting for certain types of I/O.
+     *
+     * The time is expressed in nanoseconds, and is only meaningful
+     * when compared to the result from an earlier call.  Note that
+     * nanosecond resolution does not imply nanosecond accuracy.
+     *
+     * On system which don't support this operation, the call returns -1.
+     */
+    public static long threadCpuTimeNanos() {
+        return VMDebug.threadCpuTimeNanos();
+    }
+
+    /**
+     * Count the number and aggregate size of memory allocations between
+     * two points.
+     *
+     * The "start" function resets the counts and enables counting.  The
+     * "stop" function disables the counting so that the analysis code
+     * doesn't cause additional allocations.  The "get" function returns
+     * the specified value.
+     *
+     * Counts are kept for the system as a whole and for each thread.
+     * The per-thread counts for threads other than the current thread
+     * are not cleared by the "reset" or "start" calls.
+     */
+    public static void startAllocCounting() {
+        VMDebug.startAllocCounting();
+    }
+    public static void stopAllocCounting() {
+        VMDebug.stopAllocCounting();
+    }
+
+    public static int getGlobalAllocCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
+    }
+    public static int getGlobalAllocSize() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
+    }
+    public static int getGlobalFreedCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
+    }
+    public static int getGlobalFreedSize() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
+    }
+    public static int getGlobalExternalAllocCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
+    }
+    public static int getGlobalExternalAllocSize() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
+    }
+    public static int getGlobalExternalFreedCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
+    }
+    public static int getGlobalExternalFreedSize() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
+    }
+    public static int getGlobalGcInvocationCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
+    }
+    public static int getThreadAllocCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
+    }
+    public static int getThreadAllocSize() {
+        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
+    }
+    public static int getThreadExternalAllocCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
+    }
+    public static int getThreadExternalAllocSize() {
+        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
+    }
+    public static int getThreadGcInvocationCount() {
+        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
+    }
+
+    public static void resetGlobalAllocCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
+    }
+    public static void resetGlobalAllocSize() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
+    }
+    public static void resetGlobalFreedCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
+    }
+    public static void resetGlobalFreedSize() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
+    }
+    public static void resetGlobalExternalAllocCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
+    }
+    public static void resetGlobalExternalAllocSize() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
+    }
+    public static void resetGlobalExternalFreedCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
+    }
+    public static void resetGlobalExternalFreedSize() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
+    }
+    public static void resetGlobalGcInvocationCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
+    }
+    public static void resetThreadAllocCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
+    }
+    public static void resetThreadAllocSize() {
+        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
+    }
+    public static void resetThreadExternalAllocCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
+    }
+    public static void resetThreadExternalAllocSize() {
+        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
+    }
+    public static void resetThreadGcInvocationCount() {
+        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
+    }
+    public static void resetAllCounts() {
+        VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
+    }
+
+    /**
+     * Returns the size of the native heap.
+     * @return The size of the native heap in bytes.
+     */
+    public static native long getNativeHeapSize();
+
+    /**
+     * Returns the amount of allocated memory in the native heap.
+     * @return The allocated size in bytes.
+     */
+    public static native long getNativeHeapAllocatedSize();
+
+    /**
+     * Returns the amount of free memory in the native heap.
+     * @return The freed size in bytes.
+     */
+    public static native long getNativeHeapFreeSize();
+
+    /**
+     * Retrieves information about this processes memory usages. This information is broken down by
+     * how much is in use by dalivk, the native heap, and everything else.
+     */
+    public static native void getMemoryInfo(MemoryInfo memoryInfo);
+
+    /**
+     * Establish an object allocation limit in the current thread.  Useful
+     * for catching regressions in code that is expected to operate
+     * without causing any allocations.
+     *
+     * Pass in the maximum number of allowed allocations.  Use -1 to disable
+     * the limit.  Returns the previous limit.
+     *
+     * The preferred way to use this is:
+     *
+     *  int prevLimit = -1;
+     *  try {
+     *      prevLimit = Debug.setAllocationLimit(0);
+     *      ... do stuff that's not expected to allocate memory ...
+     *  } finally {
+     *      Debug.setAllocationLimit(prevLimit);
+     *  }
+     *
+     * This allows limits to be nested.  The try/finally ensures that the
+     * limit is reset if something fails.
+     *
+     * Exceeding the limit causes a dalvik.system.AllocationLimitError to
+     * be thrown from a memory allocation call.  The limit is reset to -1
+     * when this happens.
+     *
+     * The feature may be disabled in the VM configuration.  If so, this
+     * call has no effect, and always returns -1.
+     */
+    public static int setAllocationLimit(int limit) {
+        return VMDebug.setAllocationLimit(limit);
+    }
+
+    /**
+     * Establish a global object allocation limit.  This is similar to
+     * {@link #setAllocationLimit(int)} but applies to all threads in
+     * the VM.  It will coexist peacefully with per-thread limits.
+     *
+     * [ The value of "limit" is currently restricted to 0 (no allocations
+     *   allowed) or -1 (no global limit).  This may be changed in a future
+     *   release. ]
+     */
+    public static int setGlobalAllocationLimit(int limit) {
+        if (limit != 0 && limit != -1)
+            throw new IllegalArgumentException("limit must be 0 or -1");
+        return VMDebug.setGlobalAllocationLimit(limit);
+    }
+
+    /**
+     * Dump a list of all currently loaded class to the log file.
+     *
+     * @param flags See constants above.
+     */
+    public static void printLoadedClasses(int flags) {
+        VMDebug.printLoadedClasses(flags);
+    }
+
+    /**
+     * Get the number of loaded classes.
+     * @return the number of loaded classes.
+     */
+    public static int getLoadedClassCount() {
+        return VMDebug.getLoadedClassCount();
+    }
+
+    /**
+     * Dump "hprof" data to the specified file.  This will cause a GC.
+     *
+     * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
+     * @throws UnsupportedOperationException if the VM was built without
+     *         HPROF support.
+     * @throws IOException if an error occurs while opening or writing files.
+     */
+    public static void dumpHprofData(String fileName) throws IOException {
+        VMDebug.dumpHprofData(fileName);
+    }
+
+    /**
+     * Returns the number of sent transactions from this process.
+     * @return The number of sent transactions or -1 if it could not read t.
+     */
+    public static native int getBinderSentTransactions();
+
+    /**
+     * Returns the number of received transactions from the binder driver.
+     * @return The number of received transactions or -1 if it could not read the stats.
+     */
+    public static native int getBinderReceivedTransactions();
+
+    /**
+     * Returns the number of active local Binder objects that exist in the
+     * current process.
+     */
+    public static final native int getBinderLocalObjectCount();
+
+    /**
+     * Returns the number of references to remote proxy Binder objects that
+     * exist in the current process.
+     */
+    public static final native int getBinderProxyObjectCount();
+
+    /**
+     * Returns the number of death notification links to Binder objects that
+     * exist in the current process.
+     */
+    public static final native int getBinderDeathObjectCount();
+
+    /**
+     * API for gathering and querying instruction counts.
+     *
+     * Example usage:
+     *   Debug.InstructionCount icount = new Debug.InstructionCount();
+     *   icount.resetAndStart();
+     *    [... do lots of stuff ...]
+     *   if (icount.collect()) {
+     *       System.out.println("Total instructions executed: "
+     *           + icount.globalTotal());
+     *       System.out.println("Method invocations: "
+     *           + icount.globalMethodInvocations());
+     *   }
+     */
+    public static class InstructionCount {
+        private static final int NUM_INSTR = 256;
+
+        private int[] mCounts;
+
+        public InstructionCount() {
+            mCounts = new int[NUM_INSTR];
+        }
+
+        /**
+         * Reset counters and ensure counts are running.  Counts may
+         * have already been running.
+         *
+         * @return true if counting was started
+         */
+        public boolean resetAndStart() {
+            try {
+                VMDebug.startInstructionCounting();
+                VMDebug.resetInstructionCount();
+            } catch (UnsupportedOperationException uoe) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Collect instruction counts.  May or may not stop the
+         * counting process.
+         */
+        public boolean collect() {
+            try {
+                VMDebug.stopInstructionCounting();
+                VMDebug.getInstructionCount(mCounts);
+            } catch (UnsupportedOperationException uoe) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Return the total number of instructions executed globally (i.e. in
+         * all threads).
+         */
+        public int globalTotal() {
+            int count = 0;
+            for (int i = 0; i < NUM_INSTR; i++)
+                count += mCounts[i];
+            return count;
+        }
+
+        /**
+         * Return the total number of method-invocation instructions
+         * executed globally.
+         */
+        public int globalMethodInvocations() {
+            int count = 0;
+
+            //count += mCounts[Opcodes.OP_EXECUTE_INLINE];
+            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL];
+            count += mCounts[Opcodes.OP_INVOKE_SUPER];
+            count += mCounts[Opcodes.OP_INVOKE_DIRECT];
+            count += mCounts[Opcodes.OP_INVOKE_STATIC];
+            count += mCounts[Opcodes.OP_INVOKE_INTERFACE];
+            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE];
+            count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE];
+            count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE];
+            count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE];
+            count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE];
+            //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY];
+            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK];
+            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE];
+            count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK];
+            count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE];
+            return count;
+        }
+    };
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
new file mode 100644
index 0000000..f761e8e
--- /dev/null
+++ b/core/java/android/os/Environment.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import java.io.File;
+
+/**
+ * Provides access to environment variables.
+ */
+public class Environment {
+
+    private static final File ROOT_DIRECTORY
+            = getDirectory("ANDROID_ROOT", "/system");
+
+    /**
+     * Gets the Android root directory.
+     */
+    public static File getRootDirectory() {
+        return ROOT_DIRECTORY;
+    }
+
+    private static final File DATA_DIRECTORY
+            = getDirectory("ANDROID_DATA", "/data");
+
+    private static final File EXTERNAL_STORAGE_DIRECTORY
+            = getDirectory("EXTERNAL_STORAGE", "/sdcard");
+
+    private static final File DOWNLOAD_CACHE_DIRECTORY
+            = getDirectory("DOWNLOAD_CACHE", "/cache");
+
+    /**
+     * Gets the Android data directory.
+     */
+    public static File getDataDirectory() {
+        return DATA_DIRECTORY;
+    }
+
+    /**
+     * Gets the Android external storage directory.
+     */
+    public static File getExternalStorageDirectory() {
+        return EXTERNAL_STORAGE_DIRECTORY;
+    }
+
+    /**
+     * Gets the Android Download/Cache content directory.
+     */
+    public static File getDownloadCacheDirectory() {
+        return DOWNLOAD_CACHE_DIRECTORY;
+    }
+
+    /**
+     * getExternalStorageState() returns MEDIA_REMOVED if the media is not present. 
+     */
+    public static final String MEDIA_REMOVED = "removed";
+     
+    /**
+     * getExternalStorageState() returns MEDIA_UNMOUNTED if the media is present
+     * but not mounted. 
+     */
+    public static final String MEDIA_UNMOUNTED = "unmounted";
+
+    /**
+     * getExternalStorageState() returns MEDIA_CHECKING if the media is present
+     * and being disk-checked
+     */
+    public static final String MEDIA_CHECKING = "checking";
+
+    /**
+     * getExternalStorageState() returns MEDIA_NOFS if the media is present
+     * but is blank or is using an unsupported filesystem
+     */
+    public static final String MEDIA_NOFS = "nofs";
+
+    /**
+     * getExternalStorageState() returns MEDIA_MOUNTED if the media is present
+     * and mounted at its mount point with read/write access. 
+     */
+    public static final String MEDIA_MOUNTED = "mounted";
+
+    /**
+     * getExternalStorageState() returns MEDIA_MOUNTED_READ_ONLY if the media is present
+     * and mounted at its mount point with read only access. 
+     */
+    public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
+
+    /**
+     * getExternalStorageState() returns MEDIA_SHARED if the media is present
+     * not mounted, and shared via USB mass storage. 
+     */
+    public static final String MEDIA_SHARED = "shared";
+
+    /**
+     * getExternalStorageState() returns MEDIA_BAD_REMOVAL if the media was
+     * removed before it was unmounted. 
+     */
+    public static final String MEDIA_BAD_REMOVAL = "bad_removal";
+
+    /**
+     * getExternalStorageState() returns MEDIA_UNMOUNTABLE if the media is present
+     * but cannot be mounted.  Typically this happens if the file system on the
+     * media is corrupted. 
+     */
+    public static final String MEDIA_UNMOUNTABLE = "unmountable";
+
+    /**
+     * Gets the current state of the external storage device.
+     */
+    public static String getExternalStorageState() {
+        return SystemProperties.get("EXTERNAL_STORAGE_STATE", MEDIA_REMOVED);
+    }
+
+    static File getDirectory(String variableName, String defaultPath) {
+        String path = System.getenv(variableName);
+        return path == null ? new File(defaultPath) : new File(path);
+    }
+}
diff --git a/core/java/android/os/Exec.java b/core/java/android/os/Exec.java
new file mode 100644
index 0000000..a50d5fe
--- /dev/null
+++ b/core/java/android/os/Exec.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import java.io.FileDescriptor;
+
+/**
+ * @hide
+ * Tools for executing commands.  Not for public consumption.
+ */
+
+public class Exec
+{
+    /**
+     * @param cmd The command to execute
+     * @param arg0 The first argument to the command, may be null
+     * @param arg1 the second argument to the command, may be null
+     * @return the file descriptor of the started process.
+     * 
+     */
+    public static FileDescriptor createSubprocess(
+        String cmd, String arg0, String arg1) {
+        return createSubprocess(cmd, arg0, arg1, null);
+    }
+    
+    /**
+     * @param cmd The command to execute
+     * @param arg0 The first argument to the command, may be null
+     * @param arg1 the second argument to the command, may be null
+     * @param processId A one-element array to which the process ID of the
+     * started process will be written.
+     * @return the file descriptor of the started process.
+     * 
+     */
+     public static native FileDescriptor createSubprocess(
+        String cmd, String arg0, String arg1, int[] processId);
+    
+     public static native void setPtyWindowSize(FileDescriptor fd,
+       int row, int col, int xpixel, int ypixel);
+    /**
+     * Causes the calling thread to wait for the process associated with the
+     * receiver to finish executing.
+     * 
+     * @return The exit value of the Process being waited on
+     * 
+     */
+    public static native int waitFor(int processId);
+}
+
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
new file mode 100644
index 0000000..d9804ea
--- /dev/null
+++ b/core/java/android/os/FileObserver.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.util.Log;
+
+import com.android.internal.os.RuntimeInit;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public abstract class FileObserver {
+    public static final int ACCESS = 0x00000001; /* File was accessed */
+    public static final int MODIFY = 0x00000002; /* File was modified */
+    public static final int ATTRIB = 0x00000004; /* Metadata changed */
+    public static final int CLOSE_WRITE = 0x00000008; /*  Writtable file was  closed */
+    public static final int CLOSE_NOWRITE = 0x00000010; /* Unwrittable file closed */
+    public static final int OPEN = 0x00000020; /* File was opened */
+    public static final int MOVED_FROM = 0x00000040; /* File was moved from X */
+    public static final int MOVED_TO = 0x00000080; /* File was moved to Y */
+    public static final int CREATE = 0x00000100; /* Subfile was created */
+    public static final int DELETE = 0x00000200; /* Subfile was deleted */
+    public static final int DELETE_SELF = 0x00000400; /* Self was deleted */
+    public static final int MOVE_SELF = 0x00000800; /* Self was moved */
+    public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE 
+            | CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE
+	    | DELETE_SELF | MOVE_SELF;
+    
+    private static final String LOG_TAG = "FileObserver";
+
+    private static class ObserverThread extends Thread {
+	private HashMap<Integer, WeakReference> m_observers = new HashMap<Integer, WeakReference>();
+	private int m_fd;
+
+	public ObserverThread() {
+	    super("FileObserver");
+	    m_fd = init();
+	}
+
+	public void run() {
+	    observe(m_fd);
+	}
+
+	public int startWatching(String path, int mask, FileObserver observer) {
+	    int wfd = startWatching(m_fd, path, mask);
+
+	    Integer i = new Integer(wfd);
+	    if (wfd >= 0) {
+		synchronized (m_observers) {
+		    m_observers.put(i, new WeakReference(observer));
+		}
+	    }
+
+	    return i;
+	}
+
+	public void stopWatching(int descriptor) {
+	    stopWatching(m_fd, descriptor);
+	}
+
+    public void onEvent(int wfd, int mask, String path) {
+        // look up our observer, fixing up the map if necessary...
+        FileObserver observer;
+
+        synchronized (m_observers) {
+            WeakReference weak = m_observers.get(wfd);
+            observer = (FileObserver) weak.get();
+            if (observer == null) {
+                m_observers.remove(wfd);
+            }
+        }
+
+        // ...then call out to the observer without the sync lock held
+        if (observer != null) {
+            try {
+                observer.onEvent(mask, path);
+            } catch (Throwable throwable) {
+                Log.e(LOG_TAG, "Unhandled throwable " + throwable.toString() + 
+                        " (returned by observer " + observer + ")", throwable);
+                RuntimeInit.crash("FileObserver", throwable);
+            }
+        }
+    }
+
+	private native int init();
+	private native void observe(int fd);
+	private native int startWatching(int fd, String path, int mask);
+	private native void stopWatching(int fd, int wfd);
+    }
+
+    private static ObserverThread s_observerThread;
+
+    static {
+	s_observerThread = new ObserverThread();
+	s_observerThread.start();
+    }
+
+    // instance
+    private String m_path;
+    private Integer m_descriptor;
+    private int m_mask;
+
+    public FileObserver(String path) {
+	this(path, ALL_EVENTS);
+    }
+
+    public FileObserver(String path, int mask) {
+	m_path = path;
+	m_mask = mask;
+	m_descriptor = -1;
+    }
+
+    protected void finalize() {
+	stopWatching();
+    }
+
+    public void startWatching() {
+	if (m_descriptor < 0) {
+	    m_descriptor = s_observerThread.startWatching(m_path, m_mask, this);
+	}
+    }
+
+    public void stopWatching() {
+	if (m_descriptor >= 0) {
+	    s_observerThread.stopWatching(m_descriptor);
+	    m_descriptor = -1;
+	}
+    }
+
+    public abstract void onEvent(int event, String path);
+}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
new file mode 100644
index 0000000..51dfb5b
--- /dev/null
+++ b/core/java/android/os/FileUtils.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.regex.Pattern;
+
+
+/**
+ * Tools for managing files.  Not for public consumption.
+ * @hide
+ */
+public class FileUtils
+{
+    public static final int S_IRWXU = 00700;
+    public static final int S_IRUSR = 00400;
+    public static final int S_IWUSR = 00200;
+    public static final int S_IXUSR = 00100;
+
+    public static final int S_IRWXG = 00070;
+    public static final int S_IRGRP = 00040;
+    public static final int S_IWGRP = 00020;
+    public static final int S_IXGRP = 00010;
+
+    public static final int S_IRWXO = 00007;
+    public static final int S_IROTH = 00004;
+    public static final int S_IWOTH = 00002;
+    public static final int S_IXOTH = 00001;
+    
+    
+    /**
+     * File status information. This class maps directly to the POSIX stat structure.
+     * @hide
+     */
+    public static final class FileStatus {
+        public int dev;
+        public int ino;
+        public int mode;
+        public int nlink;
+        public int uid;
+        public int gid;
+        public int rdev;
+        public long size;
+        public int blksize;
+        public long blocks;
+        public long atime;
+        public long mtime;
+        public long ctime;
+    }
+    
+    /**
+     * Get the status for the given path. This is equivalent to the POSIX stat(2) system call. 
+     * @param path The path of the file to be stat'd.
+     * @param status Optional argument to fill in. It will only fill in the status if the file
+     * exists. 
+     * @return true if the file exists and false if it does not exist. If you do not have 
+     * permission to stat the file, then this method will return false.
+     */
+    public static native boolean getFileStatus(String path, FileStatus status);
+
+    /** Regular expression for safe filenames: no spaces or metacharacters */
+    private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
+
+    public static native int setPermissions(String file, int mode, int uid, int gid);
+
+    public static native int getPermissions(String file, int[] outPermissions);
+
+    /** returns the FAT file system volume ID for the volume mounted 
+     * at the given mount point, or -1 for failure
+     * @param mount point for FAT volume
+     * @return volume ID or -1
+     */
+    public static native int getFatVolumeId(String mountPoint);
+        
+    // copy a file from srcFile to destFile, return true if succeed, return
+    // false if fail
+    public static boolean copyFile(File srcFile, File destFile) {
+        boolean result = false;
+        try {
+            InputStream in = new FileInputStream(srcFile);
+            try {
+                result = copyToFile(in, destFile);
+            } finally  {
+                in.close();
+            }
+        } catch (IOException e) {
+            result = false;
+        }
+        return result;
+    }
+    
+    /**
+     * Copy data from a source stream to destFile.
+     * Return true if succeed, return false if failed.
+     */
+    public static boolean copyToFile(InputStream inputStream, File destFile) {
+        try {
+            OutputStream out = new FileOutputStream(destFile);
+            try {
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = inputStream.read(buffer)) >= 0) {
+                    out.write(buffer, 0, bytesRead);
+                }
+            } finally {
+                out.close();
+            }
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Check if a filename is "safe" (no metacharacters or spaces).
+     * @param file  The file to check
+     */
+    public static boolean isFilenameSafe(File file) {
+        // Note, we check whether it matches what's known to be safe,
+        // rather than what's known to be unsafe.  Non-ASCII, control
+        // characters, etc. are all unsafe by default.
+        return SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches();
+    }
+
+    /**
+     * Read a text file into a String, optionally limiting the length.
+     * @param file to read (will not seek, so things like /proc files are OK)
+     * @param max length (positive for head, negative of tail, 0 for no limit)
+     * @param ellipsis to add of the file was truncated (can be null)
+     * @return the contents of the file, possibly truncated
+     * @throws IOException if something goes wrong reading the file
+     */
+    public static String readTextFile(File file, int max, String ellipsis) throws IOException {
+        InputStream input = new FileInputStream(file);
+        try {
+            if (max > 0) {  // "head" mode: read the first N bytes
+                byte[] data = new byte[max + 1];
+                int length = input.read(data);
+                if (length <= 0) return "";
+                if (length <= max) return new String(data, 0, length);
+                if (ellipsis == null) return new String(data, 0, max);
+                return new String(data, 0, max) + ellipsis;
+            } else if (max < 0) {  // "tail" mode: read it all, keep the last N
+                int len;
+                boolean rolled = false;
+                byte[] last = null, data = null;
+                do {
+                    if (last != null) rolled = true;
+                    byte[] tmp = last; last = data; data = tmp;
+                    if (data == null) data = new byte[-max];
+                    len = input.read(data);
+                } while (len == data.length);
+
+                if (last == null && len <= 0) return "";
+                if (last == null) return new String(data, 0, len);
+                if (len > 0) {
+                    rolled = true;
+                    System.arraycopy(last, len, last, 0, last.length - len);
+                    System.arraycopy(data, 0, last, last.length - len, len);
+                }
+                if (ellipsis == null || !rolled) return new String(last);
+                return ellipsis + new String(last);
+            } else {  // "cat" mode: read it all
+                ByteArrayOutputStream contents = new ByteArrayOutputStream();
+                int len;
+                byte[] data = new byte[1024];
+                do {
+                    len = input.read(data);
+                    if (len > 0) contents.write(data, 0, len);
+                } while (len == data.length);
+                return contents.toString();
+            }
+        } finally {
+            input.close();
+        }
+    }
+}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
new file mode 100644
index 0000000..2a32e54
--- /dev/null
+++ b/core/java/android/os/Handler.java
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.util.Log;
+import android.util.Printer;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * A Handler allows you to send and process {@link Message} and Runnable
+ * objects associated with a thread's {@link MessageQueue}.  Each Handler
+ * instance is associated with a single thread and that thread's message
+ * queue.  When you create a new Handler, it is bound to the thread /
+ * message queue of the thread that is creating it -- from that point on,
+ * it will deliver messages and runnables to that message queue and execute
+ * them as they come out of the message queue.
+ * 
+ * <p>There are two main uses for a Handler: (1) to schedule messages and
+ * runnables to be executed as some point in the future; and (2) to enqueue
+ * an action to be performed on a different thread than your own.
+ * 
+ * <p>Scheduling messages is accomplished with the
+ * {@link #post}, {@link #postAtTime(Runnable, long)},
+ * {@link #postDelayed}, {@link #sendEmptyMessage},
+ * {@link #sendMessage}, {@link #sendMessageAtTime}, and
+ * {@link #sendMessageDelayed} methods.  The <em>post</em> versions allow
+ * you to enqueue Runnable objects to be called by the message queue when
+ * they are received; the <em>sendMessage</em> versions allow you to enqueue
+ * a {@link Message} object containing a bundle of data that will be
+ * processed by the Handler's {@link #handleMessage} method (requiring that
+ * you implement a subclass of Handler).
+ * 
+ * <p>When posting or sending to a Handler, you can either
+ * allow the item to be processed as soon as the message queue is ready
+ * to do so, or specify a delay before it gets processed or absolute time for
+ * it to be processed.  The latter two allow you to implement timeouts,
+ * ticks, and other timing-based behavior.
+ * 
+ * <p>When a
+ * process is created for your application, its main thread is dedicated to
+ * running a message queue that takes care of managing the top-level
+ * application objects (activities, broadcast receivers, etc) and any windows
+ * they create.  You can create your own threads, and communicate back with
+ * the main application thread through a Handler.  This is done by calling
+ * the same <em>post</em> or <em>sendMessage</em> methods as before, but from
+ * your new thread.  The given Runnable or Message will than be scheduled
+ * in the Handler's message queue and processed when appropriate.
+ */
+public class Handler {
+    /*
+     * Set this flag to true to detect anonymous, local or member classes
+     * that extend this Handler class and that are not static. These kind
+     * of classes can potentially create leaks.
+     */
+    private static final boolean FIND_POTENTIAL_LEAKS = false;
+    private static final String TAG = "Handler";
+
+    /**
+     * Callback interface you can use when instantiating a Handler to avoid
+     * having to implement your own subclass of Handler.
+     */
+    public interface Callback {
+        public boolean handleMessage(Message msg);
+    }
+    
+    /**
+     * Subclasses must implement this to receive messages.
+     */
+    public void handleMessage(Message msg) {
+    }
+    
+    /**
+     * Handle system messages here.
+     */
+    public void dispatchMessage(Message msg) {
+        if (msg.callback != null) {
+            handleCallback(msg);
+        } else {
+            if (mCallback != null) {
+                if (mCallback.handleMessage(msg)) {
+                    return;
+                }
+            }
+            handleMessage(msg);
+        }
+    }
+
+    /**
+     * Default constructor associates this handler with the queue for the
+     * current thread.
+     *
+     * If there isn't one, this handler won't be able to receive messages.
+     */
+    public Handler() {
+        if (FIND_POTENTIAL_LEAKS) {
+            final Class<? extends Handler> klass = getClass();
+            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
+                    (klass.getModifiers() & Modifier.STATIC) == 0) {
+                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
+                    klass.getCanonicalName());
+            }
+        }
+
+        mLooper = Looper.myLooper();
+        if (mLooper == null) {
+            throw new RuntimeException(
+                "Can't create handler inside thread that has not called Looper.prepare()");
+        }
+        mQueue = mLooper.mQueue;
+        mCallback = null;
+    }
+
+    /**
+     * Constructor associates this handler with the queue for the
+     * current thread and takes a callback interface in which you can handle
+     * messages.
+     */
+    public Handler(Callback callback) {
+        if (FIND_POTENTIAL_LEAKS) {
+            final Class<? extends Handler> klass = getClass();
+            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
+                    (klass.getModifiers() & Modifier.STATIC) == 0) {
+                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
+                    klass.getCanonicalName());
+            }
+        }
+
+        mLooper = Looper.myLooper();
+        if (mLooper == null) {
+            throw new RuntimeException(
+                "Can't create handler inside thread that has not called Looper.prepare()");
+        }
+        mQueue = mLooper.mQueue;
+        mCallback = callback;
+    }
+
+    /**
+     * Use the provided queue instead of the default one.
+     */
+    public Handler(Looper looper) {
+        mLooper = looper;
+        mQueue = looper.mQueue;
+        mCallback = null;
+    }
+
+    /**
+     * Use the provided queue instead of the default one and take a callback
+     * interface in which to handle messages.
+     */
+    public Handler(Looper looper, Callback callback) {
+        mLooper = looper;
+        mQueue = looper.mQueue;
+        mCallback = callback;
+    }
+
+    /**
+     * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
+     * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
+     *  If you don't want that facility, just call Message.obtain() instead.
+     */
+    public final Message obtainMessage()
+    {
+        return Message.obtain(this);
+    }
+
+    /**
+     * Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
+     * 
+     * @param what Value to assign to the returned Message.what field.
+     * @return A Message from the global message pool.
+     */
+    public final Message obtainMessage(int what)
+    {
+        return Message.obtain(this, what);
+    }
+    
+    /**
+     * 
+     * Same as {@link #obtainMessage()}, except that it also sets the what and obj members 
+     * of the returned Message.
+     * 
+     * @param what Value to assign to the returned Message.what field.
+     * @param obj Value to assign to the returned Message.obj field.
+     * @return A Message from the global message pool.
+     */
+    public final Message obtainMessage(int what, Object obj)
+    {
+        return Message.obtain(this, what, obj);
+    }
+
+    /**
+     * 
+     * Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned
+     * Message.
+     * @param what Value to assign to the returned Message.what field.
+     * @param arg1 Value to assign to the returned Message.arg1 field.
+     * @param arg2 Value to assign to the returned Message.arg2 field.
+     * @return A Message from the global message pool.
+     */
+    public final Message obtainMessage(int what, int arg1, int arg2)
+    {
+        return Message.obtain(this, what, arg1, arg2);
+    }
+    
+    /**
+     * 
+     * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the 
+     * returned Message.
+     * @param what Value to assign to the returned Message.what field.
+     * @param arg1 Value to assign to the returned Message.arg1 field.
+     * @param arg2 Value to assign to the returned Message.arg2 field.
+     * @param obj Value to assign to the returned Message.obj field.
+     * @return A Message from the global message pool.
+     */
+    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
+    {
+        return Message.obtain(this, what, arg1, arg2, obj);
+    }
+
+    /**
+     * Causes the Runnable r to be added to the message queue.
+     * The runnable will be run on the thread to which this handler is 
+     * attached. 
+     *  
+     * @param r The Runnable that will be executed.
+     * 
+     * @return Returns true if the Runnable was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.
+     */
+    public final boolean post(Runnable r)
+    {
+       return  sendMessageDelayed(getPostMessage(r), 0);
+    }
+    
+    /**
+     * Causes the Runnable r to be added to the message queue, to be run
+     * at a specific time given by <var>uptimeMillis</var>.
+     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
+     * The runnable will be run on the thread to which this handler is attached.
+     *
+     * @param r The Runnable that will be executed.
+     * @param uptimeMillis The absolute time at which the callback should run,
+     *         using the {@link android.os.SystemClock#uptimeMillis} time-base.
+     *  
+     * @return Returns true if the Runnable was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.  Note that a
+     *         result of true does not mean the Runnable will be processed -- if
+     *         the looper is quit before the delivery time of the message
+     *         occurs then the message will be dropped.
+     */
+    public final boolean postAtTime(Runnable r, long uptimeMillis)
+    {
+        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
+    }
+    
+    /**
+     * Causes the Runnable r to be added to the message queue, to be run
+     * at a specific time given by <var>uptimeMillis</var>.
+     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
+     * The runnable will be run on the thread to which this handler is attached.
+     *
+     * @param r The Runnable that will be executed.
+     * @param uptimeMillis The absolute time at which the callback should run,
+     *         using the {@link android.os.SystemClock#uptimeMillis} time-base.
+     * 
+     * @return Returns true if the Runnable was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.  Note that a
+     *         result of true does not mean the Runnable will be processed -- if
+     *         the looper is quit before the delivery time of the message
+     *         occurs then the message will be dropped.
+     *         
+     * @see android.os.SystemClock#uptimeMillis
+     */
+    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
+    {
+        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
+    }
+    
+    /**
+     * Causes the Runnable r to be added to the message queue, to be run
+     * after the specified amount of time elapses.
+     * The runnable will be run on the thread to which this handler
+     * is attached.
+     *  
+     * @param r The Runnable that will be executed.
+     * @param delayMillis The delay (in milliseconds) until the Runnable
+     *        will be executed.
+     *        
+     * @return Returns true if the Runnable was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.  Note that a
+     *         result of true does not mean the Runnable will be processed --
+     *         if the looper is quit before the delivery time of the message
+     *         occurs then the message will be dropped.
+     */
+    public final boolean postDelayed(Runnable r, long delayMillis)
+    {
+        return sendMessageDelayed(getPostMessage(r), delayMillis);
+    }
+    
+    /**
+     * Posts a message to an object that implements Runnable.
+     * Causes the Runnable r to executed on the next iteration through the
+     * message queue. The runnable will be run on the thread to which this
+     * handler is attached.
+     * <b>This method is only for use in very special circumstances -- it
+     * can easily starve the message queue, cause ordering problems, or have
+     * other unexpected side-effects.</b>
+     *  
+     * @param r The Runnable that will be executed.
+     * 
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.
+     */
+    public final boolean postAtFrontOfQueue(Runnable r)
+    {
+        return sendMessageAtFrontOfQueue(getPostMessage(r));
+    }
+
+    /**
+     * Remove any pending posts of Runnable r that are in the message queue.
+     */
+    public final void removeCallbacks(Runnable r)
+    {
+        mQueue.removeMessages(this, r, null);
+    }
+
+    /**
+     * Remove any pending posts of Runnable <var>r</var> with Object
+     * <var>token</var> that are in the message queue.
+     */
+    public final void removeCallbacks(Runnable r, Object token)
+    {
+        mQueue.removeMessages(this, r, token);
+    }
+
+    /**
+     * Pushes a message onto the end of the message queue after all pending messages
+     * before the current time. It will be received in {@link #handleMessage},
+     * in the thread attached to this handler.
+     *  
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.
+     */
+    public final boolean sendMessage(Message msg)
+    {
+        return sendMessageDelayed(msg, 0);
+    }
+
+    /**
+     * Sends a Message containing only the what value.
+     *  
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.
+     */
+    public final boolean sendEmptyMessage(int what)
+    {
+        return sendEmptyMessageDelayed(what, 0);
+    }
+
+    /**
+     * Sends a Message containing only the what value, to be delivered
+     * after the specified amount of time elapses.
+     * @see #sendMessageDelayed(android.os.Message, long) 
+     * 
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.
+     */
+    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
+        Message msg = Message.obtain();
+        msg.what = what;
+        return sendMessageDelayed(msg, delayMillis);
+    }
+
+    /**
+     * Sends a Message containing only the what value, to be delivered 
+     * at a specific time.
+     * @see #sendMessageAtTime(android.os.Message, long)
+     *  
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.
+     */
+
+    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
+        Message msg = Message.obtain();
+        msg.what = what;
+        return sendMessageAtTime(msg, uptimeMillis);
+    }
+
+    /**
+     * Enqueue a message into the message queue after all pending messages
+     * before (current time + delayMillis). You will receive it in
+     * {@link #handleMessage}, in the thread attached to this handler.
+     *  
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.  Note that a
+     *         result of true does not mean the message will be processed -- if
+     *         the looper is quit before the delivery time of the message
+     *         occurs then the message will be dropped.
+     */
+    public final boolean sendMessageDelayed(Message msg, long delayMillis)
+    {
+        if (delayMillis < 0) {
+            delayMillis = 0;
+        }
+        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
+    }
+
+    /**
+     * Enqueue a message into the message queue after all pending messages
+     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
+     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
+     * You will receive it in {@link #handleMessage}, in the thread attached
+     * to this handler.
+     * 
+     * @param uptimeMillis The absolute time at which the message should be
+     *         delivered, using the
+     *         {@link android.os.SystemClock#uptimeMillis} time-base.
+     *         
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.  Note that a
+     *         result of true does not mean the message will be processed -- if
+     *         the looper is quit before the delivery time of the message
+     *         occurs then the message will be dropped.
+     */
+    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
+    {
+        boolean sent = false;
+        MessageQueue queue = mQueue;
+        if (queue != null) {
+            msg.target = this;
+            sent = queue.enqueueMessage(msg, uptimeMillis);
+        }
+        else {
+            RuntimeException e = new RuntimeException(
+                this + " sendMessageAtTime() called with no mQueue");
+            Log.w("Looper", e.getMessage(), e);
+        }
+        return sent;
+    }
+
+    /**
+     * Enqueue a message at the front of the message queue, to be processed on
+     * the next iteration of the message loop.  You will receive it in
+     * {@link #handleMessage}, in the thread attached to this handler.
+     * <b>This method is only for use in very special circumstances -- it
+     * can easily starve the message queue, cause ordering problems, or have
+     * other unexpected side-effects.</b>
+     *  
+     * @return Returns true if the message was successfully placed in to the 
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.
+     */
+    public final boolean sendMessageAtFrontOfQueue(Message msg)
+    {
+        boolean sent = false;
+        MessageQueue queue = mQueue;
+        if (queue != null) {
+            msg.target = this;
+            sent = queue.enqueueMessage(msg, 0);
+        }
+        else {
+            RuntimeException e = new RuntimeException(
+                this + " sendMessageAtTime() called with no mQueue");
+            Log.w("Looper", e.getMessage(), e);
+        }
+        return sent;
+    }
+
+    /**
+     * Remove any pending posts of messages with code 'what' that are in the
+     * message queue.
+     */
+    public final void removeMessages(int what) {
+        mQueue.removeMessages(this, what, null, true);
+    }
+
+    /**
+     * Remove any pending posts of messages with code 'what' and whose obj is
+     * 'object' that are in the message queue.
+     */
+    public final void removeMessages(int what, Object object) {
+        mQueue.removeMessages(this, what, object, true);
+    }
+
+    /**
+     * Remove any pending posts of callbacks and sent messages whose
+     * <var>obj</var> is <var>token</var>.
+     */
+    public final void removeCallbacksAndMessages(Object token) {
+        mQueue.removeCallbacksAndMessages(this, token);
+    }
+
+    /**
+     * Check if there are any pending posts of messages with code 'what' in
+     * the message queue.
+     */
+    public final boolean hasMessages(int what) {
+        return mQueue.removeMessages(this, what, null, false);
+    }
+
+    /**
+     * Check if there are any pending posts of messages with code 'what' and
+     * whose obj is 'object' in the message queue.
+     */
+    public final boolean hasMessages(int what, Object object) {
+        return mQueue.removeMessages(this, what, object, false);
+    }
+
+    // if we can get rid of this method, the handler need not remember its loop
+    // we could instead export a getMessageQueue() method... 
+    public final Looper getLooper() {
+        return mLooper;
+    }
+
+    public final void dump(Printer pw, String prefix) {
+        pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
+        if (mLooper == null) {
+            pw.println(prefix + "looper uninitialized");
+        } else {
+            mLooper.dump(pw, prefix + "  ");
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Handler{"
+        + Integer.toHexString(System.identityHashCode(this))
+        + "}";
+    }
+
+    final IMessenger getIMessenger() {
+        synchronized (mQueue) {
+            if (mMessenger != null) {
+                return mMessenger;
+            }
+            mMessenger = new MessengerImpl();
+            return mMessenger;
+        }
+    }
+    
+    private final class MessengerImpl extends IMessenger.Stub {
+        public void send(Message msg) {
+            Handler.this.sendMessage(msg);
+        }
+    }
+    
+    private final Message getPostMessage(Runnable r) {
+        Message m = Message.obtain();
+        m.callback = r;
+        return m;
+    }
+
+    private final Message getPostMessage(Runnable r, Object token) {
+        Message m = Message.obtain();
+        m.obj = token;
+        m.callback = r;
+        return m;
+    }
+
+    private final void handleCallback(Message message) {
+        message.callback.run();
+    }
+
+    final MessageQueue mQueue;
+    final Looper mLooper;
+    final Callback mCallback;
+    IMessenger mMessenger;
+}
diff --git a/core/java/android/os/HandlerState.java b/core/java/android/os/HandlerState.java
new file mode 100644
index 0000000..0708f7d
--- /dev/null
+++ b/core/java/android/os/HandlerState.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * {@hide}
+ */
+public abstract class HandlerState {
+    public HandlerState() {
+    }
+
+    public void enter(Message message) {
+    }
+
+    public abstract void processMessage(Message message);
+
+    public void exit(Message message) {
+    }
+}
diff --git a/core/java/android/os/HandlerStateMachine.java b/core/java/android/os/HandlerStateMachine.java
new file mode 100644
index 0000000..d004a25
--- /dev/null
+++ b/core/java/android/os/HandlerStateMachine.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.util.Log;
+import android.util.LogPrinter;
+
+/**
+ * {@hide}
+ *
+ * Implement a state machine where each state is an object,
+ * HandlerState. Each HandlerState must implement processMessage
+ * and optionally enter/exit. When a state machine is created
+ * the initial state must be set. When messages are sent to
+ * a state machine the current state's processMessage method is
+ * invoked. If this is the first message for this state the
+ * enter method is called prior to processMessage and when
+ * transtionTo is invoked the state's exit method will be
+ * called after returning from processMessage.
+ *
+ * If a message should be handled in a different state the
+ * processMessage method may call deferMessage. This causes
+ * the message to be saved on a list until transitioning
+ * to a new state, at which time all of the deferred messages
+ * will be put on the front of the state machines queue and
+ * processed by the new current state's processMessage
+ * method.
+ *
+ * Below is an example state machine with two state's, S1 and S2.
+ * The initial state is S1 which defers all messages and only
+ * transition to S2 when message.what == TEST_WHAT_2. State S2
+ * will process each messages until it receives TEST_WHAT_2
+ * where it will transition back to S1:
+<code>
+     class StateMachine1 extends HandlerStateMachine {
+        private static final int TEST_WHAT_1 = 1;
+        private static final int TEST_WHAT_2 = 2;
+
+        StateMachine1(String name) {
+            super(name);
+            setInitialState(mS1);
+        }
+
+        class S1 extends HandlerState {
+            @Override public void enter(Message message) {
+            }
+
+            @Override public void processMessage(Message message) {
+                deferMessage(message);
+                if (message.what == TEST_WHAT_2) {
+                    transitionTo(mS2);
+                }
+            }
+
+            @Override public void exit(Message message) {
+            }
+        }
+
+        class S2 extends HandlerState {
+            @Override public void processMessage(Message message) {
+                // Do some processing
+                if (message.what == TEST_WHAT_2) {
+                    transtionTo(mS1);
+                }
+            }
+        }
+
+        private S1 mS1 = new S1();
+        private S2 mS2 = new S2();
+    }
+</code>
+ */
+public class HandlerStateMachine {
+
+    private boolean mDbg = false;
+    private static final String TAG = "HandlerStateMachine";
+    private String mName;
+    private SmHandler mHandler;
+    private HandlerThread mHandlerThread;
+
+    /**
+     * Handle messages sent to the state machine by calling
+     * the current state's processMessage. It also handles
+     * the enter/exit calls and placing any deferred messages
+     * back onto the queue when transitioning to a new state.
+     */
+    class SmHandler extends Handler {
+
+        SmHandler(Looper looper) {
+          super(looper);
+        }
+
+        /**
+         * This will dispatch the message to the
+         * current state's processMessage.
+         */
+        @Override
+        final public void handleMessage(Message msg) {
+            if (mDbg) Log.d(TAG, "SmHandler.handleMessage E");
+            if (mDestState != null) {
+                if (mDbg) Log.d(TAG, "SmHandler.handleMessage; new destation call enter");
+                mCurrentState = mDestState;
+                mDestState = null;
+                mCurrentState.enter(msg);
+            }
+            if (mCurrentState != null) {
+                if (mDbg) Log.d(TAG, "SmHandler.handleMessage; call processMessage");
+                mCurrentState.processMessage(msg);
+            } else {
+                /* Strange no state to execute */
+                Log.e(TAG, "handleMessage: no current state, did you call setInitialState");
+            }
+
+            if (mDestState != null) {
+                if (mDbg) Log.d(TAG, "SmHandler.handleMessage; new destination call exit");
+                mCurrentState.exit(msg);
+
+                /**
+                 * Place the messages from the deferred queue:t
+                 * on to the Handler's message queue in the
+                 * same order that they originally arrived.
+                 *
+                 * We set cur.when = 0 to circumvent the check
+                 * that this message has already been sent.
+                 */
+                while (mDeferredMessages != null) {
+                    Message cur = mDeferredMessages;
+                    mDeferredMessages = mDeferredMessages.next;
+                    cur.when = 0;
+                    if (mDbg) Log.d(TAG, "SmHandler.handleMessage; queue deferred message what="
+                                                + cur.what + " target=" + cur.target);
+                    sendMessageAtFrontOfQueue(cur);
+                }
+                if (mDbg) Log.d(TAG, "SmHandler.handleMessage X");
+            }
+        }
+
+        public HandlerState mCurrentState;
+        public HandlerState mDestState;
+        public Message mDeferredMessages;
+    }
+
+    /**
+     * Create an active StateMachine, one that has a
+     * dedicated thread/looper/queue.
+     */
+    public HandlerStateMachine(String name) {
+        mName = name;
+        mHandlerThread =  new HandlerThread(name);
+        mHandlerThread.start();
+        mHandler = new SmHandler(mHandlerThread.getLooper());
+    }
+
+    /**
+     * Get a message and set Message.target = this.
+     */
+    public final Message obtainMessage()
+    {
+        Message msg = Message.obtain(mHandler);
+        if (mDbg) Log.d(TAG, "StateMachine.obtainMessage() EX target=" + msg.target);
+        return msg;
+    }
+
+    /**
+     * Get a message and set Message.target = this and
+     * Message.what = what.
+     */
+    public final Message obtainMessage(int what) {
+        Message msg = Message.obtain(mHandler, what);
+        if (mDbg) {
+            Log.d(TAG, "StateMachine.obtainMessage(what) EX what=" + msg.what +
+                       " target=" + msg.target);
+        }
+        return msg;
+    }
+
+    /**
+     * Enqueue a message to this state machine.
+     */
+    public final void sendMessage(Message msg) {
+        if (mDbg) Log.d(TAG, "StateMachine.sendMessage EX msg.what=" + msg.what);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Enqueue a message to this state machine after a delay.
+     */
+    public final void sendMessageDelayed(Message msg, long delayMillis) {
+        if (mDbg) {
+            Log.d(TAG, "StateMachine.sendMessageDelayed EX msg.what="
+                            + msg.what + " delay=" + delayMillis);
+        }
+        mHandler.sendMessageDelayed(msg, delayMillis);
+    }
+
+    /**
+     * Set the initial state. This must be invoked before
+     * and messages are sent to the state machine.
+     */
+    public void setInitialState(HandlerState initialState) {
+        if (mDbg) {
+            Log.d(TAG, "StateMachine.setInitialState EX initialState"
+                            + initialState.getClass().getName());
+        }
+        mHandler.mDestState = initialState;
+    }
+
+    /**
+     * transition to destination state. Upon returning
+     * from processMessage the current state's exit will
+     * be executed and upon the next message arriving
+     * destState.enter will be invoked.
+     */
+    final public void transitionTo(HandlerState destState) {
+        if (mDbg) {
+            Log.d(TAG, "StateMachine.transitionTo EX destState"
+                            + destState.getClass().getName());
+        }
+        mHandler.mDestState = destState;
+    }
+
+    /**
+     * Defer this message until next state transition.
+     * Upon transitioning all deferred messages will be
+     * placed on the queue and reprocessed in the original
+     * order. (i.e. The next state the oldest messages will
+     * be processed first)
+     */
+    final public void deferMessage(Message msg) {
+        if (mDbg) {
+            Log.d(TAG, "StateMachine.deferMessage EX mDeferredMessages="
+                            + mHandler.mDeferredMessages);
+        }
+
+        /* Copy the "msg" to "newMsg" as "msg" will be recycled */
+        Message newMsg = obtainMessage();
+        newMsg.copyFrom(msg);
+
+        /* Place on front of queue */
+        newMsg.next = mHandler.mDeferredMessages;
+        mHandler.mDeferredMessages = newMsg;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * @return Handler
+     */
+    public Handler getHandler() {
+        return mHandler;
+    }
+
+    /**
+     * @return if debugging is enabled
+     */
+    public boolean isDbg() {
+        return mDbg;
+    }
+
+    /**
+     * Set debug enable/disabled.
+     */
+    public void setDbg(boolean dbg) {
+        mDbg = dbg;
+        if (mDbg) {
+            mHandlerThread.getLooper().setMessageLogging(new LogPrinter(Log.VERBOSE, TAG));
+        } else {
+            mHandlerThread.getLooper().setMessageLogging(null);
+        }
+   }
+}
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
new file mode 100644
index 0000000..0ce86db
--- /dev/null
+++ b/core/java/android/os/HandlerThread.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * Handy class for starting a new thread that has a looper. The looper can then be 
+ * used to create handler classes. Note that start() must still be called.
+ */
+public class HandlerThread extends Thread {
+    private int mPriority;
+    private int mTid = -1;
+    private Looper mLooper;
+
+    public HandlerThread(String name) {
+        super(name);
+        mPriority = Process.THREAD_PRIORITY_DEFAULT;
+    }
+    
+    /**
+     * Constructs a HandlerThread.
+     * @param name
+     * @param priority The priority to run the thread at. The value supplied must be from 
+     * {@link android.os.Process} and not from java.lang.Thread.
+     */
+    public HandlerThread(String name, int priority) {
+        super(name);
+        mPriority = priority;
+    }
+    
+    /**
+     * Call back method that can be explicitly over ridden if needed to execute some
+     * setup before Looper loops.
+     */
+    protected void onLooperPrepared() {
+    }
+
+    public void run() {
+        mTid = Process.myTid();
+        Looper.prepare();
+        synchronized (this) {
+            mLooper = Looper.myLooper();
+            Process.setThreadPriority(mPriority);
+            notifyAll();
+        }
+        onLooperPrepared();
+        Looper.loop();
+        mTid = -1;
+    }
+    
+    /**
+     * This method returns the Looper associated with this thread. If this thread not been started
+     * or for any reason is isAlive() returns false, this method will return null. If this thread 
+     * has been started, this method will blocked until the looper has been initialized.  
+     * @return The looper.
+     */
+    public Looper getLooper() {
+        if (!isAlive()) {
+            return null;
+        }
+        
+        // If the thread has been started, wait until the looper has been created.
+        synchronized (this) {
+            while (isAlive() && mLooper == null) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        return mLooper;
+    }
+    
+    /**
+     * Returns the identifier of this thread. See Process.myTid().
+     */
+    public int getThreadId() {
+        return mTid;
+    }
+}
diff --git a/core/java/android/os/Hardware.java b/core/java/android/os/Hardware.java
new file mode 100644
index 0000000..3b6c9d7
--- /dev/null
+++ b/core/java/android/os/Hardware.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * {@hide}
+ */
+public class Hardware 
+{
+    /**
+     * Control the LED.
+     */
+    public static native int setLedState(int colorARGB, int onMS, int offMS);
+    
+    /**
+     * Control the Flashlight
+     */
+    public static native boolean getFlashlightEnabled();
+    public static native void setFlashlightEnabled(boolean on);
+    public static native void enableCameraFlash(int milliseconds);
+
+    /**
+     * Control the backlights
+     */
+    public static native void setScreenBacklight(int brightness);
+    public static native void setKeyboardBacklight(boolean on);
+    public static native void setButtonBacklight(boolean on);
+}
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
new file mode 100644
index 0000000..5c40c9a0
--- /dev/null
+++ b/core/java/android/os/IBinder.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Base interface for a remotable object, the core part of a lightweight
+ * remote procedure call mechanism designed for high performance when
+ * performing in-process and cross-process calls.  This
+ * interface describes the abstract protocol for interacting with a
+ * remotable object.  Do not implement this interface directly, instead
+ * extend from {@link Binder}.
+ * 
+ * <p>The key IBinder API is {@link #transact transact()} matched by
+ * {@link Binder#onTransact Binder.onTransact()}.  These
+ * methods allow you to send a call to an IBinder object and receive a
+ * call coming in to a Binder object, respectively.  This transaction API
+ * is synchronous, such that a call to {@link #transact transact()} does not
+ * return until the target has returned from
+ * {@link Binder#onTransact Binder.onTransact()}; this is the
+ * expected behavior when calling an object that exists in the local
+ * process, and the underlying inter-process communication (IPC) mechanism
+ * ensures that these same semantics apply when going across processes.
+ * 
+ * <p>The data sent through transact() is a {@link Parcel}, a generic buffer
+ * of data that also maintains some meta-data about its contents.  The meta
+ * data is used to manage IBinder object references in the buffer, so that those
+ * references can be maintained as the buffer moves across processes.  This
+ * mechanism ensures that when an IBinder is written into a Parcel and sent to
+ * another process, if that other process sends a reference to that same IBinder
+ * back to the original process, then the original process will receive the
+ * same IBinder object back.  These semantics allow IBinder/Binder objects to
+ * be used as a unique identity (to serve as a token or for other purposes)
+ * that can be managed across processes.
+ * 
+ * <p>The system maintains a pool of transaction threads in each process that
+ * it runs in.  These threads are used to dispatch all
+ * IPCs coming in from other processes.  For example, when an IPC is made from
+ * process A to process B, the calling thread in A blocks in transact() as
+ * it sends the transaction to process B.  The next available pool thread in
+ * B receives the incoming transaction, calls Binder.onTransact() on the target
+ * object, and replies with the result Parcel.  Upon receiving its result, the
+ * thread in process A returns to allow its execution to continue.  In effect,
+ * other processes appear to use as additional threads that you did not create
+ * executing in your own process.
+ * 
+ * <p>The Binder system also supports recursion across processes.  For example
+ * if process A performs a transaction to process B, and process B while
+ * handling that transaction calls transact() on an IBinder that is implemented
+ * in A, then the thread in A that is currently waiting for the original
+ * transaction to finish will take care of calling Binder.onTransact() on the
+ * object being called by B.  This ensures that the recursion semantics when
+ * calling remote binder object are the same as when calling local objects.
+ * 
+ * <p>When working with remote objects, you often want to find out when they
+ * are no longer valid.  There are three ways this can be determined:
+ * <ul>
+ * <li> The {@link #transact transact()} method will throw a
+ * {@link RemoteException} exception if you try to call it on an IBinder
+ * whose process no longer exists.
+ * <li> The {@link #pingBinder()} method can be called, and will return false
+ * if the remote process no longer exists.
+ * <li> The {@link #linkToDeath linkToDeath()} method can be used to register
+ * a {@link DeathRecipient} with the IBinder, which will be called when its
+ * containing process goes away.
+ * </ul>
+ * 
+ * @see Binder
+ */
+public interface IBinder {
+    /**
+     * The first transaction code available for user commands.
+     */
+    int FIRST_CALL_TRANSACTION  = 0x00000001;
+    /**
+     * The last transaction code available for user commands.
+     */
+    int LAST_CALL_TRANSACTION   = 0x00ffffff;
+    
+    /**
+     * IBinder protocol transaction code: pingBinder().
+     */
+    int PING_TRANSACTION        = ('_'<<24)|('P'<<16)|('N'<<8)|'G';
+    
+    /**
+     * IBinder protocol transaction code: dump internal state.
+     */
+    int DUMP_TRANSACTION        = ('_'<<24)|('D'<<16)|('M'<<8)|'P';
+    
+    /**
+     * IBinder protocol transaction code: interrogate the recipient side
+     * of the transaction for its canonical interface descriptor.
+     */
+    int INTERFACE_TRANSACTION   = ('_'<<24)|('N'<<16)|('T'<<8)|'F';
+
+    /**
+     * Flag to {@link #transact}: this is a one-way call, meaning that the
+     * caller returns immediately, without waiting for a result from the
+     * callee.
+     */
+    int FLAG_ONEWAY             = 0x00000001;
+    
+    /**
+     * Get the canonical name of the interface supported by this binder.
+     */
+    public String getInterfaceDescriptor() throws RemoteException;
+
+    /**
+     * Check to see if the object still exists.
+     * 
+     * @return Returns false if the
+     * hosting process is gone, otherwise the result (always by default
+     * true) returned by the pingBinder() implementation on the other
+     * side.
+     */
+    public boolean pingBinder();
+
+    /**
+     * Check to see if the process that the binder is in is still alive.
+     *
+     * @return false if the process is not alive.  Note that if it returns
+     * true, the process may have died while the call is returning.
+     */
+    public boolean isBinderAlive();
+    
+    /**
+     * Attempt to retrieve a local implementation of an interface
+     * for this Binder object.  If null is returned, you will need
+     * to instantiate a proxy class to marshall calls through
+     * the transact() method.
+     */
+    public IInterface queryLocalInterface(String descriptor);
+    
+    /**
+     * Print the object's state into the given stream.
+     * 
+     * @param fd The raw file descriptor that the dump is being sent to.
+     * @param args additional arguments to the dump request.
+     */
+    public void dump(FileDescriptor fd, String[] args) throws RemoteException;
+    
+    /**
+     * Perform a generic operation with the object.
+     * 
+     * @param code The action to perform.  This should
+     * be a number between {@link #FIRST_CALL_TRANSACTION} and
+     * {@link #LAST_CALL_TRANSACTION}.
+     * @param data Marshalled data to send to the target.  Most not be null.
+     * If you are not sending any data, you must create an empty Parcel
+     * that is given here.
+     * @param reply Marshalled data to be received from the target.  May be
+     * null if you are not interested in the return value.
+     * @param flags Additional operation flags.  Either 0 for a normal
+     * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
+     */
+    public boolean transact(int code, Parcel data, Parcel reply, int flags)
+        throws RemoteException;
+
+    /**
+     * Interface for receiving a callback when the process hosting an IBinder
+     * has gone away.
+     * 
+     * @see #linkToDeath
+     */
+    public interface DeathRecipient {
+        public void binderDied();
+    }
+
+    /**
+     * Register the recipient for a notification if this binder
+     * goes away.  If this binder object unexpectedly goes away
+     * (typically because its hosting process has been killed),
+     * then the given {@link DeathRecipient}'s
+     * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
+     * will be called.
+     * 
+     * <p>You will only receive death notifications for remote binders,
+     * as local binders by definition can't die without you dying as well.
+     * 
+     * @throws Throws {@link RemoteException} if the target IBinder's
+     * process has already died.
+     * 
+     * @see #unlinkToDeath
+     */
+    public void linkToDeath(DeathRecipient recipient, int flags)
+            throws RemoteException;
+
+    /**
+     * Remove a previously registered death notification.
+     * The recipient will no longer be called if this object
+     * dies.
+     * 
+     * @return Returns true if the <var>recipient</var> is successfully
+     * unlinked, assuring you that its
+     * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
+     * will not be called.  Returns false if the target IBinder has already
+     * died, meaning the method has been (or soon will be) called.
+     * 
+     * @throws Throws {@link java.util.NoSuchElementException} if the given
+     * <var>recipient</var> has not been registered with the IBinder, and
+     * the IBinder is still alive.  Note that if the <var>recipient</var>
+     * was never registered, but the IBinder has already died, then this
+     * exception will <em>not</em> be thrown, and you will receive a false
+     * return value instead.
+     */
+    public boolean unlinkToDeath(DeathRecipient recipient, int flags);
+}
diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl
new file mode 100644
index 0000000..e56b55d
--- /dev/null
+++ b/core/java/android/os/ICheckinService.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007 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 android.os;
+
+import android.os.IParentalControlCallback;
+
+/**
+ * System private API for direct access to the checkin service.
+ * Users should use the content provider instead.
+ *
+ * @see android.provider.Checkin
+ * {@hide}
+ */
+interface ICheckinService {
+    /** Synchronously attempt a checkin with the server, return true
+      * on success.
+      * @throws IllegalStateException whenever an error occurs.  The
+      * cause of the exception will be the real exception:
+      * IOException for network errors, JSONException for invalid
+      * server responses, etc.
+      */
+    boolean checkin();
+
+    /** Direct submission of crash data; returns after writing the crash. */
+    void reportCrashSync(in byte[] crashData);
+
+    /** Asynchronous "fire and forget" version of crash reporting. */
+    oneway void reportCrashAsync(in byte[] crashData);
+
+    /** Reboot into the recovery system and wipe all user data. */
+    void masterClear();
+
+    /**
+     * Determine if the device is under parental control. Return null if
+     * we are unable to check the parental control status.
+     */
+    void getParentalControlState(IParentalControlCallback p,
+                                 String requestingApp);
+}
diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl
new file mode 100755
index 0000000..4f6029f
--- /dev/null
+++ b/core/java/android/os/IHardwareService.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2007, 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 android.os;
+
+/** {@hide} */
+interface IHardwareService
+{
+    // Vibrator support
+    void vibrate(long milliseconds);
+    void vibratePattern(in long[] pattern, int repeat, IBinder token);
+    void cancelVibrate();
+    
+    // flashlight support
+    boolean getFlashlightEnabled();
+    void setFlashlightEnabled(boolean on);
+    void enableCameraFlash(int milliseconds);
+    
+    // backlight support
+    void setScreenBacklight(int brightness);
+    void setKeyboardBacklight(boolean on);
+    void setButtonBacklight(boolean on);
+    
+    // LED support
+    void setLedState(int colorARGB, int onMS, int offMS);
+}
+
diff --git a/core/java/android/os/IInterface.java b/core/java/android/os/IInterface.java
new file mode 100644
index 0000000..2a2605a
--- /dev/null
+++ b/core/java/android/os/IInterface.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * Base class for Binder interfaces.  When defining a new interface,
+ * you must derive it from IInterface.
+ */
+public interface IInterface
+{
+    /**
+     * Retrieve the Binder object associated with this interface.
+     * You must use this instead of a plain cast, so that proxy objects
+     * can return the correct result.
+     */
+    public IBinder asBinder();
+}
diff --git a/core/java/android/os/IMessenger.aidl b/core/java/android/os/IMessenger.aidl
new file mode 100644
index 0000000..e4a8431
--- /dev/null
+++ b/core/java/android/os/IMessenger.aidl
@@ -0,0 +1,25 @@
+/* //device/java/android/android/app/IActivityPendingResult.aidl
+**
+** Copyright 2007, 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 android.os;
+
+import android.os.Message;
+
+/** @hide */
+oneway interface IMessenger {
+    void send(in Message msg);
+}
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
new file mode 100644
index 0000000..88dae85
--- /dev/null
+++ b/core/java/android/os/IMountService.aidl
@@ -0,0 +1,66 @@
+/* //device/java/android/android/os/IUsb.aidl
+**
+** Copyright 2007, 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 android.os;
+
+/** WARNING! Update IMountService.h and IMountService.cpp if you change this file.
+ * In particular, the ordering of the methods below must match the 
+ * _TRANSACTION enum in IMountService.cpp
+ * @hide
+ */
+interface IMountService
+{
+    /**
+     * Is mass storage support enabled?
+     */
+    boolean getMassStorageEnabled();
+
+    /**
+     * Enable or disable mass storage support.
+     */
+    void setMassStorageEnabled(boolean enabled);
+
+    /**
+     * Is mass storage connected?
+     */
+    boolean getMassStorageConnected();
+    
+    /**
+     * Mount external storage at given mount point.
+     */
+    void mountMedia(String mountPoint);
+
+    /**
+     * Safely unmount external storage at given mount point.
+     */
+    void unmountMedia(String mountPoint);
+
+    /**
+     * Format external storage given a mount point
+     */
+    void formatMedia(String mountPoint);
+
+    /**
+     * Returns true if media notification sounds are enabled.
+     */
+    boolean getPlayNotificationSounds();
+
+    /**
+     * Sets whether or not media notification sounds are played.
+     */
+    void setPlayNotificationSounds(boolean value);
+}
diff --git a/core/java/android/os/INetStatService.aidl b/core/java/android/os/INetStatService.aidl
new file mode 100644
index 0000000..a8f3de0
--- /dev/null
+++ b/core/java/android/os/INetStatService.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+/**
+ * Retrieves packet and byte counts for the phone data interface,
+ * and for all interfaces.
+ * Used for the data activity icon and the phone status in Settings.
+ *
+ * {@hide}
+ */
+interface INetStatService {
+    long getMobileTxPackets();
+    long getMobileRxPackets();
+    long getMobileTxBytes();
+    long getMobileRxBytes();
+    long getTotalTxPackets();
+    long getTotalRxPackets();
+    long getTotalTxBytes();
+    long getTotalRxBytes();
+}
diff --git a/core/java/android/os/IParentalControlCallback.aidl b/core/java/android/os/IParentalControlCallback.aidl
new file mode 100644
index 0000000..2f1a563
--- /dev/null
+++ b/core/java/android/os/IParentalControlCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2008 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 android.os;
+
+import com.google.android.net.ParentalControlState;
+
+/**
+ * This callback interface is used to deliver the parental control state to the calling application.
+ * {@hide}
+ */
+oneway interface IParentalControlCallback {
+	void onResult(in ParentalControlState state);
+}
diff --git a/core/java/android/os/IPermissionController.aidl b/core/java/android/os/IPermissionController.aidl
new file mode 100644
index 0000000..73a68f1
--- /dev/null
+++ b/core/java/android/os/IPermissionController.aidl
@@ -0,0 +1,23 @@
+/* //device/java/android/android/os/IPowerManager.aidl
+**
+** Copyright 2007, 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 android.os;
+
+/** @hide */
+interface IPermissionController {
+    boolean checkPermission(String permission, int pid, int uid);
+}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
new file mode 100644
index 0000000..5486920
--- /dev/null
+++ b/core/java/android/os/IPowerManager.aidl
@@ -0,0 +1,33 @@
+/* //device/java/android/android/os/IPowerManager.aidl
+**
+** Copyright 2007, 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 android.os;
+
+/** @hide */
+interface IPowerManager
+{
+    void acquireWakeLock(int flags, IBinder lock, String tag);
+    void goToSleep(long time);
+    void releaseWakeLock(IBinder lock);
+    void userActivity(long when, boolean noChangeLights);
+    void userActivityWithForce(long when, boolean noChangeLights, boolean force);
+    void setPokeLock(int pokey, IBinder lock, String tag);
+    void setStayOnSetting(int val);
+    long getScreenOnTime();
+    void preventScreenOn(boolean prevent);
+    void setScreenBrightnessOverride(int brightness);
+}
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
new file mode 100644
index 0000000..9a5ff47
--- /dev/null
+++ b/core/java/android/os/IServiceManager.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * Basic interface for finding and publishing system services.
+ * 
+ * An implementation of this interface is usually published as the
+ * global context object, which can be retrieved via
+ * BinderNative.getContextObject().  An easy way to retrieve this
+ * is with the static method BnServiceManager.getDefault().
+ * 
+ * @hide
+ */
+public interface IServiceManager extends IInterface
+{
+    /**
+     * Retrieve an existing service called @a name from the
+     * service manager.  Blocks for a few seconds waiting for it to be
+     * published if it does not already exist.
+     */
+    public IBinder getService(String name) throws RemoteException;
+    
+    /**
+     * Retrieve an existing service called @a name from the
+     * service manager.  Non-blocking.
+     */
+    public IBinder checkService(String name) throws RemoteException;
+
+    /**
+     * Place a new @a service called @a name into the service
+     * manager.
+     */
+    public void addService(String name, IBinder service) throws RemoteException;
+
+    /**
+     * Return a list of all currently running services.
+     */
+    public String[] listServices() throws RemoteException;
+
+    /**
+     * Assign a permission controller to the service manager.  After set, this
+     * interface is checked before any services are added.
+     */
+    public void setPermissionController(IPermissionController controller)
+            throws RemoteException;
+    
+    static final String descriptor = "android.os.IServiceManager";
+
+    int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
+    int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
+    int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
+    int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
+    int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
+    int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
+}
diff --git a/core/java/android/os/LocalPowerManager.java b/core/java/android/os/LocalPowerManager.java
new file mode 100644
index 0000000..55d7972
--- /dev/null
+++ b/core/java/android/os/LocalPowerManager.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+/** @hide */
+public interface LocalPowerManager {
+    public static final int OTHER_EVENT = 0;
+    public static final int CHEEK_EVENT = 1;
+    public static final int TOUCH_EVENT = 2;
+    public static final int BUTTON_EVENT = 3;  // Button and trackball events.
+
+    public static final int POKE_LOCK_IGNORE_CHEEK_EVENTS = 0x1;
+    public static final int POKE_LOCK_SHORT_TIMEOUT = 0x2;
+    public static final int POKE_LOCK_MEDIUM_TIMEOUT = 0x4;
+
+    public static final int POKE_LOCK_TIMEOUT_MASK = 0x6;
+
+    void goToSleep(long time);
+    
+    // notify power manager when keyboard is opened/closed
+    void setKeyboardVisibility(boolean visible);
+
+    // when the keyguard is up, it manages the power state, and userActivity doesn't do anything.
+    void enableUserActivity(boolean enabled);
+
+    // the same as the method on PowerManager
+    public void userActivity(long time, boolean noChangeLights, int eventType);
+}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
new file mode 100644
index 0000000..9581893
--- /dev/null
+++ b/core/java/android/os/Looper.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.util.Config;
+import android.util.Printer;
+
+/**
+  * Class used to run a message loop for a thread.  Threads by default do
+  * not have a message loop associated with them; to create one, call
+  * {@link #prepare} in the thread that is to run the loop, and then
+  * {@link #loop} to have it process messages until the loop is stopped.
+  * 
+  * <p>Most interaction with a message loop is through the
+  * {@link Handler} class.
+  * 
+  * <p>This is a typical example of the implementation of a Looper thread,
+  * using the separation of {@link #prepare} and {@link #loop} to create an
+  * initial Handler to communicate with the Looper.
+  * 
+  * <pre>
+  *  class LooperThread extends Thread {
+  *      public Handler mHandler;
+  *      
+  *      public void run() {
+  *          Looper.prepare();
+  *          
+  *          mHandler = new Handler() {
+  *              public void handleMessage(Message msg) {
+  *                  // process incoming messages here
+  *              }
+  *          };
+  *          
+  *          Looper.loop();
+  *      }
+  *  }</pre>
+  */
+public class Looper {
+    private static final boolean DEBUG = false;
+    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
+
+    // sThreadLocal.get() will return null unless you've called prepare().
+    private static final ThreadLocal sThreadLocal = new ThreadLocal();
+
+    final MessageQueue mQueue;
+    volatile boolean mRun;
+    Thread mThread;
+    private Printer mLogging = null;
+    private static Looper mMainLooper = null;
+    
+     /** Initialize the current thread as a looper.
+      * This gives you a chance to create handlers that then reference
+      * this looper, before actually starting the loop. Be sure to call
+      * {@link #loop()} after calling this method, and end it by calling
+      * {@link #quit()}.
+      */
+    public static final void prepare() {
+        if (sThreadLocal.get() != null) {
+            throw new RuntimeException("Only one Looper may be created per thread");
+        }
+        sThreadLocal.set(new Looper());
+    }
+    
+    /** Initialize the current thread as a looper, marking it as an application's main 
+     *  looper. The main looper for your application is created by the Android environment,
+     *  so you should never need to call this function yourself.
+     * {@link #prepare()}
+     */
+     
+    public static final void prepareMainLooper() {
+        prepare();
+        setMainLooper(myLooper());
+        if (Process.supportsProcesses()) {
+            myLooper().mQueue.mQuitAllowed = false;
+        }
+    }
+
+    private synchronized static void setMainLooper(Looper looper) {
+        mMainLooper = looper;
+    }
+    
+    /** Returns the application's main looper, which lives in the main thread of the application.
+     */
+    public synchronized static final Looper getMainLooper() {
+        return mMainLooper;
+    }
+
+    /**
+     *  Run the message queue in this thread. Be sure to call
+     * {@link #quit()} to end the loop.
+     */
+    public static final void loop() {
+        Looper me = myLooper();
+        MessageQueue queue = me.mQueue;
+        while (true) {
+            Message msg = queue.next(); // might block
+            //if (!me.mRun) {
+            //    break;
+            //}
+            if (msg != null) {
+                if (msg.target == null) {
+                    // No target is a magic identifier for the quit message.
+                    return;
+                }
+                if (me.mLogging!= null) me.mLogging.println(
+                        ">>>>> Dispatching to " + msg.target + " "
+                        + msg.callback + ": " + msg.what
+                        );
+                msg.target.dispatchMessage(msg);
+                if (me.mLogging!= null) me.mLogging.println(
+                        "<<<<< Finished to    " + msg.target + " "
+                        + msg.callback);
+                msg.recycle();
+            }
+        }
+    }
+
+    /**
+     * Return the Looper object associated with the current thread.  Returns
+     * null if the calling thread is not associated with a Looper.
+     */
+    public static final Looper myLooper() {
+        return (Looper)sThreadLocal.get();
+    }
+
+    /**
+     * Control logging of messages as they are processed by this Looper.  If
+     * enabled, a log message will be written to <var>printer</var> 
+     * at the beginning and ending of each message dispatch, identifying the
+     * target Handler and message contents.
+     * 
+     * @param printer A Printer object that will receive log messages, or
+     * null to disable message logging.
+     */
+    public void setMessageLogging(Printer printer) {
+        mLogging = printer;
+    }
+    
+    /**
+     * Return the {@link MessageQueue} object associated with the current
+     * thread.  This must be called from a thread running a Looper, or a
+     * NullPointerException will be thrown.
+     */
+    public static final MessageQueue myQueue() {
+        return myLooper().mQueue;
+    }
+
+    private Looper() {
+        mQueue = new MessageQueue();
+        mRun = true;
+        mThread = Thread.currentThread();
+    }
+
+    public void quit() {
+        Message msg = Message.obtain();
+        // NOTE: By enqueueing directly into the message queue, the
+        // message is left with a null target.  This is how we know it is
+        // a quit message.
+        mQueue.enqueueMessage(msg, 0);
+    }
+
+    /**
+     * Return the Thread associated with this Looper.
+     * 
+     * @since CURRENT
+     * {@hide pending API Council approval}
+     */
+    public Thread getThread() {
+        return mThread;
+    }
+    
+    public void dump(Printer pw, String prefix) {
+        pw.println(prefix + this);
+        pw.println(prefix + "mRun=" + mRun);
+        pw.println(prefix + "mThread=" + mThread);
+        pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));
+        if (mQueue != null) {
+            synchronized (mQueue) {
+                Message msg = mQueue.mMessages;
+                int n = 0;
+                while (msg != null) {
+                    pw.println(prefix + "  Message " + n + ": " + msg);
+                    n++;
+                    msg = msg.next;
+                }
+                pw.println(prefix + "(Total messages: " + n + ")");
+            }
+        }
+    }
+
+    public String toString() {
+        return "Looper{"
+            + Integer.toHexString(System.identityHashCode(this))
+            + "}";
+    }
+
+    static class HandlerException extends Exception {
+
+        HandlerException(Message message, Throwable cause) {
+            super(createMessage(cause), cause);
+        }
+
+        static String createMessage(Throwable cause) {
+            String causeMsg = cause.getMessage();
+            if (causeMsg == null) {
+                causeMsg = cause.toString();
+            }
+            return causeMsg;
+        }
+    }
+}
+
diff --git a/core/java/android/os/MailboxNotAvailableException.java b/core/java/android/os/MailboxNotAvailableException.java
new file mode 100644
index 0000000..574adbd
--- /dev/null
+++ b/core/java/android/os/MailboxNotAvailableException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/** @hide */
+public class MailboxNotAvailableException extends Throwable
+{
+  /**
+   * This exception represents the case when a request for a
+   * named, published mailbox fails because the requested name has not been published
+   */
+
+    public
+    MailboxNotAvailableException()
+    {
+    }
+
+    public
+    MailboxNotAvailableException(String s)
+    {
+        super(s);
+    }
+}
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
new file mode 100644
index 0000000..76e4f47
--- /dev/null
+++ b/core/java/android/os/MemoryFile.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+/**
+ * MemoryFile is a wrapper for the Linux ashmem driver.
+ * MemoryFiles are backed by shared memory, which can be optionally
+ * set to be purgeable.
+ * Purgeable files may have their contents reclaimed by the kernel 
+ * in low memory conditions (only if allowPurging is set to true).
+ * After a file is purged, attempts to read or write the file will
+ * cause an IOException to be thrown.
+ */
+public class MemoryFile
+{
+    private static String TAG = "MemoryFile";
+ 
+    // returns fd
+    private native int native_open(String name, int length);
+    // returns memory address for ashmem region
+    private native int native_mmap(int fd, int length);
+    private native void native_close(int fd);
+    private native int native_read(int fd, int address, byte[] buffer, 
+            int srcOffset, int destOffset, int count, boolean isUnpinned);
+    private native void native_write(int fd, int address, byte[] buffer, 
+            int srcOffset, int destOffset, int count, boolean isUnpinned);
+    private native void native_pin(int fd, boolean pin);
+
+    private int mFD;        // ashmem file descriptor
+    private int mAddress;   // address of ashmem memory
+    private int mLength;    // total length of our ashmem region
+    private boolean mAllowPurging = false;  // true if our ashmem region is unpinned
+
+    /**
+     * MemoryFile constructor.
+     *
+     * @param name optional name for the file (can be null).
+     * @param length of the memory file in bytes.
+     */
+    public MemoryFile(String name, int length) {
+        mLength = length;
+        mFD = native_open(name, length);
+        mAddress = native_mmap(mFD, length);
+    }
+
+    /**
+     * Closes and releases all resources for the memory file.
+     */
+    public void close() {
+        if (mFD > 0) {
+            native_close(mFD);
+            mFD = 0;
+        }
+    }
+
+    @Override
+    protected void finalize() {
+        if (mFD > 0) {
+            Log.e(TAG, "MemoryFile.finalize() called while ashmem still open");
+            close();
+        }
+    }
+   
+    /**
+     * Returns the length of the memory file.
+     *
+     * @return file length.
+     */
+    public int length() {
+        return mLength;
+    }
+
+    /**
+     * Is memory file purging enabled?
+     *
+     * @return true if the file may be purged.
+     */
+    public boolean isPurgingAllowed() {
+        return mAllowPurging;
+    }
+
+    /**
+     * Enables or disables purging of the memory file.
+     *
+     * @param allowPurging true if the operating system can purge the contents
+     * of the file in low memory situations
+     * @return previous value of allowPurging
+     */
+    synchronized public boolean allowPurging(boolean allowPurging) throws IOException {
+        boolean oldValue = mAllowPurging;
+        if (oldValue != allowPurging) {
+            native_pin(mFD, !allowPurging);
+            mAllowPurging = allowPurging;
+        }
+        return oldValue;
+    }
+
+    /**
+     * Creates a new InputStream for reading from the memory file.
+     *
+     @return InputStream
+     */
+    public InputStream getInputStream() {
+        return new MemoryInputStream();
+    }
+
+    /**
+     * Creates a new OutputStream for writing to the memory file.
+     *
+     @return OutputStream
+     */
+     public OutputStream getOutputStream() {
+
+        return new MemoryOutputStream();
+    }
+
+    /**
+     * Reads bytes from the memory file.
+     * Will throw an IOException if the file has been purged.
+     *
+     * @param buffer byte array to read bytes into.
+     * @param srcOffset offset into the memory file to read from.
+     * @param destOffset offset into the byte array buffer to read into.
+     * @param count number of bytes to read.
+     * @return number of bytes read.
+     */
+    public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count) 
+            throws IOException {
+        if (destOffset < 0 || destOffset > buffer.length || count < 0
+                || count > buffer.length - destOffset
+                || srcOffset < 0 || srcOffset > mLength
+                || count > mLength - srcOffset) {
+            throw new IndexOutOfBoundsException();
+        }
+        return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
+    }
+
+    /**
+     * Write bytes to the memory file.
+     * Will throw an IOException if the file has been purged.
+     *
+     * @param buffer byte array to write bytes from.
+     * @param srcOffset offset into the byte array buffer to write from.
+     * @param destOffset offset  into the memory file to write to.
+     * @param count number of bytes to write.
+     */
+    public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)
+            throws IOException {
+        if (srcOffset < 0 || srcOffset > buffer.length || count < 0
+                || count > buffer.length - srcOffset
+                || destOffset < 0 || destOffset > mLength
+                || count > mLength - destOffset) {
+            throw new IndexOutOfBoundsException();
+        }
+        native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
+    }
+
+    private class MemoryInputStream extends InputStream {
+
+        private int mMark = 0;
+        private int mOffset = 0;
+        private byte[] mSingleByte;
+
+        @Override
+        public int available() throws IOException {
+            if (mOffset >= mLength) {
+                return 0;
+            }
+            return mLength - mOffset;
+        }
+
+        @Override
+        public boolean markSupported() {
+            return true;
+        }
+
+        @Override
+        public void mark(int readlimit) {
+            mMark = mOffset;
+        }
+
+        @Override
+        public void reset() throws IOException {
+            mOffset = mMark;
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (mSingleByte == null) {
+                mSingleByte = new byte[1];
+            }
+            int result = read(mSingleByte, 0, 1);
+            if (result != 1) {
+                throw new IOException("read() failed");
+            }
+            return mSingleByte[0];
+        }
+
+        @Override
+        public int read(byte buffer[], int offset, int count) throws IOException {
+            int result = readBytes(buffer, mOffset, offset, count);
+            if (result > 0) {
+                mOffset += result;
+            }
+            return result;
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            if (mOffset + n > mLength) {
+                n = mLength - mOffset;
+            }
+            mOffset += n;
+            return n;
+        }
+    }
+
+    private class MemoryOutputStream extends OutputStream {
+
+        private int mOffset = 0;
+        private byte[] mSingleByte;
+
+        @Override
+        public void write(byte buffer[], int offset, int count) throws IOException {
+            writeBytes(buffer, offset, mOffset, count);
+        }
+
+        @Override
+        public void write(int oneByte) throws IOException {
+            if (mSingleByte == null) {
+                mSingleByte = new byte[1];
+            }
+            mSingleByte[0] = (byte)oneByte;
+            write(mSingleByte, 0, 1);
+        }
+    }
+}
diff --git a/core/java/android/os/Message.aidl b/core/java/android/os/Message.aidl
new file mode 100644
index 0000000..e8dbb5a
--- /dev/null
+++ b/core/java/android/os/Message.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/content/Intent.aidl
+**
+** Copyright 2007, 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 android.os;
+
+parcelable Message;
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
new file mode 100644
index 0000000..4130109
--- /dev/null
+++ b/core/java/android/os/Message.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * 
+ * Defines a message containing a description and arbitrary data object that can be
+ * sent to a {@link Handler}.  This object contains two extra int fields and an
+ * extra object field that allow you to not do allocations in many cases.  
+ *
+ * <p class="note">While the constructor of Message is public, the best way to get
+ * one of these is to call {@link #obtain Message.obtain()} or one of the
+ * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
+ * them from a pool of recycled objects.</p>
+ */
+public final class Message implements Parcelable {
+    /**
+     * User-defined message code so that the recipient can identify 
+     * what this message is about. Each {@link Handler} has its own name-space
+     * for message codes, so you do not need to worry about yours conflicting
+     * with other handlers.
+     */
+    public int what;
+
+    // Use these fields instead of using the class's Bundle if you can. 
+    /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
+    if you only need to store a few integer values. */
+    public int arg1; 
+
+    /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
+    if you only need to store a few integer values.*/ 
+    public int arg2;
+
+    /** An arbitrary object to send to the recipient.  This must be null when
+     * sending messages across processes. */
+    public Object obj;
+
+    /** Optional Messenger where replies to this message can be sent.
+     */
+    public Messenger replyTo;
+    
+    /*package*/ long when;
+    
+    /*package*/ Bundle data;
+    
+    /*package*/ Handler target;     
+    
+    /*package*/ Runnable callback;   
+    
+    // sometimes we store linked lists of these things
+    /*package*/ Message next;
+
+    private static Object mPoolSync = new Object();
+    private static Message mPool;
+    private static int mPoolSize = 0;
+
+    private static final int MAX_POOL_SIZE = 10;
+    
+    /**
+     * Return a new Message instance from the global pool. Allows us to
+     * avoid allocating new objects in many cases.
+     */
+    public static Message obtain() {
+        synchronized (mPoolSync) {
+            if (mPool != null) {
+                Message m = mPool;
+                mPool = m.next;
+                m.next = null;
+                return m;
+            }
+        }
+        return new Message();
+    }
+
+    /**
+     * Same as {@link #obtain()}, but copies the values of an existing
+     * message (including its target) into the new one.
+     * @param orig Original message to copy.
+     * @return A Message object from the global pool.
+     */
+    public static Message obtain(Message orig) {
+        Message m = obtain();
+        m.what = orig.what;
+        m.arg1 = orig.arg1;
+        m.arg2 = orig.arg2;
+        m.obj = orig.obj;
+        m.replyTo = orig.replyTo;
+        if (orig.data != null) {
+            m.data = new Bundle(orig.data);
+        }
+        m.target = orig.target;
+        m.callback = orig.callback;
+
+        return m;
+    }
+
+    /**
+     * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
+     * @param h  Handler to assign to the returned Message object's <em>target</em> member.
+     * @return A Message object from the global pool.
+     */
+    public static Message obtain(Handler h) {
+        Message m = obtain();
+        m.target = h;
+
+        return m;
+    }
+
+    /**
+     * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
+     * the Message that is returned.
+     * @param h  Handler to assign to the returned Message object's <em>target</em> member.
+     * @param callback Runnable that will execute when the message is handled.
+     * @return A Message object from the global pool.
+     */
+    public static Message obtain(Handler h, Runnable callback) {
+        Message m = obtain();
+        m.target = h;
+        m.callback = callback;
+
+        return m;
+    }
+
+    /**
+     * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
+     * <em>what</em> members on the Message.
+     * @param h  Value to assign to the <em>target</em> member.
+     * @param what  Value to assign to the <em>what</em> member.
+     * @return A Message object from the global pool.
+     */
+    public static Message obtain(Handler h, int what) {
+        Message m = obtain();
+        m.target = h;
+        m.what = what;
+
+        return m;
+    }
+
+    /**
+     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
+     * members.
+     * @param h  The <em>target</em> value to set.
+     * @param what  The <em>what</em> value to set.
+     * @param obj  The <em>object</em> method to set.
+     * @return  A Message object from the global pool.
+     */
+    public static Message obtain(Handler h, int what, Object obj) {
+        Message m = obtain();
+        m.target = h;
+        m.what = what;
+        m.obj = obj;
+
+        return m;
+    }
+
+    /**
+     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
+     * <em>arg1</em>, and <em>arg2</em> members.
+     * 
+     * @param h  The <em>target</em> value to set.
+     * @param what  The <em>what</em> value to set.
+     * @param arg1  The <em>arg1</em> value to set.
+     * @param arg2  The <em>arg2</em> value to set.
+     * @return  A Message object from the global pool.
+     */
+    public static Message obtain(Handler h, int what, int arg1, int arg2) {
+        Message m = obtain();
+        m.target = h;
+        m.what = what;
+        m.arg1 = arg1;
+        m.arg2 = arg2;
+
+        return m;
+    }
+
+    /**
+     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
+     * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
+     * 
+     * @param h  The <em>target</em> value to set.
+     * @param what  The <em>what</em> value to set.
+     * @param arg1  The <em>arg1</em> value to set.
+     * @param arg2  The <em>arg2</em> value to set.
+     * @param obj  The <em>obj</em> value to set.
+     * @return  A Message object from the global pool.
+     */
+    public static Message obtain(Handler h, int what, 
+            int arg1, int arg2, Object obj) {
+        Message m = obtain();
+        m.target = h;
+        m.what = what;
+        m.arg1 = arg1;
+        m.arg2 = arg2;
+        m.obj = obj;
+
+        return m;
+    }
+
+    /**
+     * Return a Message instance to the global pool.  You MUST NOT touch
+     * the Message after calling this function -- it has effectively been
+     * freed.
+     */
+    public void recycle() {
+        synchronized (mPoolSync) {
+            if (mPoolSize < MAX_POOL_SIZE) {
+                clearForRecycle();
+                
+                next = mPool;
+                mPool = this;
+            }
+        }
+    }
+
+    /**
+     * Make this message like o.  Performs a shallow copy of the data field.
+     * Does not copy the linked list fields, nor the timestamp or
+     * target/callback of the original message.
+     */
+    public void copyFrom(Message o) {
+        this.what = o.what;
+        this.arg1 = o.arg1;
+        this.arg2 = o.arg2;
+        this.obj = o.obj;
+        this.replyTo = o.replyTo;
+
+        if (o.data != null) {
+            this.data = (Bundle) o.data.clone();
+        } else {
+            this.data = null;
+        }
+    }
+
+    /**
+     * Return the targeted delivery time of this message, in milliseconds.
+     */
+    public long getWhen() {
+        return when;
+    }
+    
+    public void setTarget(Handler target) {
+        this.target = target;
+    }
+
+    /**
+     * Retrieve the a {@link android.os.Handler Handler} implementation that
+     * will receive this message. The object must implement
+     * {@link android.os.Handler#handleMessage(android.os.Message)
+     * Handler.handleMessage()}. Each Handler has its own name-space for
+     * message codes, so you do not need to
+     * worry about yours conflicting with other handlers.
+     */
+    public Handler getTarget() {
+        return target;
+    }
+
+    /**
+     * Retrieve callback object that will execute when this message is handled.
+     * This object must implement Runnable. This is called by
+     * the <em>target</em> {@link Handler} that is receiving this Message to
+     * dispatch it.  If
+     * not set, the message will be dispatched to the receiving Handler's
+     * {@link Handler#handleMessage(Message Handler.handleMessage())}. */
+    public Runnable getCallback() {
+        return callback;
+    }
+    
+    /** 
+     * Obtains a Bundle of arbitrary data associated with this
+     * event, lazily creating it if necessary. Set this value by calling {@link #setData(Bundle)}.
+     */
+    public Bundle getData() {
+        if (data == null) {
+            data = new Bundle();
+        }
+        
+        return data;
+    }
+
+    /** 
+     * Like getData(), but does not lazily create the Bundle.  A null
+     * is returned if the Bundle does not already exist.
+     */
+    public Bundle peekData() {
+        return data;
+    }
+
+    /** Sets a Bundle of arbitrary data values. Use arg1 and arg1 members 
+     * as a lower cost way to send a few simple integer values, if you can. */
+    public void setData(Bundle data) {
+        this.data = data;
+    }
+
+    /**
+     * Sends this Message to the Handler specified by {@link #getTarget}.
+     * Throws a null pointer exception if this field has not been set.
+     */
+    public void sendToTarget() {
+        target.sendMessage(this);
+    }
+
+    /*package*/ void clearForRecycle() {
+        what = 0;
+        arg1 = 0;
+        arg2 = 0;
+        obj = null;
+        replyTo = null;
+        when = 0;
+        target = null;
+        callback = null;
+        data = null;
+    }
+
+    /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
+    */
+    public Message() {
+    }
+
+    public String toString() {
+        StringBuilder   b = new StringBuilder();
+        
+        b.append("{ what=");
+        b.append(what);
+
+        b.append(" when=");
+        b.append(when);
+
+        if (arg1 != 0) {
+            b.append(" arg1=");
+            b.append(arg1);
+        }
+
+        if (arg2 != 0) {
+            b.append(" arg2=");
+            b.append(arg2);
+        }
+
+        if (obj != null) {
+            b.append(" obj=");
+            b.append(obj);
+        }
+
+        b.append(" }");
+        
+        return b.toString();
+    }
+
+    public static final Parcelable.Creator<Message> CREATOR
+            = new Parcelable.Creator<Message>() {
+        public Message createFromParcel(Parcel source) {
+            Message msg = Message.obtain();
+            msg.readFromParcel(source);
+            return msg;
+        }
+        
+        public Message[] newArray(int size) {
+            return new Message[size];
+        }
+    };
+        
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        if (obj != null || callback != null) {
+            throw new RuntimeException(
+                "Can't marshal objects across processes.");
+        }
+        dest.writeInt(what);
+        dest.writeInt(arg1);
+        dest.writeInt(arg2);
+        dest.writeLong(when);
+        dest.writeBundle(data);
+        Messenger.writeMessengerOrNullToParcel(replyTo, dest);
+    }
+
+    private final void readFromParcel(Parcel source) {
+        what = source.readInt();
+        arg1 = source.readInt();
+        arg2 = source.readInt();
+        when = source.readLong();
+        data = source.readBundle();
+        replyTo = Messenger.readMessengerOrNullFromParcel(source);
+    }
+}
+
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
new file mode 100644
index 0000000..caf0923
--- /dev/null
+++ b/core/java/android/os/MessageQueue.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import java.util.ArrayList;
+
+import android.util.AndroidRuntimeException;
+import android.util.Config;
+import android.util.Log;
+
+import com.android.internal.os.RuntimeInit;
+
+/**
+ * Low-level class holding the list of messages to be dispatched by a
+ * {@link Looper}.  Messages are not added directly to a MessageQueue,
+ * but rather through {@link Handler} objects associated with the Looper.
+ * 
+ * <p>You can retrieve the MessageQueue for the current thread with
+ * {@link Looper#myQueue() Looper.myQueue()}.
+ */
+public class MessageQueue {
+    Message mMessages;
+    private final ArrayList mIdleHandlers = new ArrayList();
+    private boolean mQuiting = false;
+    boolean mQuitAllowed = true;
+    
+    /**
+     * Callback interface for discovering when a thread is going to block
+     * waiting for more messages.
+     */
+    public static interface IdleHandler {
+        /**
+         * Called when the message queue has run out of messages and will now
+         * wait for more.  Return true to keep your idle handler active, false
+         * to have it removed.  This may be called if there are still messages
+         * pending in the queue, but they are all scheduled to be dispatched
+         * after the current time.
+         */
+        boolean queueIdle();
+    }
+
+    /**
+     * Add a new {@link IdleHandler} to this message queue.  This may be
+     * removed automatically for you by returning false from
+     * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
+     * invoked, or explicitly removing it with {@link #removeIdleHandler}.
+     * 
+     * <p>This method is safe to call from any thread.
+     * 
+     * @param handler The IdleHandler to be added.
+     */
+    public final void addIdleHandler(IdleHandler handler) {
+        if (handler == null) {
+            throw new NullPointerException("Can't add a null IdleHandler");
+        }
+        synchronized (this) {
+            mIdleHandlers.add(handler);
+        }
+    }
+
+    /**
+     * Remove an {@link IdleHandler} from the queue that was previously added
+     * with {@link #addIdleHandler}.  If the given object is not currently
+     * in the idle list, nothing is done.
+     * 
+     * @param handler The IdleHandler to be removed.
+     */
+    public final void removeIdleHandler(IdleHandler handler) {
+        synchronized (this) {
+            mIdleHandlers.remove(handler);
+        }
+    }
+
+    MessageQueue() {
+    }
+
+    final Message next() {
+        boolean tryIdle = true;
+
+        while (true) {
+            long now;
+            Object[] idlers = null;
+    
+            // Try to retrieve the next message, returning if found.
+            synchronized (this) {
+                now = SystemClock.uptimeMillis();
+                Message msg = pullNextLocked(now);
+                if (msg != null) return msg;
+                if (tryIdle && mIdleHandlers.size() > 0) {
+                    idlers = mIdleHandlers.toArray();
+                }
+            }
+    
+            // There was no message so we are going to wait...  but first,
+            // if there are any idle handlers let them know.
+            boolean didIdle = false;
+            if (idlers != null) {
+                for (Object idler : idlers) {
+                    boolean keep = false;
+                    try {
+                        didIdle = true;
+                        keep = ((IdleHandler)idler).queueIdle();
+                    } catch (Throwable t) {
+                        Log.e("MessageQueue",
+                              "IdleHandler threw exception", t);
+                        RuntimeInit.crash("MessageQueue", t);
+                    }
+
+                    if (!keep) {
+                        synchronized (this) {
+                            mIdleHandlers.remove(idler);
+                        }
+                    }
+                }
+            }
+            
+            // While calling an idle handler, a new message could have been
+            // delivered...  so go back and look again for a pending message.
+            if (didIdle) {
+                tryIdle = false;
+                continue;
+            }
+
+            synchronized (this) {
+                // No messages, nobody to tell about it...  time to wait!
+                try {
+                    if (mMessages != null) {
+                        if (mMessages.when-now > 0) {
+                            Binder.flushPendingCommands();
+                            this.wait(mMessages.when-now);
+                        }
+                    } else {
+                        Binder.flushPendingCommands();
+                        this.wait();
+                    }
+                }
+                catch (InterruptedException e) {
+                }
+            }
+        }
+    }
+
+    final Message pullNextLocked(long now) {
+        Message msg = mMessages;
+        if (msg != null) {
+            if (now >= msg.when) {
+                mMessages = msg.next;
+                if (Config.LOGV) Log.v(
+                    "MessageQueue", "Returning message: " + msg);
+                return msg;
+            }
+        }
+
+        return null;
+    }
+
+    final boolean enqueueMessage(Message msg, long when) {
+        if (msg.when != 0) {
+            throw new AndroidRuntimeException(msg
+                    + " This message is already in use.");
+        }
+        if (msg.target == null && !mQuitAllowed) {
+            throw new RuntimeException("Main thread not allowed to quit");
+        }
+        synchronized (this) {
+            if (mQuiting) {
+                RuntimeException e = new RuntimeException(
+                    msg.target + " sending message to a Handler on a dead thread");
+                Log.w("MessageQueue", e.getMessage(), e);
+                return false;
+            } else if (msg.target == null) {
+                mQuiting = true;
+            }
+
+            msg.when = when;
+            //Log.d("MessageQueue", "Enqueing: " + msg);
+            Message p = mMessages;
+            if (p == null || when == 0 || when < p.when) {
+                msg.next = p;
+                mMessages = msg;
+                this.notify();
+            } else {
+                Message prev = null;
+                while (p != null && p.when <= when) {
+                    prev = p;
+                    p = p.next;
+                }
+                msg.next = prev.next;
+                prev.next = msg;
+                this.notify();
+            }
+        }
+        return true;
+    }
+
+    final boolean removeMessages(Handler h, int what, Object object,
+            boolean doRemove) {
+        synchronized (this) {
+            Message p = mMessages;
+            boolean found = false;
+
+            // Remove all messages at front.
+            while (p != null && p.target == h && p.what == what
+                   && (object == null || p.obj == object)) {
+                if (!doRemove) return true;
+                found = true;
+                Message n = p.next;
+                mMessages = n;
+                p.recycle();
+                p = n;
+            }
+
+            // Remove all messages after front.
+            while (p != null) {
+                Message n = p.next;
+                if (n != null) {
+                    if (n.target == h && n.what == what
+                        && (object == null || n.obj == object)) {
+                        if (!doRemove) return true;
+                        found = true;
+                        Message nn = n.next;
+                        n.recycle();
+                        p.next = nn;
+                        continue;
+                    }
+                }
+                p = n;
+            }
+            
+            return found;
+        }
+    }
+
+    final void removeMessages(Handler h, Runnable r, Object object) {
+        if (r == null) {
+            return;
+        }
+
+        synchronized (this) {
+            Message p = mMessages;
+
+            // Remove all messages at front.
+            while (p != null && p.target == h && p.callback == r
+                   && (object == null || p.obj == object)) {
+                Message n = p.next;
+                mMessages = n;
+                p.recycle();
+                p = n;
+            }
+
+            // Remove all messages after front.
+            while (p != null) {
+                Message n = p.next;
+                if (n != null) {
+                    if (n.target == h && n.callback == r
+                        && (object == null || n.obj == object)) {
+                        Message nn = n.next;
+                        n.recycle();
+                        p.next = nn;
+                        continue;
+                    }
+                }
+                p = n;
+            }
+        }
+    }
+
+    final void removeCallbacksAndMessages(Handler h, Object object) {
+        synchronized (this) {
+            Message p = mMessages;
+
+            // Remove all messages at front.
+            while (p != null && p.target == h
+                    && (object == null || p.obj == object)) {
+                Message n = p.next;
+                mMessages = n;
+                p.recycle();
+                p = n;
+            }
+
+            // Remove all messages after front.
+            while (p != null) {
+                Message n = p.next;
+                if (n != null) {
+                    if (n.target == h && (object == null || n.obj == object)) {
+                        Message nn = n.next;
+                        n.recycle();
+                        p.next = nn;
+                        continue;
+                    }
+                }
+                p = n;
+            }
+        }
+    }
+
+    /*
+    private void dumpQueue_l()
+    {
+        Message p = mMessages;
+        System.out.println(this + "  queue is:");
+        while (p != null) {
+            System.out.println("            " + p);
+            p = p.next;
+        }
+    }
+    */
+
+    void poke()
+    {
+        synchronized (this) {
+            this.notify();
+        }
+    }
+}
diff --git a/core/java/android/os/Messenger.aidl b/core/java/android/os/Messenger.aidl
new file mode 100644
index 0000000..e6b8886
--- /dev/null
+++ b/core/java/android/os/Messenger.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/content/Intent.aidl
+**
+** Copyright 2007, 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 android.os;
+
+parcelable Messenger;
diff --git a/core/java/android/os/Messenger.java b/core/java/android/os/Messenger.java
new file mode 100644
index 0000000..1bc554e
--- /dev/null
+++ b/core/java/android/os/Messenger.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * Reference to a Handler, which others can use to send messages to it.
+ * This allows for the implementation of message-based communication across
+ * processes, by creating a Messenger pointing to a Handler in one process,
+ * and handing that Messenger to another process.
+ */
+public final class Messenger implements Parcelable {
+    private final IMessenger mTarget;
+
+    /**
+     * Create a new Messenger pointing to the given Handler.  Any Message
+     * objects sent through this Messenger will appear in the Handler as if
+     * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
+     * be called directly.
+     * 
+     * @param target The Handler that will receive sent messages.
+     */
+    public Messenger(Handler target) {
+        mTarget = target.getIMessenger();
+    }
+    
+    /**
+     * Send a Message to this Messenger's Handler.
+     * 
+     * @param message The Message to send.  Usually retrieved through
+     * {@link Message#obtain() Message.obtain()}.
+     * 
+     * @throws RemoteException Throws DeadObjectException if the target
+     * Handler no longer exists.
+     */
+    public void send(Message message) throws RemoteException {
+        mTarget.send(message);
+    }
+    
+    /**
+     * Retrieve the IBinder that this Messenger is using to communicate with
+     * its associated Handler.
+     * 
+     * @return Returns the IBinder backing this Messenger.
+     */
+    public IBinder getBinder() {
+        return mTarget.asBinder();
+    }
+    
+    /**
+     * Comparison operator on two Messenger objects, such that true
+     * is returned then they both point to the same Handler.
+     */
+    public boolean equals(Object otherObj) {
+        if (otherObj == null) {
+            return false;
+        }
+        try {
+            return mTarget.asBinder().equals(((Messenger)otherObj)
+                    .mTarget.asBinder());
+        } catch (ClassCastException e) {
+        }
+        return false;
+    }
+
+    public int hashCode() {
+        return mTarget.asBinder().hashCode();
+    }
+    
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeStrongBinder(mTarget.asBinder());
+    }
+
+    public static final Parcelable.Creator<Messenger> CREATOR
+            = new Parcelable.Creator<Messenger>() {
+        public Messenger createFromParcel(Parcel in) {
+            IBinder target = in.readStrongBinder();
+            return target != null ? new Messenger(target) : null;
+        }
+
+        public Messenger[] newArray(int size) {
+            return new Messenger[size];
+        }
+    };
+
+    /**
+     * Convenience function for writing either a Messenger or null pointer to
+     * a Parcel.  You must use this with {@link #readMessengerOrNullFromParcel}
+     * for later reading it.
+     * 
+     * @param messenger The Messenger to write, or null.
+     * @param out Where to write the Messenger.
+     */
+    public static void writeMessengerOrNullToParcel(Messenger messenger,
+            Parcel out) {
+        out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
+                : null);
+    }
+    
+    /**
+     * Convenience function for reading either a Messenger or null pointer from
+     * a Parcel.  You must have previously written the Messenger with
+     * {@link #writeMessengerOrNullToParcel}.
+     * 
+     * @param in The Parcel containing the written Messenger.
+     * 
+     * @return Returns the Messenger read from the Parcel, or null if null had
+     * been written.
+     */
+    public static Messenger readMessengerOrNullFromParcel(Parcel in) {
+        IBinder b = in.readStrongBinder();
+        return b != null ? new Messenger(b) : null;
+    }
+    
+    /**
+     * Create a Messenger from a raw IBinder, which had previously been
+     * retrieved with {@link #getBinder}.
+     * 
+     * @param target The IBinder this Messenger should communicate with.
+     */
+    public Messenger(IBinder target) {
+        mTarget = IMessenger.Stub.asInterface(target);
+    }
+}
diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java
new file mode 100644
index 0000000..e294cdf
--- /dev/null
+++ b/core/java/android/os/NetStat.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.io.IOException;
+
+/** @hide */
+public class NetStat {
+
+    // Logging tag.
+    private final static String TAG = "netstat";
+
+    // We pre-create all the File objects so we don't spend a lot of
+    // CPU at runtime converting from Java Strings to byte[] for the
+    // kernel calls.
+    private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets");
+    private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets");
+    private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes");
+    private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes");
+    private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net");
+
+    /**
+     * Get total number of tx packets sent through rmnet0 or ppp0
+     *
+     * @return number of Tx packets through rmnet0 or ppp0
+     */
+    public static long getMobileTxPkts() {
+        return getMobileStat(MOBILE_TX_PACKETS);
+    }
+
+    /**
+     *  Get total number of rx packets received through rmnet0 or ppp0
+     *
+     * @return number of Rx packets through rmnet0 or ppp0
+     */
+    public static long getMobileRxPkts() {
+        return getMobileStat(MOBILE_RX_PACKETS);
+    }
+
+    /**
+     *  Get total number of tx bytes received through rmnet0 or ppp0
+     *
+     * @return number of Tx bytes through rmnet0 or ppp0
+     */
+      public static long getMobileTxBytes() {
+          return getMobileStat(MOBILE_TX_BYTES);
+      }
+
+    /**
+     *  Get total number of rx bytes received through rmnet0 or ppp0
+     *
+     * @return number of Rx bytes through rmnet0 or ppp0
+     */
+    public static long getMobileRxBytes() {
+        return getMobileStat(MOBILE_RX_BYTES);
+    }
+
+    /**
+     * Get the total number of packets sent through all network interfaces.
+     *
+     * @return the number of packets sent through all network interfaces
+     */
+    public static long getTotalTxPkts() {
+        return getTotalStat("tx_packets");
+    }
+
+    /**
+     * Get the total number of packets received through all network interfaces.
+     *
+     * @return the number of packets received through all network interfaces
+     */
+    public static long getTotalRxPkts() {
+        return getTotalStat("rx_packets");
+    }
+
+    /**
+     * Get the total number of bytes sent through all network interfaces.
+     *
+     * @return the number of bytes sent through all network interfaces
+     */
+    public static long getTotalTxBytes() {
+        return getTotalStat("tx_bytes");
+    }
+
+    /**
+     * Get the total number of bytes received through all network interfaces.
+     *
+     * @return the number of bytes received through all network interfaces
+     */
+    public static long getTotalRxBytes() {
+        return getTotalStat("rx_bytes");
+    }
+
+    /**
+     * Gets network bytes sent for this UID.
+     * The statistics are across all interfaces.
+     * The statistics come from /proc/uid_stat.
+     *
+     * {@see android.os.Process#myUid()}.
+     *
+     * @param uid
+     * @return byte count
+     */
+    public static long getUidTxBytes(int uid) {
+        return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd");
+    }
+
+    /**
+     * Gets network bytes received for this UID.
+     * The statistics are across all interfaces.
+     * The statistics come from /proc/uid_stat.
+     *
+     * {@see android.os.Process#myUid()}.
+     *
+     * @param uid
+     * @return byte count
+     */
+    public static long getUidRxBytes(int uid) {
+        return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv");
+    }
+
+    /**
+     * Returns the array of two possible File locations for a given
+     * statistic.
+     */
+    private static File[] mobileFiles(String whatStat) {
+        // Note that we stat them at runtime to see which is
+        // available, rather than here, to guard against the files
+        // coming & going later as modules shut down (e.g. airplane
+        // mode) and whatnot.  The runtime stat() isn't expensive compared
+        // to the previous charset conversion that happened before we
+        // were reusing File instances.
+        File[] files = new File[2];
+        files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat);
+        files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat);
+        return files;
+    }
+
+    private static long getTotalStat(String whatStat) {
+        File netdir = new File("/sys/class/net");
+
+        File[] nets = SYS_CLASS_NET_DIR.listFiles();
+        if (nets == null) {
+            return 0;
+        }
+        long total = 0;
+        StringBuffer strbuf = new StringBuffer();
+        for (File net : nets) {
+            strbuf.append(net.getPath()).append(File.separator).append("statistics")
+                    .append(File.separator).append(whatStat);
+            total += getNumberFromFilePath(strbuf.toString());
+            strbuf.setLength(0);
+        }
+        return total;
+    }
+
+    private static long getMobileStat(File[] files) {
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            if (!file.exists()) {
+                continue;
+            }
+            try {
+                RandomAccessFile raf = new RandomAccessFile(file, "r");
+                return getNumberFromFile(raf, file.getAbsolutePath());
+            } catch (IOException e) {
+                Log.w(TAG,
+                      "Exception opening TCP statistics file " + file.getAbsolutePath(),
+                      e);
+            }
+        }
+        return 0L;
+    }
+
+    // File will have format <number><newline>
+    private static long getNumberFromFilePath(String filename) {
+        RandomAccessFile raf = getFile(filename);
+        if (raf == null) {
+            return 0L;
+        }
+        return getNumberFromFile(raf, filename);
+    }
+
+    // Private buffer for getNumberFromFile.  Safe for re-use because
+    // getNumberFromFile is synchronized.
+    private final static byte[] buf = new byte[16];
+
+    private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) {
+        try {
+            raf.read(buf);
+            raf.close();
+        } catch (IOException e) {
+            Log.w(TAG, "Exception getting TCP bytes from " + filename, e);
+            return 0L;
+        } finally {
+            if (raf != null) {
+                try {
+                    raf.close();
+                } catch (IOException e) {
+                    Log.w(TAG, "Exception closing " + filename, e);
+                }
+            }
+        }
+
+        long num = 0L;
+        for (int i = 0; i < buf.length; i++) {
+            if (buf[i] < '0' || buf[i] > '9') {
+                break;
+            }
+            num *= 10;
+            num += buf[i] - '0';
+        }
+        return num;
+    }
+
+    private static RandomAccessFile getFile(String filename) {
+        File f = new File(filename);
+        if (!f.canRead()) {
+            return null;
+        }
+
+        try {
+            return new RandomAccessFile(f, "r");
+        } catch (IOException e) {
+            Log.w(TAG, "Exception opening TCP statistics file " + filename, e);
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
new file mode 100644
index 0000000..9a71f6e
--- /dev/null
+++ b/core/java/android/os/Parcel.java
@@ -0,0 +1,2051 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Container for a message (data and object references) that can
+ * be sent through an IBinder.  A Parcel can contain both flattened data
+ * that will be unflattened on the other side of the IPC (using the various
+ * methods here for writing specific types, or the general
+ * {@link Parcelable} interface), and references to live {@link IBinder}
+ * objects that will result in the other side receiving a proxy IBinder
+ * connected with the original IBinder in the Parcel.
+ *
+ * <p class="note">Parcel is <strong>not</strong> a general-purpose
+ * serialization mechanism.  This class (and the corresponding
+ * {@link Parcelable} API for placing arbitrary objects into a Parcel) is
+ * designed as a high-performance IPC transport.  As such, it is not
+ * appropriate to place any Parcel data in to persistent storage: changes
+ * in the underlying implementation of any of the data in the Parcel can
+ * render older data unreadable.</p>
+ * 
+ * <p>The bulk of the Parcel API revolves around reading and writing data
+ * of various types.  There are six major classes of such functions available.</p>
+ * 
+ * <h3>Primitives</h3>
+ * 
+ * <p>The most basic data functions are for writing and reading primitive
+ * data types: {@link #writeByte}, {@link #readByte}, {@link #writeDouble},
+ * {@link #readDouble}, {@link #writeFloat}, {@link #readFloat}, {@link #writeInt},
+ * {@link #readInt}, {@link #writeLong}, {@link #readLong},
+ * {@link #writeString}, {@link #readString}.  Most other
+ * data operations are built on top of these.  The given data is written and
+ * read using the endianess of the host CPU.</p>
+ * 
+ * <h3>Primitive Arrays</h3>
+ * 
+ * <p>There are a variety of methods for reading and writing raw arrays
+ * of primitive objects, which generally result in writing a 4-byte length
+ * followed by the primitive data items.  The methods for reading can either
+ * read the data into an existing array, or create and return a new array.
+ * These available types are:</p>
+ * 
+ * <ul>
+ * <li> {@link #writeBooleanArray(boolean[])},
+ * {@link #readBooleanArray(boolean[])}, {@link #createBooleanArray()}
+ * <li> {@link #writeByteArray(byte[])},
+ * {@link #writeByteArray(byte[], int, int)}, {@link #readByteArray(byte[])},
+ * {@link #createByteArray()}
+ * <li> {@link #writeCharArray(char[])}, {@link #readCharArray(char[])},
+ * {@link #createCharArray()}
+ * <li> {@link #writeDoubleArray(double[])}, {@link #readDoubleArray(double[])},
+ * {@link #createDoubleArray()}
+ * <li> {@link #writeFloatArray(float[])}, {@link #readFloatArray(float[])},
+ * {@link #createFloatArray()}
+ * <li> {@link #writeIntArray(int[])}, {@link #readIntArray(int[])},
+ * {@link #createIntArray()}
+ * <li> {@link #writeLongArray(long[])}, {@link #readLongArray(long[])},
+ * {@link #createLongArray()}
+ * <li> {@link #writeStringArray(String[])}, {@link #readStringArray(String[])},
+ * {@link #createStringArray()}.
+ * <li> {@link #writeSparseBooleanArray(SparseBooleanArray)},
+ * {@link #readSparseBooleanArray()}.
+ * </ul>
+ * 
+ * <h3>Parcelables</h3>
+ * 
+ * <p>The {@link Parcelable} protocol provides an extremely efficient (but
+ * low-level) protocol for objects to write and read themselves from Parcels.
+ * You can use the direct methods {@link #writeParcelable(Parcelable, int)}
+ * and {@link #readParcelable(ClassLoader)} or
+ * {@link #writeParcelableArray} and
+ * {@link #readParcelableArray(ClassLoader)} to write or read.  These
+ * methods write both the class type and its data to the Parcel, allowing
+ * that class to be reconstructed from the appropriate class loader when
+ * later reading.</p>
+ * 
+ * <p>There are also some methods that provide a more efficient way to work
+ * with Parcelables: {@link #writeTypedArray},
+ * {@link #writeTypedList(List)},
+ * {@link #readTypedArray} and {@link #readTypedList}.  These methods
+ * do not write the class information of the original object: instead, the
+ * caller of the read function must know what type to expect and pass in the
+ * appropriate {@link Parcelable.Creator Parcelable.Creator} instead to
+ * properly construct the new object and read its data.  (To more efficient
+ * write and read a single Parceable object, you can directly call
+ * {@link Parcelable#writeToParcel Parcelable.writeToParcel} and
+ * {@link Parcelable.Creator#createFromParcel Parcelable.Creator.createFromParcel}
+ * yourself.)</p>
+ * 
+ * <h3>Bundles</h3>
+ * 
+ * <p>A special type-safe container, called {@link Bundle}, is available
+ * for key/value maps of heterogeneous values.  This has many optimizations
+ * for improved performance when reading and writing data, and its type-safe
+ * API avoids difficult to debug type errors when finally marshalling the
+ * data contents into a Parcel.  The methods to use are
+ * {@link #writeBundle(Bundle)}, {@link #readBundle()}, and
+ * {@link #readBundle(ClassLoader)}.
+ * 
+ * <h3>Active Objects</h3>
+ * 
+ * <p>An unusual feature of Parcel is the ability to read and write active
+ * objects.  For these objects the actual contents of the object is not
+ * written, rather a special token referencing the object is written.  When
+ * reading the object back from the Parcel, you do not get a new instance of
+ * the object, but rather a handle that operates on the exact same object that
+ * was originally written.  There are two forms of active objects available.</p>
+ * 
+ * <p>{@link Binder} objects are a core facility of Android's general cross-process
+ * communication system.  The {@link IBinder} interface describes an abstract
+ * protocol with a Binder object.  Any such interface can be written in to
+ * a Parcel, and upon reading you will receive either the original object
+ * implementing that interface or a special proxy implementation
+ * that communicates calls back to the original object.  The methods to use are
+ * {@link #writeStrongBinder(IBinder)},
+ * {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()},
+ * {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])},
+ * {@link #createBinderArray()},
+ * {@link #writeBinderList(List)}, {@link #readBinderList(List)},
+ * {@link #createBinderArrayList()}.</p>
+ * 
+ * <p>FileDescriptor objects, representing raw Linux file descriptor identifiers,
+ * can be written and {@link ParcelFileDescriptor} objects returned to operate
+ * on the original file descriptor.  The returned file descriptor is a dup
+ * of the original file descriptor: the object and fd is different, but
+ * operating on the same underlying file stream, with the same position, etc.
+ * The methods to use are {@link #writeFileDescriptor(FileDescriptor)},
+ * {@link #readFileDescriptor()}.
+ * 
+ * <h3>Untyped Containers</h3>
+ * 
+ * <p>A final class of methods are for writing and reading standard Java
+ * containers of arbitrary types.  These all revolve around the
+ * {@link #writeValue(Object)} and {@link #readValue(ClassLoader)} methods
+ * which define the types of objects allowed.  The container methods are
+ * {@link #writeArray(Object[])}, {@link #readArray(ClassLoader)},
+ * {@link #writeList(List)}, {@link #readList(List, ClassLoader)},
+ * {@link #readArrayList(ClassLoader)},
+ * {@link #writeMap(Map)}, {@link #readMap(Map, ClassLoader)},
+ * {@link #writeSparseArray(SparseArray)},
+ * {@link #readSparseArray(ClassLoader)}.
+ */
+public final class Parcel {
+    private static final boolean DEBUG_RECYCLE = false;
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    private int mObject; // used by native code
+    @SuppressWarnings({"UnusedDeclaration"})
+    private int mOwnObject; // used by native code
+    private RuntimeException mStack;
+
+    private static final int POOL_SIZE = 6;
+    private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
+    private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
+
+    private static final int VAL_NULL = -1;
+    private static final int VAL_STRING = 0;
+    private static final int VAL_INTEGER = 1;
+    private static final int VAL_MAP = 2;
+    private static final int VAL_BUNDLE = 3;
+    private static final int VAL_PARCELABLE = 4;
+    private static final int VAL_SHORT = 5;
+    private static final int VAL_LONG = 6;
+    private static final int VAL_FLOAT = 7;
+    private static final int VAL_DOUBLE = 8;
+    private static final int VAL_BOOLEAN = 9;
+    private static final int VAL_CHARSEQUENCE = 10;
+    private static final int VAL_LIST  = 11;
+    private static final int VAL_SPARSEARRAY = 12;
+    private static final int VAL_BYTEARRAY = 13;
+    private static final int VAL_STRINGARRAY = 14;
+    private static final int VAL_IBINDER = 15;
+    private static final int VAL_PARCELABLEARRAY = 16;
+    private static final int VAL_OBJECTARRAY = 17;
+    private static final int VAL_INTARRAY = 18;
+    private static final int VAL_LONGARRAY = 19;
+    private static final int VAL_BYTE = 20;
+    private static final int VAL_SERIALIZABLE = 21;
+    private static final int VAL_SPARSEBOOLEANARRAY = 22;
+    private static final int VAL_BOOLEANARRAY = 23;
+
+    private static final int EX_SECURITY = -1;
+    private static final int EX_BAD_PARCELABLE = -2;
+    private static final int EX_ILLEGAL_ARGUMENT = -3;
+    private static final int EX_NULL_POINTER = -4;
+    private static final int EX_ILLEGAL_STATE = -5;
+    
+    public final static Parcelable.Creator<String> STRING_CREATOR
+             = new Parcelable.Creator<String>() {
+        public String createFromParcel(Parcel source) {
+            return source.readString();
+        }
+        public String[] newArray(int size) {
+            return new String[size];
+        }
+    };
+
+    /**
+     * Retrieve a new Parcel object from the pool.
+     */
+    public static Parcel obtain() {
+        final Parcel[] pool = sOwnedPool;
+        synchronized (pool) {
+            Parcel p;
+            for (int i=0; i<POOL_SIZE; i++) {
+                p = pool[i];
+                if (p != null) {
+                    pool[i] = null;
+                    if (DEBUG_RECYCLE) {
+                        p.mStack = new RuntimeException();
+                    }
+                    return p;
+                }
+            }
+        }
+        return new Parcel(0);
+    }
+
+    /**
+     * Put a Parcel object back into the pool.  You must not touch
+     * the object after this call.
+     */
+    public final void recycle() {
+        if (DEBUG_RECYCLE) mStack = null;
+        freeBuffer();
+        final Parcel[] pool = mOwnObject != 0 ? sOwnedPool : sHolderPool;
+        synchronized (pool) {
+            for (int i=0; i<POOL_SIZE; i++) {
+                if (pool[i] == null) {
+                    pool[i] = this;
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the total amount of data contained in the parcel.
+     */
+    public final native int dataSize();
+
+    /**
+     * Returns the amount of data remaining to be read from the
+     * parcel.  That is, {@link #dataSize}-{@link #dataPosition}.
+     */
+    public final native int dataAvail();
+
+    /**
+     * Returns the current position in the parcel data.  Never
+     * more than {@link #dataSize}.
+     */
+    public final native int dataPosition();
+
+    /**
+     * Returns the total amount of space in the parcel.  This is always
+     * >= {@link #dataSize}.  The difference between it and dataSize() is the
+     * amount of room left until the parcel needs to re-allocate its
+     * data buffer.
+     */
+    public final native int dataCapacity();
+
+    /**
+     * Change the amount of data in the parcel.  Can be either smaller or
+     * larger than the current size.  If larger than the current capacity,
+     * more memory will be allocated.
+     *
+     * @param size The new number of bytes in the Parcel.
+     */
+    public final native void setDataSize(int size);
+
+    /**
+     * Move the current read/write position in the parcel.
+     * @param pos New offset in the parcel; must be between 0 and
+     * {@link #dataSize}.
+     */
+    public final native void setDataPosition(int pos);
+
+    /**
+     * Change the capacity (current available space) of the parcel.
+     *
+     * @param size The new capacity of the parcel, in bytes.  Can not be
+     * less than {@link #dataSize} -- that is, you can not drop existing data
+     * with this method.
+     */
+    public final native void setDataCapacity(int size);
+
+    /**
+     * Returns the raw bytes of the parcel.
+     *
+     * <p class="note">The data you retrieve here <strong>must not</strong>
+     * be placed in any kind of persistent storage (on local disk, across
+     * a network, etc).  For that, you should use standard serialization
+     * or another kind of general serialization mechanism.  The Parcel
+     * marshalled representation is highly optimized for local IPC, and as
+     * such does not attempt to maintain compatibility with data created
+     * in different versions of the platform.
+     */
+    public final native byte[] marshall();
+
+    /**
+     * Set the bytes in data to be the raw bytes of this Parcel.
+     */
+    public final native void unmarshall(byte[] data, int offest, int length);
+
+    public final native void appendFrom(Parcel parcel, int offset, int length);
+
+    /**
+     * Report whether the parcel contains any marshalled file descriptors.
+     */
+    public final native boolean hasFileDescriptors();
+
+    /**
+     * Store or read an IBinder interface token in the parcel at the current
+     * {@link #dataPosition}.  This is used to validate that the marshalled
+     * transaction is intended for the target interface.
+     */
+    public final native void writeInterfaceToken(String interfaceName);
+    public final native void enforceInterface(String interfaceName);
+
+    /**
+     * Write a byte array into the parcel at the current {#link #dataPosition},
+     * growing {@link #dataCapacity} if needed.
+     * @param b Bytes to place into the parcel.
+     */
+    public final void writeByteArray(byte[] b) {
+        writeByteArray(b, 0, (b != null) ? b.length : 0);
+    }
+
+    /**
+     * Write an byte array into the parcel at the current {#link #dataPosition},
+     * growing {@link #dataCapacity} if needed.
+     * @param b Bytes to place into the parcel.
+     * @param offset Index of first byte to be written.
+     * @param len Number of bytes to write.
+     */
+    public final void writeByteArray(byte[] b, int offset, int len) {
+        if (b == null) {
+            writeInt(-1);
+            return;
+        }
+        if (b.length < offset + len || len < 0 || offset < 0) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        writeNative(b, offset, len);
+    }
+
+    private native void writeNative(byte[] b, int offset, int len);
+
+    /**
+     * Write an integer value into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final native void writeInt(int val);
+
+    /**
+     * Write a long integer value into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final native void writeLong(long val);
+
+    /**
+     * Write a floating point value into the parcel at the current
+     * dataPosition(), growing dataCapacity() if needed.
+     */
+    public final native void writeFloat(float val);
+
+    /**
+     * Write a double precision floating point value into the parcel at the
+     * current dataPosition(), growing dataCapacity() if needed.
+     */
+    public final native void writeDouble(double val);
+
+    /**
+     * Write a string value into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final native void writeString(String val);
+
+    /**
+     * Write an object into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final native void writeStrongBinder(IBinder val);
+
+    /**
+     * Write an object into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final void writeStrongInterface(IInterface val) {
+        writeStrongBinder(val == null ? null : val.asBinder());
+    }
+
+    /**
+     * Write a FileDescriptor into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final native void writeFileDescriptor(FileDescriptor val);
+
+    /**
+     * Write an byte value into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final void writeByte(byte val) {
+        writeInt(val);
+    }
+
+    /**
+     * Please use {@link #writeBundle} instead.  Flattens a Map into the parcel
+     * at the current dataPosition(),
+     * growing dataCapacity() if needed.  The Map keys must be String objects.
+     * The Map values are written using {@link #writeValue} and must follow
+     * the specification there.
+     * 
+     * <p>It is strongly recommended to use {@link #writeBundle} instead of
+     * this method, since the Bundle class provides a type-safe API that
+     * allows you to avoid mysterious type errors at the point of marshalling.
+     */
+    public final void writeMap(Map val) {
+        writeMapInternal((Map<String,Object>) val);
+    }
+
+    /**
+     * Flatten a Map into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.  The Map keys must be String objects.
+     */
+    private void writeMapInternal(Map<String,Object> val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        Set<Map.Entry<String,Object>> entries = val.entrySet();
+        writeInt(entries.size());
+        for (Map.Entry<String,Object> e : entries) {
+            writeValue(e.getKey());
+            writeValue(e.getValue());
+        }
+    }
+
+    /**
+     * Flatten a Bundle into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.
+     */
+    public final void writeBundle(Bundle val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+
+        if (val.mParcelledData != null) {
+            int length = val.mParcelledData.dataSize();
+            appendFrom(val.mParcelledData, 0, length);
+        } else {
+            writeInt(-1); // dummy, will hold length
+            int oldPos = dataPosition();
+            writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
+
+            writeMapInternal(val.mMap);
+            int newPos = dataPosition();
+
+            // Backpatch length
+            setDataPosition(oldPos - 4);
+            int length = newPos - oldPos;
+            writeInt(length);
+            setDataPosition(newPos);
+        }
+    }
+
+    /**
+     * Flatten a List into the parcel at the current dataPosition(), growing
+     * dataCapacity() if needed.  The List values are written using
+     * {@link #writeValue} and must follow the specification there.
+     */
+    public final void writeList(List val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        int N = val.size();
+        int i=0;
+        writeInt(N);
+        while (i < N) {
+            writeValue(val.get(i));
+            i++;
+        }
+    }
+
+    /**
+     * Flatten an Object array into the parcel at the current dataPosition(),
+     * growing dataCapacity() if needed.  The array values are written using
+     * {@link #writeValue} and must follow the specification there.
+     */
+    public final void writeArray(Object[] val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        int N = val.length;
+        int i=0;
+        writeInt(N);
+        while (i < N) {
+            writeValue(val[i]);
+            i++;
+        }
+    }
+
+    /**
+     * Flatten a generic SparseArray into the parcel at the current
+     * dataPosition(), growing dataCapacity() if needed.  The SparseArray
+     * values are written using {@link #writeValue} and must follow the
+     * specification there.
+     */
+    public final void writeSparseArray(SparseArray<Object> val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        int N = val.size();
+        writeInt(N);
+        int i=0;
+        while (i < N) {
+            writeInt(val.keyAt(i));
+            writeValue(val.valueAt(i));
+            i++;
+        }
+    }
+
+    public final void writeSparseBooleanArray(SparseBooleanArray val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        int N = val.size();
+        writeInt(N);
+        int i=0;
+        while (i < N) {
+            writeInt(val.keyAt(i));
+            writeByte((byte)(val.valueAt(i) ? 1 : 0));
+            i++;
+        }
+    }
+
+    public final void writeBooleanArray(boolean[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeInt(val[i] ? 1 : 0);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final boolean[] createBooleanArray() {
+        int N = readInt();
+        // >>2 as a fast divide-by-4 works in the create*Array() functions
+        // because dataAvail() will never return a negative number.  4 is
+        // the size of a stored boolean in the stream.
+        if (N >= 0 && N <= (dataAvail() >> 2)) {
+            boolean[] val = new boolean[N];
+            for (int i=0; i<N; i++) {
+                val[i] = readInt() != 0;
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readBooleanArray(boolean[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = readInt() != 0;
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    public final void writeCharArray(char[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeInt((int)val[i]);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final char[] createCharArray() {
+        int N = readInt();
+        if (N >= 0 && N <= (dataAvail() >> 2)) {
+            char[] val = new char[N];
+            for (int i=0; i<N; i++) {
+                val[i] = (char)readInt();
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readCharArray(char[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = (char)readInt();
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    public final void writeIntArray(int[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeInt(val[i]);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final int[] createIntArray() {
+        int N = readInt();
+        if (N >= 0 && N <= (dataAvail() >> 2)) {
+            int[] val = new int[N];
+            for (int i=0; i<N; i++) {
+                val[i] = readInt();
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readIntArray(int[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = readInt();
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    public final void writeLongArray(long[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeLong(val[i]);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final long[] createLongArray() {
+        int N = readInt();
+        // >>3 because stored longs are 64 bits
+        if (N >= 0 && N <= (dataAvail() >> 3)) {
+            long[] val = new long[N];
+            for (int i=0; i<N; i++) {
+                val[i] = readLong();
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readLongArray(long[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = readLong();
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    public final void writeFloatArray(float[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeFloat(val[i]);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final float[] createFloatArray() {
+        int N = readInt();
+        // >>2 because stored floats are 4 bytes
+        if (N >= 0 && N <= (dataAvail() >> 2)) {
+            float[] val = new float[N];
+            for (int i=0; i<N; i++) {
+                val[i] = readFloat();
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readFloatArray(float[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = readFloat();
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    public final void writeDoubleArray(double[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeDouble(val[i]);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final double[] createDoubleArray() {
+        int N = readInt();
+        // >>3 because stored doubles are 8 bytes
+        if (N >= 0 && N <= (dataAvail() >> 3)) {
+            double[] val = new double[N];
+            for (int i=0; i<N; i++) {
+                val[i] = readDouble();
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readDoubleArray(double[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = readDouble();
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    public final void writeStringArray(String[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeString(val[i]);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final String[] createStringArray() {
+        int N = readInt();
+        if (N >= 0) {
+            String[] val = new String[N];
+            for (int i=0; i<N; i++) {
+                val[i] = readString();
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readStringArray(String[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = readString();
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    public final void writeBinderArray(IBinder[] val) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeStrongBinder(val[i]);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    public final IBinder[] createBinderArray() {
+        int N = readInt();
+        if (N >= 0) {
+            IBinder[] val = new IBinder[N];
+            for (int i=0; i<N; i++) {
+                val[i] = readStrongBinder();
+            }
+            return val;
+        } else {
+            return null;
+        }
+    }
+
+    public final void readBinderArray(IBinder[] val) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                val[i] = readStrongBinder();
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    /**
+     * Flatten a List containing a particular object type into the parcel, at
+     * the current dataPosition() and growing dataCapacity() if needed.  The
+     * type of the objects in the list must be one that implements Parcelable.
+     * Unlike the generic writeList() method, however, only the raw data of the
+     * objects is written and not their type, so you must use the corresponding
+     * readTypedList() to unmarshall them.
+     *
+     * @param val The list of objects to be written.
+     *
+     * @see #createTypedArrayList
+     * @see #readTypedList
+     * @see Parcelable
+     */
+    public final <T extends Parcelable> void writeTypedList(List<T> val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        int N = val.size();
+        int i=0;
+        writeInt(N);
+        while (i < N) {
+            T item = val.get(i);
+            if (item != null) {
+                writeInt(1);
+                item.writeToParcel(this, 0);
+            } else {
+                writeInt(0);
+            }
+            i++;
+        }
+    }
+
+    /**
+     * Flatten a List containing String objects into the parcel, at
+     * the current dataPosition() and growing dataCapacity() if needed.  They
+     * can later be retrieved with {@link #createStringArrayList} or
+     * {@link #readStringList}.
+     *
+     * @param val The list of strings to be written.
+     *
+     * @see #createStringArrayList
+     * @see #readStringList
+     */
+    public final void writeStringList(List<String> val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        int N = val.size();
+        int i=0;
+        writeInt(N);
+        while (i < N) {
+            writeString(val.get(i));
+            i++;
+        }
+    }
+
+    /**
+     * Flatten a List containing IBinder objects into the parcel, at
+     * the current dataPosition() and growing dataCapacity() if needed.  They
+     * can later be retrieved with {@link #createBinderArrayList} or
+     * {@link #readBinderList}.
+     *
+     * @param val The list of strings to be written.
+     *
+     * @see #createBinderArrayList
+     * @see #readBinderList
+     */
+    public final void writeBinderList(List<IBinder> val) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        int N = val.size();
+        int i=0;
+        writeInt(N);
+        while (i < N) {
+            writeStrongBinder(val.get(i));
+            i++;
+        }
+    }
+
+    /**
+     * Flatten a heterogeneous array containing a particular object type into
+     * the parcel, at
+     * the current dataPosition() and growing dataCapacity() if needed.  The
+     * type of the objects in the array must be one that implements Parcelable.
+     * Unlike the {@link #writeParcelableArray} method, however, only the
+     * raw data of the objects is written and not their type, so you must use
+     * {@link #readTypedArray} with the correct corresponding
+     * {@link Parcelable.Creator} implementation to unmarshall them.
+     *
+     * @param val The array of objects to be written.
+     * @param parcelableFlags Contextual flags as per
+     * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
+     *
+     * @see #readTypedArray
+     * @see #writeParcelableArray
+     * @see Parcelable.Creator
+     */
+    public final <T extends Parcelable> void writeTypedArray(T[] val,
+            int parcelableFlags) {
+        if (val != null) {
+            int N = val.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                T item = val[i];
+                if (item != null) {
+                    writeInt(1);
+                    item.writeToParcel(this, parcelableFlags);
+                } else {
+                    writeInt(0);
+                }
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    /**
+     * Flatten a generic object in to a parcel.  The given Object value may
+     * currently be one of the following types:
+     * 
+     * <ul>
+     * <li> null
+     * <li> String
+     * <li> Byte
+     * <li> Short
+     * <li> Integer
+     * <li> Long
+     * <li> Float
+     * <li> Double
+     * <li> Boolean
+     * <li> String[]
+     * <li> boolean[]
+     * <li> byte[]
+     * <li> int[]
+     * <li> long[]
+     * <li> Object[] (supporting objects of the same type defined here).
+     * <li> {@link Bundle}
+     * <li> Map (as supported by {@link #writeMap}).
+     * <li> Any object that implements the {@link Parcelable} protocol.
+     * <li> Parcelable[]
+     * <li> CharSequence (as supported by {@link TextUtils#writeToParcel}).
+     * <li> List (as supported by {@link #writeList}).
+     * <li> {@link SparseArray} (as supported by {@link #writeSparseArray}).
+     * <li> {@link IBinder}
+     * <li> Any object that implements Serializable (but see
+     *      {@link #writeSerializable} for caveats).  Note that all of the
+     *      previous types have relatively efficient implementations for
+     *      writing to a Parcel; having to rely on the generic serialization
+     *      approach is much less efficient and should be avoided whenever
+     *      possible.
+     * </ul>
+     */
+    public final void writeValue(Object v) {
+        if (v == null) {
+            writeInt(VAL_NULL);
+        } else if (v instanceof String) {
+            writeInt(VAL_STRING);
+            writeString((String) v);
+        } else if (v instanceof Integer) {
+            writeInt(VAL_INTEGER);
+            writeInt((Integer) v);
+        } else if (v instanceof Map) {
+            writeInt(VAL_MAP);
+            writeMap((Map) v);
+        } else if (v instanceof Bundle) {
+            // Must be before Parcelable
+            writeInt(VAL_BUNDLE);
+            writeBundle((Bundle) v);
+        } else if (v instanceof Parcelable) {
+            writeInt(VAL_PARCELABLE);
+            writeParcelable((Parcelable) v, 0);
+        } else if (v instanceof Short) {
+            writeInt(VAL_SHORT);
+            writeInt(((Short) v).intValue());
+        } else if (v instanceof Long) {
+            writeInt(VAL_LONG);
+            writeLong((Long) v);
+        } else if (v instanceof Float) {
+            writeInt(VAL_FLOAT);
+            writeFloat((Float) v);
+        } else if (v instanceof Double) {
+            writeInt(VAL_DOUBLE);
+            writeDouble((Double) v);
+        } else if (v instanceof Boolean) {
+            writeInt(VAL_BOOLEAN);
+            writeInt((Boolean) v ? 1 : 0);
+        } else if (v instanceof CharSequence) {
+            // Must be after String
+            writeInt(VAL_CHARSEQUENCE);
+            TextUtils.writeToParcel((CharSequence) v, this, 0);
+        } else if (v instanceof List) {
+            writeInt(VAL_LIST);
+            writeList((List) v);
+        } else if (v instanceof SparseArray) {
+            writeInt(VAL_SPARSEARRAY);
+            writeSparseArray((SparseArray) v);
+        } else if (v instanceof boolean[]) {
+            writeInt(VAL_BOOLEANARRAY);
+            writeBooleanArray((boolean[]) v);
+        } else if (v instanceof byte[]) {
+            writeInt(VAL_BYTEARRAY);
+            writeByteArray((byte[]) v);
+        } else if (v instanceof String[]) {
+            writeInt(VAL_STRINGARRAY);
+            writeStringArray((String[]) v);
+        } else if (v instanceof IBinder) {
+            writeInt(VAL_IBINDER);
+            writeStrongBinder((IBinder) v);
+        } else if (v instanceof Parcelable[]) {
+            writeInt(VAL_PARCELABLEARRAY);
+            writeParcelableArray((Parcelable[]) v, 0);
+        } else if (v instanceof Object[]) {
+            writeInt(VAL_OBJECTARRAY);
+            writeArray((Object[]) v);
+        } else if (v instanceof int[]) {
+            writeInt(VAL_INTARRAY);
+            writeIntArray((int[]) v);
+        } else if (v instanceof long[]) {
+            writeInt(VAL_LONGARRAY);
+            writeLongArray((long[]) v);
+        } else if (v instanceof Byte) {
+            writeInt(VAL_BYTE);
+            writeInt((Byte) v);
+        } else if (v instanceof Serializable) {
+            // Must be last
+            writeInt(VAL_SERIALIZABLE);
+            writeSerializable((Serializable) v);
+        } else {
+            throw new RuntimeException("Parcel: unable to marshal value " + v);
+        }
+    }
+
+    /**
+     * Flatten the name of the class of the Parcelable and its contents
+     * into the parcel.
+     * 
+     * @param p The Parcelable object to be written.
+     * @param parcelableFlags Contextual flags as per
+     * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
+     */
+    public final void writeParcelable(Parcelable p, int parcelableFlags) {
+        if (p == null) {
+            writeString(null);
+            return;
+        }
+        String name = p.getClass().getName();
+        writeString(name);
+        p.writeToParcel(this, parcelableFlags);
+    }
+
+    /**
+     * Write a generic serializable object in to a Parcel.  It is strongly
+     * recommended that this method be avoided, since the serialization
+     * overhead is extremely large, and this approach will be much slower than
+     * using the other approaches to writing data in to a Parcel.
+     */
+    public final void writeSerializable(Serializable s) {
+        if (s == null) {
+            writeString(null);
+            return;
+        }
+        String name = s.getClass().getName();
+        writeString(name);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(s);
+            oos.close();
+
+            writeByteArray(baos.toByteArray());
+        } catch (IOException ioe) {
+            throw new RuntimeException("Parcelable encountered " +
+                "IOException writing serializable object (name = " + name +
+                ")", ioe);
+        }
+    }
+
+    /**
+     * Special function for writing an exception result at the header of
+     * a parcel, to be used when returning an exception from a transaction.
+     * Note that this currently only supports a few exception types; any other
+     * exception will be re-thrown by this function as a RuntimeException
+     * (to be caught by the system's last-resort exception handling when
+     * dispatching a transaction).
+     * 
+     * <p>The supported exception types are:
+     * <ul>
+     * <li>{@link BadParcelableException}
+     * <li>{@link IllegalArgumentException}
+     * <li>{@link IllegalStateException}
+     * <li>{@link NullPointerException}
+     * <li>{@link SecurityException}
+     * </ul>
+     * 
+     * @param e The Exception to be written.
+     *
+     * @see #writeNoException
+     * @see #readException
+     */
+    public final void writeException(Exception e) {
+        int code = 0;
+        if (e instanceof SecurityException) {
+            code = EX_SECURITY;
+        } else if (e instanceof BadParcelableException) {
+            code = EX_BAD_PARCELABLE;
+        } else if (e instanceof IllegalArgumentException) {
+            code = EX_ILLEGAL_ARGUMENT;
+        } else if (e instanceof NullPointerException) {
+            code = EX_NULL_POINTER;
+        } else if (e instanceof IllegalStateException) {
+            code = EX_ILLEGAL_STATE;
+        }
+        writeInt(code);
+        if (code == 0) {
+            if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            }
+            throw new RuntimeException(e);
+        }
+        writeString(e.getMessage());
+    }
+
+    /**
+     * Special function for writing information at the front of the Parcel
+     * indicating that no exception occurred.
+     *
+     * @see #writeException
+     * @see #readException
+     */
+    public final void writeNoException() {
+        writeInt(0);
+    }
+
+    /**
+     * Special function for reading an exception result from the header of
+     * a parcel, to be used after receiving the result of a transaction.  This
+     * will throw the exception for you if it had been written to the Parcel,
+     * otherwise return and let you read the normal result data from the Parcel.
+     *
+     * @see #writeException
+     * @see #writeNoException
+     */
+    public final void readException() {
+        int code = readInt();
+        if (code == 0) return;
+        String msg = readString();
+        readException(code, msg);
+    }
+
+    /**
+     * Use this function for customized exception handling.
+     * customized method call this method for all unknown case
+     * @param code exception code
+     * @param msg exception message
+     */
+    public final void readException(int code, String msg) {
+        switch (code) {
+            case EX_SECURITY:
+                throw new SecurityException(msg);
+            case EX_BAD_PARCELABLE:
+                throw new BadParcelableException(msg);
+            case EX_ILLEGAL_ARGUMENT:
+                throw new IllegalArgumentException(msg);
+            case EX_NULL_POINTER:
+                throw new NullPointerException(msg);
+            case EX_ILLEGAL_STATE:
+                throw new IllegalStateException(msg);
+        }
+        throw new RuntimeException("Unknown exception code: " + code
+                + " msg " + msg);
+    }
+
+    /**
+     * Read an integer value from the parcel at the current dataPosition().
+     */
+    public final native int readInt();
+
+    /**
+     * Read a long integer value from the parcel at the current dataPosition().
+     */
+    public final native long readLong();
+
+    /**
+     * Read a floating point value from the parcel at the current
+     * dataPosition().
+     */
+    public final native float readFloat();
+
+    /**
+     * Read a double precision floating point value from the parcel at the
+     * current dataPosition().
+     */
+    public final native double readDouble();
+
+    /**
+     * Read a string value from the parcel at the current dataPosition().
+     */
+    public final native String readString();
+
+    /**
+     * Read an object from the parcel at the current dataPosition().
+     */
+    public final native IBinder readStrongBinder();
+
+    /**
+     * Read a FileDescriptor from the parcel at the current dataPosition().
+     */
+    public final ParcelFileDescriptor readFileDescriptor() {
+        FileDescriptor fd = internalReadFileDescriptor();
+        return fd != null ? new ParcelFileDescriptor(fd) : null;
+    }
+
+    private native FileDescriptor internalReadFileDescriptor();
+    /*package*/ static native FileDescriptor openFileDescriptor(String file,
+            int mode) throws FileNotFoundException;
+    /*package*/ static native void closeFileDescriptor(FileDescriptor desc)
+            throws IOException;
+
+    /**
+     * Read a byte value from the parcel at the current dataPosition().
+     */
+    public final byte readByte() {
+        return (byte)(readInt() & 0xff);
+    }
+
+    /**
+     * Please use {@link #readBundle(ClassLoader)} instead (whose data must have
+     * been written with {@link #writeBundle}.  Read into an existing Map object
+     * from the parcel at the current dataPosition().
+     */
+    public final void readMap(Map outVal, ClassLoader loader) {
+        int N = readInt();
+        readMapInternal(outVal, N, loader);
+    }
+
+    /**
+     * Read into an existing List object from the parcel at the current
+     * dataPosition(), using the given class loader to load any enclosed
+     * Parcelables.  If it is null, the default class loader is used.
+     */
+    public final void readList(List outVal, ClassLoader loader) {
+        int N = readInt();
+        readListInternal(outVal, N, loader);
+    }
+
+    /**
+     * Please use {@link #readBundle(ClassLoader)} instead (whose data must have
+     * been written with {@link #writeBundle}.  Read and return a new HashMap
+     * object from the parcel at the current dataPosition(), using the given
+     * class loader to load any enclosed Parcelables.  Returns null if
+     * the previously written map object was null.
+     */
+    public final HashMap readHashMap(ClassLoader loader)
+    {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        HashMap m = new HashMap(N);
+        readMapInternal(m, N, loader);
+        return m;
+    }
+
+    /**
+     * Read and return a new Bundle object from the parcel at the current
+     * dataPosition().  Returns null if the previously written Bundle object was
+     * null.
+     */
+    public final Bundle readBundle() {
+        return readBundle(null);
+    }
+
+    /**
+     * Read and return a new Bundle object from the parcel at the current
+     * dataPosition(), using the given class loader to initialize the class
+     * loader of the Bundle for later retrieval of Parcelable objects.
+     * Returns null if the previously written Bundle object was null.
+     */
+    public final Bundle readBundle(ClassLoader loader) {
+        int offset = dataPosition();
+        int length = readInt();
+        if (length < 0) {
+            return null;
+        }
+        int magic = readInt();
+        if (magic != 0x4C444E42) {
+            //noinspection ThrowableInstanceNeverThrown
+            String st = Log.getStackTraceString(new RuntimeException());
+            Log.e("Bundle", "readBundle: bad magic number");
+            Log.e("Bundle", "readBundle: trace = " + st);
+        }
+
+        // Advance within this Parcel
+        setDataPosition(offset + length + 4);
+
+        Parcel p = new Parcel(0);
+        p.setDataPosition(0);
+        p.appendFrom(this, offset, length + 4);
+        p.setDataPosition(0);
+        final Bundle bundle = new Bundle(p);
+        if (loader != null) {
+            bundle.setClassLoader(loader);
+        }
+        return bundle;
+    }
+
+    /**
+     * Read and return a new Bundle object from the parcel at the current
+     * dataPosition().  Returns null if the previously written Bundle object was
+     * null.  The returned bundle will have its contents fully unpacked using
+     * the given ClassLoader.
+     */
+    /* package */ Bundle readBundleUnpacked(ClassLoader loader) {
+        int length = readInt();
+        if (length == -1) {
+            return null;
+        }
+        int magic = readInt();
+        if (magic != 0x4C444E42) {
+            //noinspection ThrowableInstanceNeverThrown
+            String st = Log.getStackTraceString(new RuntimeException());
+            Log.e("Bundle", "readBundleUnpacked: bad magic number");
+            Log.e("Bundle", "readBundleUnpacked: trace = " + st);
+        }
+        Bundle m = new Bundle(loader);
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        readMapInternal(m.mMap, N, loader);
+        return m;
+    }
+
+    /**
+     * Read and return a byte[] object from the parcel.
+     */
+    public final native byte[] createByteArray();
+
+    /**
+     * Read a byte[] object from the parcel and copy it into the
+     * given byte array.
+     */
+    public final void readByteArray(byte[] val) {
+        // TODO: make this a native method to avoid the extra copy.
+        byte[] ba = createByteArray();
+        if (ba.length == val.length) {
+           System.arraycopy(ba, 0, val, 0, ba.length);
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    /**
+     * Read and return a String[] object from the parcel.
+     * {@hide}
+     */
+    public final String[] readStringArray() {
+        String[] array = null;
+
+        int length = readInt();
+        if (length >= 0)
+        {
+            array = new String[length];
+
+            for (int i = 0 ; i < length ; i++)
+            {
+                array[i] = readString();
+            }
+        }
+
+        return array;
+    }
+
+    /**
+     * Read and return a new ArrayList object from the parcel at the current
+     * dataPosition().  Returns null if the previously written list object was
+     * null.  The given class loader will be used to load any enclosed
+     * Parcelables.
+     */
+    public final ArrayList readArrayList(ClassLoader loader) {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        ArrayList l = new ArrayList(N);
+        readListInternal(l, N, loader);
+        return l;
+    }
+
+    /**
+     * Read and return a new Object array from the parcel at the current
+     * dataPosition().  Returns null if the previously written array was
+     * null.  The given class loader will be used to load any enclosed
+     * Parcelables.
+     */
+    public final Object[] readArray(ClassLoader loader) {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        Object[] l = new Object[N];
+        readArrayInternal(l, N, loader);
+        return l;
+    }
+
+    /**
+     * Read and return a new SparseArray object from the parcel at the current
+     * dataPosition().  Returns null if the previously written list object was
+     * null.  The given class loader will be used to load any enclosed
+     * Parcelables.
+     */
+    public final SparseArray readSparseArray(ClassLoader loader) {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        SparseArray sa = new SparseArray(N);
+        readSparseArrayInternal(sa, N, loader);
+        return sa;
+    }
+
+    /**
+     * Read and return a new SparseBooleanArray object from the parcel at the current
+     * dataPosition().  Returns null if the previously written list object was
+     * null.
+     */
+    public final SparseBooleanArray readSparseBooleanArray() {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        SparseBooleanArray sa = new SparseBooleanArray(N);
+        readSparseBooleanArrayInternal(sa, N);
+        return sa;
+    }
+
+    /**
+     * Read and return a new ArrayList containing a particular object type from
+     * the parcel that was written with {@link #writeTypedList} at the
+     * current dataPosition().  Returns null if the
+     * previously written list object was null.  The list <em>must</em> have
+     * previously been written via {@link #writeTypedList} with the same object
+     * type.
+     *
+     * @return A newly created ArrayList containing objects with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeTypedList
+     */
+    public final <T> ArrayList<T> createTypedArrayList(Parcelable.Creator<T> c) {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        ArrayList<T> l = new ArrayList<T>(N);
+        while (N > 0) {
+            if (readInt() != 0) {
+                l.add(c.createFromParcel(this));
+            } else {
+                l.add(null);
+            }
+            N--;
+        }
+        return l;
+    }
+
+    /**
+     * Read into the given List items containing a particular object type
+     * that were written with {@link #writeTypedList} at the
+     * current dataPosition().  The list <em>must</em> have
+     * previously been written via {@link #writeTypedList} with the same object
+     * type.
+     *
+     * @return A newly created ArrayList containing objects with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeTypedList
+     */
+    public final <T> void readTypedList(List<T> list, Parcelable.Creator<T> c) {
+        int M = list.size();
+        int N = readInt();
+        int i = 0;
+        for (; i < M && i < N; i++) {
+            if (readInt() != 0) {
+                list.set(i, c.createFromParcel(this));
+            } else {
+                list.set(i, null);
+            }
+        }
+        for (; i<N; i++) {
+            if (readInt() != 0) {
+                list.add(c.createFromParcel(this));
+            } else {
+                list.add(null);
+            }
+        }
+        for (; i<M; i++) {
+            list.remove(N);
+        }
+    }
+
+    /**
+     * Read and return a new ArrayList containing String objects from
+     * the parcel that was written with {@link #writeStringList} at the
+     * current dataPosition().  Returns null if the
+     * previously written list object was null.
+     *
+     * @return A newly created ArrayList containing strings with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeStringList
+     */
+    public final ArrayList<String> createStringArrayList() {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        ArrayList<String> l = new ArrayList<String>(N);
+        while (N > 0) {
+            l.add(readString());
+            N--;
+        }
+        return l;
+    }
+
+    /**
+     * Read and return a new ArrayList containing IBinder objects from
+     * the parcel that was written with {@link #writeBinderList} at the
+     * current dataPosition().  Returns null if the
+     * previously written list object was null.
+     *
+     * @return A newly created ArrayList containing strings with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeBinderList
+     */
+    public final ArrayList<IBinder> createBinderArrayList() {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        ArrayList<IBinder> l = new ArrayList<IBinder>(N);
+        while (N > 0) {
+            l.add(readStrongBinder());
+            N--;
+        }
+        return l;
+    }
+
+    /**
+     * Read into the given List items String objects that were written with
+     * {@link #writeStringList} at the current dataPosition().
+     *
+     * @return A newly created ArrayList containing strings with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeStringList
+     */
+    public final void readStringList(List<String> list) {
+        int M = list.size();
+        int N = readInt();
+        int i = 0;
+        for (; i < M && i < N; i++) {
+            list.set(i, readString());
+        }
+        for (; i<N; i++) {
+            list.add(readString());
+        }
+        for (; i<M; i++) {
+            list.remove(N);
+        }
+    }
+
+    /**
+     * Read into the given List items IBinder objects that were written with
+     * {@link #writeBinderList} at the current dataPosition().
+     *
+     * @return A newly created ArrayList containing strings with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeBinderList
+     */
+    public final void readBinderList(List<IBinder> list) {
+        int M = list.size();
+        int N = readInt();
+        int i = 0;
+        for (; i < M && i < N; i++) {
+            list.set(i, readStrongBinder());
+        }
+        for (; i<N; i++) {
+            list.add(readStrongBinder());
+        }
+        for (; i<M; i++) {
+            list.remove(N);
+        }
+    }
+
+    /**
+     * Read and return a new array containing a particular object type from
+     * the parcel at the current dataPosition().  Returns null if the
+     * previously written array was null.  The array <em>must</em> have
+     * previously been written via {@link #writeTypedArray} with the same
+     * object type.
+     *
+     * @return A newly created array containing objects with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeTypedArray
+     */
+    public final <T> T[] createTypedArray(Parcelable.Creator<T> c) {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        T[] l = c.newArray(N);
+        for (int i=0; i<N; i++) {
+            if (readInt() != 0) {
+                l[i] = c.createFromParcel(this);
+            }
+        }
+        return l;
+    }
+
+    public final <T> void readTypedArray(T[] val, Parcelable.Creator<T> c) {
+        int N = readInt();
+        if (N == val.length) {
+            for (int i=0; i<N; i++) {
+                if (readInt() != 0) {
+                    val[i] = c.createFromParcel(this);
+                } else {
+                    val[i] = null;
+                }
+            }
+        } else {
+            throw new RuntimeException("bad array lengths");
+        }
+    }
+
+    /**
+     * @deprecated
+     * @hide
+     */
+    @Deprecated
+    public final <T> T[] readTypedArray(Parcelable.Creator<T> c) {
+        return createTypedArray(c);
+    }
+
+    /**
+     * Write a heterogeneous array of Parcelable objects into the Parcel.
+     * Each object in the array is written along with its class name, so
+     * that the correct class can later be instantiated.  As a result, this
+     * has significantly more overhead than {@link #writeTypedArray}, but will
+     * correctly handle an array containing more than one type of object.
+     *
+     * @param value The array of objects to be written.
+     * @param parcelableFlags Contextual flags as per
+     * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
+     *
+     * @see #writeTypedArray
+     */
+    public final <T extends Parcelable> void writeParcelableArray(T[] value,
+            int parcelableFlags) {
+        if (value != null) {
+            int N = value.length;
+            writeInt(N);
+            for (int i=0; i<N; i++) {
+                writeParcelable(value[i], parcelableFlags);
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    /**
+     * Read a typed object from a parcel.  The given class loader will be
+     * used to load any enclosed Parcelables.  If it is null, the default class
+     * loader will be used.
+     */
+    public final Object readValue(ClassLoader loader) {
+        int type = readInt();
+
+        switch (type) {
+        case VAL_NULL:
+            return null;
+
+        case VAL_STRING:
+            return readString();
+
+        case VAL_INTEGER:
+            return readInt();
+
+        case VAL_MAP:
+            return readHashMap(loader);
+
+        case VAL_PARCELABLE:
+            return readParcelable(loader);
+
+        case VAL_SHORT:
+            return (short) readInt();
+
+        case VAL_LONG:
+            return readLong();
+
+        case VAL_FLOAT:
+            return readFloat();
+
+        case VAL_DOUBLE:
+            return readDouble();
+
+        case VAL_BOOLEAN:
+            return readInt() == 1;
+
+        case VAL_CHARSEQUENCE:
+            return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this);
+
+        case VAL_LIST:
+            return readArrayList(loader);
+
+        case VAL_BOOLEANARRAY:
+            return createBooleanArray();        
+
+        case VAL_BYTEARRAY:
+            return createByteArray();
+
+        case VAL_STRINGARRAY:
+            return readStringArray();
+
+        case VAL_IBINDER:
+            return readStrongBinder();
+
+        case VAL_OBJECTARRAY:
+            return readArray(loader);
+
+        case VAL_INTARRAY:
+            return createIntArray();
+
+        case VAL_LONGARRAY:
+            return createLongArray();
+
+        case VAL_BYTE:
+            return readByte();
+
+        case VAL_SERIALIZABLE:
+            return readSerializable();
+
+        case VAL_PARCELABLEARRAY:
+            return readParcelableArray(loader);
+
+        case VAL_SPARSEARRAY:
+            return readSparseArray(loader);
+
+        case VAL_SPARSEBOOLEANARRAY:
+            return readSparseBooleanArray();
+
+        case VAL_BUNDLE:
+            return readBundle(loader); // loading will be deferred
+
+        default:
+            int off = dataPosition() - 4;
+            throw new RuntimeException(
+                "Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off);
+        }
+    }
+
+    /**
+     * Read and return a new Parcelable from the parcel.  The given class loader
+     * will be used to load any enclosed Parcelables.  If it is null, the default
+     * class loader will be used.
+     * @param loader A ClassLoader from which to instantiate the Parcelable
+     * object, or null for the default class loader.
+     * @return Returns the newly created Parcelable, or null if a null
+     * object has been written.
+     * @throws BadParcelableException Throws BadParcelableException if there
+     * was an error trying to instantiate the Parcelable.
+     */
+    public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
+        String name = readString();
+        if (name == null) {
+            return null;
+        }
+        Parcelable.Creator<T> creator;
+        synchronized (mCreators) {
+            HashMap<String,Parcelable.Creator> map = mCreators.get(loader);
+            if (map == null) {
+                map = new HashMap<String,Parcelable.Creator>();
+                mCreators.put(loader, map);
+            }
+            creator = map.get(name);
+            if (creator == null) {
+                try {
+                    Class c = loader == null ?
+                        Class.forName(name) : Class.forName(name, true, loader);
+                    Field f = c.getField("CREATOR");
+                    creator = (Parcelable.Creator)f.get(null);
+                }
+                catch (IllegalAccessException e) {
+                    Log.e("Parcel", "Class not found when unmarshalling: "
+                                        + name + ", e: " + e);
+                    throw new BadParcelableException(
+                            "IllegalAccessException when unmarshalling: " + name);
+                }
+                catch (ClassNotFoundException e) {
+                    Log.e("Parcel", "Class not found when unmarshalling: "
+                                        + name + ", e: " + e);
+                    throw new BadParcelableException(
+                            "ClassNotFoundException when unmarshalling: " + name);
+                }
+                catch (ClassCastException e) {
+                    throw new BadParcelableException("Parcelable protocol requires a "
+                                        + "Parcelable.Creator object called "
+                                        + " CREATOR on class " + name);
+                }
+                catch (NoSuchFieldException e) {
+                    throw new BadParcelableException("Parcelable protocol requires a "
+                                        + "Parcelable.Creator object called "
+                                        + " CREATOR on class " + name);
+                }
+                if (creator == null) {
+                    throw new BadParcelableException("Parcelable protocol requires a "
+                                        + "Parcelable.Creator object called "
+                                        + " CREATOR on class " + name);
+                }
+
+                map.put(name, creator);
+            }
+        }
+
+        return creator.createFromParcel(this);
+    }
+
+    /**
+     * Read and return a new Parcelable array from the parcel.
+     * The given class loader will be used to load any enclosed
+     * Parcelables.
+     * @return the Parcelable array, or null if the array is null
+     */
+    public final Parcelable[] readParcelableArray(ClassLoader loader) {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        Parcelable[] p = new Parcelable[N];
+        for (int i = 0; i < N; i++) {
+            p[i] = (Parcelable) readParcelable(loader);
+        }
+        return p;
+    }
+
+    /**
+     * Read and return a new Serializable object from the parcel.
+     * @return the Serializable object, or null if the Serializable name
+     * wasn't found in the parcel.
+     */
+    public final Serializable readSerializable() {
+        String name = readString();
+        if (name == null) {
+            // For some reason we were unable to read the name of the Serializable (either there
+            // is nothing left in the Parcel to read, or the next value wasn't a String), so
+            // return null, which indicates that the name wasn't found in the parcel.
+            return null;
+        }
+
+        byte[] serializedData = createByteArray();
+        ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);
+        try {
+            ObjectInputStream ois = new ObjectInputStream(bais);
+            return (Serializable) ois.readObject();
+        } catch (IOException ioe) {
+            throw new RuntimeException("Parcelable encountered " +
+                "IOException reading a Serializable object (name = " + name +
+                ")", ioe);
+        } catch (ClassNotFoundException cnfe) {
+            throw new RuntimeException("Parcelable encountered" +
+                "ClassNotFoundException reading a Serializable object (name = "
+                + name + ")", cnfe);
+        }
+    }
+
+    // Cache of previously looked up CREATOR.createFromParcel() methods for
+    // particular classes.  Keys are the names of the classes, values are
+    // Method objects.
+    private static final HashMap<ClassLoader,HashMap<String,Parcelable.Creator>>
+        mCreators = new HashMap<ClassLoader,HashMap<String,Parcelable.Creator>>();
+
+    static protected final Parcel obtain(int obj) {
+        final Parcel[] pool = sHolderPool;
+        synchronized (pool) {
+            Parcel p;
+            for (int i=0; i<POOL_SIZE; i++) {
+                p = pool[i];
+                if (p != null) {
+                    pool[i] = null;
+                    if (DEBUG_RECYCLE) {
+                        p.mStack = new RuntimeException();
+                    }
+                    p.init(obj);
+                    return p;
+                }
+            }
+        }
+        return new Parcel(obj);
+    }
+
+    private Parcel(int obj) {
+        if (DEBUG_RECYCLE) {
+            mStack = new RuntimeException();
+        }
+        //Log.i("Parcel", "Initializing obj=0x" + Integer.toHexString(obj), mStack);
+        init(obj);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        if (DEBUG_RECYCLE) {
+            if (mStack != null) {
+                Log.w("Parcel", "Client did not call Parcel.recycle()", mStack);
+            }
+        }
+        destroy();
+    }
+
+    private native void freeBuffer();
+    private native void init(int obj);
+    private native void destroy();
+
+    private void readMapInternal(Map outVal, int N,
+        ClassLoader loader) {
+        while (N > 0) {
+            Object key = readValue(loader);
+            Object value = readValue(loader);
+            outVal.put(key, value);
+            N--;
+        }
+    }
+
+    private void readListInternal(List outVal, int N,
+        ClassLoader loader) {
+        while (N > 0) {
+            Object value = readValue(loader);
+            //Log.d("Parcel", "Unmarshalling value=" + value);
+            outVal.add(value);
+            N--;
+        }
+    }
+
+    private void readArrayInternal(Object[] outVal, int N,
+        ClassLoader loader) {
+        for (int i = 0; i < N; i++) {
+            Object value = readValue(loader);
+            //Log.d("Parcel", "Unmarshalling value=" + value);
+            outVal[i] = value;
+        }
+    }
+
+    private void readSparseArrayInternal(SparseArray outVal, int N,
+        ClassLoader loader) {
+        while (N > 0) {
+            int key = readInt();
+            Object value = readValue(loader);
+            //Log.i("Parcel", "Unmarshalling key=" + key + " value=" + value);
+            outVal.append(key, value);
+            N--;
+        }
+    }
+
+
+    private void readSparseBooleanArrayInternal(SparseBooleanArray outVal, int N) {
+        while (N > 0) {
+            int key = readInt();
+            boolean value = this.readByte() == 1;
+            //Log.i("Parcel", "Unmarshalling key=" + key + " value=" + value);
+            outVal.append(key, value);
+            N--;
+        }
+    }
+}
diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/core/java/android/os/ParcelFileDescriptor.aidl
new file mode 100644
index 0000000..5857aae
--- /dev/null
+++ b/core/java/android/os/ParcelFileDescriptor.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/os/ParcelFileDescriptor.aidl
+**
+** Copyright 2007, 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 android.os;
+
+parcelable ParcelFileDescriptor;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
new file mode 100644
index 0000000..3fcb18e
--- /dev/null
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+
+/**
+ * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
+ * you to close it when done with it.
+ */
+public class ParcelFileDescriptor implements Parcelable {
+    private final FileDescriptor mFileDescriptor;
+    private boolean mClosed;
+    //this field is to create wrapper for ParcelFileDescriptor using another
+    //PartialFileDescriptor but avoid invoking close twice
+    //consider ParcelFileDescriptor A(fileDescriptor fd),  ParcelFileDescriptor B(A)
+    //in this particular case fd.close might be invoked twice.
+    private final ParcelFileDescriptor mParcelDescriptor;
+    
+    /**
+     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
+     * and this file doesn't already exist, then create the file with
+     * permissions such that any application can read it.
+     */
+    public static final int MODE_WORLD_READABLE = 0x00000001;
+    
+    /**
+     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
+     * and this file doesn't already exist, then create the file with
+     * permissions such that any application can write it.
+     */
+    public static final int MODE_WORLD_WRITEABLE = 0x00000002;
+    
+    /**
+     * For use with {@link #open}: open the file with read-only access.
+     */
+    public static final int MODE_READ_ONLY = 0x10000000;
+    
+    /**
+     * For use with {@link #open}: open the file with write-only access.
+     */
+    public static final int MODE_WRITE_ONLY = 0x20000000;
+    
+    /**
+     * For use with {@link #open}: open the file with read and write access.
+     */
+    public static final int MODE_READ_WRITE = 0x30000000;
+    
+    /**
+     * For use with {@link #open}: create the file if it doesn't already exist.
+     */
+    public static final int MODE_CREATE = 0x08000000;
+    
+    /**
+     * For use with {@link #open}: erase contents of file when opening.
+     */
+    public static final int MODE_TRUNCATE = 0x04000000;
+    
+    /**
+     * For use with {@link #open}: append to end of file while writing.
+     */
+    public static final int MODE_APPEND = 0x02000000;
+    
+    /**
+     * Create a new ParcelFileDescriptor accessing a given file.
+     * 
+     * @param file The file to be opened.
+     * @param mode The desired access mode, must be one of
+     * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
+     * {@link #MODE_READ_WRITE}; may also be any combination of
+     * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
+     * {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
+     * 
+     * @return Returns a new ParcelFileDescriptor pointing to the given
+     * file.
+     * 
+     * @throws FileNotFoundException Throws FileNotFoundException if the given
+     * file does not exist or can not be opened with the requested mode.
+     */
+    public static ParcelFileDescriptor open(File file, int mode)
+            throws FileNotFoundException {
+        String path = file.getPath();
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+            if ((mode&MODE_WRITE_ONLY) != 0) {
+                security.checkWrite(path);
+            }
+        }
+        
+        if ((mode&MODE_READ_WRITE) == 0) {
+            throw new IllegalArgumentException(
+                    "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
+        }
+        
+        FileDescriptor fd = Parcel.openFileDescriptor(path, mode);
+        return new ParcelFileDescriptor(fd);
+    }
+
+    /**
+     * Create a new ParcelFileDescriptor from the specified Socket.
+     *
+     * @param socket The Socket whose FileDescriptor is used to create
+     *               a new ParcelFileDescriptor.
+     *
+     * @return A new ParcelFileDescriptor with the FileDescriptor of the
+     *         specified Socket.
+     */
+    public static ParcelFileDescriptor fromSocket(Socket socket) {
+        FileDescriptor fd = getFileDescriptorFromSocket(socket);
+        return new ParcelFileDescriptor(fd);
+    }
+
+    // Extracts the file descriptor from the specified socket and returns it untouched
+    private static native FileDescriptor getFileDescriptorFromSocket(Socket socket);
+
+    /**
+     * Retrieve the actual FileDescriptor associated with this object.
+     * 
+     * @return Returns the FileDescriptor associated with this object.
+     */
+    public FileDescriptor getFileDescriptor() {
+        return mFileDescriptor;
+    }
+    
+    /**
+     * Return the total size of the file representing this fd, as determined
+     * by stat().  Returns -1 if the fd is not a file.
+     */
+    public native long getStatSize();
+    
+    /**
+     * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
+     * and I really don't think we want it to be public.
+     * @hide
+     */
+    public native long seekTo(long pos);
+    
+    /**
+     * Close the ParcelFileDescriptor. This implementation closes the underlying
+     * OS resources allocated to represent this stream.
+     * 
+     * @throws IOException
+     *             If an error occurs attempting to close this ParcelFileDescriptor.
+     */
+    public void close() throws IOException {
+        mClosed = true;
+        if (mParcelDescriptor != null) {
+            // If this is a proxy to another file descriptor, just call through to its
+            // close method.
+            mParcelDescriptor.close();
+        } else {
+            Parcel.closeFileDescriptor(mFileDescriptor);
+        }
+    }
+    
+    /**
+     * An InputStream you can create on a ParcelFileDescriptor, which will
+     * take care of calling {@link ParcelFileDescriptor#close
+     * ParcelFileDescritor.close()} for you when the stream is closed.
+     */
+    public static class AutoCloseInputStream extends FileInputStream {
+        private final ParcelFileDescriptor mFd;
+        
+        public AutoCloseInputStream(ParcelFileDescriptor fd) {
+            super(fd.getFileDescriptor());
+            mFd = fd;
+        }
+
+        @Override
+        public void close() throws IOException {
+            mFd.close();
+        }
+    }
+    
+    /**
+     * An OutputStream you can create on a ParcelFileDescriptor, which will
+     * take care of calling {@link ParcelFileDescriptor#close
+     * ParcelFileDescritor.close()} for you when the stream is closed.
+     */
+    public static class AutoCloseOutputStream extends FileOutputStream {
+        private final ParcelFileDescriptor mFd;
+        
+        public AutoCloseOutputStream(ParcelFileDescriptor fd) {
+            super(fd.getFileDescriptor());
+            mFd = fd;
+        }
+
+        @Override
+        public void close() throws IOException {
+            mFd.close();
+        }
+    }
+    
+    @Override
+    public String toString() {
+        return "{ParcelFileDescriptor: " + mFileDescriptor + "}";
+    }
+    
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (!mClosed) {
+                close();
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+    
+    public ParcelFileDescriptor(ParcelFileDescriptor descriptor) {
+        super();
+        mParcelDescriptor = descriptor;
+        mFileDescriptor = mParcelDescriptor.mFileDescriptor;
+    }
+    
+    /*package */ParcelFileDescriptor(FileDescriptor descriptor) {
+        super();
+        mFileDescriptor = descriptor;
+        mParcelDescriptor = null;
+    }
+    
+    /* Parcelable interface */
+    public int describeContents() {
+        return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeFileDescriptor(mFileDescriptor);
+        if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
+            try {
+                close();
+            } catch (IOException e) {
+                // Empty
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
+            = new Parcelable.Creator<ParcelFileDescriptor>() {
+        public ParcelFileDescriptor createFromParcel(Parcel in) {
+            return in.readFileDescriptor();
+        }
+        public ParcelFileDescriptor[] newArray(int size) {
+            return new ParcelFileDescriptor[size];
+        }
+    };
+
+}
diff --git a/core/java/android/os/ParcelFormatException.java b/core/java/android/os/ParcelFormatException.java
new file mode 100644
index 0000000..8b6fda0
--- /dev/null
+++ b/core/java/android/os/ParcelFormatException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * The contents of a Parcel (usually during unmarshalling) does not
+ * contain the expected data.
+ */
+public class ParcelFormatException extends RuntimeException {
+    public ParcelFormatException() {
+        super();
+    }
+
+    public ParcelFormatException(String reason) {
+        super(reason);
+    }
+}
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
new file mode 100644
index 0000000..aee1e0b
--- /dev/null
+++ b/core/java/android/os/Parcelable.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * Interface for classes whose instances can be written to
+ * and restored from a {@link Parcel}.  Classes implementing the Parcelable
+ * interface must also have a static field called <code>CREATOR</code>, which
+ * is an object implementing the {@link Parcelable.Creator Parcelable.Creator}
+ * interface.
+ * 
+ * <p>A typical implementation of Parcelable is:</p>
+ * 
+ * <pre>
+ * public class MyParcelable implements Parcelable {
+ *     private int mData;
+ *     
+ *     public void writeToParcel(Parcel out, int flags) {
+ *         out.writeInt(mData);
+ *     }
+ *
+ *     public static final Parcelable.Creator<MyParcelable> CREATOR
+ *             = new Parcelable.Creator<MyParcelable>() {
+ *         public MyParcelable createFromParcel(Parcel in) {
+ *             return new MyParcelable(in);
+ *         }
+ *
+ *         public MyParcelable[] newArray(int size) {
+ *             return new MyParcelable[size];
+ *         }
+ *     }
+ *     
+ *     private MyParcelable(Parcel in) {
+ *         mData = in.readInt();
+ *     }
+ * }</pre>
+ */
+public interface Parcelable {
+    /**
+     * Flag for use with {@link #writeToParcel}: the object being written
+     * is a return value, that is the result of a function such as
+     * "<code>Parcelable someFunction()</code>",
+     * "<code>void someFunction(out Parcelable)</code>", or
+     * "<code>void someFunction(inout Parcelable)</code>".  Some implementations
+     * may want to release resources at this point.
+     */
+    public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
+    
+    /**
+     * Bit masks for use with {@link #describeContents}: each bit represents a
+     * kind of object considered to have potential special significance when
+     * marshalled.
+     */
+    public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;
+    
+    /**
+     * Describe the kinds of special objects contained in this Parcelable's
+     * marshalled representation.
+     *  
+     * @return a bitmask indicating the set of special object types marshalled
+     * by the Parcelable.
+     */
+    public int describeContents();
+    
+    /**
+     * Flatten this object in to a Parcel.
+     * 
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    public void writeToParcel(Parcel dest, int flags);
+
+    /**
+     * Interface that must be implemented and provided as a public CREATOR
+     * field that generates instances of your Parcelable class from a Parcel.
+     */
+    public interface Creator<T> {
+        /**
+         * Create a new instance of the Parcelable class, instantiating it
+         * from the given Parcel whose data had previously been written by
+         * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
+         * 
+         * @param source The Parcel to read the object's data from.
+         * @return Returns a new instance of the Parcelable class.
+         */
+        public T createFromParcel(Parcel source);
+        
+        /**
+         * Create a new array of the Parcelable class.
+         * 
+         * @param size Size of the array.
+         * @return Returns an array of the Parcelable class, with every entry
+         * initialized to null.
+         */
+        public T[] newArray(int size);
+    }
+}
diff --git a/core/java/android/os/PatternMatcher.aidl b/core/java/android/os/PatternMatcher.aidl
new file mode 100644
index 0000000..86309f1
--- /dev/null
+++ b/core/java/android/os/PatternMatcher.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+parcelable PatternMatcher;
diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
new file mode 100644
index 0000000..56dc837
--- /dev/null
+++ b/core/java/android/os/PatternMatcher.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+/**
+ * A simple pattern matcher, which is safe to use on untrusted data: it does
+ * not provide full reg-exp support, only simple globbing that can not be
+ * used maliciously.
+ */
+public class PatternMatcher implements Parcelable {
+    /**
+     * Pattern type: the given pattern must exactly match the string it is
+     * tested against.
+     */
+    public static final int PATTERN_LITERAL = 0;
+    
+    /**
+     * Pattern type: the given pattern must match the
+     * beginning of the string it is tested against.
+     */
+    public static final int PATTERN_PREFIX = 1;
+    
+    /**
+     * Pattern type: the given pattern is interpreted with a
+     * simple glob syntax for matching against the string it is tested against.
+     * In this syntax, you can use the '*' character to match against zero or
+     * more occurrences of the character immediately before.  If the
+     * character before it is '.' it will match any character.  The character
+     * '\' can be used as an escape.  This essentially provides only the '*'
+     * wildcard part of a normal regexp. 
+     */
+    public static final int PATTERN_SIMPLE_GLOB = 2;
+    
+    private final String mPattern;
+    private final int mType;
+    
+    public PatternMatcher(String pattern, int type) {
+        mPattern = pattern;
+        mType = type;
+    }
+
+    public final String getPath() {
+        return mPattern;
+    }
+    
+    public final int getType() {
+        return mType;
+    }
+    
+    public boolean match(String str) {
+        return matchPattern(mPattern, str, mType);
+    }
+
+    public String toString() {
+        String type = "? ";
+        switch (mType) {
+            case PATTERN_LITERAL:
+                type = "LITERAL: ";
+                break;
+            case PATTERN_PREFIX:
+                type = "PREFIX: ";
+                break;
+            case PATTERN_SIMPLE_GLOB:
+                type = "GLOB: ";
+                break;
+        }
+        return "PatternMatcher{" + type + mPattern + "}";
+    }
+    
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mPattern);
+        dest.writeInt(mType);
+    }
+    
+    public PatternMatcher(Parcel src) {
+        mPattern = src.readString();
+        mType = src.readInt();
+    }
+    
+    public static final Parcelable.Creator<PatternMatcher> CREATOR
+            = new Parcelable.Creator<PatternMatcher>() {
+        public PatternMatcher createFromParcel(Parcel source) {
+            return new PatternMatcher(source);
+        }
+
+        public PatternMatcher[] newArray(int size) {
+            return new PatternMatcher[size];
+        }
+    };
+    
+    static boolean matchPattern(String pattern, String match, int type) {
+        if (match == null) return false;
+        if (type == PATTERN_LITERAL) {
+            return pattern.equals(match);
+        } if (type == PATTERN_PREFIX) {
+            return match.startsWith(pattern);
+        } else if (type != PATTERN_SIMPLE_GLOB) {
+            return false;
+        }
+        
+        final int NP = pattern.length();
+        if (NP <= 0) {
+            return match.length() <= 0;
+        }
+        final int NM = match.length();
+        int ip = 0, im = 0;
+        char nextChar = pattern.charAt(0);
+        while ((ip<NP) && (im<NM)) {
+            char c = nextChar;
+            ip++;
+            nextChar = ip < NP ? pattern.charAt(ip) : 0;
+            final boolean escaped = (c == '\\');
+            if (escaped) {
+                c = nextChar;
+                ip++;
+                nextChar = ip < NP ? pattern.charAt(ip) : 0;
+            }
+            if (nextChar == '*') {
+                if (!escaped && c == '.') {
+                    if (ip >= (NP-1)) {
+                        // at the end with a pattern match, so
+                        // all is good without checking!
+                        return true;
+                    }
+                    ip++;
+                    nextChar = pattern.charAt(ip);
+                    // Consume everything until the next character in the
+                    // pattern is found.
+                    if (nextChar == '\\') {
+                        ip++;
+                        nextChar = ip < NP ? pattern.charAt(ip) : 0;
+                    }
+                    do {
+                        if (match.charAt(im) == nextChar) {
+                            break;
+                        }
+                        im++;
+                    } while (im < NM);
+                    if (im == NM) {
+                        // Whoops, the next character in the pattern didn't
+                        // exist in the match.
+                        return false;
+                    }
+                    ip++;
+                    nextChar = ip < NP ? pattern.charAt(ip) : 0;
+                    im++;
+                } else {
+                    // Consume only characters matching the one before '*'.
+                    do {
+                        if (match.charAt(im) != c) {
+                            break;
+                        }
+                        im++;
+                    } while (im < NM);
+                    ip++;
+                    nextChar = ip < NP ? pattern.charAt(ip) : 0;
+                }
+            } else {
+                if (c != '.' && match.charAt(im) != c) return false;
+                im++;
+            }
+        }
+        
+        if (ip >= NP && im >= NM) {
+            // Reached the end of both strings, all is good!
+            return true;
+        }
+        
+        // One last check: we may have finished the match string, but still
+        // have a '.*' at the end of the pattern, which should still count
+        // as a match.
+        if (ip == NP-2 && pattern.charAt(ip) == '.'
+            && pattern.charAt(ip+1) == '*') {
+            return true;
+        }
+        
+        return false;
+    }
+}
diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java
new file mode 100644
index 0000000..b53e227
--- /dev/null
+++ b/core/java/android/os/Power.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import java.io.IOException;
+
+/**
+ * Class that provides access to some of the power management functions.
+ *
+ * {@hide}
+ */
+public class Power
+{
+    // can't instantiate this class
+    private Power()
+    {
+    }
+
+    /**
+     * Wake lock that ensures that the CPU is running.  The screen might
+     * not be on.
+     */
+    public static final int PARTIAL_WAKE_LOCK = 1;
+
+    /**
+     * Wake lock that ensures that the screen is on.
+     */
+    public static final int FULL_WAKE_LOCK = 2;
+
+    public static native void acquireWakeLock(int lock, String id);
+    public static native void releaseWakeLock(String id);
+
+    /**
+     * Flag to turn on and off the keyboard light.
+     */
+    public static final int KEYBOARD_LIGHT = 0x00000001;
+
+    /**
+     * Flag to turn on and off the screen backlight.
+     */
+    public static final int SCREEN_LIGHT = 0x00000002;
+
+    /**
+     * Flag to turn on and off the button backlight.
+     */
+    public static final int BUTTON_LIGHT = 0x00000004;
+
+    /**
+     * Flags to turn on and off all the backlights.
+     */
+    public static final int ALL_LIGHTS = (KEYBOARD_LIGHT|SCREEN_LIGHT|BUTTON_LIGHT);
+
+    /**
+     * Brightness value for fully off
+     */
+    public static final int BRIGHTNESS_OFF = 0;
+
+    /**
+     * Brightness value for dim backlight
+     */
+    public static final int BRIGHTNESS_DIM = 20;
+
+    /**
+     * Brightness value for fully on
+     */
+    public static final int BRIGHTNESS_ON = 255;
+
+    /**
+     * Brightness value to use when battery is low
+     */
+    public static final int BRIGHTNESS_LOW_BATTERY = 10;
+
+    /**
+     * Threshold for BRIGHTNESS_LOW_BATTERY (percentage)
+     * Screen will stay dim if battery level is <= LOW_BATTERY_THRESHOLD
+     */
+    public static final int LOW_BATTERY_THRESHOLD = 10;
+
+    /**
+     * Set the brightness for one or more lights
+     *
+     * @param mask flags indicating which lights to change brightness
+     * @param brightness new brightness value (0 = off, 255 = fully bright)
+     */
+    public static native int setLightBrightness(int mask, int brightness);
+
+    /**
+     * Turn the screen on or off
+     *
+     * @param on Whether you want the screen on or off
+     */
+    public static native int setScreenState(boolean on);
+
+    public static native int setLastUserActivityTimeout(long ms);
+
+    /**
+     * Turn the device off.
+     *
+     * This method is considered deprecated in favor of
+     * {@link android.policy.ShutdownThread.shutdownAfterDisablingRadio()}.
+     *
+     * @deprecated
+     * @hide
+     */
+    @Deprecated
+    public static native void shutdown();
+
+    /**
+     * Reboot the device.
+     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
+     *
+     * @throws IOException if reboot fails for some reason (eg, lack of
+     *         permission)
+     */
+    public static native void reboot(String reason) throws IOException;
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
new file mode 100644
index 0000000..bfcf2fc
--- /dev/null
+++ b/core/java/android/os/PowerManager.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import android.util.Log;
+
+import com.android.internal.os.RuntimeInit;
+
+/**
+ * This class gives you control of the power state of the device.  
+ * 
+ * <p><b>Device battery life will be significantly affected by the use of this API.</b>  Do not
+ * acquire WakeLocks unless you really need them, use the minimum levels possible, and be sure
+ * to release it as soon as you can.
+ * 
+ * <p>You can obtain an instance of this class by calling 
+ * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
+ * 
+ * <p>The primary API you'll use is {@link #newWakeLock(int, String) newWakeLock()}.  This will
+ * create a {@link PowerManager.WakeLock} object.  You can then use methods on this object to 
+ * control the power state of the device.  In practice it's quite simple:
+ * 
+ * {@samplecode
+ * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ * PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
+ * wl.acquire();
+ *   ..screen will stay on during this section..
+ * wl.release();
+ * }
+ * 
+ * <p>The following flags are defined, with varying effects on system power.  <i>These flags are
+ * mutually exclusive - you may only specify one of them.</i>
+ * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+ *
+ *     <thead>
+ *     <tr><th>Flag Value</th> 
+ *     <th>CPU</th> <th>Screen</th> <th>Keyboard</th></tr>
+ *     </thead>
+ *
+ *     <tbody>
+ *     <tr><th>{@link #PARTIAL_WAKE_LOCK}</th>
+ *         <td>On*</td> <td>Off</td> <td>Off</td> 
+ *     </tr>
+ *     
+ *     <tr><th>{@link #SCREEN_DIM_WAKE_LOCK}</th>
+ *         <td>On</td> <td>Dim</td> <td>Off</td> 
+ *     </tr>
+ *
+ *     <tr><th>{@link #SCREEN_BRIGHT_WAKE_LOCK}</th>
+ *         <td>On</td> <td>Bright</td> <td>Off</td> 
+ *     </tr>
+ *     
+ *     <tr><th>{@link #FULL_WAKE_LOCK}</th>
+ *         <td>On</td> <td>Bright</td> <td>Bright</td> 
+ *     </tr>
+ *     </tbody>
+ * </table>
+ * 
+ * <p>*<i>If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers 
+ * and even after the user presses the power button.  In all other wakelocks, the CPU will run, but
+ * the user can still put the device to sleep using the power button.</i>
+ * 
+ * <p>In addition, you can add two more flags, which affect behavior of the screen only.  <i>These
+ * flags have no effect when combined with a {@link #PARTIAL_WAKE_LOCK}.</i>
+ * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+ *
+ *     <thead>
+ *     <tr><th>Flag Value</th> <th>Description</th></tr>
+ *     </thead>
+ *
+ *     <tbody>
+ *     <tr><th>{@link #ACQUIRE_CAUSES_WAKEUP}</th>
+ *         <td>Normal wake locks don't actually turn on the illumination.  Instead, they cause
+ *         the illumination to remain on once it turns on (e.g. from user activity).  This flag
+ *         will force the screen and/or keyboard to turn on immediately, when the WakeLock is
+ *         acquired.  A typical use would be for notifications which are important for the user to
+ *         see immediately.</td> 
+ *     </tr>
+ *     
+ *     <tr><th>{@link #ON_AFTER_RELEASE}</th>
+ *         <td>If this flag is set, the user activity timer will be reset when the WakeLock is
+ *         released, causing the illumination to remain on a bit longer.  This can be used to 
+ *         reduce flicker if you are cycling between wake lock conditions.</td> 
+ *     </tr>
+ *     </tbody>
+ * </table>
+ * 
+ * 
+ */
+public class PowerManager
+{
+    private static final String TAG = "PowerManager";
+    
+    /**
+     * These internal values define the underlying power elements that we might
+     * want to control individually.  Eventually we'd like to expose them.
+     */
+    private static final int WAKE_BIT_CPU_STRONG = 1;
+    private static final int WAKE_BIT_CPU_WEAK = 2;
+    private static final int WAKE_BIT_SCREEN_DIM = 4;
+    private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
+    private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
+    
+    private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
+                                        | WAKE_BIT_CPU_WEAK
+                                        | WAKE_BIT_SCREEN_DIM
+                                        | WAKE_BIT_SCREEN_BRIGHT
+                                        | WAKE_BIT_KEYBOARD_BRIGHT;
+
+    /**
+     * Wake lock that ensures that the CPU is running.  The screen might
+     * not be on.
+     */
+    public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG;
+
+    /**
+     * Wake lock that ensures that the screen and keyboard are on at
+     * full brightness.
+     */
+    public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT 
+                                            | WAKE_BIT_KEYBOARD_BRIGHT;
+
+    /**
+     * Wake lock that ensures that the screen is on at full brightness;
+     * the keyboard backlight will be allowed to go off.
+     */
+    public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;
+
+    /**
+     * Wake lock that ensures that the screen is on (but may be dimmed);
+     * the keyboard backlight will be allowed to go off.
+     */
+    public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
+
+    /**
+     * Normally wake locks don't actually wake the device, they just cause
+     * it to remain on once it's already on.  Think of the video player
+     * app as the normal behavior.  Notifications that pop up and want
+     * the device to be on are the exception; use this flag to be like them.
+     * <p> 
+     * Does not work with PARTIAL_WAKE_LOCKs.
+     */
+    public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
+
+    /**
+     * When this wake lock is released, poke the user activity timer
+     * so the screen stays on for a little longer.
+     * <p>
+     * Will not turn the screen on if it is not already on.  See {@link #ACQUIRE_CAUSES_WAKEUP}
+     * if you want that.
+     * <p>
+     * Does not work with PARTIAL_WAKE_LOCKs.
+     */
+    public static final int ON_AFTER_RELEASE = 0x20000000;
+    
+    /**
+     * Class lets you say that you need to have the device on.
+     *
+     * <p>Call release when you are done and don't need the lock anymore.
+     */
+    public class WakeLock
+    {
+        static final int RELEASE_WAKE_LOCK = 1;
+
+        Runnable mReleaser = new Runnable() {
+            public void run() {
+                release();
+            }
+        };
+	
+        int mFlags;
+        String mTag;
+        IBinder mToken;
+        int mCount = 0;
+        boolean mRefCounted = true;
+        boolean mHeld = false;
+
+        WakeLock(int flags, String tag)
+        {
+            switch (flags & LOCK_MASK) {
+            case PARTIAL_WAKE_LOCK:
+            case SCREEN_DIM_WAKE_LOCK:
+            case SCREEN_BRIGHT_WAKE_LOCK:
+            case FULL_WAKE_LOCK:
+                break;
+            default:
+                throw new IllegalArgumentException();
+            }
+
+            mFlags = flags;
+            mTag = tag;
+            mToken = new Binder();
+        }
+
+        /**
+         * Sets whether this WakeLock is ref counted.
+         *
+         * @param value true for ref counted, false for not ref counted.
+         */
+        public void setReferenceCounted(boolean value)
+        {
+            mRefCounted = value;
+        }
+
+        /**
+         * Makes sure the device is on at the level you asked when you created
+         * the wake lock.
+         */
+        public void acquire()
+        {
+            synchronized (mToken) {
+                if (!mRefCounted || mCount++ == 0) {
+                    try {
+                        mService.acquireWakeLock(mFlags, mToken, mTag);
+                    } catch (RemoteException e) {
+                    }
+                    mHeld = true;
+                }
+            }
+        }
+        
+        /**
+         * Makes sure the device is on at the level you asked when you created
+         * the wake lock. The lock will be released after the given timeout.
+         * 
+         * @param timeout Release the lock after the give timeout in milliseconds.
+         */
+        public void acquire(long timeout) {
+            acquire();
+            mHandler.postDelayed(mReleaser, timeout);
+        }
+        
+
+        /**
+         * Release your claim to the CPU or screen being on.
+         *
+         * <p>
+         * It may turn off shortly after you release it, or it may not if there
+         * are other wake locks held.
+         */
+        public void release()
+        {
+            synchronized (mToken) {
+                if (!mRefCounted || --mCount == 0) {
+                    try {
+                        mService.releaseWakeLock(mToken);
+                    } catch (RemoteException e) {
+                    }
+                    mHeld = false;
+                }
+                if (mCount < 0) {
+                    throw new RuntimeException("WakeLock under-locked " + mTag);
+                }
+            }
+        }
+
+        public boolean isHeld()
+        {
+            synchronized (mToken) {
+                return mHeld;
+            }
+        }
+
+        public String toString() {
+            synchronized (mToken) {
+                return "WakeLock{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " held=" + mHeld + ", refCount=" + mCount + "}";
+            }
+        }
+
+        @Override
+        protected void finalize() throws Throwable
+        {
+            synchronized (mToken) {
+                if (mHeld) {
+                    try {
+                        mService.releaseWakeLock(mToken);
+                    } catch (RemoteException e) {
+                    }
+                    RuntimeInit.crash(TAG, new Exception(
+                                "WakeLock finalized while still held: "+mTag));
+                }
+            }
+        }
+    }
+
+    /**
+     * Get a wake lock at the level of the flags parameter.  Call
+     * {@link WakeLock#acquire() acquire()} on the object to acquire the
+     * wake lock, and {@link WakeLock#release release()} when you are done.
+     *
+     * {@samplecode
+     *PowerManager pm = (PowerManager)mContext.getSystemService(
+     *                                          Context.POWER_SERVICE);
+     *PowerManager.WakeLock wl = pm.newWakeLock(
+     *                                      PowerManager.SCREEN_DIM_WAKE_LOCK
+     *                                      | PowerManager.ON_AFTER_RELEASE,
+     *                                      TAG);
+     *wl.acquire();
+     * // ...
+     *wl.release();
+     * }
+     *
+     * @param flags Combination of flag values defining the requested behavior of the WakeLock.
+     * @param tag Your class name (or other tag) for debugging purposes.
+     *
+     * @see WakeLock#acquire()
+     * @see WakeLock#release()
+     */
+    public WakeLock newWakeLock(int flags, String tag)
+    {
+        return new WakeLock(flags, tag);
+    }
+
+    /**
+     * User activity happened.
+     * <p>
+     * Turns the device from whatever state it's in to full on, and resets
+     * the auto-off timer.
+     *
+     * @param when is used to order this correctly with the wake lock calls.
+     *          This time should be in the {@link SystemClock#uptimeMillis
+     *          SystemClock.uptimeMillis()} time base.
+     * @param noChangeLights should be true if you don't want the lights to
+     *          turn on because of this event.  This is set when the power
+     *          key goes down.  We want the device to stay on while the button
+     *          is down, but we're about to turn off.  Otherwise the lights
+     *          flash on and then off and it looks weird.
+     */
+    public void userActivity(long when, boolean noChangeLights)
+    {
+        try {
+            mService.userActivity(when, noChangeLights);
+        } catch (RemoteException e) {
+        }
+    }
+
+   /**
+     * Force the device to go to sleep. Overrides all the wake locks that are
+     * held.
+     * 
+     * @param time is used to order this correctly with the wake lock calls. 
+     *          The time  should be in the {@link SystemClock#uptimeMillis 
+     *          SystemClock.uptimeMillis()} time base.
+     */
+    public void goToSleep(long time) 
+    {
+        try {
+            mService.goToSleep(time);
+        } catch (RemoteException e) {
+        }
+    }
+    
+    private PowerManager()
+    {
+    }
+
+    /**
+     * {@hide}
+     */
+    public PowerManager(IPowerManager service, Handler handler)
+    {
+        mService = service;
+        mHandler = handler;
+    }
+
+    /**
+     *  TODO: It would be nice to be able to set the poke lock here,
+     *  but I'm not sure what would be acceptable as an interface -
+     *  either a PokeLock object (like WakeLock) or, possibly just a
+     *  method call to set the poke lock. 
+     */
+    
+    IPowerManager mService;
+    Handler mHandler;
+}
+
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
new file mode 100644
index 0000000..cd86fbe
--- /dev/null
+++ b/core/java/android/os/Process.java
@@ -0,0 +1,706 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.net.LocalSocketAddress;
+import android.net.LocalSocket;
+import android.util.Log;
+import dalvik.system.Zygote;
+
+import java.io.BufferedWriter;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+
+/*package*/ class ZygoteStartFailedEx extends Exception {
+    /**
+     * Something prevented the zygote process startup from happening normally
+     */
+
+    ZygoteStartFailedEx() {};
+    ZygoteStartFailedEx(String s) {super(s);}
+    ZygoteStartFailedEx(Throwable cause) {super(cause);}
+}
+
+/**
+ * Tools for managing OS processes.
+ */
+public class Process {
+    private static final String LOG_TAG = "Process";
+
+    private static final String ZYGOTE_SOCKET = "zygote";
+
+    /**
+     * Name of a process for running the platform's media services.
+     * {@hide}
+     */
+    public static final String ANDROID_SHARED_MEDIA = "com.android.process.media";
+
+    /**
+     * Name of the process that Google content providers can share.
+     * {@hide}
+     */
+    public static final String GOOGLE_SHARED_APP_CONTENT = "com.google.process.content";
+
+    /**
+     * Defines the UID/GID under which system code runs.
+     */
+    public static final int SYSTEM_UID = 1000;
+
+    /**
+     * Defines the UID/GID under which the telephony code runs.
+     */
+    public static final int PHONE_UID = 1001;
+
+    /**
+     * Defines the start of a range of UIDs (and GIDs), going from this
+     * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
+     * to applications.
+     */
+    public static final int FIRST_APPLICATION_UID = 10000;
+    /**
+     * Last of application-specific UIDs starting at
+     * {@link #FIRST_APPLICATION_UID}.
+     */
+    public static final int LAST_APPLICATION_UID = 99999;
+
+    /**
+     * Defines a secondary group id for access to the bluetooth hardware.
+     */
+    public static final int BLUETOOTH_GID = 2000;
+    
+    /**
+     * Standard priority of application threads.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_DEFAULT = 0;
+
+    /*
+     * ***************************************
+     * ** Keep in sync with utils/threads.h **
+     * ***************************************
+     */
+    
+    /**
+     * Lowest available thread priority.  Only for those who really, really
+     * don't want to run if anything else is happening.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_LOWEST = 19;
+    
+    /**
+     * Standard priority background threads.  This gives your thread a slightly
+     * lower than normal priority, so that it will have less chance of impacting
+     * the responsiveness of the user interface.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_BACKGROUND = 10;
+    
+    /**
+     * Standard priority of threads that are currently running a user interface
+     * that the user is interacting with.  Applications can not normally
+     * change to this priority; the system will automatically adjust your
+     * application threads as the user moves through the UI.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_FOREGROUND = -2;
+    
+    /**
+     * Standard priority of system display threads, involved in updating
+     * the user interface.  Applications can not
+     * normally change to this priority.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_DISPLAY = -4;
+    
+    /**
+     * Standard priority of the most important display threads, for compositing
+     * the screen and retrieving input events.  Applications can not normally
+     * change to this priority.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8;
+
+    /**
+     * Standard priority of audio threads.  Applications can not normally
+     * change to this priority.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_AUDIO = -16;
+
+    /**
+     * Standard priority of the most important audio threads.
+     * Applications can not normally change to this priority.
+     * Use with {@link #setThreadPriority(int)} and
+     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
+     * {@link java.lang.Thread} class.
+     */
+    public static final int THREAD_PRIORITY_URGENT_AUDIO = -19;
+
+    /**
+     * Minimum increment to make a priority more favorable.
+     */
+    public static final int THREAD_PRIORITY_MORE_FAVORABLE = -1;
+
+    /**
+     * Minimum increment to make a priority less favorable.
+     */
+    public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1;
+
+    public static final int SIGNAL_QUIT = 3;
+    public static final int SIGNAL_KILL = 9;
+    public static final int SIGNAL_USR1 = 10;
+    
+    // State for communicating with zygote process
+
+    static LocalSocket sZygoteSocket;
+    static DataInputStream sZygoteInputStream;
+    static BufferedWriter sZygoteWriter;
+
+    /** true if previous zygote open failed */
+    static boolean sPreviousZygoteOpenFailed;
+
+    /**
+     * Start a new process.
+     * 
+     * <p>If processes are enabled, a new process is created and the
+     * static main() function of a <var>processClass</var> is executed there.
+     * The process will continue running after this function returns.
+     * 
+     * <p>If processes are not enabled, a new thread in the caller's
+     * process is created and main() of <var>processClass</var> called there.
+     * 
+     * <p>The niceName parameter, if not an empty string, is a custom name to
+     * give to the process instead of using processClass.  This allows you to
+     * make easily identifyable processes even if you are using the same base
+     * <var>processClass</var> to start them.
+     * 
+     * @param processClass The class to use as the process's main entry
+     *                     point.
+     * @param niceName A more readable name to use for the process.
+     * @param uid The user-id under which the process will run.
+     * @param gid The group-id under which the process will run.
+     * @param gids Additional group-ids associated with the process.
+     * @param enableDebugger True if debugging should be enabled for this process.
+     * @param zygoteArgs Additional arguments to supply to the zygote process.
+     * 
+     * @return int If > 0 the pid of the new process; if 0 the process is
+     *         being emulated by a thread
+     * @throws RuntimeException on fatal start failure
+     * 
+     * {@hide}
+     */
+    public static final int start(final String processClass,
+                                  final String niceName,
+                                  int uid, int gid, int[] gids,
+                                  int debugFlags,
+                                  String[] zygoteArgs)
+    {
+        if (supportsProcesses()) {
+            try {
+                return startViaZygote(processClass, niceName, uid, gid, gids,
+                        debugFlags, zygoteArgs);
+            } catch (ZygoteStartFailedEx ex) {
+                Log.e(LOG_TAG,
+                        "Starting VM process through Zygote failed");
+                throw new RuntimeException(
+                        "Starting VM process through Zygote failed", ex);
+            }
+        } else {
+            // Running in single-process mode
+            
+            Runnable runnable = new Runnable() {
+                        public void run() {
+                            Process.invokeStaticMain(processClass);
+                        }
+            };
+            
+            // Thread constructors must not be called with null names (see spec). 
+            if (niceName != null) {
+                new Thread(runnable, niceName).start();
+            } else {
+                new Thread(runnable).start();
+            }
+            
+            return 0;
+        }
+    }
+    
+    /**
+     * Start a new process.  Don't supply a custom nice name.
+     * {@hide}
+     */
+    public static final int start(String processClass, int uid, int gid,
+            int[] gids, int debugFlags, String[] zygoteArgs) {
+        return start(processClass, "", uid, gid, gids, 
+                debugFlags, zygoteArgs);
+    }
+
+    private static void invokeStaticMain(String className) {
+        Class cl;
+        Object args[] = new Object[1];
+
+        args[0] = new String[0];     //this is argv
+   
+        try {
+            cl = Class.forName(className);
+            cl.getMethod("main", new Class[] { String[].class })
+                    .invoke(null, args);            
+        } catch (Exception ex) {
+            // can be: ClassNotFoundException,
+            // NoSuchMethodException, SecurityException,
+            // IllegalAccessException, IllegalArgumentException
+            // InvocationTargetException
+            // or uncaught exception from main()
+
+            Log.e(LOG_TAG, "Exception invoking static main on " 
+                    + className, ex);
+
+            throw new RuntimeException(ex);
+        }
+
+    }
+
+    /** retry interval for opening a zygote socket */
+    static final int ZYGOTE_RETRY_MILLIS = 500;
+
+    /**
+     * Tries to open socket to Zygote process if not already open. If
+     * already open, does nothing.  May block and retry.
+     */
+    private static void openZygoteSocketIfNeeded() 
+            throws ZygoteStartFailedEx {
+
+        int retryCount;
+
+        if (sPreviousZygoteOpenFailed) {
+            /*
+             * If we've failed before, expect that we'll fail again and
+             * don't pause for retries.
+             */
+            retryCount = 0;
+        } else {
+            retryCount = 10;            
+        }
+
+        /*
+         * See bug #811181: Sometimes runtime can make it up before zygote.
+         * Really, we'd like to do something better to avoid this condition,
+         * but for now just wait a bit...
+         */
+        for (int retry = 0
+                ; (sZygoteSocket == null) && (retry < (retryCount + 1))
+                ; retry++ ) {
+
+            if (retry > 0) {
+                try {
+                    Log.i("Zygote", "Zygote not up yet, sleeping...");
+                    Thread.sleep(ZYGOTE_RETRY_MILLIS);
+                } catch (InterruptedException ex) {
+                    // should never happen
+                }
+            }
+
+            try {
+                sZygoteSocket = new LocalSocket();
+
+                sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, 
+                        LocalSocketAddress.Namespace.RESERVED));
+
+                sZygoteInputStream
+                        = new DataInputStream(sZygoteSocket.getInputStream());
+
+                sZygoteWriter =
+                    new BufferedWriter(
+                            new OutputStreamWriter(
+                                    sZygoteSocket.getOutputStream()),
+                            256);
+
+                Log.i("Zygote", "Process: zygote socket opened");
+
+                sPreviousZygoteOpenFailed = false;
+                break;
+            } catch (IOException ex) {
+                if (sZygoteSocket != null) {
+                    try {
+                        sZygoteSocket.close();
+                    } catch (IOException ex2) {
+                        Log.e(LOG_TAG,"I/O exception on close after exception",
+                                ex2);
+                    }
+                }
+
+                sZygoteSocket = null;
+            }
+        }
+
+        if (sZygoteSocket == null) {
+            sPreviousZygoteOpenFailed = true;
+            throw new ZygoteStartFailedEx("connect failed");                 
+        }
+    }
+
+    /**
+     * Sends an argument list to the zygote process, which starts a new child
+     * and returns the child's pid. Please note: the present implementation
+     * replaces newlines in the argument list with spaces.
+     * @param args argument list
+     * @return PID of new child process
+     * @throws ZygoteStartFailedEx if process start failed for any reason
+     */
+    private static int zygoteSendArgsAndGetPid(ArrayList<String> args)
+            throws ZygoteStartFailedEx {
+
+        int pid;
+
+        openZygoteSocketIfNeeded();
+
+        try {
+            /**
+             * See com.android.internal.os.ZygoteInit.readArgumentList()
+             * Presently the wire format to the zygote process is:
+             * a) a count of arguments (argc, in essence)
+             * b) a number of newline-separated argument strings equal to count
+             *
+             * After the zygote process reads these it will write the pid of
+             * the child or -1 on failure.
+             */
+
+            sZygoteWriter.write(Integer.toString(args.size()));
+            sZygoteWriter.newLine();
+
+            int sz = args.size();
+            for (int i = 0; i < sz; i++) {
+                String arg = args.get(i);
+                if (arg.indexOf('\n') >= 0) {
+                    throw new ZygoteStartFailedEx(
+                            "embedded newlines not allowed");
+                }
+                sZygoteWriter.write(arg);
+                sZygoteWriter.newLine();
+            }
+
+            sZygoteWriter.flush();
+
+            // Should there be a timeout on this?
+            pid = sZygoteInputStream.readInt();
+
+            if (pid < 0) {
+                throw new ZygoteStartFailedEx("fork() failed");
+            }
+        } catch (IOException ex) {
+            try {
+                if (sZygoteSocket != null) {
+                    sZygoteSocket.close();
+                }
+            } catch (IOException ex2) {
+                // we're going to fail anyway
+                Log.e(LOG_TAG,"I/O exception on routine close", ex2);
+            }
+
+            sZygoteSocket = null;
+
+            throw new ZygoteStartFailedEx(ex);
+        }
+
+        return pid;
+    }
+
+    /**
+     * Starts a new process via the zygote mechanism.
+     *
+     * @param processClass Class name whose static main() to run
+     * @param niceName 'nice' process name to appear in ps
+     * @param uid a POSIX uid that the new process should setuid() to
+     * @param gid a POSIX gid that the new process shuold setgid() to
+     * @param gids null-ok; a list of supplementary group IDs that the
+     * new process should setgroup() to.
+     * @param enableDebugger True if debugging should be enabled for this process.
+     * @param extraArgs Additional arguments to supply to the zygote process.
+     * @return PID
+     * @throws ZygoteStartFailedEx if process start failed for any reason
+     */
+    private static int startViaZygote(final String processClass,
+                                  final String niceName,
+                                  final int uid, final int gid,
+                                  final int[] gids,
+                                  int debugFlags,
+                                  String[] extraArgs)
+                                  throws ZygoteStartFailedEx {
+        int pid;
+
+        synchronized(Process.class) {
+            ArrayList<String> argsForZygote = new ArrayList<String>();
+
+            // --runtime-init, --setuid=, --setgid=,
+            // and --setgroups= must go first
+            argsForZygote.add("--runtime-init");
+            argsForZygote.add("--setuid=" + uid);
+            argsForZygote.add("--setgid=" + gid);
+            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
+                argsForZygote.add("--enable-debugger");
+            }
+            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
+                argsForZygote.add("--enable-checkjni");
+            }
+            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
+                argsForZygote.add("--enable-assert");
+            }
+
+            //TODO optionally enable debuger
+            //argsForZygote.add("--enable-debugger");
+
+            // --setgroups is a comma-separated list
+            if (gids != null && gids.length > 0) {
+                StringBuilder sb = new StringBuilder();
+                sb.append("--setgroups=");
+
+                int sz = gids.length;
+                for (int i = 0; i < sz; i++) {
+                    if (i != 0) {
+                        sb.append(',');
+                    }
+                    sb.append(gids[i]);
+                }
+
+                argsForZygote.add(sb.toString());
+            }
+
+            if (niceName != null) {
+                argsForZygote.add("--nice-name=" + niceName);
+            }
+
+            argsForZygote.add(processClass);
+
+            if (extraArgs != null) {
+                for (String arg : extraArgs) {
+                    argsForZygote.add(arg);
+                }
+            }
+            
+            pid = zygoteSendArgsAndGetPid(argsForZygote);
+        }
+
+        if (pid <= 0) {
+            throw new ZygoteStartFailedEx("zygote start failed:" + pid);
+        }
+
+        return pid;
+    }
+    
+    /**
+     * Returns elapsed milliseconds of the time this process has run.
+     * @return  Returns the number of milliseconds this process has return.
+     */
+    public static final native long getElapsedCpuTime();
+    
+    /**
+     * Returns the identifier of this process, which can be used with
+     * {@link #killProcess} and {@link #sendSignal}.
+     */
+    public static final native int myPid();
+
+    /**
+     * Returns the identifier of the calling thread, which be used with
+     * {@link #setThreadPriority(int, int)}.
+     */
+    public static final native int myTid();
+
+    /**
+     * Returns the identifier of this process's user.
+     */
+    public static final native int myUid();
+
+    /**
+     * Returns the UID assigned to a particular user name, or -1 if there is
+     * none.  If the given string consists of only numbers, it is converted
+     * directly to a uid.
+     */
+    public static final native int getUidForName(String name);
+    
+    /**
+     * Returns the GID assigned to a particular user name, or -1 if there is
+     * none.  If the given string consists of only numbers, it is converted
+     * directly to a gid.
+     */
+    public static final native int getGidForName(String name);
+    
+    /**
+     * Set the priority of a thread, based on Linux priorities.
+     * 
+     * @param tid The identifier of the thread/process to change.
+     * @param priority A Linux priority level, from -20 for highest scheduling
+     * priority to 19 for lowest scheduling priority.
+     * 
+     * @throws IllegalArgumentException Throws IllegalArgumentException if
+     * <var>tid</var> does not exist.
+     * @throws SecurityException Throws SecurityException if your process does
+     * not have permission to modify the given thread, or to use the given
+     * priority.
+     */
+    public static final native void setThreadPriority(int tid, int priority)
+            throws IllegalArgumentException, SecurityException;
+    
+    /**
+     * Set the priority of the calling thread, based on Linux priorities.  See
+     * {@link #setThreadPriority(int, int)} for more information.
+     * 
+     * @param priority A Linux priority level, from -20 for highest scheduling
+     * priority to 19 for lowest scheduling priority.
+     * 
+     * @throws IllegalArgumentException Throws IllegalArgumentException if
+     * <var>tid</var> does not exist.
+     * @throws SecurityException Throws SecurityException if your process does
+     * not have permission to modify the given thread, or to use the given
+     * priority.
+     * 
+     * @see #setThreadPriority(int, int)
+     */
+    public static final native void setThreadPriority(int priority)
+            throws IllegalArgumentException, SecurityException;
+    
+    /**
+     * Return the current priority of a thread, based on Linux priorities.
+     * 
+     * @param tid The identifier of the thread/process to change.
+     * 
+     * @return Returns the current priority, as a Linux priority level,
+     * from -20 for highest scheduling priority to 19 for lowest scheduling
+     * priority.
+     * 
+     * @throws IllegalArgumentException Throws IllegalArgumentException if
+     * <var>tid</var> does not exist.
+     */
+    public static final native int getThreadPriority(int tid)
+            throws IllegalArgumentException;
+    
+    /**
+     * Determine whether the current environment supports multiple processes.
+     * 
+     * @return Returns true if the system can run in multiple processes, else
+     * false if everything is running in a single process.
+     */
+    public static final native boolean supportsProcesses();
+
+    /**
+     * Set the out-of-memory badness adjustment for a process.
+     * 
+     * @param pid The process identifier to set.
+     * @param amt Adjustment value -- linux allows -16 to +15.
+     * 
+     * @return Returns true if the underlying system supports this
+     *         feature, else false.
+     *         
+     * {@hide}
+     */
+    public static final native boolean setOomAdj(int pid, int amt);
+
+    /**
+     * Change this process's argv[0] parameter.  This can be useful to show
+     * more descriptive information in things like the 'ps' command.
+     * 
+     * @param text The new name of this process.
+     * 
+     * {@hide}
+     */
+    public static final native void setArgV0(String text);
+
+    /**
+     * Kill the process with the given PID.
+     * Note that, though this API allows us to request to
+     * kill any process based on its PID, the kernel will
+     * still impose standard restrictions on which PIDs you
+     * are actually able to kill.  Typically this means only
+     * the process running the caller's packages/application
+     * and any additional processes created by that app; packages
+     * sharing a common UID will also be able to kill each
+     * other's processes.
+     */
+    public static final void killProcess(int pid) {
+        sendSignal(pid, SIGNAL_KILL);
+    }
+
+    /** @hide */
+    public static final native int setUid(int uid);
+
+    /** @hide */
+    public static final native int setGid(int uid);
+
+    /**
+     * Send a signal to the given process.
+     * 
+     * @param pid The pid of the target process.
+     * @param signal The signal to send.
+     */
+    public static final native void sendSignal(int pid, int signal);
+    
+    /** @hide */
+    public static final native int getFreeMemory();
+    
+    /** @hide */
+    public static final native void readProcLines(String path,
+            String[] reqFields, long[] outSizes);
+    
+    /** @hide */
+    public static final native int[] getPids(String path, int[] lastArray);
+    
+    /** @hide */
+    public static final int PROC_TERM_MASK = 0xff;
+    /** @hide */
+    public static final int PROC_ZERO_TERM = 0;
+    /** @hide */
+    public static final int PROC_SPACE_TERM = (int)' ';
+    /** @hide */
+    public static final int PROC_COMBINE = 0x100;
+    /** @hide */
+    public static final int PROC_PARENS = 0x200;
+    /** @hide */
+    public static final int PROC_OUT_STRING = 0x1000;
+    /** @hide */
+    public static final int PROC_OUT_LONG = 0x2000;
+    /** @hide */
+    public static final int PROC_OUT_FLOAT = 0x4000;
+    
+    /** @hide */
+    public static final native boolean readProcFile(String file, int[] format,
+            String[] outStrings, long[] outLongs, float[] outFloats);
+
+    /**
+     * Gets the total Pss value for a given process, in bytes.
+     * 
+     * @param pid the process to the Pss for
+     * @return the total Pss value for the given process in bytes,
+     *  or -1 if the value cannot be determined 
+     * @hide
+     */
+    public static final native long getPss(int pid);
+}
diff --git a/core/java/android/os/Registrant.java b/core/java/android/os/Registrant.java
new file mode 100644
index 0000000..c1780b9
--- /dev/null
+++ b/core/java/android/os/Registrant.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.os.Handler;
+import android.os.Message;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+
+/** @hide */
+public class Registrant
+{
+    public
+    Registrant(Handler h, int what, Object obj)
+    {
+        refH = new WeakReference(h);
+        this.what = what;
+        userObj = obj;
+    }
+
+    public void
+    clear()
+    {
+        refH = null;
+        userObj = null;
+    }
+
+    public void
+    notifyRegistrant()
+    {
+        internalNotifyRegistrant (null, null);
+    }
+    
+    public void
+    notifyResult(Object result)
+    {
+        internalNotifyRegistrant (result, null);
+    }
+
+    public void
+    notifyException(Throwable exception)
+    {
+        internalNotifyRegistrant (null, exception);
+    }
+
+    /**
+     * This makes a copy of @param ar
+     */
+    public void
+    notifyRegistrant(AsyncResult ar)
+    {
+        internalNotifyRegistrant (ar.result, ar.exception);
+    }
+
+    /*package*/ void
+    internalNotifyRegistrant (Object result, Throwable exception)
+    {
+        Handler h = getHandler();
+
+        if (h == null) {
+            clear();
+        } else {
+            Message msg = Message.obtain();
+
+            msg.what = what;
+            
+            msg.obj = new AsyncResult(userObj, result, exception);
+            
+            h.sendMessage(msg);
+        }
+    }
+
+    /**
+     * NOTE: May return null if weak reference has been collected
+     */
+
+    public Message
+    messageForRegistrant()
+    {
+        Handler h = getHandler();
+
+        if (h == null) {
+            clear();
+
+            return null;
+        } else {
+            Message msg = h.obtainMessage();
+
+            msg.what = what;
+            msg.obj = userObj;
+
+            return msg;
+        }
+    }
+
+    public Handler
+    getHandler()
+    {
+        if (refH == null)
+            return null;
+
+        return (Handler) refH.get();
+    }
+
+    WeakReference   refH;
+    int             what;
+    Object          userObj;
+}
+
diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java
new file mode 100644
index 0000000..56b9e2b
--- /dev/null
+++ b/core/java/android/os/RegistrantList.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+import android.os.Handler;         
+import android.os.Message;         
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/** @hide */
+public class RegistrantList
+{
+    ArrayList   registrants = new ArrayList();      // of Registrant
+
+    public synchronized void
+    add(Handler h, int what, Object obj)
+    {
+        add(new Registrant(h, what, obj));
+    }
+
+    public synchronized void
+    addUnique(Handler h, int what, Object obj)
+    {
+        // if the handler is already in the registrant list, remove it
+        remove(h);
+        add(new Registrant(h, what, obj));        
+    }
+    
+    public synchronized void
+    add(Registrant r)
+    {
+        removeCleared();
+        registrants.add(r);
+    }
+
+    public synchronized void
+    removeCleared()
+    {
+        for (int i = registrants.size() - 1; i >= 0 ; i--) {
+            Registrant  r = (Registrant) registrants.get(i);
+            
+            if (r.refH == null) {
+                registrants.remove(i);
+            }
+        }
+    }
+
+    public synchronized int
+    size()
+    {
+        return registrants.size();
+    }
+
+    public synchronized Object
+    get(int index)
+    {
+        return registrants.get(index);
+    }
+
+    private synchronized void
+    internalNotifyRegistrants (Object result, Throwable exception)
+    {
+       for (int i = 0, s = registrants.size(); i < s ; i++) {
+            Registrant  r = (Registrant) registrants.get(i);
+            r.internalNotifyRegistrant(result, exception);
+       }
+    }
+    
+    public /*synchronized*/ void
+    notifyRegistrants()
+    {
+        internalNotifyRegistrants(null, null);
+    }
+
+    public /*synchronized*/ void
+    notifyException(Throwable exception)
+    {
+        internalNotifyRegistrants (null, exception);
+    }
+
+    public /*synchronized*/ void
+    notifyResult(Object result)
+    {
+        internalNotifyRegistrants (result, null);
+    }
+
+    
+    public /*synchronized*/ void
+    notifyRegistrants(AsyncResult ar)
+    {
+        internalNotifyRegistrants(ar.result, ar.exception);
+    }
+    
+    public synchronized void
+    remove(Handler h)
+    {
+        for (int i = 0, s = registrants.size() ; i < s ; i++) {
+            Registrant  r = (Registrant) registrants.get(i);
+            Handler     rh;
+
+            rh = r.getHandler();
+
+            /* Clean up both the requested registrant and
+             * any now-collected registrants
+             */
+            if (rh == null || rh == h) {
+                r.clear();
+            }
+        }
+
+        removeCleared();
+    }
+}
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
new file mode 100644
index 0000000..04e7ef0
--- /dev/null
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+import java.util.HashMap;
+
+/**
+ * Takes care of the grunt work of maintaining a list of remote interfaces,
+ * typically for the use of performing callbacks from a
+ * {@link android.app.Service} to its clients.  In particular, this:
+ * 
+ * <ul>
+ * <li> Keeps track of a set of registered {@link IInterface} callbacks,
+ * taking care to identify them through their underlying unique {@link IBinder}
+ * (by calling {@link IInterface#asBinder IInterface.asBinder()}.
+ * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to
+ * each registered interface, so that it can be cleaned out of the list if its
+ * process goes away.
+ * <li> Performs locking of the underlying list of interfaces to deal with
+ * multithreaded incoming calls, and a thread-safe way to iterate over a
+ * snapshot of the list without holding its lock.
+ * </ul>
+ * 
+ * <p>To use this class, simply create a single instance along with your
+ * service, and call its {@link #register} and {@link #unregister} methods
+ * as client register and unregister with your service.  To call back on to
+ * the registered clients, use {@link #beginBroadcast},
+ * {@link #getBroadcastItem}, and {@link #finishBroadcast}.
+ * 
+ * <p>If a registered callback's process goes away, this class will take
+ * care of automatically removing it from the list.  If you want to do
+ * additional work in this situation, you can create a subclass that
+ * implements the {@link #onCallbackDied} method.
+ */
+public class RemoteCallbackList<E extends IInterface> {
+    /*package*/ HashMap<IBinder, Callback> mCallbacks
+            = new HashMap<IBinder, Callback>();
+    private IInterface[] mActiveBroadcast;
+    private boolean mKilled = false;
+    
+    private final class Callback implements IBinder.DeathRecipient {
+        final E mCallback;
+        
+        Callback(E callback) {
+            mCallback = callback;
+        }
+        
+        public void binderDied() {
+            synchronized (mCallbacks) {
+                mCallbacks.remove(mCallback.asBinder());
+            }
+            onCallbackDied(mCallback);
+        }
+    }
+    
+    /**
+     * Add a new callback to the list.  This callback will remain in the list
+     * until a corresponding call to {@link #unregister} or its hosting process
+     * goes away.  If the callback was already registered (determined by
+     * checking to see if the {@link IInterface#asBinder callback.asBinder()}
+     * object is already in the list), then it will be left as-is.
+     * Registrations are not counted; a single call to {@link #unregister}
+     * will remove a callback after any number calls to register it.
+     * 
+     * @param callback The callback interface to be added to the list.  Must
+     * not be null -- passing null here will cause a NullPointerException.
+     * Most services will want to check for null before calling this with
+     * an object given from a client, so that clients can't crash the
+     * service with bad data.
+     * 
+     * @return Returns true if the callback was successfully added to the list.
+     * Returns false if it was not added, either because {@link #kill} had
+     * previously been called or the callback's process has gone away.
+     * 
+     * @see #unregister
+     * @see #kill
+     * @see #onCallbackDied
+     */
+    public boolean register(E callback) {
+        synchronized (mCallbacks) {
+            if (mKilled) {
+                return false;
+            }
+            IBinder binder = callback.asBinder();
+            try {
+                Callback cb = new Callback(callback);
+                binder.linkToDeath(cb, 0);
+                mCallbacks.put(binder, cb);
+                return true;
+            } catch (RemoteException e) {
+                return false;
+            }
+        }
+    }
+    
+    /**
+     * Remove from the list a callback that was previously added with
+     * {@link #register}.  This uses the
+     * {@link IInterface#asBinder callback.asBinder()} object to correctly
+     * find the previous registration.
+     * Registrations are not counted; a single unregister call will remove
+     * a callback after any number calls to {@link #register} for it.
+     * 
+     * @param callback The callback to be removed from the list.  Passing
+     * null here will cause a NullPointerException, so you will generally want
+     * to check for null before calling.
+     * 
+     * @return Returns true if the callback was found and unregistered.  Returns
+     * false if the given callback was not found on the list.
+     * 
+     * @see #register
+     */
+    public boolean unregister(E callback) {
+        synchronized (mCallbacks) {
+            Callback cb = mCallbacks.remove(callback.asBinder());
+            if (cb != null) {
+                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
+                return true;
+            }
+            return false;
+        }
+    }
+    
+    /**
+     * Disable this callback list.  All registered callbacks are unregistered,
+     * and the list is disabled so that future calls to {@link #register} will
+     * fail.  This should be used when a Service is stopping, to prevent clients
+     * from registering callbacks after it is stopped.
+     * 
+     * @see #register
+     */
+    public void kill() {
+        synchronized (mCallbacks) {
+            for (Callback cb : mCallbacks.values()) {
+                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
+            }
+            mCallbacks.clear();
+            mKilled = true;
+        }
+    }
+    
+    /**
+     * Called when the process hosting a callback in the list has gone away.
+     * The default implementation does nothing.
+     * 
+     * @param callback The callback whose process has died.  Note that, since
+     * its process has died, you can not make any calls on to this interface.
+     * You can, however, retrieve its IBinder and compare it with another
+     * IBinder to see if it is the same object.
+     * 
+     * @see #register
+     */
+    public void onCallbackDied(E callback) {
+    }
+    
+    /**
+     * Prepare to start making calls to the currently registered callbacks.
+     * This creates a copy of the callback list, which you can retrieve items
+     * from using {@link #getBroadcastItem}.  Note that only one broadcast can
+     * be active at a time, so you must be sure to always call this from the
+     * same thread (usually by scheduling with {@link Handler} or
+     * do your own synchronization.  You must call {@link #finishBroadcast}
+     * when done.
+     * 
+     * <p>A typical loop delivering a broadcast looks like this:
+     * 
+     * <pre>
+     * final int N = callbacks.beginBroadcast();
+     * for (int i=0; i<N; i++) {
+     *     try {
+     *         callbacks.getBroadcastItem(i).somethingHappened();
+     *     } catch (RemoteException e) {
+     *         // The RemoteCallbackList will take care of removing
+     *         // the dead object for us.
+     *     }
+     * }
+     * callbacks.finishBroadcast();</pre>
+     * 
+     * @return Returns the number of callbacks in the broadcast, to be used
+     * with {@link #getBroadcastItem} to determine the range of indices you
+     * can supply.
+     * 
+     * @see #getBroadcastItem
+     * @see #finishBroadcast
+     */
+    public int beginBroadcast() {
+        synchronized (mCallbacks) {
+            final int N = mCallbacks.size();
+            if (N <= 0) {
+                return 0;
+            }
+            IInterface[] active = mActiveBroadcast;
+            if (active == null || active.length < N) {
+                mActiveBroadcast = active = new IInterface[N];
+            }
+            int i=0;
+            for (Callback cb : mCallbacks.values()) {
+                active[i++] = cb.mCallback;
+            }
+            return N;
+        }
+    }
+    
+    /**
+     * Retrieve an item in the active broadcast that was previously started
+     * with {@link #beginBroadcast}.  This can <em>only</em> be called after
+     * the broadcast is started, and its data is no longer valid after
+     * calling {@link #finishBroadcast}.
+     * 
+     * <p>Note that it is possible for the process of one of the returned
+     * callbacks to go away before you call it, so you will need to catch
+     * {@link RemoteException} when calling on to the returned object.
+     * The callback list itself, however, will take care of unregistering
+     * these objects once it detects that it is no longer valid, so you can
+     * handle such an exception by simply ignoring it.
+     * 
+     * @param index Which of the registered callbacks you would like to
+     * retrieve.  Ranges from 0 to 1-{@link #beginBroadcast}.
+     * 
+     * @return Returns the callback interface that you can call.  This will
+     * always be non-null.
+     * 
+     * @see #beginBroadcast
+     */
+    public E getBroadcastItem(int index) {
+        return (E)mActiveBroadcast[index];
+    }
+    
+    /**
+     * Clean up the state of a broadcast previously initiated by calling
+     * {@link #beginBroadcast}.  This must always be called when you are done
+     * with a broadcast.
+     * 
+     * @see #beginBroadcast
+     */
+    public void finishBroadcast() {
+        IInterface[] active = mActiveBroadcast;
+        if (active != null) {
+            final int N = active.length;
+            for (int i=0; i<N; i++) {
+                active[i] = null;
+            }
+        }
+    }
+}
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
new file mode 100644
index 0000000..9d76156
--- /dev/null
+++ b/core/java/android/os/RemoteException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+import android.util.AndroidException;
+
+/**
+ * Parent exception for all Binder remote-invocation errors
+ */
+public class RemoteException extends AndroidException {
+    public RemoteException() {
+        super();
+    }
+}
diff --git a/core/java/android/os/RemoteMailException.java b/core/java/android/os/RemoteMailException.java
new file mode 100644
index 0000000..1ac96d1
--- /dev/null
+++ b/core/java/android/os/RemoteMailException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/** @hide */
+public class RemoteMailException extends Exception
+{
+    public RemoteMailException()
+    {
+    }
+
+    public RemoteMailException(String s)
+    {
+        super(s);
+    }
+}
+
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
new file mode 100644
index 0000000..b721665
--- /dev/null
+++ b/core/java/android/os/ServiceManager.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import com.android.internal.os.BinderInternal;
+
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** @hide */
+public final class ServiceManager {
+    private static final String TAG = "ServiceManager";
+
+    private static IServiceManager sServiceManager;
+    private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
+
+    private static IServiceManager getIServiceManager() {
+        if (sServiceManager != null) {
+            return sServiceManager;
+        }
+
+        // Find the service manager
+        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
+        return sServiceManager;
+    }
+
+    /**
+     * Returns a reference to a service with the given name.
+     * 
+     * @param name the name of the service to get
+     * @return a reference to the service, or <code>null</code> if the service doesn't exist
+     */
+    public static IBinder getService(String name) {
+        try {
+            IBinder service = sCache.get(name);
+            if (service != null) {
+                return service;
+            } else {
+                return getIServiceManager().getService(name);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "error in getService", e);
+        }
+        return null;
+    }
+
+    /**
+     * Place a new @a service called @a name into the service
+     * manager.
+     * 
+     * @param name the name of the new service
+     * @param service the service object
+     */
+    public static void addService(String name, IBinder service) {
+        try {
+            getIServiceManager().addService(name, service);
+        } catch (RemoteException e) {
+            Log.e(TAG, "error in addService", e);
+        }
+    }
+    
+    /**
+     * Retrieve an existing service called @a name from the
+     * service manager.  Non-blocking.
+     */
+    public static IBinder checkService(String name) {
+        try {
+            IBinder service = sCache.get(name);
+            if (service != null) {
+                return service;
+            } else {
+                return getIServiceManager().checkService(name);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "error in checkService", e);
+            return null;
+        }
+    }
+
+    /**
+     * Return a list of all currently running services.
+     */
+    public static String[] listServices() throws RemoteException {
+        try {
+            return getIServiceManager().listServices();
+        } catch (RemoteException e) {
+            Log.e(TAG, "error in listServices", e);
+            return null;
+        }
+    }
+
+    /**
+     * This is only intended to be called when the process is first being brought
+     * up and bound by the activity manager. There is only one thread in the process
+     * at that time, so no locking is done.
+     * 
+     * @param cache the cache of service references
+     * @hide
+     */
+    public static void initServiceCache(Map<String, IBinder> cache) {
+        if (sCache.size() != 0 && Process.supportsProcesses()) {
+            throw new IllegalStateException("setServiceCache may only be called once");
+        }
+        sCache.putAll(cache);
+    }
+}
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
new file mode 100644
index 0000000..2aab0e6
--- /dev/null
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+
+/**
+ * Native implementation of the service manager.  Most clients will only
+ * care about getDefault() and possibly asInterface().
+ * @hide
+ */
+public abstract class ServiceManagerNative extends Binder implements IServiceManager
+{
+    /**
+     * Cast a Binder object into a service manager interface, generating
+     * a proxy if needed.
+     */
+    static public IServiceManager asInterface(IBinder obj)
+    {
+        if (obj == null) {
+            return null;
+        }
+        IServiceManager in =
+            (IServiceManager)obj.queryLocalInterface(descriptor);
+        if (in != null) {
+            return in;
+        }
+        
+        return new ServiceManagerProxy(obj);
+    }
+    
+    public ServiceManagerNative()
+    {
+        attachInterface(this, descriptor);
+    }
+    
+    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+    {
+        try {
+            switch (code) {
+            case IServiceManager.GET_SERVICE_TRANSACTION: {
+                data.enforceInterface(IServiceManager.descriptor);
+                String name = data.readString();
+                IBinder service = getService(name);
+                reply.writeStrongBinder(service);
+                return true;
+            }
+    
+            case IServiceManager.CHECK_SERVICE_TRANSACTION: {
+                data.enforceInterface(IServiceManager.descriptor);
+                String name = data.readString();
+                IBinder service = checkService(name);
+                reply.writeStrongBinder(service);
+                return true;
+            }
+    
+            case IServiceManager.ADD_SERVICE_TRANSACTION: {
+                data.enforceInterface(IServiceManager.descriptor);
+                String name = data.readString();
+                IBinder service = data.readStrongBinder();
+                addService(name, service);
+                return true;
+            }
+    
+            case IServiceManager.LIST_SERVICES_TRANSACTION: {
+                data.enforceInterface(IServiceManager.descriptor);
+                String[] list = listServices();
+                reply.writeStringArray(list);
+                return true;
+            }
+            
+            case IServiceManager.SET_PERMISSION_CONTROLLER_TRANSACTION: {
+                data.enforceInterface(IServiceManager.descriptor);
+                IPermissionController controller
+                        = IPermissionController.Stub.asInterface(
+                                data.readStrongBinder());
+                setPermissionController(controller);
+                return true;
+            }
+            }
+        } catch (RemoteException e) {
+        }
+        
+        return false;
+    }
+
+    public IBinder asBinder()
+    {
+        return this;
+    }
+}
+
+class ServiceManagerProxy implements IServiceManager {
+    public ServiceManagerProxy(IBinder remote) {
+        mRemote = remote;
+    }
+    
+    public IBinder asBinder() {
+        return mRemote;
+    }
+    
+    public IBinder getService(String name) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IServiceManager.descriptor);
+        data.writeString(name);
+        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
+        IBinder binder = reply.readStrongBinder();
+        reply.recycle();
+        data.recycle();
+        return binder;
+    }
+
+    public IBinder checkService(String name) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IServiceManager.descriptor);
+        data.writeString(name);
+        mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0);
+        IBinder binder = reply.readStrongBinder();
+        reply.recycle();
+        data.recycle();
+        return binder;
+    }
+
+    public void addService(String name, IBinder service)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IServiceManager.descriptor);
+        data.writeString(name);
+        data.writeStrongBinder(service);
+        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
+        reply.recycle();
+        data.recycle();
+    }
+    
+    public String[] listServices() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IServiceManager.descriptor);
+        mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
+        String[] list = reply.readStringArray();
+        reply.recycle();
+        data.recycle();
+        return list;
+    }
+
+    public void setPermissionController(IPermissionController controller)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IServiceManager.descriptor);
+        data.writeStrongBinder(controller.asBinder());
+        mRemote.transact(SET_PERMISSION_CONTROLLER_TRANSACTION, data, reply, 0);
+        reply.recycle();
+        data.recycle();
+    }
+
+    private IBinder mRemote;
+}
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
new file mode 100644
index 0000000..912bfdf
--- /dev/null
+++ b/core/java/android/os/StatFs.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+/**
+ * Retrieve overall information about the space on a filesystem.  This is a
+ * Wrapper for Unix statfs().
+ */
+public class StatFs {
+    /**
+     * Construct a new StatFs for looking at the stats of the
+     * filesystem at <var>path</var>.  Upon construction, the stat of
+     * the file system will be performed, and the values retrieved available
+     * from the methods on this class.
+     * 
+     * @param path A path in the desired file system to state.
+     */
+    public StatFs(String path) { native_setup(path); }
+    
+    /**
+     * Perform a restat of the file system referenced by this object.  This
+     * is the same as re-constructing the object with the same file system
+     * path, and the new stat values are available upon return.
+     */
+    public void restat(String path) { native_restat(path); }
+
+    @Override
+    protected void finalize() { native_finalize(); }
+
+    /**
+     * The size, in bytes, of a block on the file system.  This corresponds
+     * to the Unix statfs.f_bsize field.
+     */
+    public native int getBlockSize();
+
+    /**
+     * The total number of blocks on the file system.  This corresponds
+     * to the Unix statfs.f_blocks field.
+     */
+    public native int getBlockCount();
+
+    /**
+     * The total number of blocks that are free on the file system, including
+     * reserved blocks (that are not available to normal applications).  This
+     * corresponds to the Unix statfs.f_bfree field.  Most applications will
+     * want to use {@link #getAvailableBlocks()} instead.
+     */
+    public native int getFreeBlocks();
+
+    /**
+     * The number of blocks that are free on the file system and available to
+     * applications.  This corresponds to the Unix statfs.f_bavail field.
+     */
+    public native int getAvailableBlocks();    
+    
+    private int mNativeContext;
+    private native void native_restat(String path);
+    private native void native_setup(String path);
+    private native void native_finalize();
+}
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
new file mode 100644
index 0000000..2b57b39
--- /dev/null
+++ b/core/java/android/os/SystemClock.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+
+/**
+ * Core timekeeping facilities.
+ *
+ * <p> Three different clocks are available, and they should not be confused:
+ *
+ * <ul>
+ *     <li> <p> {@link System#currentTimeMillis System.currentTimeMillis()}
+ *     is the standard "wall" clock (time and date) expressing milliseconds
+ *     since the epoch.  The wall clock can be set by the user or the phone
+ *     network (see {@link #setCurrentTimeMillis}), so the time may jump
+ *     backwards or forwards unpredictably.  This clock should only be used
+ *     when correspondence with real-world dates and times is important, such
+ *     as in a calendar or alarm clock application.  Interval or elapsed
+ *     time measurements should use a different clock.
+ *
+ *     <li> <p> {@link #uptimeMillis} is counted in milliseconds since the
+ *     system was booted.  This clock stops when the system enters deep
+ *     sleep (CPU off, display dark, device waiting for external input),
+ *     but is not affected by clock scaling, idle, or other power saving
+ *     mechanisms.  This is the basis for most interval timing
+ *     such as {@link Thread#sleep(long) Thread.sleep(millls)},
+ *     {@link Object#wait(long) Object.wait(millis)}, and
+ *     {@link System#nanoTime System.nanoTime()}.  This clock is guaranteed
+ *     to be monotonic, and is the recommended basis for the general purpose
+ *     interval timing of user interface events, performance measurements,
+ *     and anything else that does not need to measure elapsed time during
+ *     device sleep.  Most methods that accept a timestamp value expect the
+ *     {@link #uptimeMillis} clock.
+ *
+ *     <li> <p> {@link #elapsedRealtime} is counted in milliseconds since the
+ *     system was booted, including deep sleep.  This clock should be used
+ *     when measuring time intervals that may span periods of system sleep.
+ * </ul>
+ *
+ * There are several mechanisms for controlling the timing of events:
+ *
+ * <ul>
+ *     <li> <p> Standard functions like {@link Thread#sleep(long)
+ *     Thread.sleep(millis)} and {@link Object#wait(long) Object.wait(millis)}
+ *     are always available.  These functions use the {@link #uptimeMillis}
+ *     clock; if the device enters sleep, the remainder of the time will be
+ *     postponed until the device wakes up.  These synchronous functions may
+ *     be interrupted with {@link Thread#interrupt Thread.interrupt()}, and
+ *     you must handle {@link InterruptedException}.
+ *
+ *     <li> <p> {@link #sleep SystemClock.sleep(millis)} is a utility function
+ *     very similar to {@link Thread#sleep(long) Thread.sleep(millis)}, but it
+ *     ignores {@link InterruptedException}.  Use this function for delays if
+ *     you do not use {@link Thread#interrupt Thread.interrupt()}, as it will
+ *     preserve the interrupted state of the thread.
+ *
+ *     <li> <p> The {@link android.os.Handler} class can schedule asynchronous
+ *     callbacks at an absolute or relative time.  Handler objects also use the
+ *     {@link #uptimeMillis} clock, and require an {@link android.os.Looper
+ *     event loop} (normally present in any GUI application).
+ *
+ *     <li> <p> The {@link android.app.AlarmManager} can trigger one-time or
+ *     recurring events which occur even when the device is in deep sleep
+ *     or your application is not running.  Events may be scheduled with your
+ *     choice of {@link java.lang.System#currentTimeMillis} (RTC) or
+ *     {@link #elapsedRealtime} (ELAPSED_REALTIME), and cause an
+ *     {@link android.content.Intent} broadcast when they occur.
+ * </ul>
+ */
+public final class SystemClock {
+    /**
+     * This class is uninstantiable.
+     */
+    private SystemClock() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Waits a given number of milliseconds (of uptimeMillis) before returning.
+     * Similar to {@link java.lang.Thread#sleep(long)}, but does not throw
+     * {@link InterruptedException}; {@link Thread#interrupt()} events are
+     * deferred until the next interruptible operation.  Does not return until
+     * at least the specified number of milliseconds has elapsed.
+     *
+     * @param ms to sleep before returning, in milliseconds of uptime.
+     */
+    public static void sleep(long ms)
+    {
+        long start = uptimeMillis();
+        long duration = ms;
+        boolean interrupted = false;
+        do {
+            try {
+                Thread.sleep(duration);
+            }
+            catch (InterruptedException e) {
+                interrupted = true;
+            }
+            duration = start + ms - uptimeMillis();
+        } while (duration > 0);
+        
+        if (interrupted) {
+            // Important: we don't want to quietly eat an interrupt() event,
+            // so we make sure to re-interrupt the thread so that the next
+            // call to Thread.sleep() or Object.wait() will be interrupted.
+            Thread.currentThread().interrupt();
+        }
+    }
+    
+    /**
+     * Sets the current wall time, in milliseconds.  Requires the calling
+     * process to have appropriate permissions.
+     *
+     * @return if the clock was successfully set to the specified time.
+     */
+    native public static boolean setCurrentTimeMillis(long millis);
+
+    /**
+     * Returns milliseconds since boot, not counting time spent in deep sleep.
+     * <b>Note:</b> This value may get reset occasionally (before it would
+     * otherwise wrap around).
+     *
+     * @return milliseconds of non-sleep uptime since boot.
+     */
+    native public static long uptimeMillis();
+
+    /**
+     * Returns milliseconds since boot, including time spent in sleep.
+     *
+     * @return elapsed milliseconds since boot.
+     */
+    native public static long elapsedRealtime();
+    
+    /**
+     * Returns milliseconds running in the current thread.
+     * 
+     * @return elapsed milliseconds in the thread
+     */
+    public static native long currentThreadTimeMillis();
+}
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
new file mode 100644
index 0000000..c3ae3c2
--- /dev/null
+++ b/core/java/android/os/SystemProperties.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+
+/**
+ * Gives access to the system properties store.  The system properties
+ * store contains a list of string key-value pairs.
+ *
+ * {@hide}
+ */
+public class SystemProperties
+{
+    public static final int PROP_NAME_MAX = 31;
+    public static final int PROP_VALUE_MAX = 91;
+
+    private static native String native_get(String key);
+    private static native String native_get(String key, String def);
+    private static native void native_set(String key, String def);
+
+    /**
+     * Get the value for the given key.
+     * @return an empty string if the key isn't found
+     * @throws IllegalArgumentException if the key exceeds 32 characters
+     */
+    public static String get(String key) {
+        if (key.length() > PROP_NAME_MAX) {
+            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+        }
+        return native_get(key);
+    }
+
+    /**
+     * Get the value for the given key.
+     * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
+     * @throws IllegalArgumentException if the key exceeds 32 characters
+     */
+    public static String get(String key, String def) {
+        if (key.length() > PROP_NAME_MAX) {
+            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+        }
+        return native_get(key, def);
+    }
+
+    /**
+     * Get the value for the given key, and return as an integer.
+     * @param key the key to lookup
+     * @param def a default value to return
+     * @return the key parsed as an integer, or def if the key isn't found or
+     *         cannot be parsed
+     * @throws IllegalArgumentException if the key exceeds 32 characters
+     */
+    public static int getInt(String key, int def) {
+        try {
+            return Integer.parseInt(get(key));
+        } catch (NumberFormatException e) {
+            return def;
+        }
+    }
+
+    /**
+     * Get the value for the given key, and return as a long.
+     * @param key the key to lookup
+     * @param def a default value to return
+     * @return the key parsed as a long, or def if the key isn't found or
+     *         cannot be parsed
+     * @throws IllegalArgumentException if the key exceeds 32 characters
+     */
+    public static long getLong(String key, long def) {
+        try {
+            return Long.parseLong(get(key));
+        } catch (NumberFormatException e) {
+            return def;
+        }
+    }
+
+    /**
+     * Get the value for the given key, returned as a boolean.
+     * Values 'n', 'no', '0', 'false' or 'off' are considered false.
+     * Values 'y', 'yes', '1', 'true' or 'on' are considered true.
+     * (case insensitive).
+     * If the key does not exist, or has any other value, then the default
+     * result is returned.
+     * @param key the key to lookup
+     * @param def a default value to return
+     * @return the key parsed as a boolean, or def if the key isn't found or is
+     *         not able to be parsed as a boolean.
+     * @throws IllegalArgumentException if the key exceeds 32 characters
+     */
+    public static boolean getBoolean(String key, boolean def) {
+        String value = get(key);
+        // Deal with these quick cases first: not found, 0 and 1
+        if (value.equals("")) {
+            return def;
+        } else if (value.equals("0")) {
+            return false;
+        } else if (value.equals("1")) {
+            return true;
+        // now for slower (and hopefully less common) cases
+        } else if (value.equalsIgnoreCase("n") ||
+                   value.equalsIgnoreCase("no") ||
+                   value.equalsIgnoreCase("false") ||
+                   value.equalsIgnoreCase("off")) {
+            return false;
+        } else if (value.equalsIgnoreCase("y") ||
+                   value.equalsIgnoreCase("yes") ||
+                   value.equalsIgnoreCase("true") ||
+                   value.equalsIgnoreCase("on")) {
+            return true;
+        }
+        return def;
+    }
+
+    /**
+     * Set the value for the given key.
+     * @throws IllegalArgumentException if the key exceeds 32 characters
+     * @throws IllegalArgumentException if the value exceeds 92 characters
+     */
+    public static void set(String key, String val) {
+        if (key.length() > PROP_NAME_MAX) {
+            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
+        }
+        if (val != null && val.length() > PROP_VALUE_MAX) {
+            throw new IllegalArgumentException("val.length > " +
+                PROP_VALUE_MAX);
+        }
+        native_set(key, val);
+    }
+}
diff --git a/core/java/android/os/SystemService.java b/core/java/android/os/SystemService.java
new file mode 100644
index 0000000..447cd1f
--- /dev/null
+++ b/core/java/android/os/SystemService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/** @hide */
+public class SystemService
+{
+        /** Request that the init daemon start a named service. */
+    public static void start(String name) {
+        SystemProperties.set("ctl.start", name);
+    }
+    
+        /** Request that the init daemon stop a named service. */
+    public static void stop(String name) {
+        SystemProperties.set("ctl.stop", name);
+    }
+}
diff --git a/core/java/android/os/TokenWatcher.java b/core/java/android/os/TokenWatcher.java
new file mode 100755
index 0000000..ac3cc92
--- /dev/null
+++ b/core/java/android/os/TokenWatcher.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2007 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 android.os;
+
+import java.util.WeakHashMap;
+import java.util.Set;
+import android.util.Log;
+
+/**
+ * Helper class that helps you use IBinder objects as reference counted
+ * tokens.  IBinders make good tokens because we find out when they are
+ * removed
+ *
+ */
+public abstract class TokenWatcher
+{
+    /**
+     * Construct the TokenWatcher
+     *
+     * @param h A handler to call {@link #acquired} and {@link #released}
+     * on.  If you don't care, just call it like this, although your thread
+     * will have to be a Looper thread.
+     * <code>new TokenWatcher(new Handler())</code>
+     * @param tag A debugging tag for this TokenWatcher
+     */
+    public TokenWatcher(Handler h, String tag)
+    {
+        mHandler = h;
+        mTag = tag != null ? tag : "TokenWatcher";
+    }
+
+    /**
+     * Called when the number of active tokens goes from 0 to 1.
+     */
+    public abstract void acquired();
+
+    /**
+     * Called when the number of active tokens goes from 1 to 0.
+     */
+    public abstract void released();
+
+    /**
+     * Record that this token has been acquired.  When acquire is called, and
+     * the current count is 0, the acquired method is called on the given
+     * handler.
+     * 
+     * @param token An IBinder object.  If this token has already been acquired,
+     *              no action is taken.
+     * @param tag   A string used by the {@link #dump} method for debugging,
+     *              to see who has references.
+     */
+    public void acquire(IBinder token, String tag)
+    {
+        synchronized (mTokens) {
+            // explicitly checked to avoid bogus sendNotification calls because
+            // of the WeakHashMap and the GC
+            int oldSize = mTokens.size();
+
+            Death d = new Death(token, tag);
+            try {
+                token.linkToDeath(d, 0);
+            } catch (RemoteException e) {
+                return;
+            }
+            mTokens.put(token, d);
+
+            if (oldSize == 0 && !mAcquired) {
+                sendNotificationLocked(true);
+                mAcquired = true;
+            }
+        }
+    }
+
+    public void cleanup(IBinder token, boolean unlink)
+    {
+        synchronized (mTokens) {
+            Death d = mTokens.remove(token);
+            if (unlink && d != null) {
+                d.token.unlinkToDeath(d, 0);
+                d.token = null;
+            }
+
+            if (mTokens.size() == 0 && mAcquired) {
+                sendNotificationLocked(false);
+                mAcquired = false;
+            }
+        }
+    }
+
+    public void release(IBinder token)
+    {
+        cleanup(token, true);
+    }
+
+    public boolean isAcquired()
+    {
+        synchronized (mTokens) {
+            return mAcquired;
+        }
+    }
+
+    public void dump()
+    {
+        synchronized (mTokens) {
+            Set<IBinder> keys = mTokens.keySet();
+            Log.i(mTag, "Token count: " + mTokens.size());
+            int i = 0;
+            for (IBinder b: keys) {
+                Log.i(mTag, "[" + i + "] " + mTokens.get(b).tag + " - " + b);
+                i++;
+            }
+        }
+    }
+
+    private Runnable mNotificationTask = new Runnable() {
+        public void run()
+        {
+            int value;
+            synchronized (mTokens) {
+                value = mNotificationQueue;
+                mNotificationQueue = -1;
+            }
+            if (value == 1) {
+                acquired();
+            }
+            else if (value == 0) {
+                released();
+            }
+        }
+    };
+
+    private void sendNotificationLocked(boolean on)
+    {
+        int value = on ? 1 : 0;
+        if (mNotificationQueue == -1) {
+            // empty
+            mNotificationQueue = value;
+            mHandler.post(mNotificationTask);
+        }
+        else if (mNotificationQueue != value) {
+            // it's a pair, so cancel it
+            mNotificationQueue = -1;
+            mHandler.removeCallbacks(mNotificationTask);
+        }
+        // else, same so do nothing -- maybe we should warn?
+    }
+
+    private class Death implements IBinder.DeathRecipient
+    {
+        IBinder token;
+        String tag;
+
+        Death(IBinder token, String tag)
+        {
+            this.token = token;
+            this.tag = tag;
+        }
+
+        public void binderDied()
+        {
+            cleanup(token, false);
+        }
+
+        protected void finalize() throws Throwable
+        {
+            try {
+                if (token != null) {
+                    Log.w(mTag, "cleaning up leaked reference: " + tag);
+                    release(token);
+                }
+            }
+            finally {
+                super.finalize();
+            }
+        }
+    }
+
+    private WeakHashMap<IBinder,Death> mTokens = new WeakHashMap<IBinder,Death>();
+    private Handler mHandler;
+    private String mTag;
+    private int mNotificationQueue = -1;
+    private volatile boolean mAcquired = false;
+}
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
new file mode 100644
index 0000000..b924e84
--- /dev/null
+++ b/core/java/android/os/UEventObserver.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2008 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 android.os;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * UEventObserver is an abstract class that receives UEvent's from the kernel.<p>
+ *
+ * Subclass UEventObserver, implementing onUEvent(UEvent event), then call
+ * startObserving() with a match string. The UEvent thread will then call your
+ * onUEvent() method when a UEvent occurs that contains your match string.<p>
+ *
+ * Call stopObserving() to stop receiving UEvent's.<p>
+ *
+ * There is only one UEvent thread per process, even if that process has
+ * multiple UEventObserver subclass instances. The UEvent thread starts when
+ * the startObserving() is called for the first time in that process. Once
+ * started the UEvent thread will not stop (although it can stop notifying
+ * UEventObserver's via stopObserving()).<p>
+ *
+ * @hide
+*/
+public abstract class UEventObserver {
+    private static final String TAG = UEventObserver.class.getSimpleName();
+
+    /**
+     * Representation of a UEvent.
+     */
+    static public class UEvent {
+        // collection of key=value pairs parsed from the uevent message
+        public HashMap<String,String> mMap = new HashMap<String,String>();
+
+        public UEvent(String message) {
+            int offset = 0;
+            int length = message.length();
+
+            while (offset < length) {
+                int equals = message.indexOf('=', offset);
+                int at = message.indexOf(0, offset);
+                if (at < 0) break;
+
+                if (equals > offset && equals < at) {
+                    // key is before the equals sign, and value is after
+                    mMap.put(message.substring(offset, equals),
+                            message.substring(equals + 1, at));
+                }
+
+                offset = at + 1;
+            }
+        }
+
+        public String get(String key) {
+            return mMap.get(key);
+        }
+
+        public String get(String key, String defaultValue) {
+            String result = mMap.get(key);
+            return (result == null ? defaultValue : result);
+        }
+
+        public String toString() {
+            return mMap.toString();
+        }
+    }
+
+    private static UEventThread sThread;
+    private static boolean sThreadStarted = false;
+
+    private static class UEventThread extends Thread {
+        /** Many to many mapping of string match to observer.
+         *  Multimap would be better, but not available in android, so use
+         *  an ArrayList where even elements are the String match and odd
+         *  elements the corresponding UEventObserver observer */
+        private ArrayList<Object> mObservers = new ArrayList<Object>();
+        
+        UEventThread() {
+            super("UEventObserver");
+        }
+        
+        public void run() {
+            native_setup();
+
+            byte[] buffer = new byte[1024];
+            int len;
+            while (true) {
+                len = next_event(buffer);
+                if (len > 0) {
+                    String bufferStr = new String(buffer, 0, len);  // easier to search a String
+                    synchronized (mObservers) {
+                        for (int i = 0; i < mObservers.size(); i += 2) {
+                            if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {
+                                ((UEventObserver)mObservers.get(i+1))
+                                        .onUEvent(new UEvent(bufferStr));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        public void addObserver(String match, UEventObserver observer) {
+            synchronized(mObservers) {
+                mObservers.add(match);
+                mObservers.add(observer);
+            }
+        }
+        /** Removes every key/value pair where value=observer from mObservers */
+        public void removeObserver(UEventObserver observer) {
+            synchronized(mObservers) {
+                boolean found = true;
+                while (found) {
+                    found = false;
+                    for (int i = 0; i < mObservers.size(); i += 2) {
+                        if (mObservers.get(i+1) == observer) {
+                            mObservers.remove(i+1);
+                            mObservers.remove(i);
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private static native void native_setup();
+    private static native int next_event(byte[] buffer);
+
+    private static final synchronized void ensureThreadStarted() {
+        if (sThreadStarted == false) {
+            sThread = new UEventThread();
+            sThread.start();
+            sThreadStarted = true;
+        }
+    }
+
+    /**
+     * Begin observation of UEvent's.<p>
+     * This method will cause the UEvent thread to start if this is the first
+     * invocation of startObserving in this process.<p>
+     * Once called, the UEvent thread will call onUEvent() when an incoming
+     * UEvent matches the specified string.<p>
+     * This method can be called multiple times to register multiple matches.
+     * Only one call to stopObserving is required even with multiple registered
+     * matches.
+     * @param match A substring of the UEvent to match. Use "" to match all
+     *              UEvent's
+     */
+    public final synchronized void startObserving(String match) {
+        ensureThreadStarted();
+        sThread.addObserver(match, this);
+    }
+
+    /**
+     * End observation of UEvent's.<p>
+     * This process's UEvent thread will never call onUEvent() on this
+     * UEventObserver after this call. Repeated calls have no effect.
+     */
+    public final synchronized void stopObserving() {
+        sThread.removeObserver(this);
+    }
+
+    /**
+     * Subclasses of UEventObserver should override this method to handle
+     * UEvents.
+     */
+    public abstract void onUEvent(UEvent event);
+
+    protected void finalize() throws Throwable {
+        try {
+            stopObserving();
+        } finally {
+            super.finalize();
+        }
+    }
+}
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
new file mode 100644
index 0000000..0f75289
--- /dev/null
+++ b/core/java/android/os/Vibrator.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006 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 android.os;
+
+/**
+ * Class that operates the vibrator on the device.
+ * <p>
+ * If your process exits, any vibration you started with will stop.
+ */
+public class Vibrator
+{
+    IHardwareService mService;
+
+    /** @hide */
+    public Vibrator()
+    {
+        mService = IHardwareService.Stub.asInterface(
+                ServiceManager.getService("hardware"));
+    }
+
+    /**
+     * Turn the vibrator on.
+     *
+     * @param milliseconds How long to vibrate for.
+     */
+    public void vibrate(long milliseconds)
+    {
+        try {
+            mService.vibrate(milliseconds);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Vibrate with a given pattern.
+     *
+     * <p>
+     * Pass in an array of ints that are the times at which to turn on or off
+     * the vibrator.  The first one is how long to wait before turning it on,
+     * and then after that it alternates.  If you want to repeat, pass the
+     * index into the pattern at which to start the repeat.
+     *
+     * @param pattern an array of longs of times to turn the vibrator on or off.
+     * @param repeat the index into pattern at which to repeat, or -1 if
+     *        you don't want to repeat.
+     */
+    public void vibrate(long[] pattern, int repeat)
+    {
+        // catch this here because the server will do nothing.  pattern may
+        // not be null, let that be checked, because the server will drop it
+        // anyway
+        if (repeat < pattern.length) {
+            try {
+                mService.vibratePattern(pattern, repeat, new Binder());
+            } catch (RemoteException e) {
+            }
+        } else {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Turn the vibrator off.
+     */
+    public void cancel()
+    {
+        try {
+            mService.cancelVibrate();
+        } catch (RemoteException e) {
+        }
+    }
+}
diff --git a/core/java/android/os/package.html b/core/java/android/os/package.html
new file mode 100644
index 0000000..fb0ecda
--- /dev/null
+++ b/core/java/android/os/package.html
@@ -0,0 +1,6 @@
+<HTML>
+<BODY>
+Provides basic operating system services, message passing, and inter-process
+communication on the device.
+</BODY>
+</HTML>
\ No newline at end of file