Merge "This hardware video decoder lies about its required input buffer sizes allocating 2.7 MB of memory instead of the required 176 KB... Added another quirk."
diff --git a/api/current.xml b/api/current.xml
index a753165..2729ff4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -23748,7 +23748,7 @@
 >
 <parameter name="parcel" type="android.os.Parcel">
 </parameter>
-<parameter name="flagz" type="int">
+<parameter name="flags" type="int">
 </parameter>
 </method>
 <field name="CREATOR"
@@ -26277,6 +26277,83 @@
 </parameter>
 </method>
 </interface>
+<class name="UiModeManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="disableCarMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNightMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setNightMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<field name="MODE_AUTO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_NIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_NOTNIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="WallpaperInfo"
  extends="java.lang.Object"
  abstract="false"
@@ -34549,6 +34626,17 @@
  visibility="public"
 >
 </field>
+<field name="UI_MODE_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;uimode&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="VIBRATOR_SERVICE"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c7c9429..50dcdf9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -194,6 +194,7 @@
     private AccountManager mAccountManager; // protected by mSync
     private DropBoxManager mDropBoxManager = null;
     private DevicePolicyManager mDevicePolicyManager = null;
+    private UiModeManager mUiModeManager = null;
 
     private final Object mSync = new Object();
 
@@ -960,6 +961,8 @@
             return getDropBoxManager();
         } else if (DEVICE_POLICY_SERVICE.equals(name)) {
             return getDevicePolicyManager();
+        } else if (UI_MODE_SERVICE.equals(name)) {
+            return getUiModeManager();
         }
 
         return null;
@@ -1153,6 +1156,15 @@
         return mDevicePolicyManager;
     }
 
+    private UiModeManager getUiModeManager() {
+        synchronized (mSync) {
+            if (mUiModeManager == null) {
+                mUiModeManager = new UiModeManager();
+            }
+        }
+        return mUiModeManager;
+    }
+
     @Override
     public int checkPermission(String permission, int pid, int uid) {
         if (permission == null) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 4598bb5..0ed5eb8 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -822,13 +822,15 @@
         final SearchManager searchManager = (SearchManager) mContext
                 .getSystemService(Context.SEARCH_SERVICE);
 
-        // associate search with owner activity if possible (otherwise it will default to
-        // global search).
+        // associate search with owner activity
         final ComponentName appName = getAssociatedActivity();
-        final boolean globalSearch = (appName == null);
-        searchManager.startSearch(null, false, appName, null, globalSearch);
-        dismiss();
-        return true;
+        if (appName != null) {
+            searchManager.startSearch(null, false, appName, null, false);
+            dismiss();
+            return true;
+        } else {
+            return false;
+        }
     }
 
     /**
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index ce5f1bf..99edfac 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1639,6 +1639,7 @@
             return;
         }
         Intent intent = new Intent(INTENT_ACTION_GLOBAL_SEARCH);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setComponent(globalSearchActivity);
         // TODO: Always pass name of calling package as an extra?
         if (appSearchData != null) {
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
new file mode 100644
index 0000000..aca8ab4
--- /dev/null
+++ b/core/java/android/app/UiModeManager.java
@@ -0,0 +1,83 @@
+package android.app;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * This class provides access to the system uimode services.  These services
+ * allow applications to control UI modes of the device.
+ * It provides functionality to disable the car mode and it gives access to the
+ * night mode settings.
+ *
+ * <p>You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.UI_MODE_SERVICE)}.
+ */
+public class UiModeManager {
+    private static final String TAG = "UiModeManager";
+
+    public static final int MODE_NOTNIGHT = 1;
+    public static final int MODE_NIGHT = 2;
+    public static final int MODE_AUTO = 3;
+
+    private IUiModeManager mService;
+
+    /*package*/ UiModeManager() {
+        mService = IUiModeManager.Stub.asInterface(
+                ServiceManager.getService("uimode"));
+    }
+
+    /**
+     * Disables the car mode.
+     */
+    public void disableCarMode() {
+        if (mService != null) {
+            try {
+                mService.disableCarMode();
+            } catch (RemoteException e) {
+                Log.e(TAG, "disableCarMode: RemoteException", e);
+            }
+        }
+    }
+
+    /**
+     * Sets the night mode.  Changes to the night mode are only effective when
+     * the car mode is enabled on a device.
+     *
+     * <p>The mode can be one of:
+     * <ul>
+     *   <li><em>{@link #MODE_NOTNIGHT}<em> - sets the device into notnight
+     *       mode.</li>
+     *   <li><em>{@link #MODE_NIGHT}</em> - sets the device into night mode.
+     *   </li>
+     *   <li><em>{@link #MODE_AUTO}</em> - automatic night/notnight switching
+     *       depending on the location and certain other sensors.</li>
+     */
+    public void setNightMode(int mode) {
+        if (mService != null) {
+            try {
+                mService.setNightMode(mode);
+            } catch (RemoteException e) {
+                Log.e(TAG, "setNightMode: RemoteException", e);
+            }
+        }
+    }
+
+    /**
+     * Returns the currently configured night mode.
+     *
+     * @return {@link #MODE_NOTNIGHT}, {@link #MODE_NIGHT} or {@link #MODE_AUTO}
+     *         When an error occurred -1 is returned.
+     */
+    public int getNightMode() {
+        if (mService != null) {
+            try {
+                return mService.getNightMode();
+            } catch (RemoteException e) {
+                Log.e(TAG, "getNightMode: RemoteException", e);
+            }
+        }
+        return -1;
+    }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 672e5f7..897d702 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1204,6 +1204,8 @@
      * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
      * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
      * for management of input methods.
+     * <dt> {@link #UI_MODE_SERVICE} ("uimode")
+     * <dd> An {@link android.app.UiModeManager} for controlling UI modes.
      * </dl>
      * 
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -1249,6 +1251,8 @@
      * @see android.telephony.TelephonyManager
      * @see #INPUT_METHOD_SERVICE
      * @see android.view.inputmethod.InputMethodManager
+     * @see #UI_MODE_SERVICE
+     * @see android.app.UiModeManager
      */
     public abstract Object getSystemService(String name);
 
@@ -1511,6 +1515,14 @@
     public static final String DEVICE_POLICY_SERVICE = "device_policy";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.app.UiModeManager} for controlling UI modes.
+     *
+     * @see #getSystemService
+     */
+    public static final String UI_MODE_SERVICE = "uimode";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index eb85822..a7a1d9a 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -95,12 +95,16 @@
         }
     }
 
-    /* package */ synchronized boolean isInUse() {
-        return mInUse;
-    }
-
-    /* package */ synchronized void acquire() {
+    /**
+     * returns true if acquire() succeeds. false otherwise.
+     */
+    /* package */ synchronized boolean acquire() {
+        if (mInUse) {
+            // someone already has acquired it.
+            return false;
+        }
         mInUse = true;
+        return true;
     }
 
     /* package */ synchronized void release() {
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 2bb2f5d..a3a8486 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -61,16 +61,13 @@
             mCompiledSql.acquire();
         } else {
             // it is already in compiled-sql cache.
-            if (mCompiledSql.isInUse()) {
-                // but the CompiledSql in cache is in use by some other SQLiteProgram object.
+            // try to acquire the object.
+            if (!mCompiledSql.acquire()) {
+                // the SQLiteCompiledSql in cache is in use by some other SQLiteProgram object.
                 // we can't have two different SQLiteProgam objects can't share the same
                 // CompiledSql object. create a new one.
                 // finalize it when I am done with it in "this" object.
                 mCompiledSql = new SQLiteCompiledSql(db, sql);
-            } else {
-                // the CompiledSql in cache is NOT in use by any other SQLiteProgram object.
-                // it is safe to give it to this SQLIteProgram Object.
-                mCompiledSql.acquire();
             }
         }
         nStatement = mCompiledSql.nStatement;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a79bbee..17d5bb7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1960,7 +1960,6 @@
             if (getHeight() > 0 && getChildCount() > 0) {
                 // We do not lose focus initiating a touch (since AbsListView is focusable in
                 // touch mode). Force an initial layout to get rid of the selection.
-                mLayoutMode = LAYOUT_NORMAL;
                 layoutChildren();
             }
         } else {
@@ -3118,7 +3117,9 @@
 
     void hideSelector() {
         if (mSelectedPosition != INVALID_POSITION) {
-            mResurrectToPosition = mSelectedPosition;
+            if (mLayoutMode != LAYOUT_SPECIFIC) {
+                mResurrectToPosition = mSelectedPosition;
+            }
             if (mNextSelectedPosition >= 0 && mNextSelectedPosition != mSelectedPosition) {
                 mResurrectToPosition = mNextSelectedPosition;
             }
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index f56b15c..107b145 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,6 +26,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.text.TextUtils;
+import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -48,7 +49,6 @@
 import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
 import android.widget.AdapterView.OnItemClickListener;
-import android.util.AttributeSet;
 
 import com.android.internal.R;
 
@@ -322,24 +322,24 @@
     public Button getButton(int whichButton) {
         switch (whichButton) {
             case DialogInterface.BUTTON_POSITIVE:
-                return mButtonPositiveMessage != null ? mButtonPositive : null;
+                return mButtonPositive;
             case DialogInterface.BUTTON_NEGATIVE:
-                return mButtonNegativeMessage != null ? mButtonNegative : null;
+                return mButtonNegative;
             case DialogInterface.BUTTON_NEUTRAL:
-                return mButtonNeutralMessage != null ? mButtonNeutral : null;
+                return mButtonNeutral;
             default:
                 return null;
         }
     }
     
+    @SuppressWarnings({"UnusedDeclaration"})
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (mScrollView != null && mScrollView.executeKeyEvent(event)) return true;
-        return false;
+        return mScrollView != null && mScrollView.executeKeyEvent(event);
     }
 
+    @SuppressWarnings({"UnusedDeclaration"})
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (mScrollView != null && mScrollView.executeKeyEvent(event)) return true;
-        return false;
+        return mScrollView != null && mScrollView.executeKeyEvent(event);
     }
     
     private void setupView() {
@@ -469,7 +469,6 @@
     }
 
     private boolean setupButtons() {
-        View defaultButton = null;
         int BIT_BUTTON_POSITIVE = 1;
         int BIT_BUTTON_NEGATIVE = 2;
         int BIT_BUTTON_NEUTRAL = 4;
@@ -482,7 +481,6 @@
         } else {
             mButtonPositive.setText(mButtonPositiveText);
             mButtonPositive.setVisibility(View.VISIBLE);
-            defaultButton = mButtonPositive;
             whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
         }
 
@@ -495,9 +493,6 @@
             mButtonNegative.setText(mButtonNegativeText);
             mButtonNegative.setVisibility(View.VISIBLE);
 
-            if (defaultButton == null) {
-                defaultButton = mButtonNegative;
-            }
             whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
         }
 
@@ -510,9 +505,6 @@
             mButtonNeutral.setText(mButtonNeutralText);
             mButtonNeutral.setVisibility(View.VISIBLE);
 
-            if (defaultButton == null) {
-                defaultButton = mButtonNeutral;
-            }
             whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
         }
 
@@ -565,8 +557,6 @@
                 R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
         int bottomMedium = a.getResourceId(
                 R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
-        int centerMedium = a.getResourceId(
-                R.styleable.AlertDialog_centerMedium, R.drawable.popup_center_medium);
         
         /*
          * We now set the background of all of the sections of the alert.
@@ -596,7 +586,7 @@
          */
         views[pos] = (contentPanel.getVisibility() == View.GONE) 
                 ? null : contentPanel;
-        light[pos] = mListView == null ? false : true;
+        light[pos] = mListView != null;
         pos++;
         if (customPanel != null) {
             views[pos] = customPanel;
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index ba6c711..66c34b2 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -30,6 +30,7 @@
 class ProcessState;
 class String8;
 class TextOutput;
+class Flattenable;
 
 struct flat_binder_object;  // defined in support_p/binder_module.h
 
@@ -81,6 +82,7 @@
     status_t            writeString16(const char16_t* str, size_t len);
     status_t            writeStrongBinder(const sp<IBinder>& val);
     status_t            writeWeakBinder(const wp<IBinder>& val);
+    status_t            write(const Flattenable& val);
 
     // Place a native_handle into the parcel (the native_handle's file-
     // descriptors are dup'ed, so it is safe to delete the native_handle
@@ -119,7 +121,7 @@
     const char16_t*     readString16Inplace(size_t* outLen) const;
     sp<IBinder>         readStrongBinder() const;
     wp<IBinder>         readWeakBinder() const;
-
+    status_t            read(Flattenable& val) const;
     
     // Retrieve native_handle from the parcel. This returns a copy of the
     // parcel's native_handle (the caller takes ownership). The caller
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index b9c491be..e72b6b3 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -23,6 +23,7 @@
 #include <ui/android_native_buffer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
+#include <utils/Flattenable.h>
 #include <pixelflinger/pixelflinger.h>
 
 struct android_native_buffer_t;
@@ -30,7 +31,6 @@
 namespace android {
 
 class GraphicBufferMapper;
-class Parcel;
 
 // ===========================================================================
 // GraphicBuffer
@@ -40,7 +40,7 @@
     : public EGLNativeBase<
         android_native_buffer_t, 
         GraphicBuffer, 
-        LightRefBase<GraphicBuffer> >
+        LightRefBase<GraphicBuffer> >, public Flattenable
 {
 public:
 
@@ -97,7 +97,6 @@
     uint32_t getVerticalStride() const;
 
 protected:
-    GraphicBuffer(const Parcel& reply);
     virtual ~GraphicBuffer();
 
     enum {
@@ -122,8 +121,16 @@
     status_t initSize(uint32_t w, uint32_t h, PixelFormat format, 
             uint32_t usage);
 
-    static status_t writeToParcel(Parcel* reply, 
-            android_native_buffer_t const* buffer);
+    void free_handle();
+
+    // Flattenable interface
+    size_t getFlattenedSize() const;
+    size_t getFdCount() const;
+    status_t flatten(void* buffer, size_t size,
+            int fds[], size_t count) const;
+    status_t unflatten(void const* buffer, size_t size,
+            int fds[], size_t count);
+
 
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h
new file mode 100644
index 0000000..852be3b
--- /dev/null
+++ b/include/utils/Flattenable.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_UTILS_FLATTENABLE_H
+#define ANDROID_UTILS_FLATTENABLE_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class Flattenable
+{
+public:
+    // size in bytes of the flattened object
+    virtual size_t getFlattenedSize() const = 0;
+
+    // number of file descriptors to flatten
+    virtual size_t getFdCount() const = 0;
+
+    // flattens the object into buffer.
+    // size should be at least of getFlattenedSize()
+    // file descriptors are written in the fds[] array but ownership is
+    // not transfered (ie: they must be dupped by the caller of
+    // flatten() if needed).
+    virtual status_t flatten(void* buffer, size_t size,
+            int fds[], size_t count) const = 0;
+
+    // unflattens the object from buffer.
+    // size should be equal to the value of getFlattenedSize() when the
+    // object was flattened.
+    // unflattened file descriptors are found in the fds[] array and
+    // don't need to be dupped(). ie: the caller of unflatten doesn't
+    // keep ownership. If a fd is not retained by unflatten() it must be
+    // explicitly closed.
+    virtual status_t unflatten(void const* buffer, size_t size,
+            int fds[], size_t count) = 0;
+
+protected:
+    virtual ~Flattenable() = 0;
+
+};
+
+}; // namespace android
+
+
+#endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/keystore/java/android/security/SystemKeyStore.java b/keystore/java/android/security/SystemKeyStore.java
index 61a4293..abdb0ae 100644
--- a/keystore/java/android/security/SystemKeyStore.java
+++ b/keystore/java/android/security/SystemKeyStore.java
@@ -17,6 +17,7 @@
 package android.security;
 
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Process;
 
 import java.io.File;
@@ -92,6 +93,8 @@
             fos.write(retKey);
             fos.flush();
             fos.close();
+            FileUtils.setPermissions(keyFile.getName(), (FileUtils.S_IRUSR | FileUtils.S_IWUSR),
+                -1, -1);
         } catch (IOException ioe) {
             return null;
         }
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index e397bce..00d2210 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -28,6 +28,7 @@
 #include <utils/String16.h>
 #include <utils/TextOutput.h>
 #include <utils/misc.h>
+#include <utils/Flattenable.h>
 
 #include <private/binder/binder_module.h>
 
@@ -675,6 +676,42 @@
     return writeObject(obj, true);
 }
 
+status_t Parcel::write(const Flattenable& val)
+{
+    status_t err;
+
+    // size if needed
+    size_t len = val.getFlattenedSize();
+    size_t fd_count = val.getFdCount();
+
+    err = this->writeInt32(len);
+    if (err) return err;
+
+    err = this->writeInt32(fd_count);
+    if (err) return err;
+
+    // payload
+    void* buf = this->writeInplace(PAD_SIZE(len));
+    if (buf == NULL)
+        return BAD_VALUE;
+
+    int* fds = NULL;
+    if (fd_count) {
+        fds = new int[fd_count];
+    }
+
+    err = val.flatten(buf, len, fds, fd_count);
+    for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
+        err = this->writeDupFileDescriptor( fds[i] );
+    }
+
+    if (fd_count) {
+        delete [] fds;
+    }
+
+    return err;
+}
+
 status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
 {
     const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
@@ -713,7 +750,6 @@
     goto restart_write;
 }
 
-
 void Parcel::remove(size_t start, size_t amt)
 {
     LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
@@ -940,6 +976,38 @@
     return BAD_TYPE;
 }
 
+status_t Parcel::read(Flattenable& val) const
+{
+    // size
+    const size_t len = this->readInt32();
+    const size_t fd_count = this->readInt32();
+
+    // payload
+    void const* buf = this->readInplace(PAD_SIZE(len));
+    if (buf == NULL)
+        return BAD_VALUE;
+
+    int* fds = NULL;
+    if (fd_count) {
+        fds = new int[fd_count];
+    }
+
+    status_t err = NO_ERROR;
+    for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
+        fds[i] = dup(this->readFileDescriptor());
+        if (fds[i] < 0) err = BAD_VALUE;
+    }
+
+    if (err == NO_ERROR) {
+        err = val.unflatten(buf, len, fds, fd_count);
+    }
+
+    if (fd_count) {
+        delete [] fds;
+    }
+
+    return err;
+}
 const flat_binder_object* Parcel::readObject(bool nullMetaData) const
 {
     const size_t DPOS = mDataPos;
diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp
index 9125146..bb86199 100644
--- a/libs/surfaceflinger_client/ISurface.cpp
+++ b/libs/surfaceflinger_client/ISurface.cpp
@@ -78,7 +78,8 @@
         data.writeInt32(bufferIdx);
         data.writeInt32(usage);
         remote()->transact(REQUEST_BUFFER, data, &reply);
-        sp<GraphicBuffer> buffer = new GraphicBuffer(reply);
+        sp<GraphicBuffer> buffer = new GraphicBuffer();
+        reply.read(*buffer);
         return buffer;
     }
 
@@ -141,7 +142,9 @@
             int bufferIdx = data.readInt32();
             int usage = data.readInt32();
             sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
-            return GraphicBuffer::writeToParcel(reply, buffer.get());
+            if (buffer == NULL)
+                return BAD_VALUE;
+            return reply->write(*buffer);
         }
         case REGISTER_BUFFERS: {
             CHECK_INTERFACE(ISurface, data, reply);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 6a5c8a9..ba1fd9c 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "GraphicBuffer"
+
 #include <stdlib.h>
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <binder/Parcel.h>
-
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
@@ -77,34 +77,21 @@
     handle = inHandle;
 }
 
-GraphicBuffer::GraphicBuffer(const Parcel& data) 
-    : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
-{
-    // we own the handle in this case
-    width  = data.readInt32();
-    if (width < 0) {
-        width = height = stride = format = usage = 0;
-        handle = 0;
-    } else {
-        height = data.readInt32();
-        stride = data.readInt32();
-        format = data.readInt32();
-        usage  = data.readInt32();
-        handle = data.readNativeHandle();
-    }
-}
-
 GraphicBuffer::~GraphicBuffer()
 {
     if (handle) {
-        if (mOwner == ownHandle) {
-            native_handle_close(handle);
-            native_handle_delete(const_cast<native_handle*>(handle));
-        } else if (mOwner == ownData) {
-            GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
-            allocator.free(handle);
-        }
+        free_handle();
+    }
+}
+
+void GraphicBuffer::free_handle()
+{
+    if (mOwner == ownHandle) {
+        native_handle_close(handle);
+        native_handle_delete(const_cast<native_handle*>(handle));
+    } else if (mOwner == ownData) {
+        GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
+        allocator.free(handle);
     }
 }
 
@@ -192,29 +179,83 @@
     return res;
 }
 
+size_t GraphicBuffer::getFlattenedSize() const {
+    return (8 + (handle ? handle->numInts : 0))*sizeof(int);
+}
 
-status_t GraphicBuffer::writeToParcel(Parcel* reply, 
-        android_native_buffer_t const* buffer)
+size_t GraphicBuffer::getFdCount() const {
+    return handle ? handle->numFds : 0;
+}
+
+status_t GraphicBuffer::flatten(void* buffer, size_t size,
+        int fds[], size_t count) const
 {
-    if (buffer == NULL)
-        return BAD_VALUE;
+    size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
+    if (size < sizeNeeded) return NO_MEMORY;
 
-    if (buffer->width < 0 || buffer->height < 0)
-        return BAD_VALUE;
+    size_t fdCountNeeded = GraphicBuffer::getFdCount();
+    if (count < fdCountNeeded) return NO_MEMORY;
 
-    status_t err = NO_ERROR;
-    if (buffer->handle == NULL) {
-        // this buffer doesn't have a handle
-        reply->writeInt32(NO_MEMORY);
-    } else {
-        reply->writeInt32(buffer->width);
-        reply->writeInt32(buffer->height);
-        reply->writeInt32(buffer->stride);
-        reply->writeInt32(buffer->format);
-        reply->writeInt32(buffer->usage);
-        err = reply->writeNativeHandle(buffer->handle);
+    int* buf = static_cast<int*>(buffer);
+    buf[0] = 'GBFR';
+    buf[1] = width;
+    buf[2] = height;
+    buf[3] = stride;
+    buf[4] = format;
+    buf[5] = usage;
+    buf[6] = 0;
+    buf[7] = 0;
+
+    if (handle) {
+        buf[6] = handle->numFds;
+        buf[7] = handle->numInts;
+        native_handle_t const* const h = handle;
+        memcpy(fds,     h->data,             h->numFds*sizeof(int));
+        memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int));
     }
-    return err;
+
+    return NO_ERROR;
+}
+
+status_t GraphicBuffer::unflatten(void const* buffer, size_t size,
+        int fds[], size_t count)
+{
+    if (size < 8*sizeof(int)) return NO_MEMORY;
+
+    int const* buf = static_cast<int const*>(buffer);
+    if (buf[0] != 'GBFR') return BAD_TYPE;
+
+    const size_t numFds  = buf[6];
+    const size_t numInts = buf[7];
+
+    const size_t sizeNeeded = (8 + numInts) * sizeof(int);
+    if (size < sizeNeeded) return NO_MEMORY;
+
+    size_t fdCountNeeded = 0;
+    if (count < fdCountNeeded) return NO_MEMORY;
+
+    if (handle) {
+        // free previous handle if any
+        free_handle();
+    }
+
+    if (numFds || numInts) {
+        width  = buf[1];
+        height = buf[2];
+        stride = buf[3];
+        format = buf[4];
+        usage  = buf[5];
+        native_handle* h = native_handle_create(numFds, numInts);
+        memcpy(h->data,          fds,     numFds*sizeof(int));
+        memcpy(h->data + numFds, &buf[8], numInts*sizeof(int));
+        handle = h;
+    } else {
+        width = height = stride = format = usage = 0;
+        handle = NULL;
+    }
+
+    mOwner = ownHandle;
+    return NO_ERROR;
 }
 
 
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index d2cfd3b..d0eedb4 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -25,6 +25,7 @@
 	CallStack.cpp \
 	Debug.cpp \
 	FileMap.cpp \
+	Flattenable.cpp \
 	RefBase.cpp \
 	ResourceTypes.cpp \
 	SharedBuffer.cpp \
diff --git a/libs/utils/Flattenable.cpp b/libs/utils/Flattenable.cpp
new file mode 100644
index 0000000..1f2ffaa
--- /dev/null
+++ b/libs/utils/Flattenable.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Flattenable.h>
+
+namespace android {
+
+Flattenable::~Flattenable() {
+}
+
+}; // namespace android
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 2a78806..39ee314 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -202,7 +202,7 @@
         String vs = getVolumeState(path);
         if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
             mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
-            int rc = doUnmountVolume(path, false);
+            int rc = doUnmountVolume(path, true);
             mUmsEnabling = false; // Clear override
             if (rc != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));