Merge "Fix deadlock in BackupManagerService"
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index f562851..1dcaa04 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1173,13 +1173,11 @@
         if (oldValues != null) {
             int numValues = oldValues.length;
             anim.mValues = new PropertyValuesHolder[numValues];
-            for (int i = 0; i < numValues; ++i) {
-                anim.mValues[i] = oldValues[i].clone();
-            }
             anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
             for (int i = 0; i < numValues; ++i) {
-                PropertyValuesHolder valuesHolder = mValues[i];
-                anim.mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
+                PropertyValuesHolder newValuesHolder = oldValues[i].clone();
+                anim.mValues[i] = newValuesHolder;
+                anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
             }
         }
         return anim;
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 4991914..c1dd911 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -16,6 +16,11 @@
 
 package android.os;
 
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -37,9 +42,6 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import android.content.Context;
-import android.util.Log;
-
 import org.apache.harmony.security.asn1.BerInputStream;
 import org.apache.harmony.security.pkcs7.ContentInfo;
 import org.apache.harmony.security.pkcs7.SignedData;
@@ -336,8 +338,21 @@
      * @throws IOException  if writing the recovery command file
      * fails, or if the reboot itself fails.
      */
-    public static void rebootWipeUserData(Context context)
-        throws IOException {
+    public static void rebootWipeUserData(Context context) throws IOException {
+        final ConditionVariable condition = new ConditionVariable();
+
+        Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
+        context.sendOrderedBroadcast(intent, android.Manifest.permission.MASTER_CLEAR,
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        condition.open();
+                    }
+                }, null, 0, null, null);
+
+        // Block until the ordered broadcast has completed.
+        condition.block();
+
         bootCommand(context, "--wipe_data");
     }
 
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 4c83515..27da3c3 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -637,6 +637,22 @@
                 }
                 return _result;
             }
+
+            public String[] getVolumeList() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                String[] _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readStringArray();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
         }
 
         private static final String DESCRIPTOR = "IMountService";
@@ -699,6 +715,8 @@
 
         static final int TRANSACTION_changeEncryptionPassword = IBinder.FIRST_CALL_TRANSACTION + 28;
 
+        static final int TRANSACTION_getVolumeList = IBinder.FIRST_CALL_TRANSACTION + 29;
+
         /**
          * Cast an IBinder object into an IMountService interface, generating a
          * proxy if needed.
@@ -1004,6 +1022,13 @@
                     reply.writeInt(result);
                     return true;
                 }
+                case TRANSACTION_getVolumeList: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String[] result = getVolumeList();
+                    reply.writeNoException();
+                    reply.writeStringArray(result);
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -1179,4 +1204,8 @@
      */
     public int changeEncryptionPassword(String password) throws RemoteException;
 
+    /**
+     * Returns list of all mountable volumes.
+     */
+    public String[] getVolumeList() throws RemoteException;
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 73ac79f..234057b 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -527,4 +527,30 @@
 
         return null;
     }
+
+    /**
+     * Gets the state of a volume via its mountpoint.
+     * @hide
+     */
+    public String getVolumeState(String mountPoint) {
+        try {
+            return mMountService.getVolumeState(mountPoint);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get volume state", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns list of all mountable volumes.
+     * @hide
+     */
+    public String[] getVolumeList() {
+        try {
+            return mMountService.getVolumeList();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get volume list", e);
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java
index 69cf93c..68334e4 100644
--- a/core/java/android/text/util/Rfc822Tokenizer.java
+++ b/core/java/android/text/util/Rfc822Tokenizer.java
@@ -256,7 +256,7 @@
                     if (c == '"') {
                         i++;
                         break;
-                    } else if (c == '\\') {
+                    } else if (c == '\\' && i + 1 < len) {
                         i += 2;
                     } else {
                         i++;
@@ -275,7 +275,7 @@
                     } else if (c == '(') {
                         level++;
                         i++;
-                    } else if (c == '\\') {
+                    } else if (c == '\\' && i + 1 < len) {
                         i += 2;
                     } else {
                         i++;
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
index b87f7c4..d09c4e9 100644
--- a/core/jni/android_bluetooth_BluetoothSocket.cpp
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -448,7 +448,7 @@
 #ifdef HAVE_BLUETOOTH
     LOGV("%s", __FUNCTION__);
 
-    int ret;
+    int ret, total;
     jbyte *b;
     int sz;
     struct asocket *s = get_socketData(env, obj);
@@ -471,15 +471,21 @@
         return -1;
     }
 
-    ret = asocket_write(s, &b[offset], length, -1);
-    if (ret < 0) {
-        jniThrowIOException(env, errno);
-        env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
-        return -1;
+    total = 0;
+    while (length > 0) {
+        ret = asocket_write(s, &b[offset], length, -1);
+        if (ret < 0) {
+            jniThrowIOException(env, errno);
+            env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
+            return -1;
+        }
+        offset += ret;
+        total += ret;
+        length -= ret;
     }
 
     env->ReleaseByteArrayElements(jb, b, JNI_ABORT);  // no need to commit
-    return (jint)ret;
+    return (jint)total;
 
 #endif
     jniThrowIOException(env, ENOSYS);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 348ded7..2a4d1b2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -57,6 +57,7 @@
     <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
     <protected-broadcast android:name="android.intent.action.REBOOT" />
     <protected-broadcast android:name="android.intent.action.DOCK_EVENT" />
+    <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
 
     <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
new file mode 100644
index 0000000..27112a6
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
@@ -0,0 +1,131 @@
+/*
+ * 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.content.pm;
+
+import com.android.internal.content.PackageHelper;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.storage.IMountService;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class PackageHelperTests extends AndroidTestCase {
+    private static final boolean localLOGV = true;
+    public static final String TAG = "PackageHelperTests";
+    protected final String PREFIX = "android.content.pm";
+    private IMountService mMs;
+    private String fullId;
+    private String fullId2;
+
+    private IMountService getMs() {
+        IBinder service = ServiceManager.getService("mount");
+        if (service != null) {
+            return IMountService.Stub.asInterface(service);
+        } else {
+            Log.e(TAG, "Can't get mount service");
+        }
+        return null;
+    }
+
+    private void cleanupContainers() throws RemoteException {
+        Log.d(TAG,"cleanUp");
+        IMountService ms = getMs();
+        String[] containers = ms.getSecureContainerList();
+        for (int i = 0; i < containers.length; i++) {
+            if (containers[i].startsWith(PREFIX)) {
+                Log.d(TAG,"cleaing up "+containers[i]);
+                ms.destroySecureContainer(containers[i], true);
+            }
+        }
+    }
+
+    void failStr(String errMsg) {
+        Log.w(TAG, "errMsg=" + errMsg);
+        fail(errMsg);
+    }
+
+    void failStr(Exception e) {
+        failStr(e.getMessage());
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
+        cleanupContainers();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
+        cleanupContainers();
+    }
+
+    public void testMountAndPullSdCard() {
+        try {
+            fullId = PREFIX;
+            fullId2 = PackageHelper.createSdDir(1024, fullId, "none", android.os.Process.myUid());
+
+            Log.d(TAG,PackageHelper.getSdDir(fullId));
+            PackageHelper.unMountSdDir(fullId);
+
+            Runnable r1 = getMountRunnable();
+            Runnable r2 = getDestroyRunnable();
+            Thread thread = new Thread(r1);
+            Thread thread2 = new Thread(r2);
+            thread2.start();
+            thread.start();
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public Runnable getMountRunnable() {
+        Runnable r = new Runnable () {
+            public void run () {
+                try {
+                    Thread.sleep(5);
+                    String path = PackageHelper.mountSdDir(fullId, "none",
+                            android.os.Process.myUid());
+                    Log.e(TAG, "mount done " + path);
+                } catch (IllegalArgumentException iae) {
+                    throw iae;
+                } catch (Throwable t) {
+                    Log.e(TAG, "mount failed", t);
+                }
+            }
+        };
+        return r;
+    }
+
+    public Runnable getDestroyRunnable() {
+        Runnable r = new Runnable () {
+            public void run () {
+                try {
+                    PackageHelper.destroySdDir(fullId);
+                    Log.e(TAG, "destroy done: " + fullId);
+                } catch (Throwable t) {
+                    Log.e(TAG, "destroy failed", t);
+                }
+            }
+        };
+        return r;
+    }
+}
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index e8e56de..c82962d 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -247,6 +247,23 @@
         assertEquals("Foo Bar", tokens[0].getAddress());
     }
 
+    @SmallTest
+    public void testRfc822FindToken() {
+        Rfc822Tokenizer tokenizer = new Rfc822Tokenizer();
+        //                0           1         2           3         4
+        //                0 1234 56789012345678901234 5678 90123456789012345
+        String address = "\"Foo\" <foo@google.com>, \"Bar\" <bar@google.com>";
+        assertEquals(0, tokenizer.findTokenStart(address, 21));
+        assertEquals(22, tokenizer.findTokenEnd(address, 21));
+        assertEquals(24, tokenizer.findTokenStart(address, 25));
+        assertEquals(46, tokenizer.findTokenEnd(address, 25));
+    }
+
+    @SmallTest
+    public void testRfc822FindTokenWithError() {
+        assertEquals(9, new Rfc822Tokenizer().findTokenEnd("\"Foo Bar\\", 0));
+    }
+
     @LargeTest
     public void testEllipsize() {
         CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
diff --git a/docs/html/guide/developing/index.jd b/docs/html/guide/developing/index.jd
index 4257bf0..3d7e353 100644
--- a/docs/html/guide/developing/index.jd
+++ b/docs/html/guide/developing/index.jd
@@ -9,25 +9,21 @@
   <p>However, you may choose to develop with another IDE or a simple text editor and invoke the
   tools on the command line or with scripts. This is a less streamlined way to develop because you
   will sometimes have to call command line tools manually, but you will have access to the same
-  amount of features that you would have in Eclipse.</p>
+  number of features that you would have in Eclipse.</p>
+
+  <p class="note"><strong>Note:</strong> Before you begin developing Android applications, make
+    sure you have gone through all of the steps outlined in <a
+href="{@docRoot}sdk/installing.html">Installing the SDK</a>.</p>
 
   <p>The basic steps for developing applications with or without Eclipse are the same:</p>
 
   <ol>
-    <li>Install Eclipse or your own IDE.
-
-      <p>Install Eclipse along with <a href="{@docRoot}sdk/eclipse-adt.html#installing">the ADT
-      Plugin</a>, or install an editor of your choice if you want to use the command line SDK tools.
-      If you are already developing applications, be sure to <a href= 
-      "{@docRoot}sdk/eclipse-adt.html#updating">update Your ADT Plugin</a> to the latest version
-      before continuing.</p>
-    </li>
 
     <li>Set up Android Virtual Devices or hardware devices.
 
       <p>You need to create Android Virtual Devices (AVD) or connect hardware devices on which
       you will install your applications.</p>
-      
+
       <p>See <a href="{@docRoot}guide/developing/devices/index.html">Managing Virtual Devices</a>
       and <a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a> for more
 information.
diff --git a/docs/html/guide/developing/tools/index.jd b/docs/html/guide/developing/tools/index.jd
index c603780..3d831f3 100644
--- a/docs/html/guide/developing/tools/index.jd
+++ b/docs/html/guide/developing/tools/index.jd
@@ -3,83 +3,83 @@
 
 <img src="{@docRoot}assets/images/android_wrench.png" alt="" align="right">
 
-<p>The Android SDK includes a variety of custom tools that help you develop mobile
-applications on the Android platform. The most important of these are the Android
-Emulator and the Android Development Tools plugin for Eclipse, but the SDK also
-includes a variety of other tools for debugging, packaging, and installing your
-applications on the emulator. </p>
+<p>The Android SDK includes a variety of tools that help you develop mobile
+applications for the Android platform. The tools are classified into two groups: SDK tools
+and platform tools. SDK tools are platform independent and are required no matter which
+Android platform you are developing on. Platform tools are customized to support the features of the
+latest Android platform.</p>
 
- <dl>
-  <dt><a href="adb.html">Android Debug Bridge</a></dt>
-    <dd>A versatile tool lets you manage the state of an emulator instance
-    or Android-powered device.</dd>    
+<h2 id="tools-sdk">SDK Tools</h2>
+<p>The SDK tools are installed with the SDK starter package and are periodically updated.
+The SDK tools are required if you are developing Android applications. The most important SDK tools
+include the Android SDK and AVD Manager (<code>android</code>), the emulator
+(<code>emulator</code>), and the Dalvik Debug Monitor Server
+(<code>ddms</code>). A short summary of some frequently-used SDK tools is provided below.</p>
 
-   <dt><a href="android.html">android</a></dt>
-     <dd>Lets you manage AVDs, projects, and the installed components of the SDK.
-     </dd>
-
-  <dt><a href="bmgr.html">bmgr</a></dt>
-
-    <dd>Lets you interact with the Backup Manager on Android devices
-    supporting API Level 8 or greater. It provides commands to invoke backup and restore operations
-    so that you don't need to repeatedly wipe data or take similar intrusive steps in order to test
-    your application's backup agent. These commands are accessed via the adb shell.
-    </dd>
-
+<dl>
+  <dt><a href="android.html">android</a></dt>
+    <dd>Lets you manage AVDs, projects, and the installed components of the SDK.</dd>
+  <dt><a href="{@docRoot}guide/developing/debugging/ddms.html">Dalvik Debug Monitor
+Server (ddms)</a></dt>
+    <dd>Lets you debug Android applications.</dd>
   <dt><a href="dmtracedump.html">dmtracedump</a></dt>
-
-    <dd>Generates graphical call-stack diagrams from trace log files.
-    The tool uses the Graphviz Dot utility to create the graphical output, so you need to install
-    Graphviz before running <code>dmtracedump</code>. For more information on using <code>dmtracedump</code>, see
-    <a href="{@docRoot}guide/developing/debugging/debugging-tracing.html#dmtracedump">Profiling with
-    Traceview and dmtracedump</a>
-    </dd>
-
-    <dt><a href="draw9patch.html">Draw 9-patch</a></dt>
-	    <dd>Allows you to easily create a {@link android.graphics.NinePatch} graphic using a WYSIWYG editor.
-	    It also previews stretched versions of the image, and highlights the area in which content is allowed.
-	    </dd>
-
-  <dt><a href="emulator.html">Android Emulator</a></dt>
-    <dd>A QEMU-based device-emulation tool that you can use to design,
-    debug, and test your applications in an actual Android run-time environment. </dd>
-
+    <dd>Generates graphical call-stack diagrams from trace log files. The tool uses the
+Graphviz Dot utility to create the graphical output, so you need to install Graphviz before
+running <code>dmtracedump</code>. For more information on using <code>dmtracedump</code>, see <a
+href="{@docRoot}guide/developing/debugging/debugging-tracing.html#dmtracedump">Profiling
+with Traceview and dmtracedump</a></dd>
+  <dt><a href="draw9patch.html">Draw 9-patch</a></dt>
+    <dd>Allows you to easily create a {@link android.graphics.NinePatch} graphic using a
+WYSIWYG editor. It also previews stretched versions of the image, and highlights the area in which
+content is allowed.</dd>
+  <dt><a href="emulator.html">Android Emulator (emulator)</a></dt>
+    <dd>A QEMU-based device-emulation tool that you can use to design, debug, and test
+your applications in an actual Android run-time environment.</dd>
+  <dt><a href="hierarchy-viewer.html">Hierarchy Viewer (hierarchyviewer)</a></dt>
+    <dd>Lets you debug and optimize an Android application's user interface.</dd>
   <dt><a href="hprof-conv.html">hprof-conv</a></dt>
-
-    <dd>Converts the HPROF file that is generated by the Android SDK tools to a
-    standard format so you can view the file in a profiling tool of your choice.</dd>
-
+    <dd>Converts the HPROF file that is generated by the Android SDK tools to a standard format so
+you can view the file in a profiling tool of your choice.</dd>
   <dt><a href="layoutopt.html">layoutopt</a></dt>
-    <dd>Lets you quickly analyze your application's layouts in order to
-    optimize them for efficiency.
-    </dd>
-
-  <dt><a href="mksdcard.html">logcat</a></dt>
-      <dd>Lets you read system log messages that are output on an Android device or emulator.</dd>
-
+    <dd>Lets you quickly analyze your application's layouts in order to optimize them for
+efficiency.</dd>
   <dt><a href="mksdcard.html">mksdcard</a></dt>
-      <dd>Helps you create a disk image that you can use with the emulator, 
-      to simulate the presence of an external storage card (such as an SD card).</dd>
-
+    <dd>Helps you create a disk image that you can use with the emulator, to simulate the presence
+of an external storage card (such as an SD card).</dd>
   <dt><a href="monkey.html">Monkey</a></dt>
-      <dd>Runs on your emulator or device and generates pseudo-random
-      streams of user events such as clicks, touches, or gestures, as well as a number of system-level events.
-      You can use the Monkey to stress-test applications that you are developing, in a random yet repeatable manner.</dd>
-
+    <dd>Runs on your emulator or device and generates pseudo-random streams of user events such
+as clicks, touches, or gestures, as well as a number of  system-level events. You can use the Monkey
+to stress-test applications that you are developing, in a random yet repeatable manner.</dd>
   <dt><a href="monkeyrunner_concepts.html">monkeyrunner</a></dt>
-      <dd>Provides an API for writing programs that control an Android device
-      or emulator from outside of Android code.</dd>
-
+    <dd>Provides an API for writing programs that control an Android device or emulator from
+outside of Android code.</dd>
   <dt><a href="proguard.html">ProGuard</a></dt>
-      <dd>Shrinks, optimizes, and obfuscates your code by removing unused code and renaming classes,
-      fields, and methods with semantically obscure names.</dd>
-
+    <dd>Shrinks, optimizes, and obfuscates your code by removing unused code and renaming
+classes, fields, and methods with semantically obscure names.</dd>
   <dt><a href="sqlite3.html">sqlite3</a></dt>
-      <dd>Lets you access the SQLite data files created and used by Android applications.</dd>
-
+    <dd>Lets you access the SQLite data files created and used by Android applications.</dd>
+  <dt><a href="traceview.html">traceview</a></dt>
+    <dd>Provides a graphical viewer for execution logs saved by your application.</dd>
   <dt><a href="zipalign.html">zipalign</a></dt>
-            <dd>Optimizes <code>.apk</code> files by ensuring that all uncompressed data starts
-            with a particular alignment relative to the start of the file. This should always be used
-            to align .apk files after they have been signed.</dd>
-</dl>
+    <dd>Optimizes <code>.apk</code> files by ensuring that all uncompressed data starts with a
+particular alignment relative to the start of the file. This should always be used to align .apk
+files after they have been signed.</dd>
+ </dl>
 
+<h2 id="tools-platform">Platform Tools</h2>
+
+<p>The platform tools are typically updated every time you install a new SDK platform. Each update
+of the platform tools is backward compatible with older platforms. Usually, you directly use only
+one of the platform tools&mdash;the <a href="adb.html">Android Debug Bridge (<code>adb</code>)</a>.
+Android Debug Bridge is a versatile tool that lets you manage the state of an emulator instance or
+Android-powered device. You can also use it to install an Android application (.apk) file on a
+device.</p>
+
+<p>The other platform tools, such as <a href="{@docRoot}guide/developing/tools/aidl.html">aidl</a>,
+<code>aapt</code>, <code>dexdump</code>, and <code>dx</code>, are typically called by the Android
+build tools or Android Development Tools (ADT), so you rarely need to invoke these tools directly.
+As a general rule, you should rely on the build tools or the ADT plugin to call them as needed.</p>
+
+<p class="note"><strong>Note:</strong> The Android SDK provides additional shell tools that can
+be accessed through <code>adb</code>, such as <a href="bmgr.html">bmgr</a> and
+<a href="logcat.html">logcat</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index ece9d4a..feb84b1 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -656,7 +656,7 @@
 <h3 id="downloading">Downloading the ADT Plugin</h3>
 
 <p>Use the Update Manager feature of your Eclipse installation to install the latest
-revision of ADT on your development computer.<p>
+revision of ADT on your development computer.<>
 
 <p>Assuming that you have a compatible version of the Eclipse IDE installed, as
 described in <a href="#preparing">Preparing for Installation</a>, above, follow
@@ -671,26 +671,32 @@
     <li>In the Add Repository dialog that appears, enter "ADT Plugin" for the <em>Name</em> and the
 following URL for the <em>Location</em>:
       <pre>https://dl-ssl.google.com/android/eclipse/</pre>
-        <p>Note: If you have trouble acquiring the plugin, try using "http" in the Location URL,
-        instead of "https" (https is preferred for security reasons).</p>
-      <p>Click <strong>OK</strong>.</p></li>
-    <li>In the Available Software dialog, select
-the checkbox next to Developer Tools and click <strong>Next</strong>.</li>
+    </li>
+    <li>Click <strong>OK</strong>
+      <p>Note: If you have trouble acquiring the plugin, try using "http" in the Location URL,
+instead of "https" (https is preferred for security reasons).</p></li>
+    <li>In the Available Software dialog, select the checkbox next to Developer Tools and click
+<strong>Next</strong>.</li>
     <li>In the next window, you'll see a list of the tools to be downloaded. Click
 <strong>Next</strong>. </li>
-    <li>Read and accept the license agreements, then click <strong>Finish</strong>.</li>
+    <li>Read and accept the license agreements, then click <strong>Finish</strong>.
+      <p>Note: If you get a security warning saying that the authenticity or validity of
+the software can't be established, click <strong>OK</strong>.</p></li>
     <li>When the installation completes, restart Eclipse. </li>
 </ol>
 
 <h3 id="configuring">Configuring the ADT Plugin</h3>
 
-<p>Once you've successfully downloaded ADT as described above, the next step
+<p>After you've successfully downloaded the ADT as described above, the next step
 is to modify your ADT preferences in Eclipse to point to the Android SDK directory:</p>
 
 <ol>
     <li>Select <strong>Window</strong> &gt; <strong>Preferences...</strong> to open the Preferences
         panel (Mac OS X: <strong>Eclipse</strong> &gt; <strong>Preferences</strong>).</li>
-    <li>Select <strong>Android</strong> from the left panel. </li>
+    <li>Select <strong>Android</strong> from the left panel.</li>
+      <p>You may see a dialog asking whether you want to send usage statistics to Google. If so,
+make your choice and click <strong>Proceed</strong>. You cannot continue with this procedure until
+you click <strong>Proceed</strong>.</p>
     <li>For the <em>SDK Location</em> in the main panel, click <strong>Browse...</strong> and
         locate your downloaded SDK directory. </li>
     <li>Click <strong>Apply</strong>, then <strong>OK</strong>.</li>
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index a1080c2..1dce483 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -81,9 +81,9 @@
 
 <h4>Updating?</h4>
 
-<p>If you already have an Android SDK, use the <em>Android SDK and AVD Manager</em> tool to install
+<p>If you already have an Android SDK, use the Android SDK and AVD Manager tool to install
 updated tools and new Android platforms into your existing environment. For information about how to
-do that, see <a href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a></p>
+do that, see <a href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a>.</p>
 
 
 <h2 id="Preparing">Step 1. Preparing Your Development Computer</h2>
@@ -126,7 +126,7 @@
 
 <p>Make a note of the name and location of the SDK directory on your system&mdash;you will need to
 refer to the SDK directory later, when setting up the ADT plugin and when using
-the SDK tools from command line.</p>
+the SDK tools from the command line.</p>
 
 
 <h2 id="InstallingADT">Step 3. Installing the ADT Plugin for Eclipse</h2>
@@ -147,26 +147,25 @@
 last step in setting up your Android SDK.</p>
 
 <p>If you prefer to work in a different IDE, you do not need to
-install Eclipse or ADT, instead, you can directly use the SDK tools to build and
-debug your application. The <a href="{@docRoot}guide/developing/index.html">Overview</a>
-section of the developer guide outlines the major steps that you need to complete
-when developing in Eclipse or other IDEs.</p>
+install Eclipse or ADT. Instead, you can directly use the SDK tools to build and
+debug your application. The <a href="{@docRoot}guide/developing/index.html">Introduction</a>
+to Android application development outlines the major steps that you need to complete when
+developing in Eclipse or other IDEs.</p>
 
 
 
 <h2 id="AddingComponents">Step 4. Adding Platforms and Other Components</h2>
 
-<p>The last step in setting up your SDK is using the <em>Android SDK and AVD Manager</em> (a
-tool included in the SDK starter package) to download
-essential SDK components into your development environment.</p>
+<p>The last step in setting up your SDK is using the Android SDK and AVD Manager (a
+tool included in the SDK starter package) to download essential SDK components into your development
+environment.</p>
 
 <p>The SDK uses a modular structure that separates the major parts of the SDK&mdash;Android platform
 versions, add-ons, tools, samples, and documentation&mdash;into a set of separately installable
 components. The SDK starter package, which you've already downloaded, includes only a single
-component: the latest version of the SDK Tools. To develop an Android
-application, you also need to download at least one Android platform and the SDK Platform-tools
-(tools that the latest platform depend upon). However, downloading
-additional components is highly recommended.</p>
+component: the latest version of the SDK Tools. To develop an Android application, you also need to
+download at least one Android platform and the associated platform tools. You can add other
+components and platforms as well, which is highly recommended.</p>
 
 <p>If you used the Windows installer, when you complete the installation wizard, it will launch the
 Android SDK and AVD Manager with a default set of platforms and other components selected
@@ -185,10 +184,10 @@
 </ul>
 
 <p>To download components, use the graphical UI of the Android SDK and AVD
-Manager, shown in Figure 1, to browse the SDK repository and select new or updated
-components. The Android SDK and AVD Manager will install the selected components in
-your SDK environment. For information about which components you should download, see the following
-section about <a href="#which">Recommended Components</a>.</p>
+Manager to browse the SDK repository and select new or updated
+components (see figure 1). The Android SDK and AVD Manager installs the selected components in
+your SDK environment. For information about which components you should download, see <a
+href="#which">Recommended Components</a>.</p>
 
 <img src="/images/sdk_manager_packages.png" />
 <p class="img-caption"><strong>Figure 1.</strong> The Android SDK and AVD Manager's
@@ -204,35 +203,34 @@
 <p>The <em>Android Repository</em> offers these types of components:</p>
 
 <ul>
-<li><strong>SDK Tools</strong> (pre-installed in the Android SDK starter
-package) &mdash; Contains tools for debugging
-and testing your application and other utility tools. You can access these
-in the <code>&lt;sdk&gt;/tools/</code> directory of your SDK and read more about them in the <a
-href="{@docRoot}guide/developing/tools/index.html">Tools</a> section of the developer guide. </li>
+<li><strong>SDK Tools</strong> &mdash; Contains tools for debugging and testing your application
+and other utility tools. These tools are installed with the Android SDK starter package and receive
+periodic updates. You can access these tools in the <code>&lt;sdk&gt;/tools/</code> directory of
+your SDK. To learn more about
+them, see <a href="{@docRoot}guide/developing/tools/index.html#tools-sdk">SDK Tools</a> in the
+developer guide.</li>
 
-<li><strong>SDK Platform-tools</strong> &mdash; Contains tools that are required to develop and
-debug your application, but which are developed alongside the Android platform in order to support
-the latest features. These tools are typically updated only when a new platform becomes
-available. You can access these
-in the <code>&lt;sdk&gt;/platform-tools/</code> directory. Read more about them in
-the <a href="{@docRoot}guide/developing/tools/index.html">Tools</a> section of the developer guide.
-</li>
+<li><strong>SDK Platform-tools</strong> &mdash; Contains platform-dependent tools for developing
+and debugging your application. These tools support the latest features of the Android platform and
+are typically updated only when a new platform becomes available. You can access these tools in the
+<code>&lt;sdk&gt;/platform-tools/</code> directory. To learn more about them, see <a
+href="{@docRoot}guide/developing/tools/index.html#tools-platform">Platform Tools</a> in the
+developer guide.</li>
 
 <li><strong>Android platforms</strong> &mdash; An SDK platform is
-available for every production Android platform deployable to Android-powered
-devices. Each platform component includes a fully compliant Android library and
-system image, sample code, emulator skins, and any version specific tools. For
-detailed information about each platform, see the overview documents available
-under the section "Downloadable SDK Components," at left. </li>
+available for every production Android platform deployable to Android-powered devices. Each
+SDK platform component includes a fully compliant Android library, system image, sample code,
+and emulator skins. To learn more about a specific platform, see the list of platforms that appears
+under the section "Downloadable SDK Components" on the left part of this page.</li>
 
 <li><strong>USB Driver for Windows</strong> (Windows only) &mdash; Contains driver files
 that you can install on your Windows computer, so that you can run and debug
 your applications on an actual device. You <em>do not</em> need the USB driver unless
 you plan to debug your application on an actual Android-powered device. If you
 develop on Mac OS X or Linux, you do not need a special driver to debug
-your application on an Android-powered device. (See <a
-href="{@docRoot}guide/developing/device.html">Developing on a Device</a> for more information
-about developing on a real device.)</li>
+your application on an Android-powered device. See <a
+href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a> for more information
+about developing on a real device.</li>
 
 <li><strong>Samples</strong> &mdash; Contains the sample code and apps available
 for each Android development platform. If you are just getting started with
@@ -247,8 +245,8 @@
 
 <p>The <em>Third party Add-ons</em> provide components that allow you to create a development
 environment using a specific Android external library (such as the Google Maps library) or a
-customized (but fully compliant) Android system image. You can add additional Add-on repositories,
-by clicking <strong>Add Add-on Site</strong>.</p>
+customized (but fully compliant) Android system image. You can add additional Add-on repositories by
+clicking <strong>Add Add-on Site</strong>.</p>
 
 
 <h3 id="which">Recommended Components</h3>
@@ -381,12 +379,11 @@
 </tr>
 <tr>
 <td colspan="3"><code>platform-tools/</code></td>
-<td>Contains development tools that may be updated with each platform release (from the <em>Android
-SDK Platform-tools</em> component). Tools in here include {@code adb}, {@code dexdump}, and others
-others that you don't typically use directly. These tools are separate from the generic development
-tools in the {@code tools/} directory, because these tools may be updated in order to support new
-features in the latest Android platform, whereas the other tools have no dependencies on the
-platform version.</td>
+<td>Contains platform-dependent development tools that may be updated with each platform release.
+The platform tools include the Android Debug Bridge ({@code adb}) as well as other tools that you
+don't typically use directly. These tools are separate from the development tools in the {@code
+tools/} directory because these tools may be updated in order to support new
+features in the latest Android platform.</td>
 </tr>
 <tr>
 <td colspan="3"><code>platforms/</code></td>
@@ -394,52 +391,12 @@
 applications against, each in a separate directory.  </td>
 </tr>
 <tr>
-<td style="width:2em;border-bottom-color:white;"></td>
+<td style="width:2em;"></td>
 <td colspan="2"><code><em>&lt;platform&gt;</em>/</code></td>
-<td>Platform version directory, for example "android-1.6". All platform version
-directories contain a similar set of files and subdirectory structure.</td>
-</tr>
-
-<tr>
-<td style="width:2em;border-bottom-color:white;">&nbsp;</td>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td><code>data/</code></td>
-<td>Storage area for default fonts and resource definitions.</td>
-</tr>
-<tr>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td><code>images/</code></td>
-<td>Storage area for default disk images, including the Android system image,
-the default userdata image, the default ramdisk image, and more. The images
-are used in emulator sessions.</td>
-</tr>
-<tr>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td><code>skins/</code></td>
-<td>A set of emulator skins available for the platform version. Each skin is
-designed for a specific screen resolution.</td>
-</tr>
-<tr>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td><code>templates/</code></td>
-<td>Storage area for file templates used by the SDK development tools.</td>
-</tr>
-<tr>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td style="width:2em;border-bottom-color:white;"></td>
-<td><code>tools/</code></td>
-<td>This directory is used only by SDK Tools r7 and below for development tools that are specific to
-this platform version&mdash;it's not used by SDK Tools r8 and above.</td>
-</tr>
-<tr>
-<td style="width:2em;"></td>
-<td style="width:2em;"></td>
-<td><code>android.jar</code></td>
-<td>The Android library used when compiling applications against this platform
-version.</td>
+<td>Platform version directory, for example "android-11". All platform version directories contain
+a similar set of files and subdirectory structure. Each platform directory also includes the
+Android library (<code>android.jar</code>) that is used to compile applications against the
+platform version.</td>
 </tr>
 <tr>
 <td colspan="3"><code>samples/</code></td>
@@ -448,21 +405,20 @@
 <tr>
 <td colspan="3"><code>tools/</code></td>
 <td>Contains the set of development and profiling tools that are platform-independent, such
-as the emulator, the AVD and SDK Manager, ddms, hierarchyviewer and more. The tools in
-this directory may be updated at any time (from the <em>Android SDK Tools</em> component),
-independent of platform releases, whereas the tools in {@code platform-tools/} may be updated based
-on the latest platform release.</td>
+as the emulator, the Android SDK and AVD Manager, <code>ddms</code>, <code>hierarchyviewer</code>
+and more. The tools in this directory may be updated at any time using the Android SDK and AVD
+Manager and are independent of platform releases.</td>
 </tr>
 <tr>
 <td colspan="3"><code>SDK Readme.txt</code></td>
 <td>A file that explains how to perform the initial setup of your SDK,
 including how to launch the Android SDK and AVD Manager tool on all
-platforms</td>
+platforms.</td>
 </tr>
 <tr>
 <td colspan="3"><code>SDK Manager.exe</code></td>
 <td>Windows SDK only. A shortcut that launches the Android SDK and AVD
-Manager tool, which you use to add components to your SDK. </td>
+Manager tool, which you use to add components to your SDK.</td>
 </tr>
 <!--<tr>
 <td colspan="3"><code>documentation.html</code></td>
@@ -499,7 +455,7 @@
 
   <li>On Linux, edit your <code>~/.bash_profile</code> or <code>~/.bashrc</code> file. Look
   for a line that sets the PATH environment variable and add the
-  full path to the <code>tools/</code> and <code>platform-tools</code> directories to it. If you
+  full path to the <code>tools/</code> and <code>platform-tools/</code> directories to it. If you
   don't see a line setting the path, you can add one:
   <pre>export PATH=${PATH}:&lt;sdk&gt;/tools:&lt;sdk&gt;/platform-tools</pre>
   </li>
@@ -533,28 +489,27 @@
 <p><strong>Learn about Android</strong></p>
 <ul>
   <li>Take a look at the <a href="{@docRoot}guide/index.html">Dev
-  Guide</a> and the types of information it provides</li>
+  Guide</a> and the types of information it provides.</li>
   <li>Read an introduction to Android as a platform in <a
   href="{@docRoot}guide/basics/what-is-android.html">What is
   Android?</a></li>
   <li>Learn about the Android framework and how applications run on it in
   <a href="{@docRoot}guide/topics/fundamentals.html">Application
-  Fundamentals</a></li>
+  Fundamentals</a>.</li>
   <li>Take a look at the Android framework API specification in the <a
-  href="{@docRoot}reference/packages.html">Reference</a> tab</li>
+  href="{@docRoot}reference/packages.html">Reference</a> tab.</li>
 </ul>
 
 <p><strong>Explore the development tools</strong></p>
 <ul>
   <li>Get an overview of the <a
   href="{@docRoot}guide/developing/tools/index.html">development
-  tools</a> that are available to you</li>
-  <li>Read the <a
-  href="{@docRoot}guide/developing/index.html">Overview</a>
-  for how to develop an Android application.
+  tools</a> that are available to you.</li>
+  <li>Read the <a href="{@docRoot}guide/developing/index.html">Introduction</a> to Android
+application development.
   </li>
-  <li>Read <a href="{@docRoot}guide/developing/device.html">Developing on a Device</a> to set up an
-Android-powered device to run and test your application.</li>
+  <li>Read <a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a> to learn
+how to set up an Android-powered device so you can run and test your application.</li>
 </ul>
 
 <p><strong>Follow the Notepad tutorial</strong></p>
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
index adde938..c8ddfce 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
index adde938..6b6a6df 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
index c61cce7..827d84a 100755
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
index c61cce7..edc6023 100755
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 3997702..f57f32e 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1294,6 +1294,7 @@
                     }
                     if (!teardown(otherNet)) {
                         loge("Network declined teardown request");
+                        teardown(thisNet);
                         return;
                     }
                 }
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 4e80147..7e5fd29 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -65,6 +65,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
@@ -148,7 +149,8 @@
 
     private Context                               mContext;
     private NativeDaemonConnector                 mConnector;
-    private String                                mLegacyState = Environment.MEDIA_REMOVED;
+    private final HashMap<String, String>         mVolumeStates = new HashMap<String, String>();
+    private String                                mExternalStoragePath;
     private PackageManagerService                 mPms;
     private boolean                               mUmsEnabling;
     // Used as a lock for methods that register/unregister listeners.
@@ -453,22 +455,25 @@
                     @Override
                     public void run() {
                         try {
-                            String path = Environment.getExternalStorageDirectory().getPath();
-                            String state = getVolumeState(path);
+                            synchronized (mVolumeStates) {
+                                for (String path : mVolumeStates.keySet()) {
+                                    String state = mVolumeStates.get(path);
 
-                            if (mEmulateExternalStorage) {
-                                notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Mounted);
-                            } else if (state.equals(Environment.MEDIA_UNMOUNTED)) {
-                                int rc = doMountVolume(path);
-                                if (rc != StorageResultCode.OperationSucceeded) {
-                                    Slog.e(TAG, String.format("Boot-time mount failed (%d)", rc));
+                                    if (state.equals(Environment.MEDIA_UNMOUNTED)) {
+                                        int rc = doMountVolume(path);
+                                        if (rc != StorageResultCode.OperationSucceeded) {
+                                            Slog.e(TAG, String.format("Boot-time mount failed (%d)",
+                                                    rc));
+                                        }
+                                    } else if (state.equals(Environment.MEDIA_SHARED)) {
+                                        /*
+                                         * Bootstrap UMS enabled state since vold indicates
+                                         * the volume is shared (runtime restart while ums enabled)
+                                         */
+                                        notifyVolumeStateChange(null, path, VolumeState.NoMedia,
+                                                VolumeState.Shared);
+                                    }
                                 }
-                            } else if (state.equals(Environment.MEDIA_SHARED)) {
-                                /*
-                                 * Bootstrap UMS enabled state since vold indicates
-                                 * the volume is shared (runtime restart while ums enabled)
-                                 */
-                                notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared);
                             }
 
                             /*
@@ -519,35 +524,36 @@
     }
 
     private void updatePublicVolumeState(String path, String state) {
-        if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
-            Slog.w(TAG, "Multiple volumes not currently supported");
+        String oldState;
+        synchronized(mVolumeStates) {
+            oldState = mVolumeStates.put(path, state);
+        }
+        if (state.equals(oldState)) {
+            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
+                    state, state, path));
             return;
         }
 
-        if (mLegacyState.equals(state)) {
-            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
-            return;
-        }
-        // Update state on PackageManager, but only of real events
-        if (!mEmulateExternalStorage) {
-            if (Environment.MEDIA_UNMOUNTED.equals(state)) {
-                mPms.updateExternalMediaStatus(false, false);
+        Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
 
-                /*
-                 * Some OBBs might have been unmounted when this volume was
-                 * unmounted, so send a message to the handler to let it know to
-                 * remove those from the list of mounted OBBS.
-                 */
-                mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE,
-                        path));
-            } else if (Environment.MEDIA_MOUNTED.equals(state)) {
-                mPms.updateExternalMediaStatus(true, false);
+        if (path.equals(mExternalStoragePath)) {
+            // Update state on PackageManager, but only of real events
+            if (!mEmulateExternalStorage) {
+                if (Environment.MEDIA_UNMOUNTED.equals(state)) {
+                    mPms.updateExternalMediaStatus(false, false);
+
+                    /*
+                     * Some OBBs might have been unmounted when this volume was
+                     * unmounted, so send a message to the handler to let it know to
+                     * remove those from the list of mounted OBBS.
+                     */
+                    mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
+                            OBB_FLUSH_MOUNT_STATE, path));
+                } else if (Environment.MEDIA_MOUNTED.equals(state)) {
+                    mPms.updateExternalMediaStatus(true, false);
+                }
             }
         }
-
-        String oldState = mLegacyState;
-        mLegacyState = state;
-
         synchronized (mListeners) {
             for (int i = mListeners.size() -1; i >= 0; i--) {
                 MountServiceBinderListener bl = mListeners.get(i);
@@ -578,20 +584,15 @@
                 /**
                  * Determine media state and UMS detection status
                  */
-                String path = Environment.getExternalStorageDirectory().getPath();
-                String state = Environment.MEDIA_REMOVED;
-
                 try {
                     String[] vols = mConnector.doListCommand(
                         "volume list", VoldResponseCode.VolumeListResult);
                     for (String volstr : vols) {
                         String[] tok = volstr.split(" ");
                         // FMT: <label> <mountpoint> <state>
-                        if (!tok[1].equals(path)) {
-                            Slog.w(TAG, String.format(
-                                    "Skipping unknown volume '%s'",tok[1]));
-                            continue;
-                        }
+                        String path = tok[1];
+                        String state = Environment.MEDIA_REMOVED;
+
                         int st = Integer.parseInt(tok[2]);
                         if (st == VolumeState.NoMedia) {
                             state = Environment.MEDIA_REMOVED;
@@ -606,14 +607,15 @@
                         } else {
                             throw new Exception(String.format("Unexpected state %d", st));
                         }
-                    }
-                    if (state != null) {
-                        if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
-                        updatePublicVolumeState(path, state);
+
+                        if (state != null) {
+                            if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
+                            updatePublicVolumeState(path, state);
+                        }
                     }
                 } catch (Exception e) {
                     Slog.e(TAG, "Error processing initial volume state", e);
-                    updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
+                    updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
                 }
 
                 try {
@@ -1055,11 +1057,12 @@
     public MountService(Context context) {
         mContext = context;
 
+        mExternalStoragePath = Environment.getExternalStorageDirectory().getPath();
         mEmulateExternalStorage = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_emulateExternalStorage);
         if (mEmulateExternalStorage) {
             Slog.d(TAG, "using emulated external storage");
-            mLegacyState = Environment.MEDIA_MOUNTED;
+            mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
         }
 
         // XXX: This will go away soon in favor of IMountServiceObserver
@@ -1127,54 +1130,56 @@
         validatePermission(android.Manifest.permission.SHUTDOWN);
 
         Slog.i(TAG, "Shutting down");
+        synchronized (mVolumeStates) {
+            for (String path : mVolumeStates.keySet()) {
+                String state = mVolumeStates.get(path);
 
-        String path = Environment.getExternalStorageDirectory().getPath();
-        String state = getVolumeState(path);
-
-        if (state.equals(Environment.MEDIA_SHARED)) {
-            /*
-             * If the media is currently shared, unshare it.
-             * XXX: This is still dangerous!. We should not
-             * be rebooting at *all* if UMS is enabled, since
-             * the UMS host could have dirty FAT cache entries
-             * yet to flush.
-             */
-            setUsbMassStorageEnabled(false);
-        } else if (state.equals(Environment.MEDIA_CHECKING)) {
-            /*
-             * If the media is being checked, then we need to wait for
-             * it to complete before being able to proceed.
-             */
-            // XXX: @hackbod - Should we disable the ANR timer here?
-            int retries = 30;
-            while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException iex) {
-                    Slog.e(TAG, "Interrupted while waiting for media", iex);
-                    break;
+                if (state.equals(Environment.MEDIA_SHARED)) {
+                    /*
+                     * If the media is currently shared, unshare it.
+                     * XXX: This is still dangerous!. We should not
+                     * be rebooting at *all* if UMS is enabled, since
+                     * the UMS host could have dirty FAT cache entries
+                     * yet to flush.
+                     */
+                    setUsbMassStorageEnabled(false);
+                } else if (state.equals(Environment.MEDIA_CHECKING)) {
+                    /*
+                     * If the media is being checked, then we need to wait for
+                     * it to complete before being able to proceed.
+                     */
+                    // XXX: @hackbod - Should we disable the ANR timer here?
+                    int retries = 30;
+                    while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
+                        try {
+                            Thread.sleep(1000);
+                        } catch (InterruptedException iex) {
+                            Slog.e(TAG, "Interrupted while waiting for media", iex);
+                            break;
+                        }
+                        state = Environment.getExternalStorageState();
+                    }
+                    if (retries == 0) {
+                        Slog.e(TAG, "Timed out waiting for media to check");
+                    }
                 }
-                state = Environment.getExternalStorageState();
-            }
-            if (retries == 0) {
-                Slog.e(TAG, "Timed out waiting for media to check");
-            }
-        }
 
-        if (state.equals(Environment.MEDIA_MOUNTED)) {
-            // Post a unmount message.
-            ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
-            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
-        } else if (observer != null) {
-            /*
-             * Observer is waiting for onShutDownComplete when we are done.
-             * Since nothing will be done send notification directly so shutdown
-             * sequence can continue.
-             */
-            try {
-                observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException when shutting down");
+                if (state.equals(Environment.MEDIA_MOUNTED)) {
+                    // Post a unmount message.
+                    ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
+                    mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
+                } else if (observer != null) {
+                    /*
+                     * Observer is waiting for onShutDownComplete when we are done.
+                     * Since nothing will be done send notification directly so shutdown
+                     * sequence can continue.
+                     */
+                    try {
+                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException when shutting down");
+                    }
+                }
             }
         }
     }
@@ -1246,16 +1251,15 @@
      * @return state of the volume at the specified mount point
      */
     public String getVolumeState(String mountPoint) {
-        /*
-         * XXX: Until we have multiple volume discovery, just hardwire
-         * this to /sdcard
-         */
-        if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
-            Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
-            throw new IllegalArgumentException();
-        }
+        synchronized (mVolumeStates) {
+            String state = mVolumeStates.get(mountPoint);
+            if (state == null) {
+                Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
+                throw new IllegalArgumentException();
+            }
 
-        return mLegacyState;
+            return state;
+        }
     }
 
     public boolean isExternalStorageEmulated() {
@@ -1534,7 +1538,8 @@
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedStorageNotFound) {
-                throw new IllegalArgumentException(String.format("Container '%s' not found", id));
+                Slog.i(TAG, String.format("Container '%s' not found", id));
+                return null;
             } else {
                 throw new IllegalStateException(String.format("Unexpected response code %d", code));
             }
@@ -1729,6 +1734,18 @@
         }
     }
 
+    public String[] getVolumeList() {
+        synchronized(mVolumeStates) {
+            Set<String> volumes = mVolumeStates.keySet();
+            String[] result = new String[volumes.size()];
+            int i = 0;
+            for (String volume : volumes) {
+                result[i++] = volume;
+            }
+            return result;
+        }
+    }
+
     private void addObbStateLocked(ObbState obbState) throws RemoteException {
         final IBinder binder = obbState.getBinder();
         List<ObbState> obbStates = mObbMounts.get(binder);