Merge "Add RouteInfo objects for tracking routes." into honeycomb-LTE
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 9e6bcc8..6570078 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -109,7 +109,10 @@
 
     run_command("NETWORK INTERFACES", 10, "su", "root", "netcfg", NULL);
     dump_file("NETWORK ROUTES", "/proc/net/route");
+    dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
     dump_file("ARP CACHE", "/proc/net/arp");
+    run_command("IPTABLES", 10, "su", "root", "iptables", "-L", NULL);
+    run_command("IPTABLE NAT", 10, "su", "root", "iptables", "-t", "nat", "-L", NULL);
 
     run_command("WIFI NETWORKS", 20,
             "su", "root", "wpa_cli", "list_networks", NULL);
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
new file mode 100644
index 0000000..eaf087f
--- /dev/null
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.DhcpInfoInternal;
+import android.net.NetworkUtils;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * StateMachine that interacts with the native DHCP client and can talk to
+ * a controller that also needs to be a StateMachine
+ *
+ * The Dhcp state machine provides the following features:
+ * - Wakeup and renewal using the native DHCP client  (which will not renew
+ *   on its own when the device is in suspend state and this can lead to device
+ *   holding IP address beyond expiry)
+ * - A notification right before DHCP request or renewal is started. This
+ *   can be used for any additional setup before DHCP. For example, wifi sets
+ *   BT-Wifi coex settings right before DHCP is initiated
+ *
+ * @hide
+ */
+public class DhcpStateMachine extends StateMachine {
+
+    private static final String TAG = "DhcpStateMachine";
+    private static final boolean DBG = false;
+
+
+    /* A StateMachine that controls the DhcpStateMachine */
+    private StateMachine mController;
+
+    private Context mContext;
+    private BroadcastReceiver mBroadcastReceiver;
+    private AlarmManager mAlarmManager;
+    private PendingIntent mDhcpRenewalIntent;
+    private PowerManager.WakeLock mDhcpRenewWakeLock;
+    private static final String WAKELOCK_TAG = "DHCP";
+
+    private static final int DHCP_RENEW = 0;
+    private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
+
+    private enum DhcpAction {
+        START,
+        RENEW
+    };
+
+    private String mInterfaceName;
+    private boolean mRegisteredForPreDhcpNotification = false;
+
+    private static final int BASE = Protocol.BASE_DHCP;
+
+    /* Commands from controller to start/stop DHCP */
+    public static final int CMD_START_DHCP                  = BASE + 1;
+    public static final int CMD_STOP_DHCP                   = BASE + 2;
+    public static final int CMD_RENEW_DHCP                  = BASE + 3;
+
+    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+    public static final int CMD_PRE_DHCP_ACTION             = BASE + 4;
+    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+     * success/failure */
+    public static final int CMD_POST_DHCP_ACTION            = BASE + 5;
+
+    /* Command from controller to indicate DHCP discovery/renewal can continue
+     * after pre DHCP action is complete */
+    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = BASE + 6;
+
+    /* Message.arg1 arguments to CMD_POST_DHCP notification */
+    public static final int DHCP_SUCCESS = 1;
+    public static final int DHCP_FAILURE = 2;
+
+    private State mDefaultState = new DefaultState();
+    private State mStoppedState = new StoppedState();
+    private State mWaitBeforeStartState = new WaitBeforeStartState();
+    private State mRunningState = new RunningState();
+    private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
+
+    private DhcpStateMachine(Context context, StateMachine controller, String intf) {
+        super(TAG);
+
+        mContext = context;
+        mController = controller;
+        mInterfaceName = intf;
+
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
+        mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
+
+        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
+        mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                //DHCP renew
+                if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
+                //acquire a 40s wakelock to finish DHCP renewal
+                mDhcpRenewWakeLock.acquire(40000);
+                sendMessage(CMD_RENEW_DHCP);
+            }
+        };
+        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
+
+        addState(mDefaultState);
+            addState(mStoppedState, mDefaultState);
+            addState(mWaitBeforeStartState, mDefaultState);
+            addState(mRunningState, mDefaultState);
+            addState(mWaitBeforeRenewalState, mDefaultState);
+
+        setInitialState(mStoppedState);
+    }
+
+    public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller,
+            String intf) {
+        DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
+        dsm.start();
+        return dsm;
+    }
+
+    /**
+     * This sends a notification right before DHCP request/renewal so that the
+     * controller can do certain actions before DHCP packets are sent out.
+     * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
+     * to indicate DHCP can continue
+     *
+     * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
+     * handling during Dhcp
+     */
+    public void registerForPreDhcpNotification() {
+        mRegisteredForPreDhcpNotification = true;
+    }
+
+    class DefaultState extends State {
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_RENEW_DHCP:
+                    Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
+                    break;
+                case SM_QUIT_CMD:
+                    mContext.unregisterReceiver(mBroadcastReceiver);
+                    //let parent kill the state machine
+                    return NOT_HANDLED;
+                default:
+                    Log.e(TAG, "Error! unhandled message  " + message);
+                    break;
+            }
+            return HANDLED;
+        }
+    }
+
+
+    class StoppedState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_START_DHCP:
+                    if (mRegisteredForPreDhcpNotification) {
+                        /* Notify controller before starting DHCP */
+                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
+                        transitionTo(mWaitBeforeStartState);
+                    } else {
+                        if (runDhcp(DhcpAction.START)) {
+                            transitionTo(mRunningState);
+                        }
+                    }
+                    break;
+                case CMD_STOP_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+                    break;
+            }
+            return retValue;
+        }
+    }
+
+    class WaitBeforeStartState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
+                    if (runDhcp(DhcpAction.START)) {
+                        transitionTo(mRunningState);
+                    } else {
+                        transitionTo(mStoppedState);
+                    }
+                    break;
+                case CMD_STOP_DHCP:
+                    transitionTo(mStoppedState);
+                    break;
+                case CMD_START_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+                    break;
+            }
+            return retValue;
+        }
+    }
+
+    class RunningState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_STOP_DHCP:
+                    mAlarmManager.cancel(mDhcpRenewalIntent);
+                    if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+                        Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+                    }
+                    transitionTo(mStoppedState);
+                    break;
+                case CMD_RENEW_DHCP:
+                    if (mRegisteredForPreDhcpNotification) {
+                        /* Notify controller before starting DHCP */
+                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
+                        transitionTo(mWaitBeforeRenewalState);
+                    } else {
+                        if (!runDhcp(DhcpAction.RENEW)) {
+                            transitionTo(mStoppedState);
+                        }
+                    }
+                    break;
+                case CMD_START_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+            }
+            return retValue;
+        }
+    }
+
+    class WaitBeforeRenewalState extends State {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_STOP_DHCP:
+                    mAlarmManager.cancel(mDhcpRenewalIntent);
+                    if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+                        Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+                    }
+                    transitionTo(mStoppedState);
+                    break;
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
+                    if (runDhcp(DhcpAction.RENEW)) {
+                       transitionTo(mRunningState);
+                    } else {
+                       transitionTo(mStoppedState);
+                    }
+                    break;
+                case CMD_START_DHCP:
+                    //ignore
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+                    break;
+            }
+            return retValue;
+        }
+    }
+
+    private boolean runDhcp(DhcpAction dhcpAction) {
+        boolean success = false;
+        DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
+
+        if (dhcpAction == DhcpAction.START) {
+            Log.d(TAG, "DHCP request on " + mInterfaceName);
+            success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
+        } else if (dhcpAction == DhcpAction.RENEW) {
+            Log.d(TAG, "DHCP renewal on " + mInterfaceName);
+            success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal);
+        }
+
+        if (success) {
+            Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
+            //Do it a bit earlier than half the lease duration time
+            //to beat the native DHCP client and avoid extra packets
+            //48% for one hour lease time = 29 minutes
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime() +
+                    dhcpInfoInternal.leaseDuration * 480, //in milliseconds
+                    mDhcpRenewalIntent);
+
+            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal)
+                .sendToTarget();
+        } else {
+            Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " +
+                    NetworkUtils.getDhcpError());
+            NetworkUtils.stopDhcp(mInterfaceName);
+            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
+                .sendToTarget();
+        }
+        return success;
+    }
+}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b3f3988..823d10f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -80,6 +80,16 @@
     public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
 
     /**
+     * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
+     * a result (either success or failure) from the daemon.
+     * @param interfaceName the name of the interface to configure
+     * @param ipInfo if the request succeeds, this object is filled in with
+     * the IP address information.
+     * @return {@code true} for success, {@code false} for failure
+     */
+    public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo);
+
+    /**
      * Shut down the DHCP client daemon.
      * @param interfaceName the name of the interface for which the daemon
      * should be stopped
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index cf72ec4..6b676b4 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -64,15 +64,16 @@
  *
  * <p>
  * A progress bar can also be made indeterminate. In indeterminate mode, the
- * progress bar shows a cyclic animation. This mode is used by applications
- * when the length of the task is unknown. 
+ * progress bar shows a cyclic animation without an indication of progress. This mode is used by
+ * applications when the length of the task is unknown. The indeterminate progress bar can be either
+ * a spinning wheel or a horizontal bar.
  * </p>
  *
  * <p>The following code example shows how a progress bar can be used from
  * a worker thread to update the user interface to notify the user of progress:
  * </p>
  * 
- * <pre class="prettyprint">
+ * <pre>
  * public class MyActivity extends Activity {
  *     private static final int PROGRESS = 0x1;
  *
@@ -91,7 +92,7 @@
  *         // Start lengthy operation in a background thread
  *         new Thread(new Runnable() {
  *             public void run() {
- *                 while (mProgressStatus < 100) {
+ *                 while (mProgressStatus &lt; 100) {
  *                     mProgressStatus = doWork();
  *
  *                     // Update the progress bar
@@ -104,8 +105,61 @@
  *             }
  *         }).start();
  *     }
- * }
- * </pre>
+ * }</pre>
+ *
+ * <p>To add a progress bar to a layout file, you can use the {@code &lt;ProgressBar&gt;} element.
+ * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a
+ * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal
+ * Widget.ProgressBar.Horizontal} style, like so:</p>
+ *
+ * <pre>
+ * &lt;ProgressBar
+ *     style="@android:style/Widget.ProgressBar.Horizontal"
+ *     ... /&gt;</pre>
+ *
+ * <p>If you will use the progress bar to show real progress, you must use the horizontal bar. You
+ * can then increment the  progress with {@link #incrementProgressBy incrementProgressBy()} or
+ * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If
+ * necessary, you can adjust the maximum value (the value for a full bar) using the {@link
+ * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed
+ * below.</p>
+ *
+ * <p>Another common style to apply to the progress bar is {@link
+ * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller
+ * version of the spinning wheel&mdash;useful when waiting for content to load.
+ * For example, you can insert this kind of progress bar into your default layout for
+ * a view that will be populated by some content fetched from the Internet&mdash;the spinning wheel
+ * appears immediately and when your application receives the content, it replaces the progress bar
+ * with the loaded content. For example:</p>
+ *
+ * <pre>
+ * &lt;LinearLayout
+ *     android:orientation="horizontal"
+ *     ... &gt;
+ *     &lt;ProgressBar
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         style="@android:style/Widget.ProgressBar.Small"
+ *         android:layout_marginRight="5dp" /&gt;
+ *     &lt;TextView
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:text="@string/loading" /&gt;
+ * &lt;/LinearLayout&gt;</pre>
+ *
+ * <p>Other progress bar styles provided by the system include:</p>
+ * <ul>
+ * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
+ * Widget.ProgressBar.Small.Inverse}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
+ * Widget.ProgressBar.Large.Inverse}</li>
+ * </ul>
+ * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
+ * if your application uses a light colored theme (a white background).</p>
  *  
  * <p><strong>XML attributes</b></strong> 
  * <p> 
@@ -113,13 +167,21 @@
  * {@link android.R.styleable#View View Attributes}
  * </p>
  * 
- * <p><strong>Styles</b></strong> 
- * <p> 
- * @attr ref android.R.styleable#Theme_progressBarStyle
- * @attr ref android.R.styleable#Theme_progressBarStyleSmall
- * @attr ref android.R.styleable#Theme_progressBarStyleLarge
- * @attr ref android.R.styleable#Theme_progressBarStyleHorizontal
- * </p>
+ * @attr ref android.R.styleable#ProgressBar_animationResolution
+ * @attr ref android.R.styleable#ProgressBar_indeterminate
+ * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
+ * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
+ * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
+ * @attr ref android.R.styleable#ProgressBar_interpolator
+ * @attr ref android.R.styleable#ProgressBar_max
+ * @attr ref android.R.styleable#ProgressBar_maxHeight
+ * @attr ref android.R.styleable#ProgressBar_maxWidth
+ * @attr ref android.R.styleable#ProgressBar_minHeight
+ * @attr ref android.R.styleable#ProgressBar_minWidth
+ * @attr ref android.R.styleable#ProgressBar_progress
+ * @attr ref android.R.styleable#ProgressBar_progressDrawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgress
  */
 @RemoteView
 public class ProgressBar extends View {
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 101dd91..3973344 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -44,16 +44,16 @@
  * In this usage model there is no need for the destination to
  * use the connect methods. The typical sequence of operations is:</p>
  *<ol>
- *   <li>Client calls AsyncChannel#connect</li>
- *   <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *   <li>Client calls AsyncChannel#connectSync or Asynchronously:</li>
+ *      <ol>For an asynchronous half connection client calls AsyncChannel#connect.</ol>
+ *          <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *      </ol>
  *   <li><code>comm-loop:</code></li>
- *   <li>Client calls AsyncChannel#sendMessage(msgX)</li>
- *   <li>Server receives and processes msgX</li>
- *   <li>Server optionally calls AsyncChannel#replyToMessage(msgY)
- *       and if sent Client receives and processes msgY</li>
+ *   <li>Client calls AsyncChannel#sendMessage</li>
+ *   <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage
  *   <li>Loop to <code>comm-loop</code> until done</li>
- *   <li>When done Client calls {@link AsyncChannel#disconnect(int)}</li>
- *   <li>Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
+ *   <li>When done Client calls {@link AsyncChannel#disconnect}</li>
+ *   <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
  *</ol>
  *<br/>
  * <p>A second usage model is where the server/destination needs to know
@@ -62,21 +62,26 @@
  * different state for each client. In this model the server will also
  * use the connect methods. The typical sequence of operation is:</p>
  *<ol>
- *   <li>Client calls AsyncChannel#connect</li>
- *   <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
- *   <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ *   <li>Client calls AsyncChannel#fullyConnectSync or Asynchronously:<li>
+ *      <ol>For an asynchronous full connection it calls AsyncChannel#connect</li>
+ *          <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *          <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ *      </ol>
  *   <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li>
- *   <li>Server calls AsyncChannel#connect</li>
- *   <li>Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *   <li>Server calls AsyncChannel#connected</li>
  *   <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li>
  *   <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li>
  *   <li><code>comm-loop:</code></li>
  *   <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage
  *       to communicate and perform work</li>
  *   <li>Loop to <code>comm-loop</code> until done</li>
- *   <li>When done Client/Server calls {@link AsyncChannel#disconnect(int)}</li>
+ *   <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li>
  *   <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
  *</ol>
+ *
+ * TODO: Consider simplifying where we have connect and fullyConnect with only one response
+ * message RSP_CHANNEL_CONNECT instead of two, CMD_CHANNEL_HALF_CONNECTED and
+ * CMD_CHANNEL_FULLY_CONNECTED. We'd also change CMD_CHANNEL_FULL_CONNECTION to REQ_CHANNEL_CONNECT.
  */
 public class AsyncChannel {
     /** Log tag */
@@ -85,6 +90,8 @@
     /** Enable to turn on debugging */
     private static final boolean DBG = false;
 
+    private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL;
+
     /**
      * Command sent when the channel is half connected. Half connected
      * means that the channel can be used to send commends to the destination
@@ -98,7 +105,7 @@
      * msg.obj  == the AsyncChannel
      * msg.replyTo == dstMessenger if successful
      */
-    public static final int CMD_CHANNEL_HALF_CONNECTED = -1;
+    public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0;
 
     /**
      * Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED.
@@ -107,7 +114,7 @@
      *
      * msg.replyTo = srcMessenger.
      */
-    public static final int CMD_CHANNEL_FULL_CONNECTION = -2;
+    public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1;
 
     /**
      * Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION.
@@ -115,31 +122,33 @@
      *
      * msg.arg1 == 0 : Accept connection
      *               : All other values signify the destination rejected the connection
-     *                 and {@link AsyncChannel#disconnect(int)} would typically be called.
+     *                 and {@link AsyncChannel#disconnect} would typically be called.
      */
-    public static final int CMD_CHANNEL_FULLY_CONNECTED = -3;
+    public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2;
 
     /**
      * Command sent when one side or the other wishes to disconnect. The sender
      * may or may not be able to receive a reply depending upon the protocol and
-     * the state of the connection. The receiver should call {@link AsyncChannel#disconnect(int)}
+     * the state of the connection. The receiver should call {@link AsyncChannel#disconnect}
      * to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED
      * when the channel is closed.
      *
      * msg.replyTo = messenger that is disconnecting
      */
-    public static final int CMD_CHANNEL_DISCONNECT = -4;
+    public static final int CMD_CHANNEL_DISCONNECT = BASE + 3;
 
     /**
      * Command sent when the channel becomes disconnected. This is sent when the
      * channel is forcibly disconnected by the system or as a reply to CMD_CHANNEL_DISCONNECT.
      *
      * msg.arg1 == 0 : STATUS_SUCCESSFUL
+     *             1 : STATUS_BINDING_UNSUCCESSFUL
+     *             2 : STATUS_SEND_UNSUCCESSFUL
      *               : All other values signify failure and the channel state is indeterminate
      * msg.obj  == the AsyncChannel
      * msg.replyTo = messenger disconnecting or null if it was never connected.
      */
-    public static final int CMD_CHANNEL_DISCONNECTED = -5;
+    public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
 
     /** Successful status always 0, !0 is an unsuccessful status */
     public static final int STATUS_SUCCESSFUL = 0;
@@ -147,6 +156,12 @@
     /** Error attempting to bind on a connect */
     public static final int STATUS_BINDING_UNSUCCESSFUL = 1;
 
+    /** Error attempting to send a message */
+    public static final int STATUS_SEND_UNSUCCESSFUL = 2;
+
+    /** CMD_FULLY_CONNECTED refused because a connection already exists*/
+    public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
+
     /** Service connection */
     private AsyncChannelConnection mConnection;
 
@@ -169,9 +184,7 @@
     }
 
     /**
-     * Connect handler to named package/class.
-     *
-     * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
+     * Connect handler to named package/class synchronously.
      *
      * @param srcContext is the context of the source
      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
@@ -179,8 +192,10 @@
      * @param dstPackageName is the destination package name
      * @param dstClassName is the fully qualified class name (i.e. contains
      *            package name)
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
      */
-    private void connectSrcHandlerToPackage(
+    public int connectSrcHandlerToPackageSync(
             Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) {
         if (DBG) log("connect srcHandler to dst Package & class E");
 
@@ -202,11 +217,61 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClassName(dstPackageName, dstClassName);
         boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-        if (!result) {
-            replyHalfConnected(STATUS_BINDING_UNSUCCESSFUL);
-        }
-
         if (DBG) log("connect srcHandler to dst Package & class X result=" + result);
+        return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL;
+    }
+
+    /**
+     * Connect a handler to Messenger synchronously.
+     *
+     * @param srcContext is the context of the source
+     * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+     *            messages
+     * @param dstMessenger is the hander to send messages to.
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
+     */
+    public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+        if (DBG) log("halfConnectSync srcHandler to the dstMessenger  E");
+
+        // We are connected
+        connected(srcContext, srcHandler, dstMessenger);
+
+        if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
+        return STATUS_SUCCESSFUL;
+    }
+
+    /**
+     * connect two local Handlers synchronously.
+     *
+     * @param srcContext is the context of the source
+     * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+     *            messages
+     * @param dstHandler is the hander to send messages to.
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
+     */
+    public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
+        return connectSync(srcContext, srcHandler, new Messenger(dstHandler));
+    }
+
+    /**
+     * Fully connect two local Handlers synchronously.
+     *
+     * @param srcContext is the context of the source
+     * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+     *            messages
+     * @param dstHandler is the hander to send messages to.
+     *
+     * @return STATUS_SUCCESSFUL on success any other value is an error.
+     */
+    public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
+        int status = connectSync(srcContext, srcHandler, dstHandler);
+        if (status == STATUS_SUCCESSFUL) {
+            Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION);
+            status = response.arg1;
+        }
+        return status;
     }
 
     /**
@@ -241,8 +306,11 @@
                 mDstClassName = dstClassName;
             }
 
+            @Override
             public void run() {
-                connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName);
+                int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName,
+                        mDstClassName);
+                replyHalfConnected(result);
             }
         }
 
@@ -281,15 +349,8 @@
     public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
         if (DBG) log("connect srcHandler to the dstMessenger  E");
 
-        // Initialize source fields
-        mSrcContext = srcContext;
-        mSrcHandler = srcHandler;
-        mSrcMessenger = new Messenger(mSrcHandler);
-
-        // Initialize destination fields
-        mDstMessenger = dstMessenger;
-
-        if (DBG) log("tell source we are half connected");
+        // We are connected
+        connected(srcContext, srcHandler, dstMessenger);
 
         // Tell source we are half connected
         replyHalfConnected(STATUS_SUCCESSFUL);
@@ -298,11 +359,31 @@
     }
 
     /**
-     * Connect two local Handlers.
+     * Connect handler to messenger. This method is typically called
+     * when a server receives a CMD_CHANNEL_FULL_CONNECTION request
+     * and initializes the internal instance variables to allow communication
+     * with the dstMessenger.
      *
-     * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
-     *      msg.arg1 = status
-     *      msg.obj = the AsyncChannel
+     * @param srcContext
+     * @param srcHandler
+     * @param dstMessenger
+     */
+    public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+        if (DBG) log("connected srcHandler to the dstMessenger  E");
+
+        // Initialize source fields
+        mSrcContext = srcContext;
+        mSrcHandler = srcHandler;
+        mSrcMessenger = new Messenger(mSrcHandler);
+
+        // Initialize destination fields
+        mDstMessenger = dstMessenger;
+
+        if (DBG) log("connected srcHandler to the dstMessenger X");
+    }
+
+    /**
+     * Connect two local Handlers.
      *
      * @param srcContext is the context of the source
      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
@@ -331,6 +412,7 @@
      * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED
      */
     public void disconnected() {
+        mSrcContext = null;
         mSrcHandler = null;
         mSrcMessenger = null;
         mDstMessenger = null;
@@ -341,15 +423,11 @@
      * Disconnect
      */
     public void disconnect() {
-        if (mConnection != null) {
+        if ((mConnection != null) && (mSrcContext != null)) {
             mSrcContext.unbindService(mConnection);
         }
         if (mSrcHandler != null) {
-            Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
-            msg.arg1 = STATUS_SUCCESSFUL;
-            msg.obj = this;
-            msg.replyTo = mDstMessenger;
-            mSrcHandler.sendMessage(msg);
+            replyDisconnected(STATUS_SUCCESSFUL);
         }
     }
 
@@ -363,7 +441,7 @@
         try {
             mDstMessenger.send(msg);
         } catch (RemoteException e) {
-            log("TODO: handle sendMessage RemoteException" + e);
+            replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
         }
     }
 
@@ -444,6 +522,7 @@
      */
     public void replyToMessage(Message srcMsg, Message dstMsg) {
         try {
+            dstMsg.replyTo = mSrcMessenger;
             srcMsg.replyTo.send(dstMsg);
         } catch (RemoteException e) {
             log("TODO: handle replyToMessage RemoteException" + e);
@@ -694,10 +773,14 @@
         private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
             SyncMessenger sm = SyncMessenger.obtain();
             try {
-                msg.replyTo = sm.mMessenger;
-                dstMessenger.send(msg);
-                synchronized (sm.mHandler.mLockObject) {
-                    sm.mHandler.mLockObject.wait();
+                if (dstMessenger != null && msg != null) {
+                    msg.replyTo = sm.mMessenger;
+                    synchronized (sm.mHandler.mLockObject) {
+                        dstMessenger.send(msg);
+                        sm.mHandler.mLockObject.wait();
+                    }
+                } else {
+                    sm.mHandler.mResultMsg = null;
                 }
             } catch (InterruptedException e) {
                 sm.mHandler.mResultMsg = null;
@@ -712,6 +795,7 @@
 
     /**
      * Reply to the src handler that we're half connected.
+     * see: CMD_CHANNEL_HALF_CONNECTED for message contents
      *
      * @param status to be stored in msg.arg1
      */
@@ -724,23 +808,36 @@
     }
 
     /**
+     * Reply to the src handler that we are disconnected
+     * see: CMD_CHANNEL_DISCONNECTED for message contents
+     *
+     * @param status to be stored in msg.arg1
+     */
+    private void replyDisconnected(int status) {
+        Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
+        msg.arg1 = status;
+        msg.obj = this;
+        msg.replyTo = mDstMessenger;
+        mSrcHandler.sendMessage(msg);
+    }
+
+
+    /**
      * ServiceConnection to receive call backs.
      */
     class AsyncChannelConnection implements ServiceConnection {
         AsyncChannelConnection() {
         }
 
+        @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             mDstMessenger = new Messenger(service);
             replyHalfConnected(STATUS_SUCCESSFUL);
         }
 
+        @Override
         public void onServiceDisconnected(ComponentName className) {
-            Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
-            msg.arg1 = STATUS_SUCCESSFUL;
-            msg.obj = AsyncChannel.this;
-            msg.replyTo = mDstMessenger;
-            mSrcHandler.sendMessage(msg);
+            replyDisconnected(STATUS_SUCCESSFUL);
         }
     }
 
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
new file mode 100644
index 0000000..b35f615
--- /dev/null
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+/**
+ * This class defines Message.what base addresses for various protocols that are recognized
+ * to be unique by any {@link com.android.internal.util.Statemachine} implementation. This
+ * allows for interaction between different StateMachine implementations without a conflict
+ * of message codes.
+ *
+ * As an example, all messages in {@link android.net.wifi.WifiStateMachine} will have message
+ * codes with Message.what starting at Protocol.WIFI + 1 and less than or equal to Protocol.WIFI +
+ * Protocol.MAX_MESSAGE
+ *
+ * {@hide}
+ */
+public class Protocol {
+    public static final int MAX_MESSAGE                                             = 0x0000FFFF;
+
+    /** Base reserved for system */
+    public static final int BASE_SYSTEM_RESERVED                                    = 0x00010000;
+    public static final int BASE_SYSTEM_ASYNC_CHANNEL                               = 0x00011000;
+
+    /** Non system protocols */
+    public static final int BASE_WIFI                                               = 0x00020000;
+    public static final int BASE_DHCP                                               = 0x00030000;
+    public static final int BASE_DATA_CONNECTION                                    = 0x00040000;
+    public static final int BASE_DATA_CONNECTION_TRACKER                            = 0x00050000;
+
+    //TODO: define all used protocols
+}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 33ba26a..904eaf9 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -40,6 +40,16 @@
                     const char *dns2,
                     const char *server,
                     uint32_t  *lease);
+
+int dhcp_do_request_renew(const char *ifname,
+                    const char *ipaddr,
+                    const char *gateway,
+                    uint32_t  *prefixLength,
+                    const char *dns1,
+                    const char *dns2,
+                    const char *server,
+                    uint32_t  *lease);
+
 int dhcp_stop(const char *ifname);
 int dhcp_release_lease(const char *ifname);
 char *dhcp_get_errmsg();
@@ -145,7 +155,8 @@
     return (jint)result;
 }
 
-static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
+        jobject info, bool renew)
 {
     int result;
     char  ipaddr[PROPERTY_VALUE_MAX];
@@ -159,8 +170,14 @@
     const char *nameStr = env->GetStringUTFChars(ifname, NULL);
     if (nameStr == NULL) return (jboolean)false;
 
-    result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
-                                        dns1, dns2, server, &lease);
+    if (renew) {
+        result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
+                dns1, dns2, server, &lease);
+    } else {
+        result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
+                dns1, dns2, server, &lease);
+    }
+
     env->ReleaseStringUTFChars(ifname, nameStr);
     if (result == 0 && dhcpInfoInternalFieldIds.dhcpInfoInternalClass != NULL) {
         env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
@@ -198,6 +215,17 @@
     return (jboolean)(result == 0);
 }
 
+static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
+}
+
+static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
+}
+
+
 static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
 {
     int result;
@@ -241,6 +269,7 @@
     { "removeDefaultRoute", "(Ljava/lang/String;)I",  (void *)android_net_utils_removeDefaultRoute },
     { "resetConnections", "(Ljava/lang/String;)I",  (void *)android_net_utils_resetConnections },
     { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z",  (void *)android_net_utils_runDhcp },
+    { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z",  (void *)android_net_utils_runDhcpRenew },
     { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
     { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 1da2622..7c84bd2 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -264,8 +264,8 @@
 names.</p>
 <table>
     <tr>
-        <th>Qualifier</th>
-        <th>Values</th>
+        <th>Configuration</th>
+        <th>Qualifier Values</th>
         <th>Description</th>
     </tr>
     <tr id="MccQualifier">
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index 2da022c..4a574be 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -295,7 +295,9 @@
    {@link android.view.ViewGroup.MarginLayoutParams} for further information.
    </p>
 
-<p>For more information about dimensions, see <a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">Dimension Values</a>.</p>
+   <p>For more information about dimensions, see 
+   <a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">Dimension Values</a>.
+   </p>
    
 
 
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index 669beac..8ce1d9a 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -75,11 +75,17 @@
      * @param name The name to assign to the object.
      */
     public void setName(String name) {
+        if (name == null) {
+            throw new RSIllegalArgumentException(
+                "setName requires a string of non-zero length.");
+        }
         if(name.length() < 1) {
-            throw new RSIllegalArgumentException("setName does not accept a zero length string.");
+            throw new RSIllegalArgumentException(
+                "setName does not accept a zero length string.");
         }
         if(mName != null) {
-            throw new RSIllegalArgumentException("setName object already has a name.");
+            throw new RSIllegalArgumentException(
+                "setName object already has a name.");
         }
 
         try {
@@ -106,9 +112,9 @@
     }
 
     /**
-     * destroy disconnects the object from the native object effectivly
+     * destroy disconnects the object from the native object effectively
      * rendering this java object dead.  The primary use is to force immediate
-     * cleanup of resources when its believed the GC will not respond quickly
+     * cleanup of resources when it is believed the GC will not respond quickly
      * enough.
      */
     synchronized public void destroy() {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 23230a6..8a4789a 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -76,13 +76,15 @@
 static float SC_randf(float max) {
     float r = (float)rand();
     r *= max;
-    return r / RAND_MAX;
+    r /= RAND_MAX;
+    return r;
 }
 
 static float SC_randf2(float min, float max) {
     float r = (float)rand();
+    r /= RAND_MAX;
     r = r * (max - min) + min;
-    return r / RAND_MAX;
+    return r;
 }
 
 static int SC_randi(int max) {
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index bee0d5e..62fb732 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -100,6 +100,7 @@
       mNumBandwidthHistoryItems(0),
       mTotalTransferTimeUs(0),
       mTotalTransferBytes(0),
+      mPrevBandwidthMeasureTimeUs(0),
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL) {
 }
@@ -534,6 +535,16 @@
         mTotalTransferBytes -= entry->mNumBytes;
         mBandwidthHistory.erase(mBandwidthHistory.begin());
         --mNumBandwidthHistoryItems;
+        int64_t timeNowUs = ALooper::GetNowUs();
+        if (timeNowUs - mPrevBandwidthMeasureTimeUs > 2000000LL) {
+            if (mPrevBandwidthMeasureTimeUs != 0) {
+                double estimatedBandwidth =
+                    ((double)mTotalTransferBytes * 8E3 / mTotalTransferTimeUs);
+                LOGI("estimated avg bandwidth is %8.2f kbps in the past %lld us",
+                    estimatedBandwidth, timeNowUs - mPrevBandwidthMeasureTimeUs);
+            }
+            mPrevBandwidthMeasureTimeUs = timeNowUs;
+        }
     }
 }
 
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
index 2569568..0d68234 100644
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ b/media/libstagefright/include/NuHTTPDataSource.h
@@ -97,6 +97,7 @@
     size_t mNumBandwidthHistoryItems;
     int64_t mTotalTransferTimeUs;
     size_t mTotalTransferBytes;
+    int64_t mPrevBandwidthMeasureTimeUs;
 
     DecryptHandle *mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index f347623..6edd0b6 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -3025,7 +3025,7 @@
             dataCall.active = p.readInt();
             dataCall.type = p.readString();
             String addresses = p.readString();
-            if (TextUtils.isEmpty(addresses)) {
+            if (!TextUtils.isEmpty(addresses)) {
                 dataCall.addresses = addresses.split(" ");
             }
         } else {
@@ -3034,7 +3034,8 @@
             dataCall.active = p.readInt();
             dataCall.type = p.readString();
             dataCall.ifname = p.readString();
-            if (TextUtils.isEmpty(dataCall.ifname)) {
+            if ((dataCall.status == DataConnection.FailCause.NONE.getErrorCode()) &&
+                    TextUtils.isEmpty(dataCall.ifname)) {
               throw new RuntimeException("getDataCallState, no ifname");
             }
             String addresses = p.readString();
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index a6c7777..2f3b177 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -135,6 +135,7 @@
     static final int MSG_ID_CALL_SETUP               = 4;
     static final int MSG_ID_REFRESH                  = 5;
     static final int MSG_ID_RESPONSE                 = 6;
+    static final int MSG_ID_SIM_READY                = 7;
 
     static final int MSG_ID_RIL_MSG_DECODED          = 10;
 
@@ -172,9 +173,11 @@
         mIccRecords = ir;
 
         // Register for SIM ready event.
+        mCmdIf.registerForSIMReady(this, MSG_ID_SIM_READY, null);
+        mCmdIf.registerForRUIMReady(this, MSG_ID_SIM_READY, null);
+        mCmdIf.registerForNVReady(this, MSG_ID_SIM_READY, null);
         mIccRecords.registerForRecordsLoaded(this, MSG_ID_ICC_RECORDS_LOADED, null);
 
-        mCmdIf.reportStkServiceIsRunning(null);
         CatLog.d(this, "Is running");
     }
 
@@ -588,6 +591,10 @@
         case MSG_ID_RESPONSE:
             handleCmdResponse((CatResponseMessage) msg.obj);
             break;
+        case MSG_ID_SIM_READY:
+            CatLog.d(this, "SIM ready. Reporting STK service running now...");
+            mCmdIf.reportStkServiceIsRunning(null);
+            break;
         default:
             throw new AssertionError("Unrecognized CAT command: " + msg.what);
         }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index cd585cf..e299d4a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -99,9 +99,9 @@
 
     @Override
     protected boolean isDnsOk(String[] domainNameServers) {
-        if ((NULL_IP.equals(domainNameServers[0])
+        if (NULL_IP.equals(domainNameServers[0])
                 && NULL_IP.equals(domainNameServers[1])
-                && !((CDMAPhone) phone).isDnsCheckDisabled())) {
+                && !phone.isDnsCheckDisabled()) {
             return false;
         } else {
             return true;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 109daf0..32c5d75 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -44,22 +44,14 @@
 
     CDMALTEPhone mCdmaLtePhone;
 
-    private int gprsState = ServiceState.STATE_OUT_OF_SERVICE;
-
-    private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE;
+    private ServiceState  mLteSS;  // The last LTE state from Voice Registration
 
     public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
         super(phone);
         mCdmaLtePhone = phone;
-        if (DBG) log("CdmaLteServiceStateTracker Constructors");
-    }
 
-    /**
-     * @return The current GPRS state. IN_SERVICE is the same as "attached" and
-     *         OUT_OF_SERVICE is the same as detached.
-     */
-    public int getCurrentDataConnectionState() {
-        return gprsState;
+        mLteSS = new ServiceState();
+        if (DBG) log("CdmaLteServiceStateTracker Constructors");
     }
 
     @Override
@@ -77,11 +69,13 @@
     }
 
     /**
-     * The LTE data connection state, only return true here
+     * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA
      */
     @Override
-    protected boolean checkAdditionalDataAvaiable() {
-        return newGPRSState != ServiceState.STATE_IN_SERVICE;
+    protected void setCdmaTechnology(int radioTechnology) {
+        // Called on voice registration state response.
+        // Just record new CDMA radio technology
+        newSS.setRadioTechnology(radioTechnology);
     }
 
     /**
@@ -109,14 +103,10 @@
                 }
             }
 
-            newGPRSState = regCodeToServiceState(regState);
             // Not sure if this is needed in CDMALTE phone.
             // mDataRoaming = regCodeIsRoaming(regState);
-            if (newGPRSState == ServiceState.STATE_IN_SERVICE) {
-                this.newCdmaDataConnectionState = newGPRSState;
-                newNetworkType = type;
-                newSS.setRadioTechnology(type);
-            }
+            mLteSS.setRadioTechnology(type);
+            mLteSS.setState(regCodeToServiceState(regState));
         } else {
             super.handlePollStateResultMessage(what, ar);
         }
@@ -216,6 +206,21 @@
 
     @Override
     protected void pollStateDone() {
+        // determine data NetworkType from both LET and CDMA SS
+        if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) {
+            //in LTE service
+            newNetworkType = mLteSS.getRadioTechnology();
+            mNewDataConnectionState = mLteSS.getState();
+            newSS.setRadioTechnology(newNetworkType);
+            log("pollStateDone LTE/eHRPD STATE_IN_SERVICE newNetworkType = " + newNetworkType);
+        } else {
+            // LTE out of service, get CDMA Service State
+            newNetworkType = newSS.getRadioTechnology();
+            mNewDataConnectionState = radioTechnologyToDataServiceState(newNetworkType);
+            log("pollStateDone CDMA STATE_IN_SERVICE newNetworkType = " + newNetworkType +
+                " mNewDataConnectionState = " + mNewDataConnectionState);
+        }
+
         if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]");
 
         boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE
@@ -225,15 +230,15 @@
                 && newSS.getState() != ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionAttached =
-            this.cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE
-                && this.newCdmaDataConnectionState == ServiceState.STATE_IN_SERVICE;
+            mDataConnectionState != ServiceState.STATE_IN_SERVICE
+                && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionDetached =
-            this.cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE
-                && this.newCdmaDataConnectionState != ServiceState.STATE_IN_SERVICE;
+            mDataConnectionState == ServiceState.STATE_IN_SERVICE
+                && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionChanged =
-            cdmaDataConnectionState != newCdmaDataConnectionState;
+            mDataConnectionState != mNewDataConnectionState;
 
         boolean hasNetworkTypeChanged = networkType != newNetworkType;
 
@@ -272,9 +277,9 @@
         }
         // Add an event log when connection state changes
         if (ss.getState() != newSS.getState()
-                || cdmaDataConnectionState != newCdmaDataConnectionState) {
+                || mDataConnectionState != mNewDataConnectionState) {
             EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(),
-                    cdmaDataConnectionState, newSS.getState(), newCdmaDataConnectionState);
+                    mDataConnectionState, newSS.getState(), mNewDataConnectionState);
         }
 
         ServiceState tss;
@@ -283,6 +288,7 @@
         newSS = tss;
         // clean slate for next time
         newSS.setStateOutOfService();
+        mLteSS.setStateOutOfService();
 
         // TODO: 4G Tech Handoff
         // if (has4gHandoff) {
@@ -309,11 +315,9 @@
         cellLoc = newCellLoc;
         newCellLoc = tcl;
 
-        cdmaDataConnectionState = newCdmaDataConnectionState;
+        mDataConnectionState = mNewDataConnectionState;
         networkType = newNetworkType;
 
-        gprsState = newCdmaDataConnectionState;
-
         newSS.setStateOutOfService(); // clean slate for next time
 
         if (hasNetworkTypeChanged) {
@@ -424,8 +428,8 @@
                     : -1;
             if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
                 lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
-                lteRsrp = (ints[offset + 6] > 0) ? -ints[offset + 7] : -1;
-                lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 6] : 99;
+                lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
+                lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
             }
 
             if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index ac8352d..afebebe 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -97,8 +97,8 @@
     /**
      * Initially assume no data connection.
      */
-    protected int cdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
-    protected int newCdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
+    protected int mDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
+    protected int mNewDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
     protected int mRegistrationState = -1;
     protected RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
 
@@ -217,8 +217,8 @@
         phone.mRuimRecords.unregisterForRecordsLoaded(this);
         cm.unSetOnSignalStrengthUpdate(this);
         cm.unSetOnNITZTime(this);
-        cr.unregisterContentObserver(this.mAutoTimeObserver);
-        cr.unregisterContentObserver(this.mAutoTimeZoneObserver);
+        cr.unregisterContentObserver(mAutoTimeObserver);
+        cr.unregisterContentObserver(mAutoTimeZoneObserver);
     }
 
     @Override
@@ -548,10 +548,12 @@
     }
 
     /**
-    * The LTE data connection state, only return true here
+    * Determine data network type based on radio technology.
     */
-    protected boolean checkAdditionalDataAvaiable(){
-        return true;
+    protected void setCdmaTechnology(int radioTechnology){
+        mNewDataConnectionState = radioTechnologyToDataServiceState(radioTechnology);
+        newSS.setRadioTechnology(radioTechnology);
+        newNetworkType = radioTechnology;
     }
 
     /**
@@ -639,12 +641,7 @@
                     regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
             newSS.setState (regCodeToServiceState(registrationState));
 
-            if(checkAdditionalDataAvaiable()) {
-                this.newCdmaDataConnectionState =
-                        radioTechnologyToDataServiceState(radioTechnology);
-                newSS.setRadioTechnology(radioTechnology);
-                newNetworkType = radioTechnology;
-            }
+            setCdmaTechnology(radioTechnology);
 
             newSS.setCssIndicator(cssIndicator);
             newSS.setSystemAndNetworkId(systemId, networkId);
@@ -953,15 +950,15 @@
             && newSS.getState() != ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionAttached =
-            this.cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE
-            && this.newCdmaDataConnectionState == ServiceState.STATE_IN_SERVICE;
+            mDataConnectionState != ServiceState.STATE_IN_SERVICE
+            && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionDetached =
-            this.cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE
-            && this.newCdmaDataConnectionState != ServiceState.STATE_IN_SERVICE;
+            mDataConnectionState == ServiceState.STATE_IN_SERVICE
+            && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE;
 
         boolean hasCdmaDataConnectionChanged =
-                       cdmaDataConnectionState != newCdmaDataConnectionState;
+                       mDataConnectionState != mNewDataConnectionState;
 
         boolean hasNetworkTypeChanged = networkType != newNetworkType;
 
@@ -975,10 +972,10 @@
 
         // Add an event log when connection state changes
         if (ss.getState() != newSS.getState() ||
-                cdmaDataConnectionState != newCdmaDataConnectionState) {
+                mDataConnectionState != mNewDataConnectionState) {
             EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE,
-                    ss.getState(), cdmaDataConnectionState,
-                    newSS.getState(), newCdmaDataConnectionState);
+                    ss.getState(), mDataConnectionState,
+                    newSS.getState(), mNewDataConnectionState);
         }
 
         ServiceState tss;
@@ -992,7 +989,7 @@
         cellLoc = newCellLoc;
         newCellLoc = tcl;
 
-        cdmaDataConnectionState = newCdmaDataConnectionState;
+        mDataConnectionState = mNewDataConnectionState;
         networkType = newNetworkType;
         // this new state has been applied - forget it until we get a new new state
         newNetworkType = 0;
@@ -1175,7 +1172,7 @@
     }
 
 
-    private int radioTechnologyToDataServiceState(int code) {
+    protected int radioTechnologyToDataServiceState(int code) {
         int retVal = ServiceState.STATE_OUT_OF_SERVICE;
         switch(code) {
         case 0:
@@ -1226,14 +1223,14 @@
      * ServiceState.RADIO_TECHNOLOGY_UNKNOWN is the same as detached.
      */
     /*package*/ int getCurrentCdmaDataConnectionState() {
-        return cdmaDataConnectionState;
+        return mDataConnectionState;
     }
 
     /**
     * TODO: In the future, we need remove getCurrentCdmaDataConnectionState
     */
     public int getCurrentDataConnectionState() {
-        return cdmaDataConnectionState;
+        return mDataConnectionState;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 8a11ae3..545ad8a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -130,7 +130,7 @@
     @Override
     protected boolean isDnsOk(String[] domainNameServers) {
         if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1])
-                && !((GSMPhone) phone).isDnsCheckDisabled()) {
+                && !phone.isDnsCheckDisabled()) {
             // Work around a race condition where QMI does not fill in DNS:
             // Deactivate PDP and let DataConnectionTracker retry.
             // Do not apply the race condition workaround for MMS APN
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 223c8ad..8e675fc 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -115,6 +115,7 @@
     static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
     static final String APN_ID = "apn_id";
     private boolean canSetPreferApn = false;
+    private boolean mRadioAvailable = false;
 
     @Override
     protected void onActionIntentReconnectAlarm(Intent intent) {
@@ -519,6 +520,7 @@
             } else {
                 if (DBG) log("return APN_ALREADY_INACTIVE");
                 apnContext.setEnabled(false);
+                apnContext.setDataConnection(null);
                 return Phone.APN_ALREADY_INACTIVE;
             }
 
@@ -1267,6 +1269,7 @@
             if (!apnContext.getDataConnection().isRetryNeeded()) {
                 if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)){
                     // if no more retries on a secondary APN attempt, tell the world and revert.
+                    apnContext.setDataConnection(null);
                     notifyDataConnection(Phone.REASON_APN_FAILED);
                     return;
                 }
@@ -1323,6 +1326,10 @@
     private void onRecordsLoaded() {
         if (DBG) log("onRecordsLoaded: createAllApnList");
         createAllApnList();
+        if (mRadioAvailable) {
+            if (DBG) log("onRecordsLoaded, notifying data availability");
+            notifyDataAvailability(null);
+        }
         setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
     }
 
@@ -1434,6 +1441,8 @@
 
     @Override
     protected void onRadioAvailable() {
+
+        mRadioAvailable = true;
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
@@ -1461,6 +1470,7 @@
             dc.resetRetryCount();
         }
         mReregisterOnReconnectFailure = false;
+        mRadioAvailable = false;
 
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -1470,6 +1480,7 @@
             if (DBG) log("Radio is off and clean up all connection");
             cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
         }
+        notifyDataAvailability(null);
     }
 
     @Override
@@ -1562,6 +1573,7 @@
                         log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
                     }
                     apnContext.setState(State.FAILED);
+                    apnContext.setDataConnection(null);
                     notifyDataConnection(Phone.REASON_APN_FAILED);
                 } else {
                     if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
@@ -1600,6 +1612,7 @@
         if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
            apnContext.setEnabled(false);
            apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
+           apnContext.setDataConnection(null);
         }
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
 
@@ -1618,7 +1631,10 @@
             if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_RECONNECT) {
                 apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
             }
-            trySetupData(apnContext);
+            // Wait a bit before trying the next APN, so that
+            // we're not tying up the RIL command channel.
+            // This also helps in any external dependency to turn off the context.
+            sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),APN_DELAY_MILLIS);
         }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index afa5c1d..a6b1a2c 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -48,6 +48,7 @@
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.DhcpInfoInternal;
+import android.net.DhcpStateMachine;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -73,6 +74,7 @@
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
@@ -151,6 +153,7 @@
     private NetworkInfo mNetworkInfo;
     private SupplicantStateTracker mSupplicantStateTracker;
     private WpsStateMachine mWpsStateMachine;
+    private DhcpStateMachine mDhcpStateMachine;
 
     private AlarmManager mAlarmManager;
     private PendingIntent mScanIntent;
@@ -165,95 +168,97 @@
     private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
     private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
 
+    /* The base for wifi message types */
+    static final int BASE = Protocol.BASE_WIFI;
     /* Load the driver */
-    static final int CMD_LOAD_DRIVER                      = 1;
+    static final int CMD_LOAD_DRIVER                      = BASE + 1;
     /* Unload the driver */
-    static final int CMD_UNLOAD_DRIVER                    = 2;
+    static final int CMD_UNLOAD_DRIVER                    = BASE + 2;
     /* Indicates driver load succeeded */
-    static final int CMD_LOAD_DRIVER_SUCCESS              = 3;
+    static final int CMD_LOAD_DRIVER_SUCCESS              = BASE + 3;
     /* Indicates driver load failed */
-    static final int CMD_LOAD_DRIVER_FAILURE              = 4;
+    static final int CMD_LOAD_DRIVER_FAILURE              = BASE + 4;
     /* Indicates driver unload succeeded */
-    static final int CMD_UNLOAD_DRIVER_SUCCESS            = 5;
+    static final int CMD_UNLOAD_DRIVER_SUCCESS            = BASE + 5;
     /* Indicates driver unload failed */
-    static final int CMD_UNLOAD_DRIVER_FAILURE            = 6;
+    static final int CMD_UNLOAD_DRIVER_FAILURE            = BASE + 6;
 
     /* Start the supplicant */
-    static final int CMD_START_SUPPLICANT                 = 11;
+    static final int CMD_START_SUPPLICANT                 = BASE + 11;
     /* Stop the supplicant */
-    static final int CMD_STOP_SUPPLICANT                  = 12;
+    static final int CMD_STOP_SUPPLICANT                  = BASE + 12;
     /* Start the driver */
-    static final int CMD_START_DRIVER                     = 13;
+    static final int CMD_START_DRIVER                     = BASE + 13;
     /* Start the driver */
-    static final int CMD_STOP_DRIVER                      = 14;
-    /* Indicates DHCP succeded */
-    static final int CMD_IP_CONFIG_SUCCESS                = 15;
-    /* Indicates DHCP failed */
-    static final int CMD_IP_CONFIG_FAILURE                = 16;
+    static final int CMD_STOP_DRIVER                      = BASE + 14;
+    /* Indicates Static IP succeded */
+    static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
+    /* Indicates Static IP failed */
+    static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
 
     /* Start the soft access point */
-    static final int CMD_START_AP                         = 21;
+    static final int CMD_START_AP                         = BASE + 21;
     /* Stop the soft access point */
-    static final int CMD_STOP_AP                          = 22;
+    static final int CMD_STOP_AP                          = BASE + 22;
 
-    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = 23;
+    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 23;
 
     /* Supplicant events */
     /* Connection to supplicant established */
-    static final int SUP_CONNECTION_EVENT                 = 31;
+    static final int SUP_CONNECTION_EVENT                 = BASE + 31;
     /* Connection to supplicant lost */
-    static final int SUP_DISCONNECTION_EVENT              = 32;
+    static final int SUP_DISCONNECTION_EVENT              = BASE + 32;
     /* Driver start completed */
-    static final int DRIVER_START_EVENT                   = 33;
+    static final int DRIVER_START_EVENT                   = BASE + 33;
     /* Driver stop completed */
-    static final int DRIVER_STOP_EVENT                    = 34;
+    static final int DRIVER_STOP_EVENT                    = BASE + 34;
     /* Network connection completed */
-    static final int NETWORK_CONNECTION_EVENT             = 36;
+    static final int NETWORK_CONNECTION_EVENT             = BASE + 36;
     /* Network disconnection completed */
-    static final int NETWORK_DISCONNECTION_EVENT          = 37;
+    static final int NETWORK_DISCONNECTION_EVENT          = BASE + 37;
     /* Scan results are available */
-    static final int SCAN_RESULTS_EVENT                   = 38;
+    static final int SCAN_RESULTS_EVENT                   = BASE + 38;
     /* Supplicate state changed */
-    static final int SUPPLICANT_STATE_CHANGE_EVENT        = 39;
+    static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 39;
     /* Password failure and EAP authentication failure */
-    static final int AUTHENTICATION_FAILURE_EVENT         = 40;
+    static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 40;
     /* WPS overlap detected */
-    static final int WPS_OVERLAP_EVENT                    = 41;
+    static final int WPS_OVERLAP_EVENT                    = BASE + 41;
 
 
     /* Supplicant commands */
     /* Is supplicant alive ? */
-    static final int CMD_PING_SUPPLICANT                  = 51;
+    static final int CMD_PING_SUPPLICANT                  = BASE + 51;
     /* Add/update a network configuration */
-    static final int CMD_ADD_OR_UPDATE_NETWORK            = 52;
+    static final int CMD_ADD_OR_UPDATE_NETWORK            = BASE + 52;
     /* Delete a network */
-    static final int CMD_REMOVE_NETWORK                   = 53;
+    static final int CMD_REMOVE_NETWORK                   = BASE + 53;
     /* Enable a network. The device will attempt a connection to the given network. */
-    static final int CMD_ENABLE_NETWORK                   = 54;
+    static final int CMD_ENABLE_NETWORK                   = BASE + 54;
     /* Enable all networks */
-    static final int CMD_ENABLE_ALL_NETWORKS              = 55;
+    static final int CMD_ENABLE_ALL_NETWORKS              = BASE + 55;
     /* Disable a network. The device does not attempt a connection to the given network. */
-    static final int CMD_DISABLE_NETWORK                  = 56;
+    static final int CMD_DISABLE_NETWORK                  = BASE + 56;
     /* Blacklist network. De-prioritizes the given BSSID for connection. */
-    static final int CMD_BLACKLIST_NETWORK                = 57;
+    static final int CMD_BLACKLIST_NETWORK                = BASE + 57;
     /* Clear the blacklist network list */
-    static final int CMD_CLEAR_BLACKLIST                  = 58;
+    static final int CMD_CLEAR_BLACKLIST                  = BASE + 58;
     /* Save configuration */
-    static final int CMD_SAVE_CONFIG                      = 59;
+    static final int CMD_SAVE_CONFIG                      = BASE + 59;
 
     /* Supplicant commands after driver start*/
     /* Initiate a scan */
-    static final int CMD_START_SCAN                       = 71;
+    static final int CMD_START_SCAN                       = BASE + 71;
     /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
-    static final int CMD_SET_SCAN_MODE                    = 72;
+    static final int CMD_SET_SCAN_MODE                    = BASE + 72;
     /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
-    static final int CMD_SET_SCAN_TYPE                    = 73;
+    static final int CMD_SET_SCAN_TYPE                    = BASE + 73;
     /* Disconnect from a network */
-    static final int CMD_DISCONNECT                       = 74;
+    static final int CMD_DISCONNECT                       = BASE + 74;
     /* Reconnect to a network */
-    static final int CMD_RECONNECT                        = 75;
+    static final int CMD_RECONNECT                        = BASE + 75;
     /* Reassociate to a network */
-    static final int CMD_REASSOCIATE                      = 76;
+    static final int CMD_REASSOCIATE                      = BASE + 76;
     /* Controls power mode and suspend mode optimizations
      *
      * When high perf mode is enabled, power mode is set to
@@ -267,19 +272,19 @@
      * - turn off roaming
      * - DTIM wake up settings
      */
-    static final int CMD_SET_HIGH_PERF_MODE               = 77;
+    static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
     /* Set the country code */
-    static final int CMD_SET_COUNTRY_CODE                 = 80;
+    static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
     /* Request connectivity manager wake lock before driver stop */
-    static final int CMD_REQUEST_CM_WAKELOCK              = 81;
+    static final int CMD_REQUEST_CM_WAKELOCK              = BASE + 81;
     /* Enables RSSI poll */
-    static final int CMD_ENABLE_RSSI_POLL                 = 82;
+    static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
     /* RSSI poll */
-    static final int CMD_RSSI_POLL                        = 83;
+    static final int CMD_RSSI_POLL                        = BASE + 83;
     /* Set up packet filtering */
-    static final int CMD_START_PACKET_FILTERING           = 84;
+    static final int CMD_START_PACKET_FILTERING           = BASE + 84;
     /* Clear packet filter */
-    static final int CMD_STOP_PACKET_FILTERING            = 85;
+    static final int CMD_STOP_PACKET_FILTERING            = BASE + 85;
     /* Connect to a specified network (network id
      * or WifiConfiguration) This involves increasing
      * the priority of the network, enabling the network
@@ -288,33 +293,33 @@
      * an existing network. All the networks get enabled
      * upon a successful connection or a failure.
      */
-    static final int CMD_CONNECT_NETWORK                  = 86;
+    static final int CMD_CONNECT_NETWORK                  = BASE + 86;
     /* Save the specified network. This involves adding
      * an enabled network (if new) and updating the
      * config and issuing a save on supplicant config.
      */
-    static final int CMD_SAVE_NETWORK                     = 87;
+    static final int CMD_SAVE_NETWORK                     = BASE + 87;
     /* Delete the specified network. This involves
      * removing the network and issuing a save on
      * supplicant config.
      */
-    static final int CMD_FORGET_NETWORK                   = 88;
+    static final int CMD_FORGET_NETWORK                   = BASE + 88;
     /* Start Wi-Fi protected setup */
-    static final int CMD_START_WPS                        = 89;
+    static final int CMD_START_WPS                        = BASE + 89;
     /* Set the frequency band */
-    static final int CMD_SET_FREQUENCY_BAND               = 90;
+    static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
     /* Enable background scan for configured networks */
-    static final int CMD_ENABLE_BACKGROUND_SCAN           = 91;
+    static final int CMD_ENABLE_BACKGROUND_SCAN           = BASE + 91;
 
     /* Commands from/to the SupplicantStateTracker */
     /* Reset the supplicant state tracker */
-    static final int CMD_RESET_SUPPLICANT_STATE           = 111;
+    static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
 
     /* Commands/events reported by WpsStateMachine */
     /* Indicates the completion of WPS activity */
-    static final int WPS_COMPLETED_EVENT                  = 121;
+    static final int WPS_COMPLETED_EVENT                  = BASE + 121;
     /* Reset the WPS state machine */
-    static final int CMD_RESET_WPS_STATE                  = 122;
+    static final int CMD_RESET_WPS_STATE                  = BASE + 122;
 
     private static final int CONNECT_MODE   = 1;
     private static final int SCAN_ONLY_MODE = 2;
@@ -335,8 +340,11 @@
      */
     private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
 
-    private static final int POWER_MODE_ACTIVE = 1;
-    private static final int POWER_MODE_AUTO = 0;
+    static final int POWER_MODE_ACTIVE = 1;
+    static final int POWER_MODE_AUTO = 0;
+
+    /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
+    private int mPowerMode = POWER_MODE_AUTO;
 
     /**
      * See {@link Settings.Secure#WIFI_SCAN_INTERVAL_MS}. This is the default value if a
@@ -1389,8 +1397,10 @@
          */
         NetworkUtils.resetConnections(mInterfaceName);
 
-        if (!NetworkUtils.stopDhcp(mInterfaceName)) {
-            Log.e(TAG, "Could not stop DHCP");
+        if (mDhcpStateMachine != null) {
+            mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+            mDhcpStateMachine.quit();
+            mDhcpStateMachine = null;
         }
 
         /* Disable interface */
@@ -1416,6 +1426,100 @@
 
     }
 
+    void handlePreDhcpSetup() {
+        if (!mBluetoothConnectionActive) {
+            /*
+             * There are problems setting the Wi-Fi driver's power
+             * mode to active when bluetooth coexistence mode is
+             * enabled or sense.
+             * <p>
+             * We set Wi-Fi to active mode when
+             * obtaining an IP address because we've found
+             * compatibility issues with some routers with low power
+             * mode.
+             * <p>
+             * In order for this active power mode to properly be set,
+             * we disable coexistence mode until we're done with
+             * obtaining an IP address.  One exception is if we
+             * are currently connected to a headset, since disabling
+             * coexistence would interrupt that connection.
+             */
+            // Disable the coexistence mode
+            WifiNative.setBluetoothCoexistenceModeCommand(
+                    WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+        }
+
+        mPowerMode =  WifiNative.getPowerModeCommand();
+        if (mPowerMode < 0) {
+            // Handle the case where supplicant driver does not support
+            // getPowerModeCommand.
+            mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
+        }
+        if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
+            WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
+        }
+    }
+
+
+    void handlePostDhcpSetup() {
+        /* restore power mode */
+        WifiNative.setPowerModeCommand(mPowerMode);
+
+        // Set the coexistence mode back to its default value
+        WifiNative.setBluetoothCoexistenceModeCommand(
+                WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+    }
+
+    private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
+        synchronized (mDhcpInfoInternal) {
+            mDhcpInfoInternal = dhcpInfoInternal;
+        }
+        mLastSignalLevel = -1; // force update of signal strength
+        WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
+        InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
+        mWifiInfo.setInetAddress(addr);
+        if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+            //DHCP renewal in connected state
+            LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
+            linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
+            linkProperties.setInterfaceName(mInterfaceName);
+            if (!linkProperties.equals(mLinkProperties)) {
+                Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
+                    + " old: " + mLinkProperties + "new: " + linkProperties);
+                NetworkUtils.resetConnections(mInterfaceName);
+                mLinkProperties = linkProperties;
+                sendLinkConfigurationChangedBroadcast();
+            }
+        } else {
+            configureLinkProperties();
+            setNetworkDetailedState(DetailedState.CONNECTED);
+            sendNetworkStateChangeBroadcast(mLastBssid);
+        }
+    }
+
+    private void handleFailedIpConfiguration() {
+        Log.e(TAG, "IP configuration failed");
+
+        mWifiInfo.setInetAddress(null);
+        /**
+         * If we've exceeded the maximum number of retries for DHCP
+         * to a given network, disable the network
+         */
+        if (++mReconnectCount > getMaxDhcpRetries()) {
+            Log.e(TAG, "Failed " +
+                    mReconnectCount + " times, Disabling " + mLastNetworkId);
+            WifiConfigStore.disableNetwork(mLastNetworkId);
+            mReconnectCount = 0;
+        }
+
+        /* DHCP times out after about 30 seconds, we do a
+         * disconnect and an immediate reconnect to try again
+         */
+        WifiNative.disconnectCommand();
+        WifiNative.reconnectCommand();
+
+    }
+
 
     /*********************************************************
      * Notifications from WifiMonitor
@@ -1587,6 +1691,8 @@
                 case CMD_FORGET_NETWORK:
                 case CMD_RSSI_POLL:
                 case CMD_ENABLE_ALL_NETWORKS:
+                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
                     break;
                 case CMD_START_WPS:
                     /* Return failure when the state machine cannot handle WPS initiation*/
@@ -2459,74 +2565,18 @@
     }
 
     class ConnectingState extends State {
-        boolean mModifiedBluetoothCoexistenceMode;
-        int mPowerMode;
-        boolean mUseStaticIp;
-        Thread mDhcpThread;
 
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-            mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId);
-            if (!mUseStaticIp) {
-                mDhcpThread = null;
-                mModifiedBluetoothCoexistenceMode = false;
-                mPowerMode = POWER_MODE_AUTO;
 
-                if (!mBluetoothConnectionActive) {
-                    /*
-                     * There are problems setting the Wi-Fi driver's power
-                     * mode to active when bluetooth coexistence mode is
-                     * enabled or sense.
-                     * <p>
-                     * We set Wi-Fi to active mode when
-                     * obtaining an IP address because we've found
-                     * compatibility issues with some routers with low power
-                     * mode.
-                     * <p>
-                     * In order for this active power mode to properly be set,
-                     * we disable coexistence mode until we're done with
-                     * obtaining an IP address.  One exception is if we
-                     * are currently connected to a headset, since disabling
-                     * coexistence would interrupt that connection.
-                     */
-                    mModifiedBluetoothCoexistenceMode = true;
-
-                    // Disable the coexistence mode
-                    WifiNative.setBluetoothCoexistenceModeCommand(
-                            WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
-                }
-
-                mPowerMode =  WifiNative.getPowerModeCommand();
-                if (mPowerMode < 0) {
-                  // Handle the case where supplicant driver does not support
-                  // getPowerModeCommand.
-                    mPowerMode = POWER_MODE_AUTO;
-                }
-                if (mPowerMode != POWER_MODE_ACTIVE) {
-                    WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE);
-                }
-
-                Log.d(TAG, "DHCP request started");
-                mDhcpThread = new Thread(new Runnable() {
-                    public void run() {
-                        DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
-                        if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) {
-                            Log.d(TAG, "DHCP request succeeded");
-                            synchronized (mDhcpInfoInternal) {
-                                mDhcpInfoInternal = dhcpInfoInternal;
-                            }
-                            WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
-                            sendMessage(CMD_IP_CONFIG_SUCCESS);
-                        } else {
-                            Log.d(TAG, "DHCP request failed: " +
-                                    NetworkUtils.getDhcpError());
-                            sendMessage(CMD_IP_CONFIG_FAILURE);
-                        }
-                    }
-                });
-                mDhcpThread.start();
+             if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+                //start DHCP
+                mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
+                        mContext, WifiStateMachine.this, mInterfaceName);
+                mDhcpStateMachine.registerForPreDhcpNotification();
+                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
             } else {
                 DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
                         mLastNetworkId);
@@ -2538,16 +2588,13 @@
                 try {
                     netd.setInterfaceConfig(mInterfaceName, ifcg);
                     Log.v(TAG, "Static IP configuration succeeded");
-                    synchronized (mDhcpInfoInternal) {
-                        mDhcpInfoInternal = dhcpInfoInternal;
-                    }
-                    sendMessage(CMD_IP_CONFIG_SUCCESS);
+                    sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
                 } catch (RemoteException re) {
                     Log.v(TAG, "Static IP configuration failed: " + re);
-                    sendMessage(CMD_IP_CONFIG_FAILURE);
+                    sendMessage(CMD_STATIC_IP_FAILURE);
                 } catch (IllegalStateException e) {
                     Log.v(TAG, "Static IP configuration failed: " + e);
-                    sendMessage(CMD_IP_CONFIG_FAILURE);
+                    sendMessage(CMD_STATIC_IP_FAILURE);
                 }
             }
          }
@@ -2556,44 +2603,26 @@
           if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
 
           switch(message.what) {
-              case CMD_IP_CONFIG_SUCCESS:
-                  mLastSignalLevel = -1; // force update of signal strength
-                  InetAddress addr;
-                  synchronized (mDhcpInfoInternal) {
-                      addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress);
+              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                  handlePreDhcpSetup();
+                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+                  break;
+              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+                  handlePostDhcpSetup();
+                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+                      transitionTo(mConnectedState);
+                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+                      handleFailedIpConfiguration();
+                      transitionTo(mDisconnectingState);
                   }
-                  mWifiInfo.setInetAddress(addr);
-                  configureLinkProperties();
-                  if (getNetworkDetailedState() == DetailedState.CONNECTED) {
-                      sendLinkConfigurationChangedBroadcast();
-                  } else {
-                      setNetworkDetailedState(DetailedState.CONNECTED);
-                      sendNetworkStateChangeBroadcast(mLastBssid);
-                  }
-                  //TODO: The framework is not detecting a DHCP renewal and a possible
-                  //IP change. we should detect this and send out a config change broadcast
+                  break;
+              case CMD_STATIC_IP_SUCCESS:
+                  handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
                   transitionTo(mConnectedState);
                   break;
-              case CMD_IP_CONFIG_FAILURE:
-                  mWifiInfo.setInetAddress(null);
-
-                  Log.e(TAG, "IP configuration failed");
-                  /**
-                   * If we've exceeded the maximum number of retries for DHCP
-                   * to a given network, disable the network
-                   */
-                  if (++mReconnectCount > getMaxDhcpRetries()) {
-                      Log.e(TAG, "Failed " +
-                              mReconnectCount + " times, Disabling " + mLastNetworkId);
-                      WifiConfigStore.disableNetwork(mLastNetworkId);
-                      mReconnectCount = 0;
-                  }
-
-                  /* DHCP times out after about 30 seconds, we do a
-                   * disconnect and an immediate reconnect to try again
-                   */
-                  WifiNative.disconnectCommand();
-                  WifiNative.reconnectCommand();
+              case CMD_STATIC_IP_FAILURE:
+                  handleFailedIpConfiguration();
                   transitionTo(mDisconnectingState);
                   break;
               case CMD_DISCONNECT:
@@ -2637,23 +2666,6 @@
           EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
           return HANDLED;
       }
-
-      @Override
-      public void exit() {
-          /* reset power state & bluetooth coexistence if on DHCP */
-          if (!mUseStaticIp) {
-              if (mPowerMode != POWER_MODE_ACTIVE) {
-                  WifiNative.setPowerModeCommand(mPowerMode);
-              }
-
-              if (mModifiedBluetoothCoexistenceMode) {
-                  // Set the coexistence mode back to its default value
-                  WifiNative.setBluetoothCoexistenceModeCommand(
-                          WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
-              }
-          }
-
-      }
     }
 
     class ConnectedState extends State {
@@ -2671,6 +2683,19 @@
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
             boolean eventLoggingEnabled = true;
             switch (message.what) {
+              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                  handlePreDhcpSetup();
+                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+                  break;
+              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+                  handlePostDhcpSetup();
+                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+                      handleFailedIpConfiguration();
+                      transitionTo(mDisconnectingState);
+                  }
+                  break;
                 case CMD_DISCONNECT:
                     WifiNative.disconnectCommand();
                     transitionTo(mDisconnectingState);