diff --git a/DEPS b/DEPS
index 9e3e3199..aa93e94 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '8da9e940721168143d6296f578b6d7423de55d69',
+  'skia_revision': 'e393a629491e9a52dd6662983d2bfd424541957e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '5c1961dfa0b1828eb2db38dc637548584c5cc704',
+  'pdfium_revision': 'e472622d33bdca2316a22ff5ff8d77ac975c2eb2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'aa4354795733e91c5caf2a25b111240bf3637b5f',
+  'catapult_revision': '5cdfbfc974591fbaca53645b670c8191cb89f8aa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -404,7 +404,7 @@
 
     # For Linux and Chromium OS.
     'src/third_party/cros_system_api':
-      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '7c84418f4f0479eabc607d8c4cb678269aee01c4',
+      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'ce814837221c4a4d385fd92094b7673bf4601c9f',
 
     'src/third_party/freetype/src':
       Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + Var('freetype_revision'),
diff --git a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java
index ffbcca9..eb9dc56 100644
--- a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java
+++ b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java
@@ -94,7 +94,7 @@
     private static final String MORE_OPTIONS_ACTION = "More options";
     private static final String PASTE_ACTION = "Paste";
     private static final String SHARE_ACTION = "Share";
-    private static final String SELECT_ALL_ACTION = "Select All";
+    private static final String SELECT_ALL_ACTION = "Select all";
     private static final String WEB_SEARCH_ACTION = "Web search";
 
     private static final String QUICK_SEARCH_BOX_PKG = "com.google.android.googlequicksearchbox";
@@ -147,7 +147,7 @@
     @UseLayout("edittext_webview")
     public void testSelectAll() {
         longClickOnLastWord(R.id.webview);
-        clickPopupAction("Select all");
+        clickPopupAction(SELECT_ALL_ACTION);
         clickPopupAction(COPY_ACTION);
         longClickOnLastWord(R.id.edittext);
         clickPopupAction(PASTE_ACTION);
@@ -246,6 +246,14 @@
                     .perform(click());
             onData(new MenuItemMatcher(equalTo(name))).inRoot(rootMatcher).perform(click());
         }
+
+        /**
+         * After select all action is clicked, the PopUp Menu may disappear
+         * briefly due to selection change, wait for the menu to reappear
+         */
+        if (name.equals(SELECT_ALL_ACTION)) {
+            mActionBarIdlingResource.start();
+        }
     }
 
     /**
@@ -286,11 +294,6 @@
         private boolean mActionStarting;
         private ResourceCallback mResourceCallback;
 
-        ActionBarIdlingResource() {
-            mActionStarting = false;
-            mResourceCallback = null;
-        }
-
         @Override
         public String getName() {
             return "ActionBarIdlingResource";
diff --git a/ash/common/shelf/shelf_constants.cc b/ash/common/shelf/shelf_constants.cc
index c260855..25a8fe3 100644
--- a/ash/common/shelf/shelf_constants.cc
+++ b/ash/common/shelf/shelf_constants.cc
@@ -23,7 +23,7 @@
 const SkColor kShelfIconColor = SK_ColorWHITE;
 const int kShelfTranslucentAlpha = 153;
 const int kShelfTranslucentColorDarkenAlpha = 102;
-const int kShelfOpaqueColorDarkenAlpha = 230;
+const int kShelfOpaqueColorDarkenAlpha = 178;
 const int kOverflowButtonSize = 32;
 const int kOverflowButtonCornerRadius = 2;
 const int kAppListButtonRadius = kOverflowButtonSize / 2;
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index c5db1b24..d2b8197 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -238,8 +238,8 @@
   """Copy the VS runtime DLLs, only if the target doesn't exist, but the target
   directory does exist. Handles VS 2013, VS 2015, and VS 2017."""
   suffix = "d.dll" if debug else ".dll"
-  if GetVisualStudioVersion() == '2015' or GetVisualStudioVersion() == '2017':
-    # VS 2017 RC uses the same CRT DLLs as VS 2015.
+  if GetVisualStudioVersion() in ['2015', '2017']:
+    # VS 2017 uses the same CRT DLLs as VS 2015.
     _CopyUCRTRuntime(target_dir, source_dir, '%s140' + suffix, suffix)
   else:
     _CopyRuntime2013(target_dir, source_dir, 'msvc%s120' + suffix)
@@ -343,8 +343,10 @@
   if GetVisualStudioVersion() == '2015':
     # Update 3 final with patches with 10.0.14393.0 SDK.
     return ['d3cb0e37bdd120ad0ac4650b674b09e81be45616']
-  else:
+  elif GetVisualStudioVersion() == '2013':
     return ['03a4e939cd325d6bc5216af41b92d02dda1366a6']
+  else:
+    raise Exception('Unsupported VS version %s' % GetVisualStudioVersion())
 
 
 def ShouldUpdateToolchain():
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index c200375..50eef3c4 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -24,8 +24,35 @@
 using base::trace_event::MemoryDumpLevelOfDetail;
 
 namespace cc {
+namespace {
+bool ResourceMeetsSizeRequirements(const gfx::Size& requested_size,
+                                   const gfx::Size& actual_size) {
+  const float kReuseThreshold = 2.0f;
+
+  // Allocating new resources is expensive, and we'd like to re-use our
+  // existing ones within reason. Allow a larger resource to be used for a
+  // smaller request.
+  if (actual_size.width() < requested_size.width() ||
+      actual_size.height() < requested_size.height())
+    return false;
+
+  // GetArea will crash on overflow, however all sizes in use are tile sizes.
+  // These are capped at ResourceProvider::max_texture_size(), and will not
+  // overflow.
+  float actual_area = actual_size.GetArea();
+  float requested_area = requested_size.GetArea();
+  // Don't use a resource that is more than |kReuseThreshold| times the
+  // requested pixel area, as we want to free unnecessarily large resources.
+  if (actual_area / requested_area > kReuseThreshold)
+    return false;
+
+  return true;
+}
+
+}  // namespace
+
 base::TimeDelta ResourcePool::kDefaultExpirationDelay =
-    base::TimeDelta::FromSeconds(1);
+    base::TimeDelta::FromSeconds(5);
 
 void ResourcePool::PoolResource::OnMemoryDump(
     base::trace_event::ProcessMemoryDump* pmd,
@@ -119,7 +146,7 @@
 
     if (resource->format() != format)
       continue;
-    if (resource->size() != size)
+    if (!ResourceMeetsSizeRequirements(size, resource->size()))
       continue;
     if (resource->color_space() != color_space)
       continue;
diff --git a/cc/resources/resource_pool_unittest.cc b/cc/resources/resource_pool_unittest.cc
index aa8e853e..ec9bae41 100644
--- a/cc/resources/resource_pool_unittest.cc
+++ b/cc/resources/resource_pool_unittest.cc
@@ -33,6 +33,12 @@
   }
 
  protected:
+  void CheckAndReturnResource(Resource* resource) {
+    EXPECT_NE(nullptr, resource);
+    resource_pool_->ReleaseResource(resource);
+    resource_pool_->CheckBusyResources();
+  }
+
   scoped_refptr<TestContextProvider> context_provider_;
   std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
@@ -105,32 +111,28 @@
   gfx::ColorSpace color_space1;
   gfx::ColorSpace color_space2 = gfx::ColorSpace::CreateSRGB();
 
-  Resource* resource =
-      resource_pool_->AcquireResource(size, format, color_space1);
-  resource_pool_->ReleaseResource(resource);
-  resource_pool_->CheckBusyResources();
+  CheckAndReturnResource(
+      resource_pool_->AcquireResource(size, format, color_space1));
   EXPECT_EQ(1u, resource_provider_->num_resources());
 
   // Same size/format should re-use resource.
-  resource = resource_pool_->AcquireResource(size, format, color_space1);
+  Resource* resource =
+      resource_pool_->AcquireResource(size, format, color_space1);
   EXPECT_EQ(1u, resource_provider_->num_resources());
-  resource_pool_->ReleaseResource(resource);
-  resource_pool_->CheckBusyResources();
+  CheckAndReturnResource(resource);
   EXPECT_EQ(1u, resource_provider_->num_resources());
 
   // Different size/format should allocate new resource.
   resource = resource_pool_->AcquireResource(gfx::Size(50, 50), LUMINANCE_8,
                                              color_space1);
   EXPECT_EQ(2u, resource_provider_->num_resources());
-  resource_pool_->ReleaseResource(resource);
-  resource_pool_->CheckBusyResources();
+  CheckAndReturnResource(resource);
   EXPECT_EQ(2u, resource_provider_->num_resources());
 
   // Different color space should allocate new resource.
   resource = resource_pool_->AcquireResource(size, format, color_space2);
   EXPECT_EQ(3u, resource_provider_->num_resources());
-  resource_pool_->ReleaseResource(resource);
-  resource_pool_->CheckBusyResources();
+  CheckAndReturnResource(resource);
   EXPECT_EQ(3u, resource_provider_->num_resources());
 }
 
@@ -317,25 +319,47 @@
   ResourceFormat format = RGBA_8888;
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
 
-  // Create unused resources with sizes close to 100, 100.
-  resource_pool_->ReleaseResource(
-      resource_pool_->CreateResource(gfx::Size(99, 100), format, color_space));
-  resource_pool_->ReleaseResource(
-      resource_pool_->CreateResource(gfx::Size(99, 99), format, color_space));
-  resource_pool_->ReleaseResource(
-      resource_pool_->CreateResource(gfx::Size(100, 99), format, color_space));
-  resource_pool_->ReleaseResource(
-      resource_pool_->CreateResource(gfx::Size(101, 101), format, color_space));
-  resource_pool_->CheckBusyResources();
+  // Create unused resource with size 100x100.
+  CheckAndReturnResource(
+      resource_pool_->CreateResource(gfx::Size(100, 100), format, color_space));
 
-  gfx::Size size(100, 100);
-  Resource* resource = resource_pool_->ReuseResource(size, format, color_space);
-  EXPECT_EQ(nullptr, resource);
-  size = gfx::Size(100, 99);
-  resource = resource_pool_->ReuseResource(size, format, color_space);
-  EXPECT_NE(nullptr, resource);
-  ASSERT_EQ(nullptr, resource_pool_->ReuseResource(size, format, color_space));
-  resource_pool_->ReleaseResource(resource);
+  // Try some cases that are too large, none should succeed.
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(101, 100), format,
+                                                   color_space));
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 101), format,
+                                                   color_space));
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(90, 120), format,
+                                                   color_space));
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(120, 120), format,
+                                                   color_space));
+
+  // Try some cases that are more than 2x smaller than 100x100 in area and
+  // won't be re-used.
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(49, 100), format,
+                                                   color_space));
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 49), format,
+                                                   color_space));
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(50, 50), format,
+                                                   color_space));
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(70, 70), format,
+                                                   color_space));
+
+  // Try some cases that are smaller than 100x100, but within 2x area. Reuse
+  // should succeed.
+  CheckAndReturnResource(
+      resource_pool_->ReuseResource(gfx::Size(50, 100), format, color_space));
+  CheckAndReturnResource(
+      resource_pool_->ReuseResource(gfx::Size(100, 50), format, color_space));
+  CheckAndReturnResource(
+      resource_pool_->ReuseResource(gfx::Size(71, 71), format, color_space));
+
+  // 100x100 is an exact match and should succeed. A subsequent request for
+  // the same size should fail (the resource is already in use).
+  Resource* resource =
+      resource_pool_->ReuseResource(gfx::Size(100, 100), format, color_space);
+  EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 100), format,
+                                                   color_space));
+  CheckAndReturnResource(resource);
 }
 
 TEST_F(ResourcePoolTest, MemoryStateSuspended) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 88ddbec..52c4b8ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -761,7 +761,7 @@
             return false;
         }
 
-        getTabCreator(false).launchUrl(UrlConstants.NTP_URL, TabLaunchType.FROM_CHROME_UI);
+        getTabCreator(false).launchUrl(UrlConstants.NTP_URL, TabLaunchType.FROM_EXTERNAL_APP);
         return true;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
index 913965b..becd503 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
@@ -62,8 +62,12 @@
                 intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_PATH);
         boolean isSupportedMimeType =  IntentUtils.safeGetBooleanExtra(
                 intent, DownloadNotificationService.EXTRA_IS_SUPPORTED_MIME_TYPE, false);
+        boolean isOffTheRecord = IntentUtils.safeGetBooleanExtra(
+                intent, DownloadNotificationService.EXTRA_IS_OFF_THE_RECORD, false);
+        String downloadGuid = IntentUtils.safeGetStringExtra(
+                intent, DownloadNotificationService.EXTRA_DOWNLOAD_GUID);
         DownloadManagerService.openDownloadedContent(
-                context, downloadFilename, isSupportedMimeType, id);
+                context, downloadFilename, isSupportedMimeType, isOffTheRecord, downloadGuid, id);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 855c911..c1c51ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -1065,13 +1065,11 @@
                 ? false : ExternalNavigationDelegateImpl.resolveIntent(intent, true);
     }
 
-    /** See {@link #openDownloadedContent(Context, String, boolean, long)}. */
+    /** See {@link #openDownloadedContent(Context, String, boolean, boolean, String, long)}. */
     protected void openDownloadedContent(final DownloadInfo downloadInfo, final long downloadId) {
-        // TODO(shaktisahu): Move this to the broader openDownloadedContent() or a better place if
-        // possible.
-        updateLastAccessTime(downloadInfo.getDownloadGuid(), downloadInfo.isOffTheRecord());
         openDownloadedContent(mContext, downloadInfo.getFilePath(),
-                isSupportedMimeType(downloadInfo.getMimeType()), downloadId);
+                isSupportedMimeType(downloadInfo.getMimeType()), downloadInfo.isOffTheRecord(),
+                downloadInfo.getDownloadGuid(), downloadId);
     }
 
     /**
@@ -1081,10 +1079,13 @@
      * @param context             Context to use.
      * @param filePath            Path to the downloaded item.
      * @param isSupportedMimeType MIME type of the downloaded item.
+     * @param isOffTheRecord      Whether the download was for a off the record profile.
+     * @param downloadGuid        GUID of the download item in DownloadManager.
      * @param downloadId          ID of the download item in DownloadManager.
      */
     protected static void openDownloadedContent(final Context context, final String filePath,
-            final boolean isSupportedMimeType, final long downloadId) {
+            final boolean isSupportedMimeType, final boolean isOffTheRecord,
+            final String downloadGuid, final long downloadId) {
         new AsyncTask<Void, Void, Intent>() {
             @Override
             public Intent doInBackground(Void... params) {
@@ -1098,6 +1099,10 @@
                         || !ExternalNavigationDelegateImpl.resolveIntent(intent, true)
                         || !DownloadUtils.fireOpenIntentForDownload(context, intent)) {
                     openDownloadsPage(context);
+                } else {
+                    DownloadManagerService service =
+                            DownloadManagerService.getDownloadManagerService(context);
+                    service.updateLastAccessTime(downloadGuid, isOffTheRecord);
                 }
             }
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -1786,6 +1791,8 @@
      */
     @Override
     public void updateLastAccessTime(String downloadGuid, boolean isOffTheRecord) {
+        if (TextUtils.isEmpty(downloadGuid)) return;
+
         nativeUpdateLastAccessTime(getNativeDownloadManagerService(), downloadGuid, isOffTheRecord);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index c30c373..bc4f784 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -876,9 +876,9 @@
      *         user click on the snackbar.
      */
     @VisibleForTesting
-    public int notifyDownloadSuccessful(
-            String downloadGuid, String filePath, String fileName, long systemDownloadId,
-            boolean isOfflinePage, boolean isSupportedMimeType) {
+    public int notifyDownloadSuccessful(String downloadGuid, String filePath, String fileName,
+            long systemDownloadId, boolean isOffTheRecord, boolean isOfflinePage,
+            boolean isSupportedMimeType) {
         int notificationId = getNotificationId(downloadGuid);
         ChromeNotificationBuilder builder = buildNotification(R.drawable.offline_pin, fileName,
                 mContext.getResources().getString(R.string.download_notification_completed));
@@ -893,6 +893,8 @@
             intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS, idArray);
             intent.putExtra(EXTRA_DOWNLOAD_FILE_PATH, filePath);
             intent.putExtra(EXTRA_IS_SUPPORTED_MIME_TYPE, isSupportedMimeType);
+            intent.putExtra(EXTRA_IS_OFF_THE_RECORD, isOffTheRecord);
+            intent.putExtra(EXTRA_DOWNLOAD_GUID, downloadGuid);
         }
         intent.setComponent(component);
         builder.setContentIntent(PendingIntent.getBroadcast(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index 67d2f88..f958dc8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -469,12 +469,13 @@
      * Opens a file in Chrome or in another app if appropriate.
      * @param file path to the file to open.
      * @param mimeType mime type of the file.
+     * @param downloadGuid The associated download GUID.
      * @param isOffTheRecord whether we are in an off the record context.
      * @return whether the file could successfully be opened.
      */
-    public static boolean openFile(File file, String mimeType, boolean isOffTheRecord) {
+    public static boolean openFile(
+            File file, String mimeType, String downloadGuid, boolean isOffTheRecord) {
         Context context = ContextUtils.getApplicationContext();
-        Intent viewIntent = createViewIntentForDownloadItem(getUriForItem(file), mimeType);
         DownloadManagerService service = DownloadManagerService.getDownloadManagerService(context);
 
         // Check if Chrome should open the file itself.
@@ -488,12 +489,15 @@
             Intent intent =
                     getMediaViewerIntentForDownloadItem(fileUri, contentUri, normalizedMimeType);
             IntentHandler.startActivityForTrustedIntent(intent);
+            service.updateLastAccessTime(downloadGuid, isOffTheRecord);
             return true;
         }
 
         // Check if any apps can open the file.
         try {
+            Intent viewIntent = createViewIntentForDownloadItem(getUriForItem(file), mimeType);
             context.startActivity(viewIntent);
+            service.updateLastAccessTime(downloadGuid, isOffTheRecord);
             return true;
         } catch (ActivityNotFoundException e) {
             // Can't launch the Intent.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
index 85a6c77..8c5aee9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
@@ -281,8 +281,8 @@
             case DOWNLOAD_NOTIFICATION_TYPE_SUCCESS:
                 final int notificationId = mBoundService.notifyDownloadSuccessful(
                         info.getDownloadGuid(), info.getFilePath(), info.getFileName(),
-                        notificationInfo.systemDownloadId, info.isOfflinePage(),
-                        notificationInfo.isSupportedMimeType);
+                        notificationInfo.systemDownloadId, info.isOffTheRecord(),
+                        info.isOfflinePage(), notificationInfo.isSupportedMimeType);
                 onSuccessNotificationShown(notificationInfo, notificationId);
                 break;
             case DOWNLOAD_NOTIFICATION_TYPE_FAILURE:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
index e36debb..c368bbc5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
@@ -329,9 +329,8 @@
                 return;
             }
 
-            if (DownloadUtils.openFile(getFile(), getMimeType(), isOffTheRecord())) {
-                mBackendProvider.getDownloadDelegate().updateLastAccessTime(
-                        mItem.getId(), isOffTheRecord());
+            if (DownloadUtils.openFile(getFile(), getMimeType(),
+                        mItem.getDownloadInfo().getDownloadGuid(), isOffTheRecord())) {
                 recordOpenSuccess();
             } else {
                 recordOpenFailure();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OWNERS
index 92e42be0..a5ae8db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OWNERS
@@ -1,2 +1,4 @@
+set noparent
+
 dfalcantara@chromium.org
 twellington@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java
index 01b5b76..1e62c4f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java
@@ -74,7 +74,7 @@
         return getMessageText(template, filename, new ClickableSpan() {
             @Override
             public void onClick(View view) {
-                DownloadUtils.openFile(file, mimeType, mIsIncognito);
+                DownloadUtils.openFile(file, mimeType, null, mIsIncognito);
             }
         });
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
index 96409080..9f3bead 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
@@ -59,6 +59,9 @@
     /** Whether the linked article represents an asset download. */
     private boolean mIsAssetDownload;
 
+    /** The GUID of the asset download (only for asset download articles). */
+    private String mAssetDownloadGuid;
+
     /** The path to the asset download (only for asset download articles). */
     private File mAssetDownloadFile;
 
@@ -132,6 +135,16 @@
     }
 
     /**
+     * @return the GUID of the asset download. May only be called if {@link #mIsAssetDownload} is
+     * {@code true} (which implies that this snippet belongs to the DOWNLOADS category).
+     */
+    public String getAssetDownloadGuid() {
+        assert isDownload();
+        assert mIsAssetDownload;
+        return mAssetDownloadGuid;
+    }
+
+    /**
      * @return the asset download path. May only be called if {@link #mIsAssetDownload} is
      * {@code true} (which implies that this snippet belongs to the DOWNLOADS category).
      */
@@ -155,9 +168,10 @@
      * Marks the article suggestion as an asset download with the given path and mime type. May only
      * be called if this snippet belongs to DOWNLOADS category.
      */
-    public void setAssetDownloadData(String filePath, String mimeType) {
+    public void setAssetDownloadData(String downloadGuid, String filePath, String mimeType) {
         assert isDownload();
         mIsAssetDownload = true;
+        mAssetDownloadGuid = downloadGuid;
         mAssetDownloadFile = new File(filePath);
         mAssetDownloadMimeType = mimeType;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index 767af465..15d272e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -271,8 +271,8 @@
 
     @CalledByNative
     private static void setAssetDownloadDataForSuggestion(
-            SnippetArticle suggestion, String filePath, String mimeType) {
-        suggestion.setAssetDownloadData(filePath, mimeType);
+            SnippetArticle suggestion, String downloadGuid, String filePath, String mimeType) {
+        suggestion.setAssetDownloadData(downloadGuid, filePath, mimeType);
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
index 20e2d429..0b0f6c2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
@@ -4,6 +4,10 @@
 
 package org.chromium.chrome.browser.physicalweb;
 
+import android.annotation.TargetApi;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.net.Uri;
@@ -153,4 +157,28 @@
                 new Intent(Intent.ACTION_VIEW, Uri.parse(UrlConstants.PHYSICAL_WEB_URL))
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
     }
+
+    /**
+     * Check if bluetooth is on and enabled.
+     */
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static boolean bluetoothIsEnabled() {
+        Context context = ContextUtils.getApplicationContext();
+        BluetoothManager bluetoothManager =
+                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
+        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
+        return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
+    }
+
+    /**
+     * Check if the device bluetooth hardware supports BLE advertisements.
+     */
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static boolean hasBleAdvertiseCapability() {
+        Context context = ContextUtils.getApplicationContext();
+        BluetoothManager bluetoothManager =
+                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
+        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
+        return bluetoothAdapter != null && bluetoothAdapter.getBluetoothLeAdvertiser() != null;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebShareActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebShareActivity.java
index 3b6dbcb..09891aa8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebShareActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebShareActivity.java
@@ -26,11 +26,15 @@
     /**
      * Returns whether we should show this sharing option in the share sheet.
      * Pre-conditions for Physical Web Sharing to be enabled:
+     *      Device has hardware BLE advertising capabilities.
+     *      Device had Bluetooth on.
      *      Device is Marshmallow or above.
      *      Device has sharing feature enabled.
      * @return {@code true} if the feature should be enabled.
      */
     public static boolean featureIsAvailable() {
-        return PhysicalWeb.sharingIsEnabled() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;
+        return PhysicalWeb.hasBleAdvertiseCapability() && PhysicalWeb.bluetoothIsEnabled()
+                && PhysicalWeb.sharingIsEnabled();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
index bc6bc00..6fc318b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
@@ -97,8 +97,8 @@
             assert windowOpenDisposition == WindowOpenDisposition.CURRENT_TAB
                     || windowOpenDisposition == WindowOpenDisposition.NEW_WINDOW
                     || windowOpenDisposition == WindowOpenDisposition.NEW_BACKGROUND_TAB;
-            DownloadUtils.openFile(
-                    article.getAssetDownloadFile(), article.getAssetDownloadMimeType(), false);
+            DownloadUtils.openFile(article.getAssetDownloadFile(),
+                    article.getAssetDownloadMimeType(), article.getAssetDownloadGuid(), false);
             return;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
index d40f46b2..1a2c0137 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
@@ -333,8 +333,11 @@
         super.onTabOrModelChanged();
         boolean incognito = isIncognito();
         if (mUseLightColorAssets == null || mUseLightColorAssets != incognito) {
-            setBackgroundResource(incognito
-                    ? R.color.incognito_primary_color : R.color.default_primary_color);
+            int colorResource =
+                    incognito ? R.color.incognito_primary_color : R.color.default_primary_color;
+            setBackgroundResource(colorResource);
+            getProgressBar().setThemeColor(
+                    ApiCompatibilityUtils.getColor(getResources(), colorResource), isIncognito());
 
             mMenuButton.setTint(incognito ? mLightModeTint : mDarkModeTint);
             mHomeButton.setTint(incognito ? mLightModeTint : mDarkModeTint);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
index a41d5a46..7775861 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -289,7 +289,8 @@
                 sharedPrefs, DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
         assertEquals(3, entries.size());
 
-        service.notifyDownloadSuccessful(guid1, "/path/to/success", "success", 100L, false, false);
+        service.notifyDownloadSuccessful(
+                guid1, "/path/to/success", "success", 100L, false, false, false);
         entries = DownloadManagerService.getStoredDownloadInfo(
                 sharedPrefs, DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
         assertEquals(2, entries.size());
@@ -315,7 +316,7 @@
         startNotificationService();
         DownloadNotificationService service = bindNotificationService();
         String guid = UUID.randomUUID().toString();
-        service.notifyDownloadSuccessful(guid, "/path/to/test", "test", 100L, false, false);
+        service.notifyDownloadSuccessful(guid, "/path/to/test", "test", 100L, false, false, false);
         assertEquals(1, getService().getNotificationIds().size());
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
index c5b99f67..6bc32bc7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
@@ -93,15 +93,14 @@
     }
 
     @Override
-    public int notifyDownloadSuccessful(
-            final String downloadGuid, final String filePath, final String fileName,
-            final long systemDownloadId, final boolean isOfflinePage,
-            final boolean isSupportedMimeType) {
+    public int notifyDownloadSuccessful(final String downloadGuid, final String filePath,
+            final String fileName, final long systemDownloadId, final boolean isOffTheRecord,
+            final boolean isOfflinePage, final boolean isSupportedMimeType) {
         return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer>() {
             @Override
             public Integer call() throws Exception {
-                return MockDownloadNotificationService.super.notifyDownloadSuccessful(
-                        downloadGuid, filePath, fileName, systemDownloadId, isOfflinePage,
+                return MockDownloadNotificationService.super.notifyDownloadSuccessful(downloadGuid,
+                        filePath, fileName, systemDownloadId, isOffTheRecord, isOfflinePage,
                         isSupportedMimeType);
             }
         });
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc
index 7bac0755..cf40708b 100644
--- a/chrome/app/chrome_exe_main_win.cc
+++ b/chrome/app/chrome_exe_main_win.cc
@@ -230,6 +230,7 @@
   HINSTANCE instance = GetModuleHandle(nullptr);
 #endif
   install_static::InitializeFromPrimaryModule();
+  SignalInitializeCrashReporting();
 
   // Initialize the CommandLine singleton from the environment.
   base::CommandLine::Init(0, nullptr);
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 8991b14d..8a4e8f2e 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -62,12 +62,13 @@
 #if defined(OS_WIN)
 #include <atlbase.h>
 #include <malloc.h>
+
 #include <algorithm>
+
 #include "base/debug/close_handle_hook_win.h"
 #include "chrome/browser/downgrade/user_data_downgrade.h"
 #include "chrome/child/v8_breakpad_support_win.h"
 #include "chrome/common/child_process_logging.h"
-#include "components/crash/content/app/crashpad.h"
 #include "sandbox/win/src/sandbox.h"
 #include "ui/base/resource/resource_bundle_win.h"
 #endif
@@ -78,7 +79,6 @@
 #include "chrome/browser/mac/relauncher.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/common/mac/cfbundle_blocker.h"
-#include "components/crash/content/app/crashpad.h"
 #include "components/crash/core/common/objc_zombie.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #endif
@@ -127,6 +127,7 @@
 
 #if defined(OS_MACOSX) || defined(OS_WIN)
 #include "chrome/browser/policy/policy_path_parser.h"
+#include "components/crash/content/app/crashpad.h"
 #endif
 
 #if defined(OS_CHROMEOS)
@@ -222,7 +223,7 @@
 #endif  // defined(OS_WIN)
 
 #if defined(OS_LINUX)
-static void AdjustLinuxOOMScore(const std::string& process_type) {
+void AdjustLinuxOOMScore(const std::string& process_type) {
   // Browsers and zygotes should still be killable, but killed last.
   const int kZygoteScore = 0;
   // The minimum amount to bump a score by.  This is large enough that
@@ -271,6 +272,9 @@
   } else {
     NOTREACHED() << "Unknown process type";
   }
+  // In the case of a 0 score, still try to adjust it. Most likely the score is
+  // 0 already, but it may not be if this process inherited a higher score from
+  // its parent process.
   if (score > -1)
     base::AdjustOOMScore(base::GetCurrentProcId(), score);
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 20521d5..0af3e63 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -12580,6 +12580,21 @@
           <message name="IDS_PIN_KEYBOARD_DELETE_ACCESSIBLE_NAME" desc="Text to be spoken when the focus is set to the delete button of the PIN keyboard.">
             Delete
           </message>
+          <message name="IDS_FINGERPRINT_HINT_TEXT" desc="Text to display in the password field for user pod when user moves his mouse over the fingerprint icon.">
+            Touch to sign in
+          </message>
+          <message name="IDS_FINGERPRINT_LOGIN_TEXT" desc="Text to display in the password field for user pod when user is trying to login with fingerprint.">
+            Signing in...
+          </message>
+          <message name="IDS_FINGERPRINT_LOGIN_FAILED_TEXT" desc="Text to display in the password field for user pod when user failed to login with fingerprint.">
+            Not recognized
+          </message>
+          <message name="IDS_FINGERPRINT_ICON_MESSAGE" desc="Message to display when user moves his mouse over the fingerprint icon in the user pod.">
+            Place your finger on the fingerprint sensor to unlock the device.
+          </message>
+          <message name="IDS_LOGIN_ERROR_FINGERPRINT_MAX_ATTEMPT" desc="Couldn't sign in because fingerprint unlock has reached maximum attempt">
+            Sorry, your fingerprint is still not recognized. Please enter your password.
+          </message>
         </if>
         <message name="IDS_LOGIN_ERROR_AUTHENTICATING" desc="Couldn't sign in because password is invalid">
           Sorry, your password could not be verified. Please try again.
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index b5d38e19..e8e554c 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -71,6 +71,8 @@
       if (suggestion.download_suggestion_extra()->is_download_asset) {
         Java_SnippetsBridge_setAssetDownloadDataForSuggestion(
             env, java_suggestion,
+            ConvertUTF8ToJavaString(
+                env, suggestion.download_suggestion_extra()->download_guid),
             ConvertUTF8ToJavaString(env, suggestion.download_suggestion_extra()
                                              ->target_file_path.value()),
             ConvertUTF8ToJavaString(
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 765ca42..8ee0da30 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -211,7 +211,6 @@
 #include "chrome/browser/win/browser_util.h"
 #include "chrome/browser/win/chrome_select_file_dialog_factory.h"
 #include "chrome/install_static/install_util.h"
-#include "components/crash/content/app/crashpad.h"
 #include "ui/base/l10n/l10n_util_win.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 #endif  // defined(OS_WIN)
@@ -1417,18 +1416,6 @@
 int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
   TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopRunImpl");
 
-#if defined(OS_WIN)
-  HMODULE chrome_elf = GetModuleHandle(chrome::kChromeElfDllName);
-  if (chrome_elf) {
-    auto block_until_handler_started = reinterpret_cast<void (*)()>(
-        GetProcAddress(chrome_elf, "BlockUntilHandlerStartedImpl"));
-    if (block_until_handler_started) {
-      SCOPED_UMA_HISTOGRAM_TIMER("Startup.BlockForCrashpadHandlerStartupTime");
-      block_until_handler_started();
-    }
-  }
-#endif
-
   SCOPED_UMA_HISTOGRAM_LONG_TIMER("Startup.PreMainMessageLoopRunImplLongTime");
   const base::TimeTicks start_time_step1 = base::TimeTicks::Now();
 
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
index d1029f88..534381c 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
@@ -41,8 +41,8 @@
 IN_PROC_BROWSER_TEST_F(EnrollmentScreenTest, TestCancel) {
   ASSERT_TRUE(WizardController::default_controller());
 
-  EnrollmentScreen* enrollment_screen =
-      EnrollmentScreen::Get(WizardController::default_controller());
+  EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(
+      WizardController::default_controller()->screen_manager());
   ASSERT_TRUE(enrollment_screen);
 
   base::RunLoop run_loop;
@@ -69,8 +69,8 @@
   ASSERT_TRUE(WizardController::default_controller());
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
 
-  EnrollmentScreen* enrollment_screen =
-      EnrollmentScreen::Get(WizardController::default_controller());
+  EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(
+      WizardController::default_controller()->screen_manager());
   ASSERT_TRUE(enrollment_screen);
 
   base::RunLoop run_loop;
@@ -105,8 +105,8 @@
 IN_PROC_BROWSER_TEST_F(AttestationAuthEnrollmentScreenTest, TestCancel) {
   ASSERT_TRUE(WizardController::default_controller());
 
-  EnrollmentScreen* enrollment_screen =
-      EnrollmentScreen::Get(WizardController::default_controller());
+  EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(
+      WizardController::default_controller()->screen_manager());
   ASSERT_TRUE(enrollment_screen);
 
   base::RunLoop run_loop;
@@ -133,7 +133,8 @@
   WizardController* wcontroller = WizardController::default_controller();
   ASSERT_TRUE(wcontroller);
 
-  EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(wcontroller);
+  EnrollmentScreen* enrollment_screen =
+      EnrollmentScreen::Get(wcontroller->screen_manager());
   ASSERT_TRUE(enrollment_screen);
 
   EnrollmentScreenView* view = enrollment_screen->GetView();
@@ -177,8 +178,8 @@
 IN_PROC_BROWSER_TEST_F(ForcedAttestationAuthEnrollmentScreenTest, TestCancel) {
   ASSERT_TRUE(WizardController::default_controller());
 
-  EnrollmentScreen* enrollment_screen =
-      EnrollmentScreen::Get(WizardController::default_controller());
+  EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(
+      WizardController::default_controller()->screen_manager());
   ASSERT_TRUE(enrollment_screen);
 
   base::RunLoop run_loop;
@@ -224,8 +225,8 @@
 IN_PROC_BROWSER_TEST_F(MultiAuthEnrollmentScreenTest, TestCancel) {
   ASSERT_TRUE(WizardController::default_controller());
 
-  EnrollmentScreen* enrollment_screen =
-      EnrollmentScreen::Get(WizardController::default_controller());
+  EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(
+      WizardController::default_controller()->screen_manager());
   ASSERT_TRUE(enrollment_screen);
 
   base::RunLoop run_loop;
@@ -269,8 +270,8 @@
 IN_PROC_BROWSER_TEST_F(ProvisionedEnrollmentScreenTest, TestBackButton) {
   ASSERT_TRUE(WizardController::default_controller());
 
-  EnrollmentScreen* enrollment_screen =
-      EnrollmentScreen::Get(WizardController::default_controller());
+  EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(
+      WizardController::default_controller()->screen_manager());
   ASSERT_TRUE(enrollment_screen);
 
   base::RunLoop run_loop;
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 41f22f90..7b602e2 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -201,7 +201,8 @@
 
   // Helper method to return the current EnrollmentScreen instance.
   EnrollmentScreen* enrollment_screen() {
-    return EnrollmentScreen::Get(WizardController::default_controller());
+    return EnrollmentScreen::Get(
+        WizardController::default_controller()->screen_manager());
   }
 
  private:
diff --git a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
index 8dd3473..b389b27 100644
--- a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
@@ -94,8 +94,8 @@
 class LanguageListWaiter : public NetworkScreen::Observer {
  public:
   LanguageListWaiter()
-      : network_screen_(
-            NetworkScreen::Get(WizardController::default_controller())),
+      : network_screen_(NetworkScreen::Get(
+            WizardController::default_controller()->screen_manager())),
         loop_(base::TimeDelta::FromSeconds(kTimeoutSeconds), "LanguageList") {
     network_screen_->AddObserver(this);
     CheckLanguageList();
diff --git a/chrome/browser/chromeos/login/screen_manager.cc b/chrome/browser/chromeos/login/screen_manager.cc
index 8457c5a6..23ee4fa 100644
--- a/chrome/browser/chromeos/login/screen_manager.cc
+++ b/chrome/browser/chromeos/login/screen_manager.cc
@@ -4,22 +4,24 @@
 
 #include "chrome/browser/chromeos/login/screen_manager.h"
 
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+
 namespace chromeos {
 
-ScreenManager::ScreenManager() {
-}
+ScreenManager::ScreenManager(WizardController* wizard_controller)
+    : wizard_controller_(wizard_controller) {}
 
-ScreenManager::~ScreenManager() {
-}
+ScreenManager::~ScreenManager() {}
 
 BaseScreen* ScreenManager::GetScreen(OobeScreen screen) {
   auto iter = screens_.find(screen);
   if (iter != screens_.end())
     return iter->second.get();
 
-  BaseScreen* result = CreateScreen(screen);
+  BaseScreen* result = wizard_controller_->CreateScreen(screen);
   DCHECK(result) << "Can not create screen named " << GetOobeScreenName(screen);
-  screens_[screen] = make_linked_ptr(result);
+  screens_[screen] = base::WrapUnique(result);
   return result;
 }
 
diff --git a/chrome/browser/chromeos/login/screen_manager.h b/chrome/browser/chromeos/login/screen_manager.h
index 360d2b2..e0b1383 100644
--- a/chrome/browser/chromeos/login/screen_manager.h
+++ b/chrome/browser/chromeos/login/screen_manager.h
@@ -6,26 +6,26 @@
 #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_MANAGER_H_
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
 
 namespace chromeos {
 
+class WizardController;
+
 // Class that manages creation and ownership of screens.
 class ScreenManager {
  public:
-  ScreenManager();
-  virtual ~ScreenManager();
+  // |wizard_controller| is not owned by this class.
+  explicit ScreenManager(WizardController* wizard_controller);
+  ~ScreenManager();
 
   // Getter for screen with lazy initialization.
-  virtual BaseScreen* GetScreen(OobeScreen screen);
-
-  // Factory for screen instances.
-  virtual BaseScreen* CreateScreen(OobeScreen screen) = 0;
+  BaseScreen* GetScreen(OobeScreen screen);
 
   bool HasScreen(OobeScreen screen);
 
@@ -37,8 +37,11 @@
   friend class WizardInProcessBrowserTest;
   friend class WizardControllerBrokenLocalStateTest;
 
-  // Screens.
-  std::map<OobeScreen, linked_ptr<BaseScreen>> screens_;
+  // Created screens.
+  std::map<OobeScreen, std::unique_ptr<BaseScreen>> screens_;
+
+  // Used to allocate BaseScreen instances. Unowned.
+  WizardController* wizard_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenManager);
 };
diff --git a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
index 55da5eb..3337dee 100644
--- a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
@@ -71,8 +71,8 @@
     WizardInProcessBrowserTest::SetUpOnMainThread();
     mock_base_screen_delegate_.reset(new MockBaseScreenDelegate());
     ASSERT_TRUE(WizardController::default_controller() != nullptr);
-    network_screen_ =
-        NetworkScreen::Get(WizardController::default_controller());
+    network_screen_ = NetworkScreen::Get(
+        WizardController::default_controller()->screen_manager());
     ASSERT_TRUE(network_screen_ != nullptr);
     ASSERT_EQ(WizardController::default_controller()->current_screen(),
               network_screen_);
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
index 0eff6659..84dbbc8 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -83,9 +83,10 @@
 
     WizardInProcessBrowserTest::SetUpOnMainThread();
 
-    ASSERT_TRUE(WizardController::default_controller() != NULL);
-    update_screen_ = UpdateScreen::Get(WizardController::default_controller());
-    ASSERT_TRUE(update_screen_ != NULL);
+    ASSERT_TRUE(WizardController::default_controller() != nullptr);
+    update_screen_ = UpdateScreen::Get(
+        WizardController::default_controller()->screen_manager());
+    ASSERT_TRUE(update_screen_ != nullptr);
     ASSERT_EQ(WizardController::default_controller()->current_screen(),
               update_screen_);
     update_screen_->base_screen_delegate_ = mock_base_screen_delegate_.get();
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
index 394046d..ff70fbbd 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
@@ -18,8 +18,8 @@
 SupervisedUserCreationScreen* GetScreen(LoginDisplayHost* host) {
   DCHECK(host);
   DCHECK(host->GetWizardController());
-  SupervisedUserCreationScreen* result =
-      SupervisedUserCreationScreen::Get(host->GetWizardController());
+  SupervisedUserCreationScreen* result = SupervisedUserCreationScreen::Get(
+      host->GetWizardController()->screen_manager());
   DCHECK(result);
   return result;
 }
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc b/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
index 9ec5471..747c037 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
@@ -189,7 +189,8 @@
 bool UserImageSyncObserver::CanUpdateLocalImageNow() {
   if (WizardController* wizard_controller =
           WizardController::default_controller()) {
-    UserImageScreen* screen = UserImageScreen::Get(wizard_controller);
+    UserImageScreen* screen =
+        UserImageScreen::Get(wizard_controller->screen_manager());
     if (wizard_controller->current_screen() == screen) {
       if (screen->user_selected_image())
         return false;
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index eeb7042c..b06e37f 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -251,7 +251,10 @@
 PrefService* WizardController::local_state_for_testing_ = nullptr;
 
 WizardController::WizardController(LoginDisplayHost* host, OobeUI* oobe_ui)
-    : host_(host), oobe_ui_(oobe_ui), weak_factory_(this) {
+    : screen_manager_(this),
+      host_(host),
+      oobe_ui_(oobe_ui),
+      weak_factory_(this) {
   DCHECK(default_controller_ == nullptr);
   default_controller_ = this;
   if (!ash_util::IsRunningInMash()) {
@@ -358,7 +361,7 @@
 BaseScreen* WizardController::GetScreen(OobeScreen screen) {
   if (screen == OobeScreen::SCREEN_ERROR_MESSAGE)
     return GetErrorScreen();
-  return ScreenManager::GetScreen(screen);
+  return screen_manager_.GetScreen(screen);
 }
 
 BaseScreen* WizardController::CreateScreen(OobeScreen screen) {
@@ -430,7 +433,8 @@
   VLOG(1) << "Showing network screen.";
   // Hide the status area initially; it only appears after OOBE first animates
   // in. Keep it visible if the user goes back to the existing network screen.
-  SetStatusAreaVisible(HasScreen(OobeScreen::SCREEN_OOBE_NETWORK));
+  SetStatusAreaVisible(
+      screen_manager_.HasScreen(OobeScreen::SCREEN_OOBE_NETWORK));
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_NETWORK));
 
   // There are two possible screens where we listen to the incoming Bluetooth
@@ -582,7 +586,8 @@
 void WizardController::ShowAutoEnrollmentCheckScreen() {
   VLOG(1) << "Showing Auto-enrollment check screen.";
   SetStatusAreaVisible(true);
-  AutoEnrollmentCheckScreen* screen = AutoEnrollmentCheckScreen::Get(this);
+  AutoEnrollmentCheckScreen* screen =
+      AutoEnrollmentCheckScreen::Get(screen_manager());
   if (retry_auto_enrollment_check_)
     screen->ClearState();
   screen->set_auto_enrollment_controller(host_->GetAutoEnrollmentController());
@@ -893,7 +898,7 @@
 void WizardController::StartOOBEUpdate() {
   VLOG(1) << "StartOOBEUpdate";
   SetCurrentScreenSmooth(GetScreen(OobeScreen::SCREEN_OOBE_UPDATE), true);
-  UpdateScreen::Get(this)->StartNetworkCheck();
+  UpdateScreen::Get(screen_manager())->StartNetworkCheck();
 }
 
 void WizardController::StartTimezoneResolve() {
@@ -1195,7 +1200,7 @@
 void WizardController::SetHostNetwork() {
   if (!shark_controller_)
     return;
-  NetworkScreen* network_screen = NetworkScreen::Get(this);
+  NetworkScreen* network_screen = NetworkScreen::Get(screen_manager());
   std::string onc_spec;
   network_screen->GetConnectedWifiNetwork(&onc_spec);
   if (!onc_spec.empty())
@@ -1205,7 +1210,7 @@
 void WizardController::SetHostConfiguration() {
   if (!shark_controller_)
     return;
-  NetworkScreen* network_screen = NetworkScreen::Get(this);
+  NetworkScreen* network_screen = NetworkScreen::Get(screen_manager());
   shark_controller_->SetHostConfiguration(
       true,  // Eula must be accepted before we get this far.
       network_screen->GetApplicationLocale(), network_screen->GetTimezone(),
@@ -1224,7 +1229,7 @@
     StartupUtils::MarkEulaAccepted();
   SetUsageStatisticsReporting(send_reports);
 
-  NetworkScreen* network_screen = NetworkScreen::Get(this);
+  NetworkScreen* network_screen = NetworkScreen::Get(screen_manager());
   network_screen->SetApplicationLocaleAndInputMethod(lang, keyboard_layout);
   network_screen->SetTimezone(timezone);
 
@@ -1241,7 +1246,7 @@
   remora_controller_->OnNetworkConnectivityChanged(
       pairing_chromeos::HostPairingController::CONNECTIVITY_CONNECTING);
 
-  NetworkScreen* network_screen = NetworkScreen::Get(this);
+  NetworkScreen* network_screen = NetworkScreen::Get(screen_manager());
   const chromeos::NetworkState* network_state = chromeos::NetworkHandler::Get()
                                                     ->network_state_handler()
                                                     ->DefaultNetwork();
@@ -1506,7 +1511,7 @@
             : policy::EnrollmentConfig::MODE_MANUAL_REENROLLMENT;
   }
 
-  EnrollmentScreen* screen = EnrollmentScreen::Get(this);
+  EnrollmentScreen* screen = EnrollmentScreen::Get(screen_manager());
   screen->SetParameters(effective_config, shark_controller_.get());
   SetStatusAreaVisible(true);
   SetCurrentScreen(screen);
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index d11dffc..8e9d150 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -51,7 +51,6 @@
 // Class that manages control flow between wizard screens. Wizard controller
 // interacts with screen controllers to move the user between screens.
 class WizardController : public BaseScreenDelegate,
-                         public ScreenManager,
                          public EulaScreen::Delegate,
                          public ControllerPairingScreen::Delegate,
                          public HostPairingScreen::Delegate,
@@ -113,13 +112,19 @@
   // Returns true if the current wizard instance has reached the login screen.
   bool login_screen_started() const { return login_screen_started_; }
 
-  // ScreenManager implementation.
-  BaseScreen* GetScreen(OobeScreen screen) override;
-  BaseScreen* CreateScreen(OobeScreen screen) override;
+  // Returns a given screen. Creates it lazily.
+  BaseScreen* GetScreen(OobeScreen screen);
+
+  // Returns the current ScreenManager instance.
+  ScreenManager* screen_manager() { return &screen_manager_; }
 
   // Volume percent at which spoken feedback is still audible.
   static const int kMinAudibleOutputVolumePercent;
 
+  // Allocate a given BaseScreen for the given |Screen|. Used by
+  // |screen_manager_|.
+  BaseScreen* CreateScreen(OobeScreen screen);
+
  private:
   // Show specific screen.
   void ShowNetworkScreen();
@@ -300,6 +305,8 @@
   // attestation-based enrollment if appropriate.
   void StartEnrollmentScreen(bool force_interactive);
 
+  ScreenManager screen_manager_;
+
   // Whether to skip any screens that may normally be shown after login
   // (registration, Terms of Service, user image selection).
   static bool skip_post_login_screens_;
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index bb21659..fc2123da 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -222,20 +222,22 @@
   std::unique_ptr<H> view_;
 };
 
-#define MOCK(mock_var, screen_name, mocked_class, view_class)     \
-  mock_var = new MockOutShowHide<mocked_class, view_class>(       \
-      WizardController::default_controller(), new view_class);    \
-  WizardController::default_controller()->screens_[screen_name] = \
-      make_linked_ptr(mock_var);                                  \
-  EXPECT_CALL(*mock_var, Show()).Times(0);                        \
+#define MOCK(mock_var, screen_name, mocked_class, view_class)  \
+  mock_var = new MockOutShowHide<mocked_class, view_class>(    \
+      WizardController::default_controller(), new view_class); \
+  WizardController::default_controller()                       \
+      ->screen_manager()                                       \
+      ->screens_[screen_name] = base::WrapUnique(mock_var);    \
+  EXPECT_CALL(*mock_var, Show()).Times(0);                     \
   EXPECT_CALL(*mock_var, Hide()).Times(0);
 
 #define MOCK_WITH_DELEGATE(mock_var, screen_name, mocked_class, view_class) \
   mock_var = new MockOutShowHide<mocked_class, view_class>(                 \
       WizardController::default_controller(),                               \
       WizardController::default_controller(), new view_class);              \
-  WizardController::default_controller()->screens_[screen_name] =           \
-      make_linked_ptr(mock_var);                                            \
+  WizardController::default_controller()                                    \
+      ->screen_manager()                                                    \
+      ->screens_[screen_name] = base::WrapUnique(mock_var);                 \
   EXPECT_CALL(*mock_var, Show()).Times(0);                                  \
   EXPECT_CALL(*mock_var, Hide()).Times(0);
 
@@ -419,11 +421,13 @@
     NetworkHandler::Get()->network_state_handler()->SetCheckPortalList("");
 
     // Set up the mocks for all screens.
-    mock_network_screen_.reset(new MockNetworkScreen(
+    mock_network_screen_ = new MockNetworkScreen(
         WizardController::default_controller(),
-        WizardController::default_controller(), GetOobeUI()->GetNetworkView()));
+        WizardController::default_controller(), GetOobeUI()->GetNetworkView());
     WizardController::default_controller()
-        ->screens_[OobeScreen::SCREEN_OOBE_NETWORK] = mock_network_screen_;
+        ->screen_manager()
+        ->screens_[OobeScreen::SCREEN_OOBE_NETWORK]
+        .reset(mock_network_screen_);
     EXPECT_CALL(*mock_network_screen_, Show()).Times(0);
     EXPECT_CALL(*mock_network_screen_, Hide()).Times(0);
 
@@ -442,9 +446,10 @@
          OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING, MockEnableDebuggingScreen,
          MockEnableDebuggingScreenView);
     device_disabled_screen_view_.reset(new MockDeviceDisabledScreenView);
-    wizard_controller->screens_[OobeScreen::SCREEN_DEVICE_DISABLED] =
-        make_linked_ptr(new DeviceDisabledScreen(
-            wizard_controller, device_disabled_screen_view_.get()));
+    wizard_controller->screen_manager()
+        ->screens_[OobeScreen::SCREEN_DEVICE_DISABLED] =
+        base::MakeUnique<DeviceDisabledScreen>(
+            wizard_controller, device_disabled_screen_view_.get());
     EXPECT_CALL(*device_disabled_screen_view_, Show()).Times(0);
 
     // Switch to the initial screen.
@@ -454,7 +459,7 @@
   }
 
   void TearDownOnMainThread() override {
-    mock_network_screen_.reset();
+    mock_network_screen_ = nullptr;
     device_disabled_screen_view_.reset();
     WizardControllerTest::TearDownOnMainThread();
   }
@@ -512,7 +517,7 @@
   }
 
   void ResetAutoEnrollmentCheckScreen() {
-    WizardController::default_controller()->screens_.erase(
+    WizardController::default_controller()->screen_manager()->screens_.erase(
         OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
   }
 
@@ -567,7 +572,7 @@
                               ->GetCurrentTimezoneID()));
   }
 
-  linked_ptr<MockNetworkScreen> mock_network_screen_;
+  MockNetworkScreen* mock_network_screen_;  // Unowned ptr.
   MockOutShowHide<MockUpdateScreen, MockUpdateView>* mock_update_screen_;
   MockOutShowHide<MockEulaScreen, MockEulaView>* mock_eula_screen_;
   MockOutShowHide<MockEnrollmentScreen, MockEnrollmentScreenView>*
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
index d333cb9..9806dd7b 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
@@ -33,6 +33,9 @@
 // The rate in milliseconds at which we will poll CUPS for print job updates.
 const int kPollRate = 1000;
 
+// Threshold for giving up on communicating with CUPS.
+const int kRetryMax = 6;
+
 // Returns the equivalient CupsPrintJob#State from a CupsJob#JobState.
 chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) {
   using cpj = chromeos::CupsPrintJob::State;
@@ -61,6 +64,13 @@
   return cpj::STATE_NONE;
 }
 
+chromeos::QueryResult QueryCups(::printing::CupsConnection* connection,
+                                const std::vector<std::string>& printer_ids) {
+  chromeos::QueryResult result;
+  result.success = connection->GetJobs(printer_ids, &result.queues);
+  return result;
+}
+
 }  // namespace
 
 namespace chromeos {
@@ -134,6 +144,7 @@
                                             total_page_number);
   std::string key = cpj->GetUniqueId();
   jobs_[key] = std::move(cpj);
+
   CupsPrintJob* job = jobs_[key].get();
   NotifyJobCreated(job);
 
@@ -153,36 +164,67 @@
 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) {
   if (!in_query_) {
     in_query_ = true;
-    content::BrowserThread::PostDelayedTask(
-        content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
-        base::Bind(&CupsPrintJobManagerImpl::QueryCups,
+
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&CupsPrintJobManagerImpl::PostQuery,
                    weak_ptr_factory_.GetWeakPtr()),
-        base::TimeDelta::FromMilliseconds(kPollRate));
+        delay);
   }
 }
 
-// Query CUPS asynchronously.  Post results back to UI thread.
-void CupsPrintJobManagerImpl::QueryCups() {
-  std::vector<::printing::CupsJob> jobs = cups_connection_.GetJobs();
+void CupsPrintJobManagerImpl::PostQuery() {
+  // The set of active printers is expected to be small.
+  std::set<std::string> printer_ids;
+  for (const auto& entry : jobs_) {
+    printer_ids.insert(entry.second->printer().id());
+  }
+  std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
 
-  content::BrowserThread::PostTask(
-      content::BrowserThread::ID::UI, FROM_HERE,
+  content::BrowserThread::PostTaskAndReplyWithResult(
+      content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
+      base::Bind(&QueryCups, &cups_connection_, ids),
       base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
-                 weak_ptr_factory_.GetWeakPtr(), jobs));
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 // Use job information to update local job states.  Previously completed jobs
 // could be in |jobs| but those are ignored as we will not emit updates for them
 // after they are completed.
-void CupsPrintJobManagerImpl::UpdateJobs(
-    const std::vector<::printing::CupsJob>& jobs) {
+void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) {
+  const std::vector<::printing::QueueStatus>& queues = result.queues;
+
+  // Query has completed.  Allow more queries.
   in_query_ = false;
 
+  // If the query failed, either retry or purge.
+  if (!result.success) {
+    retry_count_++;
+    LOG(WARNING) << "Failed to query CUPS for queue status.  Schedule retry ("
+                 << retry_count_ << ")";
+    if (retry_count_ > kRetryMax) {
+      LOG(ERROR) << "CUPS is unreachable.  Giving up on all jobs.";
+      PurgeJobs();
+    } else {
+      // Schedule another query with a larger delay.
+      DCHECK_GE(1, retry_count_);
+      ScheduleQuery(
+          base::TimeDelta::FromMilliseconds(kPollRate * retry_count_));
+    }
+    return;
+  }
+
+  // A query has completed.  Reset retry counter.
+  retry_count_ = 0;
+
   std::vector<std::string> active_jobs;
-  for (auto& job : jobs) {
-    std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
-    const auto& entry = jobs_.find(key);
-    if (entry != jobs_.end()) {
+  for (const auto& queue : queues) {
+    for (auto& job : queue.jobs) {
+      std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
+      const auto& entry = jobs_.find(key);
+      if (entry == jobs_.end())
+        continue;
+
       CupsPrintJob* print_job = entry->second.get();
 
       // Update a job we're tracking.
@@ -199,20 +241,25 @@
 
   // Keep polling until all jobs complete or error.
   if (!active_jobs.empty()) {
+    // During normal operations, we poll at the default rate.
     ScheduleQuery();
   } else if (!jobs_.empty()) {
     // We're tracking jobs that we didn't receive an update for.  Something bad
     // has happened.
     LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
-    for (const auto& entry : jobs_) {
-      // Declare all lost jobs errors.
-      JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
-    }
-
-    jobs_.clear();
+    PurgeJobs();
   }
 }
 
+void CupsPrintJobManagerImpl::PurgeJobs() {
+  for (const auto& entry : jobs_) {
+    // Declare all lost jobs errors.
+    JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
+  }
+
+  jobs_.clear();
+}
+
 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job,
                                               CupsPrintJob::State new_state) {
   if (job->state() == new_state)
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
index afd64c9..d32066d6 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
@@ -23,6 +23,11 @@
 
 namespace chromeos {
 
+struct QueryResult {
+  bool success;
+  std::vector<::printing::QueueStatus> queues;
+};
+
 class CupsPrintJobManagerImpl : public CupsPrintJobManager,
                                 public content::NotificationObserver {
  public:
@@ -52,11 +57,15 @@
   // Schedule a query of CUPS for print job status with a delay of |delay|.
   void ScheduleQuery(const base::TimeDelta& delay);
 
-  // Query CUPS for print job status.
-  void QueryCups();
+  // Schedule the CUPS query off the UI thread. Posts results back to UI thread
+  // to UpdateJobs.
+  void PostQuery();
 
   // Process jobs from CUPS and perform notifications.
-  void UpdateJobs(const std::vector<::printing::CupsJob>& jobs);
+  void UpdateJobs(const QueryResult& results);
+
+  // Mark remaining jobs as errors and remove active jobs.
+  void PurgeJobs();
 
   // Updates the state and performs the appropriate notifications.
   void JobStateUpdated(CupsPrintJob* job, CupsPrintJob::State new_state);
@@ -67,6 +76,9 @@
   // Prevents multiple queries from being scheduled simultaneously.
   bool in_query_ = false;
 
+  // Records the number of consecutive times the GetJobs query has failed.
+  int retry_count_ = 0;
+
   ::printing::CupsConnection cups_connection_;
   content::NotificationRegistrar registrar_;
   base::WeakPtrFactory<CupsPrintJobManagerImpl> weak_ptr_factory_;
diff --git a/chrome/browser/extensions/signin/OWNERS b/chrome/browser/extensions/signin/OWNERS
index 0a53d1b..35b5a0ac 100644
--- a/chrome/browser/extensions/signin/OWNERS
+++ b/chrome/browser/extensions/signin/OWNERS
@@ -1,3 +1,4 @@
 xiyuan@chromium.org
-guohui@chromium.org
 rogerta@chromium.org
+
+# COMPONENT: Services>SignIn
diff --git a/chrome/browser/ntp_snippets/download_suggestions_provider.cc b/chrome/browser/ntp_snippets/download_suggestions_provider.cc
index 9d38a9e..58dab7d 100644
--- a/chrome/browser/ntp_snippets/download_suggestions_provider.cc
+++ b/chrome/browser/ntp_snippets/download_suggestions_provider.cc
@@ -617,6 +617,7 @@
   suggestion.set_publisher_name(
       base::UTF8ToUTF16(download_item.GetURL().host()));
   auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>();
+  extra->download_guid = download_item.GetGuid();
   extra->target_file_path = download_item.GetTargetFilePath();
   extra->mime_type = download_item.GetMimeType();
   extra->is_download_asset = true;
diff --git a/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc b/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc
index 0b0b51e..c5f2773b 100644
--- a/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc
+++ b/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc
@@ -150,6 +150,7 @@
   std::unique_ptr<FakeDownloadItem> item = base::MakeUnique<FakeDownloadItem>();
   item->SetId(id);
   std::string id_string = base::IntToString(id);
+  item->SetGuid("XYZ-100032-EFZBDF-13323-PXZ" + id_string);
   item->SetTargetFilePath(
       base::FilePath::FromUTF8Unsafe("folder/file" + id_string + ".mhtml"));
   item->SetURL(GURL("http://download.com/redirected" + id_string));
diff --git a/chrome/browser/ntp_snippets/fake_download_item.cc b/chrome/browser/ntp_snippets/fake_download_item.cc
index 05d8a52..39eb275 100644
--- a/chrome/browser/ntp_snippets/fake_download_item.cc
+++ b/chrome/browser/ntp_snippets/fake_download_item.cc
@@ -55,6 +55,14 @@
   return id_;
 }
 
+void FakeDownloadItem::SetGuid(const std::string& guid) {
+  guid_ = guid;
+}
+
+const std::string& FakeDownloadItem::GetGuid() const {
+  return guid_;
+}
+
 void FakeDownloadItem::SetURL(const GURL& url) {
   url_ = url;
 }
@@ -156,11 +164,6 @@
   NOTREACHED();
 }
 
-const std::string& FakeDownloadItem::GetGuid() const {
-  NOTREACHED();
-  return dummy_string;
-}
-
 content::DownloadInterruptReason FakeDownloadItem::GetLastReason() const {
   NOTREACHED();
   return content::DownloadInterruptReason();
diff --git a/chrome/browser/ntp_snippets/fake_download_item.h b/chrome/browser/ntp_snippets/fake_download_item.h
index c91dfd9..37e36146 100644
--- a/chrome/browser/ntp_snippets/fake_download_item.h
+++ b/chrome/browser/ntp_snippets/fake_download_item.h
@@ -39,6 +39,9 @@
   void SetId(uint32_t id);
   uint32_t GetId() const override;
 
+  void SetGuid(const std::string& guid);
+  const std::string& GetGuid() const override;
+
   void SetURL(const GURL& url);
   const GURL& GetURL() const override;
 
@@ -73,7 +76,6 @@
   void Remove() override;
   void OpenDownload() override;
   void ShowDownloadInShell() override;
-  const std::string& GetGuid() const override;
   content::DownloadInterruptReason GetLastReason() const override;
   bool IsPaused() const override;
   bool IsTemporary() const override;
@@ -129,6 +131,7 @@
  private:
   base::ObserverList<Observer> observers_;
   uint32_t id_;
+  std::string guid_;
   GURL url_;
   base::FilePath file_path_;
   bool is_file_externally_removed_;
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index 2b80325..29b01b3 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -4,9 +4,13 @@
 
 #include "chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/nqe/ui_network_quality_estimator_service.h"
+#include "chrome/browser/net/nqe/ui_network_quality_estimator_service_factory.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "chrome/browser/profiles/profile.h"
 #include "components/ukm/ukm_entry_builder.h"
 #include "components/ukm/ukm_service.h"
+#include "content/public/browser/web_contents.h"
 
 namespace internal {
 
@@ -20,21 +24,39 @@
 const char kUkmFirstMeaningfulPaintName[] =
     "Experimental.PaintTiming.NavigationToFirstMeaningfulPaint";
 const char kUkmForegroundDurationName[] = "PageTiming.ForegroundDuration";
+const char kUkmEffectiveConnectionType[] =
+    "Net.EffectiveConnectionType.OnNavigationStart";
 
 }  // namespace internal
 
+namespace {
+
+UINetworkQualityEstimatorService* GetNQEService(
+    content::WebContents* web_contents) {
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  if (!profile)
+    return nullptr;
+  return UINetworkQualityEstimatorServiceFactory::GetForProfile(profile);
+}
+
+}  // namespace
+
 // static
 std::unique_ptr<page_load_metrics::PageLoadMetricsObserver>
-UkmPageLoadMetricsObserver::CreateIfNeeded() {
+UkmPageLoadMetricsObserver::CreateIfNeeded(content::WebContents* web_contents) {
   if (!g_browser_process->ukm_service()) {
     return nullptr;
   }
-
-  return base::MakeUnique<UkmPageLoadMetricsObserver>();
+  return base::MakeUnique<UkmPageLoadMetricsObserver>(
+      GetNQEService(web_contents));
 }
 
-UkmPageLoadMetricsObserver::UkmPageLoadMetricsObserver()
-    : source_id_(ukm::UkmService::GetNewSourceID()) {}
+UkmPageLoadMetricsObserver::UkmPageLoadMetricsObserver(
+    net::NetworkQualityEstimator::NetworkQualityProvider*
+        network_quality_provider)
+    : network_quality_provider_(network_quality_provider),
+      source_id_(ukm::UkmService::GetNewSourceID()) {}
 
 UkmPageLoadMetricsObserver::~UkmPageLoadMetricsObserver() = default;
 
@@ -45,8 +67,17 @@
   if (!started_in_foreground)
     return STOP_OBSERVING;
 
-  ukm::UkmService* ukm_service = g_browser_process->ukm_service();
-  ukm_service->UpdateSourceURL(source_id_, navigation_handle->GetURL());
+  // When OnStart is invoked, we don't yet know whether we're observing a web
+  // page load, vs another kind of load (e.g. a download or a PDF). Thus,
+  // metrics and source information should not be recorded here. Instead, we
+  // store data we might want to persist in member variables below, and later
+  // record UKM metrics for that data once we've confirmed that we're observing
+  // a web page load.
+
+  if (network_quality_provider_) {
+    effective_connection_type_ =
+        network_quality_provider_->GetEffectiveConnectionType();
+  }
   return CONTINUE_OBSERVING;
 }
 
@@ -54,17 +85,17 @@
 UkmPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordTimingMetrics(timing);
   RecordPageLoadExtraInfoMetrics(info, base::TimeTicks::Now());
+  RecordTimingMetrics(timing);
   return STOP_OBSERVING;
 }
 
 UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnHidden(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordTimingMetrics(timing);
   RecordPageLoadExtraInfoMetrics(
       info, base::TimeTicks() /* no app_background_time */);
+  RecordTimingMetrics(timing);
   return STOP_OBSERVING;
 }
 
@@ -78,9 +109,9 @@
 void UkmPageLoadMetricsObserver::OnComplete(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordTimingMetrics(timing);
   RecordPageLoadExtraInfoMetrics(
       info, base::TimeTicks() /* no app_background_time */);
+  RecordTimingMetrics(timing);
 }
 
 void UkmPageLoadMetricsObserver::RecordTimingMetrics(
@@ -115,16 +146,20 @@
     const page_load_metrics::PageLoadExtraInfo& info,
     base::TimeTicks app_background_time) {
   ukm::UkmService* ukm_service = g_browser_process->ukm_service();
+  ukm_service->UpdateSourceURL(source_id_, info.start_url);
   ukm_service->UpdateSourceURL(source_id_, info.url);
 
+  std::unique_ptr<ukm::UkmEntryBuilder> builder =
+      ukm_service->GetEntryBuilder(source_id_, internal::kUkmPageLoadEventName);
   base::Optional<base::TimeDelta> foreground_duration =
       page_load_metrics::GetInitialForegroundDuration(info,
                                                       app_background_time);
   if (foreground_duration) {
-    std::unique_ptr<ukm::UkmEntryBuilder> builder =
-        ukm_service->GetEntryBuilder(source_id_,
-                                     internal::kUkmPageLoadEventName);
     builder->AddMetric(internal::kUkmForegroundDurationName,
                        foreground_duration.value().InMilliseconds());
   }
+  if (effective_connection_type_ != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
+    builder->AddMetric(internal::kUkmEffectiveConnectionType,
+                       static_cast<int64_t>(effective_connection_type_));
+  }
 }
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
index 59df31f..16dfbbb 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -7,6 +7,11 @@
 
 #include "base/macros.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
+#include "net/nqe/network_quality_estimator.h"
+
+namespace content {
+class WebContents;
+}
 
 namespace internal {
 
@@ -18,6 +23,7 @@
 extern const char kUkmFirstContentfulPaintName[];
 extern const char kUkmFirstMeaningfulPaintName[];
 extern const char kUkmForegroundDurationName[];
+extern const char kUkmEffectiveConnectionType[];
 
 }  // namespace internal
 
@@ -28,9 +34,11 @@
  public:
   // Returns a UkmPageLoadMetricsObserver, or nullptr if it is not needed.
   static std::unique_ptr<page_load_metrics::PageLoadMetricsObserver>
-  CreateIfNeeded();
+  CreateIfNeeded(content::WebContents* web_contents);
 
-  UkmPageLoadMetricsObserver();
+  explicit UkmPageLoadMetricsObserver(
+      net::NetworkQualityEstimator::NetworkQualityProvider*
+          network_quality_provider);
   ~UkmPageLoadMetricsObserver() override;
 
   // page_load_metrics::PageLoadMetricsObserver implementation:
@@ -65,9 +73,15 @@
       const page_load_metrics::PageLoadExtraInfo& info,
       base::TimeTicks app_background_time);
 
+  net::NetworkQualityEstimator::NetworkQualityProvider* const
+      network_quality_provider_;
+
   // Unique UKM identifier for the page load we are recording metrics for.
   const int32_t source_id_;
 
+  net::EffectiveConnectionType effective_connection_type_ =
+      net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+
   DISALLOW_COPY_AND_ASSIGN(UkmPageLoadMetricsObserver);
 };
 
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index e5bf87d..fa4dc6c 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -12,24 +12,47 @@
 #include "components/ukm/test_ukm_service.h"
 #include "components/ukm/ukm_entry.h"
 #include "components/ukm/ukm_source.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::AnyNumber;
+using testing::Mock;
+using testing::Return;
 
 namespace {
 
 const char kTestUrl1[] = "https://www.google.com/";
 const char kTestUrl2[] = "https://www.example.com/";
 
+class MockNetworkQualityProvider
+    : public net::NetworkQualityEstimator::NetworkQualityProvider {
+ public:
+  MOCK_CONST_METHOD0(GetEffectiveConnectionType,
+                     net::EffectiveConnectionType());
+  MOCK_METHOD1(
+      AddEffectiveConnectionTypeObserver,
+      void(net::NetworkQualityEstimator::EffectiveConnectionTypeObserver*));
+  MOCK_METHOD1(
+      RemoveEffectiveConnectionTypeObserver,
+      void(net::NetworkQualityEstimator::EffectiveConnectionTypeObserver*));
+};
+
 }  // namespace
 
 class UkmPageLoadMetricsObserverTest
     : public page_load_metrics::PageLoadMetricsObserverTestHarness {
  protected:
   void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
-    tracker->AddObserver(base::MakeUnique<UkmPageLoadMetricsObserver>());
+    tracker->AddObserver(base::MakeUnique<UkmPageLoadMetricsObserver>(
+        &mock_network_quality_provider_));
   }
 
   void SetUp() override {
     page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp();
 
+    EXPECT_CALL(mock_network_quality_provider_, GetEffectiveConnectionType())
+        .Times(AnyNumber())
+        .WillRepeatedly(Return(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN));
+
     TestingBrowserProcess::GetGlobal()->SetUkmService(
         ukm_service_test_harness_.test_ukm_service());
   }
@@ -42,6 +65,10 @@
     return ukm_service_test_harness_.test_ukm_service()->entries_count();
   }
 
+  MockNetworkQualityProvider& mock_network_quality_provider() {
+    return mock_network_quality_provider_;
+  }
+
   const ukm::UkmSource* GetUkmSource(size_t source_index) {
     return ukm_service_test_harness_.test_ukm_service()->GetSource(
         source_index);
@@ -118,6 +145,7 @@
   }
 
  private:
+  MockNetworkQualityProvider mock_network_quality_provider_;
   ukm::UkmServiceTestingHarness ukm_service_test_harness_;
 };
 
@@ -250,3 +278,26 @@
   EXPECT_TRUE(
       HasMetric(internal::kUkmForegroundDurationName, entry2_proto.metrics()));
 }
+
+TEST_F(UkmPageLoadMetricsObserverTest, EffectiveConnectionType) {
+  EXPECT_CALL(mock_network_quality_provider(), GetEffectiveConnectionType())
+      .WillRepeatedly(Return(net::EFFECTIVE_CONNECTION_TYPE_3G));
+
+  NavigateAndCommit(GURL(kTestUrl1));
+
+  // Simulate closing the tab.
+  DeleteContents();
+
+  EXPECT_EQ(1ul, ukm_source_count());
+  const ukm::UkmSource* source = GetUkmSource(0);
+  EXPECT_EQ(GURL(kTestUrl1), source->url());
+
+  EXPECT_GE(ukm_entry_count(), 1ul);
+  ukm::Entry entry_proto = GetMergedEntryProtoForSourceID(source->id());
+  EXPECT_EQ(entry_proto.source_id(), source->id());
+  EXPECT_EQ(entry_proto.event_hash(),
+            base::HashMetricName(internal::kUkmPageLoadEventName));
+  EXPECT_FALSE(entry_proto.metrics().empty());
+  ExpectMetric(internal::kUkmEffectiveConnectionType,
+               net::EFFECTIVE_CONNECTION_TYPE_3G, entry_proto.metrics());
+}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 3af2ffd..ffca700 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -92,7 +92,7 @@
     tracker->AddObserver(base::MakeUnique<TabRestorePageLoadMetricsObserver>());
 
     std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> ukm_observer =
-        UkmPageLoadMetricsObserver::CreateIfNeeded();
+        UkmPageLoadMetricsObserver::CreateIfNeeded(web_contents_);
     if (ukm_observer)
       tracker->AddObserver(std::move(ukm_observer));
 
diff --git a/chrome/browser/resources/feedback/js/feedback.js b/chrome/browser/resources/feedback/js/feedback.js
index 6d8b39c..cb51b962 100644
--- a/chrome/browser/resources/feedback/js/feedback.js
+++ b/chrome/browser/resources/feedback/js/feedback.js
@@ -344,6 +344,9 @@
       });
 
       chrome.feedbackPrivate.getUserEmail(function(email) {
+        // Never add an empty option.
+        if (!email)
+          return;
         var optionElement = document.createElement('option');
         optionElement.value = email;
         optionElement.text = email;
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 57072b8..afdcd87c 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -164,27 +164,26 @@
 #endif
 }
 
-// If |protocol| is empty this function checks if Chrome is the default browser,
-// otherwise it checks if Chrome is the default handler application for
-// |protocol|.
-DefaultWebClientState GetIsDefaultWebClient(const std::string& protocol) {
-#if defined(OS_CHROMEOS)
-  return UNKNOWN_DEFAULT;
-#else
-  base::ThreadRestrictions::AssertIOAllowed();
-
-  std::unique_ptr<base::Environment> env(base::Environment::Create());
-
+#if !defined(OS_CHROMEOS)
+// If |check| is true, returns the output of "xdg-settings check {property}
+// *.desktop", otherwise returns the output of "xdg-settings get {property}",
+// where property is "default-web-browser" if |protocol| is empty or
+// "default-url-scheme-handler |protocol|" otherwise.  Returns "" if
+// xdg-settings fails for any reason.
+std::string GetXdgSettingsOutput(bool check,
+                                 const std::string& protocol,
+                                 base::Environment* env) {
   std::vector<std::string> argv;
   argv.push_back(kXdgSettings);
-  argv.push_back("check");
+  argv.push_back(check ? "check" : "get");
   if (protocol.empty()) {
     argv.push_back(kXdgSettingsDefaultBrowser);
   } else {
     argv.push_back(kXdgSettingsDefaultSchemeHandler);
     argv.push_back(protocol);
   }
-  argv.push_back(shell_integration_linux::GetDesktopName(env.get()));
+  if (check)
+    argv.push_back(shell_integration_linux::GetDesktopName(env));
 
   std::string reply;
   int success_code;
@@ -197,15 +196,47 @@
     }
   }
 
-  if (!ran_ok || success_code != EXIT_SUCCESS) {
-    // xdg-settings failed: we can't determine or set the default browser.
-    return UNKNOWN_DEFAULT;
+  if (!ran_ok || success_code != EXIT_SUCCESS)
+    return std::string();
+
+  return reply;
+}
+#endif
+
+// If |protocol| is empty this function checks if Chrome is the default browser,
+// otherwise it checks if Chrome is the default handler application for
+// |protocol|.
+DefaultWebClientState GetDefaultWebClient(const std::string& protocol) {
+#if defined(OS_CHROMEOS)
+  return UNKNOWN_DEFAULT;
+#else
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
+  std::string xdg_is_default = GetXdgSettingsOutput(true, protocol, env.get());
+  if (base::StartsWith(xdg_is_default, "yes", base::CompareCase::SENSITIVE)) {
+    return IS_DEFAULT;
+  }
+  if (base::StartsWith(xdg_is_default, "no", base::CompareCase::SENSITIVE)) {
+    // An output of "no" does not necessarily mean Chrom[e,ium] is not the
+    // default.  According to the xdg-settings man page, this can happen when
+    // "only some of the underlying settings actually reflect that value". Don't
+    // return NOT_DEFAULT unless we're sure, or else an annoying "Chrome is not
+    // your default browser" banner will appear on every launch
+    // (https://crbug.com/578888).
+    if (base::StartsWith(GetXdgSettingsOutput(false, protocol, env.get()),
+                         shell_integration_linux::GetDesktopName(env.get()),
+                         base::CompareCase::SENSITIVE)) {
+      // This is the odd case where 'xdg-settings check' said that Chrome wasn't
+      // the default, but 'xdg-settings get' returned Chrome as the default.
+      return UNKNOWN_DEFAULT;
+    }
+    // xdg-settings says the default is non-Chrome, and is self-consistent.
+    return NOT_DEFAULT;
   }
 
-  // Allow any reply that starts with "yes".
-  return base::StartsWith(reply, "yes", base::CompareCase::SENSITIVE)
-             ? IS_DEFAULT
-             : NOT_DEFAULT;
+  // xdg-settings failed: we can't determine or set the default browser.
+  return UNKNOWN_DEFAULT;
 #endif
 }
 
@@ -243,7 +274,7 @@
 }
 
 DefaultWebClientState GetDefaultBrowser() {
-  return GetIsDefaultWebClient(std::string());
+  return GetDefaultWebClient(std::string());
 }
 
 bool IsFirefoxDefaultBrowser() {
@@ -259,7 +290,7 @@
 }
 
 DefaultWebClientState IsDefaultProtocolClient(const std::string& protocol) {
-  return GetIsDefaultWebClient(protocol);
+  return GetDefaultWebClient(protocol);
 }
 
 }  // namespace shell_integration
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index 97f45645..cd187f3 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -19,6 +19,8 @@
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/webui/signin/login_ui_service.h"
+#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_switches.h"
@@ -130,19 +132,30 @@
 }
 
 bool ProfileSyncServiceHarness::SetupSync() {
-  bool result = SetupSync(syncer::UserSelectableTypes());
-  if (result == false) {
-    std::string status = GetServiceStatus();
-    LOG(ERROR) << profile_debug_name_
-               << ": SetupSync failed. Syncer status:\n" << status;
+  bool result = SetupSync(syncer::UserSelectableTypes(), false);
+  if (!result) {
+    LOG(ERROR) << profile_debug_name_ << ": SetupSync failed. Syncer status:\n"
+               << GetServiceStatus();
   } else {
     DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
   }
   return result;
 }
 
-bool ProfileSyncServiceHarness::SetupSync(
-    syncer::ModelTypeSet synced_datatypes) {
+bool ProfileSyncServiceHarness::SetupSyncForClearingServerData() {
+  bool result = SetupSync(syncer::UserSelectableTypes(), true);
+  if (!result) {
+    LOG(ERROR) << profile_debug_name_
+               << ": SetupSyncForClear failed. Syncer status:\n"
+               << GetServiceStatus();
+  } else {
+    DVLOG(1) << profile_debug_name_ << ": SetupSyncForClear successful.";
+  }
+  return result;
+}
+
+bool ProfileSyncServiceHarness::SetupSync(syncer::ModelTypeSet synced_datatypes,
+                                          bool skip_passphrase_verification) {
   DCHECK(!profile_->IsLegacySupervised())
       << "SetupSync should not be used for legacy supervised users.";
 
@@ -179,17 +192,20 @@
   // Now that auth is completed, request that sync actually start.
   service()->RequestStart();
 
-  if (!AwaitEngineInitialization()) {
+  if (!AwaitEngineInitialization(skip_passphrase_verification)) {
     return false;
   }
-
   // Choose the datatypes to be synced. If all datatypes are to be synced,
   // set sync_everything to true; otherwise, set it to false.
   bool sync_everything = (synced_datatypes == syncer::UserSelectableTypes());
   service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
 
   // Notify ProfileSyncService that we are done with configuration.
-  FinishSyncSetup();
+  if (skip_passphrase_verification) {
+    sync_blocker_.reset();
+  } else {
+    FinishSyncSetup();
+  }
 
   if ((signin_type_ == SigninType::UI_SIGNIN) &&
       !login_ui_test_utils::DismissSyncConfirmationDialog(
@@ -199,6 +215,20 @@
     return false;
   }
 
+  // OneClickSigninSyncStarter observer is created with a real user sign in.
+  // It is deleted on certain conditions which are not satisfied by our tests,
+  // and this causes the SigninTracker observer to stay hanging at shutdown.
+  // Calling LoginUIService::SyncConfirmationUIClosed forces the observer to
+  // be removed. http://crbug.com/484388
+  if (signin_type_ == SigninType::UI_SIGNIN) {
+    LoginUIServiceFactory::GetForProfile(profile_)->SyncConfirmationUIClosed(
+        LoginUIService::SYNC_WITH_DEFAULT_SETTINGS);
+  }
+
+  if (skip_passphrase_verification) {
+    return true;
+  }
+
   // Set an implicit passphrase for encryption if an explicit one hasn't already
   // been set. If an explicit passphrase has been set, immediately return false,
   // since a decryption passphrase is required.
@@ -212,7 +242,43 @@
 
   // Wait for initial sync cycle to be completed.
   if (!AwaitSyncSetupCompletion()) {
-    LOG(ERROR) << "Initial sync cycle timed out.";
+    return false;
+  }
+
+  return true;
+}
+
+bool ProfileSyncServiceHarness::RestartSyncService() {
+  DVLOG(1) << "Requesting stop for service.";
+  service()->RequestStop(ProfileSyncService::CLEAR_DATA);
+
+  std::unique_ptr<syncer::SyncSetupInProgressHandle> blocker =
+      service()->GetSetupInProgressHandle();
+  DVLOG(1) << "Requesting start for service";
+  service()->RequestStart();
+
+  if (!AwaitEngineInitialization()) {
+    LOG(ERROR) << "AwaitEngineInitialization failed.";
+    return false;
+  }
+  DVLOG(1) << "Engine Initialized successfully.";
+
+  // This passphrase should be implicit because ClearServerData should be called
+  // prior.
+  if (!service()->IsUsingSecondaryPassphrase()) {
+    service()->SetEncryptionPassphrase(password_, ProfileSyncService::IMPLICIT);
+  } else {
+    LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
+                  " until SetDecryptionPassphrase is called.";
+    return false;
+  }
+  DVLOG(1) << "Passphrase decryption success.";
+
+  blocker.reset();
+  service()->SetFirstSetupComplete();
+
+  if (!AwaitSyncSetupCompletion()) {
+    LOG(FATAL) << "AwaitSyncSetupCompletion failed.";
     return false;
   }
 
@@ -246,7 +312,8 @@
   return QuiesceStatusChangeChecker(services).Wait();
 }
 
-bool ProfileSyncServiceHarness::AwaitEngineInitialization() {
+bool ProfileSyncServiceHarness::AwaitEngineInitialization(
+    bool skip_passphrase_verification) {
   if (!EngineInitializeChecker(service()).Wait()) {
     LOG(ERROR) << "EngineInitializeChecker timed out.";
     return false;
@@ -258,7 +325,8 @@
   }
 
   // Make sure that initial sync wasn't blocked by a missing passphrase.
-  if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
+  if (!skip_passphrase_verification &&
+      service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
     LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
                   " until SetDecryptionPassphrase is called.";
     return false;
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.h b/chrome/browser/sync/test/integration/profile_sync_service_harness.h
index b4b82eb2..42ca6400 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.h
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.h
@@ -55,9 +55,21 @@
   // changes.
   bool SetupSync();
 
+  // Setup sync without the authenticating through the passphrase encryption.
+  // Use this method when you need to setup a client that you're going to call
+  // RestartSyncService() directly after.
+  bool SetupSyncForClearingServerData();
+
+  // Both SetupSync and SetupSyncForClear call into this method.
   // Same as the above method, but enables sync only for the datatypes contained
   // in |synced_datatypes|.
-  bool SetupSync(syncer::ModelTypeSet synced_datatypes);
+  bool SetupSync(syncer::ModelTypeSet synced_datatypes,
+                 bool skip_passphrase_verification = false);
+
+  // Restart sync service to simulate a sign-in/sign-out. This is useful
+  // to recover from a lost birthday. Use directly after a clear server data
+  // command to start from clean slate.
+  bool RestartSyncService();
 
   // Calling this acts as a barrier and blocks the caller until |this| and
   // |partner| have both completed a sync cycle.  When calling this method,
@@ -86,7 +98,7 @@
   // (e.g., auth error) is reached. Returns true if and only if the engine
   // initialized successfully. See ProfileSyncService's IsEngineInitialized()
   // method for the definition of engine initialization.
-  bool AwaitEngineInitialization();
+  bool AwaitEngineInitialization(bool skip_passphrase_verification = false);
 
   // Blocks the caller until sync setup is complete. Returns true if and only
   // if sync setup completed successfully. See syncer::SyncService's
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 5008bee..64cc0210 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -620,9 +620,21 @@
     }
   }
 
+  int clientIndex = 0;
+  // If we're using external servers, clear server data so the account starts
+  // with a clean slate.
+  if (UsingExternalServers()) {
+    if (!SetupAndClearClient(clientIndex++)) {
+      LOG(FATAL) << "Setting up and clearing data for client "
+                 << clientIndex - 1 << " failed";
+      return false;
+    }
+  }
+
   // Sync each of the profiles.
-  for (int i = 0; i < num_clients_; ++i) {
-    if (!GetClient(i)->SetupSync()) {
+  for (; clientIndex < num_clients_; clientIndex++) {
+    DVLOG(1) << "Setting up " << clientIndex << " client";
+    if (!GetClient(clientIndex)->SetupSync()) {
       LOG(FATAL) << "SetupSync() failed.";
       return false;
     }
@@ -669,6 +681,23 @@
   return true;
 }
 
+bool SyncTest::SetupAndClearClient(size_t index) {
+  // Setup the first client so the sync engine is initialized, which is
+  // required to clear server data.
+  DVLOG(1) << "Setting up first client for clear.";
+  if (!GetClient(index)->SetupSyncForClearingServerData()) {
+    LOG(FATAL) << "SetupSync() failed.";
+    return false;
+  }
+
+  DVLOG(1) << "Done setting up first client for clear.";
+  if (!ClearServerData(GetClient(index++))) {
+    LOG(FATAL) << "ClearServerData failed.";
+    return false;
+  }
+  return true;
+}
+
 void SyncTest::TearDownOnMainThread() {
   for (size_t i = 0; i < clients_.size(); ++i) {
     clients_[i]->service()->RequestStop(ProfileSyncService::CLEAR_DATA);
@@ -1148,3 +1177,14 @@
     const std::string& contents) {
   preexisting_preferences_file_contents_ = contents;
 }
+
+bool SyncTest::ClearServerData(ProfileSyncServiceHarness* harness) {
+  // At this point our birthday is good.
+  base::RunLoop run_loop;
+  harness->service()->ClearServerDataForTest(run_loop.QuitClosure());
+  run_loop.Run();
+
+  // Our birthday is invalidated on the server here so restart sync to get
+  // the new birthday from the server.
+  return harness->RestartSyncService();
+}
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h
index fb151cf..da2ac60d 100644
--- a/chrome/browser/sync/test/integration/sync_test.h
+++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -180,6 +180,9 @@
   // Initializes sync clients and profiles if required and syncs each of them.
   virtual bool SetupSync() WARN_UNUSED_RESULT;
 
+  // Initialize, and clear data for given client.
+  bool SetupAndClearClient(size_t index);
+
   // Sets whether or not the sync clients in this test should respond to
   // notifications of their own commits.  Real sync clients do not do this, but
   // many test assertions require this behavior.
@@ -376,6 +379,9 @@
   // value of |server_type_|.
   void InitializeInvalidations(int index);
 
+  // Clear server data, and restart sync.
+  bool ClearServerData(ProfileSyncServiceHarness* harness);
+
   // Python sync test server, started on demand.
   syncer::LocalSyncTestServer sync_server_;
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index 705b592..3fc7c95a 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -390,6 +390,9 @@
 // Returns the BrowserWindowTouchBar object associated with the window.
 - (BrowserWindowTouchBar*)browserWindowTouchBar;
 
+// Invalidates the browser's touch bar.
+- (void)invalidateTouchBar;
+
 @end  // @interface BrowserWindowController
 
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 39788f10..5b70340 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -1009,8 +1009,7 @@
   [toolbarController_ setStarredState:isStarred];
 
   [touchBar_ setIsStarred:isStarred];
-  if ([[self window] respondsToSelector:@selector(setTouchBar:)])
-    [[self window] performSelector:@selector(setTouchBar:) withObject:nil];
+  [self invalidateTouchBar];
 }
 
 - (void)setCurrentPageIsTranslated:(BOOL)on {
@@ -1149,8 +1148,7 @@
 - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
   [toolbarController_ setIsLoading:isLoading force:force];
   [touchBar_ setIsPageLoading:isLoading];
-  if ([[self window] respondsToSelector:@selector(setTouchBar:)])
-    [[self window] performSelector:@selector(setTouchBar:) withObject:nil];
+  [self invalidateTouchBar];
 }
 
 // Make the location bar the first responder, if possible.
@@ -1853,13 +1851,19 @@
 
 - (BrowserWindowTouchBar*)browserWindowTouchBar {
   if (!touchBar_) {
-    touchBar_.reset(
-        [[BrowserWindowTouchBar alloc] initWithBrowser:browser_.get()]);
+    touchBar_.reset([[BrowserWindowTouchBar alloc]
+                initWithBrowser:browser_.get()
+        browserWindowController:self]);
   }
 
   return touchBar_.get();
 }
 
+- (void)invalidateTouchBar {
+  if ([[self window] respondsToSelector:@selector(setTouchBar:)])
+    [[self window] performSelector:@selector(setTouchBar:) withObject:nil];
+}
+
 @end  // @implementation BrowserWindowController
 
 @implementation BrowserWindowController(Fullscreen)
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar.h b/chrome/browser/ui/cocoa/browser_window_touch_bar.h
index 5e670650..5952600 100644
--- a/chrome/browser/ui/cocoa/browser_window_touch_bar.h
+++ b/chrome/browser/ui/cocoa/browser_window_touch_bar.h
@@ -10,6 +10,7 @@
 #import "ui/base/cocoa/touch_bar_forward_declarations.h"
 
 class Browser;
+@class BrowserWindowController;
 
 // Provides a touch bar for the browser window. This class implements the
 // NSTouchBarDelegate and handles the items in the touch bar.
@@ -22,7 +23,8 @@
 @property(nonatomic, assign) BOOL isStarred;
 
 // Designated initializer.
-- (instancetype)initWithBrowser:(Browser*)browser;
+- (instancetype)initWithBrowser:(Browser*)browser
+        browserWindowController:(BrowserWindowController*)bwc;
 
 // Creates and returns a touch bar for the browser window.
 - (NSTouchBar*)makeTouchBar;
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
index 255b62d..274ff4cb 100644
--- a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
+++ b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
@@ -4,6 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/browser_window_touch_bar.h"
 
+#include <memory>
+
 #include "base/mac/mac_util.h"
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/sdk_forward_declarations.h"
@@ -11,12 +13,16 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/command_updater.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_command_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/omnibox/browser/vector_icons.h"
+#include "components/prefs/pref_member.h"
 #include "components/search_engines/util.h"
 #include "components/toolbar/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -36,6 +42,7 @@
 // Touch bar items identifiers.
 const NSTouchBarItemIdentifier kBackForwardTouchId = @"BackForwardTouchId";
 const NSTouchBarItemIdentifier kReloadOrStopTouchId = @"ReloadOrStopTouchId";
+const NSTouchBarItemIdentifier kHomeTouchId = @"HomeTouchId";
 const NSTouchBarItemIdentifier kSearchTouchId = @"SearchTouchId";
 const NSTouchBarItemIdentifier kStarTouchId = @"StarTouchId";
 const NSTouchBarItemIdentifier kNewTabTouchId = @"NewTabTouchId";
@@ -52,7 +59,8 @@
 const int kTouchBarIconSize = 16;
 
 // The width of the search button in the touch bar.
-const int kTouchBarSearchButtonWidth = 280;
+const int kSearchBtnWidthWithHomeBtn = 205;
+const int kSearchBtnWidthWithoutHomeBtn = 280;
 
 // Creates an NSImage from the given VectorIcon.
 NSImage* CreateNSImageFromIcon(const gfx::VectorIcon& icon,
@@ -75,6 +83,23 @@
   return button;
 }
 
+// A class registered for C++ notifications. This is used to detect changes in
+// the home button preferences and update the Touch Bar.
+class HomePrefNotificationBridge {
+ public:
+  explicit HomePrefNotificationBridge(BrowserWindowController* bwc)
+      : bwc_(bwc) {}
+
+  ~HomePrefNotificationBridge() {}
+
+  void UpdateTouchBar() { [bwc_ invalidateTouchBar]; }
+
+ private:
+  BrowserWindowController* bwc_;  // Weak.
+
+  DISALLOW_COPY_AND_ASSIGN(HomePrefNotificationBridge);
+};
+
 }  // namespace
 
 @interface BrowserWindowTouchBar () {
@@ -83,6 +108,14 @@
 
   // The browser associated with the touch bar.
   Browser* browser_;  // Weak.
+
+  BrowserWindowController* bwc_;  // Weak, own us.
+
+  // Used to monitor the optional home button pref.
+  BooleanPrefMember showHomeButton_;
+
+  // Used to receive and handle notifications for the home button pref.
+  std::unique_ptr<HomePrefNotificationBridge> notificationBridge_;
 }
 
 // Creates and return the back and forward segmented buttons.
@@ -97,11 +130,20 @@
 @synthesize isPageLoading = isPageLoading_;
 @synthesize isStarred = isStarred_;
 
-- (instancetype)initWithBrowser:(Browser*)browser {
+- (instancetype)initWithBrowser:(Browser*)browser
+        browserWindowController:(BrowserWindowController*)bwc {
   if ((self = [self init])) {
     DCHECK(browser);
     commandUpdater_ = browser->command_controller()->command_updater();
     browser_ = browser;
+    bwc_ = bwc;
+
+    notificationBridge_.reset(new HomePrefNotificationBridge(bwc_));
+    PrefService* prefs = browser->profile()->GetPrefs();
+    showHomeButton_.Init(
+        prefs::kShowHomeButton, prefs,
+        base::Bind(&HomePrefNotificationBridge::UpdateTouchBar,
+                   base::Unretained(notificationBridge_.get())));
   }
 
   return self;
@@ -113,10 +155,19 @@
 
   base::scoped_nsobject<NSTouchBar> touchBar(
       [[NSClassFromString(@"NSTouchBar") alloc] init]);
-  NSArray* touchBarItemIdentifiers = @[
-    kBackForwardTouchId, kReloadOrStopTouchId, kSearchTouchId, kStarTouchId,
-    kNewTabTouchId
-  ];
+  NSArray* touchBarItemIdentifiers;
+  if (showHomeButton_.GetValue()) {
+    touchBarItemIdentifiers = @[
+      kBackForwardTouchId, kReloadOrStopTouchId, kHomeTouchId, kSearchTouchId,
+      kStarTouchId, kNewTabTouchId
+    ];
+  } else {
+    touchBarItemIdentifiers = @[
+      kBackForwardTouchId, kReloadOrStopTouchId, kSearchTouchId, kStarTouchId,
+      kNewTabTouchId
+    ];
+  }
+
   [touchBar setCustomizationIdentifier:kBrowserWindowTouchBarId];
   [touchBar setDefaultItemIdentifiers:touchBarItemIdentifiers];
   [touchBar setCustomizationAllowedItemIdentifiers:touchBarItemIdentifiers];
@@ -139,6 +190,9 @@
         isPageLoading_ ? kNavigateStopIcon : kNavigateReloadIcon;
     int command_id = isPageLoading_ ? IDC_STOP : IDC_RELOAD;
     [touchBarItem setView:CreateTouchBarButton(icon, self, command_id)];
+  } else if ([identifier isEqualTo:kHomeTouchId]) {
+    [touchBarItem
+        setView:CreateTouchBarButton(kNavigateHomeIcon, self, IDC_HOME)];
   } else if ([identifier isEqualTo:kNewTabTouchId]) {
     [touchBarItem setView:CreateTouchBarButton(kNewTabMacTouchbarIcon, self,
                                                IDC_NEW_TAB)];
@@ -206,9 +260,9 @@
                          action:@selector(executeCommand:)];
   searchButton.imageHugsTitle = YES;
   searchButton.tag = IDC_FOCUS_LOCATION;
-  [searchButton.widthAnchor
-      constraintEqualToConstant:kTouchBarSearchButtonWidth]
-      .active = YES;
+  int width = showHomeButton_.GetValue() ? kSearchBtnWidthWithHomeBtn
+                                         : kSearchBtnWidthWithoutHomeBtn;
+  [searchButton.widthAnchor constraintEqualToConstant:width].active = YES;
   return searchButton;
 }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm b/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm
index 92ac48ee..fa9cdff 100644
--- a/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm
@@ -9,6 +9,8 @@
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/browser_window_touch_bar.h"
 #include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class BrowserWindowTouchBarUnitTest : public CocoaProfileTest {
@@ -16,8 +18,9 @@
   void SetUp() override {
     CocoaProfileTest::SetUp();
     ASSERT_TRUE(browser());
-    browserWindowTouchBar_.reset(
-        [[BrowserWindowTouchBar alloc] initWithBrowser:browser()]);
+    browserWindowTouchBar_.reset([[BrowserWindowTouchBar alloc]
+                initWithBrowser:browser()
+        browserWindowController:nil]);
   }
 
   void TearDown() override { CocoaProfileTest::TearDown(); }
@@ -29,10 +32,24 @@
   if (!base::mac::IsAtLeastOS10_12())
     return;
 
-  NSTouchBar* touchBar = [browserWindowTouchBar_ makeTouchBar];
-  NSArray* touchBarItemIds = [touchBar itemIdentifiers];
+  PrefService* prefs = profile()->GetPrefs();
+  DCHECK(prefs);
+  prefs->SetBoolean(prefs::kShowHomeButton, true);
+
+  NSArray* touchBarItemIds =
+      [[browserWindowTouchBar_ makeTouchBar] itemIdentifiers];
   EXPECT_TRUE([touchBarItemIds containsObject:@"BackForwardTouchId"]);
   EXPECT_TRUE([touchBarItemIds containsObject:@"ReloadOrStopTouchId"]);
+  EXPECT_TRUE([touchBarItemIds containsObject:@"HomeTouchId"]);
+  EXPECT_TRUE([touchBarItemIds containsObject:@"SearchTouchId"]);
+  EXPECT_TRUE([touchBarItemIds containsObject:@"NewTabTouchId"]);
+  EXPECT_TRUE([touchBarItemIds containsObject:@"StarTouchId"]);
+
+  prefs->SetBoolean(prefs::kShowHomeButton, false);
+  touchBarItemIds = [[browserWindowTouchBar_ makeTouchBar] itemIdentifiers];
+  EXPECT_TRUE([touchBarItemIds containsObject:@"BackForwardTouchId"]);
+  EXPECT_TRUE([touchBarItemIds containsObject:@"ReloadOrStopTouchId"]);
+  EXPECT_FALSE([touchBarItemIds containsObject:@"HomeTouchId"]);
   EXPECT_TRUE([touchBarItemIds containsObject:@"SearchTouchId"]);
   EXPECT_TRUE([touchBarItemIds containsObject:@"NewTabTouchId"]);
   EXPECT_TRUE([touchBarItemIds containsObject:@"StarTouchId"]);
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc
index 6e110bb..62b815b 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -15,7 +15,9 @@
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/strings/grit/components_strings.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/font_list.h"
@@ -246,4 +248,34 @@
   return label;
 }
 
+base::string16 GetShippingAddressSectionString(
+    payments::mojom::PaymentShippingType shipping_type) {
+  switch (shipping_type) {
+    case payments::mojom::PaymentShippingType::DELIVERY:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL);
+    case payments::mojom::PaymentShippingType::PICKUP:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_PICKUP_ADDRESS_LABEL);
+    case payments::mojom::PaymentShippingType::SHIPPING:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL);
+  }
+  // MSVC doesn't compile with only the above switch statement because it can't
+  // see that all control paths return a value.
+  return l10n_util::GetStringUTF16(IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL);
+}
+
+base::string16 GetShippingOptionSectionString(
+    payments::mojom::PaymentShippingType shipping_type) {
+  switch (shipping_type) {
+    case payments::mojom::PaymentShippingType::DELIVERY:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_DELIVERY_OPTION_LABEL);
+    case payments::mojom::PaymentShippingType::PICKUP:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_PICKUP_OPTION_LABEL);
+    case payments::mojom::PaymentShippingType::SHIPPING:
+      return l10n_util::GetStringUTF16(IDS_PAYMENTS_SHIPPING_OPTION_LABEL);
+  }
+  // MSVC doesn't compile with only the above switch statement because it can't
+  // see that all control paths return a value.
+  return l10n_util::GetStringUTF16(IDS_PAYMENTS_SHIPPING_OPTION_LABEL);
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.h b/chrome/browser/ui/views/payments/payment_request_views_util.h
index a15adda..6a044dd6 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.h
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/strings/string16.h"
+#include "components/payments/content/payment_request.mojom.h"
 
 namespace autofill {
 class AutofillProfile;
@@ -88,6 +89,11 @@
 // Creates a label with a bold font.
 std::unique_ptr<views::Label> CreateBoldLabel(const base::string16& text);
 
+base::string16 GetShippingAddressSectionString(
+    payments::mojom::PaymentShippingType shipping_type);
+base::string16 GetShippingOptionSectionString(
+    payments::mojom::PaymentShippingType shipping_type);
+
 }  // namespace payments
 
 #endif  // CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_VIEWS_UTIL_H_
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index e2070ab..a5ae940 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -414,7 +414,7 @@
 std::unique_ptr<views::Button> PaymentSheetViewController::CreateShippingRow() {
   std::unique_ptr<views::Button> section = CreatePaymentSheetRow(
       this,
-      l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_SHIPPING_SECTION_NAME),
+      GetShippingAddressSectionString(request()->options()->shipping_type),
       CreateShippingSectionContent(), std::unique_ptr<views::View>(nullptr),
       widest_name_column_view_width_);
   section->set_tag(
@@ -528,10 +528,8 @@
 
 std::unique_ptr<views::Button>
 PaymentSheetViewController::CreateShippingOptionRow() {
-  // TODO(anthonyvd): Use the correct IDS_PAYMENTS_*_OPTION_LABEL string based
-  // on the data passed by the website.
   std::unique_ptr<views::Button> section = CreatePaymentSheetRow(
-      this, l10n_util::GetStringUTF16(IDS_PAYMENTS_SHIPPING_OPTION_LABEL),
+      this, GetShippingOptionSectionString(request()->options()->shipping_type),
       CreateShippingOptionContent(), std::unique_ptr<views::View>(nullptr),
       widest_name_column_view_width_);
   section->set_tag(static_cast<int>(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index c03f474..0eb4c9e9 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -427,6 +427,10 @@
                IDS_PIN_KEYBOARD_HINT_TEXT_PIN_PASSWORD);
   builder->Add("pinKeyboardDeleteAccessibleName",
                IDS_PIN_KEYBOARD_DELETE_ACCESSIBLE_NAME);
+  builder->Add("fingerprintHint", IDS_FINGERPRINT_HINT_TEXT);
+  builder->Add("fingerprintIconMessage", IDS_FINGERPRINT_ICON_MESSAGE);
+  builder->Add("fingerprintSigningin", IDS_FINGERPRINT_LOGIN_TEXT);
+  builder->Add("fingerprintSigninFailed", IDS_FINGERPRINT_LOGIN_FAILED_TEXT);
   builder->Add("signingIn", IDS_LOGIN_POD_SIGNING_IN);
   builder->Add("podMenuButtonAccessibleName",
                IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME);
diff --git a/chrome/test/base/mojo_test_connector.cc b/chrome/test/base/mojo_test_connector.cc
index fcbb998..da87cda 100644
--- a/chrome/test/base/mojo_test_connector.cc
+++ b/chrome/test/base/mojo_test_connector.cc
@@ -67,15 +67,11 @@
 #else
 #error "Unsupported"
 #endif
-    service_manager::mojom::ServicePtr service =
-        service_manager::PassServiceRequestOnCommandLine(&process_connection_,
-                                                         command_line);
 
-    background_service_manager_->RegisterService(
-        service_manager::Identity(content::mojom::kPackagedServicesServiceName,
-                                  service_manager::mojom::kRootUserID),
-        std::move(service),
-        service_manager::mojom::PIDReceiverRequest(&pid_receiver_));
+    // Create the pipe token, as it must be passed to children processes via the
+    // command line.
+    service_ = service_manager::PassServiceRequestOnCommandLine(
+        &process_connection_, command_line);
 
     // ChildProcessLaunched may be called on an arbitrary thread, so track the
     // current TaskRunner and post back to it when we want to send the PID.
@@ -91,13 +87,22 @@
         handle,
         mojo::edk::ConnectionParams(platform_channel_->PassServerHandle()));
 
-    main_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&MojoTestState::SetPID, weak_factory_.GetWeakPtr(), pid));
+    main_task_runner_->PostTask(FROM_HERE,
+                                base::Bind(&MojoTestState::SetupService,
+                                           weak_factory_.GetWeakPtr(), pid));
   }
 
   // Called on the main thread only.
-  void SetPID(base::ProcessId pid) {
+  // This registers the services needed for the test. This is not done until
+  // after ChildProcessLaunched as previous test runs will tear down existing
+  // connections.
+  void SetupService(base::ProcessId pid) {
+    background_service_manager_->RegisterService(
+        service_manager::Identity(content::mojom::kPackagedServicesServiceName,
+                                  service_manager::mojom::kRootUserID),
+        std::move(service_),
+        service_manager::mojom::PIDReceiverRequest(&pid_receiver_));
+
     DCHECK(pid_receiver_.is_bound());
     pid_receiver_->SetPID(pid);
     pid_receiver_.reset();
@@ -106,6 +111,11 @@
   mojo::edk::PendingProcessConnection process_connection_;
   service_manager::BackgroundServiceManager* const background_service_manager_;
 
+  // The ServicePtr must be created before child process launch so that the pipe
+  // can be set on the command line. It is held until SetupService is called at
+  // which point |background_service_manager_| takes over ownership.
+  service_manager::mojom::ServicePtr service_;
+
   // NOTE: HandlePassingInformation must remain valid through process launch,
   // hence it lives here instead of within Init()'s stack.
   mojo::edk::HandlePassingInformation handle_passing_info_;
diff --git a/chrome_elf/chrome_elf.def b/chrome_elf/chrome_elf.def
index bc4d1c9..b4c3936 100644
--- a/chrome_elf/chrome_elf.def
+++ b/chrome_elf/chrome_elf.def
@@ -11,4 +11,5 @@
   GetUserDataDirectoryThunk
   IsBlacklistInitialized
   SignalChromeElf
+  SignalInitializeCrashReporting
   SuccessfullyBlocked
diff --git a/chrome_elf/chrome_elf_main.cc b/chrome_elf/chrome_elf_main.cc
index 23edaaf..926668c 100644
--- a/chrome_elf/chrome_elf_main.cc
+++ b/chrome_elf/chrome_elf_main.cc
@@ -14,6 +14,17 @@
 #include "chrome_elf/blacklist/blacklist.h"
 #include "chrome_elf/crash/crash_helper.h"
 
+// This function is a temporary workaround for https://crbug.com/655788. We
+// need to come up with a better way to initialize crash reporting that can
+// happen inside DllMain().
+void SignalInitializeCrashReporting() {
+  if (!elf_crash::InitializeCrashReporting()) {
+#ifdef _DEBUG
+    assert(false);
+#endif  // _DEBUG
+  }
+}
+
 void SignalChromeElf() {
   blacklist::ResetBeacon();
 }
@@ -37,10 +48,6 @@
   if (reason == DLL_PROCESS_ATTACH) {
     install_static::InitializeProductDetailsForPrimaryModule();
 
-    if (!elf_crash::InitializeCrashReporting()) {
-      assert(false);
-    }
-
     // CRT on initialization installs an exception filter which calls
     // TerminateProcess. We need to hook CRT's attempt to set an exception.
     elf_crash::DisableSetUnhandledExceptionFilter();
diff --git a/chrome_elf/chrome_elf_main.h b/chrome_elf/chrome_elf_main.h
index 52bf067..432c377 100644
--- a/chrome_elf/chrome_elf_main.h
+++ b/chrome_elf/chrome_elf_main.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_ELF_CHROME_ELF_MAIN_H_
 #define CHROME_ELF_CHROME_ELF_MAIN_H_
 
+extern "C" void SignalInitializeCrashReporting();
 extern "C" void SignalChromeElf();
 
 #endif  // CHROME_ELF_CHROME_ELF_MAIN_H_
diff --git a/chromeos/components/tether/proto/tether.proto b/chromeos/components/tether/proto/tether.proto
index 3910d190..7526f2e 100644
--- a/chromeos/components/tether/proto/tether.proto
+++ b/chromeos/components/tether/proto/tether.proto
@@ -85,6 +85,7 @@
     UNKNOWN_ERROR = 0;
     SUCCESS = 1;
     PROVISIONING_FAILED = 2;
+    TETHERING_TIMEOUT = 3;
   }
 
   optional ResponseCode response_code = 1;
diff --git a/chromeos/dbus/cros_disks_client.cc b/chromeos/dbus/cros_disks_client.cc
index 47f961d3..42ed90e 100644
--- a/chromeos/dbus/cros_disks_client.cc
+++ b/chromeos/dbus/cros_disks_client.cc
@@ -40,10 +40,6 @@
 const char kRemountOption[] = "remount";
 const char kMountLabelOption[] = "mountlabel";
 
-const char* kDefaultUnmountOptions[] = {
-  "force",
-};
-
 const char kLazyUnmountOption[] = "lazy";
 
 // Checks if retrieved media type is in boundaries of DeviceMediaType.
@@ -133,9 +129,7 @@
     dbus::MessageWriter writer(&method_call);
     writer.AppendString(device_path);
 
-    std::vector<std::string> unmount_options(
-        kDefaultUnmountOptions,
-        kDefaultUnmountOptions + arraysize(kDefaultUnmountOptions));
+    std::vector<std::string> unmount_options;
     if (options == UNMOUNT_OPTIONS_LAZY)
       unmount_options.push_back(kLazyUnmountOption);
 
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index c54f2ae..ee55bc0 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -39,39 +39,6 @@
   return labels[0];
 }
 
-// Holds the autofill profile |first|, |middle| and |last| names.
-struct NameParts {
-  NameParts(const std::string& first,
-            const std::string& middle,
-            const std::string& last)
-      : first(first), middle(middle), last(last) {}
-
-  std::string first;
-  std::string middle;
-  std::string last;
-};
-
-// Test case to be executed to validate OverwriteOrAppendNames.
-struct TestCase {
-  TestCase(const NameParts& starting_name,
-           const NameParts& additional_name,
-           const NameParts& expected_result)
-      : starting_names(std::vector<NameParts>(1, starting_name)),
-        additional_names(std::vector<NameParts>(1, additional_name)),
-        expected_result(std::vector<NameParts>(1, expected_result)) {}
-
-  TestCase(const std::vector<NameParts>& starting_names,
-           const std::vector<NameParts>& additional_names,
-           const std::vector<NameParts>& expected_result)
-      : starting_names(starting_names),
-        additional_names(additional_names),
-        expected_result(expected_result) {}
-
-  std::vector<NameParts> starting_names;
-  std::vector<NameParts> additional_names;
-  std::vector<NameParts> expected_result;
-};
-
 void SetupTestProfile(AutofillProfile& profile) {
   profile.set_guid(base::GenerateGUID());
   profile.set_origin(kSettingsOrigin);
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 9e63dfe..ed837f1 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -1197,6 +1197,14 @@
                             syncer::CLEAR_SERVER_DATA_MAX);
 }
 
+void ProfileSyncService::ClearServerDataForTest(const base::Closure& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // Sync has a restriction that the engine must be in configuration mode
+  // in order to run clear server data.
+  engine_->StartConfiguration();
+  engine_->ClearServerData(callback);
+}
+
 void ProfileSyncService::OnConfigureDone(
     const DataTypeManager::ConfigureResult& result) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -1384,6 +1392,7 @@
 std::unique_ptr<syncer::SyncSetupInProgressHandle>
 ProfileSyncService::GetSetupInProgressHandle() {
   DCHECK(thread_checker_.CalledOnValidThread());
+
   if (++outstanding_setup_in_progress_handles_ == 1) {
     DCHECK(!startup_controller_->IsSetupInProgress());
     startup_controller_->SetSetupInProgress(true);
@@ -2434,5 +2443,4 @@
     ReconfigureDatatypeManager();
   NotifyObservers();
 }
-
 }  // namespace browser_sync
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index e62cc69..b409a3e9 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -571,6 +571,10 @@
   // Triggers sync cycle with request to update specified |types|.
   void RefreshTypesForTest(syncer::ModelTypeSet types);
 
+  // Calls sync engine to send ClearServerDataMessage to server. This is used
+  // to start accounts with a clean slate when performing end to end testing.
+  void ClearServerDataForTest(const base::Closure& callback);
+
  protected:
   // SyncServiceBase implementation.
   syncer::SyncCredentials GetCredentials() override;
diff --git a/components/crash/content/app/crashpad.cc b/components/crash/content/app/crashpad.cc
index a0eabba..76f6734 100644
--- a/components/crash/content/app/crashpad.cc
+++ b/components/crash/content/app/crashpad.cc
@@ -335,13 +335,6 @@
     RequestSingleCrashUploadImpl(const std::string& local_id) {
   crash_reporter::RequestSingleCrashUpload(local_id);
 }
-
-// This helper is invoked by code in chrome.dll to wait for the handler start to
-// complete.
-void __declspec(dllexport) BlockUntilHandlerStartedImpl() {
-  crash_reporter::BlockUntilHandlerStarted();
-}
-
 }  // extern "C"
 
 #endif  // OS_WIN
diff --git a/components/crash/content/app/crashpad.h b/components/crash/content/app/crashpad.h
index 7af47f7..eeb65ac 100644
--- a/components/crash/content/app/crashpad.h
+++ b/components/crash/content/app/crashpad.h
@@ -53,10 +53,6 @@
 // line argument of --type=crashpad-handler.
 void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
                                            const std::string& process_type);
-
-// Waits until the handler has successfully completed startup or failed, and
-// logs an error in that case.
-void BlockUntilHandlerStarted();
 #endif  // OS_WIN
 
 // Enables or disables crash report upload, taking the given consent to upload
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc
index 3ad5f8d..6d01b28 100644
--- a/components/crash/content/app/crashpad_win.cc
+++ b/components/crash/content/app/crashpad_win.cc
@@ -116,15 +116,9 @@
       exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
     }
 
-    if (!g_crashpad_client.Get().StartHandler(
-            exe_file, database_path, metrics_path, url, process_annotations,
-            arguments, false, true)) {
-      // This means that CreateThread() failed, so this process is very messed
-      // up. This should be effectively unreachable. It is unlikely that there
-      // is any utility to ever making this non-fatal, however, if this is done,
-      // calls to BlockUntilHandlerStarted() will have to be amended.
-      LOG(FATAL) << "synchronous part of handler startup failed";
-    }
+    g_crashpad_client.Get().StartHandler(exe_file, database_path, metrics_path,
+                                         url, process_annotations, arguments,
+                                         false, false);
 
     // If we're the browser, push the pipe name into the environment so child
     // processes can connect to it. If we inherited another crashpad_handler's
@@ -212,16 +206,6 @@
 }  // namespace
 
 }  // namespace internal
-
-void BlockUntilHandlerStarted() {
-  // We know that the StartHandler() at least started asynchronous startup if
-  // we're here, as if it doesn't, we abort.
-  const unsigned int kTimeoutMS = 5000;
-  if (!internal::g_crashpad_client.Get().WaitForHandlerStart(kTimeoutMS)) {
-    LOG(ERROR) << "Crashpad handler failed to start, crash reporting disabled";
-  }
-}
-
 }  // namespace crash_reporter
 
 extern "C" {
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc
index 7a37026..56d3c76 100644
--- a/components/domain_reliability/quic_error_mapping.cc
+++ b/components/domain_reliability/quic_error_mapping.cc
@@ -12,247 +12,244 @@
   net::QuicErrorCode quic_error;
   const char* beacon_quic_error;
 } kQuicErrorMap[] = {
-  // Connection has reached an invalid state.
-  { net::QUIC_INTERNAL_ERROR, "quic.internal_error" },
-  // There were data frames after the a fin or reset.
-  { net::QUIC_STREAM_DATA_AFTER_TERMINATION,
-   "quic.stream_data.after_termination" },
-  // Control frame is malformed.
-  { net::QUIC_INVALID_PACKET_HEADER, "quic.invalid.packet_header" },
-  // Frame data is malformed.
-  { net::QUIC_INVALID_FRAME_DATA, "quic.invalid_frame_data" },
-  // The packet contained no payload.
-  { net::QUIC_MISSING_PAYLOAD, "quic.missing.payload" },
-  // FEC data is malformed.
-  { net::QUIC_INVALID_FEC_DATA, "quic.invalid.fec_data" },
-  // STREAM frame data is malformed.
-  { net::QUIC_INVALID_STREAM_DATA, "quic.invalid.stream_data" },
-  // STREAM frame data is not encrypted.
-  { net::QUIC_UNENCRYPTED_STREAM_DATA, "quic.unencrypted.stream_data" },
-  // Attempt to send unencrypted STREAM frame.
-  { net::QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA,
-    "quic.attempt.to.unencrypted.stream.data" },
-  // Received a frame which is likely the result of memory corruption.
-  { net::QUIC_MAYBE_CORRUPTED_MEMORY, "quic.maybe.corrupted.momery" },
-  // FEC frame data is not encrypted.
-  { net::QUIC_UNENCRYPTED_FEC_DATA, "quic.unencrypted.fec.data" },
-  // RST_STREAM frame data is malformed.
-  { net::QUIC_INVALID_RST_STREAM_DATA, "quic.invalid.rst_stream_data" },
-  // CONNECTION_CLOSE frame data is malformed.
-  { net::QUIC_INVALID_CONNECTION_CLOSE_DATA,
-   "quic.invalid.connection_close_data" },
-  // GOAWAY frame data is malformed.
-  { net::QUIC_INVALID_GOAWAY_DATA, "quic.invalid.goaway_data" },
-  // WINDOW_UPDATE frame data is malformed.
-  { net::QUIC_INVALID_WINDOW_UPDATE_DATA, "quic.invalid.window_update_data" },
-  // BLOCKED frame data is malformed.
-  { net::QUIC_INVALID_BLOCKED_DATA, "quic.invalid.blocked_data" },
-  // STOP_WAITING frame data is malformed.
-  { net::QUIC_INVALID_STOP_WAITING_DATA, "quic.invalid.stop_waiting_data" },
-  // PATH_CLOSE frame data is malformed.
-  { net::QUIC_INVALID_PATH_CLOSE_DATA, "quic.invalid_path_close_data" },
-  // ACK frame data is malformed.
-  { net::QUIC_INVALID_ACK_DATA, "quic.invalid.ack_data" },
+    // Connection has reached an invalid state.
+    {net::QUIC_INTERNAL_ERROR, "quic.internal_error"},
+    // There were data frames after the a fin or reset.
+    {net::QUIC_STREAM_DATA_AFTER_TERMINATION,
+     "quic.stream_data.after_termination"},
+    // Control frame is malformed.
+    {net::QUIC_INVALID_PACKET_HEADER, "quic.invalid.packet_header"},
+    // Frame data is malformed.
+    {net::QUIC_INVALID_FRAME_DATA, "quic.invalid_frame_data"},
+    // The packet contained no payload.
+    {net::QUIC_MISSING_PAYLOAD, "quic.missing.payload"},
+    // FEC data is malformed.
+    {net::QUIC_INVALID_FEC_DATA, "quic.invalid.fec_data"},
+    // STREAM frame data is malformed.
+    {net::QUIC_INVALID_STREAM_DATA, "quic.invalid.stream_data"},
+    // STREAM frame data is not encrypted.
+    {net::QUIC_UNENCRYPTED_STREAM_DATA, "quic.unencrypted.stream_data"},
+    // Attempt to send unencrypted STREAM frame.
+    {net::QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA,
+     "quic.attempt.to.unencrypted.stream.data"},
+    // Received a frame which is likely the result of memory corruption.
+    {net::QUIC_MAYBE_CORRUPTED_MEMORY, "quic.maybe.corrupted.momery"},
+    // FEC frame data is not encrypted.
+    {net::QUIC_UNENCRYPTED_FEC_DATA, "quic.unencrypted.fec.data"},
+    // RST_STREAM frame data is malformed.
+    {net::QUIC_INVALID_RST_STREAM_DATA, "quic.invalid.rst_stream_data"},
+    // CONNECTION_CLOSE frame data is malformed.
+    {net::QUIC_INVALID_CONNECTION_CLOSE_DATA,
+     "quic.invalid.connection_close_data"},
+    // GOAWAY frame data is malformed.
+    {net::QUIC_INVALID_GOAWAY_DATA, "quic.invalid.goaway_data"},
+    // WINDOW_UPDATE frame data is malformed.
+    {net::QUIC_INVALID_WINDOW_UPDATE_DATA, "quic.invalid.window_update_data"},
+    // BLOCKED frame data is malformed.
+    {net::QUIC_INVALID_BLOCKED_DATA, "quic.invalid.blocked_data"},
+    // STOP_WAITING frame data is malformed.
+    {net::QUIC_INVALID_STOP_WAITING_DATA, "quic.invalid.stop_waiting_data"},
+    // PATH_CLOSE frame data is malformed.
+    {net::QUIC_INVALID_PATH_CLOSE_DATA, "quic.invalid_path_close_data"},
+    // ACK frame data is malformed.
+    {net::QUIC_INVALID_ACK_DATA, "quic.invalid.ack_data"},
 
-  // Version negotiation packet is malformed.
-  { net::QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
-   "quic_invalid_version_negotiation_packet" },
-  // Public RST packet is malformed.
-  { net::QUIC_INVALID_PUBLIC_RST_PACKET, "quic.invalid.public_rst_packet" },
+    // Version negotiation packet is malformed.
+    {net::QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
+     "quic_invalid_version_negotiation_packet"},
+    // Public RST packet is malformed.
+    {net::QUIC_INVALID_PUBLIC_RST_PACKET, "quic.invalid.public_rst_packet"},
 
-  // There was an error decrypting.
-  { net::QUIC_DECRYPTION_FAILURE, "quic.decryption.failure" },
-  // There was an error encrypting.
-  { net::QUIC_ENCRYPTION_FAILURE, "quic.encryption.failure" },
-  // The packet exceeded kMaxPacketSize.
-  { net::QUIC_PACKET_TOO_LARGE, "quic.packet.too_large" },
-  // The peer is going away.  May be a client or server.
-  { net::QUIC_PEER_GOING_AWAY, "quic.peer_going_away" },
-  // A stream ID was invalid.
-  { net::QUIC_INVALID_STREAM_ID, "quic.invalid_stream_id" },
-  // A priority was invalid.
-  { net::QUIC_INVALID_PRIORITY, "quic.invalid_priority" },
-  // Too many streams already open.
-  { net::QUIC_TOO_MANY_OPEN_STREAMS, "quic.too_many_open_streams" },
-  // The peer created too many available streams.
-  { net::QUIC_TOO_MANY_AVAILABLE_STREAMS, "quic.too_many_available_streams" },
-  // Received public reset for this connection.
-  { net::QUIC_PUBLIC_RESET, "quic.public_reset" },
-  // Invalid protocol version.
-  { net::QUIC_INVALID_VERSION, "quic.invalid_version" },
+    // There was an error decrypting.
+    {net::QUIC_DECRYPTION_FAILURE, "quic.decryption.failure"},
+    // There was an error encrypting.
+    {net::QUIC_ENCRYPTION_FAILURE, "quic.encryption.failure"},
+    // The packet exceeded kMaxPacketSize.
+    {net::QUIC_PACKET_TOO_LARGE, "quic.packet.too_large"},
+    // The peer is going away.  May be a client or server.
+    {net::QUIC_PEER_GOING_AWAY, "quic.peer_going_away"},
+    // A stream ID was invalid.
+    {net::QUIC_INVALID_STREAM_ID, "quic.invalid_stream_id"},
+    // A priority was invalid.
+    {net::QUIC_INVALID_PRIORITY, "quic.invalid_priority"},
+    // Too many streams already open.
+    {net::QUIC_TOO_MANY_OPEN_STREAMS, "quic.too_many_open_streams"},
+    // The peer created too many available streams.
+    {net::QUIC_TOO_MANY_AVAILABLE_STREAMS, "quic.too_many_available_streams"},
+    // Received public reset for this connection.
+    {net::QUIC_PUBLIC_RESET, "quic.public_reset"},
+    // Invalid protocol version.
+    {net::QUIC_INVALID_VERSION, "quic.invalid_version"},
 
-  // The Header ID for a stream was too far from the previous.
-  { net::QUIC_INVALID_HEADER_ID, "quic.invalid_header_id" },
-  // Negotiable parameter received during handshake had invalid value.
-  { net::QUIC_INVALID_NEGOTIATED_VALUE, "quic.invalid_negotiated_value" },
-  // There was an error decompressing data.
-  { net::QUIC_DECOMPRESSION_FAILURE, "quic.decompression_failure" },
-  // We hit our prenegotiated (or default) timeout
-  { net::QUIC_NETWORK_IDLE_TIMEOUT, "quic.connection.idle_time_out" },
-  // We hit our overall connection timeout
-  { net::QUIC_HANDSHAKE_TIMEOUT,
-   "quic.connection.handshake_timed_out" },
-  // There was an error encountered migrating addresses.
-  { net::QUIC_ERROR_MIGRATING_ADDRESS, "quic.error_migrating_address" },
-  // There was an error encountered migrating port only.
-  { net::QUIC_ERROR_MIGRATING_PORT, "quic.error_migrating_port" },
-  // There was an error while writing to the socket.
-  { net::QUIC_PACKET_WRITE_ERROR, "quic.packet.write_error" },
-  // There was an error while reading from the socket.
-  { net::QUIC_PACKET_READ_ERROR, "quic.packet.read_error" },
-  // We received a STREAM_FRAME with no data and no fin flag set.
-  { net::QUIC_EMPTY_STREAM_FRAME_NO_FIN, "quic.empty_stream_frame_no_fin" },
-  // We received invalid data on the headers stream.
-  { net::QUIC_INVALID_HEADERS_STREAM_DATA, "quic.invalid_headers_stream_data" },
-  // The peer received too much data, violating flow control.
-  { net::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
-   "quic.flow_control.received_too_much_data" },
-  // The peer sent too much data, violating flow control.
-  { net::QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA,
-   "quic.flow_control.sent_too_much_data" },
-  // The peer received an invalid flow control window.
-  { net::QUIC_FLOW_CONTROL_INVALID_WINDOW, "quic.flow_control.invalid_window" },
-  // The connection has been IP pooled into an existing connection.
-  { net::QUIC_CONNECTION_IP_POOLED, "quic.connection.ip_pooled" },
-  // The connection has too many outstanding sent packets.
-  { net::QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
-   "quic.too_many_outstanding_sent_packets" },
-  // The connection has too many outstanding received packets.
-  { net::QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
-   "quic.too_many_outstanding_received_packets" },
-  // The quic connection job to load server config is cancelled.
-  { net::QUIC_CONNECTION_CANCELLED, "quic.connection.cancelled" },
-  // Disabled QUIC because of high packet loss rate.
-  { net::QUIC_BAD_PACKET_LOSS_RATE, "quic.bad_packet_loss_rate" },
-  // Disabled QUIC because of too many PUBLIC_RESETs post handshake.
-  { net::QUIC_PUBLIC_RESETS_POST_HANDSHAKE,
-   "quic.public_resets_post_handshake" },
-  // Disabled QUIC because of too many timeouts with streams open.
-  { net::QUIC_TIMEOUTS_WITH_OPEN_STREAMS, "quic.timeouts_with_open_streams" },
-  // Closed because we failed to serialize a packet.
-  { net::QUIC_FAILED_TO_SERIALIZE_PACKET, "quic.failed_to_serialize_packet" },
-  // QUIC timed out after too many RTOs.
-  { net::QUIC_TOO_MANY_RTOS, "quic.too_many_rtos" },
-  // Crypto errors.
+    // The Header ID for a stream was too far from the previous.
+    {net::QUIC_INVALID_HEADER_ID, "quic.invalid_header_id"},
+    // Negotiable parameter received during handshake had invalid value.
+    {net::QUIC_INVALID_NEGOTIATED_VALUE, "quic.invalid_negotiated_value"},
+    // There was an error decompressing data.
+    {net::QUIC_DECOMPRESSION_FAILURE, "quic.decompression_failure"},
+    // We hit our prenegotiated (or default) timeout
+    {net::QUIC_NETWORK_IDLE_TIMEOUT, "quic.connection.idle_time_out"},
+    // We hit our overall connection timeout
+    {net::QUIC_HANDSHAKE_TIMEOUT, "quic.connection.handshake_timed_out"},
+    // There was an error encountered migrating addresses.
+    {net::QUIC_ERROR_MIGRATING_ADDRESS, "quic.error_migrating_address"},
+    // There was an error encountered migrating port only.
+    {net::QUIC_ERROR_MIGRATING_PORT, "quic.error_migrating_port"},
+    // There was an error while writing to the socket.
+    {net::QUIC_PACKET_WRITE_ERROR, "quic.packet.write_error"},
+    // There was an error while reading from the socket.
+    {net::QUIC_PACKET_READ_ERROR, "quic.packet.read_error"},
+    // We received a STREAM_FRAME with no data and no fin flag set.
+    {net::QUIC_EMPTY_STREAM_FRAME_NO_FIN, "quic.empty_stream_frame_no_fin"},
+    // We received invalid data on the headers stream.
+    {net::QUIC_INVALID_HEADERS_STREAM_DATA, "quic.invalid_headers_stream_data"},
+    // The peer received too much data, violating flow control.
+    {net::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
+     "quic.flow_control.received_too_much_data"},
+    // The peer sent too much data, violating flow control.
+    {net::QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA,
+     "quic.flow_control.sent_too_much_data"},
+    // The peer received an invalid flow control window.
+    {net::QUIC_FLOW_CONTROL_INVALID_WINDOW, "quic.flow_control.invalid_window"},
+    // The connection has been IP pooled into an existing connection.
+    {net::QUIC_CONNECTION_IP_POOLED, "quic.connection.ip_pooled"},
+    // The connection has too many outstanding sent packets.
+    {net::QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
+     "quic.too_many_outstanding_sent_packets"},
+    // The connection has too many outstanding received packets.
+    {net::QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
+     "quic.too_many_outstanding_received_packets"},
+    // The quic connection job to load server config is cancelled.
+    {net::QUIC_CONNECTION_CANCELLED, "quic.connection.cancelled"},
+    // Disabled QUIC because of high packet loss rate.
+    {net::QUIC_BAD_PACKET_LOSS_RATE, "quic.bad_packet_loss_rate"},
+    // Disabled QUIC because of too many PUBLIC_RESETs post handshake.
+    {net::QUIC_PUBLIC_RESETS_POST_HANDSHAKE,
+     "quic.public_resets_post_handshake"},
+    // Disabled QUIC because of too many timeouts with streams open.
+    {net::QUIC_TIMEOUTS_WITH_OPEN_STREAMS, "quic.timeouts_with_open_streams"},
+    // Closed because we failed to serialize a packet.
+    {net::QUIC_FAILED_TO_SERIALIZE_PACKET, "quic.failed_to_serialize_packet"},
+    // QUIC timed out after too many RTOs.
+    {net::QUIC_TOO_MANY_RTOS, "quic.too_many_rtos"},
+    // Crypto errors.
 
-  // Hanshake failed.
-  { net::QUIC_HANDSHAKE_FAILED, "quic.handshake_failed" },
-  // Handshake message contained out of order tags.
-  { net::QUIC_CRYPTO_TAGS_OUT_OF_ORDER, "quic.crypto.tags_out_of_order" },
-  // Handshake message contained too many entries.
-  { net::QUIC_CRYPTO_TOO_MANY_ENTRIES, "quic.crypto.too_many_entries" },
-  // Handshake message contained an invalid value length.
-  { net::QUIC_CRYPTO_INVALID_VALUE_LENGTH, "quic.crypto.invalid_value_length" },
-  // A crypto message was received after the handshake was complete.
-  { net::QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
-   "quic.crypto_message_after_handshake_complete" },
-  // A crypto message was received with an illegal message tag.
-  { net::QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "quic.invalid_crypto_message_type" },
-  // A crypto message was received with an illegal parameter.
-  { net::QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
-   "quic.invalid_crypto_message_parameter" },
-  // An invalid channel id signature was supplied.
-  { net::QUIC_INVALID_CHANNEL_ID_SIGNATURE,
-   "quic.invalid_channel_id_signature" },
-  // A crypto message was received with a mandatory parameter missing.
-  { net::QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
-   "quic.crypto_message.parameter_not_found" },
-  // A crypto message was received with a parameter that has no overlap
-  // with the local parameter.
-  { net::QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP,
-   "quic.crypto_message.parameter_no_overlap" },
-  // A crypto message was received that contained a parameter with too few
-  // values.
-  { net::QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND,
-   "quic_crypto_message_index_not_found" },
-  // A demand for an unsupport proof type was received.
-  { net::QUIC_UNSUPPORTED_PROOF_DEMAND, "quic.unsupported_proof_demand" },
-  // An internal error occured in crypto processing.
-  { net::QUIC_CRYPTO_INTERNAL_ERROR, "quic.crypto.internal_error" },
-  // A crypto handshake message specified an unsupported version.
-  { net::QUIC_CRYPTO_VERSION_NOT_SUPPORTED,
-   "quic.crypto.version_not_supported" },
-  // A crypto handshake message resulted in a stateless reject.
-  { net::QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT,
-   "quic.crypto.handshake_stateless_reject" },
-  // There was no intersection between the crypto primitives supported by the
-  // peer and ourselves.
-  { net::QUIC_CRYPTO_NO_SUPPORT, "quic.crypto.no_support" },
-  // The server rejected our client hello messages too many times.
-  { net::QUIC_CRYPTO_TOO_MANY_REJECTS, "quic.crypto.too_many_rejects" },
-  // The client rejected the server's certificate chain or signature.
-  { net::QUIC_PROOF_INVALID, "quic.proof_invalid" },
-  // A crypto message was received with a duplicate tag.
-  { net::QUIC_CRYPTO_DUPLICATE_TAG, "quic.crypto.duplicate_tag" },
-  // A crypto message was received with the wrong encryption level (i.e. it
-  // should have been encrypted but was not.)
-  { net::QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
-   "quic.crypto.encryption_level_incorrect" },
-  // The server config for a server has expired.
-  { net::QUIC_CRYPTO_SERVER_CONFIG_EXPIRED,
-   "quic.crypto.server_config_expired" },
-  // We failed to setup the symmetric keys for a connection.
-  { net::QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
-   "quic.crypto.symmetric_key_setup_failed" },
-  // A handshake message arrived, but we are still validating the
-  // previous handshake message.
-  { net::QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
-   "quic.crypto_message_while_validating_client_hello" },
-  // A server config update arrived before the handshake is complete.
-  { net::QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
-   "quic.crypto.update_before_handshake_complete" },
-  // CHLO cannot fit in one packet.
-  { net::QUIC_CRYPTO_CHLO_TOO_LARGE,
-   "quic.crypto.chlo_too_large" },
-  // This connection involved a version negotiation which appears to have been
-  // tampered with.
-  { net::QUIC_VERSION_NEGOTIATION_MISMATCH,
-   "quic.version_negotiation_mismatch" },
+    // Hanshake failed.
+    {net::QUIC_HANDSHAKE_FAILED, "quic.handshake_failed"},
+    // Handshake message contained out of order tags.
+    {net::QUIC_CRYPTO_TAGS_OUT_OF_ORDER, "quic.crypto.tags_out_of_order"},
+    // Handshake message contained too many entries.
+    {net::QUIC_CRYPTO_TOO_MANY_ENTRIES, "quic.crypto.too_many_entries"},
+    // Handshake message contained an invalid value length.
+    {net::QUIC_CRYPTO_INVALID_VALUE_LENGTH, "quic.crypto.invalid_value_length"},
+    // A crypto message was received after the handshake was complete.
+    {net::QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
+     "quic.crypto_message_after_handshake_complete"},
+    // A crypto message was received with an illegal message tag.
+    {net::QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "quic.invalid_crypto_message_type"},
+    // A crypto message was received with an illegal parameter.
+    {net::QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+     "quic.invalid_crypto_message_parameter"},
+    // An invalid channel id signature was supplied.
+    {net::QUIC_INVALID_CHANNEL_ID_SIGNATURE,
+     "quic.invalid_channel_id_signature"},
+    // A crypto message was received with a mandatory parameter missing.
+    {net::QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
+     "quic.crypto_message.parameter_not_found"},
+    // A crypto message was received with a parameter that has no overlap
+    // with the local parameter.
+    {net::QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP,
+     "quic.crypto_message.parameter_no_overlap"},
+    // A crypto message was received that contained a parameter with too few
+    // values.
+    {net::QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND,
+     "quic_crypto_message_index_not_found"},
+    // A demand for an unsupport proof type was received.
+    {net::QUIC_UNSUPPORTED_PROOF_DEMAND, "quic.unsupported_proof_demand"},
+    // An internal error occured in crypto processing.
+    {net::QUIC_CRYPTO_INTERNAL_ERROR, "quic.crypto.internal_error"},
+    // A crypto handshake message specified an unsupported version.
+    {net::QUIC_CRYPTO_VERSION_NOT_SUPPORTED,
+     "quic.crypto.version_not_supported"},
+    // A crypto handshake message resulted in a stateless reject.
+    {net::QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT,
+     "quic.crypto.handshake_stateless_reject"},
+    // There was no intersection between the crypto primitives supported by the
+    // peer and ourselves.
+    {net::QUIC_CRYPTO_NO_SUPPORT, "quic.crypto.no_support"},
+    // The server rejected our client hello messages too many times.
+    {net::QUIC_CRYPTO_TOO_MANY_REJECTS, "quic.crypto.too_many_rejects"},
+    // The client rejected the server's certificate chain or signature.
+    {net::QUIC_PROOF_INVALID, "quic.proof_invalid"},
+    // A crypto message was received with a duplicate tag.
+    {net::QUIC_CRYPTO_DUPLICATE_TAG, "quic.crypto.duplicate_tag"},
+    // A crypto message was received with the wrong encryption level (i.e. it
+    // should have been encrypted but was not.)
+    {net::QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
+     "quic.crypto.encryption_level_incorrect"},
+    // The server config for a server has expired.
+    {net::QUIC_CRYPTO_SERVER_CONFIG_EXPIRED,
+     "quic.crypto.server_config_expired"},
+    // We failed to setup the symmetric keys for a connection.
+    {net::QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
+     "quic.crypto.symmetric_key_setup_failed"},
+    // A handshake message arrived, but we are still validating the
+    // previous handshake message.
+    {net::QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
+     "quic.crypto_message_while_validating_client_hello"},
+    // A server config update arrived before the handshake is complete.
+    {net::QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
+     "quic.crypto.update_before_handshake_complete"},
+    // CHLO cannot fit in one packet.
+    {net::QUIC_CRYPTO_CHLO_TOO_LARGE, "quic.crypto.chlo_too_large"},
+    // This connection involved a version negotiation which appears to have been
+    // tampered with.
+    {net::QUIC_VERSION_NEGOTIATION_MISMATCH,
+     "quic.version_negotiation_mismatch"},
 
-  // Multipath is not enabled, but a packet with multipath flag on is received.
-  { net::QUIC_BAD_MULTIPATH_FLAG, "quic.bad_multipath_flag" },
-  // A path is supposed to exist but does not.
-  { net::QUIC_MULTIPATH_PATH_DOES_NOT_EXIST,
-    "quic.quic_multipath_path_does_not_exist" },
-  // A path is supposed to be active but is not.
-  { net::QUIC_MULTIPATH_PATH_NOT_ACTIVE,
-    "quic.quic_multipath_path_not_active" },
+    // Multipath is not enabled, but a packet with multipath flag on is
+    // received.
+    {net::QUIC_BAD_MULTIPATH_FLAG, "quic.bad_multipath_flag"},
+    // A path is supposed to exist but does not.
+    {net::QUIC_MULTIPATH_PATH_DOES_NOT_EXIST,
+     "quic.quic_multipath_path_does_not_exist"},
+    // A path is supposed to be active but is not.
+    {net::QUIC_MULTIPATH_PATH_NOT_ACTIVE,
+     "quic.quic_multipath_path_not_active"},
 
-  // Network change and connection migration errors.
+    // Network change and connection migration errors.
 
-  // IP address changed causing connection close.
-  { net::QUIC_IP_ADDRESS_CHANGED, "quic.ip_address_changed" },
-  // Network changed, but connection had no migratable streams.
-  { net::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
-    "quic.connection_migration_no_migratable_streams" },
-  // Connection changed networks too many times.
-  { net::QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES,
-    "quic.connection_migration_too_many_changes" },
-  // Connection migration was attempted, but there was no new network to
-  // migrate to.
-  { net::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK,
-    "quic.connection_migration_no_new_network" },
-  // Network changed, but connection had one or more non-migratable streams.
-  { net::QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM,
-    "quic.connection_migration_non_migratable_stream" },
-  // Stream frame overlaps with buffered data.
-  { net::QUIC_OVERLAPPING_STREAM_DATA,
-    "quic.overlapping_stream_data" },
-  // Stream frames arrived too discontiguously so that stream sequencer buffer
-  // has too many gaps.
-  { net::QUIC_TOO_MANY_FRAME_GAPS,
-    "quic.too_many_frame_gaps" },
-  // Sequencer buffer get into weird state where continuing read/write
-  // will lead to crash.
-  { net::QUIC_STREAM_SEQUENCER_INVALID_STATE,
-    "quic.stream_sequencer_invalid_state" },
-  // Connection closed because of server hits max number of sessions allowed.
-  { net::QUIC_TOO_MANY_SESSIONS_ON_SERVER,
-    "quic.too_many_sessions_on_server" },
+    // IP address changed causing connection close.
+    {net::QUIC_IP_ADDRESS_CHANGED, "quic.ip_address_changed"},
+    // Network changed, but connection had no migratable streams.
+    {net::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
+     "quic.connection_migration_no_migratable_streams"},
+    // Connection changed networks too many times.
+    {net::QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES,
+     "quic.connection_migration_too_many_changes"},
+    // Connection migration was attempted, but there was no new network to
+    // migrate to.
+    {net::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK,
+     "quic.connection_migration_no_new_network"},
+    // Network changed, but connection had one or more non-migratable streams.
+    {net::QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM,
+     "quic.connection_migration_non_migratable_stream"},
+    // Stream frame overlaps with buffered data.
+    {net::QUIC_OVERLAPPING_STREAM_DATA, "quic.overlapping_stream_data"},
+    // Stream frames arrived too discontiguously so that stream sequencer buffer
+    // has too many gaps.
+    {net::QUIC_TOO_MANY_FRAME_GAPS, "quic.too_many_frame_gaps"},
+    // Sequencer buffer get into weird state where continuing read/write
+    // will lead to crash.
+    {net::QUIC_STREAM_SEQUENCER_INVALID_STATE,
+     "quic.stream_sequencer_invalid_state"},
+    // Connection closed because of server hits max number of sessions allowed.
+    {net::QUIC_TOO_MANY_SESSIONS_ON_SERVER, "quic.too_many_sessions_on_server"},
+    // There was an error decompressing data.
+    {net::QUIC_DECOMPRESSION_FAILURE, "quic.decompression_failure"},
 
-  // No error. Used as bound while iterating.
-  { net::QUIC_LAST_ERROR, "quic.last_error"}
-};
+    // No error. Used as bound while iterating.
+    {net::QUIC_LAST_ERROR, "quic.last_error"}};
 
 // Must be updated any time a net::QuicErrorCode is deprecated in
 // net/quic/core/quic_packets.h.
diff --git a/components/ntp_snippets/content_suggestion.cc b/components/ntp_snippets/content_suggestion.cc
index 3b007a4f..e5cac618 100644
--- a/components/ntp_snippets/content_suggestion.cc
+++ b/components/ntp_snippets/content_suggestion.cc
@@ -10,6 +10,9 @@
 
 DownloadSuggestionExtra::DownloadSuggestionExtra() = default;
 
+DownloadSuggestionExtra::DownloadSuggestionExtra(
+    const DownloadSuggestionExtra& other) = default;
+
 DownloadSuggestionExtra::~DownloadSuggestionExtra() = default;
 
 bool ContentSuggestion::ID::operator==(const ID& rhs) const {
diff --git a/components/ntp_snippets/content_suggestion.h b/components/ntp_snippets/content_suggestion.h
index ea17274c..b2403f6 100644
--- a/components/ntp_snippets/content_suggestion.h
+++ b/components/ntp_snippets/content_suggestion.h
@@ -21,8 +21,11 @@
 // download suggestions.
 struct DownloadSuggestionExtra {
   DownloadSuggestionExtra();
+  DownloadSuggestionExtra(const DownloadSuggestionExtra&);
   ~DownloadSuggestionExtra();
 
+  // The GUID for the downloaded file.
+  std::string download_guid;
   // The file path of the downloaded file once download completes.
   base::FilePath target_file_path;
   // The effective MIME type of downloaded content.
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 8ae228f..4a6507d 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -145,6 +145,7 @@
   }
 
   payments::mojom::PaymentDetails* details() { return details_.get(); }
+  payments::mojom::PaymentOptions* options() { return options_.get(); }
   const std::vector<std::string>& supported_card_networks() {
     return supported_card_networks_;
   }
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc
index 65c40b2..53c5d8c 100644
--- a/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -111,12 +111,14 @@
     const std::vector<GURL>& urls)
     : client(client),
       client_callback_type(client_callback_type),
-      result_threat_type(SB_THREAT_TYPE_SAFE),
+      most_severe_threat_type(SB_THREAT_TYPE_SAFE),
       stores_to_check(stores_to_check),
       urls(urls) {
   for (const auto& url : urls) {
     V4ProtocolManagerUtil::UrlToFullHashes(url, &full_hashes);
   }
+  DCHECK(full_hashes.size());
+  full_hash_threat_types.assign(full_hashes.size(), SB_THREAT_TYPE_SAFE);
 }
 
 V4LocalDatabaseManager::PendingCheck::PendingCheck(
@@ -126,9 +128,11 @@
     const std::set<FullHash>& full_hashes_set)
     : client(client),
       client_callback_type(client_callback_type),
-      result_threat_type(SB_THREAT_TYPE_SAFE),
+      most_severe_threat_type(SB_THREAT_TYPE_SAFE),
       stores_to_check(stores_to_check) {
   full_hashes.assign(full_hashes_set.begin(), full_hashes_set.end());
+  DCHECK(full_hashes.size());
+  full_hash_threat_types.assign(full_hashes.size(), SB_THREAT_TYPE_SAFE);
 }
 
 V4LocalDatabaseManager::PendingCheck::~PendingCheck() {}
@@ -503,20 +507,25 @@
 }
 
 void V4LocalDatabaseManager::GetSeverestThreatTypeAndMetadata(
-    SBThreatType* result_threat_type,
+    const std::vector<FullHashInfo>& full_hash_infos,
+    const std::vector<FullHash>& full_hashes,
+    std::vector<SBThreatType>* full_hash_threat_types,
+    SBThreatType* most_severe_threat_type,
     ThreatMetadata* metadata,
-    FullHash* matching_full_hash,
-    const std::vector<FullHashInfo>& full_hash_infos) {
-  DCHECK(result_threat_type);
-  DCHECK(metadata);
-  DCHECK(matching_full_hash);
-
+    FullHash* matching_full_hash) {
   ThreatSeverity most_severe_yet = kLeastSeverity;
   for (const FullHashInfo& fhi : full_hash_infos) {
     ThreatSeverity severity = GetThreatSeverity(fhi.list_id);
+    SBThreatType threat_type = GetSBThreatTypeForList(fhi.list_id);
+
+    const auto& it =
+        std::find(full_hashes.begin(), full_hashes.end(), fhi.full_hash);
+    DCHECK(it != full_hashes.end());
+    (*full_hash_threat_types)[it - full_hashes.begin()] = threat_type;
+
     if (severity < most_severe_yet) {
       most_severe_yet = severity;
-      *result_threat_type = GetSBThreatTypeForList(fhi.list_id);
+      *most_severe_threat_type = threat_type;
       *metadata = fhi.metadata;
       *matching_full_hash = fhi.full_hash;
     }
@@ -612,9 +621,10 @@
   }
 
   // Find out the most severe threat, if any, to report to the client.
-  GetSeverestThreatTypeAndMetadata(&check->result_threat_type,
-                                   &check->url_metadata,
-                                   &check->matching_full_hash, full_hash_infos);
+  GetSeverestThreatTypeAndMetadata(
+      full_hash_infos, check->full_hashes, &check->full_hash_threat_types,
+      &check->most_severe_threat_type, &check->url_metadata,
+      &check->matching_full_hash);
   pending_checks_.erase(it);
   RespondToClient(std::move(check));
 }
@@ -673,24 +683,31 @@
     case ClientCallbackType::CHECK_URL_FOR_SUBRESOURCE_FILTER:
       DCHECK_EQ(1u, check->urls.size());
       check->client->OnCheckBrowseUrlResult(
-          check->urls[0], check->result_threat_type, check->url_metadata);
+          check->urls[0], check->most_severe_threat_type, check->url_metadata);
       break;
 
     case ClientCallbackType::CHECK_DOWNLOAD_URLS:
       check->client->OnCheckDownloadUrlResult(check->urls,
-                                              check->result_threat_type);
+                                              check->most_severe_threat_type);
       break;
 
     case ClientCallbackType::CHECK_RESOURCE_URL:
       DCHECK_EQ(1u, check->urls.size());
-      check->client->OnCheckResourceUrlResult(
-          check->urls[0], check->result_threat_type, check->matching_full_hash);
+      check->client->OnCheckResourceUrlResult(check->urls[0],
+                                              check->most_severe_threat_type,
+                                              check->matching_full_hash);
       break;
 
     case ClientCallbackType::CHECK_EXTENSION_IDS: {
-      const std::set<FullHash> extension_ids(check->full_hashes.begin(),
-                                             check->full_hashes.end());
-      check->client->OnCheckExtensionsResult(extension_ids);
+      DCHECK_EQ(check->full_hash_threat_types.size(),
+                check->full_hashes.size());
+      std::set<FullHash> unsafe_extension_ids;
+      for (size_t i = 0; i < check->full_hash_threat_types.size(); i++) {
+        if (check->full_hash_threat_types[i] == SB_THREAT_TYPE_EXTENSION) {
+          unsafe_extension_ids.insert(check->full_hashes[i]);
+        }
+      }
+      check->client->OnCheckExtensionsResult(unsafe_extension_ids);
       break;
     }
     case ClientCallbackType::CHECK_OTHER:
diff --git a/components/safe_browsing_db/v4_local_database_manager.h b/components/safe_browsing_db/v4_local_database_manager.h
index 4cf8160..e010dee 100644
--- a/components/safe_browsing_db/v4_local_database_manager.h
+++ b/components/safe_browsing_db/v4_local_database_manager.h
@@ -134,8 +134,8 @@
     // know whether the URL in |url| is safe or unsafe.
     const ClientCallbackType client_callback_type;
 
-    // The threat verdict for the URL being checked.
-    SBThreatType result_threat_type;
+    // The most severe threat verdict for the URLs/hashes being checked.
+    SBThreatType most_severe_threat_type;
 
     // When the check was sent to the SafeBrowsing service. Used to record the
     // time it takes to get the uncached full hashes from the service (or a
@@ -149,10 +149,13 @@
     // one of |full_hashes| and |urls| should be greater than 0.
     const std::vector<GURL> urls;
 
-    // The full hashes that are being checked for being safe. The size of
-    // exactly one of |full_hashes| and |urls| should be greater than 0.
+    // The full hashes that are being checked for being safe.
     std::vector<FullHash> full_hashes;
 
+    // The most severe SBThreatType for each full hash in |full_hashes|. The
+    // length of |full_hash_threat_type| must always match |full_hashes|.
+    std::vector<SBThreatType> full_hash_threat_types;
+
     // The metadata associated with the full hash of the severest match found
     // for that URL.
     ThreatMetadata url_metadata;
@@ -196,13 +199,18 @@
       const std::unique_ptr<PendingCheck>& check,
       FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes);
 
-  // Finds the most severe |SBThreatType| and the corresponding |metadata|, and
-  // |matching_full_hash| from |full_hash_infos|.
+  // Goes over the |full_hash_infos| and stores the most severe SBThreatType in
+  // |most_severe_threat_type|, the corresponding metadata in |metadata|, and
+  // the matching full hash in |matching_full_hash|. Also, updates in
+  // |full_hash_threat_types|, the threat type for each full hash in
+  // |full_hashes|.
   void GetSeverestThreatTypeAndMetadata(
-      SBThreatType* result_threat_type,
+      const std::vector<FullHashInfo>& full_hash_infos,
+      const std::vector<FullHash>& full_hashes,
+      std::vector<SBThreatType>* full_hash_threat_types,
+      SBThreatType* most_severe_threat_type,
       ThreatMetadata* metadata,
-      FullHash* matching_full_hash,
-      const std::vector<FullHashInfo>& full_hash_infos);
+      FullHash* matching_full_hash);
 
   // Returns the SBThreatType for a given ListIdentifier.
   SBThreatType GetSBThreatTypeForList(const ListIdentifier& list_id);
diff --git a/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
index e005c18..be6a792 100644
--- a/components/safe_browsing_db/v4_local_database_manager_unittest.cc
+++ b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -191,6 +191,21 @@
   V4LocalDatabaseManager* manager_to_cancel_;
 };
 
+class TestExtensionClient : public SafeBrowsingDatabaseManager::Client {
+ public:
+  TestExtensionClient(const std::set<FullHash>& expected_bad_crxs)
+      : expected_bad_crxs(expected_bad_crxs),
+        on_check_extensions_result_called_(false) {}
+
+  void OnCheckExtensionsResult(const std::set<FullHash>& bad_crxs) override {
+    EXPECT_EQ(expected_bad_crxs, bad_crxs);
+    on_check_extensions_result_called_ = true;
+  }
+
+  const std::set<FullHash> expected_bad_crxs;
+  bool on_check_extensions_result_called_;
+};
+
 class FakeV4LocalDatabaseManager : public V4LocalDatabaseManager {
  public:
   void PerformFullHashCheck(std::unique_ptr<PendingCheck> check,
@@ -404,32 +419,48 @@
 TEST_F(V4LocalDatabaseManagerTest, TestGetSeverestThreatTypeAndMetadata) {
   WaitForTasksOnTaskRunner();
 
-  FullHash full_hash("Malware");
-  FullHashInfo fhi_malware(full_hash, GetUrlMalwareId(), base::Time::Now());
+  FullHash fh_malware("Malware");
+  FullHashInfo fhi_malware(fh_malware, GetUrlMalwareId(), base::Time::Now());
   fhi_malware.metadata.population_id = "malware_popid";
 
-  FullHashInfo fhi_api(FullHash("api"), GetChromeUrlApiId(), base::Time::Now());
+  FullHash fh_api("api");
+  FullHashInfo fhi_api(fh_api, GetChromeUrlApiId(), base::Time::Now());
   fhi_api.metadata.population_id = "api_popid";
 
+  FullHash fh_example("example");
   std::vector<FullHashInfo> fhis({fhi_malware, fhi_api});
+  std::vector<FullHash> full_hashes({fh_malware, fh_example, fh_api});
 
+  std::vector<SBThreatType> full_hash_threat_types(full_hashes.size(),
+                                                   SB_THREAT_TYPE_SAFE);
   SBThreatType result_threat_type;
   ThreatMetadata metadata;
   FullHash matching_full_hash;
 
+  const std::vector<SBThreatType> expected_full_hash_threat_types(
+      {SB_THREAT_TYPE_URL_MALWARE, SB_THREAT_TYPE_SAFE,
+       SB_THREAT_TYPE_API_ABUSE});
+
   v4_local_database_manager_->GetSeverestThreatTypeAndMetadata(
-      &result_threat_type, &metadata, &matching_full_hash, fhis);
+      fhis, full_hashes, &full_hash_threat_types, &result_threat_type,
+      &metadata, &matching_full_hash);
+  EXPECT_EQ(expected_full_hash_threat_types, full_hash_threat_types);
+
   EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, result_threat_type);
   EXPECT_EQ("malware_popid", metadata.population_id);
-  EXPECT_EQ(full_hash, matching_full_hash);
+  EXPECT_EQ(fh_malware, matching_full_hash);
 
   // Reversing the list has no effect.
   std::reverse(std::begin(fhis), std::end(fhis));
+  full_hash_threat_types.assign(full_hashes.size(), SB_THREAT_TYPE_SAFE);
+
   v4_local_database_manager_->GetSeverestThreatTypeAndMetadata(
-      &result_threat_type, &metadata, &matching_full_hash, fhis);
+      fhis, full_hashes, &full_hash_threat_types, &result_threat_type,
+      &metadata, &matching_full_hash);
+  EXPECT_EQ(expected_full_hash_threat_types, full_hash_threat_types);
   EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, result_threat_type);
   EXPECT_EQ("malware_popid", metadata.population_id);
-  EXPECT_EQ(full_hash, matching_full_hash);
+  EXPECT_EQ(fh_malware, matching_full_hash);
 }
 
 TEST_F(V4LocalDatabaseManagerTest, TestChecksAreQueued) {
@@ -801,8 +832,64 @@
   EXPECT_TRUE(client.on_check_resource_url_result_called_);
 }
 
-// TODO(nparker): Add tests for
+TEST_F(V4LocalDatabaseManagerTest, TestCheckExtensionIDsNothingBlacklisted) {
+  // Setup to receive full-hash misses.
+  ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({}));
+
+  // Reset the database manager so it picks up the replacement protocol manager.
+  ResetLocalDatabaseManager();
+  WaitForTasksOnTaskRunner();
+
+  // bad_extension_id is in the local DB but the full hash won't match.
+  const FullHash bad_extension_id("aaaabbbbccccdddd"),
+      good_extension_id("ddddccccbbbbaaaa");
+
+  // Put a match in the db that will cause a protocol-manager request.
+  StoreAndHashPrefixes store_and_hash_prefixes;
+  store_and_hash_prefixes.emplace_back(GetChromeExtMalwareId(),
+                                       bad_extension_id);
+  ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+  const std::set<FullHash> expected_bad_crxs({});
+  const std::set<FullHash> extension_ids({good_extension_id, bad_extension_id});
+  TestExtensionClient client(expected_bad_crxs);
+  EXPECT_FALSE(
+      v4_local_database_manager_->CheckExtensionIDs(extension_ids, &client));
+  EXPECT_FALSE(client.on_check_extensions_result_called_);
+  WaitForTasksOnTaskRunner();
+  EXPECT_TRUE(client.on_check_extensions_result_called_);
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestCheckExtensionIDsOneIsBlacklisted) {
+  // bad_extension_id is in the local DB and the full hash will match.
+  const FullHash bad_extension_id("aaaabbbbccccdddd"),
+      good_extension_id("ddddccccbbbbaaaa");
+  FullHashInfo fhi(bad_extension_id, GetChromeExtMalwareId(), base::Time());
+
+  // Setup to receive full-hash hit.
+  ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({fhi}));
+
+  // Reset the database manager so it picks up the replacement protocol manager.
+  ResetLocalDatabaseManager();
+  WaitForTasksOnTaskRunner();
+
+  // Put a match in the db that will cause a protocol-manager request.
+  StoreAndHashPrefixes store_and_hash_prefixes;
+  store_and_hash_prefixes.emplace_back(GetChromeExtMalwareId(),
+                                       bad_extension_id);
+  ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+  const std::set<FullHash> expected_bad_crxs({bad_extension_id});
+  const std::set<FullHash> extension_ids({good_extension_id, bad_extension_id});
+  TestExtensionClient client(expected_bad_crxs);
+  EXPECT_FALSE(
+      v4_local_database_manager_->CheckExtensionIDs(extension_ids, &client));
+  EXPECT_FALSE(client.on_check_extensions_result_called_);
+  WaitForTasksOnTaskRunner();
+  EXPECT_TRUE(client.on_check_extensions_result_called_);
+}
+
+// TODO(vakh): By 03/15/2017: Add tests for
 //   CheckDownloadUrl()
-//   CheckExtensionIDs()
 
 }  // namespace safe_browsing
diff --git a/components/signin/OWNERS b/components/signin/OWNERS
index b3c8286..11e357e 100644
--- a/components/signin/OWNERS
+++ b/components/signin/OWNERS
@@ -1,2 +1,4 @@
 msarda@chromium.org
 rogerta@chromium.org
+
+# COMPONENT: Services>SignIn
diff --git a/components/sync_bookmarks/bookmark_model_associator.cc b/components/sync_bookmarks/bookmark_model_associator.cc
index 2305bb1..8376ee04 100644
--- a/components/sync_bookmarks/bookmark_model_associator.cc
+++ b/components/sync_bookmarks/bookmark_model_associator.cc
@@ -94,7 +94,7 @@
   // Maps bookmark node titles to instances, duplicates allowed.
   // Titles are converted to the sync internal format before
   // being used as keys for the map.
-  using BookmarkNodeMap = base::hash_multimap<std::string, const BookmarkNode*>;
+  using BookmarkNodeMap = std::multimap<std::string, const BookmarkNode*>;
   using BookmarkNodeRange =
       std::pair<BookmarkNodeMap::iterator, BookmarkNodeMap::iterator>;
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d1982fd4..6a325553 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -718,6 +718,8 @@
     "host_zoom_map_impl.h",
     "host_zoom_map_observer.cc",
     "host_zoom_map_observer.h",
+    "image_capture/image_capture_impl.cc",
+    "image_capture/image_capture_impl.h",
     "indexed_db/cursor_impl.cc",
     "indexed_db/cursor_impl.h",
     "indexed_db/database_impl.cc",
@@ -892,8 +894,6 @@
     "media/capture/audio_mirroring_manager.h",
     "media/capture/desktop_capture_device_uma_types.cc",
     "media/capture/desktop_capture_device_uma_types.h",
-    "media/capture/image_capture_impl.cc",
-    "media/capture/image_capture_impl.h",
     "media/capture/web_contents_audio_input_stream.cc",
     "media/capture/web_contents_audio_input_stream.h",
     "media/capture/web_contents_audio_muter.cc",
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 191cc57..1762d79 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -277,6 +277,8 @@
     LOG(ERROR) << message;
   } else if (strstr(message, "Could not obtain desktop path or name")) {
     LOG(ERROR) << message;
+  } else if (strstr(message, "Theme parsing error")) {
+    LOG(ERROR) << message;
   } else {
     LOG(DFATAL) << log_domain << ": " << message;
   }
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 014e75e..bf41fac 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -6048,13 +6048,13 @@
       static_cast<WebContentsImpl*>(shell()->web_contents());
   FrameTreeNode* root = web_contents->GetFrameTree()->root();
 
-  // Navigate to a simple page and then perform an in-page navigation.
+  // Navigate to a simple page and then perform a fragment change navigation.
   GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), start_url));
 
-  GURL same_page_url(
+  GURL fragment_change_url(
       embedded_test_server()->GetURL("a.com", "/title1.html#foo"));
-  EXPECT_TRUE(NavigateToURL(shell(), same_page_url));
+  EXPECT_TRUE(NavigateToURL(shell(), fragment_change_url));
   EXPECT_EQ(2, web_contents->GetController().GetEntryCount());
 
   // Replace the URL of the current NavigationEntry with one that will cause
@@ -6082,8 +6082,8 @@
   // classified as SAME_PAGE) was leaving the FrameNavigationEntry with the
   // same document sequence number as the previous entry but updates the URL.
   // Doing a back session history navigation now will cause the browser to
-  // consider it as in-page because of this matching document sequence number
-  // and lead to a mismatch of origin and URL in the renderer process.
+  // consider it as same document because of this matching document sequence
+  // number and lead to a mismatch of origin and URL in the renderer process.
   {
     TestNavigationObserver observer(web_contents);
     web_contents->GetController().GoBack();
@@ -6151,26 +6151,27 @@
 };
 
 // Test which simulates a race condition between a cross-origin, same-process
-// navigation and a same page session history navigation. When such a race
+// navigation and a same document session history navigation. When such a race
 // occurs, the renderer will commit the cross-origin navigation, updating its
 // version of the current document sequence number, and will send an IPC to the
 // browser process. The session history navigation comes after the commit for
 // the cross-origin navigation and updates the URL, but not the origin of the
 // document. This results in mismatch between the two and causes the renderer
 // process to be killed. See https://crbug.com/630103.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
-                       RaceCrossOriginNavigationAndSamePageHistoryNavigation) {
+IN_PROC_BROWSER_TEST_F(
+    NavigationControllerBrowserTest,
+    RaceCrossOriginNavigationAndSameDocumentHistoryNavigation) {
   WebContentsImpl* web_contents =
       static_cast<WebContentsImpl*>(shell()->web_contents());
   FrameTreeNode* root = web_contents->GetFrameTree()->root();
 
-  // Navigate to a simple page and then perform an in-page navigation.
+  // Navigate to a simple page and then perform a same document navigation.
   GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), start_url));
 
-  GURL same_page_url(
+  GURL same_document_url(
       embedded_test_server()->GetURL("a.com", "/title1.html#foo"));
-  EXPECT_TRUE(NavigateToURL(shell(), same_page_url));
+  EXPECT_TRUE(NavigateToURL(shell(), same_document_url));
   EXPECT_EQ(2, web_contents->GetController().GetEntryCount());
 
   // Create a GoBackAndCommitFilter, which will delay the commit IPC for a
@@ -6214,7 +6215,7 @@
     EXPECT_TRUE(ExecuteScriptAndExtractString(
         web_contents, "domAutomationController.send(document.origin)",
         &origin));
-    EXPECT_EQ(same_page_url.GetOrigin().spec(), origin + "/");
+    EXPECT_EQ(same_document_url.GetOrigin().spec(), origin + "/");
   } else {
     // Wait for the back navigation to commit as well.
     history_commit_observer.Wait();
@@ -6676,10 +6677,10 @@
   bool was_renderer_initiated_;
 };
 
-// Test that a same-page navigation does not lead to the deletion of the
-// NavigationHandle for an ongoing different page navigation.
+// Test that a same document navigation does not lead to the deletion of the
+// NavigationHandle for an ongoing different document navigation.
 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
-                       SamePageNavigationDoesntDeleteNavigationHandle) {
+                       SameDocumentNavigationDoesntDeleteNavigationHandle) {
   const GURL kURL1 = embedded_test_server()->GetURL("/title1.html");
   const GURL kPushStateURL =
       embedded_test_server()->GetURL("/title1.html#fragment");
@@ -6749,10 +6750,10 @@
 
 }
 
-// Tests that a same-page browser-initiated navigation is properly reported by
-// the NavigationHandle.
+// Tests that a same document browser-initiated navigation is properly reported
+// by the NavigationHandle.
 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
-                       SamePageBrowserInitiated) {
+                       SameDocumentBrowserInitiated) {
   const GURL kURL = embedded_test_server()->GetURL("/title1.html");
   const GURL kFragmentURL =
       embedded_test_server()->GetURL("/title1.html#fragment");
diff --git a/content/browser/image_capture/OWNERS b/content/browser/image_capture/OWNERS
new file mode 100644
index 0000000..d9e863e
--- /dev/null
+++ b/content/browser/image_capture/OWNERS
@@ -0,0 +1,4 @@
+mcasas@chromium.org
+miu@chromium.org
+
+# COMPONENT: Blink>ImageCapture
diff --git a/content/browser/media/capture/image_capture_impl.cc b/content/browser/image_capture/image_capture_impl.cc
similarity index 98%
rename from content/browser/media/capture/image_capture_impl.cc
rename to content/browser/image_capture/image_capture_impl.cc
index 5c1c7e1..3ce15a8 100644
--- a/content/browser/media/capture/image_capture_impl.cc
+++ b/content/browser/image_capture/image_capture_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/media/capture/image_capture_impl.h"
+#include "content/browser/image_capture/image_capture_impl.h"
 
 #include <utility>
 
diff --git a/content/browser/media/capture/image_capture_impl.h b/content/browser/image_capture/image_capture_impl.h
similarity index 83%
rename from content/browser/media/capture/image_capture_impl.h
rename to content/browser/image_capture/image_capture_impl.h
index a4b3cf4..7ea8c320 100644
--- a/content/browser/media/capture/image_capture_impl.h
+++ b/content/browser/image_capture/image_capture_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_IMAGE_CAPTURE_IMPL_H_
-#define CONTENT_BROWSER_MEDIA_CAPTURE_IMAGE_CAPTURE_IMPL_H_
+#ifndef CONTENT_BROWSER_IMAGE_CAPTURE_IMAGE_CAPTURE_IMPL_H_
+#define CONTENT_BROWSER_IMAGE_CAPTURE_IMAGE_CAPTURE_IMPL_H_
 
 #include "media/capture/mojo/image_capture.mojom.h"
 
@@ -32,4 +32,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_MEDIA_CAPTURE_IMAGE_CAPTURE_IMPL_H_
+#endif  // CONTENT_BROWSER_IMAGE_CAPTURE_IMAGE_CAPTURE_IMPL_H_
diff --git a/content/browser/media/session/media_session_service_impl_browsertest.cc b/content/browser/media/session/media_session_service_impl_browsertest.cc
index cfbdef1..90d4375 100644
--- a/content/browser/media/session/media_session_service_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_service_impl_browsertest.cc
@@ -175,17 +175,17 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MediaSessionServiceImplBrowserTest,
-                       DontResetServiceForSamePageNavigation) {
+                       DontResetServiceForSameDocumentNavigation) {
   NavigateToURL(shell(), GetTestUrl(".", "title1.html"));
   EnsurePlayer();
 
   EXPECT_TRUE(ExecuteScriptToSetUpMediaSessionSync());
 
-  // Start a same-page navigation and check the playback state, metadata,
+  // Start a fragment navigation and check the playback state, metadata,
   // actions are not reset.
-  GURL same_page_url = GetTestUrl(".", "title1.html");
-  same_page_url = GURL(same_page_url.spec() + "#some-anchor");
-  NavigateToURLAndWaitForFinish(shell(), same_page_url);
+  GURL fragment_change_url = GetTestUrl(".", "title1.html");
+  fragment_change_url = GURL(fragment_change_url.spec() + "#some-anchor");
+  NavigateToURLAndWaitForFinish(shell(), fragment_change_url);
 
   EXPECT_EQ(blink::mojom::MediaSessionPlaybackState::PLAYING,
             GetService()->playback_state());
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index bec9b52..085fd44 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -68,7 +68,7 @@
 void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
   delegated_frame_evictor_->SetVisible(true);
 
-  if (!local_surface_id_.is_valid() && !released_front_lock_.get()) {
+  if (!has_frame_ && !released_front_lock_.get()) {
     if (compositor_)
       released_front_lock_ = compositor_->GetCompositorLock();
   }
@@ -225,7 +225,7 @@
     const gfx::Point& point,
     RenderWidgetHostViewBase* target_view,
     gfx::Point* transformed_point) {
-  if (!local_surface_id_.is_valid())
+  if (!has_frame_)
     return false;
 
   return target_view->TransformPointToLocalCoordSpace(
@@ -261,7 +261,7 @@
 }
 
 void DelegatedFrameHost::UpdateGutters() {
-  if (!local_surface_id_.is_valid()) {
+  if (!has_frame_) {
     right_gutter_.reset();
     bottom_gutter_.reset();
     return;
@@ -366,8 +366,7 @@
 
   // To avoid unnecessary browser composites, try to go directly to the Surface
   // rather than through the Layer (which goes through the browser compositor).
-  if (local_surface_id_.is_valid() &&
-      request_copy_of_output_callback_for_testing_.is_null()) {
+  if (has_frame_ && request_copy_of_output_callback_for_testing_.is_null()) {
     support_->RequestCopyOfSurface(std::move(request));
   } else {
     RequestCopyOfOutput(std::move(request));
@@ -426,7 +425,7 @@
     // resources from the old one with resources from the new one which would
     // have the same id. Changing the layer to showing painted content destroys
     // the DelegatedRendererLayer.
-    EvictDelegatedFrame();
+    local_surface_id_ = cc::LocalSurfaceId();
     ResetCompositorFrameSinkSupport();
     CreateCompositorFrameSinkSupport();
     last_compositor_frame_sink_id_ = compositor_frame_sink_id;
@@ -455,7 +454,7 @@
 
     support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
 
-    if (allocated_new_local_surface_id) {
+    if (allocated_new_local_surface_id || !has_frame_) {
       // manager must outlive compositors using it.
       cc::SurfaceId surface_id(frame_sink_id_, local_surface_id_);
       cc::SurfaceInfo surface_info(surface_id, frame_device_scale_factor,
@@ -465,6 +464,8 @@
       current_surface_size_ = frame_size;
       current_scale_factor_ = frame_device_scale_factor;
     }
+
+    has_frame_ = true;
   }
   released_front_lock_ = NULL;
   current_frame_size_in_dip_ = frame_size_in_dip;
@@ -480,7 +481,7 @@
   if (compositor_)
     can_lock_compositor_ = NO_PENDING_COMMIT;
 
-  if (local_surface_id_.is_valid()) {
+  if (has_frame_) {
     delegated_frame_evictor_->SwappedFrame(
         client_->DelegatedFrameHostIsVisible());
   }
@@ -488,8 +489,7 @@
 }
 
 void DelegatedFrameHost::ClearDelegatedFrame() {
-  if (local_surface_id_.is_valid())
-    EvictDelegatedFrame();
+  EvictDelegatedFrame();
 }
 
 void DelegatedFrameHost::DidReceiveCompositorFrameAck() {
@@ -520,11 +520,11 @@
 }
 
 void DelegatedFrameHost::EvictDelegatedFrame() {
+  if (!has_frame_)
+    return;
   client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
-  if (local_surface_id_.is_valid()) {
-    support_->EvictFrame();
-    local_surface_id_ = cc::LocalSurfaceId();
-  }
+  support_->EvictFrame();
+  has_frame_ = false;
   delegated_frame_evictor_->DiscardedFrame();
   UpdateGutters();
 }
@@ -747,8 +747,7 @@
 // DelegatedFrameHost, ImageTransportFactoryObserver implementation:
 
 void DelegatedFrameHost::OnLostResources() {
-  if (local_surface_id_.is_valid())
-    EvictDelegatedFrame();
+  EvictDelegatedFrame();
   idle_frame_subscriber_textures_.clear();
   yuv_readback_pipeline_.reset();
 }
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h
index 01f4f65..0cba4c4 100644
--- a/content/browser/renderer_host/delegated_frame_host.h
+++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -178,9 +178,7 @@
     return cc::SurfaceId(frame_sink_id_, local_surface_id_);
   }
 
-  const cc::LocalSurfaceId& LocalSurfaceIdForTesting() const {
-    return local_surface_id_;
-  }
+  bool HasFrameForTesting() const { return has_frame_; }
 
   void OnCompositingDidCommitForTesting(ui::Compositor* compositor) {
     OnCompositingDidCommit(compositor);
@@ -339,6 +337,8 @@
 
   bool needs_begin_frame_ = false;
 
+  bool has_frame_ = false;
+
   std::unique_ptr<DelegatedFrameEvictor> delegated_frame_evictor_;
 };
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index b1a238d..b5e0205c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -78,13 +78,13 @@
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/gpu/shader_cache_factory.h"
 #include "content/browser/histogram_message_filter.h"
+#include "content/browser/image_capture/image_capture_impl.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
 #include "content/browser/loader/resource_message_filter.h"
 #include "content/browser/loader/resource_scheduler_filter.h"
 #include "content/browser/loader/url_loader_factory_impl.h"
 #include "content/browser/media/capture/audio_mirroring_manager.h"
-#include "content/browser/media/capture/image_capture_impl.h"
 #include "content/browser/media/media_internals.h"
 #include "content/browser/media/midi_host.h"
 #include "content/browser/memory/memory_coordinator_impl.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 8b36a472..60cb689 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -421,12 +421,10 @@
     return GetDelegatedFrameHost()->SurfaceIdForTesting();
   }
 
-  const cc::LocalSurfaceId& GetLocalSurfaceId() const {
-    return GetDelegatedFrameHost()->LocalSurfaceIdForTesting();
+  bool HasFrameData() const {
+    return GetDelegatedFrameHost()->HasFrameForTesting();
   }
 
-  bool HasFrameData() const { return GetLocalSurfaceId().is_valid(); }
-
   bool released_front_lock_active() const {
     return GetDelegatedFrameHost()->ReleasedFrontLockActiveForTesting();
   }
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index e333809..73ad92f 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -244,38 +244,40 @@
     base::FileEnumerator en(kSelinuxPath, false, base::FileEnumerator::FILES);
     bool has_selinux_files = !en.Next().empty();
 
-    selinux = access(kSelinuxPath.value().c_str(), X_OK) == 0 &&
-              has_selinux_files;
+    selinux =
+        has_selinux_files && access(kSelinuxPath.value().c_str(), X_OK) == 0;
     selinux_valid = true;
   }
 
-  if (use_suid_sandbox_for_adj_oom_score_ && !selinux) {
-    // If heap profiling is running, these processes are not exiting, at least
-    // on ChromeOS. The easiest thing to do is not launch them when profiling.
-    // TODO(stevenjb): Investigate further and fix.
-    if (base::allocator::IsHeapProfilerRunning())
-      return;
-
-    std::vector<std::string> adj_oom_score_cmdline;
-    adj_oom_score_cmdline.push_back(sandbox_binary_);
-    adj_oom_score_cmdline.push_back(sandbox::kAdjustOOMScoreSwitch);
-    adj_oom_score_cmdline.push_back(base::Int64ToString(pid));
-    adj_oom_score_cmdline.push_back(base::IntToString(score));
-
-    base::Process sandbox_helper_process;
-    base::LaunchOptions options;
-
-    // sandbox_helper_process is a setuid binary.
-    options.allow_new_privs = true;
-
-    sandbox_helper_process =
-        base::LaunchProcess(adj_oom_score_cmdline, options);
-    if (sandbox_helper_process.IsValid())
-      base::EnsureProcessGetsReaped(sandbox_helper_process.Pid());
-  } else if (!use_suid_sandbox_for_adj_oom_score_) {
+  if (!use_suid_sandbox_for_adj_oom_score_) {
     if (!base::AdjustOOMScore(pid, score))
       PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid;
+    return;
   }
+
+  if (selinux)
+    return;
+
+  // If heap profiling is running, these processes are not exiting, at least
+  // on ChromeOS. The easiest thing to do is not launch them when profiling.
+  // TODO(stevenjb): Investigate further and fix.
+  if (base::allocator::IsHeapProfilerRunning())
+    return;
+
+  std::vector<std::string> adj_oom_score_cmdline;
+  adj_oom_score_cmdline.push_back(sandbox_binary_);
+  adj_oom_score_cmdline.push_back(sandbox::kAdjustOOMScoreSwitch);
+  adj_oom_score_cmdline.push_back(base::Int64ToString(pid));
+  adj_oom_score_cmdline.push_back(base::IntToString(score));
+
+  // sandbox_helper_process is a setuid binary.
+  base::LaunchOptions options;
+  options.allow_new_privs = true;
+
+  base::Process sandbox_helper_process =
+      base::LaunchProcess(adj_oom_score_cmdline, options);
+  if (sandbox_helper_process.IsValid())
+    base::EnsureProcessGetsReaped(sandbox_helper_process.Pid());
 }
 #endif
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
index c1276c8c3..43ef2d67d 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
@@ -4,19 +4,25 @@
 
 package org.chromium.content.browser;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
-import android.test.InstrumentationTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.LoaderErrors;
 import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 
 /**
  * Test of BrowserStartupController
  */
-public class BrowserStartupControllerTest extends InstrumentationTestCase {
-
+@RunWith(BaseJUnit4ClassRunner.class)
+public class BrowserStartupControllerTest {
     private TestBrowserStartupController mController;
 
     private static class TestBrowserStartupController extends BrowserStartupController {
@@ -84,9 +90,8 @@
         }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mController = new TestBrowserStartupController();
         // Setting the static singleton instance field enables more correct testing, since it is
         // is possible to call {@link BrowserStartupController#browserStartupComplete(int)} instead
@@ -94,6 +99,7 @@
         BrowserStartupController.overrideInstanceForTest(mController);
     }
 
+    @Test
     @SmallTest
     public void testSingleAsynchronousStartupRequest() {
         mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
@@ -107,25 +113,27 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
 
-        assertTrue("Asynchronous mode should have been set.",
+        Assert.assertTrue("Asynchronous mode should have been set.",
                 BrowserStartupController.browserMayStartAsynchonously());
-        assertEquals("The browser process should have been initialized one time.", 1,
+        Assert.assertEquals("The browser process should have been initialized one time.", 1,
                 mController.initializedCounter());
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
-        assertTrue("Callback should have been a success.", callback.mWasSuccess);
-        assertFalse("Callback should be told that the browser process was not already started.",
+        Assert.assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        Assert.assertTrue("Callback should have been a success.", callback.mWasSuccess);
+        Assert.assertFalse(
+                "Callback should be told that the browser process was not already started.",
                 callback.mAlreadyStarted);
     }
 
+    @Test
     @SmallTest
     public void testMultipleAsynchronousStartupRequests() {
         mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
@@ -141,7 +149,7 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback1);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
@@ -151,7 +159,7 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback2);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
@@ -162,26 +170,28 @@
             }
         });
 
-        assertTrue("Asynchronous mode should have been set.",
+        Assert.assertTrue("Asynchronous mode should have been set.",
                 BrowserStartupController.browserMayStartAsynchonously());
-        assertEquals("The browser process should have been initialized one time.", 1,
+        Assert.assertEquals("The browser process should have been initialized one time.", 1,
                 mController.initializedCounter());
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
-        assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
-        assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
-        assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
-        assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
-        assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
+        Assert.assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
+        Assert.assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
+        Assert.assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
+        Assert.assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
+        Assert.assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
+        Assert.assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
         // Some startup tasks might have been enqueued after the browser process was started, but
         // not the first one which kicked of the startup.
-        assertFalse("Callback 1 should be told that the browser process was not already started.",
+        Assert.assertFalse(
+                "Callback 1 should be told that the browser process was not already started.",
                 callback1.mAlreadyStarted);
     }
 
+    @Test
     @SmallTest
     public void testConsecutiveAsynchronousStartupRequests() {
         mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
@@ -196,7 +206,7 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback1);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
@@ -207,18 +217,18 @@
             }
         });
 
-        assertTrue("Asynchronous mode should have been set.",
+        Assert.assertTrue("Asynchronous mode should have been set.",
                 BrowserStartupController.browserMayStartAsynchonously());
-        assertEquals("The browser process should have been initialized one time.", 1,
+        Assert.assertEquals("The browser process should have been initialized one time.", 1,
                 mController.initializedCounter());
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
-        assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
-        assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
-        assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
+        Assert.assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
+        Assert.assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
+        Assert.assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
+        Assert.assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
 
         final TestStartupCallback callback3 = new TestStartupCallback();
         final TestStartupCallback callback4 = new TestStartupCallback();
@@ -230,7 +240,7 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback3);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
@@ -242,18 +252,19 @@
         });
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
-        assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
-        assertTrue("Callback 3 should be told that the browser process was already started.",
+        Assert.assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
+        Assert.assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
+        Assert.assertTrue("Callback 3 should be told that the browser process was already started.",
                 callback3.mAlreadyStarted);
-        assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
-        assertTrue("Callback 4 should have been a success.", callback4.mWasSuccess);
-        assertTrue("Callback 4 should be told that the browser process was already started.",
+        Assert.assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
+        Assert.assertTrue("Callback 4 should have been a success.", callback4.mWasSuccess);
+        Assert.assertTrue("Callback 4 should be told that the browser process was already started.",
                 callback4.mAlreadyStarted);
     }
 
+    @Test
     @SmallTest
     public void testSingleFailedAsynchronousStartupRequest() {
         mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
@@ -267,23 +278,24 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
 
-        assertTrue("Asynchronous mode should have been set.",
+        Assert.assertTrue("Asynchronous mode should have been set.",
                 BrowserStartupController.browserMayStartAsynchonously());
-        assertEquals("The browser process should have been initialized one time.", 1,
+        Assert.assertEquals("The browser process should have been initialized one time.", 1,
                 mController.initializedCounter());
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
-        assertTrue("Callback should have been a failure.", callback.mWasFailure);
+        Assert.assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        Assert.assertTrue("Callback should have been a failure.", callback.mWasFailure);
     }
 
+    @Test
     @SmallTest
     public void testConsecutiveFailedAsynchronousStartupRequests() {
         mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
@@ -298,7 +310,7 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback1);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
@@ -309,18 +321,18 @@
             }
         });
 
-        assertTrue("Asynchronous mode should have been set.",
+        Assert.assertTrue("Asynchronous mode should have been set.",
                 BrowserStartupController.browserMayStartAsynchonously());
-        assertEquals("The browser process should have been initialized one time.", 1,
+        Assert.assertEquals("The browser process should have been initialized one time.", 1,
                 mController.initializedCounter());
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
-        assertTrue("Callback 1 should have been a failure.", callback1.mWasFailure);
-        assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
-        assertTrue("Callback 2 should have been a failure.", callback2.mWasFailure);
+        Assert.assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
+        Assert.assertTrue("Callback 1 should have been a failure.", callback1.mWasFailure);
+        Assert.assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
+        Assert.assertTrue("Callback 2 should have been a failure.", callback2.mWasFailure);
 
         final TestStartupCallback callback3 = new TestStartupCallback();
         final TestStartupCallback callback4 = new TestStartupCallback();
@@ -332,7 +344,7 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback3);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
@@ -344,14 +356,15 @@
         });
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
-        assertTrue("Callback 3 should have been a failure.", callback3.mWasFailure);
-        assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
-        assertTrue("Callback 4 should have been a failure.", callback4.mWasFailure);
+        Assert.assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
+        Assert.assertTrue("Callback 3 should have been a failure.", callback3.mWasFailure);
+        Assert.assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
+        Assert.assertTrue("Callback 4 should have been a failure.", callback4.mWasFailure);
     }
 
+    @Test
     @SmallTest
     public void testSingleSynchronousRequest() {
         mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
@@ -363,17 +376,18 @@
                 try {
                     mController.startBrowserProcessesSync(false);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
-        assertFalse("Synchronous mode should have been set",
+        Assert.assertFalse("Synchronous mode should have been set",
                 BrowserStartupController.browserMayStartAsynchonously());
 
-        assertEquals("The browser process should have been initialized one time.", 1,
+        Assert.assertEquals("The browser process should have been initialized one time.", 1,
                 mController.initializedCounter());
     }
 
+    @Test
     @SmallTest
     public void testAsyncThenSyncRequests() {
         mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
@@ -387,7 +401,7 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
                 // To ensure that the async startup doesn't complete too soon we have
                 // to do both these in a since Runnable instance. This avoids the
@@ -395,22 +409,24 @@
                 try {
                     mController.startBrowserProcessesSync(false);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
-        assertFalse("Synchronous mode should have been set",
+        Assert.assertFalse("Synchronous mode should have been set",
                 BrowserStartupController.browserMayStartAsynchonously());
 
-        assertEquals("The browser process should have been initialized twice.", 2,
+        Assert.assertEquals("The browser process should have been initialized twice.", 2,
                 mController.initializedCounter());
 
-        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
-        assertTrue("Callback should have been a success.", callback.mWasSuccess);
-        assertFalse("Callback should be told that the browser process was not already started.",
+        Assert.assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        Assert.assertTrue("Callback should have been a success.", callback.mWasSuccess);
+        Assert.assertFalse(
+                "Callback should be told that the browser process was not already started.",
                 callback.mAlreadyStarted);
     }
 
+    @Test
     @SmallTest
     public void testSyncThenAsyncRequests() {
         mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
@@ -424,15 +440,15 @@
                 try {
                     mController.startBrowserProcessesSync(false);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
 
-        assertEquals("The browser process should have been initialized once.", 1,
+        Assert.assertEquals("The browser process should have been initialized once.", 1,
                 mController.initializedCounter());
 
-        assertFalse("Synchronous mode should have been set",
+        Assert.assertFalse("Synchronous mode should have been set",
                 BrowserStartupController.browserMayStartAsynchonously());
 
         // Kick off the asynchronous startup request. This should just queue the callback.
@@ -442,23 +458,24 @@
                 try {
                     mController.startBrowserProcessesAsync(true, callback);
                 } catch (Exception e) {
-                    fail("Browser should have started successfully");
+                    Assert.fail("Browser should have started successfully");
                 }
             }
         });
 
-        assertEquals("The browser process should not have been initialized a second time.", 1,
-                mController.initializedCounter());
+        Assert.assertEquals("The browser process should not have been initialized a second time.",
+                1, mController.initializedCounter());
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
-        assertTrue("Callback should have been a success.", callback.mWasSuccess);
-        assertTrue("Callback should be told that the browser process was already started.",
+        Assert.assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        Assert.assertTrue("Callback should have been a success.", callback.mWasSuccess);
+        Assert.assertTrue("Callback should be told that the browser process was already started.",
                 callback.mAlreadyStarted);
     }
 
+    @Test
     @SmallTest
     public void testLibraryLoadFails() {
         mController.mLibraryLoadSucceeds = false;
@@ -470,18 +487,18 @@
             public void run() {
                 try {
                     mController.startBrowserProcessesAsync(true, callback);
-                    fail("Browser should not have started successfully");
+                    Assert.fail("Browser should not have started successfully");
                 } catch (Exception e) {
                     // Exception expected, ignore.
                 }
             }
         });
 
-        assertEquals("The browser process should not have been initialized.", 0,
+        Assert.assertEquals("The browser process should not have been initialized.", 0,
                 mController.initializedCounter());
 
         // Wait for callbacks to complete.
-        getInstrumentation().waitForIdleSync();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
 
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java
index a6575931..6b2aae8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java
@@ -6,16 +6,27 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.CommandLine;
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
-import org.chromium.content.browser.test.NativeLibraryTestBase;
+import org.chromium.content.browser.test.NativeLibraryTestRule;
 import org.chromium.content_shell_apk.ContentShellApplication;
 
 /**
  * Test class for command lines.
  */
-public class ContentCommandLineTest extends NativeLibraryTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ContentCommandLineTest {
+    @Rule
+    public NativeLibraryTestRule mActivityTestRule = new NativeLibraryTestRule();
+
     // A reference command line. Note that switch2 is [brea\d], switch3 is [and "butter"],
     // and switch4 is [a "quoted" 'food'!]
     static final String INIT_SWITCHES[] = { "init_command", "--switch", "Arg",
@@ -33,65 +44,65 @@
     static final String CL_ADDED_SWITCH_2 = "username";
     static final String CL_ADDED_VALUE_2 = "bozo";
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         CommandLine.reset();
     }
 
     void loadJni() {
-        assertFalse(CommandLine.getInstance().isNativeImplementation());
-        loadNativeLibraryNoBrowserProcess();
-        assertTrue(CommandLine.getInstance().isNativeImplementation());
+        Assert.assertFalse(CommandLine.getInstance().isNativeImplementation());
+        mActivityTestRule.loadNativeLibraryNoBrowserProcess();
+        Assert.assertTrue(CommandLine.getInstance().isNativeImplementation());
     }
 
     void checkInitSwitches() {
         CommandLine cl = CommandLine.getInstance();
-        assertFalse(cl.hasSwitch("init_command"));
-        assertTrue(cl.hasSwitch("switch"));
-        assertFalse(cl.hasSwitch("--switch"));
-        assertFalse(cl.hasSwitch("arg"));
-        assertFalse(cl.hasSwitch("actually_an_arg"));
-        assertEquals("brea\\d", cl.getSwitchValue("switch2"));
-        assertEquals("and \"butter\"", cl.getSwitchValue("switch3"));
-        assertEquals("a \"quoted\" 'food'!", cl.getSwitchValue("switch4"));
-        assertNull(cl.getSwitchValue("switch"));
-        assertNull(cl.getSwitchValue("non-existant"));
+        Assert.assertFalse(cl.hasSwitch("init_command"));
+        Assert.assertTrue(cl.hasSwitch("switch"));
+        Assert.assertFalse(cl.hasSwitch("--switch"));
+        Assert.assertFalse(cl.hasSwitch("arg"));
+        Assert.assertFalse(cl.hasSwitch("actually_an_arg"));
+        Assert.assertEquals("brea\\d", cl.getSwitchValue("switch2"));
+        Assert.assertEquals("and \"butter\"", cl.getSwitchValue("switch3"));
+        Assert.assertEquals("a \"quoted\" 'food'!", cl.getSwitchValue("switch4"));
+        Assert.assertNull(cl.getSwitchValue("switch"));
+        Assert.assertNull(cl.getSwitchValue("non-existant"));
     }
 
     void checkSettingThenGetting() {
         CommandLine cl = CommandLine.getInstance();
 
         // Add a plain switch.
-        assertFalse(cl.hasSwitch(CL_ADDED_SWITCH));
+        Assert.assertFalse(cl.hasSwitch(CL_ADDED_SWITCH));
         cl.appendSwitch(CL_ADDED_SWITCH);
-        assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
+        Assert.assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
 
         // Add a switch paired with a value.
-        assertFalse(cl.hasSwitch(CL_ADDED_SWITCH_2));
-        assertNull(cl.getSwitchValue(CL_ADDED_SWITCH_2));
+        Assert.assertFalse(cl.hasSwitch(CL_ADDED_SWITCH_2));
+        Assert.assertNull(cl.getSwitchValue(CL_ADDED_SWITCH_2));
         cl.appendSwitchWithValue(CL_ADDED_SWITCH_2, CL_ADDED_VALUE_2);
-        assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
+        Assert.assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
 
         // Append a few new things.
         final String switchesAndArgs[] = { "dummy", "--superfast", "--speed=turbo" };
-        assertFalse(cl.hasSwitch("dummy"));
-        assertFalse(cl.hasSwitch("superfast"));
-        assertNull(cl.getSwitchValue("speed"));
+        Assert.assertFalse(cl.hasSwitch("dummy"));
+        Assert.assertFalse(cl.hasSwitch("superfast"));
+        Assert.assertNull(cl.getSwitchValue("speed"));
         cl.appendSwitchesAndArguments(switchesAndArgs);
-        assertFalse(cl.hasSwitch("dummy"));
-        assertFalse(cl.hasSwitch("command"));
-        assertTrue(cl.hasSwitch("superfast"));
-        assertTrue("turbo".equals(cl.getSwitchValue("speed")));
+        Assert.assertFalse(cl.hasSwitch("dummy"));
+        Assert.assertFalse(cl.hasSwitch("command"));
+        Assert.assertTrue(cl.hasSwitch("superfast"));
+        Assert.assertTrue("turbo".equals(cl.getSwitchValue("speed")));
     }
 
     void checkAppendedSwitchesPassedThrough() {
         CommandLine cl = CommandLine.getInstance();
-        assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
-        assertTrue(cl.hasSwitch(CL_ADDED_SWITCH_2));
-        assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
+        Assert.assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
+        Assert.assertTrue(cl.hasSwitch(CL_ADDED_SWITCH_2));
+        Assert.assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
     }
 
+    @Test
     @MediumTest
     @Feature({"Android-AppBase"})
     public void testJavaNativeTransition() {
@@ -102,6 +113,7 @@
         checkSettingThenGetting();
     }
 
+    @Test
     @MediumTest
     @Feature({"Android-AppBase"})
     public void testJavaNativeTransitionAfterAppends() {
@@ -113,6 +125,7 @@
         checkAppendedSwitchesPassedThrough();
     }
 
+    @Test
     @MediumTest
     @Feature({"Android-AppBase"})
     public void testNativeInitialization() {
@@ -126,6 +139,7 @@
         checkSettingThenGetting();
     }
 
+    @Test
     @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
     @MediumTest
     @Feature({"Android-AppBase"})
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
index 319e77df..172c989 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
@@ -4,15 +4,24 @@
 
 package org.chromium.content.browser;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
 import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 import org.chromium.device.geolocation.LocationProviderFactory;
 import org.chromium.device.geolocation.MockLocationProvider;
 
@@ -23,44 +32,48 @@
  * with ContentView APIs - e.g. that it's started and stopped as the
  * ContentView is hidden or shown.
  */
-public class ContentViewLocationTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ContentViewLocationTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
 
     private TestCallbackHelperContainer mTestCallbackHelperContainer;
     private TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper mJavascriptHelper;
     private MockLocationProvider mMockLocationProvider;
 
     private void hideContentViewOnUiThread() {
-        getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    getContentViewCore().onHide();
-                }
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mActivityTestRule.getContentViewCore().onHide();
+            }
         });
     }
 
     private void showContentViewOnUiThread() {
-        getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    getContentViewCore().onShow();
-                }
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mActivityTestRule.getContentViewCore().onShow();
+            }
         });
     }
 
     private void pollForPositionCallback() throws Throwable {
-        mJavascriptHelper.evaluateJavaScriptForTests(getWebContents(),
-                "positionCount = 0");
+        mJavascriptHelper.evaluateJavaScriptForTests(
+                mActivityTestRule.getWebContents(), "positionCount = 0");
         mJavascriptHelper.waitUntilHasValue();
-        assertEquals(0, Integer.parseInt(mJavascriptHelper.getJsonResultAndClear()));
+        Assert.assertEquals(0, Integer.parseInt(mJavascriptHelper.getJsonResultAndClear()));
 
         CriteriaHelper.pollInstrumentationThread(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
-                    mJavascriptHelper.evaluateJavaScriptForTests(getWebContents(), "positionCount");
+                    mJavascriptHelper.evaluateJavaScriptForTests(
+                            mActivityTestRule.getWebContents(), "positionCount");
                     try {
                         mJavascriptHelper.waitUntilHasValue();
                     } catch (Exception e) {
-                        fail();
+                        Assert.fail();
                     }
                     return Integer.parseInt(mJavascriptHelper.getJsonResultAndClear()) > 0;
                 }
@@ -68,8 +81,8 @@
     }
 
     private void startGeolocationWatchPosition() throws Throwable {
-        mJavascriptHelper.evaluateJavaScriptForTests(getWebContents(),
-                "initiate_watchPosition();");
+        mJavascriptHelper.evaluateJavaScriptForTests(
+                mActivityTestRule.getWebContents(), "initiate_watchPosition();");
         mJavascriptHelper.waitUntilHasValue();
     }
 
@@ -82,35 +95,34 @@
         }));
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setUp() throws Exception {
         mMockLocationProvider = new MockLocationProvider();
         LocationProviderFactory.setLocationProviderImpl(mMockLocationProvider);
 
         try {
-            startActivityWithTestUrl("content/test/data/android/geolocation.html");
+            mActivityTestRule.launchContentShellWithUrlSync(
+                    "content/test/data/android/geolocation.html");
         } catch (Throwable t) {
-            fail();
+            Assert.fail();
         }
 
-        mTestCallbackHelperContainer = new TestCallbackHelperContainer(getContentViewCore());
+        mTestCallbackHelperContainer =
+                new TestCallbackHelperContainer(mActivityTestRule.getContentViewCore());
         mJavascriptHelper = new OnEvaluateJavaScriptResultHelper();
 
         ensureGeolocationRunning(false);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         mMockLocationProvider.stopUpdates();
-        super.tearDown();
     }
 
+    @Test
     @MediumTest
     @Feature({"Location"})
     public void testWatchHideShowStop() throws Throwable {
-
         startGeolocationWatchPosition();
         pollForPositionCallback();
         ensureGeolocationRunning(true);
@@ -119,8 +131,8 @@
         hideContentViewOnUiThread();
         ensureGeolocationRunning(false);
 
-        mJavascriptHelper.evaluateJavaScriptForTests(getWebContents(),
-                "positionCount = 0");
+        mJavascriptHelper.evaluateJavaScriptForTests(
+                mActivityTestRule.getWebContents(), "positionCount = 0");
         mJavascriptHelper.waitUntilHasValue();
 
         // Show the ContentView again and ensure that geolocation starts again.
@@ -129,11 +141,13 @@
         ensureGeolocationRunning(true);
 
         // Navigate away and ensure that geolocation stops.
-        loadUrl(getContentViewCore().getWebContents().getNavigationController(),
+        mActivityTestRule.loadUrl(
+                mActivityTestRule.getContentViewCore().getWebContents().getNavigationController(),
                 mTestCallbackHelperContainer, new LoadUrlParams("about:blank"));
         ensureGeolocationRunning(false);
     }
 
+    @Test
     @MediumTest
     @Feature({"Location"})
     public void testHideWatchResume() throws Throwable {
@@ -146,6 +160,7 @@
         ensureGeolocationRunning(true);
     }
 
+    @Test
     @MediumTest
     @Feature({"Location"})
     public void testWatchHideNewWatchShow() throws Throwable {
@@ -165,6 +180,7 @@
         ensureGeolocationRunning(true);
     }
 
+    @Test
     @MediumTest
     @Feature({"Location"})
     public void testHideWatchStopShow() throws Throwable {
@@ -172,7 +188,8 @@
         startGeolocationWatchPosition();
         ensureGeolocationRunning(false);
 
-        loadUrl(getContentViewCore().getWebContents().getNavigationController(),
+        mActivityTestRule.loadUrl(
+                mActivityTestRule.getContentViewCore().getWebContents().getNavigationController(),
                 mTestCallbackHelperContainer, new LoadUrlParams("about:blank"));
         showContentViewOnUiThread();
         ensureGeolocationRunning(false);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
index a2ad3824..a2cef5c 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
@@ -4,26 +4,36 @@
 
 package org.chromium.content.browser;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.DOMUtils;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.util.concurrent.TimeoutException;
 
 /**
  * Class which provides test coverage for Popup Zoomer.
  */
+@RunWith(BaseJUnit4ClassRunner.class)
 @RetryOnFailure
-public class ContentViewPopupZoomerTest extends ContentShellTestBase {
+public class ContentViewPopupZoomerTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static PopupZoomer findPopupZoomer(ViewGroup view) {
         assert view != null;
         for (int i = 0; i < view.getChildCount(); i++) {
@@ -85,13 +95,14 @@
     /**
      * Tests that shows a zoomer popup and makes sure it has valid dimensions.
      */
+    @Test
     @MediumTest
     @Feature({"Browser"})
     public void testPopupZoomerShowsUp() throws InterruptedException, TimeoutException {
-        launchContentShellWithUrl(generateTestUrl(100, 15, "clickme"));
-        waitForActiveShellToBeDoneLoading();
+        mActivityTestRule.launchContentShellWithUrl(generateTestUrl(100, 15, "clickme"));
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
-        final ContentViewCore viewCore = getContentViewCore();
+        final ContentViewCore viewCore = mActivityTestRule.getContentViewCore();
         final ViewGroup view = viewCore.getContainerView();
 
         // The popup should be hidden before the click.
@@ -108,20 +119,21 @@
     /**
      * Tests Popup zoomer hides when device back key is pressed.
      */
+    @Test
     @MediumTest
     @Feature({"Browser"})
     @RetryOnFailure
     public void testBackKeyDismissesPopupZoomer() throws InterruptedException, TimeoutException {
-        launchContentShellWithUrl(generateTestUrl(100, 15, "clickme"));
-        waitForActiveShellToBeDoneLoading();
+        mActivityTestRule.launchContentShellWithUrl(generateTestUrl(100, 15, "clickme"));
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
-        final ContentViewCore viewCore = getContentViewCore();
+        final ContentViewCore viewCore = mActivityTestRule.getContentViewCore();
         final ViewGroup view = viewCore.getContainerView();
 
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, false));
         DOMUtils.clickNode(viewCore, "clickme");
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, true));
-        sendKeys(KeyEvent.KEYCODE_BACK);
+        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
         // When device key is pressed, popup zoomer should hide if already showing.
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, false));
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java
index 0b54c26..d6a824d 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java
@@ -9,16 +9,26 @@
 import android.view.InputDevice;
 import android.view.MotionEvent;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.input.AnimationIntervalProvider;
 import org.chromium.content.browser.input.JoystickZoomProvider;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 /**
  * Tests that ContentView running inside ContentShell can be zoomed using gamepad joystick.
  */
-public class ContentViewZoomingTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ContentViewZoomingTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static final String LARGE_PAGE = UrlUtils.encodeHtmlDataUri("<html><head>"
             + "<meta name=\"viewport\" content=\"width=device-width, "
             + "initial-scale=2.0, minimum-scale=2.0, maximum-scale=5.0\" />"
@@ -48,7 +58,7 @@
 
         public void animateZoomTest(final MotionEvent joystickZoomEvent, final long animationTicks)
                 throws Throwable {
-            runTestOnUiThread(new Runnable() {
+            mActivityTestRule.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     onMotion(joystickZoomEvent);
@@ -77,67 +87,68 @@
         return joystickMotionEvent;
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        launchContentShellWithUrl(LARGE_PAGE);
-        waitForActiveShellToBeDoneLoading();
-        assertWaitForPageScaleFactorMatch(2.0f);
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.launchContentShellWithUrl(LARGE_PAGE);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(2.0f);
     }
 
+    @Test
     @SmallTest
     @Feature({"JoystickZoom"})
     public void testJoystickZoomIn() throws Throwable {
         MotionEvent rTriggerEvent;
         AnimationIntervalProvider intervalProvider = new TestAnimationIntervalProvider();
-        TestJoystickZoomProvider rtJoystickZoomProvider =
-                new TestJoystickZoomProvider(getContentViewCore(), intervalProvider);
+        TestJoystickZoomProvider rtJoystickZoomProvider = new TestJoystickZoomProvider(
+                mActivityTestRule.getContentViewCore(), intervalProvider);
         // Verify page does not zoom-in if trigger motion falls in deadzone.
         rTriggerEvent = simulateJoystickEvent(0.1f, true);
         rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 20);
-        assertWaitForPageScaleFactorMatch(2.0f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(2.0f);
 
         rTriggerEvent = simulateJoystickEvent(0.3f, true);
         rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 20);
-        assertWaitForPageScaleFactorMatch(2.2018466f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(2.2018466f);
 
         rTriggerEvent = simulateJoystickEvent(0.5f, true);
         rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 40);
-        assertWaitForPageScaleFactorMatch(3.033731f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(3.033731f);
 
         rTriggerEvent = simulateJoystickEvent(0.75f, true);
         rtJoystickZoomProvider.animateZoomTest(rTriggerEvent, 50);
-        assertWaitForPageScaleFactorMatch(5.0f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(5.0f);
     }
 
+    @Test
     @SmallTest
     @Feature({"JoystickZoom"})
     public void testJoystickZoomOut() throws Throwable {
         MotionEvent lTriggerEvent;
         AnimationIntervalProvider intervalProvider = new TestAnimationIntervalProvider();
-        TestJoystickZoomProvider ltJoystickZoomProvider =
-                new TestJoystickZoomProvider(getContentViewCore(), intervalProvider);
+        TestJoystickZoomProvider ltJoystickZoomProvider = new TestJoystickZoomProvider(
+                mActivityTestRule.getContentViewCore(), intervalProvider);
 
         // Zoom page to max size.
         lTriggerEvent = simulateJoystickEvent(1.0f, true);
         ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 60);
-        assertWaitForPageScaleFactorMatch(5.0f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(5.0f);
 
         // Verify page does not zoom-out if trigger motion falls in deadzone.
         lTriggerEvent = simulateJoystickEvent(0.1f, false);
         ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 20);
-        assertWaitForPageScaleFactorMatch(5.0f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(5.0f);
 
         lTriggerEvent = simulateJoystickEvent(0.3f, false);
         ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 40);
-        assertWaitForPageScaleFactorMatch(4.125306f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(4.125306f);
 
         lTriggerEvent = simulateJoystickEvent(0.5f, false);
         ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 50);
-        assertWaitForPageScaleFactorMatch(2.7635581f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(2.7635581f);
 
         lTriggerEvent = simulateJoystickEvent(0.75f, false);
         ltJoystickZoomProvider.animateZoomTest(lTriggerEvent, 60);
-        assertWaitForPageScaleFactorMatch(2.0f);
+        mActivityTestRule.assertWaitForPageScaleFactorMatch(2.0f);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/EncodeHtmlDataUriTest.java b/content/public/android/javatests/src/org/chromium/content/browser/EncodeHtmlDataUriTest.java
index 42805f7..a07a8e1 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/EncodeHtmlDataUriTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/EncodeHtmlDataUriTest.java
@@ -5,19 +5,24 @@
 package org.chromium.content.browser;
 
 import android.support.test.filters.SmallTest;
-import android.test.InstrumentationTestCase;
 
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.UrlUtils;
 
 import java.net.URI;
 import java.net.URLDecoder;
 
-public class EncodeHtmlDataUriTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class EncodeHtmlDataUriTest {
     private static final String DATA_URI_PREFIX = "data:text/html;utf-8,";
 
     private String getData(String dataUri) {
-        assertNotNull("Data URI is null", dataUri);
-        assertTrue("Incorrect HTML Data URI prefix", dataUri.startsWith(DATA_URI_PREFIX));
+        Assert.assertNotNull("Data URI is null", dataUri);
+        Assert.assertTrue("Incorrect HTML Data URI prefix", dataUri.startsWith(DATA_URI_PREFIX));
         return dataUri.substring(DATA_URI_PREFIX.length());
     }
 
@@ -26,30 +31,35 @@
         return URLDecoder.decode(data, "UTF-8");
     }
 
+    @Test
     @SmallTest
     public void testDelimitersEncoding() throws java.io.UnsupportedEncodingException {
         String testString = "><#%\"'";
         String encodedUri = UrlUtils.encodeHtmlDataUri(testString);
         String decodedUri = decode(encodedUri);
-        assertEquals("Delimiters are not properly encoded", decodedUri, testString);
+        Assert.assertEquals("Delimiters are not properly encoded", decodedUri, testString);
     }
 
+    @Test
     @SmallTest
     public void testUnwiseCharactersEncoding() throws java.io.UnsupportedEncodingException {
         String testString = "{}|\\^[]`";
         String encodedUri = UrlUtils.encodeHtmlDataUri(testString);
         String decodedUri = decode(encodedUri);
-        assertEquals("Unwise characters are not properly encoded", decodedUri, testString);
+        Assert.assertEquals("Unwise characters are not properly encoded", decodedUri, testString);
     }
 
+    @Test
     @SmallTest
     public void testWhitespaceEncoding() throws java.io.UnsupportedEncodingException {
         String testString = " \n\t";
         String encodedUri = UrlUtils.encodeHtmlDataUri(testString);
         String decodedUri = decode(encodedUri);
-        assertEquals("Whitespace characters are not properly encoded", decodedUri, testString);
+        Assert.assertEquals(
+                "Whitespace characters are not properly encoded", decodedUri, testString);
     }
 
+    @Test
     @SmallTest
     public void testReturnsValidUri()
             throws java.net.URISyntaxException, java.io.UnsupportedEncodingException {
@@ -59,6 +69,6 @@
         // Verify that the encoded URI is valid.
         new URI(encodedUri);
         // Verify that something sensible was encoded.
-        assertEquals("Simple HTML is not properly encoded", decodedUri, testString);
+        Assert.assertEquals("Simple HTML is not properly encoded", decodedUri, testString);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
index 497299d..31c50fc3 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
@@ -6,10 +6,16 @@
 
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 
 import junit.framework.Assert;
 
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.base.test.util.UrlUtils;
@@ -19,7 +25,7 @@
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
 import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.util.concurrent.TimeUnit;
 
@@ -27,7 +33,11 @@
  * Provides test environment for Gesture Detector Reset for Content Shell.
  * This is a helper class for Content Shell tests.
 */
-public class GestureDetectorResetTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class GestureDetectorResetTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static final long WAIT_TIMEOUT_SECONDS = scaleTimeout(2);
     private static final String CLICK_TEST_URL = UrlUtils.encodeHtmlDataUri("<html><body>"
             + "<button id=\"button\" "
@@ -90,16 +100,17 @@
      * Tests that showing a select popup and having the page reload while the popup is showing does
      * not assert.
      */
+    @Test
     @LargeTest
     @Feature({"Browser"})
     @RetryOnFailure
     public void testSeparateClicksAreRegisteredOnReload()
             throws InterruptedException, Exception, Throwable {
         // Load the test page.
-        launchContentShellWithUrl(CLICK_TEST_URL);
-        waitForActiveShellToBeDoneLoading();
+        mActivityTestRule.launchContentShellWithUrl(CLICK_TEST_URL);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
-        final ContentViewCore viewCore = getContentViewCore();
+        final ContentViewCore viewCore = mActivityTestRule.getContentViewCore();
         final TestCallbackHelperContainer viewClient =
                 new TestCallbackHelperContainer(viewCore);
         final OnPageFinishedHelper onPageFinishedHelper =
@@ -110,10 +121,10 @@
 
         // Reload the test page.
         int currentCallCount = onPageFinishedHelper.getCallCount();
-        getInstrumentation().runOnMainSync(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                getActivity().getActiveShell().loadUrl(CLICK_TEST_URL);
+                mActivityTestRule.getActivity().getActiveShell().loadUrl(CLICK_TEST_URL);
             }
         });
         onPageFinishedHelper.waitForCallback(currentCallCount, 1,
@@ -124,12 +135,15 @@
 
         // Directly navigate to the test page.
         currentCallCount = onPageFinishedHelper.getCallCount();
-        getInstrumentation().runOnMainSync(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                getActivity().getActiveShell().getContentViewCore().getWebContents()
-                        .getNavigationController().loadUrl(
-                                new LoadUrlParams(CLICK_TEST_URL));
+                mActivityTestRule.getActivity()
+                        .getActiveShell()
+                        .getContentViewCore()
+                        .getWebContents()
+                        .getNavigationController()
+                        .loadUrl(new LoadUrlParams(CLICK_TEST_URL));
             }
         });
         onPageFinishedHelper.waitForCallback(currentCallCount, 1,
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java
index 5efe0c7e7..2398c37 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java
@@ -4,11 +4,19 @@
 
 package org.chromium.content.browser;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.ImportantFileWriterAndroid;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
-import org.chromium.content.browser.test.NativeLibraryTestBase;
+import org.chromium.content.browser.test.NativeLibraryTestRule;
 
 import java.io.DataInputStream;
 import java.io.File;
@@ -23,62 +31,62 @@
  * work, so is not attempting to test that writes are atomic. Instead it is just
  * testing that the Java code is calling the native code correctly.
  */
-public class ImportantFileWriterAndroidTest extends NativeLibraryTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ImportantFileWriterAndroidTest {
+    @Rule
+    public NativeLibraryTestRule mActivityTestRule = new NativeLibraryTestRule();
 
     private void checkFile(File testFile, byte[] data) {
-        assertTrue(testFile.exists());
+        Assert.assertTrue(testFile.exists());
         try {
             byte[] fileData = new byte[(int) testFile.length()];
             DataInputStream dis =
                     new DataInputStream(new FileInputStream(testFile));
             dis.readFully(fileData);
             dis.close();
-            assertEquals("Data length wrong", data.length, fileData.length);
+            Assert.assertEquals("Data length wrong", data.length, fileData.length);
             for (int i = 0; i < data.length; i++) {
-                assertEquals("Data byte wrong", data[i], fileData[i]);
+                Assert.assertEquals("Data byte wrong", data[i], fileData[i]);
             }
         } catch (IOException e) {
-            fail("Failed to read file");
+            Assert.fail("Failed to read file");
         }
 
     }
 
+    @Test
     @SmallTest
     @Feature({"Android-AppBase"})
     public void testAtomicWrite() {
         // Try writing a file that can't be created.
         byte[] data1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        assertFalse("Writing bad file succeded",
-                ImportantFileWriterAndroid.writeFileAtomically(
-                        "/junk/junk", data1));
-        File dir = getInstrumentation().getTargetContext().getFilesDir();
+        Assert.assertFalse("Writing bad file succeded",
+                ImportantFileWriterAndroid.writeFileAtomically("/junk/junk", data1));
+        File dir = InstrumentationRegistry.getInstrumentation().getTargetContext().getFilesDir();
         File testFile = new File(dir, "ImportantFileTest");
 
         // Make sure the file doesn't already exist
         if (testFile.exists()) {
-            assertTrue(testFile.delete());
+            Assert.assertTrue(testFile.delete());
         }
 
         // Write a new file
-        assertTrue("Writing new file failed",
-                ImportantFileWriterAndroid.writeFileAtomically(
-                        testFile.getAbsolutePath(), data1));
+        Assert.assertTrue("Writing new file failed",
+                ImportantFileWriterAndroid.writeFileAtomically(testFile.getAbsolutePath(), data1));
         checkFile(testFile, data1);
         byte[] data2 = {10, 20, 30, 40, 50, 60, 70, 80};
 
         // Overwrite an existing file
-        assertTrue("Writing exiting file failed",
-                ImportantFileWriterAndroid.writeFileAtomically(
-                        testFile.getAbsolutePath(), data2));
+        Assert.assertTrue("Writing exiting file failed",
+                ImportantFileWriterAndroid.writeFileAtomically(testFile.getAbsolutePath(), data2));
         checkFile(testFile, data2);
 
         // Done, tidy up
-        assertTrue(testFile.delete());
+        Assert.assertTrue(testFile.delete());
     }
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-        loadNativeLibraryNoBrowserProcess();
+        mActivityTestRule.loadNativeLibraryNoBrowserProcess();
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
index 1bdba7b1..64a9c359 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
@@ -6,7 +6,14 @@
 
 import android.support.test.filters.LargeTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.base.test.util.UrlUtils;
@@ -16,7 +23,7 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.content_shell_apk.ContentShellActivity;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -24,7 +31,10 @@
 /**
  * Tests for interstitial pages.
  */
-public class InterstitialPageTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class InterstitialPageTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
 
     private static final String URL = UrlUtils.encodeHtmlDataUri(
             "<html><head></head><body>test</body></html>");
@@ -56,12 +66,11 @@
         }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        ContentShellActivity activity = launchContentShellWithUrl(URL);
-        assertNotNull(activity);
-        waitForActiveShellToBeDoneLoading();
+    @Before
+    public void setUp() throws Exception {
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl(URL);
+        Assert.assertNotNull(activity);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
     }
 
     private void waitForInterstitial(final boolean shouldBeShown) {
@@ -69,7 +78,7 @@
                 Criteria.equals(shouldBeShown, new Callable<Boolean>() {
                     @Override
                     public Boolean call() {
-                        return getWebContents().isShowingInterstitialPage();
+                        return mActivityTestRule.getWebContents().isShowingInterstitialPage();
                     }
                 }));
     }
@@ -77,6 +86,7 @@
     /**
      * Tests that showing and hiding an interstitial works.
      */
+    @Test
     @LargeTest
     @Feature({"Navigation"})
     @RetryOnFailure
@@ -100,7 +110,7 @@
                 new InterstitialPageDelegateAndroid(htmlContent) {
             @Override
             protected void commandReceived(String command) {
-                assertEquals(command, proceedCommand);
+                Assert.assertEquals(command, proceedCommand);
                 proceed();
             }
         };
@@ -108,17 +118,19 @@
                 new Callable<TestWebContentsObserver>() {
                     @Override
                     public TestWebContentsObserver call() throws Exception {
-                        getWebContents().showInterstitialPage(URL, delegate.getNative());
-                        return new TestWebContentsObserver(getWebContents());
+                        mActivityTestRule.getWebContents().showInterstitialPage(
+                                URL, delegate.getNative());
+                        return new TestWebContentsObserver(mActivityTestRule.getWebContents());
                     }
                 });
 
         waitForInterstitial(true);
-        assertTrue("WebContentsObserver not notified of interstitial showing",
+        Assert.assertTrue("WebContentsObserver not notified of interstitial showing",
                 observer.isInterstitialShowing());
-        TouchCommon.singleClickView(getContentViewCore().getContainerView(), 10, 10);
+        TouchCommon.singleClickView(
+                mActivityTestRule.getContentViewCore().getContainerView(), 10, 10);
         waitForInterstitial(false);
-        assertTrue("WebContentsObserver not notified of interstitial hiding",
+        Assert.assertTrue("WebContentsObserver not notified of interstitial hiding",
                 !observer.isInterstitialShowing());
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
index fdf3b1d..387c35f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
@@ -6,7 +6,14 @@
 
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeTestCommon.Controller;
 
@@ -21,7 +28,13 @@
  * FIXME: Consider making our implementation more compliant, if it will not
  * break backwards-compatibility. See b/4408210.
  */
-public class JavaBridgeArrayCoercionTest extends JavaBridgeTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class JavaBridgeArrayCoercionTest {
+    private static final double ASSERTION_DELTA = 0;
+
+    @Rule
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
+
     @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
     private static class TestObject extends Controller {
         private final Object mObjectInstance;
@@ -148,11 +161,10 @@
 
     private TestObject mTestObject;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mTestObject = new TestObject();
-        injectObjectAndReload(mTestObject, "testObject");
+        mActivityTestRule.injectObjectAndReload(mTestObject, "testObject");
     }
 
     // Note that all tests use a single element array for simplicity. We test
@@ -160,809 +172,841 @@
 
     // Test passing an array of JavaScript numbers in the int32 range to a
     // method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberInt32() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([0]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([0]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
         // LIVECONNECT_COMPLIANCE: Should convert to boolean.
-        executeJavaScript("testObject.setBooleanArray([42]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([42]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray([42]);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([42]);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray([42]);");
-        assertEquals(42, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([42]);");
+        Assert.assertEquals(42, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray([42]);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([42]);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray([42]);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([42]);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray([42]);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([42]);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray([42]);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([42]);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray([42]);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([42]);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([42]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([42]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
         // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([42]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([42]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([42]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([42]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript numbers in the double range to a
     // method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberDouble() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should convert to boolean.
-        executeJavaScript("testObject.setBooleanArray([42.1]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([42.1]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray([42.1]);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([42.1]);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
-        executeJavaScript("testObject.setCharArray([42.1]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([42.1]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray([42.1]);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([42.1]);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray([42.1]);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([42.1]);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray([42.1]);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([42.1]);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray([42.1]);");
-        assertEquals(42.1f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([42.1]);");
+        Assert.assertEquals(42.1f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray([42.1]);");
-        assertEquals(42.1, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([42.1]);");
+        Assert.assertEquals(42.1, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([42.1]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([42.1]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
         // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([42.1]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([42.1]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([42.1]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([42.1]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript NaN values to a method which takes a
     // Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberNaN() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([Number.NaN]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([Number.NaN]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray([Number.NaN]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([Number.NaN]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray([Number.NaN]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([Number.NaN]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray([Number.NaN]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([Number.NaN]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray([Number.NaN]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([Number.NaN]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray([Number.NaN]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([Number.NaN]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray([Number.NaN]);");
-        assertEquals(Float.NaN, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([Number.NaN]);");
+        Assert.assertEquals(Float.NaN, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray([Number.NaN]);");
-        assertEquals(Double.NaN, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([Number.NaN]);");
+        Assert.assertEquals(Double.NaN, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([Number.NaN]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([Number.NaN]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
         // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([Number.NaN]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([Number.NaN]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([Number.NaN]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([Number.NaN]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript infinity values to a method which
     // takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberInfinity() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([Infinity]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([Infinity]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray([Infinity]);");
-        assertEquals(-1, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([Infinity]);");
+        Assert.assertEquals(-1, mTestObject.waitForByteArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should convert to maximum numeric char value.
-        executeJavaScript("testObject.setCharArray([Infinity]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([Infinity]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray([Infinity]);");
-        assertEquals(-1, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([Infinity]);");
+        Assert.assertEquals(-1, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray([Infinity]);");
-        assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([Infinity]);");
+        Assert.assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray([Infinity]);");
-        assertEquals(Long.MAX_VALUE, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([Infinity]);");
+        Assert.assertEquals(Long.MAX_VALUE, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray([Infinity]);");
-        assertEquals(Float.POSITIVE_INFINITY, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([Infinity]);");
+        Assert.assertEquals(
+                Float.POSITIVE_INFINITY, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray([Infinity]);");
-        assertEquals(Double.POSITIVE_INFINITY, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([Infinity]);");
+        Assert.assertEquals(
+                Double.POSITIVE_INFINITY, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([Infinity]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([Infinity]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
         // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([Infinity]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([Infinity]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([Infinity]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([Infinity]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript boolean values to a method which
     // takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassBoolean() throws Throwable {
-        executeJavaScript("testObject.setBooleanArray([true]);");
-        assertTrue(mTestObject.waitForBooleanArray()[0]);
-        executeJavaScript("testObject.setBooleanArray([false]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([true]);");
+        Assert.assertTrue(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([false]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setByteArray([true]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
-        executeJavaScript("testObject.setByteArray([false]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([true]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([false]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should convert to numeric char value 1.
-        executeJavaScript("testObject.setCharArray([true]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
-        executeJavaScript("testObject.setCharArray([false]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([true]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([false]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setShortArray([true]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
-        executeJavaScript("testObject.setShortArray([false]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([true]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([false]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setIntArray([true]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
-        executeJavaScript("testObject.setIntArray([false]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([true]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([false]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setLongArray([true]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
-        executeJavaScript("testObject.setLongArray([false]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([true]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([false]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setFloatArray([true]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
-        executeJavaScript("testObject.setFloatArray([false]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([true]);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([false]);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setDoubleArray([true]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
-        executeJavaScript("testObject.setDoubleArray([false]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([true]);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([false]);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([true]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([true]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
         // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String.
-        executeJavaScript("testObject.setStringArray([true]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([true]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([true]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([true]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript strings to a method which takes a
     // Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassString() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Non-empty string should convert to true.
-        executeJavaScript("testObject.setBooleanArray([\"+042.10\"]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([\"+042.10\"]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setByteArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([\"+042.10\"]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should decode and convert to numeric char value.
-        executeJavaScript("testObject.setCharArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([\"+042.10\"]);");
+        Assert.assertEquals(0, mTestObject.waitForCharArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setShortArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([\"+042.10\"]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setIntArray([\"+042.10\"]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([\"+042.10\"]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setLongArray([\"+042.10\"]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([\"+042.10\"]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setFloatArray([\"+042.10\"]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([\"+042.10\"]);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setDoubleArray([\"+042.10\"]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([\"+042.10\"]);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number.
-        executeJavaScript("testObject.setObjectArray([\"+042.10\"]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([\"+042.10\"]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray([\"+042.10\"]);");
-        assertEquals("+042.10", mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([\"+042.10\"]);");
+        Assert.assertEquals("+042.10", mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([\"+042.10\"]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([\"+042.10\"]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript objects to a method which takes a
     // Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassJavaScriptObject() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanArray([{foo: 42}]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([{foo: 42}]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteArray([{foo: 42}]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([{foo: 42}]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharArray([{foo: 42}]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([{foo: 42}]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortArray([{foo: 42}]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([{foo: 42}]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray([{foo: 42}]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([{foo: 42}]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongArray([{foo: 42}]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([{foo: 42}]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatArray([{foo: 42}]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([{foo: 42}]);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleArray([{foo: 42}]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([{foo: 42}]);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setObjectArray([{foo: 42}]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([{foo: 42}]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
         // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringArray([{foo: 42}]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([{foo: 42}]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeArray([{foo: 42}]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([{foo: 42}]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of Java objects to a method which takes a Java
     // array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassJavaObject() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanArray([testObject.getObjectInstance()]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setBooleanArray([testObject.getObjectInstance()]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteArray([testObject.getObjectInstance()]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setByteArray([testObject.getObjectInstance()]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharArray([testObject.getObjectInstance()]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setCharArray([testObject.getObjectInstance()]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortArray([testObject.getObjectInstance()]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setShortArray([testObject.getObjectInstance()]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray([testObject.getObjectInstance()]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setIntArray([testObject.getObjectInstance()]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongArray([testObject.getObjectInstance()]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setLongArray([testObject.getObjectInstance()]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatArray([testObject.getObjectInstance()]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setFloatArray([testObject.getObjectInstance()]);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleArray([testObject.getObjectInstance()]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setDoubleArray([testObject.getObjectInstance()]);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create an array and pass Java object.
-        executeJavaScript("testObject.setObjectArray([testObject.getObjectInstance()]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setObjectArray([testObject.getObjectInstance()]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
         // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringArray([testObject.getObjectInstance()]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript(
+                "testObject.setStringArray([testObject.getObjectInstance()]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should create array and pass Java object.
-        executeJavaScript("testObject.setCustomTypeArray([testObject.getObjectInstance()]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
-        executeJavaScript("testObject.setCustomTypeArray([testObject.getCustomTypeInstance()]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setCustomTypeArray([testObject.getObjectInstance()]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setCustomTypeArray([testObject.getCustomTypeInstance()]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript null values to a method which takes
     // a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNull() throws Throwable {
-        executeJavaScript("testObject.setByteArray([null]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([null]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray([null]);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([null]);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray([null]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([null]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray([null]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([null]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray([null]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([null]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray([null]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([null]);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray([null]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([null]);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setBooleanArray([null]);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([null]);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setObjectArray([null]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([null]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray([null]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([null]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setCustomTypeArray([null]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([null]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing an array of JavaScript undefined values to a method which
     // takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassUndefined() throws Throwable {
-        executeJavaScript("testObject.setByteArray([undefined]);");
-        assertEquals(0, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray([undefined]);");
+        Assert.assertEquals(0, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray([undefined]);");
-        assertEquals(0, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray([undefined]);");
+        Assert.assertEquals(0, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray([undefined]);");
-        assertEquals(0, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray([undefined]);");
+        Assert.assertEquals(0, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray([undefined]);");
-        assertEquals(0, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([undefined]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray([undefined]);");
-        assertEquals(0L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray([undefined]);");
+        Assert.assertEquals(0L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray([undefined]);");
-        assertEquals(0.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray([undefined]);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray([undefined]);");
-        assertEquals(0.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray([undefined]);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setBooleanArray([undefined]);");
-        assertEquals(false, mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray([undefined]);");
+        Assert.assertEquals(false, mTestObject.waitForBooleanArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setObjectArray([undefined]);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray([undefined]);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray([undefined]);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray([undefined]);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
         // LIVECONNECT_COMPLIANCE: Should create array and pass null.
-        executeJavaScript("testObject.setCustomTypeArray([undefined]);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray([undefined]);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Int8Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassInt8Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(1);");
-        executeJavaScript("int8_array = new Int8Array(buffer);");
-        executeJavaScript("int8_array[0] = 42;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(1);");
+        mActivityTestRule.executeJavaScript("int8_array = new Int8Array(buffer);");
+        mActivityTestRule.executeJavaScript("int8_array[0] = 42;");
 
-        executeJavaScript("testObject.setBooleanArray(int8_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(int8_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(int8_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(int8_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(int8_array);");
-        assertEquals(42, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(int8_array);");
+        Assert.assertEquals(42, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(int8_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(int8_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(int8_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(int8_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(int8_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(int8_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(int8_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(int8_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(int8_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(int8_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(int8_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(int8_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(int8_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(int8_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(int8_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(int8_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Uint8Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassUint8Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(1);");
-        executeJavaScript("uint8_array = new Uint8Array(buffer);");
-        executeJavaScript("uint8_array[0] = 42;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(1);");
+        mActivityTestRule.executeJavaScript("uint8_array = new Uint8Array(buffer);");
+        mActivityTestRule.executeJavaScript("uint8_array[0] = 42;");
 
-        executeJavaScript("testObject.setBooleanArray(uint8_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(uint8_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(uint8_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(uint8_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(uint8_array);");
-        assertEquals(42, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(uint8_array);");
+        Assert.assertEquals(42, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(uint8_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(uint8_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(uint8_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(uint8_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(uint8_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(uint8_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(uint8_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(uint8_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(uint8_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(uint8_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(uint8_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(uint8_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(uint8_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(uint8_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(uint8_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(uint8_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Int16Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassInt16Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(2);");
-        executeJavaScript("int16_array = new Int16Array(buffer);");
-        executeJavaScript("int16_array[0] = 42;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(2);");
+        mActivityTestRule.executeJavaScript("int16_array = new Int16Array(buffer);");
+        mActivityTestRule.executeJavaScript("int16_array[0] = 42;");
 
-        executeJavaScript("testObject.setBooleanArray(int16_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(int16_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(int16_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(int16_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(int16_array);");
-        assertEquals(42, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(int16_array);");
+        Assert.assertEquals(42, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(int16_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(int16_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(int16_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(int16_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(int16_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(int16_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(int16_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(int16_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(int16_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(int16_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(int16_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(int16_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(int16_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(int16_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(int16_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(int16_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Uint16Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassUint16Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(2);");
-        executeJavaScript("uint16_array = new Uint16Array(buffer);");
-        executeJavaScript("uint16_array[0] = 42;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(2);");
+        mActivityTestRule.executeJavaScript("uint16_array = new Uint16Array(buffer);");
+        mActivityTestRule.executeJavaScript("uint16_array[0] = 42;");
 
-        executeJavaScript("testObject.setBooleanArray(uint16_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(uint16_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(uint16_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(uint16_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(uint16_array);");
-        assertEquals(42, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(uint16_array);");
+        Assert.assertEquals(42, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(uint16_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(uint16_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(uint16_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(uint16_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(uint16_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(uint16_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(uint16_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(uint16_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(uint16_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(uint16_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(uint16_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(uint16_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(uint16_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(uint16_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(uint16_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(uint16_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Int32Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassInt32Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(4);");
-        executeJavaScript("int32_array = new Int32Array(buffer);");
-        executeJavaScript("int32_array[0] = 42;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(4);");
+        mActivityTestRule.executeJavaScript("int32_array = new Int32Array(buffer);");
+        mActivityTestRule.executeJavaScript("int32_array[0] = 42;");
 
-        executeJavaScript("testObject.setBooleanArray(int32_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(int32_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(int32_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(int32_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(int32_array);");
-        assertEquals(42, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(int32_array);");
+        Assert.assertEquals(42, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(int32_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(int32_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(int32_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(int32_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(int32_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(int32_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(int32_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(int32_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(int32_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(int32_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(int32_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(int32_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(int32_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(int32_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(int32_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(int32_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Uint32Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassUint32Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(4);");
-        executeJavaScript("uint32_array = new Uint32Array(buffer);");
-        executeJavaScript("uint32_array[0] = 42;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(4);");
+        mActivityTestRule.executeJavaScript("uint32_array = new Uint32Array(buffer);");
+        mActivityTestRule.executeJavaScript("uint32_array[0] = 42;");
 
-        executeJavaScript("testObject.setBooleanArray(uint32_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(uint32_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(uint32_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(uint32_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(uint32_array);");
-        assertEquals(42, mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(uint32_array);");
+        Assert.assertEquals(42, mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(uint32_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(uint32_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(uint32_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(uint32_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(uint32_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(uint32_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(uint32_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(uint32_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(uint32_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(uint32_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(uint32_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(uint32_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(uint32_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(uint32_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(uint32_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(uint32_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Float32Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassFloat32Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(4);");
-        executeJavaScript("float32_array = new Float32Array(buffer);");
-        executeJavaScript("float32_array[0] = 42.0;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(4);");
+        mActivityTestRule.executeJavaScript("float32_array = new Float32Array(buffer);");
+        mActivityTestRule.executeJavaScript("float32_array[0] = 42.0;");
 
-        executeJavaScript("testObject.setBooleanArray(float32_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(float32_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(float32_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(float32_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(float32_array);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(float32_array);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(float32_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(float32_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(float32_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(float32_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(float32_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(float32_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(float32_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(float32_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(float32_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(float32_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(float32_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(float32_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(float32_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(float32_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(float32_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(float32_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 
     // Test passing a typed Float64Array to a method which takes a Java array.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassFloat64Array() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(8);");
-        executeJavaScript("float64_array = new Float64Array(buffer);");
-        executeJavaScript("float64_array[0] = 42.0;");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(8);");
+        mActivityTestRule.executeJavaScript("float64_array = new Float64Array(buffer);");
+        mActivityTestRule.executeJavaScript("float64_array[0] = 42.0;");
 
-        executeJavaScript("testObject.setBooleanArray(float64_array);");
-        assertFalse(mTestObject.waitForBooleanArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setBooleanArray(float64_array);");
+        Assert.assertFalse(mTestObject.waitForBooleanArray()[0]);
 
-        executeJavaScript("testObject.setByteArray(float64_array);");
-        assertEquals(42, mTestObject.waitForByteArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setByteArray(float64_array);");
+        Assert.assertEquals(42, mTestObject.waitForByteArray()[0]);
 
-        executeJavaScript("testObject.setCharArray(float64_array);");
-        assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setCharArray(float64_array);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharArray()[0]);
 
-        executeJavaScript("testObject.setShortArray(float64_array);");
-        assertEquals(42, mTestObject.waitForShortArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setShortArray(float64_array);");
+        Assert.assertEquals(42, mTestObject.waitForShortArray()[0]);
 
-        executeJavaScript("testObject.setIntArray(float64_array);");
-        assertEquals(42, mTestObject.waitForIntArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(float64_array);");
+        Assert.assertEquals(42, mTestObject.waitForIntArray()[0]);
 
-        executeJavaScript("testObject.setLongArray(float64_array);");
-        assertEquals(42L, mTestObject.waitForLongArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setLongArray(float64_array);");
+        Assert.assertEquals(42L, mTestObject.waitForLongArray()[0]);
 
-        executeJavaScript("testObject.setFloatArray(float64_array);");
-        assertEquals(42.0f, mTestObject.waitForFloatArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setFloatArray(float64_array);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleArray(float64_array);");
-        assertEquals(42.0, mTestObject.waitForDoubleArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleArray(float64_array);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleArray()[0], ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setObjectArray(float64_array);");
-        assertNull(mTestObject.waitForObjectArray());
+        mActivityTestRule.executeJavaScript("testObject.setObjectArray(float64_array);");
+        Assert.assertNull(mTestObject.waitForObjectArray());
 
-        executeJavaScript("testObject.setStringArray(float64_array);");
-        assertNull(mTestObject.waitForStringArray()[0]);
+        mActivityTestRule.executeJavaScript("testObject.setStringArray(float64_array);");
+        Assert.assertNull(mTestObject.waitForStringArray()[0]);
 
-        executeJavaScript("testObject.setCustomTypeArray(float64_array);");
-        assertNull(mTestObject.waitForCustomTypeArray());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeArray(float64_array);");
+        Assert.assertNull(mTestObject.waitForCustomTypeArray());
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
index 2be60b5..f4001b8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
@@ -6,7 +6,14 @@
 
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeTestCommon.Controller;
 
@@ -20,7 +27,11 @@
  * FIXME: Consider making our implementation more compliant, if it will not
  * break backwards-compatibility. See b/4408210.
  */
-public class JavaBridgeArrayTest extends JavaBridgeTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class JavaBridgeArrayTest {
+    @Rule
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
+
     @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
     private static class TestObject extends Controller {
         private boolean mBooleanValue;
@@ -88,128 +99,140 @@
 
     private TestObject mTestObject;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mTestObject = new TestObject();
-        injectObjectAndReload(mTestObject, "testObject");
+        mActivityTestRule.injectObjectAndReload(mTestObject, "testObject");
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testArrayLength() throws Throwable {
-        executeJavaScript("testObject.setIntArray([42, 43, 44]);");
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([42, 43, 44]);");
         int[] result = mTestObject.waitForIntArray();
-        assertEquals(3, result.length);
-        assertEquals(42, result[0]);
-        assertEquals(43, result[1]);
-        assertEquals(44, result[2]);
+        Assert.assertEquals(3, result.length);
+        Assert.assertEquals(42, result[0]);
+        Assert.assertEquals(43, result[1]);
+        Assert.assertEquals(44, result[2]);
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNull() throws Throwable {
-        executeJavaScript("testObject.setIntArray(null);");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(null);");
+        Assert.assertNull(mTestObject.waitForIntArray());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassUndefined() throws Throwable {
-        executeJavaScript("testObject.setIntArray(undefined);");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(undefined);");
+        Assert.assertNull(mTestObject.waitForIntArray());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassEmptyArray() throws Throwable {
-        executeJavaScript("testObject.setIntArray([]);");
-        assertEquals(0, mTestObject.waitForIntArray().length);
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([]);");
+        Assert.assertEquals(0, mTestObject.waitForIntArray().length);
     }
 
     // Note that this requires being able to pass a string from JavaScript to
     // Java.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassArrayToStringMethod() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should call toString() on array.
-        executeJavaScript("testObject.setStringValue([42, 42, 42]);");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue([42, 42, 42]);");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
     }
 
     // Note that this requires being able to pass an integer from JavaScript to
     // Java.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassArrayToNonStringNonArrayMethod() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception.
-        executeJavaScript("testObject.setIntValue([42, 42, 42]);");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue([42, 42, 42]);");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNonArrayToArrayMethod() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception.
-        executeJavaScript("testObject.setIntArray(42);");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(42);");
+        Assert.assertNull(mTestObject.waitForIntArray());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testObjectWithLengthProperty() throws Throwable {
-        executeJavaScript("testObject.setIntArray({length: 3, 1: 42});");
+        mActivityTestRule.executeJavaScript("testObject.setIntArray({length: 3, 1: 42});");
         int[] result = mTestObject.waitForIntArray();
-        assertEquals(3, result.length);
-        assertEquals(0, result[0]);
-        assertEquals(42, result[1]);
-        assertEquals(0, result[2]);
+        Assert.assertEquals(3, result.length);
+        Assert.assertEquals(0, result[0]);
+        Assert.assertEquals(42, result[1]);
+        Assert.assertEquals(0, result[2]);
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testNonNumericLengthProperty() throws Throwable {
         // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
         // should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray({length: \"foo\"});");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntArray({length: \"foo\"});");
+        Assert.assertNull(mTestObject.waitForIntArray());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testLengthOutOfBounds() throws Throwable {
         // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
         // should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntArray({length: -1});");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntArray({length: -1});");
+        Assert.assertNull(mTestObject.waitForIntArray());
 
         // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
         // should raise a JavaScript exception.
         long length = Integer.MAX_VALUE + 1L;
-        executeJavaScript("testObject.setIntArray({length: " + length + "});");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntArray({length: " + length + "});");
+        Assert.assertNull(mTestObject.waitForIntArray());
 
         // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
         // should raise a JavaScript exception.
         length = Integer.MAX_VALUE + 1L - Integer.MIN_VALUE + 1L;
-        executeJavaScript("testObject.setIntArray({length: " + length + "});");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntArray({length: " + length + "});");
+        Assert.assertNull(mTestObject.waitForIntArray());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testSparseArray() throws Throwable {
-        executeJavaScript("var x = [42, 43]; x[3] = 45; testObject.setIntArray(x);");
+        mActivityTestRule.executeJavaScript(
+                "var x = [42, 43]; x[3] = 45; testObject.setIntArray(x);");
         int[] result = mTestObject.waitForIntArray();
-        assertEquals(4, result.length);
-        assertEquals(42, result[0]);
-        assertEquals(43, result[1]);
-        assertEquals(0, result[2]);
-        assertEquals(45, result[3]);
+        Assert.assertEquals(4, result.length);
+        Assert.assertEquals(42, result[0]);
+        Assert.assertEquals(43, result[1]);
+        Assert.assertEquals(0, result[2]);
+        Assert.assertEquals(45, result[3]);
     }
 
     // Note that this requires being able to pass a boolean from JavaScript to
     // Java.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testMethodReturningArrayNotCalled() throws Throwable {
@@ -217,39 +240,43 @@
         // exception is raised.
         // LIVECONNECT_COMPLIANCE: Should call method and convert result to
         // JavaScript array.
-        executeJavaScript("testObject.setBooleanValue(undefined === testObject.arrayMethod())");
-        assertTrue(mTestObject.waitForBooleanValue());
-        assertFalse(mTestObject.wasArrayMethodCalled());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setBooleanValue(undefined === testObject.arrayMethod())");
+        Assert.assertTrue(mTestObject.waitForBooleanValue());
+        Assert.assertFalse(mTestObject.wasArrayMethodCalled());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testMultiDimensionalArrayMethod() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays.
-        executeJavaScript("testObject.setIntIntArray([ [42, 43], [44, 45] ]);");
-        assertNull(mTestObject.waitForIntIntArray());
+        mActivityTestRule.executeJavaScript("testObject.setIntIntArray([ [42, 43], [44, 45] ]);");
+        Assert.assertNull(mTestObject.waitForIntIntArray());
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassMultiDimensionalArray() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays.
-        executeJavaScript("testObject.setIntArray([ [42, 43], [44, 45] ]);");
+        mActivityTestRule.executeJavaScript("testObject.setIntArray([ [42, 43], [44, 45] ]);");
         int[] result = mTestObject.waitForIntArray();
-        assertEquals(2, result.length);
-        assertEquals(0, result[0]);
-        assertEquals(0, result[1]);
+        Assert.assertEquals(2, result.length);
+        Assert.assertEquals(0, result[0]);
+        Assert.assertEquals(0, result[1]);
     }
 
     // Verify that ArrayBuffers are not converted into arrays when passed to Java.
     // The LiveConnect spec doesn't mention ArrayBuffers, so it doesn't seem to
     // be a compliance issue.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassArrayBuffer() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(16);");
-        executeJavaScript("testObject.setIntArray(buffer);");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);");
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(buffer);");
+        Assert.assertNull(mTestObject.waitForIntArray());
     }
 
     // Verify that ArrayBufferViews are not converted into arrays when passed to Java.
@@ -258,11 +285,12 @@
     // Here, a DataView is used as an ArrayBufferView instance (since the latter is
     // an interface and can't be instantiated directly). See also JavaBridgeArrayCoercionTest
     // for typed arrays (that also subclass ArrayBufferView) tests.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassDataView() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(16);");
-        executeJavaScript("testObject.setIntArray(new DataView(buffer));");
-        assertNull(mTestObject.waitForIntArray());
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);");
+        mActivityTestRule.executeJavaScript("testObject.setIntArray(new DataView(buffer));");
+        Assert.assertNull(mTestObject.waitForIntArray());
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java
index 0261302..ae2349e 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java
@@ -6,33 +6,44 @@
 
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 /**
  * Common functionality for testing the Java Bridge.
  */
-public class JavaBridgeBareboneTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class JavaBridgeBareboneTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private TestCallbackHelperContainer mTestCallbackHelperContainer;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        launchContentShellWithUrl(
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.launchContentShellWithUrl(
                 UrlUtils.encodeHtmlDataUri("<html><head></head><body>test</body></html>"));
-        waitForActiveShellToBeDoneLoading();
-        mTestCallbackHelperContainer = new TestCallbackHelperContainer(getContentViewCore());
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+        mTestCallbackHelperContainer =
+                new TestCallbackHelperContainer(mActivityTestRule.getContentViewCore());
     }
 
     private void injectDummyObject(final String name) throws Throwable {
-        runTestOnUiThread(new Runnable() {
+        mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                getContentViewCore().addPossiblyUnsafeJavascriptInterface(
+                mActivityTestRule.getContentViewCore().addPossiblyUnsafeJavascriptInterface(
                         new Object(), name, null);
             }
         });
@@ -40,7 +51,7 @@
 
     private String evaluateJsSync(String jsCode) throws Exception {
         OnEvaluateJavaScriptResultHelper javascriptHelper = new OnEvaluateJavaScriptResultHelper();
-        javascriptHelper.evaluateJavaScriptForTests(getWebContents(), jsCode);
+        javascriptHelper.evaluateJavaScriptForTests(mActivityTestRule.getWebContents(), jsCode);
         javascriptHelper.waitUntilHasValue();
         return javascriptHelper.getJsonResultAndClear();
     }
@@ -49,10 +60,10 @@
         OnPageFinishedHelper pageFinishedHelper =
                 mTestCallbackHelperContainer.getOnPageFinishedHelper();
         int currentCallCount = pageFinishedHelper.getCallCount();
-        runTestOnUiThread(new Runnable() {
+        mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                getWebContents().getNavigationController().reload(true);
+                mActivityTestRule.getWebContents().getNavigationController().reload(true);
             }
         });
         pageFinishedHelper.waitForCallback(currentCallCount);
@@ -69,36 +80,40 @@
     //   webView.addJavascriptInterface(new Foo(), "foo");
     //   webView.loadUrl("javascript:foo.bar();void(0);");
     //
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testImmediateAddition() throws Throwable {
         injectDummyObject("testObject");
-        assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
+        Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
     }
 
     // Now here, we evaluate some JS before injecting the object, and this behaves as
     // expected.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testNoImmediateAdditionAfterJSEvaluation() throws Throwable {
         evaluateJsSync("true");
         injectDummyObject("testObject");
-        assertEquals("\"undefined\"", evaluateJsSync("typeof testObject"));
+        Assert.assertEquals("\"undefined\"", evaluateJsSync("typeof testObject"));
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testImmediateAdditionAfterReload() throws Throwable {
         reloadSync();
         injectDummyObject("testObject");
-        assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
+        Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testReloadAfterAddition() throws Throwable {
         injectDummyObject("testObject");
         reloadSync();
-        assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
+        Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
index 075eb59..fcccc896 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
@@ -8,7 +8,14 @@
 
 import dalvik.system.DexClassLoader;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.JavaBridgeTestCommon.Controller;
@@ -27,7 +34,13 @@
  * FIXME: Consider making our implementation more compliant, if it will not
  * break backwards-compatibility. See b/4408210.
  */
-public class JavaBridgeCoercionTest extends JavaBridgeTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class JavaBridgeCoercionTest {
+    private static final double ASSERTION_DELTA = 0;
+
+    @Rule
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
+
     @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
     private static class TestObject extends Controller {
         private Object mObjectInstance;
@@ -179,451 +192,487 @@
 
     // Note that this requires that we can pass a JavaScript boolean to Java.
     private void assertRaisesException(String script) throws Throwable {
-        executeJavaScript("try {"
-                + script + ";"
+        mActivityTestRule.executeJavaScript("try {" + script + ";"
                 + "  testController.setBooleanValue(false);"
                 + "} catch (exception) {"
                 + "  testController.setBooleanValue(true);"
                 + "}");
-        assertTrue(mTestController.waitForBooleanValue());
+        Assert.assertTrue(mTestController.waitForBooleanValue());
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mTestObject = new TestObject();
         mTestController = new TestController();
-        injectObjectsAndReload(mTestObject, "testObject", mTestController, "testController", null);
+        mActivityTestRule.injectObjectsAndReload(
+                mTestObject, "testObject", mTestController, "testController", null);
     }
 
     // Test passing a 32-bit integer JavaScript number to a method of an
     // injected object. Note that JavaScript may choose to represent these
     // values as either 32-bit integers or doubles, though this should not
     // affect the result.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberInt32() throws Throwable {
-        executeJavaScript("testObject.setByteValue(42);");
-        assertEquals(42, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42);");
-        assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(42);");
+        Assert.assertEquals(42, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setByteValue(" + Byte.MAX_VALUE + " + 42);");
+        Assert.assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
 
-        executeJavaScript("testObject.setCharValue(42);");
-        assertEquals(42, mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(42);");
+        Assert.assertEquals(42, mTestObject.waitForCharValue());
 
-        executeJavaScript("testObject.setShortValue(42);");
-        assertEquals(42, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42);");
-        assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(42);");
+        Assert.assertEquals(42, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setShortValue(" + Short.MAX_VALUE + " + 42);");
+        Assert.assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
 
-        executeJavaScript("testObject.setIntValue(42);");
-        assertEquals(42, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(42);");
+        Assert.assertEquals(42, mTestObject.waitForIntValue());
 
-        executeJavaScript("testObject.setLongValue(42);");
-        assertEquals(42L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(42);");
+        Assert.assertEquals(42L, mTestObject.waitForLongValue());
 
-        executeJavaScript("testObject.setFloatValue(42);");
-        assertEquals(42.0f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(42);");
+        Assert.assertEquals(42.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleValue(42);");
-        assertEquals(42.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(42);");
+        Assert.assertEquals(42.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(42);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(42);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
         // The spec allows the JS engine flexibility in how to format the number.
-        executeJavaScript("testObject.setStringValue(42);");
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(42);");
         String str = mTestObject.waitForStringValue();
-        assertTrue("42".equals(str) || "42.0".equals(str));
+        Assert.assertTrue("42".equals(str) || "42.0".equals(str));
 
-        executeJavaScript("testObject.setBooleanValue(0);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(0);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
         // LIVECONNECT_COMPLIANCE: Should be true;
-        executeJavaScript("testObject.setBooleanValue(42);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(42);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(42);");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(42);");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
     }
 
     // Test passing a floating-point JavaScript number to a method of an
     // injected object. JavaScript represents these values as doubles.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberDouble() throws Throwable {
-        executeJavaScript("testObject.setByteValue(42.1);");
-        assertEquals(42, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42.1);");
-        assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Byte.MIN_VALUE + " - 42.1);");
-        assertEquals(Byte.MAX_VALUE - 42 + 1, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Integer.MAX_VALUE + " + 42.1);");
-        assertEquals(-1, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(" + Integer.MIN_VALUE + " - 42.1);");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(42.1);");
+        Assert.assertEquals(42, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setByteValue(" + Byte.MAX_VALUE + " + 42.1);");
+        Assert.assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setByteValue(" + Byte.MIN_VALUE + " - 42.1);");
+        Assert.assertEquals(Byte.MAX_VALUE - 42 + 1, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setByteValue(" + Integer.MAX_VALUE + " + 42.1);");
+        Assert.assertEquals(-1, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setByteValue(" + Integer.MIN_VALUE + " - 42.1);");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
         // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
-        executeJavaScript("testObject.setCharValue(42.1);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(42.1);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
-        executeJavaScript("testObject.setShortValue(42.1);");
-        assertEquals(42, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42.1);");
-        assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Short.MIN_VALUE + " - 42.1);");
-        assertEquals(Short.MAX_VALUE - 42 + 1, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Integer.MAX_VALUE + " + 42.1);");
-        assertEquals(-1, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(" + Integer.MIN_VALUE + " - 42.1);");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(42.1);");
+        Assert.assertEquals(42, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setShortValue(" + Short.MAX_VALUE + " + 42.1);");
+        Assert.assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setShortValue(" + Short.MIN_VALUE + " - 42.1);");
+        Assert.assertEquals(Short.MAX_VALUE - 42 + 1, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setShortValue(" + Integer.MAX_VALUE + " + 42.1);");
+        Assert.assertEquals(-1, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setShortValue(" + Integer.MIN_VALUE + " - 42.1);");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
-        executeJavaScript("testObject.setIntValue(42.1);");
-        assertEquals(42, mTestObject.waitForIntValue());
-        executeJavaScript("testObject.setIntValue(" + Integer.MAX_VALUE + " + 42.1);");
-        assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
-        executeJavaScript("testObject.setIntValue(" + Integer.MIN_VALUE + " - 42.1);");
-        assertEquals(Integer.MIN_VALUE, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(42.1);");
+        Assert.assertEquals(42, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setIntValue(" + Integer.MAX_VALUE + " + 42.1);");
+        Assert.assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setIntValue(" + Integer.MIN_VALUE + " - 42.1);");
+        Assert.assertEquals(Integer.MIN_VALUE, mTestObject.waitForIntValue());
 
-        executeJavaScript("testObject.setLongValue(42.1);");
-        assertEquals(42L, mTestObject.waitForLongValue());
-        executeJavaScript("testObject.setLongValue(" + Long.MAX_VALUE + " + 42.1);");
-        assertEquals(Long.MAX_VALUE, mTestObject.waitForLongValue());
-        executeJavaScript("testObject.setLongValue(" + Long.MIN_VALUE + " - 42.1);");
-        assertEquals(Long.MIN_VALUE, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(42.1);");
+        Assert.assertEquals(42L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setLongValue(" + Long.MAX_VALUE + " + 42.1);");
+        Assert.assertEquals(Long.MAX_VALUE, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setLongValue(" + Long.MIN_VALUE + " - 42.1);");
+        Assert.assertEquals(Long.MIN_VALUE, mTestObject.waitForLongValue());
 
-        executeJavaScript("testObject.setFloatValue(42.1);");
-        assertEquals(42.1f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(42.1);");
+        Assert.assertEquals(42.1f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleValue(42.1);");
-        assertEquals(42.1, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(42.1);");
+        Assert.assertEquals(42.1, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(42.1);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(42.1);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setStringValue(42.1);");
-        assertEquals("42.1", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(42.1);");
+        Assert.assertEquals("42.1", mTestObject.waitForStringValue());
 
-        executeJavaScript("testObject.setBooleanValue(0.0);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(0.0);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
         // LIVECONNECT_COMPLIANCE: Should be true.
-        executeJavaScript("testObject.setBooleanValue(42.1);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(42.1);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(42.1);");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(42.1);");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
     }
 
     // Test passing JavaScript NaN to a method of an injected object.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberNaN() throws Throwable {
-        executeJavaScript("testObject.setByteValue(Number.NaN);");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(Number.NaN);");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
-        executeJavaScript("testObject.setCharValue(Number.NaN);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(Number.NaN);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
-        executeJavaScript("testObject.setShortValue(Number.NaN);");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(Number.NaN);");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
-        executeJavaScript("testObject.setIntValue(Number.NaN);");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(Number.NaN);");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
 
-        executeJavaScript("testObject.setLongValue(Number.NaN);");
-        assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(Number.NaN);");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
 
-        executeJavaScript("testObject.setFloatValue(Number.NaN);");
-        assertEquals(Float.NaN, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(Number.NaN);");
+        Assert.assertEquals(Float.NaN, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleValue(Number.NaN);");
-        assertEquals(Double.NaN, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(Number.NaN);");
+        Assert.assertEquals(Double.NaN, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(Number.NaN);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(Number.NaN);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setStringValue(Number.NaN);");
-        assertTrue("nan".equalsIgnoreCase(mTestObject.waitForStringValue()));
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(Number.NaN);");
+        Assert.assertTrue("nan".equalsIgnoreCase(mTestObject.waitForStringValue()));
 
-        executeJavaScript("testObject.setBooleanValue(Number.NaN);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(Number.NaN);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(Number.NaN);");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(Number.NaN);");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
     }
 
     // Test passing JavaScript infinity to a method of an injected object.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNumberInfinity() throws Throwable {
-        executeJavaScript("testObject.setByteValue(Infinity);");
-        assertEquals(-1, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(Infinity);");
+        Assert.assertEquals(-1, mTestObject.waitForByteValue());
 
         // LIVECONNECT_COMPLIANCE: Should convert to maximum numeric char value.
-        executeJavaScript("testObject.setCharValue(Infinity);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(Infinity);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
-        executeJavaScript("testObject.setShortValue(Infinity);");
-        assertEquals(-1, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(Infinity);");
+        Assert.assertEquals(-1, mTestObject.waitForShortValue());
 
-        executeJavaScript("testObject.setIntValue(Infinity);");
-        assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(Infinity);");
+        Assert.assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
 
-        executeJavaScript("testObject.setLongValue(Infinity);");
-        assertEquals(Long.MAX_VALUE, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(Infinity);");
+        Assert.assertEquals(Long.MAX_VALUE, mTestObject.waitForLongValue());
 
-        executeJavaScript("testObject.setFloatValue(Infinity);");
-        assertEquals(Float.POSITIVE_INFINITY, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(Infinity);");
+        Assert.assertEquals(
+                Float.POSITIVE_INFINITY, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleValue(Infinity);");
-        assertEquals(Double.POSITIVE_INFINITY, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(Infinity);");
+        Assert.assertEquals(
+                Double.POSITIVE_INFINITY, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
-        executeJavaScript("testObject.setObjectValue(Infinity);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(Infinity);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setStringValue(Infinity);");
-        assertTrue("inf".equalsIgnoreCase(mTestObject.waitForStringValue()));
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(Infinity);");
+        Assert.assertTrue("inf".equalsIgnoreCase(mTestObject.waitForStringValue()));
 
-        executeJavaScript("testObject.setBooleanValue(Infinity);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(Infinity);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(Infinity);");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(Infinity);");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
     }
 
     // Test passing a JavaScript boolean to a method of an injected object.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassBoolean() throws Throwable {
-        executeJavaScript("testObject.setBooleanValue(true);");
-        assertTrue(mTestObject.waitForBooleanValue());
-        executeJavaScript("testObject.setBooleanValue(false);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(true);");
+        Assert.assertTrue(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(false);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
 
         // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Boolean.
-        executeJavaScript("testObject.setObjectValue(true);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(true);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setStringValue(false);");
-        assertEquals("false", mTestObject.waitForStringValue());
-        executeJavaScript("testObject.setStringValue(true);");
-        assertEquals("true", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(false);");
+        Assert.assertEquals("false", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(true);");
+        Assert.assertEquals("true", mTestObject.waitForStringValue());
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setByteValue(true);");
-        assertEquals(0, mTestObject.waitForByteValue());
-        executeJavaScript("testObject.setByteValue(false);");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(true);");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(false);");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
         // LIVECONNECT_COMPLIANCE: Should convert to numeric char value 1.
-        executeJavaScript("testObject.setCharValue(true);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
-        executeJavaScript("testObject.setCharValue(false);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(true);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(false);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setShortValue(true);");
-        assertEquals(0, mTestObject.waitForShortValue());
-        executeJavaScript("testObject.setShortValue(false);");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(true);");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(false);");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setIntValue(true);");
-        assertEquals(0, mTestObject.waitForIntValue());
-        executeJavaScript("testObject.setIntValue(false);");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(true);");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(false);");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
 
         // LIVECONNECT_COMPLIANCE: Should be 1.
-        executeJavaScript("testObject.setLongValue(true);");
-        assertEquals(0L, mTestObject.waitForLongValue());
-        executeJavaScript("testObject.setLongValue(false);");
-        assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(true);");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(false);");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
 
         // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setFloatValue(true);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
-        executeJavaScript("testObject.setFloatValue(false);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(true);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(false);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should be 1.0.
-        executeJavaScript("testObject.setDoubleValue(true);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
-        executeJavaScript("testObject.setDoubleValue(false);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(true);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(false);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(true);");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(true);");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
     }
 
     // Test passing a JavaScript string to a method of an injected object.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassString() throws Throwable {
-        executeJavaScript("testObject.setStringValue(\"+042.10\");");
-        assertEquals("+042.10", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(\"+042.10\");");
+        Assert.assertEquals("+042.10", mTestObject.waitForStringValue());
 
         // Make sure that we distinguish between the empty string and NULL.
-        executeJavaScript("testObject.setStringValue(\"\");");
-        assertEquals("", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(\"\");");
+        Assert.assertEquals("", mTestObject.waitForStringValue());
 
         // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.String.
-        executeJavaScript("testObject.setObjectValue(\"+042.10\");");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(\"+042.10\");");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setByteValue(\"+042.10\");");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(\"+042.10\");");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setShortValue(\"+042.10\");");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(\"+042.10\");");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setIntValue(\"+042.10\");");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(\"+042.10\");");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setLongValue(\"+042.10\");");
-        assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(\"+042.10\");");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setFloatValue(\"+042.10\");");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(\"+042.10\");");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
-        executeJavaScript("testObject.setDoubleValue(\"+042.10\");");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(\"+042.10\");");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should decode and convert to numeric char value.
-        executeJavaScript("testObject.setCharValue(\"+042.10\");");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(\"+042.10\");");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
         // LIVECONNECT_COMPLIANCE: Non-empty string should convert to true.
-        executeJavaScript("testObject.setBooleanValue(\"+042.10\");");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(\"+042.10\");");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue(\"+042.10\");");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(\"+042.10\");");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
     }
 
     // Test passing a JavaScript object to a method of an injected object.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassJavaScriptObject() throws Throwable {
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setObjectValue({foo: 42});");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue({foo: 42});");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCustomTypeValue({foo: 42});");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue({foo: 42});");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
 
         // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringValue({foo: 42});");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue({foo: 42});");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteValue({foo: 42});");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue({foo: 42});");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharValue({foo: 42});");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue({foo: 42});");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortValue({foo: 42});");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue({foo: 42});");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntValue({foo: 42});");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue({foo: 42});");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongValue({foo: 42});");
-        assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue({foo: 42});");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatValue({foo: 42});");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue({foo: 42});");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleValue({foo: 42});");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue({foo: 42});");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanValue({foo: 42});");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue({foo: 42});");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
     }
 
     // Test passing a Java object to a method of an injected object. Note that
     // this test requires being able to return objects from the methods of
     // injected objects. This is tested elsewhere.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassJavaObject() throws Throwable {
-        executeJavaScript("testObject.setObjectValue(testObject.getObjectInstance());");
-        assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForObjectValue());
-        executeJavaScript("testObject.setObjectValue(testObject.getCustomTypeInstance());");
-        assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setObjectValue(testObject.getObjectInstance());");
+        Assert.assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setObjectValue(testObject.getCustomTypeInstance());");
+        Assert.assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForObjectValue());
 
         assertRaisesException("testObject.setCustomTypeValue(testObject.getObjectInstance());");
-        executeJavaScript("testObject.setCustomTypeValue(testObject.getCustomTypeInstance());");
-        assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setCustomTypeValue(testObject.getCustomTypeInstance());");
+        Assert.assertTrue(
+                mTestObject.getCustomTypeInstance() == mTestObject.waitForCustomTypeValue());
         assertRaisesException(
                 "testObject.setCustomTypeValue(testObject.getCustomType2Instance());");
 
         // LIVECONNECT_COMPLIANCE: Should call toString() on object.
-        executeJavaScript("testObject.setStringValue(testObject.getObjectInstance());");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setStringValue(testObject.getObjectInstance());");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setByteValue(testObject.getObjectInstance());");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setByteValue(testObject.getObjectInstance());");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setCharValue(testObject.getObjectInstance());");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setCharValue(testObject.getObjectInstance());");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setShortValue(testObject.getObjectInstance());");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setShortValue(testObject.getObjectInstance());");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setIntValue(testObject.getObjectInstance());");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setIntValue(testObject.getObjectInstance());");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setLongValue(testObject.getObjectInstance());");
-        assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setLongValue(testObject.getObjectInstance());");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setFloatValue(testObject.getObjectInstance());");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setFloatValue(testObject.getObjectInstance());");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setDoubleValue(testObject.getObjectInstance());");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setDoubleValue(testObject.getObjectInstance());");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
         // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
-        executeJavaScript("testObject.setBooleanValue(testObject.getObjectInstance());");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript(
+                "testObject.setBooleanValue(testObject.getObjectInstance());");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
     }
 
     static void assertFileIsReadable(String filePath) {
         File file = new File(filePath);
         try {
-            assertTrue("Test file \"" + filePath + "\" is not readable.", file.canRead());
+            Assert.assertTrue("Test file \"" + filePath + "\" is not readable.", file.canRead());
         } catch (SecurityException e) {
-            fail("Got a SecurityException for \"" + filePath + "\": " + e.toString());
+            Assert.fail("Got a SecurityException for \"" + filePath + "\": " + e.toString());
         }
     }
 
@@ -632,6 +681,7 @@
     // WebView and the app use different class loaders, thus we need to make
     // sure that WebView code doesn't attempt to find an app's class using
     // its own class loader. See crbug.com/491800.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassJavaObjectFromCustomClassLoader() throws Throwable {
@@ -649,167 +699,174 @@
         final String dexFileName = "content/test/data/android/SelfConsumingObject.dex";
         assertFileIsReadable(UrlUtils.getIsolatedTestFilePath(dexFileName));
         final File optimizedDir = File.createTempFile("optimized", "");
-        assertTrue(optimizedDir.delete());
-        assertTrue(optimizedDir.mkdirs());
+        Assert.assertTrue(optimizedDir.delete());
+        Assert.assertTrue(optimizedDir.mkdirs());
         DexClassLoader loader = new DexClassLoader(UrlUtils.getIsolatedTestFilePath(dexFileName),
                 optimizedDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
         final Object selfConsuming = loader.loadClass(
                 "org.example.SelfConsumingObject").newInstance();
-        runTestOnUiThread(new Runnable() {
+        mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                getContentViewCore().addPossiblyUnsafeJavascriptInterface(
+                mActivityTestRule.getContentViewCore().addPossiblyUnsafeJavascriptInterface(
                         selfConsuming, "selfConsuming", null);
             }
         });
-        synchronousPageReload();
-        executeJavaScript("testObject.setBooleanValue("
+        mActivityTestRule.synchronousPageReload();
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue("
                 + "selfConsuming.verifySelf(selfConsuming.getSelf()));");
-        assertTrue(mTestObject.waitForBooleanValue());
+        Assert.assertTrue(mTestObject.waitForBooleanValue());
     }
 
     // Test passing JavaScript null to a method of an injected object.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassNull() throws Throwable {
-        executeJavaScript("testObject.setObjectValue(null);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(null);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setCustomTypeValue(null);");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(null);");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
 
-        executeJavaScript("testObject.setStringValue(null);");
-        assertNull(mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(null);");
+        Assert.assertNull(mTestObject.waitForStringValue());
 
-        executeJavaScript("testObject.setByteValue(null);");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(null);");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
-        executeJavaScript("testObject.setCharValue(null);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(null);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
-        executeJavaScript("testObject.setShortValue(null);");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(null);");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
-        executeJavaScript("testObject.setIntValue(null);");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(null);");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
 
-        executeJavaScript("testObject.setLongValue(null);");
-        assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(null);");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
 
-        executeJavaScript("testObject.setFloatValue(null);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(null);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleValue(null);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(null);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setBooleanValue(null);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(null);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
     }
 
     // Test passing JavaScript undefined to a method of an injected object.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassUndefined() throws Throwable {
-        executeJavaScript("testObject.setObjectValue(undefined);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(undefined);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setCustomTypeValue(undefined);");
-        assertNull(mTestObject.waitForCustomTypeValue());
+        mActivityTestRule.executeJavaScript("testObject.setCustomTypeValue(undefined);");
+        Assert.assertNull(mTestObject.waitForCustomTypeValue());
 
         // LIVECONNECT_COMPLIANCE: Should be NULL.
-        executeJavaScript("testObject.setStringValue(undefined);");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(undefined);");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
 
-        executeJavaScript("testObject.setByteValue(undefined);");
-        assertEquals(0, mTestObject.waitForByteValue());
+        mActivityTestRule.executeJavaScript("testObject.setByteValue(undefined);");
+        Assert.assertEquals(0, mTestObject.waitForByteValue());
 
-        executeJavaScript("testObject.setCharValue(undefined);");
-        assertEquals('\u0000', mTestObject.waitForCharValue());
+        mActivityTestRule.executeJavaScript("testObject.setCharValue(undefined);");
+        Assert.assertEquals('\u0000', mTestObject.waitForCharValue());
 
-        executeJavaScript("testObject.setShortValue(undefined);");
-        assertEquals(0, mTestObject.waitForShortValue());
+        mActivityTestRule.executeJavaScript("testObject.setShortValue(undefined);");
+        Assert.assertEquals(0, mTestObject.waitForShortValue());
 
-        executeJavaScript("testObject.setIntValue(undefined);");
-        assertEquals(0, mTestObject.waitForIntValue());
+        mActivityTestRule.executeJavaScript("testObject.setIntValue(undefined);");
+        Assert.assertEquals(0, mTestObject.waitForIntValue());
 
-        executeJavaScript("testObject.setLongValue(undefined);");
-        assertEquals(0L, mTestObject.waitForLongValue());
+        mActivityTestRule.executeJavaScript("testObject.setLongValue(undefined);");
+        Assert.assertEquals(0L, mTestObject.waitForLongValue());
 
-        executeJavaScript("testObject.setFloatValue(undefined);");
-        assertEquals(0.0f, mTestObject.waitForFloatValue());
+        mActivityTestRule.executeJavaScript("testObject.setFloatValue(undefined);");
+        Assert.assertEquals(0.0f, mTestObject.waitForFloatValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setDoubleValue(undefined);");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(undefined);");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setBooleanValue(undefined);");
-        assertFalse(mTestObject.waitForBooleanValue());
+        mActivityTestRule.executeJavaScript("testObject.setBooleanValue(undefined);");
+        Assert.assertFalse(mTestObject.waitForBooleanValue());
     }
 
     // Verify that ArrayBuffers are not converted into objects or strings when passed
     // to Java. Basically, ArrayBuffers are treated as generic JavaScript objects.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassArrayBuffer() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(16);");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);");
 
-        executeJavaScript("testObject.setObjectValue(buffer);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(buffer);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setStringValue(buffer);");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(buffer);");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
     }
 
     // Verify that ArrayBufferViewss are not converted into objects or strings when passed
     // to Java. Basically, ArrayBufferViews are treated as generic JavaScript objects.
     // Here, a DataView is used as an ArrayBufferView instance (since the latter is
     // an interface and can't be instantiated directly).
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassDataView() throws Throwable {
-        executeJavaScript("buffer = new ArrayBuffer(16);");
+        mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);");
 
-        executeJavaScript("testObject.setObjectValue(new DataView(buffer));");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(new DataView(buffer));");
+        Assert.assertNull(mTestObject.waitForObjectValue());
 
-        executeJavaScript("testObject.setStringValue(new DataView(buffer));");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(new DataView(buffer));");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
     }
 
     // Verify that Date objects are not converted into double values, strings or objects.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassDateObject() throws Throwable {
-        executeJavaScript("testObject.setDoubleValue(new Date(2000, 0, 1));");
-        assertEquals(0.0, mTestObject.waitForDoubleValue());
+        mActivityTestRule.executeJavaScript("testObject.setDoubleValue(new Date(2000, 0, 1));");
+        Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA);
 
-        executeJavaScript("testObject.setStringValue(new Date(2000, 0, 1));");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(new Date(2000, 0, 1));");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
 
-        executeJavaScript("testObject.setObjectValue(new Date(2000, 0, 1));");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(new Date(2000, 0, 1));");
+        Assert.assertNull(mTestObject.waitForObjectValue());
     }
 
     // Verify that RegExp objects are not converted into strings or objects.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassRegExpObject() throws Throwable {
-        executeJavaScript("testObject.setStringValue(/abc/);");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(/abc/);");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
 
-        executeJavaScript("testObject.setObjectValue(/abc/);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(/abc/);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
     }
 
     // Verify that Function objects are not converted into strings or objects.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testPassFunctionObject() throws Throwable {
-        executeJavaScript("func = new Function('a', 'b', 'return a + b');");
+        mActivityTestRule.executeJavaScript("func = new Function('a', 'b', 'return a + b');");
 
-        executeJavaScript("testObject.setStringValue(func);");
-        assertEquals("undefined", mTestObject.waitForStringValue());
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(func);");
+        Assert.assertEquals("undefined", mTestObject.waitForStringValue());
 
-        executeJavaScript("testObject.setObjectValue(func);");
-        assertNull(mTestObject.waitForObjectValue());
+        mActivityTestRule.executeJavaScript("testObject.setObjectValue(func);");
+        Assert.assertNull(mTestObject.waitForObjectValue());
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
index e1cb4b21..6f9a6de 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
@@ -6,7 +6,14 @@
 
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeTestCommon.Controller;
 
@@ -14,7 +21,11 @@
  * Part of the test suite for the Java Bridge. This test tests the
  * use of fields.
  */
-public class JavaBridgeFieldsTest extends JavaBridgeTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class JavaBridgeFieldsTest {
+    @Rule
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
+
     @SuppressFBWarnings({"CHROMIUM_SYNCHRONIZED_METHOD", "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"})
     private static class TestObject extends Controller {
         private String mStringValue;
@@ -48,45 +59,45 @@
 
     TestObject mTestObject;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mTestObject = new TestObject();
-        injectObjectAndReload(mTestObject, "testObject");
+        mActivityTestRule.injectObjectAndReload(mTestObject, "testObject");
     }
 
     // Note that this requires that we can pass a JavaScript string to Java.
     protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
-        executeJavaScript("testObject.setStringValue(" + script + ");");
+        mActivityTestRule.executeJavaScript("testObject.setStringValue(" + script + ");");
         return mTestObject.waitForStringValue();
     }
 
     // The Java bridge does not provide access to fields.
     // FIXME: Consider providing support for this. See See b/4408210.
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testFieldTypes() throws Throwable {
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.booleanField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.byteField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.charField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.shortField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.intField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.longField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.floatField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.doubleField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.objectField"));
-        assertEquals("undefined",
-                executeJavaScriptAndGetStringResult("typeof testObject.stringField"));
-        assertEquals("undefined",
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.booleanField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.byteField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.charField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.shortField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.intField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.longField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.floatField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.doubleField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.objectField"));
+        Assert.assertEquals(
+                "undefined", executeJavaScriptAndGetStringResult("typeof testObject.stringField"));
+        Assert.assertEquals("undefined",
                 executeJavaScriptAndGetStringResult("typeof testObject.customTypeField"));
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
index 3b46841..904e4538 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
@@ -6,7 +6,14 @@
 
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeTestCommon.Controller;
 
@@ -21,7 +28,11 @@
  * FIXME: Consider making our implementation more compliant, if it will not
  * break backwards-compatibility. See b/4408210.
  */
-public class JavaBridgeReturnValuesTest extends JavaBridgeTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class JavaBridgeReturnValuesTest {
+    @Rule
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
+
     // An instance of this class is injected into the page to test returning
     // Java values to JavaScript.
     @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
@@ -105,88 +116,93 @@
 
     TestObject mTestObject;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mTestObject = new TestObject();
-        injectObjectAndReload(mTestObject, "testObject");
+        mActivityTestRule.injectObjectAndReload(mTestObject, "testObject");
     }
 
     // Note that this requires that we can pass a JavaScript string to Java.
     protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
-        executeJavaScript("testObject.setStringResult(" + script + ");");
+        mActivityTestRule.executeJavaScript("testObject.setStringResult(" + script + ");");
         return mTestObject.waitForStringResult();
     }
 
     // Note that this requires that we can pass a JavaScript boolean to Java.
     private boolean executeJavaScriptAndGetBooleanResult(String script) throws Throwable {
-        executeJavaScript("testObject.setBooleanResult(" + script + ");");
+        mActivityTestRule.executeJavaScript("testObject.setBooleanResult(" + script + ");");
         return mTestObject.waitForBooleanResult();
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testMethodReturnTypes() throws Throwable {
-        assertEquals("boolean",
+        Assert.assertEquals("boolean",
                 executeJavaScriptAndGetStringResult("typeof testObject.getBooleanValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getByteValue()"));
+        Assert.assertEquals(
+                "number", executeJavaScriptAndGetStringResult("typeof testObject.getByteValue()"));
         // char values are returned to JavaScript as numbers.
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getCharValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getShortValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getIntValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getLongValue()"));
-        assertEquals("number",
-                executeJavaScriptAndGetStringResult("typeof testObject.getFloatValue()"));
-        assertEquals("number",
+        Assert.assertEquals(
+                "number", executeJavaScriptAndGetStringResult("typeof testObject.getCharValue()"));
+        Assert.assertEquals(
+                "number", executeJavaScriptAndGetStringResult("typeof testObject.getShortValue()"));
+        Assert.assertEquals(
+                "number", executeJavaScriptAndGetStringResult("typeof testObject.getIntValue()"));
+        Assert.assertEquals(
+                "number", executeJavaScriptAndGetStringResult("typeof testObject.getLongValue()"));
+        Assert.assertEquals(
+                "number", executeJavaScriptAndGetStringResult("typeof testObject.getFloatValue()"));
+        Assert.assertEquals("number",
                 executeJavaScriptAndGetStringResult("typeof testObject.getFloatValueNoDecimal()"));
-        assertEquals("number",
+        Assert.assertEquals("number",
                 executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValue()"));
-        assertEquals("number",
+        Assert.assertEquals("number",
                 executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValueNoDecimal()"));
-        assertEquals("string",
+        Assert.assertEquals("string",
                 executeJavaScriptAndGetStringResult("typeof testObject.getStringValue()"));
-        assertEquals("string",
+        Assert.assertEquals("string",
                 executeJavaScriptAndGetStringResult("typeof testObject.getEmptyStringValue()"));
         // LIVECONNECT_COMPLIANCE: This should have type object.
-        assertEquals("undefined",
+        Assert.assertEquals("undefined",
                 executeJavaScriptAndGetStringResult("typeof testObject.getNullStringValue()"));
-        assertEquals("object",
+        Assert.assertEquals("object",
                 executeJavaScriptAndGetStringResult("typeof testObject.getObjectValue()"));
-        assertEquals("object",
+        Assert.assertEquals("object",
                 executeJavaScriptAndGetStringResult("typeof testObject.getNullObjectValue()"));
-        assertEquals("object",
+        Assert.assertEquals("object",
                 executeJavaScriptAndGetStringResult("typeof testObject.getCustomTypeValue()"));
-        assertEquals("undefined",
+        Assert.assertEquals("undefined",
                 executeJavaScriptAndGetStringResult("typeof testObject.getVoidValue()"));
     }
 
+    @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testMethodReturnValues() throws Throwable {
         // We do the string comparison in JavaScript, to avoid relying on the
         // coercion algorithm from JavaScript to Java.
-        assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getByteValue()"));
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()"));
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getByteValue()"));
         // char values are returned to JavaScript as numbers.
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getCharValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getShortValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getIntValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getLongValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getCharValue()"));
+        Assert.assertTrue(
+                executeJavaScriptAndGetBooleanResult("42 === testObject.getShortValue()"));
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getIntValue()"));
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getLongValue()"));
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult(
                 "Math.abs(42.1 - testObject.getFloatValue()) < 0.001"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult(
                 "42.0 === testObject.getFloatValueNoDecimal()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult(
                 "Math.abs(42.1 - testObject.getDoubleValue()) < 0.001"));
-        assertTrue(executeJavaScriptAndGetBooleanResult(
+        Assert.assertTrue(executeJavaScriptAndGetBooleanResult(
                 "42.0 === testObject.getDoubleValueNoDecimal()"));
-        assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.getStringValue()"));
-        assertEquals("", executeJavaScriptAndGetStringResult("testObject.getEmptyStringValue()"));
-        assertTrue(executeJavaScriptAndGetBooleanResult("undefined === testObject.getVoidValue()"));
+        Assert.assertEquals(
+                "foo", executeJavaScriptAndGetStringResult("testObject.getStringValue()"));
+        Assert.assertEquals(
+                "", executeJavaScriptAndGetStringResult("testObject.getEmptyStringValue()"));
+        Assert.assertTrue(
+                executeJavaScriptAndGetBooleanResult("undefined === testObject.getVoidValue()"));
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/MediaResourceGetterTest.java b/content/public/android/javatests/src/org/chromium/content/browser/MediaResourceGetterTest.java
index 6d99aff..3b6775dc 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/MediaResourceGetterTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/MediaResourceGetterTest.java
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -11,10 +11,15 @@
 import android.net.ConnectivityManager;
 import android.net.Uri;
 import android.support.test.filters.SmallTest;
-import android.test.InstrumentationTestCase;
 import android.test.mock.MockContext;
 import android.util.SparseArray;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.content.browser.MediaResourceGetter.MediaMetadata;
 
 import java.io.File;
@@ -25,8 +30,9 @@
 /**
  * Tests for MediaResourceGetter.
  */
+@RunWith(BaseJUnit4ClassRunner.class)
 @SuppressLint("SdCardPath")
-public class MediaResourceGetterTest extends InstrumentationTestCase {
+public class MediaResourceGetterTest {
     private static final String TEST_HTTP_URL = "http://example.com";
     private static final String TEST_USER_AGENT = // Anything, really
             "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 "
@@ -207,8 +213,7 @@
         boolean mAllowPermission = false;
         @Override
         public int checkCallingOrSelfPermission(String permission) {
-            assertEquals(android.Manifest.permission.ACCESS_NETWORK_STATE,
-                    permission);
+            Assert.assertEquals(android.Manifest.permission.ACCESS_NETWORK_STATE, permission);
             return mAllowPermission ? PackageManager.PERMISSION_GRANTED :
                 PackageManager.PERMISSION_DENIED;
         }
@@ -223,153 +228,166 @@
     private FakeMediaResourceGetter mFakeMRG;
     private InternalMockContext mMockContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mFakeMRG = new FakeMediaResourceGetter();
         mMockContext = new InternalMockContext();
     }
 
+    @Test
     @SmallTest
     public void testMediaMetadataEquals() {
-        assertEquals(sEmptyMetadata, sEmptyMetadata);
-        assertEquals(sEmptyMetadata, new MediaMetadata(0, 0, 0, false));
-        assertFalse(sEmptyMetadata.equals(null));
-        assertFalse(sEmptyMetadata.equals("test"));
-        assertFalse(sEmptyMetadata.equals(new MediaMetadata(1, 0, 0, false)));
-        assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 1, 0, false)));
-        assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 1, false)));
-        assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 0, true)));
+        Assert.assertEquals(sEmptyMetadata, sEmptyMetadata);
+        Assert.assertEquals(sEmptyMetadata, new MediaMetadata(0, 0, 0, false));
+        Assert.assertFalse(sEmptyMetadata.equals(null));
+        Assert.assertFalse(sEmptyMetadata.equals("test"));
+        Assert.assertFalse(sEmptyMetadata.equals(new MediaMetadata(1, 0, 0, false)));
+        Assert.assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 1, 0, false)));
+        Assert.assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 1, false)));
+        Assert.assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 0, true)));
     }
 
+    @Test
     @SmallTest
     public void testMediaMetadataHashCode() {
-        assertEquals(sEmptyMetadata.hashCode(), sEmptyMetadata.hashCode());
-        assertEquals(sEmptyMetadata.hashCode(), new MediaMetadata(0, 0, 0, false).hashCode());
-        assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(1, 0, 0, false).hashCode());
-        assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 1, 0, false).hashCode());
-        assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 1, false).hashCode());
-        assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 0, true).hashCode());
+        Assert.assertEquals(sEmptyMetadata.hashCode(), sEmptyMetadata.hashCode());
+        Assert.assertEquals(
+                sEmptyMetadata.hashCode(), new MediaMetadata(0, 0, 0, false).hashCode());
+        Assert.assertFalse(
+                sEmptyMetadata.hashCode() == new MediaMetadata(1, 0, 0, false).hashCode());
+        Assert.assertFalse(
+                sEmptyMetadata.hashCode() == new MediaMetadata(0, 1, 0, false).hashCode());
+        Assert.assertFalse(
+                sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 1, false).hashCode());
+        Assert.assertFalse(
+                sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 0, true).hashCode());
     }
 
+    @Test
     @SmallTest
     public void testMediaMetadataGetters() {
         MediaMetadata data = new MediaMetadata(1, 2, 3, true);
-        assertEquals(1, data.getDurationInMilliseconds());
-        assertEquals(2, data.getWidth());
-        assertEquals(3, data.getHeight());
-        assertTrue(data.isSuccess());
+        Assert.assertEquals(1, data.getDurationInMilliseconds());
+        Assert.assertEquals(2, data.getWidth());
+        Assert.assertEquals(3, data.getHeight());
+        Assert.assertTrue(data.isSuccess());
 
         // Validate no overlap of test values with defaults
         data = new MediaMetadata(4, 5, 6, false);
-        assertEquals(4, data.getDurationInMilliseconds());
-        assertEquals(5, data.getWidth());
-        assertEquals(6, data.getHeight());
-        assertFalse(data.isSuccess());
+        Assert.assertEquals(4, data.getDurationInMilliseconds());
+        Assert.assertEquals(5, data.getWidth());
+        Assert.assertEquals(6, data.getHeight());
+        Assert.assertFalse(data.isSuccess());
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_NoPermissions() {
         mMockContext.mAllowPermission = false;
-        assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                       TEST_COOKIES, TEST_USER_AGENT));
+        Assert.assertFalse(
+                mFakeMRG.configure(mMockContext, TEST_HTTP_URL, TEST_COOKIES, TEST_USER_AGENT));
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_NoActiveNetwork() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = null;
-        assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                       TEST_COOKIES, TEST_USER_AGENT));
+        Assert.assertFalse(
+                mFakeMRG.configure(mMockContext, TEST_HTTP_URL, TEST_COOKIES, TEST_USER_AGENT));
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Disallowed_Mobile() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_MOBILE;
-        assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                       TEST_COOKIES, TEST_USER_AGENT));
+        Assert.assertFalse(
+                mFakeMRG.configure(mMockContext, TEST_HTTP_URL, TEST_COOKIES, TEST_USER_AGENT));
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Disallowed_Wimax() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_WIMAX;
-        assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                       TEST_COOKIES, TEST_USER_AGENT));
+        Assert.assertFalse(
+                mFakeMRG.configure(mMockContext, TEST_HTTP_URL, TEST_COOKIES, TEST_USER_AGENT));
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Allowed_Ethernet_Cookies_NoUA() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
-        assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                      TEST_COOKIES, null));
-        assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
-        assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
-        assertNull(mFakeMRG.mPath);
-        assertNull(mFakeMRG.mContentUri);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL, TEST_COOKIES, null));
+        Assert.assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
+        Assert.assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
+        Assert.assertNull(mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mContentUri);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Allowed_Wifi_Cookies_NoUA() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_WIFI;
-        assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                      TEST_COOKIES, null));
-        assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
-        assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
-        assertNull(mFakeMRG.mPath);
-        assertNull(mFakeMRG.mContentUri);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL, TEST_COOKIES, null));
+        Assert.assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
+        Assert.assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
+        Assert.assertNull(mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mContentUri);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Allowed_Ethernet_NoCookies_NoUA() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
-        assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                      "", null));
-        assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
-        assertEquals(Collections.emptyMap(), mFakeMRG.mHeaders);
-        assertNull(mFakeMRG.mPath);
-        assertNull(mFakeMRG.mContentUri);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL, "", null));
+        Assert.assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
+        Assert.assertEquals(Collections.emptyMap(), mFakeMRG.mHeaders);
+        Assert.assertNull(mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mContentUri);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Allowed_Ethernet_Cookies_WithUA() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
-        assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                      TEST_COOKIES, TEST_USER_AGENT));
-        assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
-        assertEquals(sHeadersCookieAndUA, mFakeMRG.mHeaders);
-        assertNull(mFakeMRG.mPath);
-        assertNull(mFakeMRG.mContentUri);
+        Assert.assertTrue(
+                mFakeMRG.configure(mMockContext, TEST_HTTP_URL, TEST_COOKIES, TEST_USER_AGENT));
+        Assert.assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
+        Assert.assertEquals(sHeadersCookieAndUA, mFakeMRG.mHeaders);
+        Assert.assertNull(mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mContentUri);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Allowed_Ethernet_NoCookies_WithUA() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
-        assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                      "", TEST_USER_AGENT));
-        assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
-        assertEquals(sHeadersUAOnly, mFakeMRG.mHeaders);
-        assertNull(mFakeMRG.mPath);
-        assertNull(mFakeMRG.mContentUri);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL, "", TEST_USER_AGENT));
+        Assert.assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
+        Assert.assertEquals(sHeadersUAOnly, mFakeMRG.mHeaders);
+        Assert.assertNull(mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mContentUri);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Allowed_Ethernet_Exception() {
         mMockContext.mAllowPermission = true;
         mFakeMRG.mThrowExceptionInConfigure = true;
         mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
-        assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
-                                       "", TEST_USER_AGENT));
-        assertNull(mFakeMRG.mUri);
-        assertNull(mFakeMRG.mHeaders);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL, "", TEST_USER_AGENT));
+        Assert.assertNull(mFakeMRG.mUri);
+        Assert.assertNull(mFakeMRG.mHeaders);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Net_Allowed_LocalHost_WithNoNetwork() {
         String[] localHostUrls = {
@@ -382,195 +400,219 @@
         mMockContext.mAllowPermission = true;
         mFakeMRG.mNetworkType = null;
         for (String localHostUrl : localHostUrls) {
-            assertTrue(mFakeMRG.configure(mMockContext, localHostUrl,
-                                          TEST_COOKIES, TEST_USER_AGENT));
-            assertEquals(localHostUrl, mFakeMRG.mUri);
-            assertEquals(sHeadersCookieAndUA, mFakeMRG.mHeaders);
-            assertNull(mFakeMRG.mPath);
-            assertNull(mFakeMRG.mContentUri);
+            Assert.assertTrue(
+                    mFakeMRG.configure(mMockContext, localHostUrl, TEST_COOKIES, TEST_USER_AGENT));
+            Assert.assertEquals(localHostUrl, mFakeMRG.mUri);
+            Assert.assertEquals(sHeadersCookieAndUA, mFakeMRG.mHeaders);
+            Assert.assertNull(mFakeMRG.mPath);
+            Assert.assertNull(mFakeMRG.mContentUri);
         }
     }
 
+    @Test
     @SmallTest
     public void testConfigure_File_Allowed_MntSdcard() {
         final String path = "/mnt/sdcard/test";
         final String url = "file://" + path;
         mFakeMRG.mFileExists = true;
-        assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
-        assertEquals(path, mFakeMRG.mPath);
-        assertNull(mFakeMRG.mUri);
-        assertNull(mFakeMRG.mContentUri);
-        assertNull(mFakeMRG.mHeaders);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertEquals(path, mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mUri);
+        Assert.assertNull(mFakeMRG.mContentUri);
+        Assert.assertNull(mFakeMRG.mHeaders);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_File_Allowed_Sdcard() {
         final String path = "/sdcard/test";
         final String url = "file://" + path;
         mFakeMRG.mFileExists = true;
-        assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
-        assertEquals(path, mFakeMRG.mPath);
-        assertNull(mFakeMRG.mUri);
-        assertNull(mFakeMRG.mContentUri);
-        assertNull(mFakeMRG.mHeaders);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertEquals(path, mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mUri);
+        Assert.assertNull(mFakeMRG.mContentUri);
+        Assert.assertNull(mFakeMRG.mHeaders);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_File_Allowed_Sdcard_DoesntExist() {
         final String path = "/sdcard/test";
         final String url = "file://" + path;
         mFakeMRG.mFileExists = false;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_File_Allowed_ExternalStorage() {
         final String path = sExternalStorageDirectory + "/test";
         final String url = "file://" + path;
         mFakeMRG.mFileExists = true;
-        assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
-        assertEquals(path, mFakeMRG.mPath);
-        assertNull(mFakeMRG.mUri);
-        assertNull(mFakeMRG.mContentUri);
-        assertNull(mFakeMRG.mHeaders);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertEquals(path, mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mUri);
+        Assert.assertNull(mFakeMRG.mContentUri);
+        Assert.assertNull(mFakeMRG.mHeaders);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_File_Disallowed_Innocent() {
         final String path = "/malicious/path";
         final String url = "file://" + path;
         mFakeMRG.mFileExists = true;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_File_Disallowed_Malicious() {
         final String path = "/mnt/sdcard/../../data";
         final String url = "file://" + path;
         mFakeMRG.mFileExists = true;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_File_Allowed_Exception() {
         final String path = "/mnt/sdcard/test";
         final String url = "file://" + path;
         mFakeMRG.mFileExists = true;
         mFakeMRG.mThrowExceptionInConfigure = true;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Blob_Disallow_Null_Cache() {
         final String path = "/data/data/" + null + "/cache/";
         final String url = path;
         mFakeMRG.mFileExists = true;
         mFakeMRG.mThrowExceptionInConfigure = true;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Blob_Disallowed_Incomplete_Path() {
         final String path = "/data/data/";
         final String url = path;
         mFakeMRG.mFileExists = true;
         mFakeMRG.mThrowExceptionInConfigure = true;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Blob_Disallowed_Unknown_Path() {
         final String path = "/unknown/path/";
         final String url = path;
         mFakeMRG.mFileExists = true;
         mFakeMRG.mThrowExceptionInConfigure = true;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Blob_Disallowed_Other_Application() {
         final String path = "/data/data/org.some.other.app/cache/";
         final String url = path;
         mFakeMRG.mFileExists = true;
         mFakeMRG.mThrowExceptionInConfigure = true;
-        assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
-        assertNull(mFakeMRG.mPath);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Content_Uri_Allowed() {
-        assertTrue(mFakeMRG.configure(mMockContext, TEST_CONTENT_URI, "", null));
-        assertNull(mFakeMRG.mPath);
-        assertNull(mFakeMRG.mUri);
-        assertEquals(TEST_CONTENT_URI, mFakeMRG.mContentUri);
+        Assert.assertTrue(mFakeMRG.configure(mMockContext, TEST_CONTENT_URI, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mUri);
+        Assert.assertEquals(TEST_CONTENT_URI, mFakeMRG.mContentUri);
     }
 
+    @Test
     @SmallTest
     public void testConfigure_Content_Uri_Disallowed() {
         mFakeMRG.mThrowExceptionInConfigure = true;
-        assertFalse(mFakeMRG.configure(mMockContext, TEST_CONTENT_URI, "", null));
-        assertNull(mFakeMRG.mPath);
-        assertNull(mFakeMRG.mUri);
-        assertNull(mFakeMRG.mContentUri);
+        Assert.assertFalse(mFakeMRG.configure(mMockContext, TEST_CONTENT_URI, "", null));
+        Assert.assertNull(mFakeMRG.mPath);
+        Assert.assertNull(mFakeMRG.mUri);
+        Assert.assertNull(mFakeMRG.mContentUri);
     }
 
+    @Test
     @SmallTest
     public void testExtract_NoMetadata() {
         mFakeMRG.mFileExists = true;
-        assertEquals(sEmptyMetadata, mFakeMRG.extract(
-                mMockContext, TEST_FILE_URL, null, null));
-        assertEquals("configured successfully when we shouldn't have",
-                     TEST_FILE_PATH, mFakeMRG.mPath); // tricky
+        Assert.assertEquals(
+                sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals("configured successfully when we shouldn't have", TEST_FILE_PATH,
+                mFakeMRG.mPath); // tricky
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_ValidDuration() {
         mFakeMRG.mFileExists = true;
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
         final MediaMetadata expected = new MediaMetadata(1, 0, 0, true);
-        assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_InvalidDuration() {
         mFakeMRG.mFileExists = true;
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "i am not an integer");
-        assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(
+                sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_ValidDuration_HasVideo_NoWidth_NoHeight() {
         mFakeMRG.mFileExists = true;
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
-        assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(
+                sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_NoHeight() {
         mFakeMRG.mFileExists = true;
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "1");
-        assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(
+                sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_ValidDuration_HasVideo_InvalidWidth_NoHeight() {
         mFakeMRG.mFileExists = true;
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "i am not an integer");
-        assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(
+                sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_ValidHeight() {
         mFakeMRG.mFileExists = true;
@@ -579,9 +621,10 @@
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "2");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, "3");
         final MediaMetadata expected = new MediaMetadata(1, 2, 3, true);
-        assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_InvalidHeight() {
         mFakeMRG.mFileExists = true;
@@ -589,17 +632,21 @@
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "1");
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, "i am not an integer");
-        assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(
+                sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtract_WithMetadata_ValidDuration_ExceptionInExtract() {
         mFakeMRG.mFileExists = true;
         mFakeMRG.mThrowExceptionInExtract = true;
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
-        assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
+        Assert.assertEquals(
+                sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
     }
 
+    @Test
     @SmallTest
     public void testExtractFromFileDescriptor_ValidMetadata() {
         mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
@@ -610,9 +657,9 @@
         int fd = 1234;
         long offset = 1000;
         long length = 9000;
-        assertEquals(expected, mFakeMRG.extract(fd, offset, length));
-        assertEquals(fd, mFakeMRG.mFd);
-        assertEquals(offset, mFakeMRG.mOffset);
-        assertEquals(length, mFakeMRG.mLength);
+        Assert.assertEquals(expected, mFakeMRG.extract(fd, offset, length));
+        Assert.assertEquals(fd, mFakeMRG.mFd);
+        Assert.assertEquals(offset, mFakeMRG.mOffset);
+        Assert.assertEquals(length, mFakeMRG.mLength);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/NavigationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/NavigationTest.java
index 30bf112..46243c8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/NavigationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/NavigationTest.java
@@ -6,6 +6,12 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.UrlUtils;
@@ -15,12 +21,15 @@
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.NavigationHistory;
 import org.chromium.content_shell_apk.ContentShellActivity;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 /**
  * Tests for various aspects of navigation.
  */
-public class NavigationTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class NavigationTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
 
     private static final String URL_1 = UrlUtils.encodeHtmlDataUri("<html>1</html>");
     private static final String URL_2 = UrlUtils.encodeHtmlDataUri("<html>2</html>");
@@ -32,9 +41,8 @@
 
     private void goBack(final NavigationController navigationController,
             TestCallbackHelperContainer testCallbackHelperContainer) throws Throwable {
-        handleBlockingCallbackAction(
-                testCallbackHelperContainer.getOnPageFinishedHelper(),
-                new Runnable() {
+        mActivityTestRule.handleBlockingCallbackAction(
+                testCallbackHelperContainer.getOnPageFinishedHelper(), new Runnable() {
                     @Override
                     public void run() {
                         navigationController.goBack();
@@ -44,9 +52,8 @@
 
     private void reload(final NavigationController navigationController,
             TestCallbackHelperContainer testCallbackHelperContainer) throws Throwable {
-        handleBlockingCallbackAction(
-                testCallbackHelperContainer.getOnPageFinishedHelper(),
-                new Runnable() {
+        mActivityTestRule.handleBlockingCallbackAction(
+                testCallbackHelperContainer.getOnPageFinishedHelper(), new Runnable() {
                     @Override
                     public void run() {
                         navigationController.reload(true);
@@ -54,49 +61,56 @@
                 });
     }
 
+    @Test
     @MediumTest
     @Feature({"Navigation"})
     @FlakyTest
     public void testDirectedNavigationHistory() throws Throwable {
-        ContentShellActivity activity = launchContentShellWithUrl(URL_1);
-        waitForActiveShellToBeDoneLoading();
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl(URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
         ContentViewCore contentViewCore = activity.getActiveContentViewCore();
         NavigationController navigationController = contentViewCore.getWebContents()
                 .getNavigationController();
         TestCallbackHelperContainer testCallbackHelperContainer =
                 new TestCallbackHelperContainer(contentViewCore);
 
-        loadUrl(navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_2));
-        loadUrl(navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_3));
-        loadUrl(navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_4));
-        loadUrl(navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_5));
-        loadUrl(navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_6));
-        loadUrl(navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_7));
+        mActivityTestRule.loadUrl(
+                navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_2));
+        mActivityTestRule.loadUrl(
+                navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_3));
+        mActivityTestRule.loadUrl(
+                navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_4));
+        mActivityTestRule.loadUrl(
+                navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_5));
+        mActivityTestRule.loadUrl(
+                navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_6));
+        mActivityTestRule.loadUrl(
+                navigationController, testCallbackHelperContainer, new LoadUrlParams(URL_7));
 
         NavigationHistory history = navigationController.getDirectedNavigationHistory(false, 3);
-        assertEquals(3, history.getEntryCount());
-        assertEquals(URL_6, history.getEntryAtIndex(0).getUrl());
-        assertEquals(URL_5, history.getEntryAtIndex(1).getUrl());
-        assertEquals(URL_4, history.getEntryAtIndex(2).getUrl());
+        Assert.assertEquals(3, history.getEntryCount());
+        Assert.assertEquals(URL_6, history.getEntryAtIndex(0).getUrl());
+        Assert.assertEquals(URL_5, history.getEntryAtIndex(1).getUrl());
+        Assert.assertEquals(URL_4, history.getEntryAtIndex(2).getUrl());
 
         history = navigationController.getDirectedNavigationHistory(true, 3);
-        assertEquals(history.getEntryCount(), 0);
+        Assert.assertEquals(history.getEntryCount(), 0);
 
         goBack(navigationController, testCallbackHelperContainer);
         goBack(navigationController, testCallbackHelperContainer);
         goBack(navigationController, testCallbackHelperContainer);
 
         history = navigationController.getDirectedNavigationHistory(false, 4);
-        assertEquals(3, history.getEntryCount());
-        assertEquals(URL_3, history.getEntryAtIndex(0).getUrl());
-        assertEquals(URL_2, history.getEntryAtIndex(1).getUrl());
-        assertEquals(URL_1, history.getEntryAtIndex(2).getUrl());
+        Assert.assertEquals(3, history.getEntryCount());
+        Assert.assertEquals(URL_3, history.getEntryAtIndex(0).getUrl());
+        Assert.assertEquals(URL_2, history.getEntryAtIndex(1).getUrl());
+        Assert.assertEquals(URL_1, history.getEntryAtIndex(2).getUrl());
 
         history = navigationController.getDirectedNavigationHistory(true, 4);
-        assertEquals(3, history.getEntryCount());
-        assertEquals(URL_5, history.getEntryAtIndex(0).getUrl());
-        assertEquals(URL_6, history.getEntryAtIndex(1).getUrl());
-        assertEquals(URL_7, history.getEntryAtIndex(2).getUrl());
+        Assert.assertEquals(3, history.getEntryCount());
+        Assert.assertEquals(URL_5, history.getEntryAtIndex(0).getUrl());
+        Assert.assertEquals(URL_6, history.getEntryAtIndex(1).getUrl());
+        Assert.assertEquals(URL_7, history.getEntryAtIndex(2).getUrl());
     }
 
     /**
@@ -104,6 +118,7 @@
      * Checks to make sure that OnPageFinished events were fired and that the timestamps of when
      * the page loaded are different after the reload.
      */
+    @Test
     @MediumTest
     @Feature({"Navigation"})
     public void testPageReload() throws Throwable {
@@ -112,8 +127,8 @@
                 + "function getLoadtime() { return loadTimestamp; }</script></head></html>";
         final String urlLoadTime = UrlUtils.encodeHtmlDataUri(htmlLoadTime);
 
-        ContentShellActivity activity = launchContentShellWithUrl(urlLoadTime);
-        waitForActiveShellToBeDoneLoading();
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl(urlLoadTime);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
         ContentViewCore contentViewCore = activity.getActiveContentViewCore();
         TestCallbackHelperContainer testCallbackHelperContainer =
                 new TestCallbackHelperContainer(contentViewCore);
@@ -124,7 +139,7 @@
                 contentViewCore.getWebContents(), "getLoadtime();");
         javascriptHelper.waitUntilHasValue();
         String firstTimestamp = javascriptHelper.getJsonResultAndClear();
-        assertNotNull("Timestamp was null.", firstTimestamp);
+        Assert.assertNotNull("Timestamp was null.", firstTimestamp);
 
         // Grab the timestamp after a reload and make sure they don't match.
         reload(contentViewCore.getWebContents().getNavigationController(),
@@ -133,7 +148,7 @@
                 contentViewCore.getWebContents(), "getLoadtime();");
         javascriptHelper.waitUntilHasValue();
         String secondTimestamp = javascriptHelper.getJsonResultAndClear();
-        assertNotNull("Timestamp was null.", secondTimestamp);
-        assertFalse("Timestamps matched.", firstTimestamp.equals(secondTimestamp));
+        Assert.assertNotNull("Timestamp was null.", secondTimestamp);
+        Assert.assertFalse("Timestamps matched.", firstTimestamp.equals(secondTimestamp));
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
index a03f016..49c90b3 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
@@ -8,11 +8,19 @@
 import android.support.test.filters.MediumTest;
 import android.view.Surface;
 
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.common.ScreenOrientationValues;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.display.DisplayAndroid.DisplayAndroidObserver;
 
@@ -26,7 +34,11 @@
  * orientation: ActivityInfo.SCREEN_ORIENTATION_*
  * orientation value: ScreenOrientationValues.*
  */
-public class ScreenOrientationListenerTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ScreenOrientationListenerTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static class OrientationChangeCallbackHelper
             extends CallbackHelper implements DisplayAndroidObserver {
         private int mLastOrientation;
@@ -49,16 +61,15 @@
     private DisplayAndroid mDisplayAndroid;
     private int mNaturalOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
-        launchContentShellWithUrl("about:blank");
+        mActivityTestRule.launchContentShellWithUrl("about:blank");
         mCallbackHelper = new OrientationChangeCallbackHelper();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mDisplayAndroid = getContentViewCore().getWindowAndroid().getDisplay();
+                mDisplayAndroid =
+                        mActivityTestRule.getContentViewCore().getWindowAndroid().getDisplay();
                 mDisplayAndroid.addObserver(mCallbackHelper);
                 DisplayAndroid.startAccurateListening();
             }
@@ -72,20 +83,20 @@
         lockOrientationAndWait(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
     }
 
-    @Override
+    @After
     public void tearDown() throws Exception {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
                 mDisplayAndroid.removeObserver(mCallbackHelper);
                 mDisplayAndroid = null;
-                getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+                mActivityTestRule.getActivity().setRequestedOrientation(
+                        ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
                 DisplayAndroid.stopAccurateListening();
             }
         });
 
         mCallbackHelper = null;
-        super.tearDown();
     }
 
     private static int getNaturalOrientation(DisplayAndroid display) {
@@ -115,7 +126,7 @@
                 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
                     return Surface.ROTATION_270;
                 default:
-                    fail("Should not be there!");
+                    Assert.fail("Should not be there!");
                     return Surface.ROTATION_0;
             }
         } else { // mNaturalOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
@@ -129,7 +140,7 @@
                 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
                     return Surface.ROTATION_180;
                 default:
-                    fail("Should not be there!");
+                    Assert.fail("Should not be there!");
                     return Surface.ROTATION_0;
             }
         }
@@ -154,24 +165,27 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                getActivity().setRequestedOrientation(orientation);
+                mActivityTestRule.getActivity().setRequestedOrientation(orientation);
             }
         });
         mCallbackHelper.waitForCallback(callCount);
         return mCallbackHelper.getLastRotation();
     }
 
+    @Test
     @MediumTest
     @Feature({"ScreenOrientation"})
     public void testOrientationChanges() throws Exception {
         int rotation = lockOrientationAndWait(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
-        assertEquals(orientationToRotation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE), rotation);
+        Assert.assertEquals(
+                orientationToRotation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE), rotation);
 
         rotation = lockOrientationAndWait(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-        assertEquals(orientationToRotation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT), rotation);
+        Assert.assertEquals(
+                orientationToRotation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT), rotation);
 
         rotation = lockOrientationAndWait(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
-        assertEquals(
+        Assert.assertEquals(
                 orientationToRotation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE), rotation);
 
         // Note: REVERSE_PORTRAIT does not work when device orientation is locked by user (eg from
@@ -195,7 +209,7 @@
                 case ScreenOrientationValues.PORTRAIT_SECONDARY:
                     return Surface.ROTATION_180;
                 default:
-                    fail("Can't requiest this orientation value " + orientationValue);
+                    Assert.fail("Can't requiest this orientation value " + orientationValue);
                     return 0;
             }
         } else { // mNaturalOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
@@ -213,7 +227,7 @@
                 case ScreenOrientationValues.PORTRAIT_SECONDARY:
                     return Surface.ROTATION_90;
                 default:
-                    fail("Can't requiest this orientation value " + orientationValue);
+                    Assert.fail("Can't requiest this orientation value " + orientationValue);
                     return 0;
             }
         }
@@ -230,26 +244,28 @@
             @Override
             public void run() {
                 ScreenOrientationProvider.lockOrientation(
-                        getContentViewCore().getWindowAndroid(), (byte) orientationValue);
+                        mActivityTestRule.getContentViewCore().getWindowAndroid(),
+                        (byte) orientationValue);
             }
         });
         mCallbackHelper.waitForCallback(callCount);
         return mCallbackHelper.getLastRotation();
     }
 
+    @Test
     @MediumTest
     @Feature({"ScreenOrientation"})
     public void testBasicValues() throws Exception {
         int rotation = lockOrientationValueAndWait(ScreenOrientationValues.LANDSCAPE_PRIMARY);
-        assertEquals(
+        Assert.assertEquals(
                 orientationValueToRotation(ScreenOrientationValues.LANDSCAPE_PRIMARY), rotation);
 
         rotation = lockOrientationValueAndWait(ScreenOrientationValues.PORTRAIT_PRIMARY);
-        assertEquals(
+        Assert.assertEquals(
                 orientationValueToRotation(ScreenOrientationValues.PORTRAIT_PRIMARY), rotation);
 
         rotation = lockOrientationValueAndWait(ScreenOrientationValues.LANDSCAPE_SECONDARY);
-        assertEquals(
+        Assert.assertEquals(
                 orientationValueToRotation(ScreenOrientationValues.LANDSCAPE_SECONDARY), rotation);
 
         // The note in testOrientationChanges about REVERSE_PORTRAIT applies to PORTRAIT_SECONDARY.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java b/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
index 1f50f05..5bfcf6a 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
@@ -6,16 +6,26 @@
 
 import android.support.test.filters.LargeTest;
 
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 /**
  * Integration tests for JavaScript execution.
  */
-public class TestsJavaScriptEvalTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class TestsJavaScriptEvalTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static final String JSTEST_URL = UrlUtils.encodeHtmlDataUri("<html><head><script>"
             + "  function foobar() { return 'foobar'; }"
             + "</script></head>"
@@ -28,22 +38,23 @@
      * Tests that evaluation of JavaScript for test purposes (using JavaScriptUtils, DOMUtils etc)
      * works even in presence of "background" (non-test-initiated) JavaScript evaluation activity.
      */
+    @Test
     @LargeTest
     @Feature({"Browser"})
     public void testJavaScriptEvalIsCorrectlyOrdered()
             throws InterruptedException, Exception, Throwable {
-        launchContentShellWithUrl(JSTEST_URL);
-        waitForActiveShellToBeDoneLoading();
+        mActivityTestRule.launchContentShellWithUrl(JSTEST_URL);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
-        final WebContents webContents = getWebContents();
+        final WebContents webContents = mActivityTestRule.getWebContents();
         for (int i = 0; i < 30; ++i) {
             for (int j = 0; j < 10; ++j) {
                 // Start evaluation of a JavaScript script -- we don't need a result.
                 webContents.evaluateJavaScriptForTests("foobar();", null);
             }
             // DOMUtils does need to evaluate a JavaScript and get its result to get DOM bounds.
-            assertNotNull("Failed to get bounds",
-                    DOMUtils.getNodeBounds(webContents, "test"));
+            Assert.assertNotNull(
+                    "Failed to get bounds", DOMUtils.getNodeBounds(webContents, "test"));
         }
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java b/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java
index ead616c..586bc15 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java
@@ -9,42 +9,52 @@
 import android.os.SystemClock;
 import android.support.test.filters.MediumTest;
 
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_shell_apk.ContentShellActivity;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.io.File;
 
 /**
  * Test suite for TracingControllerAndroid.
  */
-public class TracingControllerAndroidTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class TracingControllerAndroidTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
 
     private static final long TIMEOUT_MILLIS = scaleTimeout(30 * 1000);
 
+    @Test
     @MediumTest
     @Feature({"GPU"})
     @DisabledTest(message = "crbug.com/621956")
     public void testTraceFileCreation() throws Exception {
-        ContentShellActivity activity = launchContentShellWithUrl("about:blank");
-        waitForActiveShellToBeDoneLoading();
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
         final TracingControllerAndroid tracingController = new TracingControllerAndroid(activity);
-        assertFalse(tracingController.isTracing());
-        assertNull(tracingController.getOutputPath());
+        Assert.assertFalse(tracingController.isTracing());
+        Assert.assertNull(tracingController.getOutputPath());
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                assertTrue(tracingController.startTracing(true, "*", "record-until-full"));
+                Assert.assertTrue(tracingController.startTracing(true, "*", "record-until-full"));
             }
         });
 
-        assertTrue(tracingController.isTracing());
+        Assert.assertTrue(tracingController.isTracing());
         File file = new File(tracingController.getOutputPath());
-        assertTrue(file.getName().startsWith("chrome-profile-results"));
+        Assert.assertTrue(file.getName().startsWith("chrome-profile-results"));
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
@@ -58,14 +68,14 @@
         long startTime = SystemClock.uptimeMillis();
         while (tracingController.isTracing()) {
             if (SystemClock.uptimeMillis() > startTime + TIMEOUT_MILLIS) {
-                fail("Timed out waiting for tracing to stop.");
+                Assert.fail("Timed out waiting for tracing to stop.");
             }
             Thread.sleep(1000);
         }
 
         // It says it stopped, so it should have written the output file.
-        assertTrue(file.exists());
-        assertTrue(file.delete());
+        Assert.assertTrue(file.exists());
+        Assert.assertTrue(file.delete());
         tracingController.destroy();
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
index 16c37f7..ab26b15f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
@@ -5,11 +5,16 @@
 package org.chromium.content.browser;
 
 import android.content.Context;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
-import android.test.InstrumentationTestCase;
 import android.view.WindowManager;
 
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.ui.VSyncMonitor;
 
@@ -19,7 +24,8 @@
 /**
  * Tests VSyncMonitor to make sure it generates correct VSync timestamps.
  */
-public class VSyncMonitorTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class VSyncMonitorTest {
     private static final int FRAME_COUNT = 60;
 
     private static class VSyncDataCollector implements VSyncMonitor.Listener {
@@ -74,7 +80,7 @@
         return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<VSyncMonitor>() {
             @Override
             public VSyncMonitor call() {
-                Context context = getInstrumentation().getContext();
+                Context context = InstrumentationRegistry.getInstrumentation().getContext();
                 return new VSyncMonitor(context, listener);
             }
         });
@@ -92,6 +98,7 @@
     }
 
     // Check that the vsync period roughly matches the timestamps that the monitor generates.
+    @Test
     @MediumTest
     @DisabledTest(message = "crbug.com/674129")
     public void testVSyncPeriod() throws InterruptedException {
@@ -100,30 +107,30 @@
         VSyncMonitor monitor = createVSyncMonitor(collector);
 
         long reportedFramePeriod = monitor.getVSyncPeriodInMicroseconds();
-        assertTrue(reportedFramePeriod > 0);
+        Assert.assertTrue(reportedFramePeriod > 0);
 
-        assertFalse(collector.isDone());
+        Assert.assertFalse(collector.isDone());
         requestVSyncMonitorUpdate(monitor);
         collector.waitTillDone();
-        assertTrue(collector.isDone());
+        Assert.assertTrue(collector.isDone());
 
         // Check that the median frame rate is within 10% of the reported frame period.
-        assertTrue(collector.mFrameCount == FRAME_COUNT - 1);
+        Assert.assertTrue(collector.mFrameCount == FRAME_COUNT - 1);
         Arrays.sort(collector.mFramePeriods, 0, collector.mFramePeriods.length);
         long medianFramePeriod = collector.mFramePeriods[collector.mFramePeriods.length / 2];
         if (Math.abs(medianFramePeriod - reportedFramePeriod) > reportedFramePeriod * .1) {
-            fail("Measured median frame period " + medianFramePeriod
+            Assert.fail("Measured median frame period " + medianFramePeriod
                     + " differs by more than 10% from the reported frame period "
                     + reportedFramePeriod + " for requested frames");
         }
 
-        Context context = getInstrumentation().getContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
         float refreshRate = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay().getRefreshRate();
         if (refreshRate < 30.0f) {
             // Reported refresh rate is most likely incorrect.
             // Estimated vsync period is expected to be lower than (1000000 / 30) microseconds
-            assertTrue(monitor.getVSyncPeriodInMicroseconds() < 1000000 / 30);
+            Assert.assertTrue(monitor.getVSyncPeriodInMicroseconds() < 1000000 / 30);
         }
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java
index dcfb0a21..7db250a 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java
@@ -7,18 +7,29 @@
 import android.os.Vibrator;
 import android.support.test.filters.MediumTest;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 import org.chromium.device.vibration.VibrationManagerImpl;
 
 /**
  * Tests java implementation of VibrationManager mojo service on android.
  */
-public class VibrationManagerImplTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class VibrationManagerImplTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static final String URL_VIBRATOR_VIBRATE = UrlUtils.encodeHtmlDataUri("<html><body>"
             + "  <script type=\"text/javascript\">"
             + "    navigator.vibrate(3000);"
@@ -57,16 +68,15 @@
         }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        launchContentShellWithUrl("about:blank");
-        waitForActiveShellToBeDoneLoading();
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.launchContentShellWithUrl("about:blank");
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
         mFakeWrapper = new FakeAndroidVibratorWrapper();
         VibrationManagerImpl.setVibratorWrapperForTesting(mFakeWrapper);
-        assertEquals(-1, mFakeWrapper.mMilliSeconds);
-        assertFalse(mFakeWrapper.mCancelled);
+        Assert.assertEquals(-1, mFakeWrapper.mMilliSeconds);
+        Assert.assertFalse(mFakeWrapper.mCancelled);
     }
 
     /**
@@ -77,9 +87,10 @@
      */
     // @MediumTest
     // @Feature({"Vibration"})
+    @Test
     @DisabledTest
     public void testVibrate() throws Throwable {
-        loadNewShell(URL_VIBRATOR_VIBRATE);
+        mActivityTestRule.loadNewShell(URL_VIBRATOR_VIBRATE);
 
         // Waits until VibrationManagerImpl.Vibrate() got called.
         CriteriaHelper.pollUiThread(new Criteria() {
@@ -89,7 +100,7 @@
             }
         });
 
-        assertEquals(
+        Assert.assertEquals(
                 "Did not get vibrate mMilliSeconds correctly", 3000, mFakeWrapper.mMilliSeconds);
     }
 
@@ -98,10 +109,11 @@
      * load the webpage which will request vibrate and then request cancel,
      * the fake wrapper cancel() should be called.
      */
+    @Test
     @MediumTest
     @Feature({"Vibration"})
     public void testCancel() throws Throwable {
-        loadNewShell(URL_VIBRATOR_CANCEL);
+        mActivityTestRule.loadNewShell(URL_VIBRATOR_CANCEL);
 
         // Waits until VibrationManagerImpl.Cancel() got called.
         CriteriaHelper.pollUiThread(new Criteria() {
@@ -111,6 +123,6 @@
             }
         });
 
-        assertTrue("Did not get cancelled", mFakeWrapper.mCancelled);
+        Assert.assertTrue("Did not get cancelled", mFakeWrapper.mCancelled);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ViewportTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ViewportTest.java
index dfd6ade3..2b86f8f0 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ViewportTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ViewportTest.java
@@ -5,22 +5,32 @@
 package org.chromium.content.browser;
 
 import android.content.Context;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.util.DisplayMetrics;
 import android.view.WindowManager;
 
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 /**
  * Test suite for viewport-related properties.
  */
-public class ViewportTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ViewportTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
 
     protected String evaluateStringValue(String expression) throws Throwable {
-        return JavaScriptUtils.executeJavaScriptAndWaitForResult(getWebContents(),
-                expression);
+        return JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                mActivityTestRule.getWebContents(), expression);
     }
 
     protected float evaluateFloatValue(String expression) throws Throwable {
@@ -31,25 +41,27 @@
         return Integer.parseInt(evaluateStringValue(expression));
     }
 
+    @Test
     @MediumTest
     @Feature({"Viewport", "InitialViewportSize"})
     public void testDefaultViewportSize() throws Throwable {
-        launchContentShellWithUrl("about:blank");
-        waitForActiveShellToBeDoneLoading();
+        mActivityTestRule.launchContentShellWithUrl("about:blank");
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
-        Context context = getInstrumentation().getTargetContext();
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
         WindowManager winManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         DisplayMetrics metrics = new DisplayMetrics();
         winManager.getDefaultDisplay().getMetrics(metrics);
 
         // window.devicePixelRatio should match the default display. Only check to 1 decimal place
         // to allow for rounding.
-        assertEquals(metrics.density, evaluateFloatValue("window.devicePixelRatio"), 0.1);
+        Assert.assertEquals(metrics.density, evaluateFloatValue("window.devicePixelRatio"), 0.1);
 
         // Check that the viewport width is vaguely sensible.
         int viewportWidth = evaluateIntegerValue("document.documentElement.clientWidth");
-        assertTrue(Math.abs(evaluateIntegerValue("window.innerWidth") - viewportWidth) <= 1);
-        assertTrue(viewportWidth >= 979);
-        assertTrue(viewportWidth <= Math.max(981, metrics.widthPixels / metrics.density + 1));
+        Assert.assertTrue(Math.abs(evaluateIntegerValue("window.innerWidth") - viewportWidth) <= 1);
+        Assert.assertTrue(viewportWidth >= 979);
+        Assert.assertTrue(
+                viewportWidth <= Math.max(981, metrics.widthPixels / metrics.density + 1));
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java b/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java
index b89d1d2..4a299bd 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java
@@ -4,7 +4,16 @@
 
 package org.chromium.content.browser;
 
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.UrlUtils;
@@ -12,14 +21,18 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.content_shell_apk.ContentShellActivity;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.util.concurrent.Callable;
 
 /**
  * Tests for the WebContentsObserver APIs.
  */
-public class WebContentsObserverAndroidTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class WebContentsObserverAndroidTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static final String URL = UrlUtils.encodeHtmlDataUri(
             "<html><head></head><body>didFirstVisuallyNonEmptyPaint test</body></html>");
 
@@ -40,33 +53,36 @@
         }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        ContentShellActivity activity = launchContentShellWithUrl(null);
-        assertNotNull(activity);
-        waitForActiveShellToBeDoneLoading();
+    @Before
+    public void setUp() throws Exception {
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl(null);
+        Assert.assertNotNull(activity);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
     }
 
     /*
     @SmallTest
     @Feature({"Navigation"})
     */
+    @Test
     @DisabledTest(message = "crbug.com/411931")
     public void testDidFirstVisuallyNonEmptyPaint() throws Throwable {
         TestWebContentsObserver observer = ThreadUtils.runOnUiThreadBlocking(
                 new Callable<TestWebContentsObserver>() {
                     @Override
                     public TestWebContentsObserver call() throws Exception {
-                        return new TestWebContentsObserver(getContentViewCore().getWebContents());
+                        return new TestWebContentsObserver(
+                                mActivityTestRule.getContentViewCore().getWebContents());
                     }
                 });
 
         int callCount = observer.getDidFirstVisuallyNonEmptyPaintCallbackHelper().getCallCount();
-        getInstrumentation().runOnMainSync(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                getContentViewCore().getWebContents().getNavigationController()
+                mActivityTestRule.getContentViewCore()
+                        .getWebContents()
+                        .getNavigationController()
                         .loadUrl(new LoadUrlParams(URL));
             }
         });
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java
index f136d67..2f25c265 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java
@@ -8,134 +8,141 @@
 import android.graphics.Typeface;
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.content.browser.accessibility.captioning.CaptioningChangeDelegate.ClosedCaptionEdgeAttribute;
 import org.chromium.content.browser.accessibility.captioning.CaptioningChangeDelegate.ClosedCaptionFont;
-import org.chromium.content_shell_apk.ContentShellTestBase;
 
 /**
   * Test suite to ensure that platform settings are translated to CSS appropriately
   */
-public class CaptioningChangeDelegateTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class CaptioningChangeDelegateTest {
     private static final String DEFAULT_CAPTIONING_PREF_VALUE =
             CaptioningChangeDelegate.DEFAULT_CAPTIONING_PREF_VALUE;
 
+    @Test
     @SmallTest
     public void testFontScaleToPercentage() {
         String result = CaptioningChangeDelegate.androidFontScaleToPercentage(0f);
-        assertEquals("0%", result);
+        Assert.assertEquals("0%", result);
 
         result = CaptioningChangeDelegate.androidFontScaleToPercentage(0.000f);
-        assertEquals("0%", result);
+        Assert.assertEquals("0%", result);
 
         result = CaptioningChangeDelegate.androidFontScaleToPercentage(0.25f);
-        assertEquals("25%", result);
+        Assert.assertEquals("25%", result);
 
         result = CaptioningChangeDelegate.androidFontScaleToPercentage(1f);
-        assertEquals("100%", result);
+        Assert.assertEquals("100%", result);
 
         result = CaptioningChangeDelegate.androidFontScaleToPercentage(1.5f);
-        assertEquals("150%", result);
+        Assert.assertEquals("150%", result);
 
         result = CaptioningChangeDelegate.androidFontScaleToPercentage(0.50125f);
-        assertEquals("50%", result);
+        Assert.assertEquals("50%", result);
 
         result = CaptioningChangeDelegate.androidFontScaleToPercentage(0.50925f);
-        assertEquals("51%", result);
+        Assert.assertEquals("51%", result);
     }
 
+    @Test
     @SmallTest
     public void testAndroidColorToCssColor() {
         String result = CaptioningChangeDelegate.androidColorToCssColor(null);
-        assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, result);
+        Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, result);
 
         result = CaptioningChangeDelegate.androidColorToCssColor(Color.BLACK);
-        assertEquals("rgba(0, 0, 0, 1)", result);
+        Assert.assertEquals("rgba(0, 0, 0, 1)", result);
 
         result = CaptioningChangeDelegate.androidColorToCssColor(Color.WHITE);
-        assertEquals("rgba(255, 255, 255, 1)", result);
+        Assert.assertEquals("rgba(255, 255, 255, 1)", result);
 
         result = CaptioningChangeDelegate.androidColorToCssColor(Color.BLUE);
-        assertEquals("rgba(0, 0, 255, 1)", result);
+        Assert.assertEquals("rgba(0, 0, 255, 1)", result);
 
         // Transparent-black
         result = CaptioningChangeDelegate.androidColorToCssColor(0x00000000);
-        assertEquals("rgba(0, 0, 0, 0)", result);
+        Assert.assertEquals("rgba(0, 0, 0, 0)", result);
 
         // Transparent-white
         result = CaptioningChangeDelegate.androidColorToCssColor(0x00FFFFFF);
-        assertEquals("rgba(255, 255, 255, 0)", result);
+        Assert.assertEquals("rgba(255, 255, 255, 0)", result);
 
         // 50% opaque blue
         result = CaptioningChangeDelegate.androidColorToCssColor(0x7f0000ff);
-        assertEquals("rgba(0, 0, 255, 0.5)", result);
+        Assert.assertEquals("rgba(0, 0, 255, 0.5)", result);
 
         // No alpha information
         result = CaptioningChangeDelegate.androidColorToCssColor(0xFFFFFF);
-        assertEquals("rgba(255, 255, 255, 0)", result);
+        Assert.assertEquals("rgba(255, 255, 255, 0)", result);
     }
 
+    @Test
     @SmallTest
     public void testClosedCaptionEdgeAttributeWithDefaults() {
         ClosedCaptionEdgeAttribute edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(
                 null, null);
-        assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
+        Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(null, "red");
-        assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
+        Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(0, "red");
-        assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
+        Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, null);
-        assertEquals("silver 0.05em 0.05em 0.1em", edge.getTextShadow());
+        Assert.assertEquals("silver 0.05em 0.05em 0.1em", edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, "");
-        assertEquals("silver 0.05em 0.05em 0.1em", edge.getTextShadow());
+        Assert.assertEquals("silver 0.05em 0.05em 0.1em", edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, "red");
-        assertEquals("red 0.05em 0.05em 0.1em", edge.getTextShadow());
+        Assert.assertEquals("red 0.05em 0.05em 0.1em", edge.getTextShadow());
     }
 
+    @Test
     @SmallTest
     public void testClosedCaptionEdgeAttributeWithCustomDefaults() {
         ClosedCaptionEdgeAttribute.setShadowOffset("0.00em");
         ClosedCaptionEdgeAttribute.setDefaultEdgeColor("red");
         ClosedCaptionEdgeAttribute edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(
                 null, null);
-        assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
+        Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(null, "red");
-        assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
+        Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(0, "red");
-        assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
+        Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, null);
-        assertEquals("red 0.00em 0.00em 0.1em", edge.getTextShadow());
+        Assert.assertEquals("red 0.00em 0.00em 0.1em", edge.getTextShadow());
 
         edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, "silver");
-        assertEquals("silver 0.00em 0.00em 0.1em", edge.getTextShadow());
+        Assert.assertEquals("silver 0.00em 0.00em 0.1em", edge.getTextShadow());
     }
 
     /**
      * Verifies that certain system fonts always correspond to the default captioning font.
      */
+    @Test
     @SmallTest
     public void testClosedCaptionDefaultFonts() {
         final ClosedCaptionFont nullFont = ClosedCaptionFont.fromSystemFont(null);
-        assertEquals(
-                "Null typeface should return the default font family.",
+        Assert.assertEquals("Null typeface should return the default font family.",
                 DEFAULT_CAPTIONING_PREF_VALUE, nullFont.getFontFamily());
 
         final ClosedCaptionFont defaultFont = ClosedCaptionFont.fromSystemFont(Typeface.DEFAULT);
-        assertEquals(
-                "Typeface.DEFAULT should return the default font family.",
+        Assert.assertEquals("Typeface.DEFAULT should return the default font family.",
                 DEFAULT_CAPTIONING_PREF_VALUE, defaultFont.getFontFamily());
 
         final ClosedCaptionFont defaultBoldFont = ClosedCaptionFont.fromSystemFont(
                 Typeface.DEFAULT_BOLD);
-        assertEquals(
-                "Typeface.BOLD should return the default font family.",
+        Assert.assertEquals("Typeface.BOLD should return the default font family.",
                 DEFAULT_CAPTIONING_PREF_VALUE, defaultBoldFont.getFontFamily());
     }
 
@@ -144,40 +151,38 @@
      * so this test ensures that each typeface returns DEFAULT_CAPTIONING_PREF_VALUE if it is
      * equal to Typeface.DEFAULT or returns an explicit font family otherwise.
      */
+    @Test
     @SmallTest
     public void testClosedCaptionNonDefaultFonts() {
         final ClosedCaptionFont monospaceFont = ClosedCaptionFont.fromSystemFont(
                 Typeface.MONOSPACE);
         if (Typeface.MONOSPACE.equals(Typeface.DEFAULT)) {
-            assertEquals(
+            Assert.assertEquals(
                     "Since the default font is monospace, the default family should be returned.",
                     DEFAULT_CAPTIONING_PREF_VALUE, monospaceFont.getFontFamily());
         } else {
-            assertTrue(
-                    "Typeface.MONOSPACE should return a monospace font family.",
+            Assert.assertTrue("Typeface.MONOSPACE should return a monospace font family.",
                     monospaceFont.mFlags.contains(ClosedCaptionFont.Flags.MONOSPACE));
         }
 
         final ClosedCaptionFont sansSerifFont = ClosedCaptionFont.fromSystemFont(
                 Typeface.SANS_SERIF);
         if (Typeface.SANS_SERIF.equals(Typeface.DEFAULT)) {
-            assertEquals(
+            Assert.assertEquals(
                     "Since the default font is sans-serif, the default family should be returned.",
                     DEFAULT_CAPTIONING_PREF_VALUE, sansSerifFont.getFontFamily());
         } else {
-            assertTrue(
-                    "Typeface.SANS_SERIF should return a sans-serif font family.",
+            Assert.assertTrue("Typeface.SANS_SERIF should return a sans-serif font family.",
                     sansSerifFont.mFlags.contains(ClosedCaptionFont.Flags.SANS_SERIF));
         }
 
         final ClosedCaptionFont serifFont = ClosedCaptionFont.fromSystemFont(Typeface.SERIF);
         if (Typeface.SERIF.equals(Typeface.DEFAULT)) {
-            assertEquals(
+            Assert.assertEquals(
                     "Since the default font is serif, the default font family should be returned.",
                     DEFAULT_CAPTIONING_PREF_VALUE, serifFont.getFontFamily());
         } else {
-            assertTrue(
-                    "Typeface.SERIF should return a serif font family.",
+            Assert.assertTrue("Typeface.SERIF should return a serif font family.",
                     serifFont.mFlags.contains(ClosedCaptionFont.Flags.SERIF));
         }
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/crypto/CipherFactoryTest.java b/content/public/android/javatests/src/org/chromium/content/browser/crypto/CipherFactoryTest.java
index e379e0d..f8868b3 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/crypto/CipherFactoryTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/crypto/CipherFactoryTest.java
@@ -6,9 +6,14 @@
 
 import android.os.Bundle;
 import android.support.test.filters.MediumTest;
-import android.test.InstrumentationTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.content.browser.crypto.CipherFactory.CipherDataObserver;
 
 import java.io.IOException;
@@ -24,7 +29,8 @@
  * Tests that confirm that the class is thread-safe would require putting potentially flaky hooks
  * throughout the class to simulate artificial blockages.
  */
-public class CipherFactoryTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class CipherFactoryTest {
     private static final byte[] INPUT_DATA = {1, 16, 84};
 
     /** Generates non-random byte[] for testing. */
@@ -77,9 +83,8 @@
      * Overrides the {@link ByteArrayGenerator} used by the {@link CipherFactory} to ensure
      * deterministic results.
      */
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mNumberProvider = new DeterministicParameterGenerator();
         CipherFactory.getInstance().setRandomNumberProviderForTests(mNumberProvider);
     }
@@ -87,6 +92,7 @@
     /**
      * {@link Cipher} instances initialized using the same parameters work in exactly the same way.
      */
+    @Test
     @MediumTest
     public void testCipherUse() throws Exception {
         // Check encryption.
@@ -98,13 +104,14 @@
         Cipher aDecrypt = CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
         Cipher bDecrypt = CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
         byte[] decrypted = sameOutputDifferentCiphers(output, aDecrypt, bDecrypt);
-        assertTrue(Arrays.equals(decrypted, INPUT_DATA));
+        Assert.assertTrue(Arrays.equals(decrypted, INPUT_DATA));
     }
 
     /**
      * Restoring a {@link Bundle} containing the same parameters already in use by the
      * {@link CipherFactory} should keep the same keys.
      */
+    @Test
     @MediumTest
     public void testSameBundleRestoration() throws Exception {
         // Create two bundles with the same saved state.
@@ -120,9 +127,9 @@
         bBundle.putByteArray(CipherFactory.BUNDLE_KEY, sameKey);
 
         // Restore using the first bundle, then the second. Both should succeed.
-        assertTrue(CipherFactory.getInstance().restoreFromBundle(aBundle));
+        Assert.assertTrue(CipherFactory.getInstance().restoreFromBundle(aBundle));
         Cipher aCipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
-        assertTrue(CipherFactory.getInstance().restoreFromBundle(bBundle));
+        Assert.assertTrue(CipherFactory.getInstance().restoreFromBundle(bBundle));
         Cipher bCipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
 
         // Make sure the CipherFactory instances are using the same key.
@@ -134,6 +141,7 @@
      * by the {@link CipherFactory} should fail. Any Ciphers created after the failed restoration
      * attempt should use the already-existing keys.
      */
+    @Test
     @MediumTest
     public void testDifferentBundleRestoration() throws Exception {
         // Restore one set of parameters.
@@ -142,7 +150,7 @@
         byte[] aKey = mNumberProvider.getBytes(CipherFactory.NUM_BYTES, (byte) 100);
         aBundle.putByteArray(CipherFactory.BUNDLE_IV, aIv);
         aBundle.putByteArray(CipherFactory.BUNDLE_KEY, aKey);
-        assertTrue(CipherFactory.getInstance().restoreFromBundle(aBundle));
+        Assert.assertTrue(CipherFactory.getInstance().restoreFromBundle(aBundle));
         Cipher aCipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
 
         // Restore using a different set of parameters.
@@ -151,7 +159,7 @@
         byte[] bKey = mNumberProvider.getBytes(CipherFactory.NUM_BYTES, (byte) 200);
         bBundle.putByteArray(CipherFactory.BUNDLE_IV, bIv);
         bBundle.putByteArray(CipherFactory.BUNDLE_KEY, bKey);
-        assertFalse(CipherFactory.getInstance().restoreFromBundle(bBundle));
+        Assert.assertFalse(CipherFactory.getInstance().restoreFromBundle(bBundle));
         Cipher bCipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
 
         // Make sure they're using the same (original) key by encrypting the same data.
@@ -161,22 +169,23 @@
     /**
      * Restoration from a {@link Bundle} missing data should fail.
      */
+    @Test
     @MediumTest
     public void testIncompleteBundleRestoration() throws Exception {
         // Make sure we handle the null case.
-        assertFalse(CipherFactory.getInstance().restoreFromBundle(null));
+        Assert.assertFalse(CipherFactory.getInstance().restoreFromBundle(null));
 
         // Try restoring without the key.
         Bundle aBundle = new Bundle();
         byte[] iv = mNumberProvider.getBytes(CipherFactory.NUM_BYTES, (byte) 50);
         aBundle.putByteArray(CipherFactory.BUNDLE_IV, iv);
-        assertFalse(CipherFactory.getInstance().restoreFromBundle(aBundle));
+        Assert.assertFalse(CipherFactory.getInstance().restoreFromBundle(aBundle));
 
         // Try restoring without the initialization vector.
         Bundle bBundle = new Bundle();
         byte[] key = mNumberProvider.getBytes(CipherFactory.NUM_BYTES, (byte) 100);
         bBundle.putByteArray(CipherFactory.BUNDLE_KEY, key);
-        assertFalse(CipherFactory.getInstance().restoreFromBundle(bBundle));
+        Assert.assertFalse(CipherFactory.getInstance().restoreFromBundle(bBundle));
     }
 
     /**
@@ -184,6 +193,7 @@
      * parameters from a {@link Bundle} before this point should result in {@link Cipher}s using the
      * restored parameters instead of any generated ones.
      */
+    @Test
     @MediumTest
     public void testRestorationSucceedsBeforeCipherCreated() throws Exception {
         byte[] iv = mNumberProvider.getBytes(CipherFactory.NUM_BYTES, (byte) 50);
@@ -193,15 +203,16 @@
         bundle.putByteArray(CipherFactory.BUNDLE_KEY, key);
 
         // The keys should be initialized only after restoration.
-        assertNull(CipherFactory.getInstance().getCipherData(false));
-        assertTrue(CipherFactory.getInstance().restoreFromBundle(bundle));
-        assertNotNull(CipherFactory.getInstance().getCipherData(false));
+        Assert.assertNull(CipherFactory.getInstance().getCipherData(false));
+        Assert.assertTrue(CipherFactory.getInstance().restoreFromBundle(bundle));
+        Assert.assertNotNull(CipherFactory.getInstance().getCipherData(false));
     }
 
     /**
      * If the {@link CipherFactory} has already generated parameters, restorations of different data
      * should fail. All {@link Cipher}s should use the generated parameters.
      */
+    @Test
     @MediumTest
     public void testRestorationDiscardsAfterOtherCipherAlreadyCreated() throws Exception {
         byte[] iv = mNumberProvider.getBytes(CipherFactory.NUM_BYTES, (byte) 50);
@@ -212,7 +223,7 @@
 
         // The keys should be initialized after creating the cipher, so the keys shouldn't match.
         Cipher aCipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
-        assertFalse(CipherFactory.getInstance().restoreFromBundle(bundle));
+        Assert.assertFalse(CipherFactory.getInstance().restoreFromBundle(bundle));
         Cipher bCipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
 
         // B's cipher should use the keys generated for A.
@@ -222,42 +233,44 @@
     /**
      * Data saved out to the {@link Bundle} should match what is held by the {@link CipherFactory}.
      */
+    @Test
     @MediumTest
     public void testSavingToBundle() throws Exception {
         // Nothing should get saved out before Cipher data exists.
         Bundle initialBundle = new Bundle();
         CipherFactory.getInstance().saveToBundle(initialBundle);
-        assertFalse(initialBundle.containsKey(CipherFactory.BUNDLE_IV));
-        assertFalse(initialBundle.containsKey(CipherFactory.BUNDLE_KEY));
+        Assert.assertFalse(initialBundle.containsKey(CipherFactory.BUNDLE_IV));
+        Assert.assertFalse(initialBundle.containsKey(CipherFactory.BUNDLE_KEY));
 
         // Check that Cipher data gets saved if it exists.
         CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
         Bundle afterBundle = new Bundle();
         CipherFactory.getInstance().saveToBundle(afterBundle);
-        assertTrue(afterBundle.containsKey(CipherFactory.BUNDLE_IV));
-        assertTrue(afterBundle.containsKey(CipherFactory.BUNDLE_KEY));
+        Assert.assertTrue(afterBundle.containsKey(CipherFactory.BUNDLE_IV));
+        Assert.assertTrue(afterBundle.containsKey(CipherFactory.BUNDLE_KEY));
 
         // Confirm the saved keys match by restoring it.
-        assertTrue(CipherFactory.getInstance().restoreFromBundle(afterBundle));
+        Assert.assertTrue(CipherFactory.getInstance().restoreFromBundle(afterBundle));
     }
 
     /**
      * Checks that an observer is notified when cipher data is created.
      */
+    @Test
     @MediumTest
     public void testCipherFactoryObserver() throws Exception {
         TestCipherDataObserver observer = new TestCipherDataObserver();
         CipherFactory.getInstance().addCipherDataObserver(observer);
-        assertEquals(0, observer.getTimesNotified());
+        Assert.assertEquals(0, observer.getTimesNotified());
         CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
         ThreadUtils.runOnUiThreadBlocking(mEmptyRunnable);
-        assertEquals(1, observer.getTimesNotified());
+        Assert.assertEquals(1, observer.getTimesNotified());
         CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
         ThreadUtils.runOnUiThreadBlocking(mEmptyRunnable);
-        assertEquals(1, observer.getTimesNotified());
+        Assert.assertEquals(1, observer.getTimesNotified());
         CipherFactory.getInstance().getCipher(Cipher.ENCRYPT_MODE);
         ThreadUtils.runOnUiThreadBlocking(mEmptyRunnable);
-        assertEquals(1, observer.getTimesNotified());
+        Assert.assertEquals(1, observer.getTimesNotified());
         CipherFactory.getInstance().removeCipherDataObserver(observer);
     }
 
@@ -265,6 +278,7 @@
      * Verifies that if the observer is attached after cipher data has already been
      * created the observer doesn't fire.
      */
+    @Test
     @MediumTest
     public void testCipherFactoryObserverTooLate() throws Exception {
         CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
@@ -273,10 +287,10 @@
         TestCipherDataObserver observer = new TestCipherDataObserver();
         CipherFactory.getInstance().addCipherDataObserver(observer);
         ThreadUtils.runOnUiThreadBlocking(mEmptyRunnable);
-        assertEquals(0, observer.getTimesNotified());
+        Assert.assertEquals(0, observer.getTimesNotified());
         CipherFactory.getInstance().getCipher(Cipher.DECRYPT_MODE);
         ThreadUtils.runOnUiThreadBlocking(mEmptyRunnable);
-        assertEquals(0, observer.getTimesNotified());
+        Assert.assertEquals(0, observer.getTimesNotified());
     }
 
     /**
@@ -285,16 +299,16 @@
      */
     private byte[] sameOutputDifferentCiphers(byte[] input, Cipher aCipher, Cipher bCipher)
             throws Exception {
-        assertNotNull(aCipher);
-        assertNotNull(bCipher);
-        assertNotSame(aCipher, bCipher);
+        Assert.assertNotNull(aCipher);
+        Assert.assertNotNull(bCipher);
+        Assert.assertNotSame(aCipher, bCipher);
 
         byte[] aOutput = aCipher.doFinal(input);
         byte[] bOutput = bCipher.doFinal(input);
 
-        assertNotNull(aOutput);
-        assertNotNull(bOutput);
-        assertTrue(Arrays.equals(aOutput, bOutput));
+        Assert.assertNotNull(aOutput);
+        Assert.assertNotNull(bOutput);
+        Assert.assertTrue(Arrays.equals(aOutput, bOutput));
 
         return aOutput;
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java
index 0201310..37afba4 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java
@@ -5,9 +5,15 @@
 package org.chromium.content.browser.input;
 
 import android.content.Context;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
-import android.test.AndroidTestCase;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.picker.InputDialogContainer;
 import org.chromium.ui.base.ime.TextInputType;
@@ -15,7 +21,8 @@
 /**
  * Unittests for the {@link org.chromium.content.browser.picker.InputDialogContainer} class.
  */
-public class InputDialogContainerTest extends AndroidTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class InputDialogContainerTest {
     // Defined in third_party/WebKit/Source/platform/DateComponents.h
     private static final double DATE_DIALOG_DEFAULT_MIN = -62135596800000.0;
     private static final double DATE_DIALOG_DEFAULT_MAX = 8640000000000000.0;
@@ -28,17 +35,19 @@
     private static final double WEEK_DIALOG_DEFAULT_MIN = -62135596800000.0;
     private static final double WEEK_DIALOG_DEFAULT_MAX = 8639999568000000.0;
 
+    private static final double ASSERTION_DELTA = 0;
+
     InputActionDelegateForTests mInputActionDelegate;
     InputDialogContainerForTests mInputDialogContainer;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         mInputActionDelegate = new InputActionDelegateForTests();
-        mInputDialogContainer = new InputDialogContainerForTests(getContext(),
-                                                                 mInputActionDelegate);
+        mInputDialogContainer = new InputDialogContainerForTests(
+                InstrumentationRegistry.getContext(), mInputActionDelegate);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testDateValueParsing() {
@@ -71,6 +80,7 @@
                 DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testDatetimelocalValueParsing() {
@@ -103,6 +113,7 @@
                 DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 0.001);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testMonthValueParsing() {
@@ -135,6 +146,7 @@
                 MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testTimeValueParsing() {
@@ -161,6 +173,7 @@
                 TIME_DIALOG_DEFAULT_MIN, TIME_DIALOG_DEFAULT_MAX, 1.0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testWeekValueParsing() {
@@ -193,6 +206,7 @@
                 WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testDateValueGenerating() {
@@ -217,6 +231,7 @@
                 0, 0, 0, 0, 0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testDatetimelocalValueGenerating() {
@@ -241,6 +256,7 @@
                 1, 1, 2, 196, 0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testMonthValueGenerating() {
@@ -265,6 +281,7 @@
                 0, 0, 0, 0, 0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testTimeValueGenerating() {
@@ -284,6 +301,7 @@
                 3, 23, 45, 678, 0);
     }
 
+    @Test
     @SmallTest
     @Feature({"DateTimeDialog"})
     public void testWeekValueGenerating() {
@@ -318,7 +336,7 @@
 
         @Override
         public void replaceDateTime(double dialogValue) {
-            assertEquals(mExpectedDialogValue, dialogValue);
+            Assert.assertEquals(mExpectedDialogValue, dialogValue, ASSERTION_DELTA);
         }
 
         @Override
@@ -375,18 +393,18 @@
                 int year, int month, int monthDay,
                 int hourOfDay, int minute, int second, int millis, int week,
                 double min, double max, double step) {
-            assertEquals(mExpectedDialogType, dialogType);
-            assertEquals(mExpectedYear, year);
-            assertEquals(mExpectedMonth, month);
-            assertEquals(mExpectedMonthDay, monthDay);
-            assertEquals(mExpectedHourOfDay, hourOfDay);
-            assertEquals(mExpectedMinute, minute);
-            assertEquals(mExpectedSecond, second);
-            assertEquals(mExpectedMillis, millis);
-            assertEquals(mExpectedWeek, week);
-            assertEquals(mExpectedMin, min);
-            assertEquals(mExpectedMax, max);
-            assertEquals(mExpectedStep, step);
+            Assert.assertEquals(mExpectedDialogType, dialogType);
+            Assert.assertEquals(mExpectedYear, year);
+            Assert.assertEquals(mExpectedMonth, month);
+            Assert.assertEquals(mExpectedMonthDay, monthDay);
+            Assert.assertEquals(mExpectedHourOfDay, hourOfDay);
+            Assert.assertEquals(mExpectedMinute, minute);
+            Assert.assertEquals(mExpectedSecond, second);
+            Assert.assertEquals(mExpectedMillis, millis);
+            Assert.assertEquals(mExpectedWeek, week);
+            Assert.assertEquals(mExpectedMin, min, ASSERTION_DELTA);
+            Assert.assertEquals(mExpectedMax, max, ASSERTION_DELTA);
+            Assert.assertEquals(mExpectedStep, step, ASSERTION_DELTA);
         }
 
         @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/picker/DateTimePickerDialogTest.java b/content/public/android/javatests/src/org/chromium/content/browser/picker/DateTimePickerDialogTest.java
index 7c769ba..3b8229ab 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/picker/DateTimePickerDialogTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/picker/DateTimePickerDialogTest.java
@@ -4,20 +4,29 @@
 
 package org.chromium.content.browser.picker;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
-import android.test.InstrumentationTestCase;
 import android.widget.TimePicker;
 
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+
 /**
  * Tests for DateTimePickerDialog.
  */
-public class DateTimePickerDialogTest extends InstrumentationTestCase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class DateTimePickerDialogTest {
     //TODO(tkent): fix deprecation warnings crbug.com/537037
+    @Test
     @SuppressWarnings("deprecation")
     @SmallTest
     public void testOnTimeChanged() {
         int september = 8;
-        TimePicker picker = new TimePicker(getInstrumentation().getContext());
+        TimePicker picker =
+                new TimePicker(InstrumentationRegistry.getInstrumentation().getContext());
         // 2015-09-16 00:00 UTC
         long min = 1442361600000L;
         // 2015-09-17 00:00 UTC
@@ -27,15 +36,15 @@
         picker.setCurrentHour(1);
         picker.setCurrentMinute(30);
         DateTimePickerDialog.onTimeChangedInternal(2015, september, 16, picker, min, max);
-        assertEquals(1, picker.getCurrentHour().intValue());
-        assertEquals(30, picker.getCurrentMinute().intValue());
+        Assert.assertEquals(1, picker.getCurrentHour().intValue());
+        Assert.assertEquals(30, picker.getCurrentMinute().intValue());
 
         // Test a value near to the maximum.
         picker.setCurrentHour(22);
         picker.setCurrentMinute(56);
         DateTimePickerDialog.onTimeChangedInternal(2015, september, 16, picker, min, max);
-        assertEquals(22, picker.getCurrentHour().intValue());
-        assertEquals(56, picker.getCurrentMinute().intValue());
+        Assert.assertEquals(22, picker.getCurrentHour().intValue());
+        Assert.assertEquals(56, picker.getCurrentMinute().intValue());
 
         // Clamping.
         picker.setCurrentHour(23);
@@ -43,7 +52,7 @@
         // 2015-09-16 23:30 UTC
         max = 1442446200000L;
         DateTimePickerDialog.onTimeChangedInternal(2015, september, 16, picker, min, max);
-        assertEquals(23, picker.getCurrentHour().intValue());
-        assertEquals(30, picker.getCurrentMinute().intValue());
+        Assert.assertEquals(23, picker.getCurrentHour().intValue());
+        Assert.assertEquals(30, picker.getCurrentMinute().intValue());
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/webcontents/AccessibilitySnapshotTest.java b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/AccessibilitySnapshotTest.java
index 633470ae..a03cf73 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/webcontents/AccessibilitySnapshotTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/AccessibilitySnapshotTest.java
@@ -6,17 +6,29 @@
 
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 /**
  * Accessibility snapshot tests for Assist feature.
  */
-public class AccessibilitySnapshotTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class AccessibilitySnapshotTest {
+    private static final double ASSERTION_DELTA = 0;
+
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static class AccessibilityCallbackHelper extends CallbackHelper {
         private AccessibilitySnapshotNode mRoot;
 
@@ -32,10 +44,11 @@
 
     private AccessibilitySnapshotNode receiveAccessibilitySnapshot(String data, String js)
             throws Throwable {
-        launchContentShellWithUrl(UrlUtils.encodeHtmlDataUri(data));
-        waitForActiveShellToBeDoneLoading();
+        mActivityTestRule.launchContentShellWithUrl(UrlUtils.encodeHtmlDataUri(data));
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
         if (js != null) {
-            JavaScriptUtils.executeJavaScriptAndWaitForResult(getWebContents(), js);
+            JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                    mActivityTestRule.getWebContents(), js);
         }
 
         final AccessibilityCallbackHelper callbackHelper = new AccessibilityCallbackHelper();
@@ -48,10 +61,10 @@
         // read the callbackcount before executing the call on UI thread, since it may
         // synchronously complete.
         final int callbackCount = callbackHelper.getCallCount();
-        runTestOnUiThread(new Runnable() {
+        mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                getWebContents().requestAccessibilitySnapshot(callback);
+                mActivityTestRule.getWebContents().requestAccessibilitySnapshot(callback);
             }
         });
         callbackHelper.waitForCallback(callbackCount);
@@ -61,117 +74,125 @@
     /**
      * Verifies that AX tree is returned.
      */
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshot() throws Throwable {
         final String data = "<button>Click</button>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
-        assertEquals(1, child.children.size());
-        assertEquals("", child.text);
+        Assert.assertEquals(1, child.children.size());
+        Assert.assertEquals("", child.text);
         AccessibilitySnapshotNode grandChild = child.children.get(0);
-        assertEquals(0, grandChild.children.size());
-        assertEquals("Click", grandChild.text);
+        Assert.assertEquals(0, grandChild.children.size());
+        Assert.assertEquals("Click", grandChild.text);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotColors() throws Throwable {
         final String data = "<p style=\"color:#123456;background:#abcdef\">color</p>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
-        assertEquals("color", child.text);
-        assertTrue(child.hasStyle);
-        assertEquals("ff123456", Integer.toHexString(child.color));
-        assertEquals("ffabcdef", Integer.toHexString(child.bgcolor));
+        Assert.assertEquals("color", child.text);
+        Assert.assertTrue(child.hasStyle);
+        Assert.assertEquals("ff123456", Integer.toHexString(child.color));
+        Assert.assertEquals("ffabcdef", Integer.toHexString(child.bgcolor));
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotFontSize() throws Throwable {
         final String data = "<html><head><style> "
                 + "    p { font-size:16px; transform: scale(2); }"
                 + "    </style></head><body><p>foo</p></body></html>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
-        assertTrue(child.hasStyle);
-        assertEquals("foo", child.text);
+        Assert.assertTrue(child.hasStyle);
+        Assert.assertEquals("foo", child.text);
 
         // The font size should take the scale into account.
-        assertEquals(32.0, child.textSize, 1.0);
+        Assert.assertEquals(32.0, child.textSize, 1.0);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotStyles() throws Throwable {
         final String data = "<html><head><style> "
                 + "    body { font: italic bold 12px Courier; }"
                 + "    </style></head><body><p>foo</p></body></html>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
-        assertEquals("foo", child.text);
-        assertTrue(child.hasStyle);
-        assertTrue(child.bold);
-        assertTrue(child.italic);
-        assertFalse(child.lineThrough);
-        assertFalse(child.underline);
+        Assert.assertEquals("foo", child.text);
+        Assert.assertTrue(child.hasStyle);
+        Assert.assertTrue(child.bold);
+        Assert.assertTrue(child.italic);
+        Assert.assertFalse(child.lineThrough);
+        Assert.assertFalse(child.underline);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotStrongStyle() throws Throwable {
         final String data = "<html><body><p>foo</p><p><strong>bar</strong></p></body></html>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(2, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(2, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child1 = root.children.get(0);
-        assertEquals("foo", child1.text);
-        assertTrue(child1.hasStyle);
-        assertFalse(child1.bold);
+        Assert.assertEquals("foo", child1.text);
+        Assert.assertTrue(child1.hasStyle);
+        Assert.assertFalse(child1.bold);
         AccessibilitySnapshotNode child2 = root.children.get(1);
         AccessibilitySnapshotNode child2child = child2.children.get(0);
-        assertEquals("bar", child2child.text);
-        assertEquals(child1.textSize, child2child.textSize);
-        assertTrue(child2child.bold);
+        Assert.assertEquals("bar", child2child.text);
+        Assert.assertEquals(child1.textSize, child2child.textSize, ASSERTION_DELTA);
+        Assert.assertTrue(child2child.bold);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotItalicStyle() throws Throwable {
         final String data = "<html><body><i>foo</i></body></html>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("foo", grandchild.text);
-        assertTrue(grandchild.hasStyle);
-        assertTrue(grandchild.italic);
+        Assert.assertEquals("foo", grandchild.text);
+        Assert.assertTrue(grandchild.hasStyle);
+        Assert.assertTrue(grandchild.italic);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotBoldStyle() throws Throwable {
         final String data = "<html><body><b>foo</b></body></html>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("foo", grandchild.text);
-        assertTrue(grandchild.hasStyle);
-        assertTrue(grandchild.bold);
+        Assert.assertEquals("foo", grandchild.text);
+        Assert.assertTrue(grandchild.hasStyle);
+        Assert.assertTrue(grandchild.bold);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotNoStyle() throws Throwable {
         final String data = "<table><thead></thead></table>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode grandChild = root.children.get(0).children.get(0);
-        assertFalse(grandChild.hasStyle);
+        Assert.assertFalse(grandChild.hasStyle);
     }
 
     private String getSelectionScript(String node1, int start, String node2, int end) {
@@ -187,55 +208,60 @@
                 + "selection.addRange(range);";
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotOneCharacterSelection() throws Throwable {
         final String data = "<html><body><b id='node'>foo</b></body></html>";
 
         AccessibilitySnapshotNode root =
                 receiveAccessibilitySnapshot(data, getSelectionScript("node", 0, "node", 1));
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("foo", grandchild.text);
-        assertEquals(0, grandchild.startSelection);
-        assertEquals(1, grandchild.endSelection);
+        Assert.assertEquals("foo", grandchild.text);
+        Assert.assertEquals(0, grandchild.startSelection);
+        Assert.assertEquals(1, grandchild.endSelection);
     }
 
+    @Test
+
     @SmallTest
     public void testRequestAccessibilitySnapshotOneNodeSelection() throws Throwable {
         final String data = "<html><body><b id='node'>foo</b></body></html>";
 
         AccessibilitySnapshotNode root =
                 receiveAccessibilitySnapshot(data, getSelectionScript("node", 0, "node", 3));
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("foo", grandchild.text);
-        assertEquals(0, grandchild.startSelection);
-        assertEquals(3, grandchild.endSelection);
+        Assert.assertEquals("foo", grandchild.text);
+        Assert.assertEquals(0, grandchild.startSelection);
+        Assert.assertEquals(3, grandchild.endSelection);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotSubsequentNodeSelection() throws Throwable {
         final String data = "<html><body><b id='node1'>foo</b><b id='node2'>bar</b></body></html>";
 
         AccessibilitySnapshotNode root =
                 receiveAccessibilitySnapshot(data, getSelectionScript("node1", 1, "node2", 1));
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("foo", grandchild.text);
-        assertEquals(1, grandchild.startSelection);
-        assertEquals(3, grandchild.endSelection);
+        Assert.assertEquals("foo", grandchild.text);
+        Assert.assertEquals(1, grandchild.startSelection);
+        Assert.assertEquals(3, grandchild.endSelection);
         grandchild = child.children.get(1);
-        assertEquals("bar", grandchild.text);
-        assertEquals(0, grandchild.startSelection);
-        assertEquals(1, grandchild.endSelection);
+        Assert.assertEquals("bar", grandchild.text);
+        Assert.assertEquals(0, grandchild.startSelection);
+        Assert.assertEquals(1, grandchild.endSelection);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotMultiNodeSelection() throws Throwable {
         final String data =
@@ -243,23 +269,24 @@
 
         AccessibilitySnapshotNode root =
                 receiveAccessibilitySnapshot(data, getSelectionScript("node1", 1, "node2", 1));
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("foo", grandchild.text);
-        assertEquals(1, grandchild.startSelection);
-        assertEquals(3, grandchild.endSelection);
+        Assert.assertEquals("foo", grandchild.text);
+        Assert.assertEquals(1, grandchild.startSelection);
+        Assert.assertEquals(3, grandchild.endSelection);
         grandchild = child.children.get(1);
-        assertEquals("middle", grandchild.text);
-        assertEquals(0, grandchild.startSelection);
-        assertEquals(6, grandchild.endSelection);
+        Assert.assertEquals("middle", grandchild.text);
+        Assert.assertEquals(0, grandchild.startSelection);
+        Assert.assertEquals(6, grandchild.endSelection);
         grandchild = child.children.get(2);
-        assertEquals("bar", grandchild.text);
-        assertEquals(0, grandchild.startSelection);
-        assertEquals(1, grandchild.endSelection);
+        Assert.assertEquals("bar", grandchild.text);
+        Assert.assertEquals(0, grandchild.startSelection);
+        Assert.assertEquals(1, grandchild.endSelection);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotInputSelection() throws Throwable {
         final String data = "<html><body><input id='input' value='Hello, world'></body></html>";
@@ -268,24 +295,25 @@
                 + "input.selectionStart = 0;"
                 + "input.selectionEnd = 5;";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, js);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("Hello, world", grandchild.text);
-        assertEquals(0, grandchild.startSelection);
-        assertEquals(5, grandchild.endSelection);
+        Assert.assertEquals("Hello, world", grandchild.text);
+        Assert.assertEquals(0, grandchild.startSelection);
+        Assert.assertEquals(5, grandchild.endSelection);
     }
 
+    @Test
     @SmallTest
     public void testRequestAccessibilitySnapshotPasswordField() throws Throwable {
         final String data =
                 "<html><body><input id='input' type='password' value='foo'></body></html>";
         AccessibilitySnapshotNode root = receiveAccessibilitySnapshot(data, null);
-        assertEquals(1, root.children.size());
-        assertEquals("", root.text);
+        Assert.assertEquals(1, root.children.size());
+        Assert.assertEquals("", root.text);
         AccessibilitySnapshotNode child = root.children.get(0);
         AccessibilitySnapshotNode grandchild = child.children.get(0);
-        assertEquals("•••", grandchild.text);
+        Assert.assertEquals("•••", grandchild.text);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java
index f6b99ed2..508a224 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java
@@ -10,13 +10,19 @@
 import android.os.Parcel;
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content_public.browser.RenderFrameHost;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_shell.Shell;
 import org.chromium.content_shell_apk.ContentShellActivity;
-import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -25,7 +31,11 @@
  * Test various Java WebContents specific features.
  * TODO(dtrainor): Add more testing for the WebContents methods.
  */
-public class WebContentsTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class WebContentsTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     private static final String TEST_URL_1 = "about://blank";
     private static final String TEST_URL_2 = UrlUtils.encodeHtmlDataUri("<html>1</html>");
     private static final String WEB_CONTENTS_KEY = "WEBCONTENTSKEY";
@@ -39,21 +49,23 @@
      * @throws InterruptedException
      * @throws ExecutionException
      */
+    @Test
     @SmallTest
     public void testWebContentsIsDestroyedMethod() throws InterruptedException, ExecutionException {
-        final ContentShellActivity activity = launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
+        final ContentShellActivity activity =
+                mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
         WebContents webContents = activity.getActiveWebContents();
 
-        assertFalse("WebContents incorrectly marked as destroyed",
-                isWebContentsDestroyed(webContents));
+        Assert.assertFalse(
+                "WebContents incorrectly marked as destroyed", isWebContentsDestroyed(webContents));
 
         // Launch a new shell.
         Shell originalShell = activity.getActiveShell();
-        loadNewShell(TEST_URL_1);
-        assertNotSame("New shell not created", activity.getActiveShell(), originalShell);
+        mActivityTestRule.loadNewShell(TEST_URL_1);
+        Assert.assertNotSame("New shell not created", activity.getActiveShell(), originalShell);
 
-        assertTrue("WebContents incorrectly marked as not destroyed",
+        Assert.assertTrue("WebContents incorrectly marked as not destroyed",
                 isWebContentsDestroyed(webContents));
     }
 
@@ -62,11 +74,12 @@
      *
      * @throws InterruptedException
      */
+    @Test
     @SmallTest
     public void testWebContentsSerializeDeserializeInParcel() throws InterruptedException {
-        launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
-        WebContents webContents = getWebContents();
+        mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+        WebContents webContents = mActivityTestRule.getWebContents();
 
         Parcel parcel = Parcel.obtain();
 
@@ -80,8 +93,8 @@
                     WebContents.class.getClassLoader());
 
             // Make sure they're equal.
-            assertEquals("Deserialized object does not match",
-                    webContents, deserializedWebContents);
+            Assert.assertEquals(
+                    "Deserialized object does not match", webContents, deserializedWebContents);
         } finally {
             parcel.recycle();
         }
@@ -91,13 +104,14 @@
      * Check that it is possible to serialize and deserialize a WebContents object through Bundles.
      * @throws InterruptedException
      */
+    @Test
     @SmallTest
     // TODO(crbug.com/635567): Fix this properly.
     @SuppressLint("ParcelClassLoader")
     public void testWebContentsSerializeDeserializeInBundle() throws InterruptedException {
-        launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
-        WebContents webContents = getWebContents();
+        mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+        WebContents webContents = mActivityTestRule.getWebContents();
 
         // Use a parcel to force the Bundle to actually serialize and deserialize, otherwise it can
         // cache the WebContents object.
@@ -121,8 +135,8 @@
                     deserializedBundle.getParcelable(WEB_CONTENTS_KEY);
 
             // Make sure they're equal.
-            assertEquals("Deserialized object does not match",
-                    webContents, deserializedWebContents);
+            Assert.assertEquals(
+                    "Deserialized object does not match", webContents, deserializedWebContents);
         } finally {
             parcel.recycle();
         }
@@ -132,13 +146,14 @@
      * Check that it is possible to serialize and deserialize a WebContents object through Intents.
      * @throws InterruptedException
      */
+    @Test
     @SmallTest
     // TODO(crbug.com/635567): Fix this properly.
     @SuppressLint("ParcelClassLoader")
     public void testWebContentsSerializeDeserializeInIntent() throws InterruptedException {
-        launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
-        WebContents webContents = getWebContents();
+        mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+        WebContents webContents = mActivityTestRule.getWebContents();
 
         // Use a parcel to force the Intent to actually serialize and deserialize, otherwise it can
         // cache the WebContents object.
@@ -162,8 +177,8 @@
                     (WebContents) deserializedIntent.getParcelableExtra(WEB_CONTENTS_KEY);
 
             // Make sure they're equal.
-            assertEquals("Deserialized object does not match",
-                    webContents, deserializedWebContents);
+            Assert.assertEquals(
+                    "Deserialized object does not match", webContents, deserializedWebContents);
         } finally {
             parcel.recycle();
         }
@@ -174,12 +189,13 @@
      * instance fails.
      * @throws InterruptedException
      */
+    @Test
     @SmallTest
     public void testWebContentsFailDeserializationAcrossProcessBoundary()
             throws InterruptedException {
-        launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
-        WebContents webContents = getWebContents();
+        mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+        WebContents webContents = mActivityTestRule.getWebContents();
 
         Parcel parcel = Parcel.obtain();
 
@@ -196,7 +212,7 @@
                     WebContents.class.getClassLoader());
 
             // Make sure we weren't able to deserialize the WebContents.
-            assertNull("Unexpectedly deserialized a WebContents", deserializedWebContents);
+            Assert.assertNull("Unexpectedly deserialized a WebContents", deserializedWebContents);
         } finally {
             parcel.recycle();
         }
@@ -208,15 +224,16 @@
      * @throws InterruptedException
      * @throws ExecutionException
      */
+    @Test
     @SmallTest
     public void testSerializingADestroyedWebContentsDoesNotDeserialize()
             throws InterruptedException, ExecutionException {
-        ContentShellActivity activity = launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
         WebContents webContents = activity.getActiveWebContents();
-        loadNewShell(TEST_URL_1);
+        mActivityTestRule.loadNewShell(TEST_URL_1);
 
-        assertTrue("WebContents not destroyed", isWebContentsDestroyed(webContents));
+        Assert.assertTrue("WebContents not destroyed", isWebContentsDestroyed(webContents));
 
         Parcel parcel = Parcel.obtain();
 
@@ -230,8 +247,8 @@
                     WebContents.class.getClassLoader());
 
             // Make sure we weren't able to deserialize the WebContents.
-            assertNull("Unexpectedly deserialized a destroyed WebContents",
-                    deserializedWebContents);
+            Assert.assertNull(
+                    "Unexpectedly deserialized a destroyed WebContents", deserializedWebContents);
         } finally {
             parcel.recycle();
         }
@@ -243,11 +260,12 @@
      * @throws InterruptedException
      * @throws ExecutionException
      */
+    @Test
     @SmallTest
     public void testDestroyingAWebContentsAfterSerializingDoesNotDeserialize()
             throws InterruptedException, ExecutionException {
-        ContentShellActivity activity = launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
         WebContents webContents = activity.getActiveWebContents();
 
         Parcel parcel = Parcel.obtain();
@@ -257,8 +275,8 @@
             parcel.writeParcelable(webContents, 0);
 
             // Destroy the WebContents.
-            loadNewShell(TEST_URL_1);
-            assertTrue("WebContents not destroyed", isWebContentsDestroyed(webContents));
+            mActivityTestRule.loadNewShell(TEST_URL_1);
+            Assert.assertTrue("WebContents not destroyed", isWebContentsDestroyed(webContents));
 
             // Try to read back the WebContents.
             parcel.setDataPosition(0);
@@ -266,8 +284,8 @@
                     WebContents.class.getClassLoader());
 
             // Make sure we weren't able to deserialize the WebContents.
-            assertNull("Unexpectedly deserialized a destroyed WebContents",
-                    deserializedWebContents);
+            Assert.assertNull(
+                    "Unexpectedly deserialized a destroyed WebContents", deserializedWebContents);
         } finally {
             parcel.recycle();
         }
@@ -278,12 +296,12 @@
      * Parcel.
      * @throws InterruptedException
      */
+    @Test
     @SmallTest
-    public void testFailedDeserializationDoesntCorruptParcel()
-            throws InterruptedException {
-        launchContentShellWithUrl(TEST_URL_1);
-        waitForActiveShellToBeDoneLoading();
-        WebContents webContents = getWebContents();
+    public void testFailedDeserializationDoesntCorruptParcel() throws InterruptedException {
+        mActivityTestRule.launchContentShellWithUrl(TEST_URL_1);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+        WebContents webContents = mActivityTestRule.getWebContents();
 
         Parcel parcel = Parcel.obtain();
 
@@ -303,10 +321,10 @@
                     WebContents.class.getClassLoader());
 
             // Make sure we weren't able to deserialize the WebContents.
-            assertNull("Unexpectedly deserialized a WebContents", deserializedWebContents);
+            Assert.assertNull("Unexpectedly deserialized a WebContents", deserializedWebContents);
 
             // Make sure we can properly deserialize the String after the WebContents.
-            assertEquals("Failing to read the WebContents corrupted the parcel",
+            Assert.assertEquals("Failing to read the WebContents corrupted the parcel",
                     PARCEL_STRING_TEST_DATA, parcel.readString());
         } finally {
             parcel.recycle();
@@ -319,10 +337,12 @@
      *
      * @throws InterruptedException
      */
+    @Test
     @SmallTest
     public void testWebContentsMainFrame() throws InterruptedException {
-        final ContentShellActivity activity = launchContentShellWithUrl(TEST_URL_2);
-        waitForActiveShellToBeDoneLoading();
+        final ContentShellActivity activity =
+                mActivityTestRule.launchContentShellWithUrl(TEST_URL_2);
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
         final WebContents webContents = activity.getActiveWebContents();
 
         ThreadUtils.postOnUiThread(new Runnable() {
@@ -330,14 +350,14 @@
             public void run() {
                 RenderFrameHost frameHost = webContents.getMainFrame();
 
-                assertNotNull(frameHost);
+                Assert.assertNotNull(frameHost);
 
-                assertEquals("RenderFrameHost has incorrect last committed URL", TEST_URL_2,
+                Assert.assertEquals("RenderFrameHost has incorrect last committed URL", TEST_URL_2,
                         frameHost.getLastCommittedURL());
 
                 WebContents associatedWebContents = WebContentsImpl.fromRenderFrameHost(frameHost);
-                assertEquals("RenderFrameHost associated with different WebContents", webContents,
-                        associatedWebContents);
+                Assert.assertEquals("RenderFrameHost associated with different WebContents",
+                        webContents, associatedWebContents);
             }
         });
     }
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellPreconditionsTest.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellPreconditionsTest.java
index ab3f798..352c1088 100644
--- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellPreconditionsTest.java
+++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellPreconditionsTest.java
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java
index e5f81048..37419f5 100644
--- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java
+++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellUrlTest.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellUrlTest.java
index 5402b64..59ef4cd 100644
--- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellUrlTest.java
+++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellUrlTest.java
@@ -6,24 +6,36 @@
 
 import android.support.test.filters.SmallTest;
 
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 
 /**
  * Example test that just starts the content shell.
  */
-public class ContentShellUrlTest extends ContentShellTestBase {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class ContentShellUrlTest {
+    @Rule
+    public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
+
     // URL used for base tests.
     private static final String URL = "data:text";
 
+    @Test
     @SmallTest
     @Feature({"Main"})
     public void testBaseStartup() throws Exception {
-        ContentShellActivity activity = launchContentShellWithUrl(URL);
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl(URL);
 
         // Make sure the activity was created as expected.
-        assertNotNull(activity);
+        Assert.assertNotNull(activity);
 
         // Make sure that the URL is set as expected.
-        assertEquals(URL, activity.getActiveShell().getContentViewCore().getWebContents().getUrl());
+        Assert.assertEquals(
+                URL, activity.getActiveShell().getContentViewCore().getWebContents().getUrl());
     }
 }
diff --git a/docs/android_debugging_instructions.md b/docs/android_debugging_instructions.md
index 1102fbf..8fd2dd8 100644
--- a/docs/android_debugging_instructions.md
+++ b/docs/android_debugging_instructions.md
@@ -92,6 +92,7 @@
 
 ## Debugging Java
 
+### Eclipse
 *   In Eclipse, make a debug configuration of type "Remote Java Application".
     Choose a "Name" and set "Port" to `8700`.
 
@@ -109,6 +110,12 @@
 
 *   Run your debug configuration, and switch to the Debug perspective.
 
+### Android Studio
+*   Build and install the desired target
+
+*   Click the "Attach debugger to Android process" (see
+[here](https://developer.android.com/studio/debug/index.html) for more)
+
 ## Waiting for Java Debugger on Early Startup
 
 *   To debug early startup, pass `--wait-for-java-debugger` as a command line
diff --git a/docs/android_studio.md b/docs/android_studio.md
index 37521225..900f090 100644
--- a/docs/android_studio.md
+++ b/docs/android_studio.md
@@ -125,6 +125,8 @@
 * Instrumentation tests included as androidTest.
 * Symlinks to existing .so files in jniLibs (doesn't generate them).
 * Editing resource xml files.
+* Java debugging (see
+[here](/docs/android_debugging_instructions.md#Android-Studio))
 
 ### What doesn't work (yet) ([crbug](https://bugs.chromium.org/p/chromium/issues/detail?id=620034))
 
diff --git a/gpu/command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc b/gpu/command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc
index df65efe2..b618ecc 100644
--- a/gpu/command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc
+++ b/gpu/command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc
@@ -195,6 +195,15 @@
     return;
   }
 
+#if defined(OS_ANDROID)
+  // TODO: Figure out why this fails on NVIDIA Shield. crbug.com/700060.
+  std::string renderer(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
+  std::string version(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
+  if (renderer.find("NVIDIA Tegra") != std::string::npos &&
+      version.find("OpenGL ES 3.2 NVIDIA 361.00") != std::string::npos)
+    return;
+#endif
+
   // SAMPLE_ALPHA_TO_ONE is specified to transform alpha values of
   // covered samples to 1.0. In order to detect it, we use non-1.0
   // alpha.
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 0758389f..3cc1487 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -477,12 +477,14 @@
 @property(nonatomic, readonly) NSDictionary* currentHTTPHeaders;
 
 // TODO(crbug.com/684098): Remove these methods and inline their content.
-// Called before finishing a history navigation from |item|.
-- (void)webWillFinishHistoryNavigationFromItem:(web::NavigationItem*)item;
+// Called before finishing a history navigation from a page with the given
+// UserAgentType.
+- (void)webWillFinishHistoryNavigationWithPreviousUserAgentType:
+    (web::UserAgentType)userAgentType;
 // Requires page reconstruction if |item| has a non-NONE UserAgentType and it
 // differs from that of |fromItem|.
 - (void)updateDesktopUserAgentForItem:(web::NavigationItem*)item
-                             fromItem:(web::NavigationItem*)fromItem;
+                previousUserAgentType:(web::UserAgentType)userAgentType;
 
 // Removes the container view from the hierarchy and resets the ivar.
 - (void)resetContainerView;
@@ -602,9 +604,12 @@
 // TODO(crbug.com/661316): Move this method to NavigationManager.
 - (void)goDelta:(int)delta;
 // Loads a new URL if the current entry is not from a pushState() navigation.
-// |item| is the NavigationItem that was the current entry prior to the
-// navigation.
-- (void)finishHistoryNavigationFromItem:(web::NavigationItem*)item;
+// |fromURL| is the URL of the previous NavigationItem, |fromUserAgentType| is
+// that item's UserAgentType, and |sameDocument| is YES if the navigation is
+// between two pages with the same document.
+- (void)finishHistoryNavigationFromURL:(const GURL&)fromURL
+                         userAgentType:(web::UserAgentType)fromUserAgentType
+                          sameDocument:(BOOL)sameDocument;
 // Informs the native controller if web usage is allowed or not.
 - (void)setNativeControllerWebUsageEnabled:(BOOL)webUsageEnabled;
 // Called when web controller receives a new message from the web page.
@@ -716,9 +721,8 @@
 // Compares the two URLs being navigated between during a history navigation to
 // determine if a # needs to be appended to the URL of |toItem| to trigger a
 // hashchange event. If so, also saves the modified URL into |toItem|.
-- (GURL)URLForHistoryNavigationFromItem:(web::NavigationItem*)fromItem
-                                 toItem:(web::NavigationItem*)toItem;
-
+- (GURL)URLForHistoryNavigationToItem:(web::NavigationItem*)toItem
+                          previousURL:(const GURL&)previousURL;
 // Finds all the scrollviews in the view hierarchy and makes sure they do not
 // interfere with scroll to top when tapping the statusbar.
 - (void)optOutScrollsToTopForSubviews;
@@ -1405,8 +1409,8 @@
          [list.backList indexOfObject:item] != NSNotFound;
 }
 
-- (GURL)URLForHistoryNavigationFromItem:(web::NavigationItem*)fromItem
-                                 toItem:(web::NavigationItem*)toItem {
+- (GURL)URLForHistoryNavigationToItem:(web::NavigationItem*)toItem
+                          previousURL:(const GURL&)previousURL {
   // If navigating with native API, i.e. using a back forward list item,
   // hashchange events will be triggered automatically, so no URL tampering is
   // required.
@@ -1416,26 +1420,25 @@
     return toItem->GetURL();
   }
 
-  const GURL& startURL = fromItem->GetURL();
-  const GURL& endURL = toItem->GetURL();
+  const GURL& URL = toItem->GetURL();
 
   // Check the state of the fragments on both URLs (aka, is there a '#' in the
   // url or not).
-  if (!startURL.has_ref() || endURL.has_ref()) {
-    return endURL;
+  if (!previousURL.has_ref() || URL.has_ref()) {
+    return URL;
   }
 
   // startURL contains a fragment and endURL doesn't. Remove the fragment from
   // startURL and compare the resulting string to endURL. If they are equal, add
   // # to endURL to cause a hashchange event.
-  GURL hashless = web::GURLByRemovingRefFromGURL(startURL);
+  GURL hashless = web::GURLByRemovingRefFromGURL(previousURL);
 
-  if (hashless != endURL)
-    return endURL;
+  if (hashless != URL)
+    return URL;
 
   url::StringPieceReplacements<std::string> emptyRef;
   emptyRef.SetRefStr("");
-  GURL newEndURL = endURL.ReplaceComponents(emptyRef);
+  GURL newEndURL = URL.ReplaceComponents(emptyRef);
   toItem->SetURL(newEndURL);
   return newEndURL;
 }
@@ -2116,19 +2119,25 @@
 
   if (!_webStateImpl->IsShowingWebInterstitial())
     [self recordStateInHistory];
-  web::NavigationItem* fromItem = sessionController.currentItem;
+
+  web::NavigationItem* previousItem = sessionController.currentItem;
+  GURL previousURL = previousItem ? previousItem->GetURL() : GURL::EmptyGURL();
+  web::UserAgentType previousUserAgentType =
+      previousItem ? previousItem->GetUserAgentType()
+                   : web::UserAgentType::NONE;
   web::NavigationItem* toItem = items[index].get();
+  BOOL sameDocumentNavigation =
+      [sessionController isSameDocumentNavigationBetweenItem:previousItem
+                                                     andItem:toItem];
 
   NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
   if (![userDefaults boolForKey:@"PendingIndexNavigationDisabled"]) {
     [self clearTransientContentView];
 
     // Update the user agent before attempting the navigation.
-    [self updateDesktopUserAgentForItem:toItem fromItem:fromItem];
+    [self updateDesktopUserAgentForItem:toItem
+                  previousUserAgentType:previousUserAgentType];
 
-    BOOL sameDocumentNavigation =
-        [sessionController isSameDocumentNavigationBetweenItem:fromItem
-                                                       andItem:toItem];
     if (sameDocumentNavigation) {
       [sessionController goToItemAtIndex:index];
       [self updateHTML5HistoryState];
@@ -2144,8 +2153,11 @@
     }
   } else {
     [sessionController goToItemAtIndex:index];
-    if (fromItem)
-      [self finishHistoryNavigationFromItem:fromItem];
+    if (previousURL.is_valid()) {
+      [self finishHistoryNavigationFromURL:previousURL
+                             userAgentType:previousUserAgentType
+                              sameDocument:sameDocumentNavigation];
+    }
   }
 }
 
@@ -2239,18 +2251,19 @@
   }
 }
 
-- (void)finishHistoryNavigationFromItem:(web::NavigationItem*)item {
-  [self webWillFinishHistoryNavigationFromItem:item];
+- (void)finishHistoryNavigationFromURL:(const GURL&)fromURL
+                         userAgentType:(web::UserAgentType)fromUserAgentType
+                          sameDocument:(BOOL)sameDocument {
+  [self webWillFinishHistoryNavigationWithPreviousUserAgentType:
+            fromUserAgentType];
 
   // Only load the new URL if it has a different document than |fromEntry| to
   // prevent extra page loads from NavigationItems created by hash changes or
   // calls to window.history.pushState().
-  BOOL shouldLoadURL = ![self.sessionController
-      isSameDocumentNavigationBetweenItem:item
-                                  andItem:self.currentNavItem];
   web::NavigationItem* currentItem = self.currentNavItem;
-  GURL endURL = [self URLForHistoryNavigationFromItem:item toItem:currentItem];
-  if (shouldLoadURL) {
+  GURL endURL =
+      [self URLForHistoryNavigationToItem:currentItem previousURL:fromURL];
+  if (!sameDocument) {
     ui::PageTransition transition = ui::PageTransitionFromInt(
         ui::PAGE_TRANSITION_RELOAD | ui::PAGE_TRANSITION_FORWARD_BACK);
 
@@ -2266,7 +2279,7 @@
   // updated after the navigation is committed, as attempting to replace the URL
   // here will result in a JavaScript SecurityError due to the URLs having
   // different origins.
-  if (!shouldLoadURL)
+  if (sameDocument)
     [self updateHTML5HistoryState];
 }
 
@@ -2359,20 +2372,21 @@
   return _passKitDownloader.get();
 }
 
-- (void)webWillFinishHistoryNavigationFromItem:(web::NavigationItem*)item {
-  DCHECK(item);
-  [self updateDesktopUserAgentForItem:self.currentNavItem fromItem:item];
+- (void)webWillFinishHistoryNavigationWithPreviousUserAgentType:
+    (web::UserAgentType)userAgentType {
+  [self updateDesktopUserAgentForItem:self.currentNavItem
+                previousUserAgentType:userAgentType];
   [_delegate webWillFinishHistoryNavigation];
 }
 
 - (void)updateDesktopUserAgentForItem:(web::NavigationItem*)item
-                             fromItem:(web::NavigationItem*)fromItem {
-  if (!item || !fromItem)
+                previousUserAgentType:(web::UserAgentType)userAgentType {
+  if (!item)
     return;
   web::UserAgentType itemUserAgentType = item->GetUserAgentType();
   if (itemUserAgentType == web::UserAgentType::NONE)
     return;
-  if (itemUserAgentType != fromItem->GetUserAgentType())
+  if (itemUserAgentType != userAgentType)
     [self requirePageReconstruction];
 }
 
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 9a6f792..c204bcc 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -50,8 +50,8 @@
 
 @interface CRWWebController (PrivateAPI)
 @property(nonatomic, readwrite) web::PageDisplayState pageDisplayState;
-- (GURL)URLForHistoryNavigationFromItem:(web::NavigationItem*)fromItem
-                                 toItem:(web::NavigationItem*)toItem;
+- (GURL)URLForHistoryNavigationToItem:(web::NavigationItem*)toItem
+                          previousURL:(const GURL&)previousURL;
 @end
 
 // Used to mock CRWWebDelegate methods with C++ params.
@@ -238,27 +238,28 @@
       [urlsWithFragments addObject:[url stringByAppendingString:fragment]];
     }
   }
-  web::NavigationItemImpl fromItem;
+
+  GURL previous_url;
   web::NavigationItemImpl toItem;
 
   // No start fragment: the end url is never changed.
   for (NSString* start in urlsNoFragments) {
     for (NSString* end in urlsWithFragments) {
-      fromItem.SetURL(MAKE_URL(start));
+      previous_url = MAKE_URL(start);
       toItem.SetURL(MAKE_URL(end));
       EXPECT_EQ(MAKE_URL(end),
-                [web_controller() URLForHistoryNavigationFromItem:&fromItem
-                                                           toItem:&toItem]);
+                [web_controller() URLForHistoryNavigationToItem:&toItem
+                                                    previousURL:previous_url]);
     }
   }
   // Both contain fragments: the end url is never changed.
   for (NSString* start in urlsWithFragments) {
     for (NSString* end in urlsWithFragments) {
-      fromItem.SetURL(MAKE_URL(start));
+      previous_url = MAKE_URL(start);
       toItem.SetURL(MAKE_URL(end));
       EXPECT_EQ(MAKE_URL(end),
-                [web_controller() URLForHistoryNavigationFromItem:&fromItem
-                                                           toItem:&toItem]);
+                [web_controller() URLForHistoryNavigationToItem:&toItem
+                                                    previousURL:previous_url]);
     }
   }
   for (unsigned start_index = 0; start_index < [urlsWithFragments count];
@@ -267,21 +268,22 @@
     for (unsigned end_index = 0; end_index < [urlsNoFragments count];
          ++end_index) {
       NSString* end = urlsNoFragments[end_index];
+      previous_url = MAKE_URL(start);
       if (start_index / 2 != end_index) {
         // The URLs have nothing in common, they are left untouched.
-        fromItem.SetURL(MAKE_URL(start));
         toItem.SetURL(MAKE_URL(end));
-        EXPECT_EQ(MAKE_URL(end),
-                  [web_controller() URLForHistoryNavigationFromItem:&fromItem
-                                                             toItem:&toItem]);
+        EXPECT_EQ(
+            MAKE_URL(end),
+            [web_controller() URLForHistoryNavigationToItem:&toItem
+                                                previousURL:previous_url]);
       } else {
         // Start contains a fragment and matches end: An empty fragment is
         // added.
-        fromItem.SetURL(MAKE_URL(start));
         toItem.SetURL(MAKE_URL(end));
-        EXPECT_EQ(MAKE_URL([end stringByAppendingString:@"#"]),
-                  [web_controller() URLForHistoryNavigationFromItem:&fromItem
-                                                             toItem:&toItem]);
+        EXPECT_EQ(
+            MAKE_URL([end stringByAppendingString:@"#"]),
+            [web_controller() URLForHistoryNavigationToItem:&toItem
+                                                previousURL:previous_url]);
       }
     }
   }
diff --git a/media/capture/video/OWNERS b/media/capture/video/OWNERS
index 9b67500..ea5ac3b3 100644
--- a/media/capture/video/OWNERS
+++ b/media/capture/video/OWNERS
@@ -1,5 +1,5 @@
 emircan@chromium.org
-magjed@chromium.org
+chfremer@chromium.org
 mcasas@chromium.org
 tommi@chromium.org
 
diff --git a/mojo/public/interfaces/BUILD.gn b/mojo/public/interfaces/BUILD.gn
index 654145bd..fb11ec2 100644
--- a/mojo/public/interfaces/BUILD.gn
+++ b/mojo/public/interfaces/BUILD.gn
@@ -4,8 +4,6 @@
 
 group("interfaces") {
   deps = [
-    "application",
     "bindings",
-    "network",
   ]
 }
diff --git a/net/BUILD.gn b/net/BUILD.gn
index a6b20ba..091518f 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1199,8 +1199,6 @@
       "quic/core/frames/quic_mtu_discovery_frame.h",
       "quic/core/frames/quic_padding_frame.cc",
       "quic/core/frames/quic_padding_frame.h",
-      "quic/core/frames/quic_path_close_frame.cc",
-      "quic/core/frames/quic_path_close_frame.h",
       "quic/core/frames/quic_ping_frame.h",
       "quic/core/frames/quic_rst_stream_frame.cc",
       "quic/core/frames/quic_rst_stream_frame.h",
diff --git a/net/quic/core/frames/quic_frame.cc b/net/quic/core/frames/quic_frame.cc
index 4e086744..e209b76 100644
--- a/net/quic/core/frames/quic_frame.cc
+++ b/net/quic/core/frames/quic_frame.cc
@@ -43,9 +43,6 @@
 QuicFrame::QuicFrame(QuicBlockedFrame* frame)
     : type(BLOCKED_FRAME), blocked_frame(frame) {}
 
-QuicFrame::QuicFrame(QuicPathCloseFrame* frame)
-    : type(PATH_CLOSE_FRAME), path_close_frame(frame) {}
-
 void DeleteFrames(QuicFrames* frames) {
   for (QuicFrame& frame : *frames) {
     switch (frame.type) {
@@ -78,9 +75,6 @@
       case WINDOW_UPDATE_FRAME:
         delete frame.window_update_frame;
         break;
-      case PATH_CLOSE_FRAME:
-        delete frame.path_close_frame;
-        break;
       case NUM_FRAME_TYPES:
         DCHECK(false) << "Cannot delete type: " << frame.type;
     }
@@ -147,10 +141,6 @@
       os << "type { MTU_DISCOVERY_FRAME } ";
       break;
     }
-    case PATH_CLOSE_FRAME: {
-      os << "type { PATH_CLOSE_FRAME } " << *(frame.path_close_frame);
-      break;
-    }
     default: {
       QUIC_LOG(ERROR) << "Unknown frame type: " << frame.type;
       break;
diff --git a/net/quic/core/frames/quic_frame.h b/net/quic/core/frames/quic_frame.h
index 3ebe1cf..fce45b5 100644
--- a/net/quic/core/frames/quic_frame.h
+++ b/net/quic/core/frames/quic_frame.h
@@ -15,7 +15,6 @@
 #include "net/quic/core/frames/quic_goaway_frame.h"
 #include "net/quic/core/frames/quic_mtu_discovery_frame.h"
 #include "net/quic/core/frames/quic_padding_frame.h"
-#include "net/quic/core/frames/quic_path_close_frame.h"
 #include "net/quic/core/frames/quic_ping_frame.h"
 #include "net/quic/core/frames/quic_rst_stream_frame.h"
 #include "net/quic/core/frames/quic_stop_waiting_frame.h"
@@ -40,7 +39,6 @@
   explicit QuicFrame(QuicGoAwayFrame* frame);
   explicit QuicFrame(QuicWindowUpdateFrame* frame);
   explicit QuicFrame(QuicBlockedFrame* frame);
-  explicit QuicFrame(QuicPathCloseFrame* frame);
 
   QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
                                                       const QuicFrame& frame);
@@ -61,7 +59,6 @@
     QuicGoAwayFrame* goaway_frame;
     QuicWindowUpdateFrame* window_update_frame;
     QuicBlockedFrame* blocked_frame;
-    QuicPathCloseFrame* path_close_frame;
   };
 };
 // QuicFrameType consumes 8 bytes with padding.
diff --git a/net/quic/core/frames/quic_frames_test.cc b/net/quic/core/frames/quic_frames_test.cc
index 82b9667..dbc0d0c 100644
--- a/net/quic/core/frames/quic_frames_test.cc
+++ b/net/quic/core/frames/quic_frames_test.cc
@@ -9,7 +9,6 @@
 #include "net/quic/core/frames/quic_goaway_frame.h"
 #include "net/quic/core/frames/quic_mtu_discovery_frame.h"
 #include "net/quic/core/frames/quic_padding_frame.h"
-#include "net/quic/core/frames/quic_path_close_frame.h"
 #include "net/quic/core/frames/quic_ping_frame.h"
 #include "net/quic/core/frames/quic_rst_stream_frame.h"
 #include "net/quic/core/frames/quic_stop_waiting_frame.h"
@@ -116,14 +115,6 @@
   EXPECT_EQ("{ least_unacked: 2 }\n", stream.str());
 }
 
-TEST(QuicFramesTest, PathCloseFrameToString) {
-  QuicPathCloseFrame frame;
-  frame.path_id = 1;
-  std::ostringstream stream;
-  stream << frame;
-  EXPECT_EQ("{ path_id: 1 }\n", stream.str());
-}
-
 TEST(QuicFramesTest, IsAwaitingPacket) {
   QuicAckFrame ack_frame1;
   ack_frame1.largest_observed = 10u;
diff --git a/net/quic/core/quic_config.cc b/net/quic/core/quic_config.cc
index 3d2415a..1ee9df7 100644
--- a/net/quic/core/quic_config.cc
+++ b/net/quic/core/quic_config.cc
@@ -12,6 +12,7 @@
 #include "net/quic/core/quic_socket_address_coder.h"
 #include "net/quic/core/quic_utils.h"
 #include "net/quic/platform/api/quic_bug_tracker.h"
+#include "net/quic/platform/api/quic_flag_utils.h"
 #include "net/quic/platform/api/quic_logging.h"
 #include "net/quic/platform/api/quic_string_piece.h"
 
@@ -337,11 +338,12 @@
       initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL),
       initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL),
       socket_receive_buffer_(kSRBF, PRESENCE_OPTIONAL),
-      multipath_enabled_(kMPTH, PRESENCE_OPTIONAL),
       connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL),
       alternate_server_address_(kASAD, PRESENCE_OPTIONAL),
       force_hol_blocking_(kFHL2, PRESENCE_OPTIONAL),
-      support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL) {
+      support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL),
+      latched_no_socket_receive_buffer_(
+          FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer) {
   SetDefaults();
 }
 
@@ -543,7 +545,11 @@
 }
 
 void QuicConfig::SetSocketReceiveBufferToSend(uint32_t tcp_receive_window) {
-  socket_receive_buffer_.SetSendValue(tcp_receive_window);
+  if (latched_no_socket_receive_buffer_) {
+    QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_no_socket_receive_buffer, 1, 3);
+  } else {
+    socket_receive_buffer_.SetSendValue(tcp_receive_window);
+  }
 }
 
 bool QuicConfig::HasReceivedSocketReceiveBuffer() const {
@@ -554,15 +560,6 @@
   return socket_receive_buffer_.GetReceivedValue();
 }
 
-void QuicConfig::SetMultipathEnabled(bool multipath_enabled) {
-  uint32_t value = multipath_enabled ? 1 : 0;
-  multipath_enabled_.set(value, value);
-}
-
-bool QuicConfig::MultipathEnabled() const {
-  return multipath_enabled_.GetUint32() > 0;
-}
-
 void QuicConfig::SetDisableConnectionMigration() {
   connection_migration_disabled_.SetSendValue(1);
 }
@@ -641,7 +638,11 @@
   initial_round_trip_time_us_.ToHandshakeMessage(out);
   initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
   initial_session_flow_control_window_bytes_.ToHandshakeMessage(out);
-  socket_receive_buffer_.ToHandshakeMessage(out);
+  if (latched_no_socket_receive_buffer_) {
+    QUIC_FLAG_COUNT_N(gfe2_reloadable_flag_quic_no_socket_receive_buffer, 2, 3);
+  } else {
+    socket_receive_buffer_.ToHandshakeMessage(out);
+  }
   connection_migration_disabled_.ToHandshakeMessage(out);
   connection_options_.ToHandshakeMessage(out);
   alternate_server_address_.ToHandshakeMessage(out);
@@ -688,7 +689,9 @@
     error = initial_session_flow_control_window_bytes_.ProcessPeerHello(
         peer_hello, hello_type, error_details);
   }
-  if (error == QUIC_NO_ERROR) {
+  if (latched_no_socket_receive_buffer_) {
+    QUIC_FLAG_COUNT_N(gfe2_reloadable_flag_quic_no_socket_receive_buffer, 3, 3);
+  } else if (error == QUIC_NO_ERROR) {
     error = socket_receive_buffer_.ProcessPeerHello(peer_hello, hello_type,
                                                     error_details);
   }
diff --git a/net/quic/core/quic_config.h b/net/quic/core/quic_config.h
index 286ba1c..c1d7a89 100644
--- a/net/quic/core/quic_config.h
+++ b/net/quic/core/quic_config.h
@@ -351,10 +351,6 @@
 
   uint32_t ReceivedSocketReceiveBuffer() const;
 
-  void SetMultipathEnabled(bool multipath_enabled);
-
-  bool MultipathEnabled() const;
-
   void SetDisableConnectionMigration();
 
   bool DisableConnectionMigration() const;
@@ -428,9 +424,6 @@
   // TODO(ianswett): Deprecate once QUIC_VERSION_34 is deprecated.
   QuicFixedUint32 socket_receive_buffer_;
 
-  // Whether to support multipath for this connection.
-  QuicNegotiableUint32 multipath_enabled_;
-
   // Whether tell peer not to attempt connection migration.
   QuicFixedUint32 connection_migration_disabled_;
 
@@ -442,6 +435,9 @@
 
   // Whether support HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame.
   QuicFixedUint32 support_max_header_list_size_;
+
+  // Latched copy of FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer
+  bool latched_no_socket_receive_buffer_;
 };
 
 }  // namespace net
diff --git a/net/quic/core/quic_config_test.cc b/net/quic/core/quic_config_test.cc
index 4445e00..06e789d 100644
--- a/net/quic/core/quic_config_test.cc
+++ b/net/quic/core/quic_config_test.cc
@@ -33,7 +33,9 @@
   config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5),
                                 QuicTime::Delta::FromSeconds(2));
   config_.SetMaxStreamsPerConnection(4, 2);
-  config_.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+  if (!FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer) {
+    config_.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+  }
   CryptoHandshakeMessage msg;
   config_.ToHandshakeMessage(&msg);
 
@@ -54,9 +56,11 @@
   EXPECT_EQ(QUIC_NO_ERROR, error);
   EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value);
 
-  error = msg.GetUint32(kSRBF, &value);
-  EXPECT_EQ(QUIC_NO_ERROR, error);
-  EXPECT_EQ(kDefaultSocketReceiveBuffer, value);
+  if (!FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer) {
+    error = msg.GetUint32(kSRBF, &value);
+    EXPECT_EQ(QUIC_NO_ERROR, error);
+    EXPECT_EQ(kDefaultSocketReceiveBuffer, value);
+  }
 }
 
 TEST_F(QuicConfigTest, ProcessClientHello) {
@@ -73,7 +77,9 @@
       2 * kInitialStreamFlowControlWindowForTest);
   client_config.SetInitialSessionFlowControlWindowToSend(
       2 * kInitialSessionFlowControlWindowForTest);
-  client_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+  if (!FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer) {
+    client_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+  }
   client_config.SetForceHolBlocking();
   QuicTagVector copt;
   copt.push_back(kTBBR);
@@ -109,7 +115,10 @@
             2 * kInitialStreamFlowControlWindowForTest);
   EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
             2 * kInitialSessionFlowControlWindowForTest);
-  EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), kDefaultSocketReceiveBuffer);
+  if (!FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer) {
+    EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(),
+              kDefaultSocketReceiveBuffer);
+  }
 }
 
 TEST_F(QuicConfigTest, ProcessServerHello) {
@@ -129,7 +138,9 @@
       2 * kInitialStreamFlowControlWindowForTest);
   server_config.SetInitialSessionFlowControlWindowToSend(
       2 * kInitialSessionFlowControlWindowForTest);
-  server_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+  if (!FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer) {
+    server_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+  }
   server_config.SetAlternateServerAddressToSend(kTestServerAddress);
   CryptoHandshakeMessage msg;
   server_config.ToHandshakeMessage(&msg);
@@ -147,7 +158,10 @@
             2 * kInitialStreamFlowControlWindowForTest);
   EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
             2 * kInitialSessionFlowControlWindowForTest);
-  EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), kDefaultSocketReceiveBuffer);
+  if (!FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer) {
+    EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(),
+              kDefaultSocketReceiveBuffer);
+  }
   EXPECT_TRUE(config_.HasReceivedAlternateServerAddress());
   EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress());
 }
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index 04b0d20f..97e689d 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -259,7 +259,6 @@
       largest_received_packet_size_(0),
       goaway_sent_(false),
       goaway_received_(false),
-      multipath_enabled_(false),
       write_error_occured_(false),
       no_stop_waiting_frames_(false) {
   QUIC_DLOG(INFO) << ENDPOINT
@@ -307,10 +306,6 @@
       idle_timeout_connection_close_behavior_ =
           ConnectionCloseBehavior::SILENT_CLOSE;
     }
-    if (FLAGS_quic_reloadable_flag_quic_enable_multipath &&
-        config.MultipathEnabled()) {
-      multipath_enabled_ = true;
-    }
   } else {
     SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
                        config.max_idle_time_before_crypto_handshake());
@@ -909,16 +904,6 @@
   return connected_;
 }
 
-bool QuicConnection::OnPathCloseFrame(const QuicPathCloseFrame& frame) {
-  DCHECK(connected_);
-  if (debug_visitor_ != nullptr) {
-    debug_visitor_->OnPathCloseFrame(frame);
-  }
-  QUIC_DLOG(INFO) << ENDPOINT
-                  << "PATH_CLOSE_FRAME received for path: " << frame.path_id;
-  return connected_;
-}
-
 void QuicConnection::OnPacketComplete() {
   // Don't do anything if this packet closed the connection.
   if (!connected_) {
@@ -1314,7 +1299,7 @@
 
   // Multipath is not enabled, but a packet with multipath flag on is
   // received.
-  if (!multipath_enabled_ && header.public_header.multipath_flag) {
+  if (header.public_header.multipath_flag) {
     const string error_details =
         "Received a packet with multipath flag but multipath is not enabled.";
     QUIC_BUG << error_details;
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h
index d04d970..e5bf4ca 100644
--- a/net/quic/core/quic_connection.h
+++ b/net/quic/core/quic_connection.h
@@ -229,9 +229,6 @@
   // Called when a BlockedFrame has been parsed.
   virtual void OnBlockedFrame(const QuicBlockedFrame& frame) {}
 
-  // Called when a PathCloseFrame has been parsed.
-  virtual void OnPathCloseFrame(const QuicPathCloseFrame& frame) {}
-
   // Called when a public reset packet has been received.
   virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {}
 
@@ -445,7 +442,6 @@
   bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
-  bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
   void OnPacketComplete() override;
 
   // QuicConnectionCloseDelegateInterface
@@ -1079,9 +1075,6 @@
   // Whether a GoAway has been received.
   bool goaway_received_;
 
-  // If true, multipath is enabled for this connection.
-  bool multipath_enabled_;
-
   // Indicates whether a write error is encountered currently. This is used to
   // avoid infinite write errors.
   bool write_error_occured_;
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc
index b567e4a7..51e9f28f 100644
--- a/net/quic/core/quic_connection_test.cc
+++ b/net/quic/core/quic_connection_test.cc
@@ -929,10 +929,6 @@
     ProcessFramePacket(QuicFrame(frame));
   }
 
-  void ProcessPathClosePacket(QuicPathCloseFrame* frame) {
-    ProcessFramePacket(QuicFrame(frame));
-  }
-
   bool IsMissing(QuicPacketNumber number) {
     return IsAwaitingPacket(*outgoing_ack(), number, 0);
   }
@@ -4847,8 +4843,6 @@
 }
 
 TEST_P(QuicConnectionTest, Pacing) {
-  // static_cast here does not work if using multipath_sent_packet_manager.
-  FLAGS_quic_reloadable_flag_quic_enable_multipath = false;
   TestConnection server(connection_id_, kSelfAddress, helper_.get(),
                         alarm_factory_.get(), writer_.get(),
                         Perspective::IS_SERVER, version());
@@ -4979,32 +4973,6 @@
   EXPECT_FALSE(connection_.connected());
 }
 
-TEST_P(QuicConnectionTest, EnableMultipathNegotiation) {
-  // Test multipath negotiation during crypto handshake. Multipath is enabled
-  // when both endpoints enable multipath.
-  FLAGS_quic_reloadable_flag_quic_enable_multipath = true;
-  EXPECT_TRUE(connection_.connected());
-  EXPECT_FALSE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
-  QuicConfig config;
-  // Enable multipath on server side.
-  config.SetMultipathEnabled(true);
-
-  // Create a handshake message enables multipath.
-  CryptoHandshakeMessage msg;
-  string error_details;
-  QuicConfig client_config;
-  // Enable multipath on client side.
-  client_config.SetMultipathEnabled(true);
-  client_config.ToHandshakeMessage(&msg);
-  const QuicErrorCode error =
-      config.ProcessPeerHello(msg, CLIENT, &error_details);
-  EXPECT_EQ(QUIC_NO_ERROR, error);
-
-  connection_.SetFromConfig(config);
-  EXPECT_TRUE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
-}
-
 TEST_P(QuicConnectionTest, OnPathDegrading) {
   QuicByteCount packet_size;
   const size_t kMinTimeoutsBeforePathDegrading = 2;
diff --git a/net/quic/core/quic_constants.h b/net/quic/core/quic_constants.h
index 8560e90..9cf0e6c 100644
--- a/net/quic/core/quic_constants.h
+++ b/net/quic/core/quic_constants.h
@@ -171,11 +171,6 @@
     ((UINT64_C(1) << kUFloat16MantissaEffectiveBits) - 1)
     << kUFloat16MaxExponent;
 
-// Default path ID.
-const QuicPathId kDefaultPathId = 0;
-// Invalid path ID.
-const QuicPathId kInvalidPathId = 0xff;
-
 // kDiversificationNonceSize is the size, in bytes, of the nonce that a server
 // may set in the packet header to ensure that its INITIAL keys are not
 // duplicated.
diff --git a/net/quic/core/quic_error_codes.cc b/net/quic/core/quic_error_codes.cc
index fa36096..ca87175 100644
--- a/net/quic/core/quic_error_codes.cc
+++ b/net/quic/core/quic_error_codes.cc
@@ -94,6 +94,7 @@
     RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR);
     RETURN_STRING_LITERAL(QUIC_EMPTY_STREAM_FRAME_NO_FIN);
     RETURN_STRING_LITERAL(QUIC_INVALID_HEADERS_STREAM_DATA);
+    RETURN_STRING_LITERAL(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE);
     RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA);
     RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA);
     RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_INVALID_WINDOW);
diff --git a/net/quic/core/quic_error_codes.h b/net/quic/core/quic_error_codes.h
index 05124be..38750a5 100644
--- a/net/quic/core/quic_error_codes.h
+++ b/net/quic/core/quic_error_codes.h
@@ -153,6 +153,9 @@
   QUIC_EMPTY_STREAM_FRAME_NO_FIN = 50,
   // We received invalid data on the headers stream.
   QUIC_INVALID_HEADERS_STREAM_DATA = 56,
+  // Invalid data on the headers stream received because of decompression
+  // failure.
+  QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE = 97,
   // The peer received too much data, violating flow control.
   QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 59,
   // The peer sent too much data, violating flow control.
@@ -273,7 +276,7 @@
   QUIC_TOO_MANY_SESSIONS_ON_SERVER = 96,
 
   // No error. Used as bound while iterating.
-  QUIC_LAST_ERROR = 97,
+  QUIC_LAST_ERROR = 98,
 };
 // QuicErrorCodes is encoded as a single octet on-the-wire.
 static_assert(static_cast<int>(QUIC_LAST_ERROR) <=
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index 65e5be39..25b97cec 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -141,7 +141,7 @@
 
 // When true, ensures the session's flow control window is always at least 1.5x
 // larger than the largest stream flow control window.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_flow_control_invariant, false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_flow_control_invariant, true)
 
 // If greater than zero, mean RTT variation is multiplied by the specified
 // factor and added to the congestion window limit.
@@ -165,3 +165,9 @@
 
 // Allows one self address change.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_one_address_change, false)
+
+// If true, no longer send or process the SRBF value in QuicConfig.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_no_socket_receive_buffer, false)
+
+// If true, multipath bit is not used in public flag.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_remove_multipath_bit, false)
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc
index 977fc2f..bacec50 100644
--- a/net/quic/core/quic_framer.cc
+++ b/net/quic/core/quic_framer.cc
@@ -207,11 +207,6 @@
 }
 
 // static
-size_t QuicFramer::GetPathCloseFrameSize() {
-  return kQuicFrameTypeSize + kQuicPathIdSize;
-}
-
-// static
 size_t QuicFramer::GetStreamIdSize(QuicStreamId stream_id) {
   // Sizes are 1 through 4 bytes.
   for (int i = 1; i <= 4; ++i) {
@@ -398,12 +393,6 @@
           return 0;
         }
         break;
-      case PATH_CLOSE_FRAME:
-        if (!AppendPathCloseFrame(*frame.path_close_frame, &writer)) {
-          QUIC_BUG << "AppendPathCloseFrame failed";
-          return 0;
-        }
-        break;
       default:
         RaiseError(QUIC_INVALID_FRAME_DATA);
         QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
@@ -784,7 +773,9 @@
       (public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0;
 
   if (validate_flags_ && !public_header->version_flag &&
-      public_flags > PACKET_PUBLIC_FLAGS_MAX) {
+      public_flags > (FLAGS_quic_reloadable_flag_quic_remove_multipath_bit
+                          ? PACKET_PUBLIC_FLAGS_MAX_WITHOUT_MULTIPATH_FLAG
+                          : PACKET_PUBLIC_FLAGS_MAX)) {
     set_detailed_error("Illegal public flags value.");
     return false;
   }
@@ -825,7 +816,10 @@
     // If not, this raises an error.
     last_version_tag_ = version_tag;
     QuicVersion version = QuicTagToQuicVersion(version_tag);
-    if (version == quic_version_ && public_flags > PACKET_PUBLIC_FLAGS_MAX) {
+    if (version == quic_version_ &&
+        public_flags > (FLAGS_quic_reloadable_flag_quic_remove_multipath_bit
+                            ? PACKET_PUBLIC_FLAGS_MAX_WITHOUT_MULTIPATH_FLAG
+                            : PACKET_PUBLIC_FLAGS_MAX)) {
       set_detailed_error("Illegal public flags value.");
       return false;
     }
@@ -1113,19 +1107,6 @@
         }
         continue;
       }
-      case PATH_CLOSE_FRAME: {
-        QuicPathCloseFrame path_close_frame;
-        if (!ProcessPathCloseFrame(reader, &path_close_frame)) {
-          return RaiseError(QUIC_INVALID_PATH_CLOSE_DATA);
-        }
-        if (!visitor_->OnPathCloseFrame(path_close_frame)) {
-          QUIC_DVLOG(1) << ENDPOINT
-                        << "Visitor asked to stop further processing.";
-          // Returning true since there was no parsing error.
-          return true;
-        }
-        continue;
-      }
 
       default:
         set_detailed_error("Illegal frame type.");
@@ -1449,16 +1430,6 @@
   return true;
 }
 
-bool QuicFramer::ProcessPathCloseFrame(QuicDataReader* reader,
-                                       QuicPathCloseFrame* frame) {
-  if (!reader->ReadBytes(&frame->path_id, 1)) {
-    set_detailed_error("Unable to read path_id.");
-    return false;
-  }
-
-  return true;
-}
-
 // static
 QuicStringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
     QuicVersion version,
@@ -1699,8 +1670,6 @@
       return GetWindowUpdateFrameSize();
     case BLOCKED_FRAME:
       return GetBlockedFrameSize();
-    case PATH_CLOSE_FRAME:
-      return GetPathCloseFrameSize();
     case PADDING_FRAME:
       DCHECK(false);
       return 0;
@@ -2134,15 +2103,6 @@
   return true;
 }
 
-bool QuicFramer::AppendPathCloseFrame(const QuicPathCloseFrame& frame,
-                                      QuicDataWriter* writer) {
-  uint8_t path_id = static_cast<uint8_t>(frame.path_id);
-  if (!writer->WriteUInt8(path_id)) {
-    return false;
-  }
-  return true;
-}
-
 bool QuicFramer::RaiseError(QuicErrorCode error) {
   QUIC_DLOG(INFO) << ENDPOINT << "Error: " << QuicErrorCodeToString(error)
                   << " detail: " << detailed_error_;
diff --git a/net/quic/core/quic_framer.h b/net/quic/core/quic_framer.h
index 16d4340..2ca8ea1 100644
--- a/net/quic/core/quic_framer.h
+++ b/net/quic/core/quic_framer.h
@@ -134,9 +134,6 @@
   // Called when a BlockedFrame has been parsed.
   virtual bool OnBlockedFrame(const QuicBlockedFrame& frame) = 0;
 
-  // Called when a PathCloseFrame has been parsed.
-  virtual bool OnPathCloseFrame(const QuicPathCloseFrame& frame) = 0;
-
   // Called when a packet has been completely processed.
   virtual void OnPacketComplete() = 0;
 };
@@ -211,8 +208,6 @@
   static size_t GetWindowUpdateFrameSize();
   // Size in bytes of all Blocked frame fields.
   static size_t GetBlockedFrameSize();
-  // Size in bytes of all PathClose frame fields.
-  static size_t GetPathCloseFrameSize();
   // Size in bytes required to serialize the stream id.
   static size_t GetStreamIdSize(QuicStreamId stream_id);
   // Size in bytes required to serialize the stream offset.
@@ -391,7 +386,6 @@
   bool ProcessWindowUpdateFrame(QuicDataReader* reader,
                                 QuicWindowUpdateFrame* frame);
   bool ProcessBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame);
-  bool ProcessPathCloseFrame(QuicDataReader* reader, QuicPathCloseFrame* frame);
 
   bool DecryptPayload(QuicDataReader* encrypted_reader,
                       const QuicPacketHeader& header,
@@ -466,8 +460,6 @@
                                QuicDataWriter* writer);
   bool AppendBlockedFrame(const QuicBlockedFrame& frame,
                           QuicDataWriter* writer);
-  bool AppendPathCloseFrame(const QuicPathCloseFrame& frame,
-                            QuicDataWriter* writer);
 
   bool RaiseError(QuicErrorCode error);
 
diff --git a/net/quic/core/quic_framer_test.cc b/net/quic/core/quic_framer_test.cc
index ea6f06c0..6115ab6 100644
--- a/net/quic/core/quic_framer_test.cc
+++ b/net/quic/core/quic_framer_test.cc
@@ -57,13 +57,6 @@
   return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize;
 }
 
-// Index into the path id offset in the header (if present).
-size_t GetPathIdOffset(QuicConnectionIdLength connection_id_length,
-                       bool include_version) {
-  return kConnectionIdOffset + connection_id_length +
-         (include_version ? kQuicVersionSize : 0);
-}
-
 // Index into the packet number offset in the header.
 size_t GetPacketNumberOffset(QuicConnectionIdLength connection_id_length,
                              bool include_version) {
@@ -75,23 +68,6 @@
   return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version);
 }
 
-// Index into the private flags offset in the data packet header.
-size_t GetPrivateFlagsOffset(QuicConnectionIdLength connection_id_length,
-                             bool include_version) {
-  return GetPacketNumberOffset(connection_id_length, include_version) +
-         PACKET_6BYTE_PACKET_NUMBER;
-}
-
-size_t GetPrivateFlagsOffset(bool include_version) {
-  return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version);
-}
-
-size_t GetPrivateFlagsOffset(bool include_version,
-                             QuicPacketNumberLength packet_number_length) {
-  return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version) +
-         packet_number_length;
-}
-
 // Index into the message tag of the public reset packet.
 // Public resets always have full connection_ids.
 const size_t kPublicResetPacketMessageTagOffset =
@@ -129,7 +105,6 @@
   QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); }
 
   QuicVersion version_;
-  Perspective perspective_;
   QuicPacketNumber packet_number_;
   string associated_data_;
   string plaintext_;
@@ -168,7 +143,6 @@
   // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
   uint32_t cipher_id() const override { return 0xFFFFFFF2; }
   QuicVersion version_;
-  Perspective perspective_;
   QuicPacketNumber packet_number_;
   string associated_data_;
   string ciphertext_;
@@ -288,11 +262,6 @@
     return true;
   }
 
-  bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override {
-    path_close_frame_ = frame;
-    return true;
-  }
-
   // Counters from the visitor_ callbacks.
   int error_count_;
   int version_mismatch_;
@@ -316,7 +285,6 @@
   QuicGoAwayFrame goaway_frame_;
   QuicWindowUpdateFrame window_update_frame_;
   QuicBlockedFrame blocked_frame_;
-  QuicPathCloseFrame path_close_frame_;
   std::vector<std::unique_ptr<string>> stream_data_;
 };
 
@@ -941,7 +909,8 @@
   // clang-format off
   unsigned char packet[] = {
     // public flags: includes nonce flag
-    0x7C,
+    static_cast<unsigned char>(
+        FLAGS_quic_reloadable_flag_quic_remove_multipath_bit ? 0x3C : 0x7C),
     // connection_id
     0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
     // nonce
@@ -971,7 +940,8 @@
   // clang-format off
   unsigned char packet[] = {
     // public flags (8 byte connection_id, version flag and an unknown flag)
-    0x79,
+    static_cast<unsigned char>(
+        FLAGS_quic_reloadable_flag_quic_remove_multipath_bit ? 0x39 : 0x79),
     // connection_id
     0x10, 0x32, 0x54, 0x76,
     0x98, 0xBA, 0xDC, 0xFE,
@@ -3568,7 +3538,7 @@
   QuicVersionVector versions;
   versions.push_back(framer_.version());
   std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
-      42, false, false, false, kTestQuicStreamId, kTestString,
+      42, false, false, kTestQuicStreamId, kTestString,
       PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions));
 
   MockFramerVisitor visitor;
diff --git a/net/quic/core/quic_packet_creator.h b/net/quic/core/quic_packet_creator.h
index a80c3cd..68b70d4 100644
--- a/net/quic/core/quic_packet_creator.h
+++ b/net/quic/core/quic_packet_creator.h
@@ -3,9 +3,7 @@
 // found in the LICENSE file.
 //
 // Accumulates frames for the next packet until more frames no longer fit or
-// it's time to create a packet from them. If multipath enabled, only creates
-// packets on one path at the same time. Currently, next packet number is
-// tracked per-path.
+// it's time to create a packet from them.
 
 #ifndef NET_QUIC_CORE_QUIC_PACKET_CREATOR_H_
 #define NET_QUIC_CORE_QUIC_PACKET_CREATOR_H_
diff --git a/net/quic/core/quic_packets.h b/net/quic/core/quic_packets.h
index 05bd01c..474b121 100644
--- a/net/quic/core/quic_packets.h
+++ b/net/quic/core/quic_packets.h
@@ -64,6 +64,8 @@
   // public flags.
   QuicConnectionId connection_id;
   QuicConnectionIdLength connection_id_length;
+  // TODO(fayang): Remove multipath_flag when deprecating
+  // gfe2_reloadable_flag_quic_remove_multipath_bit.
   bool multipath_flag;
   bool reset_flag;
   bool version_flag;
diff --git a/net/quic/core/quic_server_session_base_test.cc b/net/quic/core/quic_server_session_base_test.cc
index 34c6aff..7673552 100644
--- a/net/quic/core/quic_server_session_base_test.cc
+++ b/net/quic/core/quic_server_session_base_test.cc
@@ -409,8 +409,6 @@
   // and we don't have any other data to write.
 
   // Client has sent kBWRE connection option to trigger bandwidth resumption.
-  // Disable this flag because if connection uses multipath sent packet manager,
-  // static_cast here does not work.
   QuicTagVector copt;
   copt.push_back(kBWRE);
   QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
@@ -613,8 +611,8 @@
   chlo.SetVector(kCOPT, QuicTagVector{kSREJ});
   std::vector<QuicVersion> packet_version_list = {version};
   std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
-      1, true, false, false, 1,
-      chlo.GetSerialized().AsStringPiece().as_string(),
+      1, true, false, 1,
+      string(chlo.GetSerialized().AsStringPiece().as_string()),
       PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
       &packet_version_list));
 
@@ -625,7 +623,7 @@
 
   // Set the current packet
   QuicConnectionPeer::SetCurrentPacket(session_->connection(),
-                                       packet->AsStringPiece());
+                                       packet->AsStringPiece().as_string());
 
   // Yes, this is horrible.  But it's the easiest way to trigger the behavior we
   // need to exercise.
diff --git a/net/quic/core/quic_spdy_session.cc b/net/quic/core/quic_spdy_session.cc
index 4c14b615..61d16c90 100644
--- a/net/quic/core/quic_spdy_session.cc
+++ b/net/quic/core/quic_spdy_session.cc
@@ -124,7 +124,8 @@
     if (session_->OnStreamFrameData(stream_id, data, len)) {
       return;
     }
-    CloseConnection("SPDY DATA frame received.");
+    CloseConnection("SPDY DATA frame received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   void OnStreamEnd(SpdyStreamId stream_id) override {
@@ -133,13 +134,23 @@
   }
 
   void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
-    CloseConnection("SPDY frame padding received.");
+    CloseConnection("SPDY frame padding received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   void OnError(SpdyFramer* framer) override {
-    CloseConnection(QuicStrCat(
-        "SPDY framing error: ",
-        SpdyFramer::SpdyFramerErrorToString(framer->spdy_framer_error())));
+    QuicErrorCode code = QUIC_INVALID_HEADERS_STREAM_DATA;
+    SpdyFramer::SpdyFramerError error = framer->spdy_framer_error();
+    switch (error) {
+      case SpdyFramer::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
+        code = QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
+        break;
+      default:
+        break;
+    }
+    CloseConnection(QuicStrCat("SPDY framing error: ",
+                               SpdyFramer::SpdyFramerErrorToString(error)),
+                    code);
   }
 
   void OnDataFrameHeader(SpdyStreamId stream_id,
@@ -148,16 +159,19 @@
     if (session_->OnDataFrameHeader(stream_id, length, fin)) {
       return;
     }
-    CloseConnection("SPDY DATA frame received.");
+    CloseConnection("SPDY DATA frame received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {
-    CloseConnection("SPDY RST_STREAM frame received.");
+    CloseConnection("SPDY RST_STREAM frame received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   void OnSetting(SpdySettingsIds id, uint32_t value) override {
     if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) {
-      CloseConnection("SPDY SETTINGS frame received.");
+      CloseConnection("SPDY SETTINGS frame received.",
+                      QUIC_INVALID_HEADERS_STREAM_DATA);
       return;
     }
     switch (id) {
@@ -170,14 +184,16 @@
           // See rfc7540, Section 6.5.2.
           if (value > 1) {
             CloseConnection(
-                QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value));
+                QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value),
+                QUIC_INVALID_HEADERS_STREAM_DATA);
             return;
           }
           session_->UpdateEnableServerPush(value > 0);
           break;
         } else {
           CloseConnection(
-              QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id));
+              QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
+              QUIC_INVALID_HEADERS_STREAM_DATA);
         }
         break;
       // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
@@ -188,29 +204,34 @@
         }
       default:
         CloseConnection(
-            QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id));
+            QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
+            QUIC_INVALID_HEADERS_STREAM_DATA);
     }
   }
 
   void OnSettingsAck() override {
     if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) {
-      CloseConnection("SPDY SETTINGS frame received.");
+      CloseConnection("SPDY SETTINGS frame received.",
+                      QUIC_INVALID_HEADERS_STREAM_DATA);
     }
   }
 
   void OnSettingsEnd() override {
     if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) {
-      CloseConnection("SPDY SETTINGS frame received.");
+      CloseConnection("SPDY SETTINGS frame received.",
+                      QUIC_INVALID_HEADERS_STREAM_DATA);
     }
   }
 
   void OnPing(SpdyPingId unique_id, bool is_ack) override {
-    CloseConnection("SPDY PING frame received.");
+    CloseConnection("SPDY PING frame received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   void OnGoAway(SpdyStreamId last_accepted_stream_id,
                 SpdyErrorCode error_code) override {
-    CloseConnection("SPDY GOAWAY frame received.");
+    CloseConnection("SPDY GOAWAY frame received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   void OnHeaders(SpdyStreamId stream_id,
@@ -232,14 +253,16 @@
   }
 
   void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
-    CloseConnection("SPDY WINDOW_UPDATE frame received.");
+    CloseConnection("SPDY WINDOW_UPDATE frame received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   void OnPushPromise(SpdyStreamId stream_id,
                      SpdyStreamId promised_stream_id,
                      bool end) override {
     if (!session_->supports_push_promise()) {
-      CloseConnection("PUSH_PROMISE not supported.");
+      CloseConnection("PUSH_PROMISE not supported.",
+                      QUIC_INVALID_HEADERS_STREAM_DATA);
       return;
     }
     if (!session_->IsConnected()) {
@@ -254,11 +277,13 @@
                   SpdyStreamId parent_id,
                   int weight,
                   bool exclusive) override {
-    CloseConnection("SPDY PRIORITY frame received.");
+    CloseConnection("SPDY PRIORITY frame received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
   }
 
   bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override {
-    CloseConnection("Unknown frame type received.");
+    CloseConnection("Unknown frame type received.",
+                    QUIC_INVALID_HEADERS_STREAM_DATA);
     return false;
   }
 
@@ -290,10 +315,9 @@
   }
 
  private:
-  void CloseConnection(const string& details) {
+  void CloseConnection(const string& details, QuicErrorCode code) {
     if (session_->IsConnected()) {
-      session_->CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
-                                           details);
+      session_->CloseConnectionWithDetails(code, details);
     }
   }
 
diff --git a/net/quic/core/quic_spdy_stream.cc b/net/quic/core/quic_spdy_stream.cc
index 5d98d186..cbbd96d 100644
--- a/net/quic/core/quic_spdy_stream.cc
+++ b/net/quic/core/quic_spdy_stream.cc
@@ -45,17 +45,6 @@
   }
 }
 
-void QuicSpdyStream::StopReading() {
-  if (!fin_received() && !rst_received() && write_side_closed() &&
-      !rst_sent()) {
-    DCHECK(fin_sent());
-    // Tell the peer to stop sending further data.
-    QUIC_DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
-    Reset(QUIC_STREAM_NO_ERROR);
-  }
-  QuicStream::StopReading();
-}
-
 size_t QuicSpdyStream::WriteHeaders(
     SpdyHeaderBlock header_block,
     bool fin,
diff --git a/net/quic/core/quic_spdy_stream.h b/net/quic/core/quic_spdy_stream.h
index d92d3f9..247af4d 100644
--- a/net/quic/core/quic_spdy_stream.h
+++ b/net/quic/core/quic_spdy_stream.h
@@ -66,8 +66,6 @@
   QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session);
   ~QuicSpdyStream() override;
 
-  void StopReading() override;
-
   // QuicStream implementation
   void OnClose() override;
 
diff --git a/net/quic/core/quic_transmission_info.h b/net/quic/core/quic_transmission_info.h
index 6529f4e..1dee816 100644
--- a/net/quic/core/quic_transmission_info.h
+++ b/net/quic/core/quic_transmission_info.h
@@ -58,6 +58,11 @@
   // The largest_acked in the ack frame, if the packet contains an ack.
   QuicPacketNumber largest_acked;
 };
+// TODO(ianswett): Add static_assert when size of this struct is reduced below
+// 64 bytes.
+// NOTE(vlovich): Existing static_assert removed because padding differences on
+// 64-bit iOS resulted in an 88-byte struct that is greater than the 84-byte
+// limit on other platforms.  Removing per ianswett's request.
 
 }  // namespace net
 
diff --git a/net/quic/core/quic_types.h b/net/quic/core/quic_types.h
index 30fefd2..fc665f3f 100644
--- a/net/quic/core/quic_types.h
+++ b/net/quic/core/quic_types.h
@@ -16,7 +16,6 @@
 
 namespace net {
 
-typedef uint8_t QuicPathId;
 typedef uint16_t QuicPacketLength;
 typedef uint32_t QuicHeaderId;
 typedef uint32_t QuicStreamId;
@@ -122,7 +121,6 @@
   BLOCKED_FRAME = 5,
   STOP_WAITING_FRAME = 6,
   PING_FRAME = 7,
-  PATH_CLOSE_FRAME = 8,
 
   // STREAM and ACK frames are special frames. They are encoded differently on
   // the wire and their values do not need to be stable.
@@ -184,6 +182,8 @@
   PACKET_PUBLIC_FLAGS_4BYTE_PACKET = PACKET_FLAGS_4BYTE_PACKET << 4,
   PACKET_PUBLIC_FLAGS_6BYTE_PACKET = PACKET_FLAGS_6BYTE_PACKET << 4,
 
+  // TODO(fayang): Remove PACKET_PUBLIC_FLAGS_MULTIPATH when deprecating
+  // gfe2_reloadable_flag_quic_remove_multipath_bit.
   // Bit 6: Does the packet header contain a path id?
   PACKET_PUBLIC_FLAGS_MULTIPATH = 1 << 6,
 
@@ -192,8 +192,14 @@
   // Bit 7: indicates the presence of a second flags byte.
   PACKET_PUBLIC_FLAGS_TWO_OR_MORE_BYTES = 1 << 7,
 
+  // TODO(fayang): Remove PACKET_PUBLIC_FLAGS_MAX and rename
+  // PACKET_PUBLIC_FLAGS_MAX_WITHOUT_MULTIPATH_FLAG when deprecating
+  // gfe2_reloadable_flag_quic_remove_multipath_bit.
   // All bits set (bit 7 is not currently used): 01111111
   PACKET_PUBLIC_FLAGS_MAX = (1 << 7) - 1,
+
+  // All bits set (bits 6 and 7 are not currently used): 00111111
+  PACKET_PUBLIC_FLAGS_MAX_WITHOUT_MULTIPATH_FLAG = (1 << 6) - 1,
 };
 
 // The private flags are specified in one byte.
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 344013c..d96b9914 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -104,11 +104,6 @@
 }
 
 // static
-bool QuicConnectionPeer::IsMultipathEnabled(QuicConnection* connection) {
-  return connection->multipath_enabled_;
-}
-
-// static
 void QuicConnectionPeer::SwapCrypters(QuicConnection* connection,
                                       QuicFramer* framer) {
   QuicFramerPeer::SwapCrypters(framer, &connection->framer_);
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index bea9972..81f4d1d 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -66,8 +66,6 @@
 
   static bool IsSilentCloseEnabled(QuicConnection* connection);
 
-  static bool IsMultipathEnabled(QuicConnection* connection);
-
   static void SwapCrypters(QuicConnection* connection, QuicFramer* framer);
 
   static void SetCurrentPacket(QuicConnection* connection,
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index a6c1a91..adf9df17a 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -221,10 +221,6 @@
   return true;
 }
 
-bool NoOpFramerVisitor::OnPathCloseFrame(const QuicPathCloseFrame& frame) {
-  return true;
-}
-
 MockQuicConnectionVisitor::MockQuicConnectionVisitor() {}
 
 MockQuicConnectionVisitor::~MockQuicConnectionVisitor() {}
@@ -554,48 +550,44 @@
 
 QuicEncryptedPacket* ConstructEncryptedPacket(QuicConnectionId connection_id,
                                               bool version_flag,
-                                              bool multipath_flag,
                                               bool reset_flag,
                                               QuicPacketNumber packet_number,
                                               const string& data) {
   return ConstructEncryptedPacket(
-      connection_id, version_flag, multipath_flag, reset_flag, packet_number,
-      data, PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER);
+      connection_id, version_flag, reset_flag, packet_number, data,
+      PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER);
 }
 
 QuicEncryptedPacket* ConstructEncryptedPacket(
     QuicConnectionId connection_id,
     bool version_flag,
-    bool multipath_flag,
     bool reset_flag,
     QuicPacketNumber packet_number,
     const string& data,
     QuicConnectionIdLength connection_id_length,
     QuicPacketNumberLength packet_number_length) {
-  return ConstructEncryptedPacket(
-      connection_id, version_flag, multipath_flag, reset_flag, packet_number,
-      data, connection_id_length, packet_number_length, nullptr);
+  return ConstructEncryptedPacket(connection_id, version_flag, reset_flag,
+                                  packet_number, data, connection_id_length,
+                                  packet_number_length, nullptr);
 }
 
 QuicEncryptedPacket* ConstructEncryptedPacket(
     QuicConnectionId connection_id,
     bool version_flag,
-    bool multipath_flag,
     bool reset_flag,
     QuicPacketNumber packet_number,
     const string& data,
     QuicConnectionIdLength connection_id_length,
     QuicPacketNumberLength packet_number_length,
     QuicVersionVector* versions) {
-  return ConstructEncryptedPacket(connection_id, version_flag, multipath_flag,
-                                  reset_flag, packet_number, data,
-                                  connection_id_length, packet_number_length,
-                                  versions, Perspective::IS_CLIENT);
+  return ConstructEncryptedPacket(connection_id, version_flag, reset_flag,
+                                  packet_number, data, connection_id_length,
+                                  packet_number_length, versions,
+                                  Perspective::IS_CLIENT);
 }
 QuicEncryptedPacket* ConstructEncryptedPacket(
     QuicConnectionId connection_id,
     bool version_flag,
-    bool multipath_flag,
     bool reset_flag,
     QuicPacketNumber packet_number,
     const string& data,
@@ -607,7 +599,7 @@
   header.public_header.connection_id = connection_id;
   header.public_header.connection_id_length = connection_id_length;
   header.public_header.version_flag = version_flag;
-  header.public_header.multipath_flag = multipath_flag;
+  header.public_header.multipath_flag = false;
   header.public_header.reset_flag = reset_flag;
   header.public_header.packet_number_length = packet_number_length;
   header.packet_number = packet_number;
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 5f153a2..a53d2fb 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -70,7 +70,6 @@
 QuicEncryptedPacket* ConstructEncryptedPacket(
     QuicConnectionId connection_id,
     bool version_flag,
-    bool multipath_flag,
     bool reset_flag,
     QuicPacketNumber packet_number,
     const std::string& data,
@@ -86,7 +85,6 @@
 QuicEncryptedPacket* ConstructEncryptedPacket(
     QuicConnectionId connection_id,
     bool version_flag,
-    bool multipath_flag,
     bool reset_flag,
     QuicPacketNumber packet_number,
     const std::string& data,
@@ -98,7 +96,6 @@
 QuicEncryptedPacket* ConstructEncryptedPacket(
     QuicConnectionId connection_id,
     bool version_flag,
-    bool multipath_flag,
     bool reset_flag,
     QuicPacketNumber packet_number,
     const std::string& data,
@@ -110,7 +107,6 @@
 // |versions| == nullptr.
 QuicEncryptedPacket* ConstructEncryptedPacket(QuicConnectionId connection_id,
                                               bool version_flag,
-                                              bool multipath_flag,
                                               bool reset_flag,
                                               QuicPacketNumber packet_number,
                                               const std::string& data);
@@ -247,7 +243,6 @@
   MOCK_METHOD1(OnGoAwayFrame, bool(const QuicGoAwayFrame& frame));
   MOCK_METHOD1(OnWindowUpdateFrame, bool(const QuicWindowUpdateFrame& frame));
   MOCK_METHOD1(OnBlockedFrame, bool(const QuicBlockedFrame& frame));
-  MOCK_METHOD1(OnPathCloseFrame, bool(const QuicPathCloseFrame& frame));
   MOCK_METHOD0(OnPacketComplete, void());
 
  private:
@@ -279,7 +274,6 @@
   bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
-  bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
   void OnPacketComplete() override {}
 
  private:
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index 18b449cf..734b1dc 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -106,11 +106,6 @@
     return true;
   }
 
-  bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override {
-    path_close_frames_.push_back(frame);
-    return true;
-  }
-
   void OnPacketComplete() override {}
 
   const QuicPacketHeader& header() const { return header_; }
@@ -151,7 +146,6 @@
   std::vector<QuicConnectionCloseFrame> connection_close_frames_;
   std::vector<QuicWindowUpdateFrame> window_update_frames_;
   std::vector<QuicBlockedFrame> blocked_frames_;
-  std::vector<QuicPathCloseFrame> path_close_frames_;
   std::vector<std::unique_ptr<string>> stream_data_;
 
   DISALLOW_COPY_AND_ASSIGN(SimpleFramerVisitor);
diff --git a/net/tools/quic/chlo_extractor.cc b/net/tools/quic/chlo_extractor.cc
index 56a40573..0235f72 100644
--- a/net/tools/quic/chlo_extractor.cc
+++ b/net/tools/quic/chlo_extractor.cc
@@ -45,7 +45,6 @@
   bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
-  bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
   bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
   void OnPacketComplete() override {}
 
@@ -136,10 +135,6 @@
   return true;
 }
 
-bool ChloFramerVisitor::OnPathCloseFrame(const QuicPathCloseFrame& frame) {
-  return true;
-}
-
 bool ChloFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& frame) {
   return true;
 }
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 9a7ca65..4b4b0c5 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -1322,9 +1322,6 @@
 
 TEST_P(EndToEndTest, NegotiateCongestionControl) {
   FLAGS_quic_reloadable_flag_quic_allow_new_bbr = true;
-  // Disable this flag because if connection uses multipath sent packet manager,
-  // static_cast here does not work.
-  FLAGS_quic_reloadable_flag_quic_enable_multipath = false;
   ASSERT_TRUE(Initialize());
   EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
 
@@ -2205,7 +2202,7 @@
 
   std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
       client_->client()->session()->connection()->connection_id(), false, false,
-      false, 1, "At least 20 characters.", PACKET_8BYTE_CONNECTION_ID,
+      1, "At least 20 characters.", PACKET_8BYTE_CONNECTION_ID,
       PACKET_6BYTE_PACKET_NUMBER));
   // Damage the encrypted data.
   string damaged_packet(packet->data(), packet->length());
@@ -3009,6 +3006,21 @@
   EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
 }
 
+TEST_P(EndToEndTest, WayTooLongRequestHeaders) {
+  ASSERT_TRUE(Initialize());
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  headers[":path"] = "/foo";
+  headers[":scheme"] = "https";
+  headers[":authority"] = server_hostname_;
+  headers["key"] = string(64 * 1024, 'a');
+
+  client_->SendMessage(headers, "");
+  client_->WaitForResponse();
+  EXPECT_EQ(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE,
+            client_->connection_error());
+}
+
 class EndToEndBufferedPacketsTest : public EndToEndTest {
  public:
   void CreateClientWithWriter() override {
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 1ed9bd9b..1909450c 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -267,9 +267,8 @@
   // Verify that a non-decryptable packet doesn't close the connection.
   QuicConnectionId connection_id = session_->connection()->connection_id();
   std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
-      connection_id, false, false, false, 100, "data",
-      PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, nullptr,
-      Perspective::IS_SERVER));
+      connection_id, false, false, 100, "data", PACKET_8BYTE_CONNECTION_ID,
+      PACKET_6BYTE_PACKET_NUMBER, nullptr, Perspective::IS_SERVER));
   std::unique_ptr<QuicReceivedPacket> received(
       ConstructReceivedPacket(*packet, QuicTime::Zero()));
   // Change the last byte of the encrypted data.
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 801e1f2..303a597a 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -626,11 +626,6 @@
   return false;
 }
 
-bool QuicDispatcher::OnPathCloseFrame(const QuicPathCloseFrame& frame) {
-  DCHECK(false);
-  return false;
-}
-
 void QuicDispatcher::OnPacketComplete() {
   DCHECK(false);
 }
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 266e3e4..50d754f 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -141,7 +141,6 @@
   bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
-  bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
   void OnPacketComplete() override;
 
   // QuicBufferedPacketStore::VisitorInterface implementation.
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 6fcc2db..621890ab 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -208,11 +208,9 @@
   void ProcessPacket(QuicSocketAddress client_address,
                      QuicConnectionId connection_id,
                      bool has_version_flag,
-                     bool has_multipath_flag,
                      const string& data) {
-    ProcessPacket(client_address, connection_id, has_version_flag,
-                  has_multipath_flag, data, PACKET_8BYTE_CONNECTION_ID,
-                  PACKET_6BYTE_PACKET_NUMBER);
+    ProcessPacket(client_address, connection_id, has_version_flag, data,
+                  PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER);
   }
 
   // Process a packet with a default path id, and packet number 1,
@@ -220,20 +218,17 @@
   void ProcessPacket(QuicSocketAddress client_address,
                      QuicConnectionId connection_id,
                      bool has_version_flag,
-                     bool has_multipath_flag,
                      const string& data,
                      QuicConnectionIdLength connection_id_length,
                      QuicPacketNumberLength packet_number_length) {
-    ProcessPacket(client_address, connection_id, has_version_flag,
-                  has_multipath_flag, data, connection_id_length,
-                  packet_number_length, 1);
+    ProcessPacket(client_address, connection_id, has_version_flag, data,
+                  connection_id_length, packet_number_length, 1);
   }
 
   // Process a packet using the first supported version.
   void ProcessPacket(QuicSocketAddress client_address,
                      QuicConnectionId connection_id,
                      bool has_version_flag,
-                     bool has_multipath_flag,
                      const string& data,
                      QuicConnectionIdLength connection_id_length,
                      QuicPacketNumberLength packet_number_length,
@@ -254,7 +249,7 @@
                      QuicPacketNumber packet_number) {
     QuicVersionVector versions(SupportedVersions(version));
     std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
-        connection_id, has_version_flag, false, false, packet_number, data,
+        connection_id, has_version_flag, false, packet_number, data,
         connection_id_length, packet_number_length, &versions));
     std::unique_ptr<QuicReceivedPacket> received_packet(
         ConstructReceivedPacket(*packet, helper_.GetClock()->Now()));
@@ -277,7 +272,8 @@
                       const QuicEncryptedPacket& packet) {
     EXPECT_EQ(data_connection_map_[conn_id].front().length(),
               packet.AsStringPiece().length());
-    EXPECT_EQ(data_connection_map_[conn_id].front(), packet.AsStringPiece());
+    EXPECT_EQ(data_connection_map_[conn_id].front(),
+              packet.AsStringPiece().as_string());
     data_connection_map_[conn_id].pop_front();
   }
 
@@ -348,7 +344,7 @@
               ProcessUdpPacket(_, _, _))
       .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
           &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
-  ProcessPacket(client_address, 1, true, false, SerializeCHLO());
+  ProcessPacket(client_address, 1, true, SerializeCHLO());
   EXPECT_EQ(client_address, dispatcher_->current_client_address());
   EXPECT_EQ(server_address_, dispatcher_->current_server_address());
 
@@ -361,14 +357,14 @@
               ProcessUdpPacket(_, _, _))
       .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
           &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 2))));
-  ProcessPacket(client_address, 2, true, false, SerializeCHLO());
+  ProcessPacket(client_address, 2, true, SerializeCHLO());
 
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
               ProcessUdpPacket(_, _, _))
       .Times(1)
       .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
           &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
-  ProcessPacket(client_address, 1, false, false, "data");
+  ProcessPacket(client_address, 1, false, "data");
 }
 
 TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
@@ -394,7 +390,7 @@
       .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
           &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
 
-  ProcessPacket(client_address, 1, true, false, SerializeCHLO());
+  ProcessPacket(client_address, 1, true, SerializeCHLO());
 
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
               CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
@@ -418,7 +414,7 @@
       .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
           &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
 
-  ProcessPacket(client_address, connection_id, true, false, SerializeCHLO());
+  ProcessPacket(client_address, connection_id, true, SerializeCHLO());
 
   // Close the connection by sending public reset packet.
   QuicPublicResetPacket packet;
@@ -452,7 +448,7 @@
       .Times(1);
   EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(0);
-  ProcessPacket(client_address, connection_id, true, false, "data");
+  ProcessPacket(client_address, connection_id, true, "data");
 }
 
 TEST_F(QuicDispatcherTest, NoVersionPacketToTimeWaitListManager) {
@@ -468,7 +464,7 @@
       .Times(1);
   EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(1);
-  ProcessPacket(client_address, connection_id, false, false, SerializeCHLO());
+  ProcessPacket(client_address, connection_id, false, SerializeCHLO());
 }
 
 TEST_F(QuicDispatcherTest, ProcessPacketWithZeroPort) {
@@ -482,7 +478,7 @@
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(0);
-  ProcessPacket(client_address, 1, true, false, SerializeCHLO());
+  ProcessPacket(client_address, 1, true, SerializeCHLO());
 }
 
 TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) {
@@ -501,7 +497,7 @@
           &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
   // A packet whose packet number is the largest that is allowed to start a
   // connection.
-  ProcessPacket(client_address, connection_id, true, false, SerializeCHLO(),
+  ProcessPacket(client_address, connection_id, true, SerializeCHLO(),
                 PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
                 QuicDispatcher::kMaxReasonableInitialPacketNumber);
   EXPECT_EQ(client_address, dispatcher_->current_client_address());
@@ -523,7 +519,7 @@
       .Times(1);
   // A packet whose packet number is one to large to be allowed to start a
   // connection.
-  ProcessPacket(client_address, connection_id, true, false, SerializeCHLO(),
+  ProcessPacket(client_address, connection_id, true, SerializeCHLO(),
                 PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
                 QuicDispatcher::kMaxReasonableInitialPacketNumber + 1);
 }
@@ -762,7 +758,7 @@
           Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                base::Unretained(this), connection_id))));
   // Process the first packet for the connection.
-  ProcessPacket(client_address, connection_id, true, false, SerializeCHLO());
+  ProcessPacket(client_address, connection_id, true, SerializeCHLO());
   if (ExpectStatelessReject()) {
     // If this is a stateless reject, the crypto stream will close the
     // connection.
@@ -789,7 +785,7 @@
             Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                  base::Unretained(this), connection_id))));
   }
-  ProcessPacket(client_address, connection_id, true, false, "data");
+  ProcessPacket(client_address, connection_id, true, "data");
 }
 
 TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) {
@@ -822,7 +818,7 @@
                                      {"VER\0", "Q025"}},
                                     kClientHelloMinimumSize);
 
-  ProcessPacket(client_address, connection_id, true, false,
+  ProcessPacket(client_address, connection_id, true,
                 client_hello.GetSerialized().AsStringPiece().as_string());
 
   if (GetParam().enable_stateless_rejects_via_flag) {
@@ -838,8 +834,7 @@
   const QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   const QuicConnectionId connection_id = 1;
 
-    ProcessPacket(client_address, connection_id, true, false,
-                  "NOT DATA FOR A CHLO");
+  ProcessPacket(client_address, connection_id, true, "NOT DATA FOR A CHLO");
 
   // Process the first packet for the connection.
     CryptoHandshakeMessage client_hello =
@@ -867,7 +862,7 @@
             Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                  base::Unretained(this), connection_id))))
         .RetiresOnSaturation();
-    ProcessPacket(client_address, connection_id, true, false,
+    ProcessPacket(client_address, connection_id, true,
                   client_hello.GetSerialized().AsStringPiece().as_string());
     EXPECT_FALSE(
         time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
@@ -891,7 +886,7 @@
       .Times(0);
   EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(0);
-  ProcessPacket(client_address, connection_id, true, false, "data",
+  ProcessPacket(client_address, connection_id, true, "data",
                 PACKET_0BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER);
 }
 
@@ -935,7 +930,7 @@
                 ProcessUdpPacket(_, _, _))
         .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
             &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
-    ProcessPacket(client_address, 1, true, false, SerializeCHLO());
+    ProcessPacket(client_address, 1, true, SerializeCHLO());
 
     EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
         .WillOnce(testing::Return(CreateSession(
@@ -946,7 +941,7 @@
                 ProcessUdpPacket(_, _, _))
         .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
             &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 2))));
-    ProcessPacket(client_address, 2, true, false, SerializeCHLO());
+    ProcessPacket(client_address, 2, true, SerializeCHLO());
 
     blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(dispatcher_.get());
   }
@@ -1195,7 +1190,7 @@
   EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id))
       .Times(1);
   for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) {
-    ProcessPacket(client_address, conn_id, true, false,
+    ProcessPacket(client_address, conn_id, true,
                   QuicStrCat("data packet ", i + 1), PACKET_8BYTE_CONNECTION_ID,
                   PACKET_6BYTE_PACKET_NUMBER, /*packet_number=*/i + 1);
   }
@@ -1220,7 +1215,7 @@
       .WillRepeatedly(testing::WithArg<2>(
           Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                base::Unretained(this), conn_id))));
-  ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
 }
 
 TEST_P(BufferedPacketStoreTest,
@@ -1248,7 +1243,7 @@
                     ShouldCreateOrBufferPacketForConnection(conn_id));
       }
     }
-    ProcessPacket(client_address, conn_id, true, false,
+    ProcessPacket(client_address, conn_id, true,
                   QuicStrCat("data packet on connection ", i),
                   PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
                   /*packet_number=*/2);
@@ -1299,7 +1294,7 @@
         .WillRepeatedly(testing::WithArg<2>(
             Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                  base::Unretained(this), conn_id))));
-    ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+    ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
   }
 }
 
@@ -1313,7 +1308,7 @@
           dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
           QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
-  ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
 }
 
 // Tests that a retransmitted CHLO arrives after a connection for the
@@ -1323,9 +1318,9 @@
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
   QuicConnectionId conn_id = 1;
-  ProcessPacket(client_address, conn_id, true, false,
-                QuicStrCat("data packet ", 2), PACKET_8BYTE_CONNECTION_ID,
-                PACKET_6BYTE_PACKET_NUMBER, /*packet_number=*/2);
+  ProcessPacket(client_address, conn_id, true, QuicStrCat("data packet ", 2),
+                PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+                /*packet_number=*/2);
 
   // When CHLO arrives, a new session should be created, and all packets
   // buffered should be delivered to the session.
@@ -1341,9 +1336,9 @@
       .WillRepeatedly(testing::WithArg<2>(
           Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                base::Unretained(this), conn_id))));
-  ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
 
-  ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
 }
 
 // Tests that expiration of a connection add connection id to time wait list.
@@ -1357,9 +1352,9 @@
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
   QuicConnectionId conn_id = 1;
-  ProcessPacket(client_address, conn_id, true, false,
-                QuicStrCat("data packet ", 2), PACKET_8BYTE_CONNECTION_ID,
-                PACKET_6BYTE_PACKET_NUMBER, /*packet_number=*/2);
+  ProcessPacket(client_address, conn_id, true, QuicStrCat("data packet ", 2),
+                PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+                /*packet_number=*/2);
 
   mock_helper_.AdvanceTime(
       QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs));
@@ -1371,7 +1366,7 @@
   // list.
   ASSERT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id));
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, conn_id, _, _));
-  ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
 }
 
 TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
@@ -1410,7 +1405,7 @@
               Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                    base::Unretained(this), conn_id))));
     }
-    ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+    ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO());
     if (conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore &&
         conn_id > kMaxNumSessionsToCreate) {
       EXPECT_TRUE(store->HasChloForConnection(conn_id));
@@ -1469,12 +1464,11 @@
               Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                    base::Unretained(this), conn_id))));
     }
-    ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+    ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO());
   }
   // Retransmit CHLO on last connection should be dropped.
   QuicConnectionId last_connection = kMaxNumSessionsToCreate + 1;
-  ProcessPacket(client_addr_, last_connection, true, false,
-                SerializeFullCHLO());
+  ProcessPacket(client_addr_, last_connection, true, SerializeFullCHLO());
 
   size_t packets_buffered = 2;
   if (!FLAGS_quic_reloadable_flag_quic_buffer_packets_after_chlo) {
@@ -1516,14 +1510,14 @@
               Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                    base::Unretained(this), conn_id))));
     }
-    ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+    ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO());
   }
 
   // Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The
   // last one should be dropped.
   for (QuicPacketNumber packet_number = 2;
        packet_number <= kDefaultMaxUndecryptablePackets + 2; ++packet_number) {
-    ProcessPacket(client_addr_, last_connection_id, true, false, "data packet");
+    ProcessPacket(client_addr_, last_connection_id, true, "data packet");
   }
 
   // Reset counter and process buffered CHLO.
@@ -1551,7 +1545,7 @@
       QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
 
   QuicConnectionId conn_id = 1;
-  ProcessPacket(client_addr_, conn_id, true, false, "data packet",
+  ProcessPacket(client_addr_, conn_id, true, "data packet",
                 PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
                 /*packet_number=*/1);
   // Fill packet buffer to full with CHLOs on other connections. Need to feed
@@ -1573,13 +1567,12 @@
               Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
                                    base::Unretained(this), conn_id))));
     }
-    ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+    ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO());
   }
   EXPECT_FALSE(store->HasChloForConnection(/*connection_id=*/1));
 
   // CHLO on connection 1 should still be buffered.
-  ProcessPacket(client_addr_, /*connection_id=*/1, true, false,
-                SerializeFullCHLO());
+  ProcessPacket(client_addr_, /*connection_id=*/1, true, SerializeFullCHLO());
   EXPECT_TRUE(store->HasChloForConnection(/*connection_id=*/1));
 }
 
@@ -1702,7 +1695,7 @@
   }
 
   // Send a CHLO that the StatelessRejector will accept.
-  ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
 
   check.Call(1);
@@ -1713,7 +1706,7 @@
 
   check.Call(2);
   // Verify that a data packet gets processed immediately.
-  ProcessPacket(client_addr_, conn_id, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id, true, "My name is Data");
 }
 
 // Test a simple situation of connections which the StatelessRejector will
@@ -1740,7 +1733,7 @@
   }
 
   // Send a CHLO that the StatelessRejector will reject.
-  ProcessPacket(client_addr_, conn_id, true, false, SerializeCHLO());
+  ProcessPacket(client_addr_, conn_id, true, SerializeCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
 
   // Complete the ProofSource::GetProof call and verify that the connection and
@@ -1751,7 +1744,7 @@
 
   // Verify that a data packet is passed to the time wait list manager.
   check.Call(2);
-  ProcessPacket(client_addr_, conn_id, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id, true, "My name is Data");
 }
 
 // Test a situation with multiple interleaved connections which the
@@ -1801,11 +1794,11 @@
   }
 
   // Send a CHLO that the StatelessRejector will accept.
-  ProcessPacket(client_addr_, conn_id_1, true, false, SerializeFullCHLO());
+  ProcessPacket(client_addr_, conn_id_1, true, SerializeFullCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
 
   // Send another CHLO that the StatelessRejector will accept.
-  ProcessPacket(client_addr_, conn_id_2, true, false, SerializeFullCHLO());
+  ProcessPacket(client_addr_, conn_id_2, true, SerializeFullCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2);
 
   // Complete the second ProofSource::GetProof call and verify that a session is
@@ -1816,12 +1809,12 @@
 
   // Verify that a data packet on that connection gets processed immediately.
   check.Call(2);
-  ProcessPacket(client_addr_, conn_id_2, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id_2, true, "My name is Data");
 
   // Verify that a data packet on the other connection does not get processed
   // yet.
   check.Call(3);
-  ProcessPacket(client_addr_, conn_id_1, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id_1, true, "My name is Data");
   EXPECT_TRUE(store->HasBufferedPackets(conn_id_1));
   EXPECT_FALSE(store->HasBufferedPackets(conn_id_2));
 
@@ -1870,11 +1863,11 @@
   }
 
   // Send a CHLO that the StatelessRejector will reject.
-  ProcessPacket(client_addr_, conn_id_1, true, false, SerializeCHLO());
+  ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
 
   // Send another CHLO that the StatelessRejector will reject.
-  ProcessPacket(client_addr_, conn_id_2, true, false, SerializeCHLO());
+  ProcessPacket(client_addr_, conn_id_2, true, SerializeCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2);
 
   // Complete the second ProofSource::GetProof call and verify that the
@@ -1886,11 +1879,11 @@
   // Verify that a data packet on that connection gets processed immediately by
   // the time wait manager.
   check.Call(2);
-  ProcessPacket(client_addr_, conn_id_2, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id_2, true, "My name is Data");
 
   // Verify that a data packet on the first connection gets buffered.
   check.Call(3);
-  ProcessPacket(client_addr_, conn_id_1, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id_1, true, "My name is Data");
   EXPECT_TRUE(store->HasBufferedPackets(conn_id_1));
   EXPECT_FALSE(store->HasBufferedPackets(conn_id_2));
 
@@ -1929,13 +1922,13 @@
   }
 
   // Send a CHLO that the StatelessRejector will reject.
-  ProcessPacket(client_addr_, conn_id_1, true, false, SerializeCHLO());
+  ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
   EXPECT_FALSE(store->HasBufferedPackets(conn_id_1));
 
   // Send an identical CHLO which should get buffered.
   check.Call(1);
-  ProcessPacket(client_addr_, conn_id_1, true, false, SerializeCHLO());
+  ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
   EXPECT_TRUE(store->HasBufferedPackets(conn_id_1));
 
@@ -1971,13 +1964,13 @@
   }
 
   // Send a CHLO that the StatelessRejector will accept.
-  ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
   EXPECT_FALSE(store->HasBufferedPackets(conn_id));
 
   // Send a data packet that will get buffered
   check.Call(1);
-  ProcessPacket(client_addr_, conn_id, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id, true, "My name is Data");
   EXPECT_TRUE(store->HasBufferedPackets(conn_id));
 
   // Pretend that enough time has gone by for the packets to get expired out of
@@ -2029,13 +2022,13 @@
   }
 
   // Send a CHLO that the StatelessRejector will accept.
-  ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+  ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
   EXPECT_FALSE(store->HasBufferedPackets(conn_id));
 
   // Send a data packet that will get buffered
   check.Call(1);
-  ProcessPacket(client_addr_, conn_id, true, false, "My name is Data");
+  ProcessPacket(client_addr_, conn_id, true, "My name is Data");
   EXPECT_TRUE(store->HasBufferedPackets(conn_id));
 
   // Pretend that enough time has gone by for the packets to get expired out of
diff --git a/net/tools/quic/quic_packet_printer_bin.cc b/net/tools/quic/quic_packet_printer_bin.cc
index ccac643..aa26b479 100644
--- a/net/tools/quic/quic_packet_printer_bin.cc
+++ b/net/tools/quic/quic_packet_printer_bin.cc
@@ -142,10 +142,6 @@
     std::cerr << "OnBlockedFrame: " << frame;
     return true;
   }
-  bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override {
-    std::cerr << "OnPathCloseFrame:" << frame;
-    return true;
-  }
   void OnPacketComplete() override { std::cerr << "OnPacketComplete\n"; }
 
  private:
diff --git a/net/tools/quic/quic_spdy_server_stream_base.cc b/net/tools/quic/quic_spdy_server_stream_base.cc
index e8451689..f7af873 100644
--- a/net/tools/quic/quic_spdy_server_stream_base.cc
+++ b/net/tools/quic/quic_spdy_server_stream_base.cc
@@ -20,11 +20,22 @@
     // or RST.
     DCHECK(fin_sent());
     // Tell the peer to stop sending further data.
-    QUIC_DVLOG(0) << " Server: Send QUIC_STREAM_NO_ERROR on stream " << id();
+    QUIC_DVLOG(1) << " Server: Send QUIC_STREAM_NO_ERROR on stream " << id();
     Reset(QUIC_STREAM_NO_ERROR);
   }
 
   QuicSpdyStream::CloseWriteSide();
 }
 
+void QuicSpdyServerStreamBase::StopReading() {
+  if (!fin_received() && !rst_received() && write_side_closed() &&
+      !rst_sent()) {
+    DCHECK(fin_sent());
+    // Tell the peer to stop sending further data.
+    QUIC_DVLOG(1) << " Server: Send QUIC_STREAM_NO_ERROR on stream " << id();
+    Reset(QUIC_STREAM_NO_ERROR);
+  }
+  QuicSpdyStream::StopReading();
+}
+
 }  // namespace net
diff --git a/net/tools/quic/quic_spdy_server_stream_base.h b/net/tools/quic/quic_spdy_server_stream_base.h
index 880642a7..46462a1 100644
--- a/net/tools/quic/quic_spdy_server_stream_base.h
+++ b/net/tools/quic/quic_spdy_server_stream_base.h
@@ -16,6 +16,7 @@
   // Override the base class to send QUIC_STREAM_NO_ERROR to the peer
   // when the stream has not received all the data.
   void CloseWriteSide() override;
+  void StopReading() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicSpdyServerStreamBase);
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index 78fb04d..0ff4f8d 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -125,7 +125,7 @@
       QuicConnectionId connection_id,
       QuicPacketNumber packet_number) {
     return net::test::ConstructEncryptedPacket(connection_id, false, false,
-                                               false, packet_number, "data");
+                                               packet_number, "data");
   }
 
   QuicFlagSaver flags_;  // Save/restore all QUIC flag values.
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 8883c758..e9f5d5cb 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -189,6 +189,8 @@
         "backend/cups_deleters.h",
         "backend/cups_ipp_util.cc",
         "backend/cups_ipp_util.h",
+        "backend/cups_jobs.cc",
+        "backend/cups_jobs.h",
         "backend/cups_printer.cc",
         "backend/cups_printer.h",
         "backend/print_backend_cups_ipp.cc",
diff --git a/printing/backend/cups_connection.cc b/printing/backend/cups_connection.cc
index 2b0f8c8..867e0dc 100644
--- a/printing/backend/cups_connection.cc
+++ b/printing/backend/cups_connection.cc
@@ -4,18 +4,31 @@
 
 #include "printing/backend/cups_connection.h"
 
+#include <map>
+#include <set>
 #include <string>
 #include <utility>
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
+#include "printing/backend/cups_jobs.h"
 
 namespace printing {
 
 namespace {
 
-const int kTimeoutMs = 3000;
+constexpr int kTimeoutMs = 3000;
+
+// The number of jobs we'll retrieve for a queue.  We expect a user to queue at
+// most 10 jobs per printer.  If they queue more, they won't receive updates for
+// the 11th job until one finishes.
+constexpr int kProcessingJobsLimit = 10;
+
+// The number of completed jobs that are retrieved.  We only need one update for
+// a completed job to confirm its final status.  We could retrieve one but we
+// retrieve the last 3 in case that many finished between queries.
+constexpr int kCompletedJobsLimit = 3;
 
 class DestinationEnumerator {
  public:
@@ -44,42 +57,6 @@
   DISALLOW_COPY_AND_ASSIGN(DestinationEnumerator);
 };
 
-CupsJob createCupsJob(int job_id,
-                      base::StringPiece job_title,
-                      base::StringPiece printer_id,
-                      ipp_jstate_t state) {
-  CupsJob::JobState converted_state = CupsJob::UNKNOWN;
-  switch (state) {
-    case IPP_JOB_ABORTED:
-      converted_state = CupsJob::ABORTED;
-      break;
-    case IPP_JOB_CANCELLED:
-      converted_state = CupsJob::CANCELED;
-      break;
-    case IPP_JOB_COMPLETED:
-      converted_state = CupsJob::COMPLETED;
-      break;
-    case IPP_JOB_HELD:
-      converted_state = CupsJob::HELD;
-      break;
-    case IPP_JOB_PENDING:
-      converted_state = CupsJob::PENDING;
-      break;
-    case IPP_JOB_PROCESSING:
-      converted_state = CupsJob::PROCESSING;
-      break;
-    case IPP_JOB_STOPPED:
-      converted_state = CupsJob::STOPPED;
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-
-  return {job_id, job_title.as_string(), printer_id.as_string(),
-          converted_state};
-}
-
 }  // namespace
 
 CupsConnection::CupsConnection(const GURL& print_server_url,
@@ -162,24 +139,41 @@
       std::unique_ptr<cups_dinfo_t, DestInfoDeleter>(info));
 }
 
-std::vector<CupsJob> CupsConnection::GetJobs() {
-  cups_job_t* jobs;
-  int num_jobs = cupsGetJobs2(cups_http_.get(),  // http connection
-                              &jobs,             // out param
-                              nullptr,           // all printers
-                              0,                 // all users
-                              CUPS_WHICHJOBS_ALL);
-
-  const JobsDeleter deleter(num_jobs);
-  std::unique_ptr<cups_job_t, const JobsDeleter&> scoped_jobs(jobs, deleter);
-
-  std::vector<CupsJob> job_copies;
-  for (int i = 0; i < num_jobs; i++) {
-    job_copies.push_back(
-        createCupsJob(jobs[i].id, jobs[i].title, jobs[i].dest, jobs[i].state));
+bool CupsConnection::GetJobs(const std::vector<std::string>& printer_ids,
+                             std::vector<QueueStatus>* queues) {
+  DCHECK(queues);
+  if (!Connect()) {
+    LOG(ERROR) << "Could not establish connection to CUPS";
+    return false;
   }
 
-  return job_copies;
+  std::vector<QueueStatus> temp_queues;
+
+  for (const std::string& id : printer_ids) {
+    temp_queues.emplace_back();
+    QueueStatus* queue_status = &temp_queues.back();
+
+    if (!GetPrinterStatus(cups_http_.get(), id,
+                          &queue_status->printer_status)) {
+      LOG(WARNING) << "Could not retrieve printer status for " << id;
+      return false;
+    }
+
+    if (!GetCupsJobs(cups_http_.get(), id, kCompletedJobsLimit, COMPLETED,
+                     &queue_status->jobs)) {
+      LOG(WARNING) << "Could not get completed jobs for " << id;
+      return false;
+    }
+
+    if (!GetCupsJobs(cups_http_.get(), id, kProcessingJobsLimit, PROCESSING,
+                     &queue_status->jobs)) {
+      LOG(WARNING) << "Could not get in progress jobs for " << id;
+      return false;
+    }
+  }
+  queues->insert(queues->end(), temp_queues.begin(), temp_queues.end());
+
+  return true;
 }
 
 std::string CupsConnection::server_name() const {
diff --git a/printing/backend/cups_connection.h b/printing/backend/cups_connection.h
index fe8a7a2..0f0475e4 100644
--- a/printing/backend/cups_connection.h
+++ b/printing/backend/cups_connection.h
@@ -14,29 +14,17 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "printing/backend/cups_deleters.h"
+#include "printing/backend/cups_jobs.h"
 #include "printing/backend/cups_printer.h"
 #include "printing/printing_export.h"
 #include "url/gurl.h"
 
 namespace printing {
 
-// Represents a print job sent to the queue.
-struct PRINTING_EXPORT CupsJob {
-  enum JobState {
-    UNKNOWN,
-    PENDING,
-    HELD,
-    COMPLETED,
-    PROCESSING,
-    STOPPED,
-    CANCELED,
-    ABORTED
-  };
-
-  int id;
-  std::string title;
-  std::string printer_id;
-  JobState state;
+// Represents the status of a printer queue.
+struct PRINTING_EXPORT QueueStatus {
+  PrinterStatus printer_status;
+  std::vector<CupsJob> jobs;
 };
 
 // Represents a connection to a CUPS server.
@@ -56,8 +44,12 @@
   // Returns a printer for |printer_name| from the connected server.
   std::unique_ptr<CupsPrinter> GetPrinter(const std::string& printer_name);
 
-  // Returns a list of print jobs from all connected printers.
-  std::vector<CupsJob> GetJobs();
+  // Queries CUPS for printer queue status for |printer_ids|.  Populates |jobs|
+  // with said information with one QueueStatus per printer_id.  Returns true if
+  // all the queries were successful.  In the event of failure, |jobs| will be
+  // unchanged.
+  bool GetJobs(const std::vector<std::string>& printer_ids,
+               std::vector<QueueStatus>* jobs);
 
   std::string server_name() const;
 
diff --git a/printing/backend/cups_ipp_util.h b/printing/backend/cups_ipp_util.h
index 670a9e3..2c4765e 100644
--- a/printing/backend/cups_ipp_util.h
+++ b/printing/backend/cups_ipp_util.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Methods for parsing IPP Printer attributes.
+
 #ifndef PRINTING_BACKEND_CUPS_IPP_UTIL_H_
 #define PRINTING_BACKEND_CUPS_IPP_UTIL_H_
 
diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc
new file mode 100644
index 0000000..8d8640e
--- /dev/null
+++ b/printing/backend/cups_jobs.cc
@@ -0,0 +1,396 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "printing/backend/cups_jobs.h"
+
+#include <cups/ipp.h>
+
+#include <array>
+#include <map>
+#include <memory>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+
+namespace printing {
+namespace {
+
+using PReason = PrinterStatus::PrinterReason::Reason;
+using PSeverity = PrinterStatus::PrinterReason::Severity;
+
+// printer attributes
+const char kPrinterUri[] = "printer-uri";
+const char kPrinterState[] = "printer-state";
+const char kPrinterStateReasons[] = "printer-state-reasons";
+const char kPrinterStateMessage[] = "printer-state-message";
+
+// job attributes
+const char kJobUri[] = "job-uri";
+const char kJobId[] = "job-id";
+const char kJobState[] = "job-state";
+const char kJobStateReasons[] = "job-state-reasons";
+const char kJobStateMessage[] = "job-state-message";
+const char kJobImpressionsCompleted[] = "job-impressions-completed";
+const char kTimeAtProcessing[] = "time-at-processing";
+
+// request parameters
+const char kRequestedAttributes[] = "requested-attributes";
+const char kWhichJobs[] = "which-jobs";
+const char kLimit[] = "limit";
+
+// request values
+const char kCompleted[] = "completed";
+const char kNotCompleted[] = "not-completed";
+
+// printer state severities
+const char kSeverityReport[] = "report";
+const char kSeverityWarn[] = "warning";
+const char kSeverityError[] = "error";
+
+// printer state reason values
+const char kNone[] = "none";
+const char kMediaNeeded[] = "media-needed";
+const char kMediaJam[] = "media-jam";
+const char kMovingToPaused[] = "moving-to-paused";
+const char kPaused[] = "paused";
+const char kShutdown[] = "shutdown";
+const char kConnectingToDevice[] = "connecting-to-device";
+const char kTimedOut[] = "timed-out";
+const char kStopping[] = "stopping";
+const char kStoppedPartly[] = "stopped-partly";
+const char kTonerLow[] = "toner-low";
+const char kTonerEmpty[] = "toner-empty";
+const char kSpoolAreaFull[] = "spool-area-full";
+const char kCoverOpen[] = "cover-open";
+const char kInterlockOpen[] = "interlock-open";
+const char kDoorOpen[] = "door-open";
+const char kInputTrayMissing[] = "input-tray-missing";
+const char kMediaLow[] = "media-low";
+const char kMediaEmpty[] = "media-empty";
+const char kOutputTrayMissing[] = "output-tray-missing";
+const char kOutputAreaAlmostFull[] = "output-area-almost-full";
+const char kOutputAreaFull[] = "output-area-full";
+const char kMarkerSupplyLow[] = "marker-supply-low";
+const char kMarkerSupplyEmpty[] = "marker-supply-empty";
+const char kMarkerWasteAlmostFull[] = "marker-waste-almost-full";
+const char kMarkerWasteFull[] = "marker-waste-full";
+const char kFuserOverTemp[] = "fuser-over-temp";
+const char kFuserUnderTemp[] = "fuser-under-temp";
+const char kOpcNearEol[] = "opc-near-eol";
+const char kOpcLifeOver[] = "opc-life-over";
+const char kDeveloperLow[] = "developer-low";
+const char kDeveloperEmpty[] = "developer-empty";
+const char kInterpreterResourceUnavailable[] =
+    "interpreter-resource-unavailable";
+
+constexpr std::array<const char* const, 3> kPrinterAttributes = {
+    kPrinterState, kPrinterStateReasons, kPrinterStateMessage};
+
+std::unique_ptr<ipp_t, void (*)(ipp_t*)> WrapIpp(ipp_t* ipp) {
+  return std::unique_ptr<ipp_t, void (*)(ipp_t*)>(ipp, &ippDelete);
+}
+
+// Converts an IPP attribute |attr| to the appropriate JobState enum.
+CupsJob::JobState ToJobState(ipp_attribute_t* attr) {
+  DCHECK_EQ(IPP_TAG_ENUM, ippGetValueTag(attr));
+  int state = ippGetInteger(attr, 0);
+  switch (state) {
+    case IPP_JOB_ABORTED:
+      return CupsJob::ABORTED;
+    case IPP_JOB_CANCELLED:
+      return CupsJob::CANCELED;
+    case IPP_JOB_COMPLETED:
+      return CupsJob::COMPLETED;
+    case IPP_JOB_HELD:
+      return CupsJob::HELD;
+    case IPP_JOB_PENDING:
+      return CupsJob::PENDING;
+    case IPP_JOB_PROCESSING:
+      return CupsJob::PROCESSING;
+    case IPP_JOB_STOPPED:
+      return CupsJob::STOPPED;
+    default:
+      NOTREACHED() << "Unidentifed state " << state;
+      break;
+  }
+
+  return CupsJob::UNKNOWN;
+}
+
+// Returns a lookup map from strings to PrinterReason::Reason.
+const std::map<base::StringPiece, PReason>& GetLabelToReason() {
+  static const std::map<base::StringPiece, PReason> kLabelToReason =
+      std::map<base::StringPiece, PReason>{
+          {kNone, PReason::NONE},
+          {kMediaNeeded, PReason::MEDIA_NEEDED},
+          {kMediaJam, PReason::MEDIA_JAM},
+          {kMovingToPaused, PReason::MOVING_TO_PAUSED},
+          {kPaused, PReason::PAUSED},
+          {kShutdown, PReason::SHUTDOWN},
+          {kConnectingToDevice, PReason::CONNECTING_TO_DEVICE},
+          {kTimedOut, PReason::TIMED_OUT},
+          {kStopping, PReason::STOPPING},
+          {kStoppedPartly, PReason::STOPPED_PARTLY},
+          {kTonerLow, PReason::TONER_LOW},
+          {kTonerEmpty, PReason::TONER_EMPTY},
+          {kSpoolAreaFull, PReason::SPOOL_AREA_FULL},
+          {kCoverOpen, PReason::COVER_OPEN},
+          {kInterlockOpen, PReason::INTERLOCK_OPEN},
+          {kDoorOpen, PReason::DOOR_OPEN},
+          {kInputTrayMissing, PReason::INPUT_TRAY_MISSING},
+          {kMediaLow, PReason::MEDIA_LOW},
+          {kMediaEmpty, PReason::MEDIA_EMPTY},
+          {kOutputTrayMissing, PReason::OUTPUT_TRAY_MISSING},
+          {kOutputAreaAlmostFull, PReason::OUTPUT_AREA_ALMOST_FULL},
+          {kOutputAreaFull, PReason::OUTPUT_AREA_FULL},
+          {kMarkerSupplyLow, PReason::MARKER_SUPPLY_LOW},
+          {kMarkerSupplyEmpty, PReason::MARKER_SUPPLY_EMPTY},
+          {kMarkerWasteAlmostFull, PReason::MARKER_WASTE_ALMOST_FULL},
+          {kMarkerWasteFull, PReason::MARKER_WASTE_FULL},
+          {kFuserOverTemp, PReason::FUSER_OVER_TEMP},
+          {kFuserUnderTemp, PReason::FUSER_UNDER_TEMP},
+          {kOpcNearEol, PReason::OPC_NEAR_EOL},
+          {kOpcLifeOver, PReason::OPC_LIFE_OVER},
+          {kDeveloperLow, PReason::DEVELOPER_LOW},
+          {kDeveloperEmpty, PReason::DEVELOPER_EMPTY},
+          {kInterpreterResourceUnavailable,
+           PReason::INTERPRETER_RESOURCE_UNAVAILABLE},
+      };
+  return kLabelToReason;
+}
+
+// Returns the Reason cooresponding to the string |reason|.  Returns
+// UNKOWN_REASON if the string is not recognized.
+PrinterStatus::PrinterReason::Reason ToReason(base::StringPiece reason) {
+  const auto& enum_map = GetLabelToReason();
+  const auto& entry = enum_map.find(reason);
+  return entry != enum_map.end() ? entry->second : PReason::UNKNOWN_REASON;
+}
+
+// Returns the Severity cooresponding to |severity|.  Returns UNKNOWN_SEVERITY
+// if the strin gis not recognized.
+PSeverity ToSeverity(base::StringPiece severity) {
+  if (severity == kSeverityError)
+    return PSeverity::ERROR;
+
+  if (severity == kSeverityWarn)
+    return PSeverity::WARNING;
+
+  if (severity == kSeverityReport)
+    return PSeverity::REPORT;
+
+  return PSeverity::UNKNOWN_SEVERITY;
+}
+
+// Parses the |reason| string into a PrinterReason.  Splits the string based on
+// the last '-' to determine severity.  If a recognized severity is not
+// included, severity is assumed to be ERROR per RFC2911.
+PrinterStatus::PrinterReason ToPrinterReason(base::StringPiece reason) {
+  PrinterStatus::PrinterReason parsed;
+
+  if (reason == kNone) {
+    parsed.reason = PReason::NONE;
+    parsed.severity = PSeverity::UNKNOWN_SEVERITY;
+    return parsed;
+  }
+
+  size_t last_dash = reason.rfind('-');
+  auto severity = PSeverity::UNKNOWN_SEVERITY;
+  if (last_dash != base::StringPiece::npos) {
+    // try to parse the last part of the string as the severity.
+    severity = ToSeverity(reason.substr(last_dash + 1));
+  }
+
+  if (severity == PSeverity::UNKNOWN_SEVERITY) {
+    // Severity is unknown.  No severity in the reason.
+    // Per spec, if there is no severity, severity is error.
+    parsed.severity = PSeverity::ERROR;
+    parsed.reason = ToReason(reason);
+  } else {
+    parsed.severity = severity;
+    // reason is the beginning of the string
+    parsed.reason = ToReason(reason.substr(0, last_dash));
+  }
+
+  return parsed;
+}
+
+// Populates |collection| with the collection of strings in |attr|.
+void ParseCollection(ipp_attribute_t* attr,
+                     std::vector<std::string>* collection) {
+  int count = ippGetCount(attr);
+  for (int i = 0; i < count; i++) {
+    base::StringPiece value = ippGetString(attr, i, nullptr);
+    collection->push_back(value.as_string());
+  }
+}
+
+// Parse a field for the CupsJob |job| from IPP attribute |attr| using the
+// attribute name |name|.
+void ParseField(ipp_attribute_t* attr, base::StringPiece name, CupsJob* job) {
+  DCHECK(!name.empty());
+  if (name == kJobId) {
+    job->id = ippGetInteger(attr, 0);
+  } else if (name == kJobImpressionsCompleted) {
+    job->current_pages = ippGetInteger(attr, 0);
+  } else if (name == kJobState) {
+    job->state = ToJobState(attr);
+  } else if (name == kJobStateReasons) {
+    ParseCollection(attr, &(job->state_reasons));
+  } else if (name == kJobStateMessage) {
+    job->state_message = ippGetString(attr, 0, nullptr);
+  } else if (name == kTimeAtProcessing) {
+    job->processing_started = ippGetInteger(attr, 0);
+  }
+}
+
+// Returns a new CupsJob allocated in |jobs| with |printer_id| populated.
+CupsJob* NewJob(const std::string& printer_id, std::vector<CupsJob>* jobs) {
+  jobs->emplace_back();
+  CupsJob* job = &jobs->back();
+  job->printer_id = printer_id;
+  return job;
+}
+
+void ParseJobs(ipp_t* response,
+               const std::string& printer_id,
+               ipp_attribute_t* starting_attr,
+               std::vector<CupsJob>* jobs) {
+  // We know this is a non-empty job section.  Start parsing fields for at least
+  // one job.
+  CupsJob* current_job = NewJob(printer_id, jobs);
+  for (ipp_attribute_t* attr = starting_attr; attr != nullptr;
+       attr = ippNextAttribute(response)) {
+    base::StringPiece attribute_name = ippGetName(attr);
+    // Separators indicate a new job.  Separators have empty names.
+    if (attribute_name.empty()) {
+      current_job = NewJob(printer_id, jobs);
+      continue;
+    }
+
+    // Continue to populate the job fileds.
+    ParseField(attr, attribute_name, current_job);
+  }
+}
+
+// Returns the uri for printer with |id| as served by CUPS.  Assumes that |id|
+// is a valid CUPS printer name and performs no error checking or escaping.
+std::string PrinterUriFromName(const std::string& id) {
+  return base::StringPrintf("ipp://localhost/printers/%s", id.c_str());
+}
+
+}  // namespace
+
+void ParseJobsResponse(ipp_t* response,
+                       const std::string& printer_id,
+                       std::vector<CupsJob>* jobs) {
+  // Advance the position in the response to the jobs section.
+  ipp_attribute_t* attr = ippFirstAttribute(response);
+  while (attr != nullptr && ippGetGroupTag(attr) != IPP_TAG_JOB) {
+    attr = ippNextAttribute(response);
+  }
+
+  if (attr != nullptr) {
+    ParseJobs(response, printer_id, attr, jobs);
+  }
+}
+
+void ParsePrinterStatus(ipp_t* response, PrinterStatus* printer_status) {
+  for (ipp_attribute_t* attr = ippFirstAttribute(response); attr != nullptr;
+       attr = ippNextAttribute(response)) {
+    base::StringPiece name = ippGetName(attr);
+    if (name.empty()) {
+      continue;
+    }
+
+    if (name == kPrinterState) {
+      DCHECK_EQ(IPP_TAG_ENUM, ippGetValueTag(attr));
+      printer_status->state = static_cast<ipp_pstate_t>(ippGetInteger(attr, 0));
+    } else if (name == kPrinterStateReasons) {
+      std::vector<std::string> reason_strings;
+      ParseCollection(attr, &reason_strings);
+      for (const std::string& reason : reason_strings) {
+        printer_status->reasons.push_back(ToPrinterReason(reason));
+      }
+    } else if (name == kPrinterStateMessage) {
+      printer_status->message = ippGetString(attr, 0, nullptr);
+    }
+  }
+}
+
+bool GetPrinterStatus(http_t* http,
+                      const std::string& printer_id,
+                      PrinterStatus* printer_status) {
+  DCHECK(http);
+
+  auto request = WrapIpp(ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES));
+
+  const std::string printer_uri = PrinterUriFromName(printer_id);
+  ippAddString(request.get(), IPP_TAG_OPERATION, IPP_TAG_URI, kPrinterUri,
+               nullptr, printer_uri.data());
+
+  ippAddStrings(request.get(), IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+                kRequestedAttributes, kPrinterAttributes.size(), nullptr,
+                kPrinterAttributes.data());
+
+  auto response =
+      WrapIpp(cupsDoRequest(http, request.release(), printer_uri.c_str()));
+
+  if (ippGetStatusCode(response.get()) != IPP_STATUS_OK)
+    return false;
+
+  ParsePrinterStatus(response.get(), printer_status);
+
+  return true;
+}
+
+bool GetCupsJobs(http_t* http,
+                 const std::string& printer_id,
+                 int limit,
+                 JobCompletionState which,
+                 std::vector<CupsJob>* jobs) {
+  DCHECK(http);
+
+  auto request = WrapIpp(ippNewRequest(IPP_OP_GET_JOBS));
+  const std::string printer_uri = PrinterUriFromName(printer_id);
+  ippAddString(request.get(), IPP_TAG_OPERATION, IPP_TAG_URI, kPrinterUri,
+               nullptr, printer_uri.data());
+  ippAddInteger(request.get(), IPP_TAG_OPERATION, IPP_TAG_INTEGER, kLimit,
+                limit);
+
+  std::vector<const char*> job_attributes = {
+      kJobUri,          kJobId,           kJobState,
+      kJobStateReasons, kJobStateMessage, kJobImpressionsCompleted,
+      kTimeAtProcessing};
+
+  ippAddStrings(request.get(), IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+                kRequestedAttributes, job_attributes.size(), nullptr,
+                job_attributes.data());
+
+  ippAddString(request.get(), IPP_TAG_OPERATION, IPP_TAG_KEYWORD, kWhichJobs,
+               nullptr, which == COMPLETED ? kCompleted : kNotCompleted);
+
+  if (ippValidateAttributes(request.get()) != 1) {
+    LOG(WARNING) << "Could not validate ipp request: " << cupsLastErrorString();
+    return false;
+  }
+
+  // cupsDoRequest will delete the request.
+  auto response =
+      WrapIpp(cupsDoRequest(http, request.release(), printer_uri.c_str()));
+
+  ipp_status_t status = ippGetStatusCode(response.get());
+
+  if (status != IPP_OK) {
+    LOG(WARNING) << "IPP Error: " << cupsLastErrorString();
+    return false;
+  }
+
+  ParseJobsResponse(response.get(), printer_id, jobs);
+
+  return true;
+}
+
+}  // namespace printing
diff --git a/printing/backend/cups_jobs.h b/printing/backend/cups_jobs.h
new file mode 100644
index 0000000..12c2d51
--- /dev/null
+++ b/printing/backend/cups_jobs.h
@@ -0,0 +1,139 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Implementations of IPP requests for printer queue information.
+
+#ifndef PRINTING_BACKEND_CUPS_JOBS_H_
+#define PRINTING_BACKEND_CUPS_JOBS_H_
+
+#include <cups/cups.h>
+
+#include <string>
+#include <vector>
+
+#include "printing/printing_export.h"
+
+namespace printing {
+
+// Represents a print job sent to the queue.
+struct PRINTING_EXPORT CupsJob {
+  // Corresponds to job-state from RFC2911.
+  enum JobState {
+    UNKNOWN,
+    PENDING,  // waiting to be processed
+    HELD,  // the job has not begun printing and will not without intervention
+    COMPLETED,
+    PROCESSING,  // job is being sent to the printer/printed
+    STOPPED,     // job was being processed and has now stopped
+    CANCELED,    // either the spooler or a user canclled the job
+    ABORTED      // an error occurred causing the printer to give up
+  };
+
+  // job id
+  int id = -1;
+  // printer name in CUPS
+  std::string printer_id;
+  JobState state = UNKNOWN;
+  // the last page printed
+  int current_pages = -1;
+  // detail for the job state
+  std::vector<std::string> state_reasons;
+  // human readable message explaining the state
+  std::string state_message;
+  // most recent timestamp where the job entered PROCESSING
+  int processing_started = 0;
+};
+
+// Represents the status of a printer containing the properties printer-state,
+// printer-state-reasons, and printer-state-message.
+struct PrinterStatus {
+  struct PrinterReason {
+    // Standardized reasons from RFC2911.
+    enum Reason {
+      UNKNOWN_REASON,
+      NONE,
+      MEDIA_NEEDED,
+      MEDIA_JAM,
+      MOVING_TO_PAUSED,
+      PAUSED,
+      SHUTDOWN,
+      CONNECTING_TO_DEVICE,
+      TIMED_OUT,
+      STOPPING,
+      STOPPED_PARTLY,
+      TONER_LOW,
+      TONER_EMPTY,
+      SPOOL_AREA_FULL,
+      COVER_OPEN,
+      INTERLOCK_OPEN,
+      DOOR_OPEN,
+      INPUT_TRAY_MISSING,
+      MEDIA_LOW,
+      MEDIA_EMPTY,
+      OUTPUT_TRAY_MISSING,
+      OUTPUT_AREA_ALMOST_FULL,
+      OUTPUT_AREA_FULL,
+      MARKER_SUPPLY_LOW,
+      MARKER_SUPPLY_EMPTY,
+      MARKER_WASTE_ALMOST_FULL,
+      MARKER_WASTE_FULL,
+      FUSER_OVER_TEMP,
+      FUSER_UNDER_TEMP,
+      OPC_NEAR_EOL,
+      OPC_LIFE_OVER,
+      DEVELOPER_LOW,
+      DEVELOPER_EMPTY,
+      INTERPRETER_RESOURCE_UNAVAILABLE
+    };
+
+    // Severity of the state-reason.
+    enum Severity { UNKNOWN_SEVERITY, REPORT, WARNING, ERROR };
+
+    Reason reason;
+    Severity severity;
+  };
+
+  // printer-state
+  ipp_pstate_t state;
+  // printer-state-reasons
+  std::vector<PrinterReason> reasons;
+  // printer-state-message
+  std::string message;
+};
+
+// Specifies classes of jobs.
+enum JobCompletionState {
+  COMPLETED,  // only completed jobs
+  PROCESSING  // only jobs that are being processed
+};
+
+// Extracts structured job information from the |response| for |printer_id|.
+// Extracted jobs are added to |jobs|.
+void ParseJobsResponse(ipp_t* response,
+                       const std::string& printer_id,
+                       std::vector<CupsJob>* jobs);
+
+// Attempts to extract a PrinterStatus object out of |response|.
+void ParsePrinterStatus(ipp_t* response, PrinterStatus* printer_status);
+
+// Attempts to retrieve printer status using connection |http| for |printer_id|.
+// Returns true if succcssful and updates the fields in |printer_status| as
+// appropriate.  Returns false if the request failed.
+bool GetPrinterStatus(http_t* http,
+                      const std::string& printer_id,
+                      PrinterStatus* printer_status);
+
+// Attempts to retrieve job information using connection |http| for the printer
+// named |printer_id|.  Retrieves at most |limit| jobs.  If |completed| then
+// completed jobs are retrieved.  Otherwise, jobs that are currently in progress
+// are retrieved.  Results are added to |jobs| if the operation was successful.
+bool GetCupsJobs(http_t* http,
+                 const std::string& printer_id,
+                 int limit,
+                 JobCompletionState completed,
+                 std::vector<CupsJob>* jobs);
+
+}  // namespace printing
+
+#endif  // PRINTING_BACKEND_CUPS_JOBS_H_
diff --git a/rlz/OWNERS b/rlz/OWNERS
index a66406d..66f24eb 100644
--- a/rlz/OWNERS
+++ b/rlz/OWNERS
@@ -1,2 +1,4 @@
 rogerta@chromium.org
 thakis@chromium.org
+
+# COMPONENT: Internals>Core
diff --git a/services/ui/ws/drag_controller.cc b/services/ui/ws/drag_controller.cc
index 714b37a..eec033c2 100644
--- a/services/ui/ws/drag_controller.cc
+++ b/services/ui/ws/drag_controller.cc
@@ -75,6 +75,8 @@
 
 bool DragController::DispatchPointerEvent(const ui::PointerEvent& event,
                                           ServerWindow* current_target) {
+  DVLOG(2) << "DragController dispatching pointer event at "
+           << event.location().ToString();
   uint32_t event_flags =
       event.flags() &
       (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN);
@@ -83,11 +85,15 @@
   if (waiting_for_final_drop_response_) {
     // If we're waiting on a target window to respond to the final drag drop
     // call, don't process any more pointer events.
+    DVLOG(1) << "Ignoring event because we're waiting for final drop response";
     return false;
   }
 
-  if (event.pointer_details().id != drag_pointer_id_)
+  if (event.pointer_details().id != drag_pointer_id_) {
+    DVLOG(1) << "Ignoring event from different pointer "
+             << event.pointer_details().id;
     return false;
+  }
 
   // If |current_target| doesn't accept drags, walk its hierarchy up until we
   // find one that does (or set to nullptr at the top of the tree).
@@ -119,6 +125,10 @@
     }
 
     SetCurrentTargetWindow(current_target);
+  } else if (event.type() != ET_POINTER_UP) {
+    DVLOG(1) << "Performing no action for pointer event at "
+             << screen_position.ToString()
+             << "! current_target=" << current_target;
   }
 
   if (event.type() == ET_POINTER_UP) {
@@ -143,6 +153,8 @@
 
 void DragController::MessageDragCompleted(bool success,
                                           DropEffect action_taken) {
+  DVLOG(1) << "Drag Completed: success=" << success
+           << ", action_taken=" << action_taken;
   for (DragTargetConnection* connection : called_on_drag_mime_types_)
     connection->PerformOnDragDropDone();
   called_on_drag_mime_types_.clear();
@@ -212,6 +224,8 @@
                                     OperationType type,
                                     uint32_t event_flags,
                                     const gfx::Point& screen_position) {
+  DVLOG(2) << "Queueing operation " << ToString(type) << " to " << window;
+
   // If this window doesn't have the mime data, send it.
   DragTargetConnection* connection = source_->GetDragTargetForWindow(window);
   if (connection != source_connection_ &&
@@ -329,5 +343,23 @@
   }
 }
 
+// static
+std::string DragController::ToString(OperationType type) {
+  switch (type) {
+    case OperationType::NONE:
+      return "NONE";
+    case OperationType::ENTER:
+      return "ENTER";
+    case OperationType::OVER:
+      return "OVER";
+    case OperationType::LEAVE:
+      return "LEAVE";
+    case OperationType::DROP:
+      return "DROP";
+  }
+  NOTREACHED();
+  return std::string();
+}
+
 }  // namespace ws
 }  // namespace ui
diff --git a/services/ui/ws/drag_controller.h b/services/ui/ws/drag_controller.h
index cb40282..edbc11a 100644
--- a/services/ui/ws/drag_controller.h
+++ b/services/ui/ws/drag_controller.h
@@ -111,6 +111,8 @@
   // ServerWindowObserver:
   void OnWindowDestroying(ServerWindow* window) override;
 
+  static std::string ToString(OperationType type);
+
   // Our owner.
   DragSource* source_;
 
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index 9dedaed..8602975 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -1765,7 +1765,8 @@
     // We need to fail this move loop change, otherwise the client will just be
     // waiting for |change_id|.
     DVLOG(1) << "PerformDragDrop failed (access denied).";
-    OnChangeCompleted(change_id, false);
+    client()->OnPerformDragDropCompleted(change_id, false,
+                                         mojom::kDropEffectNone);
     return;
   }
 
@@ -1773,7 +1774,8 @@
   if (!display_root) {
     // The window isn't parented. There's nothing to do.
     DVLOG(1) << "PerformDragDrop failed (window unparented).";
-    OnChangeCompleted(change_id, false);
+    client()->OnPerformDragDropCompleted(change_id, false,
+                                         mojom::kDropEffectNone);
     return;
   }
 
@@ -1781,7 +1783,8 @@
     // Either the window manager is servicing a window drag or we're servicing
     // a drag and drop operation. We can't start a second drag.
     DVLOG(1) << "PerformDragDrop failed (already performing a drag).";
-    OnChangeCompleted(change_id, false);
+    client()->OnPerformDragDropCompleted(change_id, false,
+                                         mojom::kDropEffectNone);
     return;
   }
 
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index f90ea4c4..2e1e08b 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -2482,6 +2482,175 @@
       }
     ]
   },
+  "Cast Audio Linux": {
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "capture_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_alsa_cma_backend_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_crash_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_media_unittests"
+      },
+      {
+        "args": [
+          "--enable-local-file-accesses",
+          "--ozone-platform=cast",
+          "--no-sandbox",
+          "--test-launcher-jobs=1"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_shell_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_shell_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "crypto_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gpu_ipc_service_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ipc_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "jingle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_blink_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ppapi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sandbox_linux_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sql_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "storage_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "url_unittests"
+      }
+    ]
+  },
   "Cast Linux": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.swarm.json b/testing/buildbot/chromium.swarm.json
new file mode 100644
index 0000000..70f448cd
--- /dev/null
+++ b/testing/buildbot/chromium.swarm.json
@@ -0,0 +1,345 @@
+{
+  "Android N5 Swarm": {
+    "gtest_tests": [
+      {
+        "override_compile_targets": [
+          "android_webview_test_apk"
+        ],
+        "override_isolate_target": "android_webview_test_apk",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ]
+        },
+        "test": "android_webview_test_apk"
+      },
+      {
+        "override_isolate_target": "base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ]
+        },
+        "test": "base_unittests"
+      },
+      {
+        "override_compile_targets": [
+          "chrome_public_test_apk"
+        ],
+        "override_isolate_target": "chrome_public_test_apk",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ]
+        },
+        "test": "chrome_public_test_apk"
+      },
+      {
+        "override_isolate_target": "content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "override_isolate_target": "content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ]
+        },
+        "test": "content_unittests"
+      },
+      {
+        "override_isolate_target": "net_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ]
+        },
+        "test": "net_unittests"
+      },
+      {
+        "override_isolate_target": "unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ]
+        },
+        "test": "unit_tests"
+      }
+    ]
+  },
+  "Android N5X Swarm": {
+    "gtest_tests": [
+      {
+        "override_compile_targets": [
+          "android_webview_test_apk"
+        ],
+        "override_isolate_target": "android_webview_test_apk",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ]
+        },
+        "test": "android_webview_test_apk"
+      },
+      {
+        "override_isolate_target": "base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ]
+        },
+        "test": "base_unittests"
+      },
+      {
+        "override_compile_targets": [
+          "chrome_public_test_apk"
+        ],
+        "override_isolate_target": "chrome_public_test_apk",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ]
+        },
+        "test": "chrome_public_test_apk"
+      },
+      {
+        "override_isolate_target": "content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "override_isolate_target": "content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ]
+        },
+        "test": "content_unittests"
+      },
+      {
+        "override_isolate_target": "net_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ]
+        },
+        "test": "net_unittests"
+      },
+      {
+        "override_isolate_target": "unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ]
+        },
+        "test": "unit_tests"
+      }
+    ]
+  },
+  "Linux Swarm": {
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "browser_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      }
+    ]
+  },
+  "Mac Swarm": {
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "browser_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      }
+    ]
+  },
+  "Windows Swarm": {
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "browser_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      }
+    ]
+  }
+}
diff --git a/testing/buildbot/filters/mash.browser_tests.filter b/testing/buildbot/filters/mash.browser_tests.filter
index d0e92b9..5916eae 100644
--- a/testing/buildbot/filters/mash.browser_tests.filter
+++ b/testing/buildbot/filters/mash.browser_tests.filter
@@ -1 +1,2 @@
+BrowserTest.NoTitle
 BrowserTest.Title
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index fcf9ec73..9fe9789 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -132,29 +132,13 @@
             ],
             "experiments": [
                 {
-                    "name": "LastUsedDateAndExpDate_Experiment",
+                    "name": "LastUsedDateAndExpDate_IncreaseDropdownItemHeight_Experiment",
                     "params": {
+                        "dropdown_item_height": "56",
                         "show_expiration_date": "true"
                     },
                     "enable_features": [
-                        "AutofillCreditCardLastUsedDateDisplay"
-                    ]
-                }
-            ]
-        }
-    ],
-    "AutofillCreditCardPopup": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "IncreaseDropdownItemHeight",
-                    "params": {
-                        "dropdown_item_height": "56"
-                    },
-                    "enable_features": [
+                        "AutofillCreditCardLastUsedDateDisplay",
                         "AutofillCreditCardPopupLayout"
                     ]
                 }
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 05e1d0d..18a7e68 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -619,7 +619,6 @@
 Bug(none) fast/forms/select/listbox-appearance-basic.html [ Failure ]
 Bug(none) fast/forms/select/menulist-appearance-basic.html [ Failure ]
 Bug(none) fast/forms/select/menulist-appearance-rtl.html [ Failure ]
-Bug(none) fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Crash ]
 Bug(none) fast/forms/text/input-appearance-selection.html [ Failure ]
 Bug(none) fast/forms/text/input-readonly-autoscroll.html [ Failure ]
 Bug(none) fast/forms/text/input-table.html [ Failure ]
@@ -1651,3 +1650,18 @@
 Bug(none) virtual/threaded/compositing/visibility/visibility-simple-video-layer.html [ Failure ]
 Bug(none) virtual/threaded/compositing/webgl/webgl-reflection.html [ Failure ]
 Bug(none) virtual/threaded/printing/ [ Skip ]
+
+Bug(700530) fast/css/background-clip-values.html [ Failure ]
+Bug(700530) fast/borders/outline-negative-start.html [ Failure ]
+Bug(700530) svg/text/small-fonts-in-html5.html [ Failure ]
+Bug(700530) compositing/overflow/paint-neg-z-order-descendants-into-scrolling-contents-layer.html [ Failure ]
+Bug(700530) fast/multicol/tall-content-in-inner-with-fixed-height.html [ Failure ]
+Bug(700530) svg/custom/pattern-rotate.svg [ Failure ]
+Bug(700530) fast/forms/date/date-appearance-basic.html [ Failure ]
+Bug(700530) fast/forms/text/input-placeholder-paint-order.html [ Failure ]
+Bug(700530) fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Crash Failure ]
+Bug(700530) svg/W3C-SVG-1.1/animate-elem-05-t.svg [ Failure ]
+Bug(700530) svg/custom/use-referencing-nonexisting-symbol.svg [ Failure ]
+Bug(700530) svg/custom/invalid-css.svg [ Failure ]
+Bug(700530) fast/forms/textarea/textarea-placeholder-paint-order.html [ Failure ]
+Bug(700530) fast/box-shadow/box-shadow-clipped-slices.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index e158a280..98a0246 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1,5 +1,5 @@
 # Intentional failures to test the layout test system.
-Bug(intentional) [ Android Linux Win Mac10.10 Mac10.11 Retina ] harness-tests/crash.html [ Crash ]
+Bug(intentional) [ Android Linux Win Mac10.10 Mac10.11 Retina Mac10.12 ] harness-tests/crash.html [ Crash ]
 crbug.com/644303 [ Mac10.9 ] harness-tests/crash.html [ Crash Timeout ]
 Bug(intentional) harness-tests/timeout.html [ Timeout ]
 
diff --git a/third_party/WebKit/LayoutTests/editing/pasteboard/onpaste-text-html-types.html b/third_party/WebKit/LayoutTests/editing/pasteboard/onpaste-text-html-types.html
index 8dd357f..3b74ce48 100644
--- a/third_party/WebKit/LayoutTests/editing/pasteboard/onpaste-text-html-types.html
+++ b/third_party/WebKit/LayoutTests/editing/pasteboard/onpaste-text-html-types.html
@@ -1,5 +1,4 @@
-<body onpaste="paste(event)">
-<div id="test">This test verifies that we can get types from the clipboard
+<div id="test" onpaste="paste(event)">This test verifies that we can get types from the clipboard
 during an onpaste event.  This test requires DRT.</div>
 
 <div id="results">FAIL</div>
@@ -25,4 +24,3 @@
 
 runDumpAsTextEditingTest(false);
 </script>
-</body>
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn
index 2f7d82e..417c089 100644
--- a/third_party/WebKit/Source/core/editing/BUILD.gn
+++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -226,7 +226,6 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "ClipboardEventFlowTest.cpp",
     "CompositionUnderlineTest.cpp",
     "EditingCommandTest.cpp",
     "EditingStrategyTest.cpp",
diff --git a/third_party/WebKit/Source/core/editing/ClipboardEventFlowTest.cpp b/third_party/WebKit/Source/core/editing/ClipboardEventFlowTest.cpp
deleted file mode 100644
index c04a974..0000000
--- a/third_party/WebKit/Source/core/editing/ClipboardEventFlowTest.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/dom/Document.h"
-#include "core/editing/EditingTestBase.h"
-#include "core/editing/FrameSelection.h"
-#include "core/editing/Position.h"
-#include "core/editing/SelectionTemplate.h"
-#include "core/events/EventListener.h"
-#include "core/frame/LocalFrame.h"
-#include "core/frame/Settings.h"
-#include "core/html/HTMLBodyElement.h"
-#include "core/html/HTMLButtonElement.h"
-#include "core/html/HTMLDivElement.h"
-#include "core/html/HTMLHtmlElement.h"
-#include "core/layout/LayoutObject.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace blink {
-
-namespace {
-class MockEventListener : public EventListener {
- public:
-  MockEventListener() : EventListener(EventListener::CPPEventListenerType) {}
-
-  bool operator==(const EventListener& other) const final {
-    return this == &other;
-  }
-
-  MOCK_METHOD2(handleEvent, void(ExecutionContext*, Event*));
-};
-}  // namespace
-
-class ClipboardEventFlowTest : public EditingTestBase {
- private:
-  void makeDocumentEmpty() {
-    while (document().firstChild())
-      document().removeChild(document().firstChild());
-  }
-
-  void setElementText(Element& element, const std::string& text) {
-    element.setInnerHTML(String::fromUTF8(text.c_str()), ASSERT_NO_EXCEPTION);
-    updateAllLifecyclePhases();
-  }
-
-  void setElementTextAndSelectIt(Element& element,
-                                 const std::string& text,
-                                 bool selectionEditable) {
-    setElementText(element, text);
-
-    frame().selection().setSelection(
-        SelectionInDOMTree::Builder()
-            .collapse(Position(element.firstChild(), 0))
-            .extend(Position(element.firstChild(), text.size()))
-            .build());
-
-    element.setAttribute(HTMLNames::contenteditableAttr,
-                         selectionEditable ? "true" : "false");
-  }
-
- protected:
-  void clipboardEventTargetDependsOnSelectionEditabilityTest(
-      const char* command,
-      bool selectionEditable) {
-    using testing::_;
-
-    auto* html = HTMLHtmlElement::create(document());
-    auto* body = HTMLBodyElement::create(document());
-    auto* focusableElement = HTMLButtonElement::create(document());
-    auto* elementWithSelection = HTMLDivElement::create(document());
-
-    auto* eventListenerInstalledOnFocusedElement = new MockEventListener;
-    auto* eventListenerInstalledOnElementWithSelection = new MockEventListener;
-
-    focusableElement->addEventListener(command,
-                                       eventListenerInstalledOnFocusedElement);
-    elementWithSelection->addEventListener(
-        command, eventListenerInstalledOnElementWithSelection);
-
-    makeDocumentEmpty();
-    document().setDesignMode("on");
-
-    body->appendChild(focusableElement);
-    body->appendChild(elementWithSelection);
-    html->appendChild(body);
-    document().appendChild(html);
-
-    focusableElement->focus();
-
-    setElementTextAndSelectIt(*elementWithSelection, "some dummy text",
-                              selectionEditable);
-
-    // allow |document.execCommand| to access clipboard
-    frame().settings()->setJavaScriptCanAccessClipboard(true);
-
-    // test expectations
-    EXPECT_CALL(*eventListenerInstalledOnFocusedElement, handleEvent(_, _))
-        .Times(selectionEditable ? 0 : 1);
-
-    EXPECT_CALL(*eventListenerInstalledOnElementWithSelection,
-                handleEvent(_, _))
-        .Times(selectionEditable ? 1 : 0);
-
-    // execute command
-    NonThrowableExceptionState exceptionState;
-    document().execCommand(command, false, "", exceptionState);
-  }
-};
-
-TEST_F(ClipboardEventFlowTest,
-       copySetsClipboardEventTargetToActiveElementWhenSelectionIsNotEditable) {
-  clipboardEventTargetDependsOnSelectionEditabilityTest("copy", false);
-}
-
-TEST_F(
-    ClipboardEventFlowTest,
-    copySetsClipboardEventTargetToElementWithSelectionWhenSelectionIsEditable) {
-  clipboardEventTargetDependsOnSelectionEditabilityTest("copy", true);
-}
-
-TEST_F(ClipboardEventFlowTest,
-       cutSetsClipboardEventTargetToActiveElementWhenSelectionIsNotEditable) {
-  clipboardEventTargetDependsOnSelectionEditabilityTest("cut", false);
-}
-
-TEST_F(
-    ClipboardEventFlowTest,
-    cutSetsClipboardEventTargetToElementWithSelectionWhenSelectionIsEditable) {
-  clipboardEventTargetDependsOnSelectionEditabilityTest("cut", true);
-}
-
-TEST_F(ClipboardEventFlowTest,
-       pasteSetsClipboardEventTargetToActiveElementWhenSelectionIsNotEditable) {
-  // allow |document.execCommand| to execute 'paste' command
-  frame().settings()->setDOMPasteAllowed(true);
-
-  clipboardEventTargetDependsOnSelectionEditabilityTest("paste", false);
-}
-
-TEST_F(
-    ClipboardEventFlowTest,
-    pasteSetsClipboardEventTargetToElementWithSelectionWhenSelectionIsEditable) {
-  // allow |document.execCommand| to execute 'paste'
-  frame().settings()->setDOMPasteAllowed(true);
-
-  clipboardEventTargetDependsOnSelectionEditabilityTest("paste", true);
-}
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index e4e310ba..5bfbf7d 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -772,9 +772,7 @@
 }
 
 Element* Editor::findEventTargetFrom(const VisibleSelection& selection) const {
-  Element* target = selection.hasEditableStyle()
-                        ? associatedElementOf(selection.start())
-                        : frame().document()->activeElement();
+  Element* target = associatedElementOf(selection.start());
   if (!target)
     target = frame().document()->body();
 
diff --git a/third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp b/third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp
index 4e84da53..85a6ae2 100644
--- a/third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp
+++ b/third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp
@@ -51,20 +51,25 @@
 // Tests that |EphemeralRange::nodes()| will traverse the whole range exactly as
 // |for (Node* n = firstNode(); n != pastLastNode(); n = Traversal::next(*n))|
 // does.
-TEST_F(EphemeralRangeTest, rangeTraversal) {
+TEST_F(EphemeralRangeTest, rangeTraversalDOM) {
   const char* bodyContent =
-      "<p id='host'><b id='one'></b><b id='two'>22</b></p>";
+      "<p id='host'>"
+      "<b id='zero'>0</b>"
+      "<b id='one'>1</b>"
+      "<b id='two'>22</b>"
+      "<span id='three'>333</span>"
+      "</p>";
   setBodyContent(bodyContent);
 
   const std::string expectedNodes(
-      "[BODY][P id=\"host\"][B id=\"one\"][B id=\"two\"][#text \"22\"]");
+      "[BODY][P id=\"host\"][B id=\"zero\"][#text \"0\"][B id=\"one\"][#text "
+      "\"1\"][B id=\"two\"][#text \"22\"][SPAN id=\"three\"][#text \"333\"]");
 
   // Check two ways to traverse.
   EXPECT_EQ(expectedNodes, traverseRange<>(getBodyRange()));
   EXPECT_EQ(traverseRange<>(getBodyRange()),
             traverseRange(EphemeralRange(getBodyRange())));
 
-  // The same with FlatTree traversing.
   EXPECT_EQ(expectedNodes, traverseRange<FlatTreeTraversal>(getBodyRange()));
   EXPECT_EQ(traverseRange<FlatTreeTraversal>(getBodyRange()),
             traverseRange(EphemeralRangeInFlatTree(getBodyRange())));
@@ -73,65 +78,96 @@
 // Tests that |inRange| helper will traverse the whole range with shadow DOM.
 TEST_F(EphemeralRangeTest, rangeShadowTraversal) {
   const char* bodyContent =
-      "<p id='host'><b id='one'></b><input type='text' value='some'></p>";
+      "<b id='zero'>0</b>"
+      "<p id='host'>"
+      "<b id='one'>1</b>"
+      "<b id='two'>22</b>"
+      "<b id='three'>333</b>"
+      "</p>"
+      "<b id='four'>4444</b>";
+  const char* shadowContent =
+      "<p id='five'>55555</p>"
+      "<content select=#two></content>"
+      "<content select=#one></content>"
+      "<span id='six'>666666</span>"
+      "<p id='seven'>7777777</p>";
   setBodyContent(bodyContent);
+  setShadowContent(shadowContent, "host");
 
-  EXPECT_EQ("[BODY][P id=\"host\"][B id=\"one\"][INPUT]",
-            traverseRange<>(getBodyRange()));
-  EXPECT_EQ(traverseRange<>(getBodyRange()),
-            traverseRange(EphemeralRange(getBodyRange())));
+  const std::string expectedNodes(
+      "[BODY][B id=\"zero\"][#text \"0\"][P id=\"host\"][P id=\"five\"][#text "
+      "\"55555\"][B id=\"two\"][#text \"22\"][B id=\"one\"][#text \"1\"][SPAN "
+      "id=\"six\"][#text \"666666\"][P id=\"seven\"][#text \"7777777\"][B "
+      "id=\"four\"][#text \"4444\"]");
 
-  // In this case FlatTree traverse should differs from DOM tree traverse.
-  EXPECT_EQ(
-      "[BODY][P id=\"host\"][B id=\"one\"][INPUT][DIV id=\"inner-editor\" "
-      "(editable)][#text \"some\"]",
-      traverseRange<FlatTreeTraversal>(getBodyRange()));
+  EXPECT_EQ(expectedNodes, traverseRange<FlatTreeTraversal>(getBodyRange()));
   EXPECT_EQ(traverseRange<FlatTreeTraversal>(getBodyRange()),
             traverseRange(EphemeralRangeInFlatTree(getBodyRange())));
+  // Node 'three' should not appear in FlatTreeTraversal.
+  EXPECT_EQ(expectedNodes.find("three") == std::string::npos, true);
 }
 
 // Limit a range and check that it will be traversed correctly.
-TEST_F(EphemeralRangeTest, rangeTraversalLimited) {
+TEST_F(EphemeralRangeTest, rangeTraversalLimitedDOM) {
   const char* bodyContent =
-      "<p id='host'><b id='one'></b><input type='text' value='some'><span "
-      "id='two'></p>";
+      "<p id='host'>"
+      "<b id='zero'>0</b>"
+      "<b id='one'>1</b>"
+      "<b id='two'>22</b>"
+      "<span id='three'>333</span>"
+      "</p>";
   setBodyContent(bodyContent);
 
-  // Get a limited range from <body> to <b> nodes.
   Range* untilB = getBodyRange();
   untilB->setEnd(document().getElementById("one"), 0,
                  IGNORE_EXCEPTION_FOR_TESTING);
-  EXPECT_EQ("[BODY][P id=\"host\"][B id=\"one\"]", traverseRange<>(untilB));
-
+  EXPECT_EQ("[BODY][P id=\"host\"][B id=\"zero\"][#text \"0\"][B id=\"one\"]",
+            traverseRange<>(untilB));
   EXPECT_EQ(traverseRange<>(untilB), traverseRange(EphemeralRange(untilB)));
 
-  EXPECT_EQ("[BODY][P id=\"host\"][B id=\"one\"]",
-            traverseRange<FlatTreeTraversal>(untilB));
-  EXPECT_EQ(traverseRange<FlatTreeTraversal>(untilB),
-            traverseRange(EphemeralRangeInFlatTree(untilB)));
-
-  // Get a limited range from <b> to <span> nodes.
   Range* fromBToSpan = getBodyRange();
   fromBToSpan->setStart(document().getElementById("one"), 0,
                         IGNORE_EXCEPTION_FOR_TESTING);
-  fromBToSpan->setEnd(document().getElementById("two"), 0,
+  fromBToSpan->setEnd(document().getElementById("three"), 0,
                       IGNORE_EXCEPTION_FOR_TESTING);
-
-  EXPECT_EQ("[B id=\"one\"][INPUT][SPAN id=\"two\"]",
+  EXPECT_EQ("[#text \"1\"][B id=\"two\"][#text \"22\"][SPAN id=\"three\"]",
             traverseRange<>(fromBToSpan));
   EXPECT_EQ(traverseRange<>(fromBToSpan),
             traverseRange(EphemeralRange(fromBToSpan)));
+}
 
-  EXPECT_EQ(
-      "[B id=\"one\"][INPUT][DIV id=\"inner-editor\" (editable)][#text "
-      "\"some\"][SPAN id=\"two\"]",
-      traverseRange<FlatTreeTraversal>(fromBToSpan));
-  EXPECT_EQ(traverseRange<FlatTreeTraversal>(fromBToSpan),
-            traverseRange(EphemeralRangeInFlatTree(fromBToSpan)));
+TEST_F(EphemeralRangeTest, rangeTraversalLimitedFlatTree) {
+  const char* bodyContent =
+      "<b id='zero'>0</b>"
+      "<p id='host'>"
+      "<b id='one'>1</b>"
+      "<b id='two'>22</b>"
+      "</p>"
+      "<b id='three'>333</b>";
+  const char* shadowContent =
+      "<p id='four'>4444</p>"
+      "<content select=#two></content>"
+      "<content select=#one></content>"
+      "<span id='five'>55555</span>"
+      "<p id='six'>666666</p>";
+  setBodyContent(bodyContent);
+  ShadowRoot* shadowRoot = setShadowContent(shadowContent, "host");
+
+  const PositionInFlatTree startPosition(document().getElementById("one"), 0);
+  const PositionInFlatTree limitPosition(shadowRoot->getElementById("five"), 0);
+  const PositionInFlatTree endPosition(shadowRoot->getElementById("six"), 0);
+  const EphemeralRangeInFlatTree fromBToSpan(startPosition, limitPosition);
+  EXPECT_EQ("[#text \"1\"][SPAN id=\"five\"]", traverseRange(fromBToSpan));
+
+  const EphemeralRangeInFlatTree fromSpanToEnd(limitPosition, endPosition);
+  EXPECT_EQ("[#text \"55555\"][P id=\"six\"]", traverseRange(fromSpanToEnd));
 }
 
 TEST_F(EphemeralRangeTest, traversalEmptyRanges) {
-  const char* bodyContent = "<p id='host'><b id='one'></b></p>";
+  const char* bodyContent =
+      "<p id='host'>"
+      "<b id='one'>1</b>"
+      "</p>";
   setBodyContent(bodyContent);
 
   // Expect no iterations in loop for an empty EphemeralRange.
diff --git a/third_party/WebKit/Source/core/html/HTMLButtonElement.h b/third_party/WebKit/Source/core/html/HTMLButtonElement.h
index eea1848e..83576c4 100644
--- a/third_party/WebKit/Source/core/html/HTMLButtonElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLButtonElement.h
@@ -24,12 +24,11 @@
 #ifndef HTMLButtonElement_h
 #define HTMLButtonElement_h
 
-#include "core/CoreExport.h"
 #include "core/html/HTMLFormControlElement.h"
 
 namespace blink {
 
-class CORE_EXPORT HTMLButtonElement final : public HTMLFormControlElement {
+class HTMLButtonElement final : public HTMLFormControlElement {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
diff --git a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
index aefdfa3..0d585a93 100644
--- a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
@@ -41,8 +41,8 @@
   ResourceRequest resourceRequest(url);
   resourceRequest.setHTTPReferrer(SecurityPolicy::generateReferrer(
       m_referrerPolicy, url, document->outgoingReferrer()));
-  ResourceFetcher::determineRequestContext(resourceRequest, m_resourceType,
-                                           false);
+  resourceRequest.setRequestContext(
+      ResourceFetcher::determineRequestContext(m_resourceType, false));
 
   FetchRequest request(resourceRequest, initiatorInfo);
 
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
index c3b8f1e..e1ba30d 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -321,8 +321,8 @@
     return nullptr;
   }
   ResourceRequest resourceRequest(document.completeURL(href));
-  ResourceFetcher::determineRequestContext(resourceRequest,
-                                           resourceType.value(), false);
+  resourceRequest.setRequestContext(
+      ResourceFetcher::determineRequestContext(resourceType.value(), false));
 
   if (referrerPolicy != ReferrerPolicyDefault) {
     resourceRequest.setHTTPReferrer(SecurityPolicy::generateReferrer(
diff --git a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp
index 63df50a..ccecd6dc 100644
--- a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp
@@ -41,8 +41,7 @@
                                                     ResourceFetcher* fetcher) {
   DCHECK_EQ(request.resourceRequest().frameType(),
             WebURLRequest::FrameTypeNone);
-  request.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextStyle);
+  request.setRequestContext(WebURLRequest::RequestContextStyle);
   CSSStyleSheetResource* resource = toCSSStyleSheetResource(
       fetcher->requestResource(request, CSSStyleSheetResourceFactory()));
   // TODO(kouhei): Dedupe this logic w/ ScriptResource::fetch
diff --git a/third_party/WebKit/Source/core/loader/resource/DocumentResource.cpp b/third_party/WebKit/Source/core/loader/resource/DocumentResource.cpp
index 3ab496f..c6c8718 100644
--- a/third_party/WebKit/Source/core/loader/resource/DocumentResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/DocumentResource.cpp
@@ -34,8 +34,7 @@
                                                      ResourceFetcher* fetcher) {
   DCHECK_EQ(request.resourceRequest().frameType(),
             WebURLRequest::FrameTypeNone);
-  request.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextImage);
+  request.setRequestContext(WebURLRequest::RequestContextImage);
   return toDocumentResource(
       fetcher->requestResource(request, SVGDocumentResourceFactory()));
 }
diff --git a/third_party/WebKit/Source/core/loader/resource/FontResource.cpp b/third_party/WebKit/Source/core/loader/resource/FontResource.cpp
index 1488e55..28fc133 100644
--- a/third_party/WebKit/Source/core/loader/resource/FontResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/FontResource.cpp
@@ -77,8 +77,7 @@
                                   ResourceFetcher* fetcher) {
   DCHECK_EQ(request.resourceRequest().frameType(),
             WebURLRequest::FrameTypeNone);
-  request.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextFont);
+  request.setRequestContext(WebURLRequest::RequestContextFont);
   return toFontResource(
       fetcher->requestResource(request, FontResourceFactory()));
 }
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
index 65c4270a..c915425 100644
--- a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
@@ -151,8 +151,7 @@
                                     ResourceFetcher* fetcher) {
   if (request.resourceRequest().requestContext() ==
       WebURLRequest::RequestContextUnspecified) {
-    request.mutableResourceRequest().setRequestContext(
-        WebURLRequest::RequestContextImage);
+    request.setRequestContext(WebURLRequest::RequestContextImage);
   }
   if (fetcher->context().pageDismissalEventBeingDispatched()) {
     KURL requestURL = request.resourceRequest().url();
diff --git a/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.cpp b/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.cpp
index 71518b8..4f11cf3 100644
--- a/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.cpp
@@ -15,7 +15,7 @@
   DCHECK_EQ(type, LinkPrefetch);
   DCHECK_EQ(request.resourceRequest().frameType(),
             WebURLRequest::FrameTypeNone);
-  fetcher->determineRequestContext(request.mutableResourceRequest(), type);
+  request.setRequestContext(fetcher->determineRequestContext(type));
   return fetcher->requestResource(request, LinkResourceFactory(type));
 }
 
diff --git a/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp b/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp
index d3be9db..b4ba5ecd 100644
--- a/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp
@@ -41,8 +41,7 @@
                                       ResourceFetcher* fetcher) {
   DCHECK_EQ(request.resourceRequest().frameType(),
             WebURLRequest::FrameTypeNone);
-  request.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextScript);
+  request.setRequestContext(WebURLRequest::RequestContextScript);
   ScriptResource* resource = toScriptResource(
       fetcher->requestResource(request, ScriptResourceFactory()));
   if (resource && !request.integrityMetadata().isEmpty())
diff --git a/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp b/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp
index ca116558..e099c793 100644
--- a/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp
@@ -35,7 +35,7 @@
 
 namespace blink {
 
-static void applyXSLRequestProperties(ResourceRequest& request) {
+static void applyXSLRequestProperties(FetchRequest& request) {
   request.setRequestContext(WebURLRequest::RequestContextXSLT);
   // TODO(japhet): Accept: headers can be set manually on XHRs from script, in
   // the browser process, and... here. The browser process can't tell the
@@ -45,13 +45,13 @@
   DEFINE_STATIC_LOCAL(const AtomicString, acceptXSLT,
                       ("text/xml, application/xml, application/xhtml+xml, "
                        "text/xsl, application/rss+xml, application/atom+xml"));
-  request.setHTTPAccept(acceptXSLT);
+  request.mutableResourceRequest().setHTTPAccept(acceptXSLT);
 }
 
 XSLStyleSheetResource* XSLStyleSheetResource::fetchSynchronously(
     FetchRequest& request,
     ResourceFetcher* fetcher) {
-  applyXSLRequestProperties(request.mutableResourceRequest());
+  applyXSLRequestProperties(request);
   request.makeSynchronous();
   XSLStyleSheetResource* resource = toXSLStyleSheetResource(
       fetcher->requestResource(request, XSLStyleSheetResourceFactory()));
@@ -63,7 +63,7 @@
 XSLStyleSheetResource* XSLStyleSheetResource::fetch(FetchRequest& request,
                                                     ResourceFetcher* fetcher) {
   DCHECK(RuntimeEnabledFeatures::xsltEnabled());
-  applyXSLRequestProperties(request.mutableResourceRequest());
+  applyXSLRequestProperties(request);
   return toXSLStyleSheetResource(
       fetcher->requestResource(request, XSLStyleSheetResourceFactory()));
 }
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
index 81e00726..691ffb1 100644
--- a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
+++ b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
@@ -70,7 +70,14 @@
                                    false)),
       m_renderBus(AudioBus::create(numberOfOutputChannels,
                                    AudioUtilities::kRenderQuantumFrames)),
+      m_fifo(
+          WTF::wrapUnique(new PushPullFIFO(numberOfOutputChannels, kFIFOSize))),
       m_framesElapsed(0) {
+  m_callbackBufferSize = hardwareBufferSize();
+  if (!checkBufferSize()) {
+    NOTREACHED();
+  }
+
   // Create WebAudioDevice. blink::WebAudioDevice is designed to support the
   // local input (e.g. loopback from OS audio system), but Chromium's media
   // renderer does not support it currently. Thus, we use zero for the number
@@ -79,15 +86,6 @@
       0, numberOfOutputChannels, latencyHint, this, String(),
       std::move(securityOrigin)));
   DCHECK(m_webAudioDevice);
-
-  m_callbackBufferSize = m_webAudioDevice->framesPerBuffer();
-
-  if (!checkBufferSize()) {
-    NOTREACHED();
-  }
-
-  // Create a FIFO.
-  m_fifo = WTF::wrapUnique(new PushPullFIFO(numberOfOutputChannels, kFIFOSize));
 }
 
 AudioDestination::~AudioDestination() {
@@ -102,6 +100,12 @@
   CHECK_EQ(destinationData.size(), m_numberOfOutputChannels);
   CHECK_EQ(numberOfFrames, m_callbackBufferSize);
 
+  // Note that this method is called by AudioDeviceThread. If FIFO is not ready,
+  // or the requested render size is greater than FIFO size return here.
+  // (crbug.com/692423)
+  if (!m_fifo || m_fifo->length() < numberOfFrames)
+    return;
+
   m_framesElapsed -= std::min(m_framesElapsed, priorFramesSkipped);
   double outputPosition =
       m_framesElapsed / static_cast<double>(m_webAudioDevice->sampleRate()) -
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h b/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h
index 44f7213d7..7389bfc 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h
@@ -81,6 +81,10 @@
   const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
   const KURL& url() const { return m_resourceRequest.url(); }
 
+  void setRequestContext(WebURLRequest::RequestContext context) {
+    m_resourceRequest.setRequestContext(context);
+  }
+
   const String& charset() const { return m_charset; }
   void setCharset(const String& charset) { m_charset = charset; }
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
index c8111072..9ed1cee 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
@@ -46,8 +46,7 @@
                                       ResourceFetcher* fetcher) {
   DCHECK_EQ(request.resourceRequest().frameType(),
             WebURLRequest::FrameTypeNone);
-  request.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextImport);
+  request.setRequestContext(WebURLRequest::RequestContextImport);
   return toRawResource(fetcher->requestResource(
       request, RawResourceFactory(Resource::ImportResource)));
 }
@@ -101,8 +100,7 @@
                                          ResourceFetcher* fetcher) {
   DCHECK_EQ(request.resourceRequest().frameType(),
             WebURLRequest::FrameTypeNone);
-  request.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextTrack);
+  request.setRequestContext(WebURLRequest::RequestContextTrack);
   return toRawResource(fetcher->requestResource(
       request, RawResourceFactory(Resource::TextTrack)));
 }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
index 9e62580..a5eae6c5 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -208,9 +208,9 @@
   info->setFinalResponse(resource->response());
 }
 
-static WebURLRequest::RequestContext requestContextFromType(
-    bool isMainFrame,
-    Resource::Type type) {
+WebURLRequest::RequestContext ResourceFetcher::determineRequestContext(
+    Resource::Type type,
+    bool isMainFrame) {
   switch (type) {
     case Resource::MainResource:
       if (!isMainFrame)
@@ -639,17 +639,9 @@
     context().addResourceTiming(*timingInfo);
 }
 
-void ResourceFetcher::determineRequestContext(ResourceRequest& request,
-                                              Resource::Type type,
-                                              bool isMainFrame) {
-  WebURLRequest::RequestContext requestContext =
-      requestContextFromType(isMainFrame, type);
-  request.setRequestContext(requestContext);
-}
-
-void ResourceFetcher::determineRequestContext(ResourceRequest& request,
-                                              Resource::Type type) {
-  determineRequestContext(request, type, context().isMainFrame());
+WebURLRequest::RequestContext ResourceFetcher::determineRequestContext(
+    Resource::Type type) const {
+  return determineRequestContext(type, context().isMainFrame());
 }
 
 void ResourceFetcher::initializeResourceRequest(
@@ -661,7 +653,7 @@
         context().resourceRequestCachePolicy(request, type, defer));
   }
   if (request.requestContext() == WebURLRequest::RequestContextUnspecified)
-    determineRequestContext(request, type);
+    request.setRequestContext(determineRequestContext(type));
   if (type == Resource::LinkPrefetch)
     request.setHTTPHeaderField(HTTPNames::Purpose, "prefetch");
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h
index 2d33a4d..59ef02a 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h
@@ -131,10 +131,10 @@
 
   String getCacheIdentifier() const;
 
-  static void determineRequestContext(ResourceRequest&,
-                                      Resource::Type,
-                                      bool isMainFrame);
-  void determineRequestContext(ResourceRequest&, Resource::Type);
+  WARN_UNUSED_RESULT static WebURLRequest::RequestContext
+  determineRequestContext(Resource::Type, bool isMainFrame);
+  WARN_UNUSED_RESULT WebURLRequest::RequestContext determineRequestContext(
+      Resource::Type) const;
 
   void updateAllImageResourcePriorities();
 
diff --git a/third_party/WebKit/Source/platform/loader/testing/MockResource.cpp b/third_party/WebKit/Source/platform/loader/testing/MockResource.cpp
index ac4532c..6ac5161 100644
--- a/third_party/WebKit/Source/platform/loader/testing/MockResource.cpp
+++ b/third_party/WebKit/Source/platform/loader/testing/MockResource.cpp
@@ -28,8 +28,7 @@
 // static
 MockResource* MockResource::fetch(FetchRequest& request,
                                   ResourceFetcher* fetcher) {
-  request.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextSubresource);
+  request.setRequestContext(WebURLRequest::RequestContextSubresource);
   Resource* resource = fetcher->requestResource(request, MockResourceFactory());
   return static_cast<MockResource*>(resource);
 }
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 1afe4abd..ffc437e4 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -8246,8 +8246,7 @@
 static Resource* fetchManifest(Document* document, const KURL& url) {
   FetchRequest fetchRequest =
       FetchRequest(ResourceRequest(url), FetchInitiatorInfo());
-  fetchRequest.mutableResourceRequest().setRequestContext(
-      WebURLRequest::RequestContextManifest);
+  fetchRequest.setRequestContext(WebURLRequest::RequestContextManifest);
 
   return RawResource::fetchSynchronously(fetchRequest, document->fetcher());
 }
diff --git a/tools/chrome_proxy/webdriver/smoke.py b/tools/chrome_proxy/webdriver/smoke.py
index 1da694c3..78aba30b 100644
--- a/tools/chrome_proxy/webdriver/smoke.py
+++ b/tools/chrome_proxy/webdriver/smoke.py
@@ -33,6 +33,16 @@
       self.assertEqual(2, len(responses))
       for response in responses:
         self.assertHasChromeProxyViaHeader(response)
+  
+  # Ensure Chrome uses DataSaver in normal mode.
+  def testCheckPageWithNormalMode(self):
+    with TestDriver() as t:
+      t.AddChromeArg('--enable-spdy-proxy-auth')
+      t.LoadURL('http://check.googlezip.net/test.html')
+      responses = t.GetHTTPResponses()
+      self.assertNotEqual(0, len(responses))
+      for response in responses:
+        self.assertHasChromeProxyViaHeader(response)
 
   # Ensure pageload metric pingback with DataSaver.
   def testPingback(self):
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 38cfb11..75e2eb4cc 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -384,6 +384,7 @@
       'base/base_paths.cc',
       'base/base_switches.cc',
       'base/build_time.cc',
+      'base/callback_helpers.cc',
       'base/callback_internal.cc',
       'base/command_line.cc',
       'base/debug/activity_tracker.cc',
@@ -605,6 +606,7 @@
         'base/allocator/allocator_shim.cc',
         'base/allocator/allocator_shim_default_dispatch_to_glibc.cc',
         'base/memory/shared_memory_posix.cc',
+        'base/memory/shared_memory_tracker.cc',
         'base/nix/xdg_util.cc',
         'base/process/internal_linux.cc',
         'base/process/memory_linux.cc',
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index a74172d..63c1e6a 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -266,6 +266,7 @@
       'Android Tests': 'android_release_bot_minimal_symbols',
       'Cast Android (dbg)': 'android_cast_debug_static_bot',
       'Cast Linux': 'cast_release_bot',
+      'Cast Audio Linux': 'cast_audio_release_bot',
       'Linux Builder (dbg)': 'debug_bot',
       'Linux Builder (dbg)(32)': 'debug_bot_x86',
       'Linux Builder': 'release_bot',
@@ -343,7 +344,8 @@
     },
 
     'chromium.swarm': {
-      'Android Swarm': 'android_without_codecs_release_bot_minimal_symbols',
+      'Android N5 Swarm': 'android_release_bot_minimal_symbols',
+      'Android N5X Swarm': 'android_release_bot_minimal_symbols_arm64',
       'Linux Swarm': 'release_bot',
       'Mac Swarm': 'release_bot_mac_strip',
       'Windows Swarm': 'release_bot_x86',
@@ -538,6 +540,7 @@
       'Chromium Linux Codesearch Builder': 'codesearch',
       'ChromiumOS Codesearch Builder': 'codesearch',
       'cast_shell_linux': 'cast_release_trybot',
+      'cast_shell_audio_linux': 'cast_audio_release_trybot',
       'chromeos_amd64-generic_chromium_compile_only_ng': 'cros_chrome_sdk',
       'chromeos_daisy_chromium_compile_only_ng': 'cros_chrome_sdk',
       'chromeos_x86-generic_chromium_compile_only_ng': 'cros_chrome_sdk',
@@ -981,6 +984,14 @@
       'cast', 'release_trybot',
     ],
 
+    'cast_audio_release_bot': [
+      'cast', 'cast_audio', 'release_bot',
+    ],
+
+    'cast_audio_release_trybot': [
+      'cast', 'cast_audio', 'release_trybot',
+    ],
+
     'cfi_full_cfi_diag_release_static': [
       'cfi_full', 'cfi_diag', 'release', 'static',
     ],
@@ -1577,6 +1588,10 @@
       'gn_args': 'is_chromecast=true',
     },
 
+    'cast_audio': {
+      'gn_args': 'is_cast_audio_only=true enable_webrtc=false'
+    },
+
     'cfi': {
       'gn_args': 'is_cfi=true',
     },
diff --git a/tools/valgrind/asan/third_party/asan_symbolize.py b/tools/valgrind/asan/third_party/asan_symbolize.py
index 59fceaaed..1a56e44 100755
--- a/tools/valgrind/asan/third_party/asan_symbolize.py
+++ b/tools/valgrind/asan/third_party/asan_symbolize.py
@@ -23,6 +23,8 @@
 binary_name_filter = None
 fix_filename_patterns = None
 logfile = sys.stdin
+allow_system_symbolizer = True
+force_system_symbolizer = False
 
 # FIXME: merge the code that calls fix_filename().
 def fix_filename(file_name):
@@ -36,6 +38,10 @@
 def sysroot_path_filter(binary_name):
   return sysroot_path + binary_name
 
+def is_valid_arch(s):
+  return s in ["i386", "x86_64", "x86_64h", "arm", "armv6", "armv7", "armv7s",
+               "armv7k", "arm64", "powerpc64", "powerpc64le", "s390x", "s390"]
+
 def guess_arch(addr):
   # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
   if len(addr) > 10:
@@ -76,17 +82,19 @@
     cmd = [self.symbolizer_path,
            '--use-symbol-table=true',
            '--demangle=%s' % demangle,
-           '--functions=short',
+           '--functions=linkage',
            '--inlining=true',
            '--default-arch=%s' % self.default_arch]
     if self.system == 'Darwin':
       for hint in self.dsym_hints:
         cmd.append('--dsym-hint=%s' % hint)
     if DEBUG:
-      print ' '.join(cmd)
+      print(' '.join(cmd))
     try:
       result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
-                                stdout=subprocess.PIPE)
+                                stdout=subprocess.PIPE,
+                                bufsize=0,
+                                universal_newlines=True)
     except OSError:
       result = None
     return result
@@ -99,8 +107,8 @@
     try:
       symbolizer_input = '"%s" %s' % (binary, offset)
       if DEBUG:
-        print symbolizer_input
-      print >> self.pipe.stdin, symbolizer_input
+        print(symbolizer_input)
+      self.pipe.stdin.write("%s\n" % symbolizer_input)
       while True:
         function_name = self.pipe.stdout.readline().rstrip()
         if not function_name:
@@ -134,34 +142,44 @@
     super(Addr2LineSymbolizer, self).__init__()
     self.binary = binary
     self.pipe = self.open_addr2line()
+    self.output_terminator = -1
 
   def open_addr2line(self):
     addr2line_tool = 'addr2line'
     if binutils_prefix:
       addr2line_tool = binutils_prefix + addr2line_tool
-    cmd = [addr2line_tool, '-f']
+    cmd = [addr2line_tool, '-fi']
     if demangle:
       cmd += ['--demangle']
     cmd += ['-e', self.binary]
     if DEBUG:
-      print ' '.join(cmd)
+      print(' '.join(cmd))
     return subprocess.Popen(cmd,
-                            stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+                            stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+                            bufsize=0,
+                            universal_newlines=True)
 
   def symbolize(self, addr, binary, offset):
     """Overrides Symbolizer.symbolize."""
     if self.binary != binary:
       return None
+    lines = []
     try:
-      print >> self.pipe.stdin, offset
-      function_name = self.pipe.stdout.readline().rstrip()
-      file_name = self.pipe.stdout.readline().rstrip()
+      self.pipe.stdin.write("%s\n" % offset)
+      self.pipe.stdin.write("%s\n" % self.output_terminator)
+      is_first_frame = True
+      while True:
+        function_name = self.pipe.stdout.readline().rstrip()
+        file_name = self.pipe.stdout.readline().rstrip()
+        if is_first_frame:
+          is_first_frame = False
+        elif function_name in ['', '??']:
+          assert file_name == function_name
+          break
+        lines.append((function_name, file_name));
     except Exception:
-      function_name = ''
-      file_name = ''
-    file_name = fix_filename(file_name)
-    return ['%s in %s %s' % (addr, function_name, file_name)]
-
+      lines.append(('??', '??:0'))
+    return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines]
 
 class UnbufferedLineConverter(object):
   """
@@ -197,15 +215,15 @@
 
 
 class DarwinSymbolizer(Symbolizer):
-  def __init__(self, addr, binary):
+  def __init__(self, addr, binary, arch):
     super(DarwinSymbolizer, self).__init__()
     self.binary = binary
-    self.arch = guess_arch(addr)
+    self.arch = arch
     self.open_atos()
 
   def open_atos(self):
     if DEBUG:
-      print 'atos -o %s -arch %s' % (self.binary, self.arch)
+      print('atos -o %s -arch %s' % (self.binary, self.arch))
     cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
     self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
 
@@ -220,7 +238,7 @@
     #   foo(type1, type2) (in object.name) (filename.cc:80)
     match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
     if DEBUG:
-      print 'atos_line: ', atos_line
+      print('atos_line: ', atos_line)
     if match:
       function_name = match.group(1)
       function_name = re.sub('\(.*?\)', '', function_name)
@@ -259,10 +277,10 @@
   return None
 
 
-def SystemSymbolizerFactory(system, addr, binary):
+def SystemSymbolizerFactory(system, addr, binary, arch):
   if system == 'Darwin':
-    return DarwinSymbolizer(addr, binary)
-  elif system == 'Linux':
+    return DarwinSymbolizer(addr, binary, arch)
+  elif system == 'Linux' or system == 'FreeBSD':
     return Addr2LineSymbolizer(binary)
 
 
@@ -334,7 +352,7 @@
       function_name, file_name, line_no = res
       result = ['%s in %s %s:%d' % (
           addr, function_name, file_name, line_no)]
-      print result
+      print(result)
       return result
     else:
       return None
@@ -360,7 +378,7 @@
       self.frame_no = 0
       self.process_line = self.process_line_posix
 
-  def symbolize_address(self, addr, binary, offset):
+  def symbolize_address(self, addr, binary, offset, arch):
     # On non-Darwin (i.e. on platforms without .dSYM debug info) always use
     # a single symbolizer binary.
     # On Darwin, if the dsym hint producer is present:
@@ -372,29 +390,35 @@
     #     if so, reuse |last_llvm_symbolizer| which has the full set of hints;
     #  3. otherwise create a new symbolizer and pass all currently known
     #     .dSYM hints to it.
-    if not binary in self.llvm_symbolizers:
-      use_new_symbolizer = True
-      if self.system == 'Darwin' and self.dsym_hint_producer:
-        dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
-        use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
-        self.dsym_hints |= dsym_hints_for_binary
-      if self.last_llvm_symbolizer and not use_new_symbolizer:
+    result = None
+    if not force_system_symbolizer:
+      if not binary in self.llvm_symbolizers:
+        use_new_symbolizer = True
+        if self.system == 'Darwin' and self.dsym_hint_producer:
+          dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
+          use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
+          self.dsym_hints |= dsym_hints_for_binary
+        if self.last_llvm_symbolizer and not use_new_symbolizer:
+            self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
+        else:
+          self.last_llvm_symbolizer = LLVMSymbolizerFactory(
+              self.system, arch, self.dsym_hints)
           self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
-      else:
-        self.last_llvm_symbolizer = LLVMSymbolizerFactory(
-            self.system, guess_arch(addr), self.dsym_hints)
-        self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
-    # Use the chain of symbolizers:
-    # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
-    # (fall back to next symbolizer if the previous one fails).
-    if not binary in symbolizers:
-      symbolizers[binary] = ChainSymbolizer(
-          [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
-    result = symbolizers[binary].symbolize(addr, binary, offset)
+      # Use the chain of symbolizers:
+      # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
+      # (fall back to next symbolizer if the previous one fails).
+      if not binary in symbolizers:
+        symbolizers[binary] = ChainSymbolizer(
+            [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
+      result = symbolizers[binary].symbolize(addr, binary, offset)
+    else:
+      symbolizers[binary] = ChainSymbolizer([])
     if result is None:
+      if not allow_system_symbolizer:
+        raise Exception('Failed to launch or use llvm-symbolizer.')
       # Initialize system symbolizer only if other symbolizers failed.
       symbolizers[binary].append_symbolizer(
-          SystemSymbolizerFactory(self.system, addr, binary))
+          SystemSymbolizerFactory(self.system, addr, binary, arch))
       result = symbolizers[binary].symbolize(addr, binary, offset)
     # The system symbolizer must produce some result.
     assert result
@@ -414,7 +438,7 @@
     self.frame_no = 0
     for line in logfile:
       processed = self.process_line(line)
-      print '\n'.join(processed)
+      print('\n'.join(processed))
 
   def process_line_echo(self, line):
     return [line.rstrip()]
@@ -428,18 +452,28 @@
     if not match:
       return [self.current_line]
     if DEBUG:
-      print line
+      print(line)
     _, frameno_str, addr, binary, offset = match.groups()
+    arch = ""
+    # Arch can be embedded in the filename, e.g.: "libabc.dylib:x86_64h"
+    colon_pos = binary.rfind(":")
+    if colon_pos != -1:
+      maybe_arch = binary[colon_pos+1:]
+      if is_valid_arch(maybe_arch):
+        arch = maybe_arch
+        binary = binary[0:colon_pos]
+    if arch == "":
+      arch = guess_arch(addr)
     if frameno_str == '0':
       # Assume that frame #0 is the first frame of new stack trace.
       self.frame_no = 0
     original_binary = binary
     if self.binary_name_filter:
       binary = self.binary_name_filter(binary)
-    symbolized_line = self.symbolize_address(addr, binary, offset)
+    symbolized_line = self.symbolize_address(addr, binary, offset, arch)
     if not symbolized_line:
       if original_binary != binary:
-        symbolized_line = self.symbolize_address(addr, binary, offset)
+        symbolized_line = self.symbolize_address(addr, binary, offset, arch)
     return self.get_symbolized_lines(symbolized_line)
 
 
@@ -461,6 +495,8 @@
   parser.add_argument('-l','--logfile', default=sys.stdin,
                       type=argparse.FileType('r'),
                       help='set log file name to parse, default is stdin')
+  parser.add_argument('--force-system-symbolizer', action='store_true',
+                      help='don\'t use llvm-symbolizer')
   args = parser.parse_args()
   if args.path_to_cut:
     fix_filename_patterns = args.path_to_cut
@@ -475,5 +511,9 @@
     logfile = args.logfile
   else:
     logfile = sys.stdin
+  if args.force_system_symbolizer:
+    force_system_symbolizer = True
+  if force_system_symbolizer:
+    assert(allow_system_symbolizer)
   loop = SymbolizationLoop(binary_name_filter)
   loop.process_logfile()
diff --git a/ui/aura/env.cc b/ui/aura/env.cc
index c422716..1799a59 100644
--- a/ui/aura/env.cc
+++ b/ui/aura/env.cc
@@ -13,6 +13,7 @@
 #include "ui/aura/env_observer.h"
 #include "ui/aura/input_state_lookup.h"
 #include "ui/aura/mus/mus_types.h"
+#include "ui/aura/mus/os_exchange_data_provider_mus.h"
 #include "ui/aura/mus/window_port_mus.h"
 #include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
@@ -75,6 +76,9 @@
 // Env, public:
 
 Env::~Env() {
+  if (RunningInsideMus())
+    ui::OSExchangeDataProviderFactory::SetFactory(nullptr);
+
   for (EnvObserver& observer : observers_)
     observer.OnWillDestroyEnv();
   DCHECK_EQ(this, lazy_tls_ptr.Pointer()->Get());
@@ -192,8 +196,11 @@
 }
 
 void Env::Init() {
-  if (RunningInsideMus())
+  if (RunningInsideMus()) {
+    ui::OSExchangeDataProviderFactory::SetFactory(this);
     return;
+  }
+
 #if defined(USE_OZONE)
   // The ozone platform can provide its own event source. So initialize the
   // platform before creating the default event source. If running inside mus
@@ -243,4 +250,8 @@
   return NULL;
 }
 
+std::unique_ptr<ui::OSExchangeData::Provider> Env::BuildProvider() {
+  return base::MakeUnique<aura::OSExchangeDataProviderMus>();
+}
+
 }  // namespace aura
diff --git a/ui/aura/env.h b/ui/aura/env.h
index f843ca0..b6b1b2c 100644
--- a/ui/aura/env.h
+++ b/ui/aura/env.h
@@ -11,6 +11,7 @@
 #include "base/observer_list.h"
 #include "base/supports_user_data.h"
 #include "ui/aura/aura_export.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
 #include "ui/events/event_handler.h"
 #include "ui/events/event_target.h"
 #include "ui/gfx/geometry/point.h"
@@ -39,7 +40,9 @@
 class WindowTreeHost;
 
 // A singleton object that tracks general state within Aura.
-class AURA_EXPORT Env : public ui::EventTarget, public base::SupportsUserData {
+class AURA_EXPORT Env : public ui::EventTarget,
+                        public ui::OSExchangeDataProviderFactory::Factory,
+                        public base::SupportsUserData {
  public:
   enum class Mode {
     // Classic aura.
@@ -138,6 +141,9 @@
   std::unique_ptr<ui::EventTargetIterator> GetChildIterator() const override;
   ui::EventTargeter* GetEventTargeter() override;
 
+  // Overridden from ui::OSExchangeDataProviderFactory::Factory:
+  std::unique_ptr<ui::OSExchangeData::Provider> BuildProvider() override;
+
   // This is not const for tests, which may share Env across tests and so needs
   // to reset the value.
   Mode mode_;
diff --git a/ui/aura/mus/drag_drop_controller_mus.cc b/ui/aura/mus/drag_drop_controller_mus.cc
index a82841c8..ccb364dd 100644
--- a/ui/aura/mus/drag_drop_controller_mus.cc
+++ b/ui/aura/mus/drag_drop_controller_mus.cc
@@ -137,23 +137,25 @@
   // we start showing an image representation of the drag under he cursor.
 
   base::RunLoop run_loop;
-  WindowMus* source_window_mus = WindowMus::Get(source_window);
+  WindowMus* root_window_mus = WindowMus::Get(root_window);
   const uint32_t change_id =
-      drag_drop_controller_host_->CreateChangeIdForDrag(source_window_mus);
-  CurrentDragState current_drag_state = {source_window_mus->server_id(),
+      drag_drop_controller_host_->CreateChangeIdForDrag(root_window_mus);
+  CurrentDragState current_drag_state = {root_window_mus->server_id(),
                                          change_id, ui::mojom::kDropEffectNone,
                                          data, run_loop.QuitClosure()};
   base::AutoReset<CurrentDragState*> resetter(&current_drag_state_,
                                               &current_drag_state);
-  std::map<std::string, std::vector<uint8_t>> drag_data =
-      static_cast<const aura::OSExchangeDataProviderMus&>(data.provider())
-          .GetData();
-  window_tree_->PerformDragDrop(change_id, source_window_mus->server_id(),
-                                mojo::MapToUnorderedMap(drag_data),
-                                drag_operations);
 
   base::MessageLoop* loop = base::MessageLoop::current();
   base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
+
+  std::map<std::string, std::vector<uint8_t>> drag_data =
+      static_cast<const aura::OSExchangeDataProviderMus&>(data.provider())
+          .GetData();
+  window_tree_->PerformDragDrop(change_id, root_window_mus->server_id(),
+                                mojo::MapToUnorderedMap(drag_data),
+                                drag_operations);
+
   run_loop.Run();
 
   return current_drag_state.completed_action;
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc
index e59ccba7..fc09504 100644
--- a/ui/aura/mus/window_port_mus.cc
+++ b/ui/aura/mus/window_port_mus.cc
@@ -71,6 +71,10 @@
   window_tree_client_->SetEventTargetingPolicy(this, policy);
 }
 
+void WindowPortMus::SetCanAcceptDrops(bool can_accept_drops) {
+  window_tree_client_->SetCanAcceptDrops(this, can_accept_drops);
+}
+
 void WindowPortMus::Embed(
     ui::mojom::WindowTreeClientPtr client,
     uint32_t flags,
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h
index 6677505f..c1f6e35 100644
--- a/ui/aura/mus/window_port_mus.h
+++ b/ui/aura/mus/window_port_mus.h
@@ -59,6 +59,9 @@
   // Sets the EventTargetingPolicy, default is TARGET_AND_DESCENDANTS.
   void SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy policy);
 
+  // Sets whether this window can accept drops, defaults to false.
+  void SetCanAcceptDrops(bool can_accept_drops);
+
   // Embeds a new client in this Window. See WindowTreeClient::Embed() for
   // details on arguments.
   void Embed(ui::mojom::WindowTreeClientPtr client,
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index 3574d7186..82f54f0 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -826,9 +826,10 @@
   test_observers_.RemoveObserver(observer);
 }
 
-void WindowTreeClient::SetCanAcceptDrops(Id window_id, bool can_accept_drops) {
+void WindowTreeClient::SetCanAcceptDrops(WindowMus* window,
+                                         bool can_accept_drops) {
   DCHECK(tree_);
-  tree_->SetCanAcceptDrops(window_id, can_accept_drops);
+  tree_->SetCanAcceptDrops(window->server_id(), can_accept_drops);
 }
 
 void WindowTreeClient::SetEventTargetingPolicy(
@@ -1268,10 +1269,9 @@
 void WindowTreeClient::OnPerformDragDropCompleted(uint32_t change_id,
                                                   bool success,
                                                   uint32_t action_taken) {
-  if (drag_drop_controller_->DoesChangeIdMatchDragChangeId(change_id)) {
-    OnChangeCompleted(change_id, success);
+  OnChangeCompleted(change_id, success);
+  if (drag_drop_controller_->DoesChangeIdMatchDragChangeId(change_id))
     drag_drop_controller_->OnPerformDragDropCompleted(action_taken);
-  }
 }
 
 void WindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) {
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index dade5871..6307371 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -110,7 +110,7 @@
   ClientSpecificId client_id() const { return client_id_; }
 
   void SetCanFocus(Window* window, bool can_focus);
-  void SetCanAcceptDrops(Id window_id, bool can_accept_drops);
+  void SetCanAcceptDrops(WindowMus* window, bool can_accept_drops);
   void SetEventTargetingPolicy(WindowMus* window,
                                ui::mojom::EventTargetingPolicy policy);
   void SetPredefinedCursor(WindowMus* window,
diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn
index 3d71046..643971c 100644
--- a/ui/display/BUILD.gn
+++ b/ui/display/BUILD.gn
@@ -22,8 +22,6 @@
     "display_list.h",
     "display_observer.cc",
     "display_observer.h",
-    "display_snapshot_mojo.cc",
-    "display_snapshot_mojo.h",
     "display_switches.cc",
     "display_switches.h",
     "fake_display_delegate.cc",
diff --git a/ui/display/mojo/display_snapshot_mojo.typemap b/ui/display/mojo/display_snapshot_mojo.typemap
index 5a831be..bd06b0fb 100644
--- a/ui/display/mojo/display_snapshot_mojo.typemap
+++ b/ui/display/mojo/display_snapshot_mojo.typemap
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 mojom = "//ui/display/mojo/display_snapshot_mojo.mojom"
-public_headers = [ "//ui/display/display_snapshot_mojo.h" ]
+public_headers = [ "//ui/display/types/display_snapshot_mojo.h" ]
 traits_headers = [ "//ui/display/mojo/display_snapshot_mojo_struct_traits.h" ]
 sources = [
   "//ui/display/mojo/display_snapshot_mojo_struct_traits.cc",
diff --git a/ui/display/mojo/display_snapshot_mojo_struct_traits.h b/ui/display/mojo/display_snapshot_mojo_struct_traits.h
index bf4f584..0ce011efe 100644
--- a/ui/display/mojo/display_snapshot_mojo_struct_traits.h
+++ b/ui/display/mojo/display_snapshot_mojo_struct_traits.h
@@ -5,9 +5,9 @@
 #ifndef UI_DISPLAY_MOJO_DISPLAY_SNAPSHOT_MOJO_STRUCT_TRAITS_H_
 #define UI_DISPLAY_MOJO_DISPLAY_SNAPSHOT_MOJO_STRUCT_TRAITS_H_
 
-#include "ui/display/display_snapshot_mojo.h"
 #include "ui/display/mojo/display_snapshot_mojo.mojom.h"
 #include "ui/display/types/display_mode.h"
+#include "ui/display/types/display_snapshot_mojo.h"
 
 namespace mojo {
 
diff --git a/ui/display/mojo/display_struct_traits_unittest.cc b/ui/display/mojo/display_struct_traits_unittest.cc
index 119f768..e828ab7 100644
--- a/ui/display/mojo/display_struct_traits_unittest.cc
+++ b/ui/display/mojo/display_struct_traits_unittest.cc
@@ -10,10 +10,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display.h"
 #include "ui/display/display_layout.h"
-#include "ui/display/display_snapshot_mojo.h"
 #include "ui/display/mojo/display_struct_traits_test.mojom.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/display/types/display_mode.h"
+#include "ui/display/types/display_snapshot_mojo.h"
 #include "ui/display/types/gamma_ramp_rgb_entry.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/ui/display/types/BUILD.gn b/ui/display/types/BUILD.gn
index b4053c4..9cef99b 100644
--- a/ui/display/types/BUILD.gn
+++ b/ui/display/types/BUILD.gn
@@ -10,6 +10,8 @@
     "display_mode.h",
     "display_snapshot.cc",
     "display_snapshot.h",
+    "display_snapshot_mojo.cc",
+    "display_snapshot_mojo.h",
     "display_types_export.h",
     "fake_display_controller.h",
     "gamma_ramp_rgb_entry.h",
diff --git a/ui/display/display_snapshot_mojo.cc b/ui/display/types/display_snapshot_mojo.cc
similarity index 97%
rename from ui/display/display_snapshot_mojo.cc
rename to ui/display/types/display_snapshot_mojo.cc
index 53b1779..adee70dc 100644
--- a/ui/display/display_snapshot_mojo.cc
+++ b/ui/display/types/display_snapshot_mojo.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/display/display_snapshot_mojo.h"
+#include "ui/display/types/display_snapshot_mojo.h"
 
 #include "base/memory/ptr_util.h"
 #include "ui/display/types/display_constants.h"
diff --git a/ui/display/display_snapshot_mojo.h b/ui/display/types/display_snapshot_mojo.h
similarity index 92%
rename from ui/display/display_snapshot_mojo.h
rename to ui/display/types/display_snapshot_mojo.h
index fb669fe..1b0c50b 100644
--- a/ui/display/display_snapshot_mojo.h
+++ b/ui/display/types/display_snapshot_mojo.h
@@ -8,13 +8,13 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "ui/display/display_export.h"
 #include "ui/display/types/display_snapshot.h"
+#include "ui/display/types/display_types_export.h"
 
 namespace display {
 
 // DisplaySnapshot implementation that can be used with Mojo IPC.
-class DISPLAY_EXPORT DisplaySnapshotMojo : public DisplaySnapshot {
+class DISPLAY_TYPES_EXPORT DisplaySnapshotMojo : public DisplaySnapshot {
  public:
   DisplaySnapshotMojo(int64_t display_id,
                       const gfx::Point& origin,
diff --git a/ui/login/account_picker/screen_account_picker.js b/ui/login/account_picker/screen_account_picker.js
index d66258e..572404d 100644
--- a/ui/login/account_picker/screen_account_picker.js
+++ b/ui/login/account_picker/screen_account_picker.js
@@ -35,6 +35,8 @@
       'showBannerMessage',
       'showUserPodCustomIcon',
       'hideUserPodCustomIcon',
+      'setUserPodFingerprintIcon',
+      'removeUserPodFingerprintIcon',
       'disablePinKeyboardForUser',
       'setAuthType',
       'setTouchViewState',
@@ -419,6 +421,23 @@
     },
 
     /**
+     * Set a fingerprint icon in the user pod of |username|.
+     * @param {string} username Username of the selected user
+     * @param {number} state Fingerprint unlock state
+     */
+    setUserPodFingerprintIcon: function(username, state) {
+      $('pod-row').setUserPodFingerprintIcon(username, state);
+    },
+
+    /**
+     * Removes the fingerprint icon in the user pod of |username|.
+     * @param {string} username Username of the selected user.
+     */
+    removeUserPodFingerprintIcon: function(username) {
+      $('pod-row').removeUserPodFingerprintIcon(username);
+    },
+
+    /**
      * Sets the authentication type used to authenticate the user.
      * @param {string} username Username of selected user
      * @param {number} authType Authentication type, must be a valid value in
diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css
index 64e25f6e..8130e385 100644
--- a/ui/login/account_picker/user_pod_row.css
+++ b/ui/login/account_picker/user_pod_row.css
@@ -415,6 +415,7 @@
   display: none;
 }
 
+.fingerprint-icon-container,
 .custom-icon-container {
   display: flex;
   flex: none;
@@ -554,6 +555,42 @@
   background-image: url(chrome://theme/IDR_KIOSK_APP_USER_POD_ICON);
 }
 
+.fingerprint-icon-container.hidden {
+  display: none;
+}
+
+.fingerprint-icon-container.default .fingerprint-icon-image {
+  background-image: url(../../webui/resources/images/fingerprint_default.svg);
+}
+
+.fingerprint-icon-container.default:hover .fingerprint-icon-image {
+  background-image: url(../../webui/resources/images/fingerprint_signin.svg);
+}
+
+.fingerprint-icon-container.signin .fingerprint-icon-image {
+  background-image: url(../../webui/resources/images/fingerprint_signin.svg);
+}
+
+.fingerprint-icon-container.failed .fingerprint-icon-image {
+  background-image: url(../../webui/resources/images/fingerprint_failed.svg);
+}
+
+.pod input[type='password'].hidden::-webkit-input-placeholder {
+  color: grey;
+}
+
+.pod input[type='password'].default::-webkit-input-placeholder {
+  color: grey;
+}
+
+.pod input[type='password'].signin::-webkit-input-placeholder {
+  color: var(--google-blue-500);
+}
+
+.pod input[type='password'].failed::-webkit-input-placeholder {
+  color: var(--google-red-500);
+}
+
 .action-box-menu {
   display: none;
   z-index: 6;
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index c52ccfa3..13a1c64 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -125,6 +125,32 @@
     5: 'forceOfflinePassword'
   };
 
+  /**
+   * Supported fingerprint unlock states.
+   * @enum {number}
+   * @const
+   */
+  var FINGERPRINT_STATES = {
+    HIDDEN: 0,
+    DEFAULT: 1,
+    SIGNIN: 2,
+    FAILED: 3,
+  };
+
+  /**
+   * The fingerprint states to classes mapping.
+   * {@code state} properties indicate current fingerprint unlock state.
+   * {@code class} properties are CSS classes used to set the icons' background
+   * and password placeholder color.
+   * @const {Array<{type: !number, class: !string}>}
+   */
+  var FINGERPRINT_STATES_MAPPING = [
+    {state: FINGERPRINT_STATES.HIDDEN, class: 'hidden'},
+    {state: FINGERPRINT_STATES.DEFAULT, class: 'default'},
+    {state: FINGERPRINT_STATES.SIGNIN, class: 'signin'},
+    {state: FINGERPRINT_STATES.FAILED, class: 'failed'}
+  ];
+
   // Focus and tab order are organized as follows:
   //
   // (1) all user pods have tab index 1 so they are traversed first;
@@ -711,6 +737,13 @@
      */
     userClickAuthAllowed_: false,
 
+    /**
+     * Whether the user has recently authenticated with fingerprint.
+     * @type {boolean}
+     * @private
+     */
+    fingerprintAuthenticated_: false,
+
     /** @override */
     decorate: function() {
       this.tabIndex = UserPodTabOrder.POD_INPUT;
@@ -750,6 +783,15 @@
       this.actionBoxRemoveUserWarningButtonElement.addEventListener('keydown',
           this.handleRemoveUserConfirmationKeyDown_.bind(this));
 
+      if (this.fingerprintIconElement) {
+        this.fingerprintIconElement.addEventListener(
+            'mouseover', this.handleFingerprintIconMouseOver_.bind(this));
+        this.fingerprintIconElement.addEventListener(
+            'mouseout', this.handleFingerprintIconMouseOut_.bind(this));
+        this.fingerprintIconElement.addEventListener(
+            'mousedown', stopEventPropagation);
+      }
+
       var customIcon = this.customIconElement;
       customIcon.parentNode.replaceChild(new UserPodCustomIcon(), customIcon);
     },
@@ -1096,6 +1138,14 @@
     },
 
     /**
+     * Gets the fingerprint icon area.
+     * @type {!HTMLDivElement}
+     */
+    get fingerprintIconElement() {
+      return this.querySelector('.fingerprint-icon-container');
+    },
+
+    /**
      * Updates the user pod element.
      */
     update: function() {
@@ -1216,6 +1266,10 @@
       this.userTypeIconAreaElement.hidden = false;
     },
 
+    isFingerprintIconShown: function() {
+      return this.fingerprintIconElement && !this.fingerprintIconElement.hidden;
+    },
+
     /**
      * The user that this pod represents.
      * @type {!Object}
@@ -1412,6 +1466,10 @@
         this.classList.toggle('signing-in', true);
         chrome.send('attemptUnlock', [this.user.username]);
       } else if (this.isAuthTypePassword) {
+        if (this.fingerprintAuthenticated_) {
+          this.fingerprintAuthenticated_ = false;
+          return true;
+        }
         var pinValue = this.pinKeyboard ? this.pinKeyboard.value : '';
         var password = this.passwordElement.value || pinValue;
         if (!password)
@@ -1822,6 +1880,50 @@
     },
 
     /**
+     * Handles mouseover event on fingerprint icon.
+     * @param {Event} e MouseOver event.
+     */
+    handleFingerprintIconMouseOver_: function(e) {
+      var bubbleContent = document.createElement('div');
+      bubbleContent.textContent =
+          loadTimeData.getString('fingerprintIconMessage');
+      this.passwordElement.placeholder =
+          loadTimeData.getString('fingerprintHint');
+
+      /** @const */ var BUBBLE_OFFSET = 25;
+      /** @const */ var BUBBLE_PADDING = -8;
+      var attachment = this.isPinShown() ? cr.ui.Bubble.Attachment.RIGHT :
+                                           cr.ui.Bubble.Attachment.BOTTOM;
+      var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
+      $('bubble').showContentForElement(
+          bubbleAnchor, attachment, bubbleContent, BUBBLE_OFFSET,
+          BUBBLE_PADDING, true);
+    },
+
+    /**
+     * Handles mouseout event on fingerprint icon.
+     * @param {Event} e MouseOut event.
+     */
+    handleFingerprintIconMouseOut_: function(e) {
+      var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
+      $('bubble').hideForElement(bubbleAnchor);
+      this.passwordElement.placeholder = loadTimeData.getString(
+          this.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
+                              'passwordHint');
+    },
+
+    /**
+     * Returns bubble anchor of the fingerprint icon.
+     * @return {!HTMLElement} Anchor element of the bubble.
+     */
+    getBubbleAnchorForFingerprintIcon_: function() {
+      var bubbleAnchor = this;
+      if (this.isPinShown())
+        bubbleAnchor = (this.getElementsByClassName('auth-container'))[0];
+      return bubbleAnchor;
+    },
+
+    /**
      * Handles a keydown event on remove user confirmation button.
      * @param {Event} e KeyDown event.
      */
@@ -1899,8 +2001,14 @@
      * button color and state and hides the error popup bubble.
      */
     updateInput_: function() {
-      if (this.submitButton)
-        this.submitButton.disabled = this.passwordElement.value.length <= 0;
+      if (this.submitButton) {
+        this.submitButton.disabled = this.passwordElement.value.length == 0;
+        if (this.isFingerprintIconShown()) {
+          this.submitButton.hidden = this.passwordElement.value.length == 0;
+        } else {
+          this.submitButton.hidden = false;
+        }
+      }
       this.showError = false;
       $('bubble').hide();
     },
@@ -3001,6 +3109,9 @@
       // immediatelly.
       pod.customIconElement.setTooltip(
           icon.tooltip || {text: '', autoshow: false});
+
+      // Hide fingerprint icon when custom icon is shown.
+      this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.HIDDEN);
     },
 
     /**
@@ -3037,6 +3148,100 @@
 
       // TODO(tengs): Allow option for a fading transition.
       pod.customIconElement.hide();
+
+      // Show fingerprint icon if applicable.
+      this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.DEFAULT);
+    },
+
+    /**
+     * Set a fingerprint icon in the user pod of |username|.
+     * @param {string} username Username of the selected user
+     * @param {number} state Fingerprint unlock state
+     */
+    setUserPodFingerprintIcon: function(username, state) {
+      var pod = this.getPodWithUsername_(username);
+      if (pod == null) {
+        console.error(
+            'Unable to set user pod fingerprint icon: user pod not found.');
+        return;
+      }
+      pod.fingerprintAuthenticated_ = false;
+      if (!pod.fingerprintIconElement)
+        return;
+      if (!pod.user.allowFingerprint || state == FINGERPRINT_STATES.HIDDEN ||
+          !pod.customIconElement.hidden) {
+        pod.fingerprintIconElement.hidden = true;
+        pod.submitButton.hidden = false;
+        return;
+      }
+
+      FINGERPRINT_STATES_MAPPING.forEach(function(icon) {
+          pod.fingerprintIconElement.classList.toggle(
+              icon.class, state == icon.state);
+      });
+      pod.fingerprintIconElement.hidden = false;
+      pod.submitButton.hidden = pod.passwordElement.value.length == 0;
+      this.updatePasswordField_(pod, state);
+      if (state == FINGERPRINT_STATES.DEFAULT)
+        return;
+
+      pod.fingerprintAuthenticated_ = true;
+      this.setActivatedPod(pod);
+      if (state == FINGERPRINT_STATES.FAILED) {
+        /** @const */ var RESET_ICON_TIMEOUT_MS = 500;
+        setTimeout(
+            this.resetIconAndPasswordField_.bind(this, pod),
+            RESET_ICON_TIMEOUT_MS);
+      }
+    },
+
+    /**
+     * Reset the fingerprint icon and password field.
+     * @param {UserPod} pod Pod to reset.
+     */
+    resetIconAndPasswordField_: function(pod) {
+      if (!pod.fingerprintIconElement)
+        return;
+      this.setUserPodFingerprintIcon(
+          pod.user.username, FINGERPRINT_STATES.DEFAULT);
+    },
+
+    /**
+     * Remove the fingerprint icon in the user pod.
+     * @param {string} username Username of the selected user
+     */
+    removeUserPodFingerprintIcon: function(username) {
+      var pod = this.getPodWithUsername_(username);
+      if (pod == null) {
+        console.error('No user pod found (when removing fingerprint icon).');
+        return;
+      }
+      this.resetIconAndPasswordField_(pod);
+      if (pod.fingerprintIconElement) {
+        pod.fingerprintIconElement.parentNode.removeChild(
+            pod.fingerprintIconElement);
+      }
+      pod.submitButton.hidden = false;
+    },
+
+    /**
+     * Updates the password field in the user pod.
+     * @param {UserPod} pod Pod to update.
+     * @param {number} state Fingerprint unlock state
+     */
+    updatePasswordField_: function(pod, state) {
+      FINGERPRINT_STATES_MAPPING.forEach(function(item) {
+        pod.passwordElement.classList.toggle(item.class, state == item.state);
+      });
+      var placeholderStr = loadTimeData.getString(
+          pod.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
+                             'passwordHint');
+      if (state == FINGERPRINT_STATES.SIGNIN) {
+        placeholderStr = loadTimeData.getString('fingerprintSigningin');
+      } else if (state == FINGERPRINT_STATES.FAILED) {
+        placeholderStr = loadTimeData.getString('fingerprintSigninFailed');
+      }
+      pod.passwordElement.placeholder = placeholderStr;
     },
 
     /**
@@ -3308,6 +3513,8 @@
           pod.isActionBoxMenuHovered = false;
           pod.classList.remove('focused');
           pod.setPinVisibility(false);
+          this.setUserPodFingerprintIcon(
+              pod.user.username, FINGERPRINT_STATES.HIDDEN);
           // On Desktop, the faded style is not set correctly, so we should
           // manually fade out non-focused pods if there is a focused pod.
           if (pod.user.isDesktopUser && podToFocus)
@@ -3347,6 +3554,8 @@
         this.firstShown_ = false;
         this.lastFocusedPod_ = podToFocus;
         this.scrollFocusedPodIntoView();
+        this.setUserPodFingerprintIcon(
+            podToFocus.user.username, FINGERPRINT_STATES.DEFAULT);
       } else {
         chrome.send('noPodFocused');
       }
diff --git a/ui/login/account_picker/user_pod_template.html b/ui/login/account_picker/user_pod_template.html
index d09d3cd..25948b4 100644
--- a/ui/login/account_picker/user_pod_template.html
+++ b/ui/login/account_picker/user_pod_template.html
@@ -46,6 +46,12 @@
     <div class="auth-container">
       <!-- Password Authentication -->
       <div class="custom-icon-container" hidden></div>
+<if expr="chromeos">
+      <div class="fingerprint-icon-container" hidden
+           i18n-values="aria-label:fingerprintIconMessage">
+        <div class="custom-icon fingerprint-icon-image"></div>
+      </div>
+</if>
       <div class="password-entry-container">
         <div class="password-container">
           <input type="password" class="password"
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index 6efc8ff..c991bfc5 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -307,6 +307,8 @@
   if (!params.accept_events) {
     aura::WindowPortMus::Get(window())->SetEventTargetingPolicy(
         ui::mojom::EventTargetingPolicy::NONE);
+  } else {
+    aura::WindowPortMus::Get(content_window)->SetCanAcceptDrops(true);
   }
 }
 
diff --git a/ui/views/mus/mus_client.cc b/ui/views/mus/mus_client.cc
index cc3624b..d03fe330 100644
--- a/ui/views/mus/mus_client.cc
+++ b/ui/views/mus/mus_client.cc
@@ -18,7 +18,6 @@
 #include "ui/aura/env.h"
 #include "ui/aura/mus/capture_synchronizer.h"
 #include "ui/aura/mus/mus_context_factory.h"
-#include "ui/aura/mus/os_exchange_data_provider_mus.h"
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/mus/window_tree_host_mus.h"
@@ -112,8 +111,6 @@
   clipboard->Init(connector);
   ui::Clipboard::SetClipboardForCurrentThread(std::move(clipboard));
 
-  ui::OSExchangeDataProviderFactory::SetFactory(this);
-
   ViewsDelegate::GetInstance()->set_native_widget_factory(
       base::Bind(&MusClient::CreateNativeWidget, base::Unretained(this)));
 }
@@ -297,8 +294,4 @@
   return nullptr;
 }
 
-std::unique_ptr<OSExchangeData::Provider> MusClient::BuildProvider() {
-  return base::MakeUnique<aura::OSExchangeDataProviderMus>();
-}
-
 }  // namespace views
diff --git a/ui/views/mus/mus_client.h b/ui/views/mus/mus_client.h
index 3e881c5d..829a049 100644
--- a/ui/views/mus/mus_client.h
+++ b/ui/views/mus/mus_client.h
@@ -15,7 +15,6 @@
 #include "services/service_manager/public/cpp/identity.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/mus/window_tree_client_delegate.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
 #include "ui/views/mus/mus_export.h"
 #include "ui/views/mus/screen_mus_delegate.h"
 #include "ui/views/widget/widget.h"
@@ -61,10 +60,8 @@
 // MusClient establishes a connection to mus and sets up necessary state so that
 // aura and views target mus. This class is useful for typical clients, not the
 // WindowManager. Most clients don't create this directly, rather use AuraInit.
-class VIEWS_MUS_EXPORT MusClient
-    : public aura::WindowTreeClientDelegate,
-      public ScreenMusDelegate,
-      public ui::OSExchangeDataProviderFactory::Factory {
+class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
+                                   public ScreenMusDelegate {
  public:
   // Most clients should use AuraInit, which creates a MusClient.
   // |create_wm_state| indicates whether MusClient should create a wm::WMState.
@@ -135,9 +132,6 @@
   void OnWindowManagerFrameValuesChanged() override;
   aura::Window* GetWindowAtScreenPoint(const gfx::Point& point) override;
 
-  // ui:OSExchangeDataProviderFactory::Factory:
-  std::unique_ptr<OSExchangeData::Provider> BuildProvider() override;
-
   static MusClient* instance_;
 
   service_manager::Identity identity_;
diff --git a/ui/webui/resources/images/fingerprint_default.svg b/ui/webui/resources/images/fingerprint_default.svg
new file mode 100644
index 0000000..0be4db1
--- /dev/null
+++ b/ui/webui/resources/images/fingerprint_default.svg
@@ -0,0 +1 @@
+<svg width="27" height="27" viewBox="0 0 27 27" xmlns="http://www.w3.org/2000/svg"><title>fingerprint_grey_1x</title><g fill="none" fill-rule="evenodd" opacity=".34"><path d="M20.036 5.03c-.09 0-.174-.024-.26-.063-2.153-1.114-4.026-1.592-6.265-1.592-2.232 0-4.336.534-6.265 1.586-.276.147-.613.052-.765-.224-.146-.275-.05-.613.225-.765 2.098-1.14 4.387-1.72 6.806-1.72 2.398 0 4.49.53 6.785 1.716.276.14.382.483.242.76-.1.19-.298.303-.5.303zM3.937 10.934c-.112 0-.224-.034-.326-.1-.252-.18-.314-.53-.134-.783C4.59 8.477 6.013 7.24 7.7 6.368c3.54-1.83 8.06-1.834 11.605-.012 1.682.867 3.1 2.093 4.22 3.656.18.254.123.602-.13.782-.254.18-.608.124-.788-.13-1.013-1.416-2.295-2.53-3.814-3.306-3.23-1.66-7.352-1.654-10.575.01-1.524.788-2.812 1.908-3.82 3.336-.112.152-.286.23-.46.23zm7.037 13.573c-.146 0-.287-.056-.4-.17-.972-.983-1.5-1.607-2.26-2.963-.777-1.384-1.187-3.077-1.187-4.888 0-3.34 2.857-6.064 6.373-6.064s6.373 2.717 6.373 6.064c0 .31-.253.562-.562.562-.31 0-.562-.254-.562-.563 0-2.723-2.35-4.94-5.248-4.94-2.89 0-5.248 2.217-5.248 4.94 0 1.62.36 3.116 1.04 4.337.726 1.293 1.21 1.85 2.076 2.722.22.22.22.58-.005.793-.102.117-.248.168-.39.168zm8.06-2.08c-1.338 0-2.513-.34-3.486-.997-1.67-1.135-2.672-2.98-2.672-4.938 0-.31.253-.562.562-.562.31 0 .563.253.563.563 0 1.58.816 3.076 2.183 4.005.793.54 1.727.804 2.852.804.27 0 .726-.028 1.176-.107.304-.056.597.152.653.456.056.304-.152.597-.456.653-.658.118-1.215.124-1.372.124zM16.77 24.75c-.05 0-.1-.006-.146-.023-1.794-.49-2.964-1.153-4.18-2.362-1.57-1.564-2.435-3.65-2.435-5.872 0-1.83 1.552-3.314 3.465-3.314 1.912 0 3.465 1.484 3.465 3.313 0 1.203 1.052 2.188 2.34 2.188 1.288 0 2.34-.978 2.34-2.188 0-4.24-3.656-7.69-8.15-7.69-3.2 0-6.12 1.78-7.437 4.535-.44.91-.658 1.974-.658 3.155 0 .878.08 2.262.748 4.056.107.293-.04.613-.332.726-.292.107-.613-.04-.726-.332-.55-1.48-.82-2.93-.82-4.45 0-1.35.258-2.576.77-3.64 1.502-3.138 4.82-5.168 8.45-5.168 5.112 0 9.274 3.954 9.274 8.814 0 1.828-1.558 3.313-3.465 3.313-1.906 0-3.464-1.484-3.464-3.312 0-1.204-1.052-2.188-2.34-2.188-1.288 0-2.34.98-2.34 2.188 0 1.918.748 3.724 2.104 5.074 1.063 1.057 2.098 1.642 3.684 2.076.298.084.478.393.394.69-.067.25-.292.412-.54.412z" fill="#000"/><path d="M0 0h27v27H0"/></g></svg>
\ No newline at end of file
diff --git a/ui/webui/resources/images/fingerprint_failed.svg b/ui/webui/resources/images/fingerprint_failed.svg
new file mode 100644
index 0000000..314ee0c6
--- /dev/null
+++ b/ui/webui/resources/images/fingerprint_failed.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#E51C23">
+    <path fill="none" d="M0 0h24v24H0V0z"/>
+    <path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/>
+</svg>
diff --git a/ui/webui/resources/images/fingerprint_signin.svg b/ui/webui/resources/images/fingerprint_signin.svg
new file mode 100644
index 0000000..dc66b50
--- /dev/null
+++ b/ui/webui/resources/images/fingerprint_signin.svg
@@ -0,0 +1 @@
+<svg width="27" height="27" viewBox="0 0 27 27" xmlns="http://www.w3.org/2000/svg"><title>fingerprint_blue_1x</title><g fill="none" fill-rule="evenodd"><path d="M20.036 5.03c-.09 0-.174-.024-.26-.063-2.153-1.114-4.026-1.592-6.265-1.592-2.232 0-4.336.534-6.265 1.586-.276.147-.613.052-.765-.224-.146-.275-.05-.613.225-.765 2.098-1.14 4.387-1.72 6.806-1.72 2.398 0 4.49.53 6.785 1.716.276.14.382.483.242.76-.1.19-.298.303-.5.303zM3.937 10.934c-.112 0-.224-.034-.326-.1-.252-.18-.314-.53-.134-.783C4.59 8.477 6.013 7.24 7.7 6.368c3.54-1.83 8.06-1.834 11.605-.012 1.682.867 3.1 2.093 4.22 3.656.18.254.123.602-.13.782-.254.18-.608.124-.788-.13-1.013-1.416-2.295-2.53-3.814-3.306-3.23-1.66-7.352-1.654-10.575.01-1.524.788-2.812 1.908-3.82 3.336-.112.152-.286.23-.46.23zm7.037 13.573c-.146 0-.287-.056-.4-.17-.972-.983-1.5-1.607-2.26-2.963-.777-1.384-1.187-3.077-1.187-4.888 0-3.34 2.857-6.064 6.373-6.064s6.373 2.717 6.373 6.064c0 .31-.253.562-.562.562-.31 0-.562-.254-.562-.563 0-2.723-2.35-4.94-5.248-4.94-2.89 0-5.248 2.217-5.248 4.94 0 1.62.36 3.116 1.04 4.337.726 1.293 1.21 1.85 2.076 2.722.22.22.22.58-.005.793-.102.117-.248.168-.39.168zm8.06-2.08c-1.338 0-2.513-.34-3.486-.997-1.67-1.135-2.672-2.98-2.672-4.938 0-.31.253-.562.562-.562.31 0 .563.253.563.563 0 1.58.816 3.076 2.183 4.005.793.54 1.727.804 2.852.804.27 0 .726-.028 1.176-.107.304-.056.597.152.653.456.056.304-.152.597-.456.653-.658.118-1.215.124-1.372.124zM16.77 24.75c-.05 0-.1-.006-.146-.023-1.794-.49-2.964-1.153-4.18-2.362-1.57-1.564-2.435-3.65-2.435-5.872 0-1.83 1.552-3.314 3.465-3.314 1.912 0 3.465 1.484 3.465 3.313 0 1.203 1.052 2.188 2.34 2.188 1.288 0 2.34-.978 2.34-2.188 0-4.24-3.656-7.69-8.15-7.69-3.2 0-6.12 1.78-7.437 4.535-.44.91-.658 1.974-.658 3.155 0 .878.08 2.262.748 4.056.107.293-.04.613-.332.726-.292.107-.613-.04-.726-.332-.55-1.48-.82-2.93-.82-4.45 0-1.35.258-2.576.77-3.64 1.502-3.138 4.82-5.168 8.45-5.168 5.112 0 9.274 3.954 9.274 8.814 0 1.828-1.558 3.313-3.465 3.313-1.906 0-3.464-1.484-3.464-3.312 0-1.204-1.052-2.188-2.34-2.188-1.288 0-2.34.98-2.34 2.188 0 1.918.748 3.724 2.104 5.074 1.063 1.057 2.098 1.642 3.684 2.076.298.084.478.393.394.69-.067.25-.292.412-.54.412z" fill="#4285F4"/><path d="M0 0h27v27H0"/></g></svg>
\ No newline at end of file