Merge from Chromium at DEPS revision 33.0.1750.68

This commit was generated by merge_to_master.py.

Change-Id: Id5b157193ca431586fbf7615bf4a7a152aab3ff9
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 7ede406..c11aeac 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -489,9 +489,10 @@
         AwSettings.ZoomSupportChangeListener zoomListener =
                 new AwSettings.ZoomSupportChangeListener() {
                     @Override
-                    public void onGestureZoomSupportChanged(boolean supportsGestureZoom) {
-                        mContentViewCore.updateMultiTouchZoomSupport(supportsGestureZoom);
-                        mContentViewCore.updateDoubleTapSupport(supportsGestureZoom);
+                    public void onGestureZoomSupportChanged(
+                            boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom) {
+                        mContentViewCore.updateDoubleTapSupport(supportsDoubleTapZoom);
+                        mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
                     }
 
                 };
@@ -945,7 +946,7 @@
     }
 
     public boolean isMultiTouchZoomSupported() {
-        return mSettings.supportsGestureZoom();
+        return mSettings.supportsMultiTouchZoom();
     }
 
     public View getZoomControlsForTest() {
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
index 66e4f1e..4e6fbdd 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
@@ -55,6 +55,11 @@
             @Override
             public void onReceiveValue(Boolean value) {
                 proceedSslError(value.booleanValue(), id);
+                if (!value) {
+                    // For backward compatibility with the classic
+                    // webview, call onPageFinished after canceling ssl error.
+                    AwContentsClientBridge.this.mClient.onPageFinished(url);
+                }
             }
         };
         mClient.onReceivedSslError(callback, sslError);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
index d212f04..f10ff7f 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
@@ -26,7 +26,11 @@
     // Time for the longest scroll animation.
     private static final int MAX_SCROLL_ANIMATION_DURATION_MILLISEC = 750;
 
-    // The unit of all the values in this delegate are physical pixels.
+    /**
+     * The interface that all users of AwScrollOffsetManager should implement.
+     *
+     * The unit of all the values in this delegate are physical pixels.
+     */
     public interface Delegate {
         // Call View#overScrollBy on the containerView.
         void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY,
@@ -279,15 +283,13 @@
 
         mScroller.fling(scrollX, scrollY, velocityX, velocityY,
                 0, scrollRangeX, 0, scrollRangeY);
-        mFlinging = true;
         mDelegate.invalidate();
     }
 
     // Called immediately before the draw to update the scroll offset.
     public void computeScrollAndAbsorbGlow(OverScrollGlow overScrollGlow) {
-        final boolean stillAnimating = mScroller.computeScrollOffset();
-        if (!stillAnimating) {
-            mFlinging = false;
+        mFlinging = mScroller.computeScrollOffset();
+        if (!mFlinging) {
             return;
         }
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
index 6ba9ac6..149061b 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -118,8 +118,6 @@
     // The native side of this object. It's lifetime is bounded by the WebContent it is attached to.
     private long mNativeAwSettings = 0;
 
-    // A flag to avoid sending superfluous synchronization messages.
-    private boolean mIsUpdateWebkitPrefsMessagePending = false;
     // Custom handler that queues messages to call native code on the UI thread.
     private final EventHandler mEventHandler;
 
@@ -128,10 +126,12 @@
 
     // Class to handle messages to be processed on the UI thread.
     private class EventHandler {
-        // Message id for updating Webkit preferences
-        private static final int UPDATE_WEBKIT_PREFERENCES = 0;
+        // Message id for running a Runnable with mAwSettingsLock held.
+        private static final int RUN_RUNNABLE_BLOCKING = 0;
         // Actual UI thread handler
         private Handler mHandler;
+        // Synchronization flag.
+        private boolean mSynchronizationPending = false;
 
         EventHandler() {
         }
@@ -142,10 +142,12 @@
                 @Override
                 public void handleMessage(Message msg) {
                     switch (msg.what) {
-                        case UPDATE_WEBKIT_PREFERENCES:
+                        case RUN_RUNNABLE_BLOCKING:
                             synchronized (mAwSettingsLock) {
-                                updateWebkitPreferencesOnUiThreadLocked();
-                                mIsUpdateWebkitPrefsMessagePending = false;
+                                if (mNativeAwSettings != 0) {
+                                    ((Runnable)msg.obj).run();
+                                }
+                                mSynchronizationPending = false;
                                 mAwSettingsLock.notifyAll();
                             }
                             break;
@@ -154,9 +156,23 @@
             };
         }
 
-        void maybeRunOnUiThreadBlocking(Runnable r) {
-            if (mHandler != null) {
-                ThreadUtils.runOnUiThreadBlocking(r);
+        void runOnUiThreadBlockingAndLocked(Runnable r) {
+            assert Thread.holdsLock(mAwSettingsLock);
+            if (mHandler == null) return;
+            if (ThreadUtils.runningOnUiThread()) {
+                r.run();
+            } else {
+                assert !mSynchronizationPending;
+                mSynchronizationPending = true;
+                mHandler.sendMessage(Message.obtain(null, RUN_RUNNABLE_BLOCKING, r));
+                try {
+                    while (mSynchronizationPending) {
+                        mAwSettingsLock.wait();
+                    }
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Interrupted waiting a Runnable to complete", e);
+                    mSynchronizationPending = false;
+                }
             }
         }
 
@@ -166,34 +182,19 @@
             }
         }
 
-        private void updateWebkitPreferencesLocked() {
-            assert Thread.holdsLock(mAwSettingsLock);
-            if (mNativeAwSettings == 0) return;
-            if (mHandler == null) return;
-            if (ThreadUtils.runningOnUiThread()) {
-                updateWebkitPreferencesOnUiThreadLocked();
-            } else {
-                // We're being called on a background thread, so post a message.
-                if (mIsUpdateWebkitPrefsMessagePending) {
-                    return;
+        void updateWebkitPreferencesLocked() {
+            runOnUiThreadBlockingAndLocked(new Runnable() {
+                @Override
+                public void run() {
+                    updateWebkitPreferencesOnUiThreadLocked();
                 }
-                mIsUpdateWebkitPrefsMessagePending = true;
-                mHandler.sendMessage(Message.obtain(null, UPDATE_WEBKIT_PREFERENCES));
-                // We must block until the settings have been sync'd to native to
-                // ensure that they have taken effect.
-                try {
-                    while (mIsUpdateWebkitPrefsMessagePending) {
-                        mAwSettingsLock.wait();
-                    }
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "Interrupted waiting to sync settings to native", e);
-                }
-            }
+            });
         }
     }
 
     interface ZoomSupportChangeListener {
-        public void onGestureZoomSupportChanged(boolean supportsGestureZoom);
+        public void onGestureZoomSupportChanged(
+                boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom);
     }
 
     public AwSettings(Context context,
@@ -237,6 +238,7 @@
 
     @CalledByNative
     private double getDIPScaleLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mDIPScale;
     }
 
@@ -264,7 +266,8 @@
                 mEventHandler.bindUiThread();
                 mNativeAwSettings = nativeInit(nativeWebContents);
                 nativeUpdateEverythingLocked(mNativeAwSettings);
-                onGestureZoomSupportChanged(supportsGestureZoomLocked());
+                onGestureZoomSupportChanged(
+                        supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
             }
         }
     }
@@ -367,12 +370,10 @@
         synchronized (mAwSettingsLock) {
             if (mInitialPageScalePercent != scaleInPercent) {
                 mInitialPageScalePercent = scaleInPercent;
-                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
+                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                     @Override
                     public void run() {
-                        if (mNativeAwSettings != 0) {
-                            nativeUpdateInitialPageScaleLocked(mNativeAwSettings);
-                        }
+                        nativeUpdateInitialPageScaleLocked(mNativeAwSettings);
                     }
                 });
             }
@@ -381,6 +382,7 @@
 
     @CalledByNative
     private float getInitialPageScalePercentLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mInitialPageScalePercent;
     }
 
@@ -395,6 +397,7 @@
 
     @CalledByNative
     private boolean getSpatialNavigationLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mSpatialNavigationEnabled;
     }
 
@@ -434,12 +437,10 @@
         synchronized (mAwSettingsLock) {
             if (mAutoCompleteEnabled != enable) {
                 mAutoCompleteEnabled = enable;
-                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
+                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                     @Override
                     public void run() {
-                        if (mNativeAwSettings != 0) {
-                            nativeUpdateFormDataPreferencesLocked(mNativeAwSettings);
-                        }
+                        nativeUpdateFormDataPreferencesLocked(mNativeAwSettings);
                     }
                 });
             }
@@ -457,6 +458,7 @@
 
     @CalledByNative
     private boolean getSaveFormDataLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mAutoCompleteEnabled;
     }
 
@@ -480,12 +482,10 @@
                 mUserAgent = ua;
             }
             if (!oldUserAgent.equals(mUserAgent)) {
-                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
+                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                     @Override
                     public void run() {
-                        if (mNativeAwSettings != 0) {
-                            nativeUpdateUserAgentLocked(mNativeAwSettings);
-                        }
+                        nativeUpdateUserAgentLocked(mNativeAwSettings);
                     }
                 });
             }
@@ -503,6 +503,7 @@
 
     @CalledByNative
     private String getUserAgentLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mUserAgent;
     }
 
@@ -513,13 +514,11 @@
         synchronized (mAwSettingsLock) {
             if (mLoadWithOverviewMode != overview) {
                 mLoadWithOverviewMode = overview;
-                mEventHandler.updateWebkitPreferencesLocked();
-                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
+                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                     @Override
                     public void run() {
-                        if (mNativeAwSettings != 0) {
-                            nativeResetScrollAndScaleState(mNativeAwSettings);
-                        }
+                        updateWebkitPreferencesOnUiThreadLocked();
+                        nativeResetScrollAndScaleState(mNativeAwSettings);
                     }
                 });
             }
@@ -537,6 +536,7 @@
 
     @CalledByNative
     private boolean getLoadWithOverviewModeLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mLoadWithOverviewMode;
     }
 
@@ -564,6 +564,7 @@
 
     @CalledByNative
     private int getTextSizePercentLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mTextSizePercent;
     }
 
@@ -590,6 +591,7 @@
 
     @CalledByNative
     private String getStandardFontFamilyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mStandardFontFamily;
     }
 
@@ -616,6 +618,7 @@
 
     @CalledByNative
     private String getFixedFontFamilyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mFixedFontFamily;
     }
 
@@ -642,6 +645,7 @@
 
     @CalledByNative
     private String getSansSerifFontFamilyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mSansSerifFontFamily;
     }
 
@@ -668,6 +672,7 @@
 
     @CalledByNative
     private String getSerifFontFamilyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mSerifFontFamily;
     }
 
@@ -694,6 +699,7 @@
 
     @CalledByNative
     private String getCursiveFontFamilyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mCursiveFontFamily;
     }
 
@@ -720,6 +726,7 @@
 
     @CalledByNative
     private String getFantasyFontFamilyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mFantasyFontFamily;
     }
 
@@ -747,6 +754,7 @@
 
     @CalledByNative
     private int getMinimumFontSizeLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mMinimumFontSize;
     }
 
@@ -774,6 +782,7 @@
 
     @CalledByNative
     private int getMinimumLogicalFontSizeLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mMinimumLogicalFontSize;
     }
 
@@ -801,6 +810,7 @@
 
     @CalledByNative
     private int getDefaultFontSizeLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mDefaultFontSize;
     }
 
@@ -828,6 +838,7 @@
 
     @CalledByNative
     private int getDefaultFixedFontSizeLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mDefaultFixedFontSize;
     }
 
@@ -890,6 +901,7 @@
 
     @CalledByNative
     private boolean getLoadsImagesAutomaticallyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mLoadsImagesAutomatically;
     }
 
@@ -916,6 +928,7 @@
 
     @CalledByNative
     private boolean getImagesEnabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mImagesEnabled;
     }
 
@@ -930,6 +943,7 @@
 
     @CalledByNative
     private boolean getJavaScriptEnabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mJavaScriptEnabled;
     }
 
@@ -944,6 +958,7 @@
 
     @CalledByNative
     private boolean getAllowUniversalAccessFromFileURLsLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mAllowUniversalAccessFromFileURLs;
     }
 
@@ -958,6 +973,7 @@
 
     @CalledByNative
     private boolean getAllowFileAccessFromFileURLsLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mAllowFileAccessFromFileURLs;
     }
 
@@ -992,10 +1008,10 @@
     /**
      * Return true if plugins are disabled.
      * @return True if plugins are disabled.
-     * @hide
      */
     @CalledByNative
     private boolean getPluginsDisabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mPluginState == PluginState.OFF;
     }
 
@@ -1032,6 +1048,7 @@
 
     @CalledByNative
     private boolean getJavaScriptCanOpenWindowsAutomaticallyLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mJavaScriptCanOpenWindowsAutomatically;
     }
 
@@ -1060,10 +1077,10 @@
      * Gets whether Text Auto-sizing layout algorithm is enabled.
      *
      * @return true if Text Auto-sizing layout algorithm is enabled
-     * @hide
      */
     @CalledByNative
     private boolean getTextAutosizingEnabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mLayoutAlgorithm == LayoutAlgorithm.TEXT_AUTOSIZING;
     }
 
@@ -1090,11 +1107,13 @@
 
     @CalledByNative
     private boolean getSupportMultipleWindowsLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mSupportMultipleWindows;
     }
 
     @CalledByNative
     private boolean getSupportLegacyQuirksLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mSupportLegacyQuirks;
     }
 
@@ -1105,6 +1124,8 @@
         synchronized (mAwSettingsLock) {
             if (mUseWideViewport != use) {
                 mUseWideViewport = use;
+                onGestureZoomSupportChanged(
+                        supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
                 mEventHandler.updateWebkitPreferencesLocked();
             }
         }
@@ -1121,11 +1142,13 @@
 
     @CalledByNative
     private boolean getUseWideViewportLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mUseWideViewport;
     }
 
     @CalledByNative
     private boolean getPasswordEchoEnabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mPasswordEchoEnabled;
     }
 
@@ -1167,10 +1190,10 @@
      * Gets whether Application Cache is enabled.
      *
      * @return true if Application Cache is enabled
-     * @hide
      */
     @CalledByNative
     private boolean getAppCacheEnabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         if (!mAppCacheEnabled) {
             return false;
         }
@@ -1202,6 +1225,7 @@
 
     @CalledByNative
     private boolean getDomStorageEnabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mDomStorageEnabled;
     }
 
@@ -1228,6 +1252,7 @@
 
     @CalledByNative
     private boolean getDatabaseEnabledLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mDatabaseEnabled;
     }
 
@@ -1254,6 +1279,7 @@
 
     @CalledByNative
     private String getDefaultTextEncodingLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mDefaultTextEncoding;
     }
 
@@ -1280,6 +1306,7 @@
 
     @CalledByNative
     private boolean getMediaPlaybackRequiresUserGestureLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mMediaPlaybackRequiresUserGesture;
     }
 
@@ -1307,17 +1334,20 @@
 
     @CalledByNative
     private String getDefaultVideoPosterURLLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
         return mDefaultVideoPosterURL;
     }
 
-    private void onGestureZoomSupportChanged(final boolean supportsGestureZoom) {
+    private void onGestureZoomSupportChanged(
+            final boolean supportsDoubleTapZoom, final boolean supportsMultiTouchZoom) {
         // Always post asynchronously here, to avoid doubling back onto the caller.
         mEventHandler.maybePostOnUiThread(new Runnable() {
             @Override
             public void run() {
                 synchronized (mAwSettingsLock) {
                     if (mZoomChangeListener != null) {
-                        mZoomChangeListener.onGestureZoomSupportChanged(supportsGestureZoom);
+                        mZoomChangeListener.onGestureZoomSupportChanged(
+                                supportsDoubleTapZoom, supportsMultiTouchZoom);
                     }
                 }
             }
@@ -1331,7 +1361,8 @@
         synchronized (mAwSettingsLock) {
             if (mSupportZoom != support) {
                 mSupportZoom = support;
-                onGestureZoomSupportChanged(supportsGestureZoomLocked());
+                onGestureZoomSupportChanged(
+                        supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
             }
         }
     }
@@ -1352,7 +1383,8 @@
         synchronized (mAwSettingsLock) {
             if (mBuiltInZoomControls != enabled) {
                 mBuiltInZoomControls = enabled;
-                onGestureZoomSupportChanged(supportsGestureZoomLocked());
+                onGestureZoomSupportChanged(
+                        supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
             }
         }
     }
@@ -1384,20 +1416,26 @@
         }
     }
 
-    private boolean supportsGestureZoomLocked() {
+    @CalledByNative
+    private boolean supportsDoubleTapZoomLocked() {
+        assert Thread.holdsLock(mAwSettingsLock);
+        return mSupportZoom && mBuiltInZoomControls && mUseWideViewport;
+    }
+
+    private boolean supportsMultiTouchZoomLocked() {
         assert Thread.holdsLock(mAwSettingsLock);
         return mSupportZoom && mBuiltInZoomControls;
     }
 
-    boolean supportsGestureZoom() {
+    boolean supportsMultiTouchZoom() {
         synchronized (mAwSettingsLock) {
-            return supportsGestureZoomLocked();
+            return supportsMultiTouchZoomLocked();
         }
     }
 
     boolean shouldDisplayZoomControls() {
         synchronized (mAwSettingsLock) {
-            return supportsGestureZoomLocked() && mDisplayZoomControls;
+            return supportsMultiTouchZoomLocked() && mDisplayZoomControls;
         }
     }
 
@@ -1417,18 +1455,25 @@
         }
     }
 
-    private void updateWebkitPreferencesOnUiThreadLocked() {
-        if (mNativeAwSettings != 0) {
-            assert mEventHandler.mHandler != null;
-            ThreadUtils.assertOnUiThread();
-            nativeUpdateWebkitPreferencesLocked(mNativeAwSettings);
+    @CalledByNative
+    private void populateWebPreferences(long webPrefsPtr) {
+        synchronized (mAwSettingsLock) {
+            nativePopulateWebPreferencesLocked(mNativeAwSettings, webPrefsPtr);
         }
     }
 
+    private void updateWebkitPreferencesOnUiThreadLocked() {
+        assert mEventHandler.mHandler != null;
+        ThreadUtils.assertOnUiThread();
+        nativeUpdateWebkitPreferencesLocked(mNativeAwSettings);
+    }
+
     private native long nativeInit(long webContentsPtr);
 
     private native void nativeDestroy(long nativeAwSettings);
 
+    private native void nativePopulateWebPreferencesLocked(long nativeAwSettings, long webPrefsPtr);
+
     private native void nativeResetScrollAndScaleState(long nativeAwSettings);
 
     private native void nativeUpdateEverythingLocked(long nativeAwSettings);
diff --git a/android_webview/native/aw_settings.cc b/android_webview/native/aw_settings.cc
index 0a1312d..f3ade86 100644
--- a/android_webview/native/aw_settings.cc
+++ b/android_webview/native/aw_settings.cc
@@ -183,14 +183,20 @@
 void AwSettings::PopulateWebPreferences(WebPreferences* web_prefs) {
   JNIEnv* env = base::android::AttachCurrentThread();
   CHECK(env);
-
-  AwRenderViewHostExt* render_view_host_ext = GetAwRenderViewHostExt();
-  if (!render_view_host_ext) return;
-
   ScopedJavaLocalRef<jobject> scoped_obj = aw_settings_.get(env);
   jobject obj = scoped_obj.obj();
   if (!obj) return;
+  // Grab the lock and call PopulateWebPreferencesLocked.
+  Java_AwSettings_populateWebPreferences(
+      env, obj, reinterpret_cast<jlong>(web_prefs));
+}
 
+void AwSettings::PopulateWebPreferencesLocked(
+    JNIEnv* env, jobject obj, jlong web_prefs_ptr) {
+  AwRenderViewHostExt* render_view_host_ext = GetAwRenderViewHostExt();
+  if (!render_view_host_ext) return;
+
+  WebPreferences* web_prefs = reinterpret_cast<WebPreferences*>(web_prefs_ptr);
   PopulateFixedPreferences(web_prefs);
 
   web_prefs->text_autosizing_enabled =
@@ -282,9 +288,12 @@
       Java_AwSettings_getDatabaseEnabledLocked(env, obj);
 
   web_prefs->wide_viewport_quirk = true;
-  web_prefs->double_tap_to_zoom_enabled = web_prefs->use_wide_viewport =
+  web_prefs->use_wide_viewport =
       Java_AwSettings_getUseWideViewportLocked(env, obj);
 
+  web_prefs->double_tap_to_zoom_enabled =
+      Java_AwSettings_supportsDoubleTapZoomLocked(env, obj);
+
   web_prefs->initialize_at_minimum_page_scale =
       Java_AwSettings_getLoadWithOverviewModeLocked(env, obj);
 
diff --git a/android_webview/native/aw_settings.h b/android_webview/native/aw_settings.h
index 12a2c0a..ba48877 100644
--- a/android_webview/native/aw_settings.h
+++ b/android_webview/native/aw_settings.h
@@ -28,6 +28,7 @@
   // Called from Java. Methods with "Locked" suffix require that the settings
   // access lock is held during their execution.
   void Destroy(JNIEnv* env, jobject obj);
+  void PopulateWebPreferencesLocked(JNIEnv* env, jobject obj, jlong web_prefs);
   void ResetScrollAndScaleState(JNIEnv* env, jobject obj);
   void UpdateEverythingLocked(JNIEnv* env, jobject obj);
   void UpdateInitialPageScaleLocked(JNIEnv* env, jobject obj);
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc
index cd3a580..4baff1f 100644
--- a/ash/accelerators/accelerator_table.cc
+++ b/ash/accelerators/accelerator_table.cc
@@ -376,7 +376,6 @@
   CYCLE_FORWARD_MRU,
   CYCLE_LINEAR,
   DISABLE_CAPS_LOCK,
-  EXIT,
   KEYBOARD_BRIGHTNESS_DOWN,
   KEYBOARD_BRIGHTNESS_UP,
   MAGNIFY_SCREEN_ZOOM_IN,  // Control+F7
diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE
index 2d66fc5..da046b4 100644
--- a/build/util/LASTCHANGE
+++ b/build/util/LASTCHANGE
@@ -1 +1 @@
-LASTCHANGE=247552
+LASTCHANGE=248643
diff --git a/build/util/LASTCHANGE.blink b/build/util/LASTCHANGE.blink
index 195845e..d1bae50 100644
--- a/build/util/LASTCHANGE.blink
+++ b/build/util/LASTCHANGE.blink
@@ -1 +1 @@
-LASTCHANGE=165890
+LASTCHANGE=166343
diff --git a/chrome/VERSION b/chrome/VERSION
index 05b6ac3..a755828 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=33
 MINOR=0
 BUILD=1750
-PATCH=58
+PATCH=68
diff --git a/chrome/browser/browser_process_platform_part_aurawin.cc b/chrome/browser/browser_process_platform_part_aurawin.cc
index 99ec0ea..d1a00bc 100644
--- a/chrome/browser/browser_process_platform_part_aurawin.cc
+++ b/chrome/browser/browser_process_platform_part_aurawin.cc
@@ -6,13 +6,27 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/prefs/pref_service.h"
 #include "base/process/kill.h"
 #include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/first_run/upgrade_util.h"
+#include "chrome/browser/first_run/upgrade_util_win.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_service.h"
+
+#include "ui/aura/remote_root_window_host_win.h"
 
 BrowserProcessPlatformPart::BrowserProcessPlatformPart() {
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+    // Tell metro viewer to close when we are shutting down.
+    registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
+                   content::NotificationService::AllSources());
+  }
 }
 
 BrowserProcessPlatformPart::~BrowserProcessPlatformPart() {
@@ -43,3 +57,27 @@
     }
   }
 }
+
+void BrowserProcessPlatformPart::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+
+  DCHECK(type == chrome::NOTIFICATION_APP_TERMINATING);
+  PrefService* pref_service = g_browser_process->local_state();
+  bool is_relaunch = pref_service->GetBoolean(prefs::kWasRestarted);
+  if (is_relaunch) {
+    upgrade_util::RelaunchMode mode =
+        upgrade_util::RelaunchModeStringToEnum(
+            pref_service->GetString(prefs::kRelaunchMode));
+    if (metro_viewer_process_host_.get()) {
+      if (mode == upgrade_util::RELAUNCH_MODE_DESKTOP) {
+        // Metro -> Desktop
+        chrome::ActivateDesktopHelper(chrome::ASH_TERMINATE);
+      } else {
+        // Metro -> Metro
+        aura::HandleMetroExit();
+      }
+    }
+  }
+}
diff --git a/chrome/browser/browser_process_platform_part_aurawin.h b/chrome/browser/browser_process_platform_part_aurawin.h
index 8c2b96d..4d202dd 100644
--- a/chrome/browser/browser_process_platform_part_aurawin.h
+++ b/chrome/browser/browser_process_platform_part_aurawin.h
@@ -8,10 +8,13 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/browser_process_platform_part_base.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 
 class ChromeMetroViewerProcessHost;
 
-class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase {
+class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase,
+                                   public content::NotificationObserver {
  public:
   BrowserProcessPlatformPart();
   virtual ~BrowserProcessPlatformPart();
@@ -23,11 +26,18 @@
   virtual void PlatformSpecificCommandLineProcessing(
       const CommandLine& command_line) OVERRIDE;
 
+  // content::NotificationObserver method:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
  private:
   // Hosts the channel for the Windows 8 metro viewer process which runs in
   // the ASH environment.
   scoped_ptr<ChromeMetroViewerProcessHost> metro_viewer_process_host_;
 
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPart);
 };
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 5023718..172aa39 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -147,6 +147,7 @@
 #include "webkit/common/webpreferences.h"
 
 #if defined(OS_WIN)
+#include "base/win/windows_version.h"
 #include "chrome/browser/chrome_browser_main_win.h"
 #include "sandbox/win/src/sandbox_policy.h"
 #elif defined(OS_MACOSX)
@@ -1432,6 +1433,11 @@
           chromeos::switches::kLoginProfile, login_profile);
 #endif
 
+#if defined(OS_WIN)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    command_line->AppendSwitch(switches::kEnablePinch);
+#endif
+
 #if defined(ENABLE_WEBRTC)
     if (VersionInfo::GetChannel() <= VersionInfo::CHANNEL_DEV) {
       static const char* const kWebRtcDevSwitchNames[] = {
diff --git a/chrome/browser/chrome_plugin_browsertest.cc b/chrome/browser/chrome_plugin_browsertest.cc
index 4cddad3..4729940 100644
--- a/chrome/browser/chrome_plugin_browsertest.cc
+++ b/chrome/browser/chrome_plugin_browsertest.cc
@@ -10,17 +10,21 @@
 #include "base/file_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
+#include "base/prefs/pref_service.h"
 #include "base/process/kill.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_child_process_host_iterator.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/plugin_service.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/process_type.h"
@@ -29,6 +33,12 @@
 #include "content/public/test/test_utils.h"
 #include "net/base/net_util.h"
 
+#if defined(OS_WIN)
+#include "content/public/browser/web_contents_view.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#endif
+
 using content::BrowserThread;
 
 namespace {
@@ -262,3 +272,67 @@
     ASSERT_TRUE(j != plugins.size()) << "Didn't find " << expected[i];
   }
 }
+
+#if defined(OS_WIN)
+
+namespace {
+
+BOOL CALLBACK EnumerateChildren(HWND hwnd, LPARAM l_param) {
+  HWND* child = reinterpret_cast<HWND*>(l_param);
+  *child = hwnd;
+  // The first child window is the plugin, then its children. So stop
+  // enumerating after the first callback.
+  return FALSE;
+}
+
+}
+
+// Test that if a background tab loads an NPAPI plugin, they are displayed after
+// switching to that page.  http://crbug.com/335900
+IN_PROC_BROWSER_TEST_F(ChromePluginTest, WindowedNPAPIPluginHidden) {
+  browser()->profile()->GetPrefs()->SetBoolean(prefs::kPluginsAlwaysAuthorize,
+                                               true);
+
+  // First load the page in the background and wait for the NPAPI plugin's
+  // window to be created.
+  GURL url = ui_test_utils::GetTestUrl(
+      base::FilePath(),
+      base::FilePath().AppendASCII("windowed_npapi_plugin.html"));
+
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), url, NEW_BACKGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  // We create a third window just to trigger the second one to update its
+  // constrained window list. Normally this would be triggered by the status bar
+  // animation closing after the user middle clicked a link.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), GURL("about:blank"), NEW_BACKGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+
+  base::string16 expected_title(base::ASCIIToUTF16("created"));
+  content::WebContents* tab =
+      browser()->tab_strip_model()->GetWebContentsAt(1);
+  if (tab->GetTitle() != expected_title) {
+    content::TitleWatcher title_watcher(tab, expected_title);
+    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+  }
+
+  // Now activate the tab and verify that the plugin painted.
+  browser()->tab_strip_model()->ActivateTabAt(1, true);
+
+  base::string16 expected_title2(base::ASCIIToUTF16("shown"));
+  content::TitleWatcher title_watcher2(tab, expected_title2);
+  EXPECT_EQ(expected_title2, title_watcher2.WaitAndGetTitle());
+
+  HWND child = NULL;
+  HWND hwnd = tab->GetView()->GetNativeView()->GetDispatcher()->host()->
+      GetAcceleratedWidget();
+  EnumChildWindows(hwnd, EnumerateChildren,reinterpret_cast<LPARAM>(&child));
+
+  RECT region;
+  int result = GetWindowRgnBox(child, &region);
+  ASSERT_NE(result, NULLREGION);
+}
+
+#endif
diff --git a/chrome/browser/component_updater/background_downloader_win.cc b/chrome/browser/component_updater/background_downloader_win.cc
index 781fd8a..48eebb0 100644
--- a/chrome/browser/component_updater/background_downloader_win.cc
+++ b/chrome/browser/component_updater/background_downloader_win.cc
@@ -193,6 +193,33 @@
   return hr;
 }
 
+// Returns the number of bytes downloaded and bytes to download for all files
+// in the job. If the values are not known or if an error has occurred,
+// a value of -1 is reported.
+HRESULT GetJobByteCount(IBackgroundCopyJob* job,
+                        int64* bytes_downloaded,
+                        int64* bytes_total) {
+  *bytes_downloaded = -1;
+  *bytes_total = -1;
+
+  if (!job)
+    return E_FAIL;
+
+  BG_JOB_PROGRESS job_progress = {0};
+  HRESULT hr = job->GetProgress(&job_progress);
+  if (FAILED(hr))
+    return hr;
+
+  if (job_progress.BytesTransferred <= kint64max)
+    *bytes_downloaded = job_progress.BytesTransferred;
+
+  if (job_progress.BytesTotal <= kint64max &&
+      job_progress.BytesTotal != BG_SIZE_UNKNOWN)
+    *bytes_total = job_progress.BytesTotal;
+
+  return S_OK;
+}
+
 HRESULT GetJobDescription(IBackgroundCopyJob* job, const base::string16* name) {
   ScopedCoMem<char16> description;
   return job->GetDescription(&description);
@@ -478,19 +505,31 @@
     download_end_time >= download_start_time_ ?
     download_end_time - download_start_time_ : base::TimeDelta();
 
-  base::FilePath response;
-  BG_FILE_PROGRESS progress = {0};
+  int64 bytes_downloaded = -1;
+  int64 bytes_total = -1;
+  GetJobByteCount(job_, &bytes_downloaded, &bytes_total);
 
+  base::FilePath response;
   if (SUCCEEDED(error)) {
     DCHECK(job_);
     std::vector<ScopedComPtr<IBackgroundCopyFile> > files;
     GetFilesInJob(job_, &files);
     DCHECK(files.size() == 1);
     base::string16 local_name;
+    BG_FILE_PROGRESS progress = {0};
     HRESULT hr = GetJobFileProperties(files[0], &local_name, NULL, &progress);
     if (SUCCEEDED(hr)) {
+      // Sanity check the post-conditions of a successful download, including
+      // the file and job invariants. The byte counts for a job and its file
+      // must match as a job only contains one file.
       DCHECK(progress.Completed);
+      DCHECK(bytes_downloaded == static_cast<int64>(progress.BytesTransferred));
+      DCHECK(bytes_total == static_cast<int64>(progress.BytesTotal));
       response = base::FilePath(local_name);
+      if (progress.BytesTransferred <= kint64max)
+        bytes_downloaded = progress.BytesTransferred;
+      if (progress.BytesTotal <= kint64max)
+        bytes_total = progress.BytesTotal;
     } else {
       error = hr;
     }
@@ -508,12 +547,14 @@
   const bool is_handled = SUCCEEDED(error) ||
                           IsHttpServerError(GetHttpStatusFromBitsError(error));
 
+  const int error_to_report = SUCCEEDED(error) ? 0 : error;
+
   DownloadMetrics download_metrics;
   download_metrics.url = url();
   download_metrics.downloader = DownloadMetrics::kBits;
-  download_metrics.error = SUCCEEDED(error) ? 0 : error;
-  download_metrics.bytes_downloaded = progress.BytesTransferred;
-  download_metrics.bytes_total = progress.BytesTotal;
+  download_metrics.error = error_to_report;
+  download_metrics.bytes_downloaded = bytes_downloaded;
+  download_metrics.bytes_total = bytes_total;
   download_metrics.download_time_ms = download_time.InMilliseconds();
 
   // Clean up stale jobs before invoking the callback.
@@ -522,7 +563,7 @@
   bits_manager_ = NULL;
 
   Result result;
-  result.error = error;
+  result.error = error_to_report;
   result.response = response;
   BrowserThread::PostTask(
         BrowserThread::UI,
diff --git a/chrome/browser/component_updater/component_updater_ping_manager.cc b/chrome/browser/component_updater/component_updater_ping_manager.cc
index e16e6e3..c283ed0 100644
--- a/chrome/browser/component_updater/component_updater_ping_manager.cc
+++ b/chrome/browser/component_updater/component_updater_ping_manager.cc
@@ -109,14 +109,17 @@
     if (metrics.error)
       StringAppendF(&event, " errorcode=\"%d\"", metrics.error);
     StringAppendF(&event, " url=\"%s\"", metrics.url.spec().c_str());
-    if (metrics.bytes_downloaded) {
+
+    // -1 means that the  byte counts are not known.
+    if (metrics.bytes_downloaded != -1) {
       StringAppendF(&event, " downloaded=\"%s\"",
-                    base::Uint64ToString(metrics.bytes_downloaded).c_str());
+                    base::Int64ToString(metrics.bytes_downloaded).c_str());
     }
-    if (metrics.bytes_total) {
+    if (metrics.bytes_total != -1) {
       StringAppendF(&event, " total=\"%s\"",
-                    base::Uint64ToString(metrics.bytes_total).c_str());
+                    base::Int64ToString(metrics.bytes_total).c_str());
     }
+
     if (metrics.download_time_ms) {
       StringAppendF(&event, " download_time_ms=\"%s\"",
                     base::Uint64ToString(metrics.download_time_ms).c_str());
diff --git a/chrome/browser/component_updater/crx_downloader.cc b/chrome/browser/component_updater/crx_downloader.cc
index 606c2ca..535ffbe 100644
--- a/chrome/browser/component_updater/crx_downloader.cc
+++ b/chrome/browser/component_updater/crx_downloader.cc
@@ -19,8 +19,8 @@
 CrxDownloader::DownloadMetrics::DownloadMetrics()
     : downloader(kNone),
       error(0),
-      bytes_downloaded(0),
-      bytes_total(0),
+      bytes_downloaded(-1),
+      bytes_total(-1),
       download_time_ms(0) {}
 
 // On Windows, the first downloader in the chain is a background downloader,
diff --git a/chrome/browser/component_updater/crx_downloader.h b/chrome/browser/component_updater/crx_downloader.h
index 029f380..408290c 100644
--- a/chrome/browser/component_updater/crx_downloader.h
+++ b/chrome/browser/component_updater/crx_downloader.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_COMPONENT_UPDATER_CRX_DOWNLOADER_H_
 
 #include <vector>
+
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
@@ -47,8 +48,8 @@
 
     int error;
 
-    uint64 bytes_downloaded;
-    uint64 bytes_total;
+    int64 bytes_downloaded;   // -1 means that the byte count is unknown.
+    int64 bytes_total;
 
     uint64 download_time_ms;
   };
diff --git a/chrome/browser/component_updater/url_fetcher_downloader.cc b/chrome/browser/component_updater/url_fetcher_downloader.cc
index b2d16da..4d2f0e2 100644
--- a/chrome/browser/component_updater/url_fetcher_downloader.cc
+++ b/chrome/browser/component_updater/url_fetcher_downloader.cc
@@ -21,7 +21,9 @@
     const DownloadCallback& download_callback)
     : CrxDownloader(successor.Pass(), download_callback),
       context_getter_(context_getter),
-      task_runner_(task_runner) {
+      task_runner_(task_runner),
+      downloaded_bytes_(-1),
+      total_bytes_(-1) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
@@ -44,6 +46,9 @@
   url_fetcher_->Start();
 
   download_start_time_ = base::Time::Now();
+
+  downloaded_bytes_ = -1;
+  total_bytes_ = -1;
 }
 
 void UrlFetcherDownloader::OnURLFetchComplete(const net::URLFetcher* source) {
@@ -66,15 +71,25 @@
     source->GetResponseAsFilePath(true, &result.response);
   }
 
-  // The URLFetcher does not provide accessors for the number of bytes yet.
   DownloadMetrics download_metrics;
   download_metrics.url = url();
   download_metrics.downloader = DownloadMetrics::kUrlFetcher;
   download_metrics.error = fetch_error;
+  download_metrics.bytes_downloaded = downloaded_bytes_;
+  download_metrics.bytes_total = total_bytes_;
   download_metrics.download_time_ms = download_time.InMilliseconds();
 
   CrxDownloader::OnDownloadComplete(is_handled, result, download_metrics);
 }
 
+void UrlFetcherDownloader::OnURLFetchDownloadProgress(
+    const net::URLFetcher* source,
+    int64 current,
+    int64 total) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  downloaded_bytes_ = current;
+  total_bytes_ = total;
+}
+
 }  // namespace component_updater
 
diff --git a/chrome/browser/component_updater/url_fetcher_downloader.h b/chrome/browser/component_updater/url_fetcher_downloader.h
index 622758d..37272c7 100644
--- a/chrome/browser/component_updater/url_fetcher_downloader.h
+++ b/chrome/browser/component_updater/url_fetcher_downloader.h
@@ -36,13 +36,18 @@
 
   // Overrides for URLFetcherDelegate.
   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
-
+  virtual void OnURLFetchDownloadProgress(const net::URLFetcher* source,
+                                          int64 current,
+                                          int64 total) OVERRIDE;
   scoped_ptr<net::URLFetcher> url_fetcher_;
   net::URLRequestContextGetter* context_getter_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   base::Time download_start_time_;
 
+  int64 downloaded_bytes_;
+  int64 total_bytes_;
+
   DISALLOW_COPY_AND_ASSIGN(UrlFetcherDownloader);
 };
 
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id.cc b/chrome/browser/extensions/api/music_manager_private/device_id.cc
index df453bd..1bc87f5 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id.cc
@@ -12,6 +12,8 @@
 
 namespace {
 
+using extensions::api::DeviceId;
+
 // Compute HMAC-SHA256(|key|, |text|) as a string.
 bool ComputeHmacSha256(const std::string& key,
                        const std::string& text,
@@ -28,18 +30,18 @@
   return result;
 }
 
-void GetMachineIdCallback(const std::string& extension_id,
-                          const extensions::api::DeviceId::IdCallback& callback,
-                          const std::string& machine_id) {
+void GetRawDeviceIdCallback(const std::string& extension_id,
+                            const DeviceId::IdCallback& callback,
+                            const std::string& raw_device_id) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
-  if (machine_id.empty()) {
+  if (raw_device_id.empty()) {
     callback.Run("");
     return;
   }
 
   std::string device_id;
-  if (!ComputeHmacSha256(machine_id, extension_id, &device_id)) {
+  if (!ComputeHmacSha256(raw_device_id, extension_id, &device_id)) {
     DLOG(ERROR) << "Error while computing HMAC-SHA256 of device id.";
     callback.Run("");
     return;
@@ -47,12 +49,134 @@
   callback.Run(device_id);
 }
 
+bool IsValidMacAddressImpl(const void* bytes, size_t size) {
+  const size_t MAC_LENGTH = 6;
+  const size_t OUI_LENGTH = 3;
+  struct InvalidMacEntry {
+      size_t size;
+      unsigned char address[MAC_LENGTH];
+  };
+
+  // VPN, virtualization, tethering, bluetooth, etc.
+  static InvalidMacEntry invalidAddresses[] = {
+    // Empty address
+    {MAC_LENGTH, {0, 0, 0, 0, 0, 0}},
+    // VMware
+    {OUI_LENGTH, {0x00, 0x50, 0x56}},
+    {OUI_LENGTH, {0x00, 0x05, 0x69}},
+    {OUI_LENGTH, {0x00, 0x0c, 0x29}},
+    {OUI_LENGTH, {0x00, 0x1c, 0x14}},
+    // VirtualBox
+    {OUI_LENGTH, {0x08, 0x00, 0x27}},
+    // PdaNet
+    {MAC_LENGTH, {0x00, 0x26, 0x37, 0xbd, 0x39, 0x42}},
+    // Cisco AnyConnect VPN
+    {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
+    // Marvell sometimes uses this as a dummy address
+    {MAC_LENGTH, {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
+    // Apple uses this across machines for Bluetooth ethernet adapters.
+    {MAC_LENGTH-1, {0x65, 0x90, 0x07, 0x42, 0xf1}},
+    // Juniper uses this for their Virtual Adapter, the other 4 bytes are
+    // reassigned at every boot. 00-ff-xx is not assigned to anyone.
+    {2, {0x00, 0xff}},
+    // T-Mobile Wireless Ethernet
+    {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
+    // Generic Bluetooth device
+    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x3d, 0x0a, 0x57}},
+    // RAS Async Adapter
+    {MAC_LENGTH, {0x20, 0x41, 0x53, 0x59, 0x4e, 0xff}},
+    // Qualcomm USB ethernet adapter
+    {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
+    // Windows VPN
+    {MAC_LENGTH, {0x00, 0x53, 0x45, 0x00, 0x00, 0x00}},
+    // Bluetooth
+    {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x08, 0x30}},
+    {MAC_LENGTH, {0x00, 0x1b, 0x10, 0x00, 0x2a, 0xec}},
+    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x15, 0xa3, 0x10}},
+    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x07, 0xC6, 0x5A}},
+    {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0x00}},
+    {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0xdd}},
+    // Ceton TV tuner
+    {MAC_LENGTH, {0x00, 0x22, 0x2c, 0xff, 0xff, 0xff}},
+    // Check Point VPN
+    {MAC_LENGTH, {0x54, 0x55, 0x43, 0x44, 0x52, 0x09}},
+    {MAC_LENGTH, {0x54, 0xEF, 0x14, 0x71, 0xE4, 0x0E}},
+    {MAC_LENGTH, {0x54, 0xBA, 0xC6, 0xFF, 0x74, 0x10}},
+    // Cisco VPN
+    {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
+    // Cisco VPN
+    {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x78, 0x00}},
+    // Intel USB cell modem
+    {MAC_LENGTH, {0x00, 0x1e, 0x10, 0x1f, 0x00, 0x01}},
+    // Microsoft tethering
+    {MAC_LENGTH, {0x80, 0x00, 0x60, 0x0f, 0xe8, 0x00}},
+    // Nortel VPN
+    {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x42, 0x00}},
+    // AEP VPN
+    {MAC_LENGTH, {0x00, 0x30, 0x70, 0x00, 0x00, 0x01}},
+    // Positive VPN
+    {MAC_LENGTH, {0x00, 0x02, 0x03, 0x04, 0x05, 0x06}},
+    // Bluetooth
+    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0B, 0x13, 0xC0}},
+    // Kerio Virtual Network Adapter
+    {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x4f, 0x53}},
+    // Sierra Wireless cell modems.
+    {OUI_LENGTH, {0x00, 0xA0, 0xD5}},
+    // FRITZ!web DSL
+    {MAC_LENGTH, {0x00, 0x04, 0x0E, 0xFF, 0xFF, 0xFF}},
+    // VirtualPC
+    {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
+    // Bluetooth
+    {MAC_LENGTH, {0x00, 0x1F, 0x81, 0x00, 0x01, 0x00}},
+    {MAC_LENGTH, {0x00, 0x30, 0x91, 0x10, 0x00, 0x26}},
+    {MAC_LENGTH, {0x00, 0x25, 0x00, 0x5A, 0xC3, 0xD0}},
+    {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0C, 0xBF, 0xEB}},
+    // Huawei cell modem
+    {MAC_LENGTH, {0x58, 0x2C, 0x80, 0x13, 0x92, 0x63}},
+    // Fortinet VPN
+    {OUI_LENGTH, {0x00, 0x09, 0x0F}},
+    // Realtek
+    {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x30}},
+    // Other rare dupes.
+    {MAC_LENGTH, {0x00, 0x11, 0xf5, 0x0d, 0x8a, 0xe8}}, // Atheros
+    {MAC_LENGTH, {0x00, 0x20, 0x07, 0x01, 0x16, 0x06}}, // Atheros
+    {MAC_LENGTH, {0x0d, 0x0b, 0x00, 0x00, 0xe0, 0x00}}, // Atheros
+    {MAC_LENGTH, {0x90, 0x4c, 0xe5, 0x0b, 0xc8, 0x8e}}, // Atheros
+    {MAC_LENGTH, {0x00, 0x1c, 0x23, 0x38, 0x49, 0xa4}}, // Broadcom
+    {MAC_LENGTH, {0x00, 0x12, 0x3f, 0x82, 0x7c, 0x32}}, // Broadcom
+    {MAC_LENGTH, {0x00, 0x11, 0x11, 0x32, 0xc3, 0x77}}, // Broadcom
+    {MAC_LENGTH, {0x00, 0x24, 0xd6, 0xae, 0x3e, 0x39}}, // Microsoft
+    {MAC_LENGTH, {0x00, 0x0f, 0xb0, 0x3a, 0xb4, 0x80}}, // Realtek
+    {MAC_LENGTH, {0x08, 0x10, 0x74, 0xa1, 0xda, 0x1b}}, // Realtek
+    {MAC_LENGTH, {0x00, 0x21, 0x9b, 0x2a, 0x0a, 0x9c}}, // Realtek
+  };
+
+  if (size != MAC_LENGTH) {
+    return false;
+  }
+
+  if (static_cast<const unsigned char *>(bytes)[0] & 0x02) {
+    // Locally administered.
+    return false;
+  }
+
+  // Note: Use ARRAYSIZE_UNSAFE() instead of arraysize() because InvalidMacEntry
+  // is declared inside this function.
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(invalidAddresses); ++i) {
+    size_t count = invalidAddresses[i].size;
+    if (memcmp(invalidAddresses[i].address, bytes, count) == 0) {
+        return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
 namespace extensions {
 namespace api {
 
-/* static */
+// static
 void DeviceId::GetDeviceId(const std::string& extension_id,
                            const IdCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -60,7 +184,12 @@
 
   // Forward call to platform specific implementation, then compute the HMAC
   // in the callback.
-  GetMachineId(base::Bind(&GetMachineIdCallback, extension_id, callback));
+  GetRawDeviceId(base::Bind(&GetRawDeviceIdCallback, extension_id, callback));
+}
+
+// static
+bool DeviceId::IsValidMacAddress(const void* bytes, size_t size) {
+  return IsValidMacAddressImpl(bytes, size);
 }
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id.h b/chrome/browser/extensions/api/music_manager_private/device_id.h
index c51d575..a9d6461 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id.h
+++ b/chrome/browser/extensions/api/music_manager_private/device_id.h
@@ -16,23 +16,30 @@
  public:
   typedef base::Callback<void(const std::string&)> IdCallback;
 
-  // Return a "device" identifier with the following characteristics:
-  // 1. The id is shared across users of a device.
-  // 2. The id is resilient to device reboots.
-  // 3. There is *some* way for the identifier to be reset (e.g. it can *not* be
-  //    the MAC address of the device's network card).
+  // Calls |callback| with a unique device identifier as argument. The device
+  // identifier has the following characteristics:
+  // 1. It is shared across users of a device.
+  // 2. It is resilient to device reboots.
+  // 3. It can be reset in *some* way by the user. In Particular, it can *not*
+  //    be based only on a MAC address of a physical device.
   // The specific implementation varies across platforms, some of them requiring
-  // a round trip to the IO or FILE thread. "callback" will always be called
-  // on the UI thread though (sometimes directly if the implementation allows
+  // a round trip to the IO or FILE thread. "callback" will always be called on
+  // the UI thread though (sometimes directly if the implementation allows
   // running on the UI thread).
-  // The returned value is HMAC_SHA256(machine_id, |extension_id|), so that the
-  // actual machine identifier value is not exposed directly to the caller.
+  // The returned value is HMAC_SHA256(|raw_device_id|, |extension_id|), so that
+  // the actual device identifier value is not exposed directly to the caller.
   static void GetDeviceId(const std::string& extension_id,
                           const IdCallback& callback);
 
  private:
   // Platform specific implementation of "raw" machine ID retrieval.
-  static void GetMachineId(const IdCallback& callback);
+  static void GetRawDeviceId(const IdCallback& callback);
+
+  // On some platforms, part of the machine ID is the MAC address. This function
+  // is shared across platforms to filter out MAC addresses that have been
+  // identified as invalid, i.e. not unique. For example, some VM hosts assign a
+  // new MAC addresses at each reboot.
+  static bool IsValidMacAddress(const void* bytes, size_t size);
 };
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc b/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
index a6b7962..f49e513 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
@@ -9,9 +9,8 @@
 namespace extensions {
 namespace api {
 
-// ChromeOS: Use the System Salt.
-/* static */
-void DeviceId::GetMachineId(const IdCallback& callback) {
+// static
+void DeviceId::GetRawDeviceId(const IdCallback& callback) {
   chromeos::SystemSaltGetter::Get()->GetSystemSalt(callback);
 }
 
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc b/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
index 9045ca2..265742e 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
@@ -4,27 +4,46 @@
 
 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
 
+#include <sys/socket.h>  // Must be included before ifaddrs.h.
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
 #include <map>
 
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace {
 
+using extensions::api::DeviceId;
+
+typedef base::Callback<bool(const void* bytes, size_t size)>
+    IsValidMacAddressCallback;
+
 const char kDiskByUuidDirectoryName[] = "/dev/disk/by-uuid";
 const char* kDeviceNames[] = { "sda1", "hda1", "dm-0" };
+// Fedora 15 uses biosdevname feature where Embedded ethernet uses the
+// "em" prefix and PCI cards use the p[0-9]c[0-9] format based on PCI
+// slot and card information.
+const char* kNetDeviceNamePrefixes[] = {
+   "eth", "em", "en", "wl", "ww", "p0", "p1", "p2", "p3", "p4", "p5", "p6",
+   "p7", "p8", "p9", "wlan"
+};
 
 // Map from device name to disk uuid
 typedef std::map<base::FilePath, base::FilePath> DiskEntries;
 
-void GetDiskUuid(const extensions::api::DeviceId::IdCallback& callback) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+std::string GetDiskUuid() {
+  base::ThreadRestrictions::AssertIOAllowed();
 
   DiskEntries disk_uuids;
-
   base::FileEnumerator files(base::FilePath(kDiskByUuidDirectoryName),
                              false,  // Recursive.
                              base::FileEnumerator::FILES);
@@ -67,10 +86,101 @@
     }
   }
 
+  return result;
+}
+
+class MacAddressProcessor {
+ public:
+  explicit MacAddressProcessor(
+      const IsValidMacAddressCallback& is_valid_mac_address)
+      : is_valid_mac_address_(is_valid_mac_address) {
+  }
+
+  bool ProcessInterface(struct ifaddrs *ifaddr,
+                        const char* prefixes[],
+                        size_t prefixes_count) {
+    const int MAC_LENGTH = 6;
+    struct ifreq ifinfo;
+
+    memset(&ifinfo, 0, sizeof(ifinfo));
+    strncpy(ifinfo.ifr_name, ifaddr->ifa_name, sizeof(ifinfo.ifr_name) - 1);
+
+    int sd = socket(AF_INET, SOCK_DGRAM, 0);
+    int result = ioctl(sd, SIOCGIFHWADDR, &ifinfo);
+    close(sd);
+
+    if (result != 0)
+      return true;
+
+    const char* mac_address =
+        static_cast<const char*>(ifinfo.ifr_hwaddr.sa_data);
+    if (!is_valid_mac_address_.Run(mac_address, MAC_LENGTH))
+      return true;
+
+    if (!IsValidPrefix(ifinfo.ifr_name, prefixes, prefixes_count))
+      return true;
+
+    // Got one!
+    found_mac_address_ =
+        StringToLowerASCII(base::HexEncode(mac_address, MAC_LENGTH));
+    return false;
+  }
+
+  std::string mac_address() const { return found_mac_address_; }
+
+ private:
+  bool IsValidPrefix(const char* name,
+                     const char* prefixes[],
+                     size_t prefixes_count) {
+    for (size_t i = 0; i < prefixes_count; i++) {
+      if (strncmp(prefixes[i], name, strlen(prefixes[i])) == 0)
+        return true;
+    }
+    return false;
+  }
+
+  const IsValidMacAddressCallback& is_valid_mac_address_;
+  std::string found_mac_address_;
+};
+
+std::string GetMacAddress(
+    const IsValidMacAddressCallback& is_valid_mac_address) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  struct ifaddrs* ifaddrs;
+  int rv = getifaddrs(&ifaddrs);
+  if (rv < 0) {
+    PLOG(ERROR) << "getifaddrs failed " << rv;
+    return "";
+  }
+
+  MacAddressProcessor processor(is_valid_mac_address);
+  for (struct ifaddrs* ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+    bool keep_going = processor.ProcessInterface(
+        ifa, kNetDeviceNamePrefixes, arraysize(kNetDeviceNamePrefixes));
+    if (!keep_going)
+      break;
+  }
+  freeifaddrs(ifaddrs);
+  return processor.mac_address();
+}
+
+void GetRawDeviceIdImpl(const IsValidMacAddressCallback& is_valid_mac_address,
+                        const DeviceId::IdCallback& callback) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  std::string disk_id = GetDiskUuid();
+  std::string mac_address = GetMacAddress(is_valid_mac_address);
+
+  std::string raw_device_id;
+  if (!mac_address.empty() && !disk_id.empty()) {
+    raw_device_id = mac_address + disk_id;
+  }
+
   content::BrowserThread::PostTask(
       content::BrowserThread::UI,
       FROM_HERE,
-      base::Bind(callback, result));
+      base::Bind(callback, raw_device_id));
 }
 
 }  // namespace
@@ -78,15 +188,16 @@
 namespace extensions {
 namespace api {
 
-// Linux: Look for disk uuid
-/* static */
-void DeviceId::GetMachineId(const IdCallback& callback) {
+// static
+void DeviceId::GetRawDeviceId(const IdCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(GetDiskUuid, callback));
+      base::Bind(GetRawDeviceIdImpl,
+          base::Bind(DeviceId::IsValidMacAddress),
+          callback));
 }
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc b/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
index e66c0e2..d9f1388 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
@@ -7,18 +7,31 @@
 #include <CoreFoundation/CoreFoundation.h>
 #include <DiskArbitration/DASession.h>
 #include <DiskArbitration/DADisk.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/network/IOEthernetController.h>
+#include <IOKit/network/IOEthernetInterface.h>
+#include <IOKit/network/IONetworkInterface.h>
 #include <sys/mount.h>
 
 #include "base/bind.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_ioobject.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace {
 
+using extensions::api::DeviceId;
+
 const char kRootDirectory[] = "/";
 
+typedef base::Callback<bool(const void* bytes, size_t size)>
+    IsValidMacAddressCallback;
+
 // Return the BSD name (e.g. '/dev/disk1') of the root directory by enumerating
 // through the mounted volumes .
 // Return "" if an error occured.
@@ -85,8 +98,8 @@
 }
 
 // Return Volume UUID property of disk mounted as "/".
-void GetVolumeUUID(const extensions::api::DeviceId::IdCallback& callback) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+std::string GetVolumeUUID() {
+  base::ThreadRestrictions::AssertIOAllowed();
 
   std::string result;
   std::string bsd_name = FindBSDNameOfSystemDisk();
@@ -94,26 +107,147 @@
     VLOG(4) << "BSD name of root directory: '" << bsd_name << "'";
     result = GetVolumeUUIDFromBSDName(bsd_name);
   }
+  return result;
+}
+
+class MacAddressProcessor {
+ public:
+  MacAddressProcessor(const IsValidMacAddressCallback& is_valid_mac_address)
+    : is_valid_mac_address_(is_valid_mac_address) {
+  }
+
+  bool ProcessNetworkController(io_object_t network_controller) {
+    // Use the MAC address of the first network interface.
+    bool keep_going = true;
+    base::ScopedCFTypeRef<CFDataRef> mac_address_data(
+        static_cast<CFDataRef>(
+            IORegistryEntryCreateCFProperty(network_controller,
+                                            CFSTR(kIOMACAddress),
+                                            kCFAllocatorDefault,
+                                            0)));
+    if (!mac_address_data)
+      return keep_going;
+
+    const UInt8* mac_address = CFDataGetBytePtr(mac_address_data);
+    size_t mac_address_size = CFDataGetLength(mac_address_data);
+    if (!is_valid_mac_address_.Run(mac_address, mac_address_size))
+      return keep_going;
+
+    std::string mac_address_string =
+        StringToLowerASCII(base::HexEncode(mac_address, mac_address_size));
+
+    base::ScopedCFTypeRef<CFStringRef> provider_class(
+        static_cast<CFStringRef>(
+            IORegistryEntryCreateCFProperty(network_controller,
+                                            CFSTR(kIOProviderClassKey),
+                                            kCFAllocatorDefault,
+                                            0)));
+    if (provider_class) {
+      if (CFStringCompare(provider_class, CFSTR("IOPCIDevice"), 0) ==
+              kCFCompareEqualTo) {
+        // MAC address from built-in network card is always best choice.
+        found_mac_address_ = mac_address_string;
+        keep_going = false;
+        return keep_going;
+      }
+    }
+
+    // Fall back to using non built-in card MAC address, but keep looking.
+    found_mac_address_ = mac_address_string;
+    return keep_going;
+  }
+
+  std::string mac_address() const { return found_mac_address_; }
+
+ private:
+  const IsValidMacAddressCallback& is_valid_mac_address_;
+  std::string found_mac_address_;
+};
+
+std::string GetMacAddress(
+    const IsValidMacAddressCallback& is_valid_mac_address) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  mach_port_t master_port;
+  kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &master_port);
+  if (kr != KERN_SUCCESS) {
+    LOG(ERROR) << "IOMasterPort failed: " << kr;
+    return "";
+  }
+
+  CFMutableDictionaryRef match_classes =
+      IOServiceMatching(kIOEthernetInterfaceClass);
+  if (!match_classes) {
+    LOG(ERROR) << "IOServiceMatching returned a NULL dictionary";
+    return "";
+  }
+
+  io_iterator_t iterator_ref;
+  kr = IOServiceGetMatchingServices(master_port,
+                                    match_classes,
+                                    &iterator_ref);
+  if (kr != KERN_SUCCESS) {
+    LOG(ERROR) << "IOServiceGetMatchingServices failed: " << kr;
+    return "";
+  }
+  base::mac::ScopedIOObject<io_iterator_t> iterator(iterator_ref);
+
+  MacAddressProcessor processor(is_valid_mac_address);
+  while (true) {
+    // Note: interface_service should not be released.
+    io_object_t interface_service = IOIteratorNext(iterator);
+    if (!interface_service)
+      break;
+
+    io_object_t controller_service_ref;
+    kr = IORegistryEntryGetParentEntry(interface_service,
+                                       kIOServicePlane,
+                                       &controller_service_ref);
+    if (kr != KERN_SUCCESS) {
+      LOG(ERROR) << "IORegistryEntryGetParentEntry failed: " << kr;
+    } else {
+      base::mac::ScopedIOObject<io_object_t> controller_service(
+          controller_service_ref);
+      bool keep_going = processor.ProcessNetworkController(controller_service);
+      if (!keep_going) {
+        break;
+      }
+    }
+  }
+  return processor.mac_address();
+}
+
+void GetRawDeviceIdImpl(const IsValidMacAddressCallback& is_valid_mac_address,
+                        const DeviceId::IdCallback& callback) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  std::string raw_device_id;
+  std::string mac_address = GetMacAddress(is_valid_mac_address);
+  std::string disk_id = GetVolumeUUID();
+  if (!mac_address.empty() && !disk_id.empty()) {
+    raw_device_id = mac_address + disk_id;
+  }
   content::BrowserThread::PostTask(
       content::BrowserThread::UI,
       FROM_HERE,
-      base::Bind(callback, result));
+      base::Bind(callback, raw_device_id));
 }
 
-}
+}  // namespace
 
 namespace extensions {
 namespace api {
 
-// MacOS: Return Volume UUID property of disk mounted as "/".
-/* static */
-void DeviceId::GetMachineId(const IdCallback& callback) {
+// static
+void DeviceId::GetRawDeviceId(const IdCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(GetVolumeUUID, callback));
+      base::Bind(GetRawDeviceIdImpl,
+          base::Bind(DeviceId::IsValidMacAddress),
+          callback));
 }
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_win.cc b/chrome/browser/extensions/api/music_manager_private/device_id_win.cc
index c37d0e6..1bbe3c2 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_win.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_win.cc
@@ -4,24 +4,220 @@
 
 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
 
+// Note: The order of header includes is important, as we want both pre-Vista
+// and post-Vista data structures to be defined, specifically
+// PIP_ADAPTER_ADDRESSES and PMIB_IF_ROW2.
+#include <winsock2.h>
+#include <ws2def.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/scoped_native_library.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/net_util.h"
+
 #if defined(ENABLE_RLZ)
 #include "rlz/lib/machine_id.h"
 #endif
 
+namespace {
+
+using extensions::api::DeviceId;
+
+typedef base::Callback<bool(const void* bytes, size_t size)>
+    IsValidMacAddressCallback;
+
+class MacAddressProcessor {
+ public:
+  MacAddressProcessor(const IsValidMacAddressCallback& is_valid_mac_address)
+    : is_valid_mac_address_(is_valid_mac_address),
+      found_index_(ULONG_MAX) {
+  }
+
+  // Iterate through the interfaces, looking for the valid MAC address with the
+  // lowest IfIndex.
+  void ProcessAdapterAddress(PIP_ADAPTER_ADDRESSES address) {
+    if (address->IfType == IF_TYPE_TUNNEL)
+      return;
+
+    ProcessPhysicalAddress(address->IfIndex,
+                           address->PhysicalAddress,
+                           address->PhysicalAddressLength);
+  }
+
+  void ProcessInterfaceRow(const PMIB_IF_ROW2 row) {
+    if (row->Type == IF_TYPE_TUNNEL ||
+        !row->InterfaceAndOperStatusFlags.HardwareInterface) {
+      return;
+    }
+
+    ProcessPhysicalAddress(row->InterfaceIndex,
+                           row->PhysicalAddress,
+                           row->PhysicalAddressLength);
+  }
+
+  std::string mac_address() const { return found_mac_address_; }
+
+ private:
+  void ProcessPhysicalAddress(NET_IFINDEX index,
+                              const void* bytes,
+                              size_t size) {
+    if (index >= found_index_ || size == 0)
+      return;
+
+    if (!is_valid_mac_address_.Run(bytes, size))
+      return;
+
+    found_mac_address_ = StringToLowerASCII(base::HexEncode(bytes, size));
+    found_index_ = index;
+  }
+
+  const IsValidMacAddressCallback& is_valid_mac_address_;
+  std::string found_mac_address_;
+  NET_IFINDEX found_index_;
+};
+
+std::string GetMacAddressFromGetAdaptersAddresses(
+    const IsValidMacAddressCallback& is_valid_mac_address) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // MS recommends a default size of 15k.
+  ULONG bufferSize = 15 * 1024;
+  // Disable as much as we can, since all we want is MAC addresses.
+  ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER |
+                GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST |
+                GAA_FLAG_SKIP_UNICAST;
+  std::vector<unsigned char> buffer(bufferSize);
+  PIP_ADAPTER_ADDRESSES adapterAddresses =
+      reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
+
+  DWORD result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
+                                      adapterAddresses, &bufferSize);
+  if (result == ERROR_BUFFER_OVERFLOW) {
+    buffer.resize(bufferSize);
+    adapterAddresses =
+        reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
+    result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
+                                  adapterAddresses, &bufferSize);
+  }
+
+  if (result != NO_ERROR) {
+    VLOG(ERROR) << "GetAdapatersAddresses failed with error " << result;
+    return "";
+  }
+
+  MacAddressProcessor processor(is_valid_mac_address);
+  for (; adapterAddresses != NULL; adapterAddresses = adapterAddresses->Next) {
+    processor.ProcessAdapterAddress(adapterAddresses);
+  }
+  return processor.mac_address();
+}
+
+std::string GetMacAddressFromGetIfTable2(
+    const IsValidMacAddressCallback& is_valid_mac_address) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // This is available on Vista+ only.
+  base::ScopedNativeLibrary library(base::FilePath(L"Iphlpapi.dll"));
+
+  typedef DWORD (NETIOAPI_API_ *GetIfTablePtr)(PMIB_IF_TABLE2*);
+  typedef void (NETIOAPI_API_ *FreeMibTablePtr)(PMIB_IF_TABLE2);
+
+  GetIfTablePtr getIfTable = reinterpret_cast<GetIfTablePtr>(
+      library.GetFunctionPointer("GetIfTable2"));
+  FreeMibTablePtr freeMibTablePtr = reinterpret_cast<FreeMibTablePtr>(
+      library.GetFunctionPointer("FreeMibTable"));
+  if (getIfTable == NULL || freeMibTablePtr == NULL) {
+    VLOG(ERROR) << "Could not get proc addresses for machine identifier.";
+    return "";
+  }
+
+  PMIB_IF_TABLE2  ifTable = NULL;
+  DWORD result = getIfTable(&ifTable);
+  if (result != NO_ERROR || ifTable == NULL) {
+    VLOG(ERROR) << "GetIfTable failed with error " << result;
+    return "";
+  }
+
+  MacAddressProcessor processor(is_valid_mac_address);
+  for (size_t i = 0; i < ifTable->NumEntries; i++) {
+    processor.ProcessInterfaceRow(&(ifTable->Table[i]));
+  }
+
+  if (ifTable != NULL) {
+    freeMibTablePtr(ifTable);
+    ifTable = NULL;
+  }
+  return processor.mac_address();
+}
+
+void GetMacAddress(const IsValidMacAddressCallback& is_valid_mac_address,
+                   const DeviceId::IdCallback& callback) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  std::string mac_address =
+      GetMacAddressFromGetAdaptersAddresses(is_valid_mac_address);
+  if (mac_address.empty())
+    mac_address = GetMacAddressFromGetIfTable2(is_valid_mac_address);
+
+  static bool error_logged = false;
+  if (mac_address.empty() && !error_logged) {
+    error_logged = true;
+    LOG(ERROR) << "Could not find appropriate MAC address.";
+  }
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(callback, mac_address));
+}
+
+std::string GetRlzMachineId() {
+#if defined(ENABLE_RLZ)
+  std::string machine_id;
+  if (!rlz_lib::GetMachineId(&machine_id))
+    return "";
+  return machine_id;
+#else
+  return "";
+#endif
+}
+
+void GetMacAddressCallback(const DeviceId::IdCallback& callback,
+                           const std::string& mac_address) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  std::string machine_id = GetRlzMachineId();
+  if (mac_address.empty() || machine_id.empty()) {
+    callback.Run("");
+    return;
+  }
+  callback.Run(mac_address + machine_id);
+}
+
+}  // namespace
+
 namespace extensions {
 namespace api {
 
-// Windows: Use RLZ implementation of GetMachineId.
-/* static */
-void DeviceId::GetMachineId(const IdCallback& callback) {
-#if defined(ENABLE_RLZ)
-  std::string result;
-  rlz_lib::GetMachineId(&result);
-  callback.Run(result);
-#else
-  // Not implemented if RLZ not defined.
-  callback.Run("");
-#endif
+// static
+void DeviceId::GetRawDeviceId(const IdCallback& callback) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(GetMacAddress,
+        base::Bind(DeviceId::IsValidMacAddress),
+        base::Bind(GetMacAddressCallback, callback)));
 }
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc b/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
index 1f9760a..9d4c4fd 100644
--- a/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
+++ b/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
@@ -12,8 +12,17 @@
 };
 
 IN_PROC_BROWSER_TEST_F(MusicManagerPrivateTest, DeviceIdValueReturned) {
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/music_manager_private/device_id_value_returned"))
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+  // Note: Some MacOS/Linux trybots seem to run under VMware, which assigns
+  //       MAC addresses that are blacklisted. We still want the test
+  //       to succeed in that case.
+  const char* custom_arg = "device_id_may_be_undefined";
+#else
+  const char* custom_arg = NULL;
+#endif
+  ASSERT_TRUE(RunPlatformAppTestWithArg(
+      "platform_apps/music_manager_private/device_id_value_returned",
+      custom_arg))
           << message_;
 }
 
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 1365e4a..f648657 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -427,6 +427,9 @@
   if (!extension.web_extent().MatchesURL(source_url))
     return false;
 
+  // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app
+  // entities have traditionally been treated as blessed extensions, for better
+  // or worse.
   Feature::Availability availability =
       ExtensionAPI::GetSharedInstance()->IsAvailable(
           function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT,
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 5853612..fdd3f87 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -226,7 +226,8 @@
         "onMessage",
         "onMessageExternal",
         "onRestartRequired",
-        "id",
+        // Note: no "id" here because this test method is used for hosted apps,
+        // which do have access to runtime.id.
     };
 
     // Turn the array into a JS array, which effectively gets eval()ed.
@@ -313,6 +314,25 @@
                                 connectable_with_tls_channel_id_manifest());
   }
 
+  const Extension* LoadChromiumHostedApp() {
+    const Extension* hosted_app =
+        LoadExtensionIntoDir(&hosted_app_dir_, base::StringPrintf(
+            "{"
+            "  \"name\": \"chromium_hosted_app\","
+            "  \"version\": \"1.0\","
+            "  \"manifest_version\": 2,"
+            "  \"app\": {"
+            "    \"urls\": [\"%s\"],"
+            "    \"launch\": {"
+            "      \"web_url\": \"%s\""
+            "    }\n"
+            "  }\n"
+            "}", chromium_org_url().spec().c_str(),
+                 chromium_org_url().spec().c_str()));
+    CHECK(hosted_app);
+    return hosted_app;
+  }
+
   void InitializeTestServer() {
     base::FilePath test_data;
     EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
@@ -392,6 +412,7 @@
   TestExtensionDir web_connectable_dir_;
   TestExtensionDir not_connectable_dir_;
   TestExtensionDir tls_channel_id_connectable_dir_;
+  TestExtensionDir hosted_app_dir_;
 };
 
 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, NotInstalled) {
@@ -903,5 +924,42 @@
           "});", receiver->id().c_str())));
 }
 
+// Tests that a hosted app on a connectable site doesn't interfere with the
+// connectability of that site.
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, HostedAppOnWebsite) {
+  InitializeTestServer();
+
+  LoadChromiumHostedApp();
+
+  // The presence of the hosted app shouldn't give the ability to send messages.
+  ui_test_utils::NavigateToURL(browser(), chromium_org_url());
+  EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(""));
+  EXPECT_FALSE(AreAnyNonWebApisDefined());
+
+  // Once a connectable extension is installed, it should.
+  const Extension* extension = LoadChromiumConnectableExtension();
+  EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id()));
+  EXPECT_FALSE(AreAnyNonWebApisDefined());
+}
+
+// Tests that an invalid extension ID specified in a hosted app does not crash
+// the hosted app's renderer.
+//
+// This is a regression test for http://crbug.com/326250#c12.
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
+                       InvalidExtensionIDFromHostedApp) {
+  InitializeTestServer();
+
+  // The presence of the chromium hosted app triggers this bug. The chromium
+  // connectable extension needs to be installed to set up the runtime bindings.
+  LoadChromiumHostedApp();
+  LoadChromiumConnectableExtension();
+
+  ui_test_utils::NavigateToURL(browser(), chromium_org_url());
+  EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR ,
+            CanConnectAndSendMessages("invalid"));
+}
+
 }  // namespace
+
 };  // namespace extensions
diff --git a/chrome/browser/lifetime/browser_close_manager.cc b/chrome/browser/lifetime/browser_close_manager.cc
index 0f46a01..13982f1 100644
--- a/chrome/browser/lifetime/browser_close_manager.cc
+++ b/chrome/browser/lifetime/browser_close_manager.cc
@@ -4,14 +4,11 @@
 
 #include "chrome/browser/lifetime/browser_close_manager.h"
 
-#include "base/prefs/pref_service.h"
 #include "chrome/browser/background/background_mode_manager.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_service_factory.h"
-#include "chrome/browser/first_run/upgrade_util.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_iterator.h"
@@ -20,14 +17,8 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/pref_names.h"
 #include "content/public/browser/web_contents.h"
 
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#include "chrome/browser/first_run/upgrade_util_win.h"
-#endif
-
 BrowserCloseManager::BrowserCloseManager() : current_browser_(NULL) {}
 
 BrowserCloseManager::~BrowserCloseManager() {}
@@ -169,17 +160,4 @@
       }
     }
   }
-
-#if defined(OS_WIN)
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
-    PrefService* pref_service = g_browser_process->local_state();
-    bool is_relaunch = pref_service->GetBoolean(prefs::kWasRestarted);
-    if (is_relaunch) {
-      upgrade_util::RelaunchMode mode = upgrade_util::RelaunchModeStringToEnum(
-          pref_service->GetString(prefs::kRelaunchMode));
-      if (mode == upgrade_util::RELAUNCH_MODE_DESKTOP)
-        chrome::ActivateDesktopHelper(chrome::ASH_TERMINATE);
-    }
-  }
-#endif
 }
diff --git a/chrome/browser/local_discovery/privet_http_impl.cc b/chrome/browser/local_discovery/privet_http_impl.cc
index b9de4fe..25ab5fc 100644
--- a/chrome/browser/local_discovery/privet_http_impl.cc
+++ b/chrome/browser/local_discovery/privet_http_impl.cc
@@ -22,10 +22,12 @@
 const char kPrivetRegisterActionArgName[] = "action";
 const char kPrivetRegisterUserArgName[] = "user";
 
-const char kPrivetURLKeyUser[] = "user";
-const char kPrivetURLKeyJobname[] = "jobname";
+const char kPrivetURLKeyUserName[] = "user_name";
+const char kPrivetURLKeyClientName[] = "client_name";
+const char kPrivetURLKeyJobname[] = "job_name";
 const char kPrivetURLKeyOffline[] = "offline";
 const char kPrivetURLValueOffline[] = "1";
+const char kPrivetURLValueClientName[] = "Chrome";
 
 const char kPrivetContentTypePDF[] = "application/pdf";
 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster";
@@ -463,9 +465,13 @@
 
   GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
 
+  url = net::AppendQueryParameter(url,
+                                  kPrivetURLKeyClientName,
+                                  kPrivetURLValueClientName);
+
   if (!user_.empty()) {
     url = net::AppendQueryParameter(url,
-                                    kPrivetURLKeyUser,
+                                    kPrivetURLKeyUserName,
                                     user_);
   }
 
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/local_discovery/privet_http_unittest.cc
index 67d8044..ec944d3 100644
--- a/chrome/browser/local_discovery/privet_http_unittest.cc
+++ b/chrome/browser/local_discovery/privet_http_unittest.cc
@@ -827,7 +827,8 @@
   // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
-           "user=sample%40gmail.com&jobname=Sample+job+name"),
+           "client_name=Chrome&user_name=sample%40gmail.com&"
+           "job_name=Sample+job+name"),
       "Sample print data",
       kSampleLocalPrintResponse));
 };
@@ -852,7 +853,8 @@
   // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
-           "user=sample%40gmail.com&jobname=Sample+job+name"),
+           "client_name=Chrome&user_name=sample%40gmail.com&"
+           "job_name=Sample+job+name"),
       "Sample print data",
       kSampleLocalPrintResponse));
 };
@@ -877,7 +879,8 @@
   // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndFilePath(
       GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
-           "user=sample%40gmail.com&jobname=Sample+job+name"),
+           "client_name=Chrome&user_name=sample%40gmail.com"
+           "&job_name=Sample+job+name"),
       base::FilePath(FILE_PATH_LITERAL("path/to/test.pdf")),
       kSampleLocalPrintResponse));
 };
@@ -908,7 +911,8 @@
   // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
-           "user=sample%40gmail.com&jobname=Sample+job+name&job_id=1234"),
+           "client_name=Chrome&user_name=sample%40gmail.com&"
+           "job_name=Sample+job+name&job_id=1234"),
       "Sample print data",
       kSampleLocalPrintResponse));
 };
@@ -937,7 +941,8 @@
   // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
-           "user=sample%40gmail.com&jobname=Sample+job+name&job_id=1234"),
+           "client_name=Chrome&user_name=sample%40gmail.com&"
+           "job_name=Sample+job+name&job_id=1234"),
       "sample/path/",
       kSampleInvalidDocumentTypeResponse));
 
@@ -945,7 +950,8 @@
 
   EXPECT_TRUE(SuccessfulResponseToURLAndFilePath(
       GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
-           "user=sample%40gmail.com&jobname=Sample+job+name&job_id=1234"),
+           "client_name=Chrome&user_name=sample%40gmail.com&"
+           "job_name=Sample+job+name&job_id=1234"),
       base::FilePath(FILE_PATH_LITERAL("sample/path/test.pdf")),
       kSampleLocalPrintResponse));
 };
@@ -973,7 +979,8 @@
 
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
-           "user=sample%40gmail.com&jobname=Sample+job+name&job_id=1234"),
+           "client_name=Chrome&user_name=sample%40gmail.com&"
+           "job_name=Sample+job+name&job_id=1234"),
       "Sample print data",
       kSampleErrorResponsePrinterBusy));
 
diff --git a/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.cc b/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.cc
index 85cb76a..968abf0 100644
--- a/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.cc
+++ b/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.cc
@@ -58,10 +58,9 @@
   // SPDY proxy, since otherwise a user's authentication token can be
   // sniffed by a malicious proxy that presents an appropriate challenge.
   const GURL origin_origin = origin.GetOrigin();
-  if (!(target == HttpAuth::AUTH_PROXY &&
-      std::find(authorized_spdyproxy_origins_.begin(),
-                authorized_spdyproxy_origins_.end(),
-                origin_origin) != authorized_spdyproxy_origins_.end())) {
+  if (!(std::find(authorized_spdyproxy_origins_.begin(),
+                  authorized_spdyproxy_origins_.end(),
+                  origin_origin) != authorized_spdyproxy_origins_.end())) {
     UMA_HISTOGRAM_COUNTS("Net.UnexpectedSpdyProxyAuth", 1);
     VLOG(1) << "SpdyProxy auth request with an unexpected config."
             << " origin: " << origin_origin.possibly_invalid_spec();
diff --git a/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy_unittest.cc b/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy_unittest.cc
index 55bb44e..3d0035c 100644
--- a/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy_unittest.cc
+++ b/chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy_unittest.cc
@@ -41,76 +41,70 @@
   // Verifies that challenge parsing is expected as described in individual
   // cases below.
   static const struct {
-    Error err1, err2;
-    const char* origin;
-    const char* challenge;
-    const char* username;
-    const char* sid;
+    Error err1,             // Expected response from hander creation
+          err2;             // Expected response from GenerateAuthToken
+    const char* origin;     // Origin for challenge
+    const char* challenge;  // Challenge string
     const char* expected_credentials;
   } tests[] = {
       // A well-formed challenge where a sid is provided produces a valid
-      // response header echoing the sid and ps token.
+      // response header echoing the sid and ps token, for either origin.
       { OK, OK,
         kValidOrigin,
         kValidChallenge,
-        "",
-        "sid-string",
         "SpdyProxy ps=\"1-2-3-4\", sid=\"sid-string\"",},
 
-      // A non-SSL origin returns ERR_UNSUPPORTED_AUTH_SCHEME.
+      { OK, OK,
+        kValidOrigin2,
+        kValidChallenge,
+        "SpdyProxy ps=\"1-2-3-4\", sid=\"sid-string\"",},
+
+      // An origin matching host but not scheme returns
+      // ERR_UNSUPPORTED_AUTH_SCHEME
       { ERR_UNSUPPORTED_AUTH_SCHEME, OK,
-        "http://www.proxy.com/", "", "", "", "",},
+        "http://www.proxy.com/", "", "",},
 
       // An SSL origin not matching the authorized origin returns
       // ERR_UNSUPPORTED_AUTH_SCHEME.
       { ERR_UNSUPPORTED_AUTH_SCHEME, OK,
-        "https://www.unconfigured.com/", "", "", "", "",},
+        "https://www.unconfigured.com/", "", "",},
 
       // Absent ps token yields ERR_INVALID_RESPONSE.
       { ERR_INVALID_RESPONSE, OK,
-        kValidOrigin, "SpdyProxy realm=\"SpdyProxy\"", "", "", "",},
+        kValidOrigin, "SpdyProxy realm=\"SpdyProxy\"", "",},
   };
-  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
-    GURL origin(tests[i].origin);
-    GURL authorized_origin(kValidOrigin);
-    std::vector<GURL> authorized_origins;
-    authorized_origins.push_back(authorized_origin);
-    HttpAuthHandlerSpdyProxy::Factory factory(authorized_origins);
-    scoped_ptr<HttpAuthHandler> spdyproxy;
-    EXPECT_EQ(tests[i].err1, factory.CreateAuthHandlerFromString(
-        tests[i].challenge, HttpAuth::AUTH_PROXY, origin, BoundNetLog(),
-        &spdyproxy));
-    if (tests[i].err1 != OK) {
-      continue;
-    }
-    AuthCredentials credentials(ASCIIToUTF16(tests[i].username),
-                                ASCIIToUTF16(tests[i].sid));
-    HttpRequestInfo request_info;
-    std::string auth_token;
-    int rv = spdyproxy->GenerateAuthToken(&credentials, &request_info,
-                                          CompletionCallback(), &auth_token);
-    EXPECT_EQ(tests[i].err2, rv);
-    if (tests[i].err2 != OK) {
-      continue;
-    }
-    EXPECT_STREQ(tests[i].expected_credentials, auth_token.c_str());
-  }
-}
 
-TEST(HttpAuthHandlerSpdyProxyTest, NonProxyAuthTypeFails) {
-  // Verifies that an authorization request fails if requested by an ordinary
-  // site. (i.e., HttpAuth::AUTH_SERVER)
-  GURL origin(kValidOrigin);
-  GURL accepted_origin(kValidOrigin);
-  GURL accepted_origin2(kValidOrigin2);
-  std::vector<GURL> accepted_origins;
-  accepted_origins.push_back(accepted_origin);
-  accepted_origins.push_back(accepted_origin2);
-  HttpAuthHandlerSpdyProxy::Factory factory(accepted_origins);
-  scoped_ptr<HttpAuthHandler> spdyproxy;
-  EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, factory.CreateAuthHandlerFromString(
-      kValidChallenge, HttpAuth::AUTH_SERVER, origin,
-      BoundNetLog(), &spdyproxy));
+  // Run each test case for both proxy and server auth.
+  HttpAuth::Target targets[] = { HttpAuth::AUTH_SERVER, HttpAuth::AUTH_PROXY };
+
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(targets); ++i) {
+    for (size_t j = 0; j < ARRAYSIZE_UNSAFE(tests); ++j) {
+      GURL origin(tests[j].origin);
+      GURL authorized_origin(kValidOrigin);
+      GURL authorized_origin2(kValidOrigin2);
+      std::vector<GURL> authorized_origins;
+      authorized_origins.push_back(authorized_origin);
+      authorized_origins.push_back(authorized_origin2);
+      HttpAuthHandlerSpdyProxy::Factory factory(authorized_origins);
+      scoped_ptr<HttpAuthHandler> spdyproxy;
+      EXPECT_EQ(tests[j].err1, factory.CreateAuthHandlerFromString(
+          tests[j].challenge, targets[i], origin, BoundNetLog(),
+          &spdyproxy));
+      if (tests[j].err1 != OK)
+        continue;
+      AuthCredentials credentials(ASCIIToUTF16(""),
+                                  ASCIIToUTF16("sid-string"));
+      HttpRequestInfo request_info;
+      std::string auth_token;
+      int rv = spdyproxy->GenerateAuthToken(&credentials, &request_info,
+                                            CompletionCallback(), &auth_token);
+      EXPECT_EQ(tests[j].err2, rv);
+      if (tests[i].err2 != OK)
+        continue;
+      EXPECT_STREQ(tests[i].expected_credentials, auth_token.c_str());
+    }
+  }
 }
 
 TEST(HttpAuthHandlerSpdyProxyTest, HandleAnotherChallenge) {
diff --git a/chrome/browser/resources/file_manager/foreground/js/file_manager.js b/chrome/browser/resources/file_manager/foreground/js/file_manager.js
index 25ab912..201a4f6 100644
--- a/chrome/browser/resources/file_manager/foreground/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/foreground/js/file_manager.js
@@ -3545,7 +3545,7 @@
         var onDirectoryChanged = function(event) {
           self.directoryModel_.removeEventListener('scan-completed',
                                                    onDirectoryChanged);
-          self.directoryModel_.selectEntry(entry.name);
+          self.directoryModel_.selectEntry(entry);
           openIt();
         };
         // changeDirectory() returns immediately. We should wait until the
diff --git a/chrome/browser/ui/views/apps/native_app_window_views.cc b/chrome/browser/ui/views/apps/native_app_window_views.cc
index 2cc7740..887557a 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/native_app_window_views.cc
@@ -11,6 +11,7 @@
 #include "base/path_service.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/favicon/favicon_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -294,9 +295,13 @@
   views::FocusManager* focus_manager = GetFocusManager();
   const std::map<ui::Accelerator, int>& accelerator_table =
       GetAcceleratorTable();
+  const bool is_kiosk_app_mode = chrome::IsRunningInForcedAppMode();
   for (std::map<ui::Accelerator, int>::const_iterator iter =
            accelerator_table.begin();
        iter != accelerator_table.end(); ++iter) {
+    if (is_kiosk_app_mode && !chrome::IsCommandAllowedInAppMode(iter->second))
+      continue;
+
     focus_manager->RegisterAccelerator(
         iter->first, ui::AcceleratorManager::kNormalPriority, this);
   }
diff --git a/chrome/browser/ui/views/color_chooser_aura.cc b/chrome/browser/ui/views/color_chooser_aura.cc
index d7bf7eb..33e9260 100644
--- a/chrome/browser/ui/views/color_chooser_aura.cc
+++ b/chrome/browser/ui/views/color_chooser_aura.cc
@@ -35,7 +35,7 @@
 }
 
 void ColorChooserAura::End() {
-  if (widget_ && widget_->IsVisible()) {
+  if (widget_) {
     view_->set_listener(NULL);
     widget_->Close();
     view_ = NULL;
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index f819c1d..90e79ee 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1671,7 +1671,7 @@
                 '../ppapi/tests/extensions/extensions.gyp:ppapi_tests_extensions_socket',
               ],
               'conditions': [
-                ['OS=="linux"', {
+                ['chromeos==1', {
                   'sources': [
                     '../third_party/liblouis/nacl_wrapper/liblouis_wrapper_browsertest.cc',
                   ],
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 62db5f7..681b3c6 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -4,6 +4,9 @@
 
 // See c/c/e/features/* to understand this file, in particular feature.h,
 // simple_feature.h, and base_feature_provider.h.
+//
+// Note that specifying "web_page", "blessed_web_page", or "all" as a context
+// type will require manually updating chrome/renderer/resources/dispatcher.cc.
 
 {
   "activityLogPrivate": {
@@ -22,7 +25,11 @@
     "channel": "stable",
     "extension_types": ["hosted_app", "extension", "legacy_packaged_app"],
     "contexts": [
-      "blessed_extension", "unblessed_extension", "content_script", "web_page"
+      "blessed_extension",
+      "unblessed_extension",
+      "content_script",
+      "web_page",
+      "blessed_web_page"
     ],
     "matches": [
       "http://*/*", "https://*/*", "chrome-extension://*/*", "file://*/*"
@@ -237,9 +244,7 @@
     "internal": true,
     "channel": "stable",
     "extension_types": ["platform_app", "extension"],
-    "contexts": [
-      "blessed_extension", "unblessed_extension", "content_script", "web_page"
-    ],
+    "contexts": "all",
     "matches": ["<all_urls>"]
   },
   "experimental.accessibility": {
@@ -527,6 +532,7 @@
   },
   "runtime.lastError": {
     "contexts": "all",
+    "extension_types": "all",
     "matches": ["<all_urls>"]
   },
   "runtime.onConnect": {
@@ -709,7 +715,7 @@
     // Hosted apps can use the webstore API from within a blessed context.
     "channel": "stable",
     "extension_types": ["hosted_app"],
-    "contexts": ["blessed_extension", "web_page"],
+    "contexts": ["blessed_web_page", "web_page"],
     // Any webpage can use the webstore API.
     "matches": ["http://*/*", "https://*/*"]
   },
diff --git a/chrome/common/extensions/features/simple_feature.cc b/chrome/common/extensions/features/simple_feature.cc
index b971ed6..01431ce 100644
--- a/chrome/common/extensions/features/simple_feature.cc
+++ b/chrome/common/extensions/features/simple_feature.cc
@@ -35,6 +35,7 @@
     contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT;
     contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT;
     contexts["web_page"] = Feature::WEB_PAGE_CONTEXT;
+    contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT;
 
     locations["component"] = Feature::COMPONENT_LOCATION;
 
@@ -197,6 +198,8 @@
       return "content script";
     case Feature::WEB_PAGE_CONTEXT:
       return "web page";
+    case Feature::BLESSED_WEB_PAGE_CONTEXT:
+      return "hosted app";
   }
   NOTREACHED();
   return "";
diff --git a/chrome/common/extensions/features/simple_feature_unittest.cc b/chrome/common/extensions/features/simple_feature_unittest.cc
index b2ea868..38ba4af 100644
--- a/chrome/common/extensions/features/simple_feature_unittest.cc
+++ b/chrome/common/extensions/features/simple_feature_unittest.cc
@@ -430,10 +430,11 @@
   contexts->Append(new base::StringValue("unblessed_extension"));
   contexts->Append(new base::StringValue("content_script"));
   contexts->Append(new base::StringValue("web_page"));
+  contexts->Append(new base::StringValue("blessed_web_page"));
   value->Set("contexts", contexts);
   scoped_ptr<SimpleFeature> feature(new SimpleFeature());
   feature->Parse(value.get());
-  EXPECT_EQ(4u, feature->GetContexts()->size());
+  EXPECT_EQ(5u, feature->GetContexts()->size());
   EXPECT_TRUE(
       feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT));
   EXPECT_TRUE(
@@ -442,6 +443,8 @@
       feature->GetContexts()->count(Feature::CONTENT_SCRIPT_CONTEXT));
   EXPECT_TRUE(
       feature->GetContexts()->count(Feature::WEB_PAGE_CONTEXT));
+  EXPECT_TRUE(
+      feature->GetContexts()->count(Feature::BLESSED_WEB_PAGE_CONTEXT));
 
   value->SetString("contexts", "all");
   scoped_ptr<SimpleFeature> feature2(new SimpleFeature());
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
index 844c981..b85b28f 100644
--- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
@@ -111,9 +111,7 @@
 
   // extensions::ManifestPermission overrides.
   virtual std::string name() const OVERRIDE {
-    return base::StringPrintf("%s.%s",
-                              manifest_keys::kBookmarkUI,
-                              manifest_keys::kHideBookmarkButton);
+    return manifest_keys::kSettingsOverride;
   }
 
   virtual std::string id() const OVERRIDE {
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 2fa016e..72e04f0 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -991,11 +991,22 @@
 bool ChromeContentRendererClient::AllowPopup() {
   extensions::ChromeV8Context* current_context =
       extension_dispatcher_->v8_context_set().GetCurrent();
-  return current_context && current_context->extension() &&
-      (current_context->context_type() ==
-       extensions::Feature::BLESSED_EXTENSION_CONTEXT ||
-       current_context->context_type() ==
-       extensions::Feature::CONTENT_SCRIPT_CONTEXT);
+  if (!current_context || !current_context->extension())
+    return false;
+  // See http://crbug.com/117446 for the subtlety of this check.
+  switch (current_context->context_type()) {
+    case extensions::Feature::UNSPECIFIED_CONTEXT:
+    case extensions::Feature::WEB_PAGE_CONTEXT:
+    case extensions::Feature::UNBLESSED_EXTENSION_CONTEXT:
+      return false;
+    case extensions::Feature::BLESSED_EXTENSION_CONTEXT:
+    case extensions::Feature::CONTENT_SCRIPT_CONTEXT:
+      return true;
+    case extensions::Feature::BLESSED_WEB_PAGE_CONTEXT:
+      return !current_context->web_frame()->parent();
+  }
+  NOTREACHED();
+  return false;
 }
 
 bool ChromeContentRendererClient::ShouldFork(WebFrame* frame,
diff --git a/chrome/renderer/extensions/chrome_v8_context.cc b/chrome/renderer/extensions/chrome_v8_context.cc
index bdeebd1..66d14c0 100644
--- a/chrome/renderer/extensions/chrome_v8_context.cc
+++ b/chrome/renderer/extensions/chrome_v8_context.cc
@@ -106,8 +106,17 @@
 
 Feature::Availability ChromeV8Context::GetAvailability(
     const std::string& api_name) {
+  // Hack: Hosted apps should have the availability of messaging APIs based on
+  // the URL of the page (which might have access depending on some extension
+  // with externally_connectable), not whether the app has access to messaging
+  // (which it won't).
+  const Extension* extension = extension_.get();
+  if (extension && extension->is_hosted_app() &&
+      (api_name == "runtime.connect" || api_name == "runtime.sendMessage")) {
+    extension = NULL;
+  }
   return ExtensionAPI::GetSharedInstance()->IsAvailable(api_name,
-                                                        extension_.get(),
+                                                        extension,
                                                         context_type_,
                                                         GetURL());
 }
@@ -123,6 +132,7 @@
     case Feature::UNBLESSED_EXTENSION_CONTEXT: return "UNBLESSED_EXTENSION";
     case Feature::CONTENT_SCRIPT_CONTEXT:      return "CONTENT_SCRIPT";
     case Feature::WEB_PAGE_CONTEXT:            return "WEB_PAGE";
+    case Feature::BLESSED_WEB_PAGE_CONTEXT:    return "BLESSED_WEB_PAGE";
   }
   NOTREACHED();
   return std::string();
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc
index 3a21e8e..86f3283 100644
--- a/chrome/renderer/extensions/dispatcher.cc
+++ b/chrome/renderer/extensions/dispatcher.cc
@@ -707,7 +707,8 @@
   // the same code regardless of context type.
   switch (context->context_type()) {
     case Feature::UNSPECIFIED_CONTEXT:
-    case Feature::WEB_PAGE_CONTEXT: {
+    case Feature::WEB_PAGE_CONTEXT:
+    case Feature::BLESSED_WEB_PAGE_CONTEXT: {
       // Web page context; it's too expensive to run the full bindings code.
       // Hard-code that the app and webstore APIs are available...
       RegisterBinding("app", context);
@@ -1113,7 +1114,8 @@
   }
 
   Feature::Context context_type = ClassifyJavaScriptContext(
-      extension_id, extension_group,
+      extension,
+      extension_group,
       UserScriptSlave::GetDataSourceURLForFrame(frame),
       frame->document().securityOrigin());
 
@@ -1528,13 +1530,13 @@
 }
 
 Feature::Context Dispatcher::ClassifyJavaScriptContext(
-    const std::string& extension_id,
+    const Extension* extension,
     int extension_group,
     const GURL& url,
     const blink::WebSecurityOrigin& origin) {
   DCHECK_GE(extension_group, 0);
   if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) {
-    return extensions_.Contains(extension_id) ?
+    return extension ?  // TODO(kalman): when does this happen?
         Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
   }
 
@@ -1549,14 +1551,25 @@
   if (IsSandboxedPage(url))
     return Feature::WEB_PAGE_CONTEXT;
 
-  if (IsExtensionActive(extension_id))
-    return Feature::BLESSED_EXTENSION_CONTEXT;
+  if (extension && IsExtensionActive(extension->id())) {
+    // |extension| is active in this process, but it could be either a true
+    // extension process or within the extent of a hosted app. In the latter
+    // case this would usually be considered a (blessed) web page context,
+    // unless the extension in question is a component extension, in which case
+    // we cheat and call it blessed.
+    return (extension->is_hosted_app() &&
+            extension->location() != Manifest::COMPONENT) ?
+        Feature::BLESSED_WEB_PAGE_CONTEXT : Feature::BLESSED_EXTENSION_CONTEXT;
+  }
 
   // TODO(kalman): This isUnique() check is wrong, it should be performed as
   // part of IsSandboxedPage().
   if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) {
-    return extensions_.Contains(extension_id) ?
-        Feature::UNBLESSED_EXTENSION_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
+    if (!extension)  // TODO(kalman): when does this happen?
+      return Feature::UNSPECIFIED_CONTEXT;
+    return extension->is_hosted_app() ?
+        Feature::BLESSED_WEB_PAGE_CONTEXT :
+        Feature::UNBLESSED_EXTENSION_CONTEXT;
   }
 
   if (url.is_valid())
diff --git a/chrome/renderer/extensions/dispatcher.h b/chrome/renderer/extensions/dispatcher.h
index c0cf115..a111805 100644
--- a/chrome/renderer/extensions/dispatcher.h
+++ b/chrome/renderer/extensions/dispatcher.h
@@ -243,7 +243,7 @@
 
   // Returns the Feature::Context type of context for a JavaScript context.
   Feature::Context ClassifyJavaScriptContext(
-      const std::string& extension_id,
+      const Extension* extension,
       int extension_group,
       const GURL& url,
       const blink::WebSecurityOrigin& origin);
diff --git a/chrome/renderer/extensions/runtime_custom_bindings.cc b/chrome/renderer/extensions/runtime_custom_bindings.cc
index e2030d1..0db2a40 100644
--- a/chrome/renderer/extensions/runtime_custom_bindings.cc
+++ b/chrome/renderer/extensions/runtime_custom_bindings.cc
@@ -58,7 +58,13 @@
   CHECK(args[0]->IsString() && args[1]->IsString() && args[2]->IsBoolean());
 
   ExtensionMsg_ExternalConnectionInfo info;
-  info.source_id = context()->GetExtensionID();
+
+  // For messaging APIs, hosted apps should be considered a web page so hide
+  // its extension ID.
+  const Extension* extension = context()->extension();
+  if (extension && !extension->is_hosted_app())
+    info.source_id = extension->id();
+
   info.target_id = *v8::String::Utf8Value(args[0]->ToString());
   info.source_url = context()->GetURL();
   std::string channel_name = *v8::String::Utf8Value(args[1]->ToString());
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 1cbbda0..7f4da87 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1337,15 +1337,16 @@
 #if defined(OS_WIN)
 void RenderWidgetHostViewAura::UpdateConstrainedWindowRects(
     const std::vector<gfx::Rect>& rects) {
+  // Check this before setting constrained_rects_, so that next time they're set
+  // and we have a root window we don't early return.
+  if (!window_->GetDispatcher())
+    return;
+
   if (rects == constrained_rects_)
     return;
-  constrained_rects_ = rects;
-  UpdateCutoutRects();
-}
 
-void RenderWidgetHostViewAura::UpdateCutoutRects() {
-  if (!window_->GetRootWindow())
-    return;
+  constrained_rects_ = rects;
+
   HWND parent = window_->GetDispatcher()->host()->GetAcceleratedWidget();
   CutoutRectsParams params;
   params.widget = this;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 86db864..041b61d 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -566,12 +566,6 @@
   // Helper function to set keyboard focus to the main window.
   void SetKeyboardFocus();
 
-#if defined(OS_WIN)
-  // Updates the total list of cutout rects, which is the union of transient
-  // windows and constrained windows.
-  void UpdateCutoutRects();
-#endif
-
   // The model object.
   RenderWidgetHostImpl* host_;
 
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 8995b3a..484d04b 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -789,10 +789,8 @@
 
   virtual void OnWindowVisibilityChanged(aura::Window* window,
                                          bool visible) OVERRIDE {
-    if (window == view_->window_)
-      return;
-
-    if (window->parent() == parent_ ||
+    if (window == view_->window_ ||
+        window->parent() == parent_ ||
         window->parent() == view_->window_->GetRootWindow()) {
       UpdateConstrainedWindows(NULL);
     }
diff --git a/content/child/npapi/webplugin_delegate_impl.cc b/content/child/npapi/webplugin_delegate_impl.cc
index 724d598..420766b 100644
--- a/content/child/npapi/webplugin_delegate_impl.cc
+++ b/content/child/npapi/webplugin_delegate_impl.cc
@@ -52,8 +52,10 @@
     const std::vector<std::string>& arg_names,
     const std::vector<std::string>& arg_values,
     bool load_manually) {
-  if (instance_->mime_type() == "video/quicktime")
+  if (instance_->plugin_lib()->plugin_info().name.find(
+          base::ASCIIToUTF16("QuickTime Plug-in")) != std::wstring::npos) {
     quirks_ |= PLUGIN_QUIRK_COPY_STREAM_DATA;
+  }
 
   instance_->set_web_plugin(plugin_);
   if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) {
diff --git a/content/test/plugin/plugin_test_factory.cc b/content/test/plugin/plugin_test_factory.cc
index 742b8f3..3039534 100644
--- a/content/test/plugin/plugin_test_factory.cc
+++ b/content/test/plugin/plugin_test_factory.cc
@@ -99,7 +99,8 @@
              test_name == "create_instance_in_paint" ||
              test_name == "alert_in_window_message" ||
              test_name == "ensure_scripting_works_in_destroy" ||
-             test_name == "set_title_in_paint") {
+             test_name == "set_title_in_paint" ||
+             test_name == "set_title_in_set_window_and_paint") {
     new_test = new WindowedPluginTest(instance, host_functions);
 #endif
   } else if (test_name == "setup") {
diff --git a/content/test/plugin/plugin_windowed_test.cc b/content/test/plugin/plugin_windowed_test.cc
index bfc825d..c0d6630 100644
--- a/content/test/plugin/plugin_windowed_test.cc
+++ b/content/test/plugin/plugin_windowed_test.cc
@@ -39,7 +39,8 @@
 
   if ((test_name() == "create_instance_in_paint" && test_id() == "1") ||
       test_name() == "alert_in_window_message" ||
-      test_name() == "set_title_in_paint") {
+      test_name() == "set_title_in_paint" ||
+      test_name() == "set_title_in_set_window_and_paint") {
     static ATOM window_class = 0;
     if (!window_class) {
       WNDCLASSEX wcex;
@@ -68,6 +69,9 @@
     ::SetProp(window_, L"Plugin_Instance", this);
   }
 
+  if (test_name() == "set_title_in_set_window_and_paint")
+    CallJSFunction(this, "PluginCreated");
+
   return NPERR_NO_ERROR;
 }
 
@@ -122,6 +126,18 @@
       reinterpret_cast<WindowedPluginTest*>
           (::GetProp(window, L"Plugin_Instance"));
 
+  if (message == WM_PAINT) {
+    PAINTSTRUCT ps;
+    HDC hdc = BeginPaint(window, &ps);
+    HBRUSH brush = CreateSolidBrush(RGB(255, 0, 0));
+    SelectObject(hdc, brush);
+    RECT r;
+    GetClientRect(window, &r);
+    Rectangle(hdc, 0, 0, r.right, r.bottom);
+    DeleteObject(brush);
+    EndPaint(window, &ps);
+  }
+
   if (this_ptr && !this_ptr->done_) {
     if (this_ptr->test_name() == "create_instance_in_paint" &&
         message == WM_PAINT) {
@@ -138,6 +154,10 @@
                message == WM_PAINT) {
       this_ptr->done_ = true;
       CallJSFunction(this_ptr, "SetTitle");
+    } else if (this_ptr->test_name() == "set_title_in_set_window_and_paint" &&
+               message == WM_PAINT) {
+      this_ptr->done_ = true;
+      CallJSFunction(this_ptr, "PluginShown");
     }
 
     if (this_ptr->done_) {
diff --git a/extensions/common/features/feature.h b/extensions/common/features/feature.h
index 0caebf6..be85816 100644
--- a/extensions/common/features/feature.h
+++ b/extensions/common/features/feature.h
@@ -39,6 +39,11 @@
 
     // A normal web page. This should have an associated URL matching pattern.
     WEB_PAGE_CONTEXT,
+
+    // A web page context which has been blessed by the user. Typically this
+    // will be via the installation of a hosted app, so this may host an
+    // extension. This is not affected by the URL matching pattern.
+    BLESSED_WEB_PAGE_CONTEXT,
   };
 
   // The location required of extensions the feature is supported in.
diff --git a/net/net.gyp b/net/net.gyp
index 7232a16..c2d618e 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -1510,6 +1510,9 @@
                 '$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
                 '$(SDKROOT)/usr/lib/libresolv.dylib',
               ],
+              'sources!': [
+                'disk_cache/file_posix.cc',
+              ],
             },
           },
         ],
diff --git a/remoting/host/desktop_resizer_mac.cc b/remoting/host/desktop_resizer_mac.cc
index 8bb4c46..ef4659f 100644
--- a/remoting/host/desktop_resizer_mac.cc
+++ b/remoting/host/desktop_resizer_mac.cc
@@ -78,7 +78,7 @@
   CGDisplayModeRef best_mode = NULL;
   for (std::list<ScreenResolution>::const_iterator i = resolutions.begin();
        i != resolutions.end(); ++i, ++index) {
-    if (!i->Equals(resolution)) {
+    if (i->Equals(resolution)) {
       CGDisplayModeRef mode = const_cast<CGDisplayModeRef>(
           static_cast<const CGDisplayMode*>(
               CFArrayGetValueAtIndex(modes, index)));
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 7a0faba..d05c0a4 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -516,8 +516,8 @@
 
   if (token_url_.is_empty() && token_validation_url_.is_empty()) {
     factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
-        host_owner_, local_certificate, key_pair_, host_secret_hash_,
-        pairing_registry);
+        use_service_account_, host_owner_, local_certificate, key_pair_,
+        host_secret_hash_, pairing_registry);
 
   } else if (token_url_.is_valid() && token_validation_url_.is_valid()) {
     scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory>
@@ -525,7 +525,7 @@
             token_url_, token_validation_url_, key_pair_,
             context_->url_request_context_getter()));
     factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
-        host_owner_, local_certificate, key_pair_,
+        use_service_account_, host_owner_, local_certificate, key_pair_,
         token_validator_factory.Pass());
 
   } else {
diff --git a/remoting/jingle_glue/chromium_socket_factory.cc b/remoting/jingle_glue/chromium_socket_factory.cc
index 12e911c..520dc8a 100644
--- a/remoting/jingle_glue/chromium_socket_factory.cc
+++ b/remoting/jingle_glue/chromium_socket_factory.cc
@@ -13,7 +13,7 @@
 #include "net/base/net_errors.h"
 #include "net/udp/udp_server_socket.h"
 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
-#include "third_party/libjingle/source/talk/base/asyncresolverinterface.h"
+#include "third_party/libjingle/source/talk/base/nethelpers.h"
 
 namespace remoting {
 
@@ -35,29 +35,6 @@
       error == net::ERR_ADDRESS_INVALID;
 }
 
-// TODO(lambroslambrou): Move STUN/relay address resolution from
-// PepperPortAllocator to this class.
-class DummyAsyncResolver : public talk_base::AsyncResolverInterface {
- public:
-  DummyAsyncResolver() {}
-  virtual ~DummyAsyncResolver() {}
-  virtual void Start(const talk_base::SocketAddress& addr) OVERRIDE {}
-  virtual bool GetResolvedAddress(
-      int family,
-      talk_base::SocketAddress* addr) const OVERRIDE {
-    return false;
-  }
-  virtual int GetError() const OVERRIDE {
-    return 0;
-  }
-  virtual void Destroy(bool wait) OVERRIDE {
-    delete this;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DummyAsyncResolver);
-};
-
 class UdpPacketSocket : public talk_base::AsyncPacketSocket {
  public:
   UdpPacketSocket();
@@ -398,7 +375,7 @@
 
 talk_base::AsyncResolverInterface*
 ChromiumPacketSocketFactory::CreateAsyncResolver() {
-  return new DummyAsyncResolver();
+  return new talk_base::AsyncResolver();
 }
 
 }  // namespace remoting
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc
index bd926da..1b36ee7 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.cc
+++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -61,6 +61,7 @@
 // static
 scoped_ptr<AuthenticatorFactory>
 Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
+    bool use_service_account,
     const std::string& host_owner,
     const std::string& local_cert,
     scoped_refptr<RsaKeyPair> key_pair,
@@ -68,6 +69,7 @@
     scoped_refptr<PairingRegistry> pairing_registry) {
   scoped_ptr<Me2MeHostAuthenticatorFactory> result(
       new Me2MeHostAuthenticatorFactory());
+  result->use_service_account_ = use_service_account;
   result->host_owner_ = host_owner;
   result->local_cert_ = local_cert;
   result->key_pair_ = key_pair;
@@ -80,6 +82,7 @@
 // static
 scoped_ptr<AuthenticatorFactory>
 Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
+    bool use_service_account,
     const std::string& host_owner,
     const std::string& local_cert,
     scoped_refptr<RsaKeyPair> key_pair,
@@ -87,6 +90,7 @@
         token_validator_factory) {
   scoped_ptr<Me2MeHostAuthenticatorFactory> result(
       new Me2MeHostAuthenticatorFactory());
+  result->use_service_account_ = use_service_account;
   result->host_owner_ = host_owner;
   result->local_cert_ = local_cert;
   result->key_pair_ = key_pair;
@@ -111,12 +115,29 @@
     const std::string& remote_jid,
     const buzz::XmlElement* first_message) {
 
-  // Verify that the client's jid is an ASCII string, and then check
-  // that the client has the same bare jid as the host, i.e. client's
-  // full JID starts with host's bare jid. Comparison is case
-  // insensitive.
+  std::string remote_jid_prefix;
+
+  if (!use_service_account_) {
+    // JID prefixes may not match the host owner email, for example, in cases
+    // where the host owner account does not have an email associated with it.
+    // In those cases, the only guarantee we have is that JIDs for the same
+    // account will have the same prefix.
+    size_t slash_pos = local_jid.find('/');
+    if (slash_pos == std::string::npos) {
+      LOG(DFATAL) << "Invalid local JID:" << local_jid;
+      return scoped_ptr<Authenticator>(new RejectingAuthenticator());
+    }
+    remote_jid_prefix = local_jid.substr(0, slash_pos);
+  } else {
+    // TODO(rmsousa): This only works for cases where the JID prefix matches
+    // the host owner email. Figure out a way to verify the JID in other cases.
+    remote_jid_prefix = host_owner_;
+  }
+
+  // Verify that the client's jid is an ASCII string, and then check that the
+  // client JID has the expected prefix. Comparison is case insensitive.
   if (!IsStringASCII(remote_jid) ||
-      !StartsWithASCII(remote_jid, host_owner_ + '/', false)) {
+      !StartsWithASCII(remote_jid, remote_jid_prefix + '/', false)) {
     LOG(ERROR) << "Rejecting incoming connection from " << remote_jid;
     return scoped_ptr<Authenticator>(new RejectingAuthenticator());
   }
diff --git a/remoting/protocol/me2me_host_authenticator_factory.h b/remoting/protocol/me2me_host_authenticator_factory.h
index 2563347..69d8493 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.h
+++ b/remoting/protocol/me2me_host_authenticator_factory.h
@@ -27,6 +27,7 @@
  public:
   // Create a factory that dispenses shared secret authenticators.
   static scoped_ptr<AuthenticatorFactory> CreateWithSharedSecret(
+      bool use_service_account,
       const std::string& host_owner,
       const std::string& local_cert,
       scoped_refptr<RsaKeyPair> key_pair,
@@ -35,6 +36,7 @@
 
   // Create a factory that dispenses third party authenticators.
   static scoped_ptr<AuthenticatorFactory> CreateWithThirdPartyAuth(
+      bool use_service_account,
       const std::string& host_owner,
       const std::string& local_cert,
       scoped_refptr<RsaKeyPair> key_pair,
@@ -56,6 +58,7 @@
 
  private:
   // Used for all host authenticators.
+  bool use_service_account_;
   std::string host_owner_;
   std::string local_cert_;
   scoped_refptr<RsaKeyPair> key_pair_;
diff --git a/ui/app_list/views/search_result_actions_view.cc b/ui/app_list/views/search_result_actions_view.cc
index ccf848c..2c6abcf 100644
--- a/ui/app_list/views/search_result_actions_view.cc
+++ b/ui/app_list/views/search_result_actions_view.cc
@@ -6,6 +6,7 @@
 
 #include "ui/app_list/views/search_result_actions_view_delegate.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/blue_button.h"
 #include "ui/views/controls/button/image_button.h"
@@ -15,7 +16,8 @@
 
 SearchResultActionsView::SearchResultActionsView(
     SearchResultActionsViewDelegate* delegate)
-    : delegate_(delegate) {
+    : delegate_(delegate),
+      selected_action_(-1) {
   SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 10, 0));
 }
@@ -34,12 +36,34 @@
   }
 
   PreferredSizeChanged();
+  SetSelectedAction(-1);
+}
+
+void SearchResultActionsView::SetSelectedAction(int action_index) {
+  // Clamp |action_index| in [-1, child_count()].
+  action_index = std::min(child_count(), std::max(-1, action_index));
+
+  if (selected_action_ == action_index)
+    return;
+
+  selected_action_ = action_index;
+  SchedulePaint();
+
+  if (IsValidActionIndex(selected_action_)) {
+    child_at(selected_action_)->NotifyAccessibilityEvent(
+        ui::AccessibilityTypes::EVENT_FOCUS, true);
+  }
+}
+
+bool SearchResultActionsView::IsValidActionIndex(int action_index) const {
+  return action_index >= 0 && action_index < child_count();
 }
 
 void SearchResultActionsView::CreateImageButton(
     const SearchResult::Action& action) {
   views::ImageButton* button = new views::ImageButton(this);
   button->set_border(views::Border::CreateEmptyBorder(0, 9, 0, 9));
+  button->SetAccessibleName(action.tooltip_text);
   button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                             views::ImageButton::ALIGN_MIDDLE);
   button->SetImage(views::CustomButton::STATE_NORMAL, &action.base_image);
@@ -52,6 +76,7 @@
 void SearchResultActionsView::CreateBlueButton(
     const SearchResult::Action& action) {
   views::BlueButton* button = new views::BlueButton(this, action.label_text);
+  button->SetAccessibleName(action.label_text);
   button->SetTooltipText(action.tooltip_text);
   button->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
       ui::ResourceBundle::SmallBoldFont));
@@ -59,6 +84,15 @@
   AddChildView(button);
 }
 
+void SearchResultActionsView::OnPaint(gfx::Canvas* canvas) {
+  if (!IsValidActionIndex(selected_action_))
+    return;
+
+  const gfx::Rect active_action_bounds(child_at(selected_action_)->bounds());
+  const SkColor kActiveActionBackground = SkColorSetRGB(0xA0, 0xA0, 0xA0);
+  canvas->FillRect(active_action_bounds, kActiveActionBackground);
+}
+
 void SearchResultActionsView::ButtonPressed(views::Button* sender,
                                             const ui::Event& event) {
   if (!delegate_)
diff --git a/ui/app_list/views/search_result_actions_view.h b/ui/app_list/views/search_result_actions_view.h
index 0aab694..7e5fa75 100644
--- a/ui/app_list/views/search_result_actions_view.h
+++ b/ui/app_list/views/search_result_actions_view.h
@@ -24,15 +24,24 @@
 
   void SetActions(const SearchResult::Actions& actions);
 
+  void SetSelectedAction(int action_index);
+  int selected_action() const { return selected_action_; }
+
+  bool IsValidActionIndex(int action_index) const;
+
  private:
   void CreateImageButton(const SearchResult::Action& action);
   void CreateBlueButton(const SearchResult::Action& action);
 
+  // views::View overrides:
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
   // views::ButtonListener overrides:
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE;
 
   SearchResultActionsViewDelegate* delegate_;  // Not owned.
+  int selected_action_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchResultActionsView);
 };
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc
index 3387cec..84b13da 100644
--- a/ui/app_list/views/search_result_list_view.cc
+++ b/ui/app_list/views/search_result_list_view.cc
@@ -55,13 +55,21 @@
   if (selected_index_ == selected_index)
     return;
 
-  if (selected_index_ >= 0)
-    GetResultViewAt(selected_index_)->SchedulePaint();
+  if (selected_index_ >= 0) {
+    SearchResultView* selected_view  = GetResultViewAt(selected_index_);
+    selected_view->ClearSelectedAction();
+    selected_view->SchedulePaint();
+  }
 
   selected_index_ = selected_index;
 
-  if (selected_index_ >= 0)
-    GetResultViewAt(selected_index_)->SchedulePaint();
+  if (selected_index_ >= 0) {
+    SearchResultView* selected_view  = GetResultViewAt(selected_index_);
+    selected_view->ClearSelectedAction();
+    selected_view->SchedulePaint();
+    selected_view->NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS,
+                                            true);
+  }
 }
 
 bool SearchResultListView::IsResultViewSelected(
@@ -74,6 +82,9 @@
 }
 
 bool SearchResultListView::OnKeyPressed(const ui::KeyEvent& event) {
+  if (selected_index_ >= 0 && child_at(selected_index_)->OnKeyPressed(event))
+    return true;
+
   switch (event.key_code()) {
     case ui::VKEY_TAB:
       if (event.IsShiftDown())
@@ -87,10 +98,6 @@
     case ui::VKEY_DOWN:
       SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_));
       return true;
-    case ui::VKEY_RETURN:
-      if (selected_index_ >= 0)
-        SearchResultActivated(GetResultViewAt(selected_index_), event.flags());
-      return true;
     default:
       break;
   }
diff --git a/ui/app_list/views/search_result_view.cc b/ui/app_list/views/search_result_view.cc
index 9e7fe51..5ba5a20 100644
--- a/ui/app_list/views/search_result_view.cc
+++ b/ui/app_list/views/search_result_view.cc
@@ -108,12 +108,18 @@
   result_ = NULL;
 }
 
+void SearchResultView::ClearSelectedAction() {
+  actions_view_->SetSelectedAction(-1);
+}
+
 void SearchResultView::UpdateTitleText() {
   if (!result_ || result_->title().empty()) {
     title_text_.reset();
+    SetAccessibleName(base::string16());
   } else {
     title_text_.reset(CreateRenderText(result_->title(),
                                        result_->title_tags()));
+    SetAccessibleName(result_->title());
   }
 }
 
@@ -165,6 +171,34 @@
   progress_bar_->SetBoundsRect(progress_bounds);
 }
 
+bool SearchResultView::OnKeyPressed(const ui::KeyEvent& event) {
+  // |result_| could be NULL when result list is changing.
+  if (!result_)
+    return false;
+
+  switch (event.key_code()) {
+    case ui::VKEY_TAB: {
+      int new_selected = actions_view_->selected_action()
+          + (event.IsShiftDown() ? -1 : 1);
+      actions_view_->SetSelectedAction(new_selected);
+      return actions_view_->IsValidActionIndex(new_selected);
+    }
+    case ui::VKEY_RETURN: {
+      int selected = actions_view_->selected_action();
+      if (actions_view_->IsValidActionIndex(selected)) {
+        OnSearchResultActionActivated(selected, event.flags());
+      } else {
+        delegate_->SearchResultActivated(this, event.flags());
+      }
+      return true;
+    }
+    default:
+      break;
+  }
+
+  return false;
+}
+
 void SearchResultView::ChildPreferredSizeChanged(views::View* child) {
   Layout();
 }
@@ -257,6 +291,11 @@
     icon_->ResetImageSize();
   }
 
+  // Set the image to an empty image before we reset the image because
+  // since we're using the same backing store for our images, sometimes
+  // ImageView won't detect that we have a new image set due to the pixel
+  // buffer pointers remaining the same despite the image changing.
+  icon_->SetImage(gfx::ImageSkia());
   icon_->SetImage(image);
 }
 
@@ -272,7 +311,7 @@
 }
 
 void SearchResultView::OnPercentDownloadedChanged() {
-  progress_bar_->SetValue(result_->percent_downloaded() / 100.0);
+  progress_bar_->SetValue(result_ ? result_->percent_downloaded() / 100.0 : 0);
 }
 
 void SearchResultView::OnItemInstalled() {
@@ -285,7 +324,10 @@
 
 void SearchResultView::OnSearchResultActionActivated(size_t index,
                                                      int event_flags) {
-  DCHECK(result_);
+  // |result_| could be NULL when result list is changing.
+  if (!result_)
+    return;
+
   DCHECK_LT(index, result_->actions().size());
 
   delegate_->SearchResultActionActivated(this, index, event_flags);
@@ -294,6 +336,10 @@
 void SearchResultView::ShowContextMenuForView(views::View* source,
                                               const gfx::Point& point,
                                               ui::MenuSourceType source_type) {
+  // |result_| could be NULL when result list is changing.
+  if (!result_)
+    return;
+
   ui::MenuModel* menu_model = result_->GetContextMenuModel();
   if (!menu_model)
     return;
diff --git a/ui/app_list/views/search_result_view.h b/ui/app_list/views/search_result_view.h
index dde3669..d9cd907 100644
--- a/ui/app_list/views/search_result_view.h
+++ b/ui/app_list/views/search_result_view.h
@@ -54,6 +54,9 @@
   // Clears reference to SearchResult but don't schedule repaint.
   void ClearResultNoRepaint();
 
+  // Clears the selected action.
+  void ClearSelectedAction();
+
  private:
   void UpdateTitleText();
   void UpdateDetailsText();
@@ -62,6 +65,7 @@
   virtual const char* GetClassName() const OVERRIDE;
   virtual gfx::Size GetPreferredSize() OVERRIDE;
   virtual void Layout() OVERRIDE;
+  virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
   virtual void ChildPreferredSizeChanged(views::View* child) OVERRIDE;
   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
 
diff --git a/ui/aura/remote_root_window_host_win.cc b/ui/aura/remote_root_window_host_win.cc
index 760d955..3dba26a 100644
--- a/ui/aura/remote_root_window_host_win.cc
+++ b/ui/aura/remote_root_window_host_win.cc
@@ -141,6 +141,11 @@
                                                                    ash_exit);
 }
 
+void HandleMetroExit() {
+  DCHECK(aura::RemoteRootWindowHostWin::Instance());
+  aura::RemoteRootWindowHostWin::Instance()->HandleMetroExit();
+}
+
 RemoteRootWindowHostWin* g_instance = NULL;
 
 RemoteRootWindowHostWin* RemoteRootWindowHostWin::Instance() {
@@ -242,6 +247,12 @@
   host_->Send(new MetroViewerHostMsg_ActivateDesktop(shortcut, ash_exit));
 }
 
+void RemoteRootWindowHostWin::HandleMetroExit() {
+  if (!host_)
+    return;
+  host_->Send(new MetroViewerHostMsg_MetroExit());
+}
+
 void RemoteRootWindowHostWin::HandleOpenFile(
     const base::string16& title,
     const base::FilePath& default_path,
diff --git a/ui/aura/remote_root_window_host_win.h b/ui/aura/remote_root_window_host_win.h
index 6ccf94d..5c1066f 100644
--- a/ui/aura/remote_root_window_host_win.h
+++ b/ui/aura/remote_root_window_host_win.h
@@ -84,14 +84,17 @@
                                     const SelectFolderCompletion& on_success,
                                     const FileSelectionCanceled& on_failure);
 
-// Handles the activate desktop command for Metro Chrome Ash. The on_success
-// callback passed in is invoked when activation is completed.
-// The |ash_exit| parameter indicates whether the Ash process would be shutdown
-// after activating the desktop.
+// Handles the activate desktop command for Metro Chrome Ash.   The |ash_exit|
+// parameter indicates whether the Ash process would be shutdown after
+// activating the desktop.
 AURA_EXPORT void HandleActivateDesktop(
     const base::FilePath& shortcut,
     bool ash_exit);
 
+// Handles the metro exit command.  Notifies the metro viewer to shutdown
+// gracefully.
+AURA_EXPORT void HandleMetroExit();
+
 // RootWindowHost implementaton that receives events from a different
 // process. In the case of Windows this is the Windows 8 (aka Metro)
 // frontend process, which forwards input events to this class.
@@ -119,9 +122,10 @@
 
   // The |ash_exit| parameter indicates whether the Ash process would be
   // shutdown after activating the desktop.
-  void HandleActivateDesktop(
-      const base::FilePath& shortcut,
-      bool ash_exit);
+  void HandleActivateDesktop(const base::FilePath& shortcut, bool ash_exit);
+
+  // Notify the metro viewer that it should shut itself down.
+  void HandleMetroExit();
 
   void HandleOpenFile(const base::string16& title,
                       const base::FilePath& default_path,
diff --git a/ui/metro_viewer/metro_viewer_messages.h b/ui/metro_viewer/metro_viewer_messages.h
index eae79d6..e30554c 100644
--- a/ui/metro_viewer/metro_viewer_messages.h
+++ b/ui/metro_viewer/metro_viewer_messages.h
@@ -97,6 +97,9 @@
                      base::FilePath /* shortcut */,
                      bool           /* ash exit */);
 
+// Request the viewer to close itself gracefully.
+IPC_MESSAGE_CONTROL0(MetroViewerHostMsg_MetroExit);
+
 // Requests the viewer to open a URL in desktop mode.
 IPC_MESSAGE_CONTROL2(MetroViewerHostMsg_OpenURLOnDesktop,
                      base::FilePath,  /* shortcut */
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 31e694b..aea03be 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -592,6 +592,7 @@
 void HWNDMessageHandler::SetRegion(HRGN region) {
   custom_window_region_.Set(region);
   ResetWindowRegion(false, true);
+  UpdateDwmNcRenderingPolicy();
 }
 
 void HWNDMessageHandler::StackAbove(HWND other_hwnd) {
@@ -828,9 +829,6 @@
   // Called when the frame type could possibly be changing (theme change or
   // DWM composition change).
 
-  // Update rendering of the DWM/glass frame depending on the new frame type.
-  UpdateDwmNcRenderingPolicy();
-
   // Don't redraw the window here, because we need to hide and show the window
   // which will also trigger a redraw.
   ResetWindowRegion(true, false);
@@ -1186,9 +1184,8 @@
 void HWNDMessageHandler::UpdateDwmNcRenderingPolicy() {
   if (base::win::GetVersion() < base::win::VERSION_VISTA)
     return;
-  DWMNCRENDERINGPOLICY policy = DWMNCRP_ENABLED;
-  if (remove_standard_frame_ || delegate_->IsUsingCustomFrame())
-    policy = DWMNCRP_DISABLED;
+  DWMNCRENDERINGPOLICY policy = custom_window_region_ ? DWMNCRP_DISABLED
+                                                      : DWMNCRP_USEWINDOWSTYLE;
   DwmSetWindowAttribute(hwnd(), DWMWA_NCRENDERING_POLICY,
                         &policy, sizeof(DWMNCRENDERINGPOLICY));
 }
@@ -1351,7 +1348,6 @@
               0);
 
   if (remove_standard_frame_) {
-    UpdateDwmNcRenderingPolicy();
     SetWindowLong(hwnd(), GWL_STYLE,
                   GetWindowLong(hwnd(), GWL_STYLE) & ~WS_CAPTION);
     SendFrameChanged();
@@ -1865,16 +1861,49 @@
 #if defined(USE_AURA)
   LRESULT hit_test_code = DefWindowProc(hwnd(), WM_NCHITTEST, 0,
                                         MAKELPARAM(point.x, point.y));
-  // If we faked the WS_VSCROLL and WS_HSCROLL styles for this window, then
-  // Windows returns the HTVSCROLL or HTHSCROLL hit test codes if we hover or
-  // click on the non client portions of the window where the OS scrollbars
-  // would be drawn. These hittest codes are returned even when the scrollbars
-  // are hidden, which is the case in Aura. We fake the hittest code as
-  // HTCLIENT in this case to ensure that we receive client mouse messages as
-  // opposed to non client mouse messages.
-  if (needs_scroll_styles_ && (hit_test_code == HTVSCROLL ||
-      hit_test_code == HTHSCROLL))
-    hit_test_code = HTCLIENT;
+  if (needs_scroll_styles_) {
+    switch (hit_test_code) {
+      // If we faked the WS_VSCROLL and WS_HSCROLL styles for this window, then
+      // Windows returns the HTVSCROLL or HTHSCROLL hit test codes if we hover
+      // or click on the non client portions of the window where the OS
+      // scrollbars would be drawn. These hittest codes are returned even when
+      // the scrollbars are hidden, which is the case in Aura. We fake the
+      // hittest code as HTCLIENT in this case to ensure that we receive client
+      // mouse messages as opposed to non client mouse messages.
+      case HTVSCROLL:
+      case HTHSCROLL:
+        hit_test_code = HTCLIENT;
+        break;
+
+      case HTBOTTOMRIGHT: {
+        // Normally the HTBOTTOMRIGHT hittest code is received when we hover
+        // near the bottom right of the window. However due to our fake scroll
+        // styles, we get this code even when we hover around the area where
+        // the vertical scrollar down arrow would be drawn.
+        // We check if the hittest coordinates lie in this region and if yes
+        // we return HTCLIENT.
+        int border_width = ::GetSystemMetrics(SM_CXSIZEFRAME);
+        int border_height = ::GetSystemMetrics(SM_CYSIZEFRAME);
+        int scroll_width = ::GetSystemMetrics(SM_CXVSCROLL);
+        int scroll_height = ::GetSystemMetrics(SM_CYVSCROLL);
+        RECT window_rect;
+        ::GetWindowRect(hwnd(), &window_rect);
+        window_rect.bottom -= border_height;
+        window_rect.right -= border_width;
+        window_rect.left = window_rect.right - scroll_width;
+        window_rect.top = window_rect.bottom - scroll_height;
+        POINT pt;
+        pt.x = point.x;
+        pt.y = point.y;
+        if (::PtInRect(&window_rect, pt))
+          hit_test_code = HTCLIENT;
+        break;
+      }
+
+      default:
+        break;
+    }
+  }
   return hit_test_code;
 #else
   SetMsgHandled(FALSE);
diff --git a/win8/metro_driver/chrome_app_view_ash.cc b/win8/metro_driver/chrome_app_view_ash.cc
index 8b64251..c1a8f4c 100644
--- a/win8/metro_driver/chrome_app_view_ash.cc
+++ b/win8/metro_driver/chrome_app_view_ash.cc
@@ -157,6 +157,7 @@
     IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message)
       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop,
                           OnActivateDesktop)
+      IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit, OnMetroExit)
       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop,
                           OnOpenURLOnDesktop)
       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor)
@@ -194,6 +195,10 @@
         shortcut, ash_exit));
   }
 
+  void OnMetroExit() {
+    MetroExit(app_view_->core_window_hwnd());
+  }
+
   void OnOpenURLOnDesktop(const base::FilePath& shortcut,
                           const string16& url) {
     ui_proxy_->PostTask(FROM_HERE,