diff --git a/DEPS b/DEPS
index 3aa588a8..affb7e8 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # 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': '9ea894b4d030b55e377fc3858ebde12198f205ce',
+  'skia_revision': '67116384368195913ec014972b4fc38de2087fb8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '661a53a29a09544439cb49076cd9411f2c052e61',
+  'v8_revision': 'a559520badecf7f9701fc1b20d027c19006f8259',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # 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': '4741b291f462c0c4a5de4abf1653c3b3c87b613a',
+  'pdfium_revision': 'fff400a5df032c2203eef9f76a5dbb164672df3d',
   # 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': 'a067dd2f2b17fc0cb7057ac4500b07590c596e34',
+  'catapult_revision': '9e6944a8f3106212e60d36add9a357964bf55373',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/base/callback_list_unittest.nc b/base/callback_list_unittest.nc
index 0ddc135..7347f76 100644
--- a/base/callback_list_unittest.nc
+++ b/base/callback_list_unittest.nc
@@ -35,7 +35,7 @@
 };
 
 
-#if defined(NCTEST_MOVE_ONLY_TYPE_PARAMETER)  // [r"fatal error: call to deleted constructor"]
+#if defined(NCTEST_MOVE_ONLY_TYPE_PARAMETER)  // [r"fatal error: call to (implicitly-)?deleted( copy)? constructor"]
 
 // Callbacks run with a move-only typed parameter.
 //
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 30ad2e99..cf426e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -207,6 +207,8 @@
 
     private boolean mDeferredStartupPosted;
     private boolean mTabModelsInitialized;
+    private boolean mNativeInitialized;
+    private boolean mRemoveWindowBackgroundDone;
 
     // The class cannot implement TouchExplorationStateChangeListener,
     // because it is only available for Build.VERSION_CODES.KITKAT and later.
@@ -683,6 +685,9 @@
     @Override
     public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
+
+        maybeRemoveWindowBackground();
+
         Tab tab = getActivityTab();
         if (tab == null) return;
         if (hasFocus) {
@@ -1048,8 +1053,15 @@
                 ApiCompatibilityUtils.getColor(getResources(), R.color.light_background_color));
     }
 
-    @Override
-    public void finishNativeInitialization() {
+    private void maybeRemoveWindowBackground() {
+        // Only need to do this logic once.
+        if (mRemoveWindowBackgroundDone) return;
+
+        // Remove the window background only after native init and window getting focus. It's done
+        // after native init because before native init, a fake background gets shown. The window
+        // focus dependency is because doing it earlier can cause drawing bugs, e.g. crbug/673831.
+        if (!mNativeInitialized || !hasWindowFocus()) return;
+
         // The window background color is used as the resizing background color in Android N+
         // multi-window mode. See crbug.com/602366.
         if (Build.VERSION.CODENAME.equals("N") || Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
@@ -1059,6 +1071,14 @@
         } else {
             removeWindowBackground();
         }
+
+        mRemoveWindowBackgroundDone = true;
+    }
+
+    @Override
+    public void finishNativeInitialization() {
+        mNativeInitialized = true;
+        maybeRemoveWindowBackground();
         DownloadManagerService.getDownloadManagerService(
                 getApplicationContext()).onActivityLaunched();
 
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index fa618404..bced9689 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -684,9 +684,8 @@
 
 #if !defined(OS_CHROMEOS)
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          SigninStatusMetricsProvider::CreateInstance(base::WrapUnique(
-              new ChromeSigninStatusMetricsProviderDelegate))));
+      SigninStatusMetricsProvider::CreateInstance(
+          base::WrapUnique(new ChromeSigninStatusMetricsProviderDelegate)));
 #endif  // !defined(OS_CHROMEOS)
 
   metrics_service_->RegisterMetricsProvider(
diff --git a/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc b/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc
index 962c98f..1291a591 100644
--- a/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc
@@ -19,8 +19,8 @@
   std::unique_ptr<ChromeSigninStatusMetricsProviderDelegate> delegate(
       new ChromeSigninStatusMetricsProviderDelegate);
   ChromeSigninStatusMetricsProviderDelegate* raw_delegate = delegate.get();
-  std::unique_ptr<SigninStatusMetricsProvider> metrics_provider(
-      SigninStatusMetricsProvider::CreateInstance(std::move(delegate)));
+  std::unique_ptr<SigninStatusMetricsProvider> metrics_provider =
+      SigninStatusMetricsProvider::CreateInstance(std::move(delegate));
 
   // Initial status is all signed in and then a signed-in browser is opened.
   metrics_provider->UpdateInitialSigninStatusForTesting(2, 2);
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 80a1aee..4b36627f 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -322,7 +322,14 @@
       FinishProfileSyncServiceSetup();
       Initialize(new_profile, nullptr);
       DCHECK_EQ(profile_, new_profile);
+
+#if defined(OS_MACOSX)
+      // On macOS, the sync confirmation dialog is web-contents modal and thus
+      // it is dismissed on tab navigation (which always occurs when signing in
+      // to a new profile).
+      // Skip sync confirmation on macOS to workaround this issue.
       skip_sync_confirm_ = true;
+#endif
 
       // We've transferred our credentials to the new profile - notify that
       // the signin for the original profile was cancelled (must do this after
@@ -494,10 +501,6 @@
   // Regardless of whether the account was successfully added or not,
   // continue with sync starting.
 
-  // TODO(zmin): Remove this hack once the https://crbug.com/657924 fixed.
-  // Skip the Sync confirmation dialog if user choose to create a new profile
-  // for the corp signin. This is because the dialog doesn't work properly
-  // after the corp signin.
   if (skip_sync_confirm_) {
     OnSyncConfirmationUIClosed(LoginUIService::ABORT_SIGNIN);
     return;
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.h b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
index efd09d5..a2cd1b7 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.h
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
@@ -260,8 +260,10 @@
   // Prevents Sync from running until configuration is complete.
   std::unique_ptr<syncer::SyncSetupInProgressHandle> sync_blocker_;
 
-  // Temporary flag to disable new sync confirm page if user choose to create a
-  // new profile after the corp account signin.
+  // Temporary flag used only on macOS to disable new sync confirm page if user
+  // choose to create a new profile.
+  //
+  // TODO(msarda): Remove this flag once the https://crbug.com/677012 fixed.
   bool skip_sync_confirm_;
 
   base::WeakPtrFactory<OneClickSigninSyncStarter> weak_pointer_factory_;
diff --git a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
index cf9b6dc..06732fd 100644
--- a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
+++ b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
@@ -9,10 +9,13 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/signin/signin_email_confirmation_ui.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/user_metrics.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -32,19 +35,31 @@
 const char kActionCreateNewUser[] = "createNewUser";
 const char kActionStartSync[] = "startSync";
 
-class EmailConfirmationHandler : public content::WebUIMessageHandler {
- public:
-  EmailConfirmationHandler();
-  ~EmailConfirmationHandler() override;
-  void RegisterMessages() override;
-};
-
-EmailConfirmationHandler::EmailConfirmationHandler() {}
-EmailConfirmationHandler::~EmailConfirmationHandler() {}
-void EmailConfirmationHandler::RegisterMessages() {}
-
 }  // namespace
 
+class SigninEmailConfirmationDialog::DialogWebContentsObserver
+    : public content::WebContentsObserver {
+ public:
+  DialogWebContentsObserver(content::WebContents* web_contents,
+                            SigninEmailConfirmationDialog* dialog)
+      : content::WebContentsObserver(web_contents),
+        signin_email_confirmation_dialog_(dialog) {}
+  ~DialogWebContentsObserver() override {}
+
+ private:
+  void WebContentsDestroyed() override {
+    // The dialog is already closed. No need to call CloseDialog() again.
+    // NOTE: |this| is deleted after |ResetDialogObserver| returns.
+    signin_email_confirmation_dialog_->ResetDialogObserver();
+  }
+
+  void RenderProcessGone(base::TerminationStatus status) override {
+    signin_email_confirmation_dialog_->CloseDialog();
+  }
+
+  SigninEmailConfirmationDialog* signin_email_confirmation_dialog_;
+};
+
 SigninEmailConfirmationDialog::SigninEmailConfirmationDialog(
     content::WebContents* contents,
     Profile* profile,
@@ -55,8 +70,7 @@
       profile_(profile),
       last_email_(last_email),
       new_email_(new_email),
-      callback_(callback),
-      dialog_delegate_(NULL) {}
+      callback_(callback) {}
 
 SigninEmailConfirmationDialog::~SigninEmailConfirmationDialog() {}
 
@@ -71,16 +85,45 @@
       base::UserMetricsAction("Signin_Show_ImportDataPrompt"));
   SigninEmailConfirmationDialog* dialog = new SigninEmailConfirmationDialog(
       contents, profile, last_email, email, callback);
-  dialog->Show();
+  dialog->ShowDialog();
 }
 
-void SigninEmailConfirmationDialog::Show() {
+void SigninEmailConfirmationDialog::ShowDialog() {
   gfx::Size minSize(kDialogWidth, kDialogMinHeight);
   gfx::Size maxSize(kDialogWidth, kDialogMaxHeight);
-  dialog_delegate_ = ShowConstrainedWebDialogWithAutoResize(
-      profile_, this, web_contents_, minSize, maxSize);
+  ConstrainedWebDialogDelegate* dialog_delegate =
+      ShowConstrainedWebDialogWithAutoResize(profile_, this, web_contents_,
+                                             minSize, maxSize);
+
+  content::WebContents* dialog_web_contents = dialog_delegate->GetWebContents();
+  dialog_observer_.reset(
+      new DialogWebContentsObserver(dialog_web_contents, this));
 }
 
+void SigninEmailConfirmationDialog::CloseDialog() {
+  content::WebContents* dialog_web_contents = GetDialogWebContents();
+  if (dialog_web_contents == nullptr)
+    return;
+  content::WebUI* web_ui = dialog_web_contents->GetWebUI();
+  if (web_ui) {
+    SigninEmailConfirmationUI* signin_email_confirmation_ui =
+        static_cast<SigninEmailConfirmationUI*>(web_ui->GetController());
+    if (signin_email_confirmation_ui)
+      signin_email_confirmation_ui->Close();
+  }
+}
+
+void SigninEmailConfirmationDialog::ResetDialogObserver() {
+  dialog_observer_.reset();
+}
+
+content::WebContents* SigninEmailConfirmationDialog::GetDialogWebContents()
+    const {
+  return dialog_observer_.get() ? dialog_observer_->web_contents() : nullptr;
+}
+
+// ui::WebDialogDelegate implementation
+
 ui::ModalType SigninEmailConfirmationDialog::GetDialogModalType() const {
   return ui::MODAL_TYPE_WINDOW;
 }
@@ -94,9 +137,7 @@
 }
 
 void SigninEmailConfirmationDialog::GetWebUIMessageHandlers(
-    std::vector<content::WebUIMessageHandler*>* handlers) const {
-  handlers->push_back(new EmailConfirmationHandler());
-}
+    std::vector<content::WebUIMessageHandler*>* handlers) const {}
 
 void SigninEmailConfirmationDialog::GetDialogSize(gfx::Size* size) const {
   // Avoid setting a dialog size in here as this dialog auto-resizes (see
diff --git a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h
index e47d102a..353cd21 100644
--- a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h
+++ b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h
@@ -46,6 +46,8 @@
                                  const Callback& callback);
 
  private:
+  class DialogWebContentsObserver;
+
   SigninEmailConfirmationDialog(content::WebContents* contents,
                                 Profile* profile,
                                 const std::string& last_email,
@@ -68,7 +70,17 @@
 
   // Shows the dialog and releases ownership of this object. It will
   // delete itself when the dialog is closed.
-  void Show();
+  void ShowDialog();
+
+  // Closes the dialog.
+  void CloseDialog();
+
+  // Resets the dialog observer.
+  void ResetDialogObserver();
+
+  // Returns the media router dialog WebContents.
+  // Returns nullptr if there is no dialog.
+  content::WebContents* GetDialogWebContents() const;
 
   // Web contents from which the "Learn more" link should be opened.
   content::WebContents* const web_contents_;
@@ -78,8 +90,8 @@
   std::string new_email_;
   Callback callback_;
 
-  // Weak pointer to the dialog delegate.
-  ConstrainedWebDialogDelegate* dialog_delegate_;
+  // Observer for lifecycle events of the web contents of the dialog.
+  std::unique_ptr<DialogWebContentsObserver> dialog_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(SigninEmailConfirmationDialog);
 };
diff --git a/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc b/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc
index 1e13c590..127bb61 100644
--- a/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc
+++ b/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/chromium_strings.h"
@@ -13,6 +14,7 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/base/webui/web_ui_util.h"
+#include "ui/web_dialogs/web_dialog_delegate.h"
 
 SigninEmailConfirmationUI::SigninEmailConfirmationUI(content::WebUI* web_ui)
     : ConstrainedWebDialogUI(web_ui) {
@@ -47,3 +49,11 @@
 }
 
 SigninEmailConfirmationUI::~SigninEmailConfirmationUI() {}
+
+void SigninEmailConfirmationUI::Close() {
+  ConstrainedWebDialogDelegate* delegate = GetConstrainedDelegate();
+  if (delegate) {
+    delegate->GetWebDialogDelegate()->OnDialogClosed(std::string());
+    delegate->OnDialogCloseFromWebUI();
+  }
+}
diff --git a/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.h b/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.h
index b75d4df..9da37438 100644
--- a/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.h
+++ b/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.h
@@ -13,6 +13,9 @@
   explicit SigninEmailConfirmationUI(content::WebUI* web_ui);
   ~SigninEmailConfirmationUI() override;
 
+  // Closes this sign-in email confirmation webUI.
+  void Close();
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SigninEmailConfirmationUI);
 };
diff --git a/components/gcm_driver/crypto/p256_key_util.cc b/components/gcm_driver/crypto/p256_key_util.cc
index daf7e0ff..18f927d 100644
--- a/components/gcm_driver/crypto/p256_key_util.cc
+++ b/components/gcm_driver/crypto/p256_key_util.cc
@@ -51,8 +51,7 @@
   // Export the encrypted private key with an empty password. This is not done
   // to provide any security, but rather to achieve a consistent private key
   // storage between the BoringSSL and NSS implementations.
-  if (!key_pair->ExportEncryptedPrivateKey(
-          "" /* password */, 1 /* iteration */, &private_key)) {
+  if (!key_pair->ExportEncryptedPrivateKey(&private_key)) {
     DLOG(ERROR) << "Unable to export the private key.";
     return false;
   }
@@ -100,7 +99,6 @@
 
   std::unique_ptr<crypto::ECPrivateKey> local_key_pair(
       crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          "" /* no password */,
           std::vector<uint8_t>(private_key.data(),
                                private_key.data() + private_key.size()),
           std::vector<uint8_t>(
diff --git a/components/pdf/renderer/pepper_pdf_host.cc b/components/pdf/renderer/pepper_pdf_host.cc
index c56d78e..af54693 100644
--- a/components/pdf/renderer/pepper_pdf_host.cc
+++ b/components/pdf/renderer/pepper_pdf_host.cc
@@ -101,7 +101,7 @@
   if (!render_frame)
     return PP_ERROR_FAILED;
 
-  render_frame->DidStartLoading();
+  render_frame->PluginDidStartLoading();
   return PP_OK;
 }
 
@@ -111,7 +111,7 @@
   if (!render_frame)
     return PP_ERROR_FAILED;
 
-  render_frame->DidStopLoading();
+  render_frame->PluginDidStopLoading();
   return PP_OK;
 }
 
diff --git a/components/signin/core/browser/signin_status_metrics_provider.cc b/components/signin/core/browser/signin_status_metrics_provider.cc
index 04d54fa..699e61d 100644
--- a/components/signin/core/browser/signin_status_metrics_provider.cc
+++ b/components/signin/core/browser/signin_status_metrics_provider.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -45,9 +46,11 @@
 }
 
 // static
-SigninStatusMetricsProvider* SigninStatusMetricsProvider::CreateInstance(
+std::unique_ptr<SigninStatusMetricsProvider>
+SigninStatusMetricsProvider::CreateInstance(
     std::unique_ptr<SigninStatusMetricsProviderDelegate> delegate) {
-  return new SigninStatusMetricsProvider(std::move(delegate), false);
+  return base::WrapUnique(
+      new SigninStatusMetricsProvider(std::move(delegate), false));
 }
 
 void SigninStatusMetricsProvider::OnSigninManagerCreated(
diff --git a/components/signin/core/browser/signin_status_metrics_provider.h b/components/signin/core/browser/signin_status_metrics_provider.h
index 859363e..9d6e663 100644
--- a/components/signin/core/browser/signin_status_metrics_provider.h
+++ b/components/signin/core/browser/signin_status_metrics_provider.h
@@ -37,7 +37,7 @@
       metrics::ChromeUserMetricsExtension* uma_proto) override;
 
   // Factory method, creates a new instance of this class.
-  static SigninStatusMetricsProvider* CreateInstance(
+  static std::unique_ptr<SigninStatusMetricsProvider> CreateInstance(
       std::unique_ptr<SigninStatusMetricsProviderDelegate> delegate);
 
   // Update the sign-in status when a SigninManager is created.
diff --git a/content/browser/compositor/software_output_device_win.cc b/content/browser/compositor/software_output_device_win.cc
index fd74052..0a1bc20 100644
--- a/content/browser/compositor/software_output_device_win.cc
+++ b/content/browser/compositor/software_output_device_win.cc
@@ -178,8 +178,7 @@
     style |= WS_EX_LAYERED;
     SetWindowLong(hwnd_, GWL_EXSTYLE, style);
 
-    skia::ScopedPlatformPaint spp(contents_.get());
-    HDC dib_dc = spp.GetNativeDrawingContext();
+    HDC dib_dc = skia::GetNativeDrawingContext(contents_.get());
     ::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero,
                           RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
   } else {
diff --git a/content/browser/webrtc/webrtc_datachannel_browsertest.cc b/content/browser/webrtc/webrtc_datachannel_browsertest.cc
index 4c47f21..b4a789a 100644
--- a/content/browser/webrtc/webrtc_datachannel_browsertest.cc
+++ b/content/browser/webrtc/webrtc_datachannel_browsertest.cc
@@ -16,19 +16,11 @@
 
 namespace content {
 
-#if defined(OS_WIN) || (defined(OS_ANDROID) && defined(ADDRESS_SANITIZER))
-// GC does not work correctly in some cases under Android ASAN.
-// See https://crbug.com/611620.
-// This test has become flaky on Windows. See https://crbug.com/616388
-#define MAYBE_WebRtcDataChannelTest DISABLED_WebRtcDataChannelTest
-#else
-#define MAYBE_WebRtcDataChannelTest WebRtcDataChannelTest
-#endif
-
-class MAYBE_WebRtcDataChannelTest : public WebRtcContentBrowserTestBase {
+// This test is flaky, see https://crbug.com/611620.
+class DISABLED_WebRtcDataChannelTest : public WebRtcContentBrowserTestBase {
  public:
-  MAYBE_WebRtcDataChannelTest() {}
-  ~MAYBE_WebRtcDataChannelTest() override {}
+  DISABLED_WebRtcDataChannelTest() {}
+  ~DISABLED_WebRtcDataChannelTest() override {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     WebRtcContentBrowserTestBase::SetUpCommandLine(command_line);
@@ -38,10 +30,10 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(MAYBE_WebRtcDataChannelTest);
+  DISALLOW_COPY_AND_ASSIGN(DISABLED_WebRtcDataChannelTest);
 };
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcDataChannelTest, DataChannelGC) {
+IN_PROC_BROWSER_TEST_F(DISABLED_WebRtcDataChannelTest, DataChannelGC) {
   MakeTypicalCall("testDataChannelGC();", kDataChannelHtmlFile);
 }
 
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index 626229b8..81512cd 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -200,8 +200,8 @@
 
   // Used by plugins that load data in this RenderFrame to update the loading
   // notifications.
-  virtual void DidStartLoading() = 0;
-  virtual void DidStopLoading() = 0;
+  virtual void PluginDidStartLoading() = 0;
+  virtual void PluginDidStopLoading() = 0;
 #endif
 
   // Returns true if this frame is a FTP directory listing.
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index b843dd8..abfad56 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2577,11 +2577,11 @@
   return plugin_power_saver_helper_->WhitelistContentOrigin(content_origin);
 }
 
-void RenderFrameImpl::DidStartLoading() {
+void RenderFrameImpl::PluginDidStartLoading() {
   didStartLoading(true);
 }
 
-void RenderFrameImpl::DidStopLoading() {
+void RenderFrameImpl::PluginDidStopLoading() {
   didStopLoading();
 }
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 415f386f..f607fe0e 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -428,8 +428,8 @@
       const gfx::Size& unobscured_size,
       RecordPeripheralDecision record_decision) const override;
   void WhitelistContentOrigin(const url::Origin& content_origin) override;
-  void DidStartLoading() override;
-  void DidStopLoading() override;
+  void PluginDidStartLoading() override;
+  void PluginDidStopLoading() override;
 #endif
   bool IsFTPDirectoryListing() override;
   void AttachGuest(int element_instance_id) override;
diff --git a/crypto/ec_private_key.cc b/crypto/ec_private_key.cc
index 0a2344c2..9914c5dd 100644
--- a/crypto/ec_private_key.cc
+++ b/crypto/ec_private_key.cc
@@ -95,7 +95,6 @@
 
 // static
 std::unique_ptr<ECPrivateKey> ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-    const std::string& password,
     const std::vector<uint8_t>& encrypted_private_key_info,
     const std::vector<uint8_t>& subject_public_key_info) {
   // NOTE: The |subject_public_key_info| can be ignored here, it is only
@@ -113,21 +112,15 @@
   if (!p8_encrypted || ptr != data + encrypted_private_key_info.size())
     return nullptr;
 
-  bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> p8_decrypted;
-  if (password.empty()) {
-    // Hack for reading keys generated by an older version of the OpenSSL
-    // code. OpenSSL used to use "\0\0" rather than the empty string because it
-    // would treat the password as an ASCII string to be converted to UCS-2
-    // while NSS used a byte string.
-    p8_decrypted.reset(PKCS8_decrypt_pbe(
-        p8_encrypted.get(), reinterpret_cast<const uint8_t*>("\0\0"), 2));
-  }
-  if (!p8_decrypted) {
-    p8_decrypted.reset(PKCS8_decrypt_pbe(
-        p8_encrypted.get(),
-        reinterpret_cast<const uint8_t*>(password.data()),
-        password.size()));
-  }
+  // Hack for reading keys generated by an older version of the OpenSSL code.
+  // Some implementations encode the empty password as "\0\0" (passwords are
+  // normally encoded in big-endian UCS-2 with a NUL terminator) and some
+  // encode as the empty string. PKCS8_decrypt distinguishes the two by whether
+  // the password is nullptr.
+  bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> p8_decrypted(
+      PKCS8_decrypt(p8_encrypted.get(), "", 0));
+  if (!p8_decrypted)
+    p8_decrypted.reset(PKCS8_decrypt(p8_encrypted.get(), nullptr, 0));
 
   if (!p8_decrypted)
     return nullptr;
@@ -166,8 +159,6 @@
 }
 
 bool ECPrivateKey::ExportEncryptedPrivateKey(
-    const std::string& password,
-    int iterations,
     std::vector<uint8_t>* output) const {
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
   // Convert into a PKCS#8 object.
@@ -180,9 +171,8 @@
   // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL
   // equivalent.
   bssl::UniquePtr<X509_SIG> encrypted(
-      PKCS8_encrypt_pbe(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr,
-                        reinterpret_cast<const uint8_t*>(password.data()),
-                        password.size(), nullptr, 0, iterations, pkcs8.get()));
+      PKCS8_encrypt(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr, nullptr, 0,
+                    nullptr, 0, 1, pkcs8.get()));
   if (!encrypted)
     return false;
 
diff --git a/crypto/ec_private_key.h b/crypto/ec_private_key.h
index 8e5fe5e..432019b 100644
--- a/crypto/ec_private_key.h
+++ b/crypto/ec_private_key.h
@@ -41,13 +41,12 @@
 
   // Creates a new instance by importing an existing key pair.
   // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo
-  // block and an X.509 SubjectPublicKeyInfo block.
+  // block with empty password and an X.509 SubjectPublicKeyInfo block.
   // Returns nullptr if initialization fails.
   //
   // This function is deprecated. Use CreateFromPrivateKeyInfo for new code.
   // See https://crbug.com/603319.
   static std::unique_ptr<ECPrivateKey> CreateFromEncryptedPrivateKeyInfo(
-      const std::string& password,
       const std::vector<uint8_t>& encrypted_private_key_info,
       const std::vector<uint8_t>& subject_public_key_info);
 
@@ -60,16 +59,12 @@
   bool ExportPrivateKey(std::vector<uint8_t>* output) const;
 
   // Exports the private key as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo
-  // block and the public key as an X.509 SubjectPublicKeyInfo block.
-  // The |password| and |iterations| are used as inputs to the key derivation
-  // function for generating the encryption key.  PKCS #5 recommends a minimum
-  // of 1000 iterations, on modern systems a larger value may be preferrable.
+  // block wth empty password. This was historically used as a workaround for
+  // NSS API deficiencies and does not provide security.
   //
   // This function is deprecated. Use ExportPrivateKey for new code. See
   // https://crbug.com/603319.
-  bool ExportEncryptedPrivateKey(const std::string& password,
-                                 int iterations,
-                                 std::vector<uint8_t>* output) const;
+  bool ExportEncryptedPrivateKey(std::vector<uint8_t>* output) const;
 
   // Exports the public key to an X.509 SubjectPublicKeyInfo block.
   bool ExportPublicKey(std::vector<uint8_t>* output) const;
diff --git a/crypto/ec_private_key_unittest.cc b/crypto/ec_private_key_unittest.cc
index 386844c..5345647 100644
--- a/crypto/ec_private_key_unittest.cc
+++ b/crypto/ec_private_key_unittest.cc
@@ -41,9 +41,6 @@
 // should get back the same exact public key, and the private key should have
 // the same value and elliptic curve params.
 TEST(ECPrivateKeyUnitTest, InitRandomTest) {
-  static const char kPassword1[] = "";
-  static const char kPassword2[] = "test";
-
   std::unique_ptr<crypto::ECPrivateKey> keypair(crypto::ECPrivateKey::Create());
   ASSERT_TRUE(keypair);
 
@@ -58,19 +55,10 @@
   // Re-import as an EncryptedPrivateKeyInfo with kPassword1.
   std::vector<uint8_t> encrypted_privkey;
   std::vector<uint8_t> pubkey;
-  EXPECT_TRUE(
-      keypair->ExportEncryptedPrivateKey(kPassword1, 1, &encrypted_privkey));
+  EXPECT_TRUE(keypair->ExportEncryptedPrivateKey(&encrypted_privkey));
   EXPECT_TRUE(keypair->ExportPublicKey(&pubkey));
   keypair_copy = crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-      kPassword1, encrypted_privkey, pubkey);
-  ASSERT_TRUE(keypair_copy);
-  ExpectKeysEqual(keypair.get(), keypair_copy.get());
-
-  // Re-import as an EncryptedPrivateKeyInfo with kPassword2.
-  EXPECT_TRUE(
-      keypair->ExportEncryptedPrivateKey(kPassword2, 1, &encrypted_privkey));
-  keypair_copy = crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-      kPassword2, encrypted_privkey, pubkey);
+      encrypted_privkey, pubkey);
   ASSERT_TRUE(keypair_copy);
   ExpectKeysEqual(keypair.get(), keypair_copy.get());
 }
@@ -200,26 +188,6 @@
   EXPECT_FALSE(key);
 }
 
-TEST(ECPrivateKeyUnitTest, BadPasswordTest) {
-  const std::string password1;
-  const std::string password2 = "test";
-
-  std::unique_ptr<crypto::ECPrivateKey> keypair1(
-      crypto::ECPrivateKey::Create());
-  ASSERT_TRUE(keypair1);
-
-  std::vector<uint8_t> privkey1;
-  std::vector<uint8_t> pubkey1;
-  ASSERT_TRUE(keypair1->ExportEncryptedPrivateKey(
-      password1, 1, &privkey1));
-  ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1));
-
-  std::unique_ptr<crypto::ECPrivateKey> keypair2(
-      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          password2, privkey1, pubkey1));
-  ASSERT_FALSE(keypair2);
-}
-
 TEST(ECPrivateKeyUnitTest, LoadNSSKeyTest) {
   static const uint8_t kNSSKey[] = {
       0x30, 0x81, 0xb8, 0x30, 0x23, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
@@ -252,7 +220,7 @@
 
   std::unique_ptr<crypto::ECPrivateKey> keypair_nss(
       crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          "", std::vector<uint8_t>(std::begin(kNSSKey), std::end(kNSSKey)),
+          std::vector<uint8_t>(std::begin(kNSSKey), std::end(kNSSKey)),
           std::vector<uint8_t>(std::begin(kNSSPublicKey),
                                std::end(kNSSPublicKey))));
 
@@ -298,7 +266,6 @@
 
   std::unique_ptr<crypto::ECPrivateKey> keypair_openssl(
       crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          "",
           std::vector<uint8_t>(std::begin(kOpenSSLKey), std::end(kOpenSSLKey)),
           std::vector<uint8_t>(std::begin(kOpenSSLPublicKey),
                                std::end(kOpenSSLPublicKey))));
@@ -393,7 +360,6 @@
 
   std::unique_ptr<crypto::ECPrivateKey> keypair_openssl(
       crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          "",
           std::vector<uint8_t>(std::begin(kOpenSSLKey), std::end(kOpenSSLKey)),
           std::vector<uint8_t>(std::begin(kOpenSSLPublicKey),
                                std::end(kOpenSSLPublicKey))));
diff --git a/crypto/ec_signature_creator_unittest.cc b/crypto/ec_signature_creator_unittest.cc
index 018ba54a..1bfd89d 100644
--- a/crypto/ec_signature_creator_unittest.cc
+++ b/crypto/ec_signature_creator_unittest.cc
@@ -21,23 +21,19 @@
   // Do a verify round trip.
   std::unique_ptr<crypto::ECPrivateKey> key_original(
       crypto::ECPrivateKey::Create());
-  ASSERT_TRUE(key_original.get());
+  ASSERT_TRUE(key_original);
 
   std::vector<uint8_t> key_info;
-  ASSERT_TRUE(
-      key_original->ExportEncryptedPrivateKey(std::string(), 1000, &key_info));
-  std::vector<uint8_t> pubkey_info;
-  ASSERT_TRUE(key_original->ExportPublicKey(&pubkey_info));
+  ASSERT_TRUE(key_original->ExportPrivateKey(&key_info));
 
   std::unique_ptr<crypto::ECPrivateKey> key(
-      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          std::string(), key_info, pubkey_info));
-  ASSERT_TRUE(key.get());
-  ASSERT_TRUE(key->key() != NULL);
+      crypto::ECPrivateKey::CreateFromPrivateKeyInfo(key_info));
+  ASSERT_TRUE(key);
+  ASSERT_TRUE(key->key());
 
   std::unique_ptr<crypto::ECSignatureCreator> signer(
       crypto::ECSignatureCreator::Create(key.get()));
-  ASSERT_TRUE(signer.get());
+  ASSERT_TRUE(signer);
 
   std::string data("Hello, World!");
   std::vector<uint8_t> signature;
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 0c788e0..e48990b 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -276,7 +276,6 @@
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/tabs:tabs_internal",
     "//ios/chrome/browser/ui",
-    "//ios/chrome/browser/ui:browser_list",
     "//ios/chrome/browser/ui/webui:webui_internal",
   ]
 }
diff --git a/ios/chrome/browser/downstream_chromium_browser_provider.h b/ios/chrome/browser/downstream_chromium_browser_provider.h
index 9f8e139e6..2e1e189 100644
--- a/ios/chrome/browser/downstream_chromium_browser_provider.h
+++ b/ios/chrome/browser/downstream_chromium_browser_provider.h
@@ -19,7 +19,6 @@
   // ChromeBrowserProvider implementations.  All of these will move upstream
   // into ChromiumBrowserProvider eventually, and from there callers will be
   // converted to not go through the provider API at all.
-  bool IsOffTheRecordSessionActive() override;
   void GetFaviconForURL(
       ios::ChromeBrowserState* browser_state,
       const GURL& page_url,
diff --git a/ios/chrome/browser/downstream_chromium_browser_provider.mm b/ios/chrome/browser/downstream_chromium_browser_provider.mm
index f4104d6..20a3056a 100644
--- a/ios/chrome/browser/downstream_chromium_browser_provider.mm
+++ b/ios/chrome/browser/downstream_chromium_browser_provider.mm
@@ -11,17 +11,12 @@
 
 #include "base/memory/ptr_util.h"
 #include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h"
-#import "ios/chrome/browser/ui/browser_list_ios.h"
 #include "ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.h"
 
 DownstreamChromiumBrowserProvider::DownstreamChromiumBrowserProvider() {}
 
 DownstreamChromiumBrowserProvider::~DownstreamChromiumBrowserProvider() {}
 
-bool DownstreamChromiumBrowserProvider::IsOffTheRecordSessionActive() {
-  return BrowserListIOS::IsOffTheRecordSessionActive();
-}
-
 void DownstreamChromiumBrowserProvider::GetFaviconForURL(
     ios::ChromeBrowserState* browser_state,
     const GURL& page_url,
diff --git a/ios/chrome/browser/metrics/BUILD.gn b/ios/chrome/browser/metrics/BUILD.gn
index a103be6..3232e1f 100644
--- a/ios/chrome/browser/metrics/BUILD.gn
+++ b/ios/chrome/browser/metrics/BUILD.gn
@@ -9,8 +9,8 @@
     "field_trial_synchronizer.h",
     "ios_chrome_metrics_service_accessor.cc",
     "ios_chrome_metrics_service_accessor.h",
-    "ios_chrome_metrics_service_client.cc",
     "ios_chrome_metrics_service_client.h",
+    "ios_chrome_metrics_service_client.mm",
     "ios_chrome_metrics_services_manager_client.h",
     "ios_chrome_metrics_services_manager_client.mm",
     "ios_chrome_origins_seen_service_factory.cc",
@@ -48,7 +48,7 @@
     "//ios/chrome/browser/google",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
-    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:browser_list",
     "//ios/chrome/browser/variations",
     "//ios/chrome/browser/variations:ios_chrome_ui_string_overrider_factory",
     "//ios/chrome/common",
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.cc b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
similarity index 81%
rename from ios/chrome/browser/metrics/ios_chrome_metrics_service_client.cc
rename to ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
index e0b8216..eebf255 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.cc
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
@@ -51,7 +51,7 @@
 #include "ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.h"
 #include "ios/chrome/browser/sync/ios_chrome_sync_client.h"
 #include "ios/chrome/browser/tab_parenting_global_observer.h"
-#include "ios/chrome/browser/ui/browser_otr_state.h"
+#include "ios/chrome/browser/ui/browser_list_ios.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/web_thread.h"
 
@@ -152,11 +152,10 @@
 std::unique_ptr<metrics::MetricsLogUploader>
 IOSChromeMetricsServiceClient::CreateUploader(
     const base::Callback<void(int)>& on_upload_complete) {
-  return std::unique_ptr<metrics::MetricsLogUploader>(
-      new metrics::NetMetricsLogUploader(
-          GetApplicationContext()->GetSystemURLRequestContext(),
-          metrics::kDefaultMetricsServerUrl, metrics::kDefaultMetricsMimeType,
-          on_upload_complete));
+  return base::MakeUnique<metrics::NetMetricsLogUploader>(
+      GetApplicationContext()->GetSystemURLRequestContext(),
+      metrics::kDefaultMetricsServerUrl, metrics::kDefaultMetricsMimeType,
+      on_upload_complete);
 }
 
 base::TimeDelta IOSChromeMetricsServiceClient::GetStandardUploadInterval() {
@@ -182,63 +181,69 @@
 }
 
 void IOSChromeMetricsServiceClient::Initialize() {
-  metrics_service_.reset(new metrics::MetricsService(
-      metrics_state_manager_, this, GetApplicationContext()->GetLocalState()));
+  metrics_service_ = base::MakeUnique<metrics::MetricsService>(
+      metrics_state_manager_, this, GetApplicationContext()->GetLocalState());
 
   // Register metrics providers.
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          new metrics::NetworkMetricsProvider(
-              web::WebThread::GetBlockingPool())));
+      base::MakeUnique<metrics::NetworkMetricsProvider>(
+          web::WebThread::GetBlockingPool()));
 
   // Currently, we configure OmniboxMetricsProvider to not log events to UMA
   // if there is a single incognito session visible. In the future, it may
   // be worth revisiting this to still log events from non-incognito sessions.
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(new OmniboxMetricsProvider(
-          base::Bind(&::IsOffTheRecordSessionActive))));
+      base::MakeUnique<OmniboxMetricsProvider>(
+          base::Bind(&BrowserListIOS::IsOffTheRecordSessionActive)));
 
-  stability_metrics_provider_ = new IOSChromeStabilityMetricsProvider(
-      GetApplicationContext()->GetLocalState());
-  metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(stability_metrics_provider_));
+  {
+    auto stability_metrics_provider =
+        base::MakeUnique<IOSChromeStabilityMetricsProvider>(
+            GetApplicationContext()->GetLocalState());
+    stability_metrics_provider_ = stability_metrics_provider.get();
+    metrics_service_->RegisterMetricsProvider(
+        std::move(stability_metrics_provider));
+  }
 
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          new metrics::ScreenInfoMetricsProvider));
+      base::MakeUnique<metrics::ScreenInfoMetricsProvider>());
 
-  drive_metrics_provider_ = new metrics::DriveMetricsProvider(
-      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE),
-      ios::FILE_LOCAL_STATE);
-  metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(drive_metrics_provider_));
+  {
+    auto drive_metrics_provider =
+        base::MakeUnique<metrics::DriveMetricsProvider>(
+            web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE),
+            ios::FILE_LOCAL_STATE);
+    drive_metrics_provider_ = drive_metrics_provider.get();
+    metrics_service_->RegisterMetricsProvider(
+        std::move(drive_metrics_provider));
+  }
 
-  profiler_metrics_provider_ = new metrics::ProfilerMetricsProvider(
-      base::Bind(&metrics::IsCellularLogicEnabled));
-  metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(profiler_metrics_provider_));
+  {
+    auto profiler_metrics_provider =
+        base::MakeUnique<metrics::ProfilerMetricsProvider>(
+            base::Bind(&metrics::IsCellularLogicEnabled));
+    profiler_metrics_provider_ = profiler_metrics_provider.get();
+    metrics_service_->RegisterMetricsProvider(
+        std::move(profiler_metrics_provider));
+  }
 
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          new metrics::CallStackProfileMetricsProvider));
+      base::MakeUnique<metrics::CallStackProfileMetricsProvider>());
 
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          SigninStatusMetricsProvider::CreateInstance(base::WrapUnique(
-              new IOSChromeSigninStatusMetricsProviderDelegate))));
+      SigninStatusMetricsProvider::CreateInstance(
+          base::MakeUnique<IOSChromeSigninStatusMetricsProviderDelegate>()));
 
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          new MobileSessionShutdownMetricsProvider(metrics_service_.get())));
+      base::MakeUnique<MobileSessionShutdownMetricsProvider>(
+          metrics_service_.get()));
 
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          new syncer::DeviceCountMetricsProvider(
-              base::Bind(&IOSChromeSyncClient::GetDeviceInfoTrackers))));
+      base::MakeUnique<syncer::DeviceCountMetricsProvider>(
+          base::Bind(&IOSChromeSyncClient::GetDeviceInfoTrackers)));
 
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          new translate::TranslateRankerMetricsProvider()));
+      base::MakeUnique<translate::TranslateRankerMetricsProvider>());
 }
 
 void IOSChromeMetricsServiceClient::OnInitTaskGotDriveMetrics() {
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
index 1afc1478..d528c47 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
@@ -16,7 +16,7 @@
 #include "ios/chrome/browser/chrome_switches.h"
 #include "ios/chrome/browser/metrics/ios_chrome_metrics_service_accessor.h"
 #include "ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h"
-#include "ios/chrome/browser/ui/browser_otr_state.h"
+#include "ios/chrome/browser/ui/browser_list_ios.h"
 #include "ios/chrome/browser/variations/ios_chrome_variations_service_client.h"
 #include "ios/chrome/browser/variations/ios_ui_string_overrider_factory.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -50,7 +50,8 @@
 
 IOSChromeMetricsServicesManagerClient::IOSChromeMetricsServicesManagerClient(
     PrefService* local_state)
-    : enabled_state_provider_(new IOSChromeEnabledStateProvider()),
+    : enabled_state_provider_(
+          base::MakeUnique<IOSChromeEnabledStateProvider>()),
       local_state_(local_state) {
   DCHECK(local_state);
 }
@@ -62,7 +63,7 @@
 IOSChromeMetricsServicesManagerClient::CreateRapporServiceImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
   return base::MakeUnique<rappor::RapporServiceImpl>(
-      local_state_, base::Bind(&::IsOffTheRecordSessionActive));
+      local_state_, base::Bind(&BrowserListIOS::IsOffTheRecordSessionActive));
 }
 
 std::unique_ptr<variations::VariationsService>
@@ -73,7 +74,7 @@
   // a dummy value for the name of the switch that disables background
   // networking.
   return variations::VariationsService::Create(
-      base::WrapUnique(new IOSChromeVariationsServiceClient), local_state_,
+      base::MakeUnique<IOSChromeVariationsServiceClient>(), local_state_,
       GetMetricsStateManager(), "dummy-disable-background-switch",
       ::CreateUIStringOverrider());
 }
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 5c68334..90523244 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -24,8 +24,6 @@
     "animation_util.mm",
     "background_generator.h",
     "background_generator.mm",
-    "browser_otr_state.h",
-    "browser_otr_state.mm",
     "favicon_view.h",
     "favicon_view.mm",
     "file_locations.h",
@@ -59,7 +57,6 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/ui/commands",
-    "//ios/public/provider/chrome/browser",
     "//ios/web",
     "//ui/base",
     "//ui/gfx",
diff --git a/ios/chrome/browser/ui/browser_otr_state.h b/ios/chrome/browser/ui/browser_otr_state.h
deleted file mode 100644
index 7a53f0f..0000000
--- a/ios/chrome/browser/ui/browser_otr_state.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-
-#ifndef IOS_CHROME_BROWSER_UI_BROWSER_OTR_STATE_H_
-#define IOS_CHROME_BROWSER_UI_BROWSER_OTR_STATE_H_
-
-// Returns whether there is any Off-The-Record session in progress.
-bool IsOffTheRecordSessionActive();
-
-#endif  // IOS_CHROME_BROWSER_UI_BROWSER_OTR_STATE_H_
diff --git a/ios/chrome/browser/ui/browser_otr_state.mm b/ios/chrome/browser/ui/browser_otr_state.mm
deleted file mode 100644
index 9431105..0000000
--- a/ios/chrome/browser/ui/browser_otr_state.mm
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-
-#include "ios/chrome/browser/ui/browser_otr_state.h"
-
-#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-bool IsOffTheRecordSessionActive() {
-  ios::ChromeBrowserProvider* chrome_browser_provider =
-      ios::GetChromeBrowserProvider();
-  return chrome_browser_provider &&
-         chrome_browser_provider->IsOffTheRecordSessionActive();
-}
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 31702128..9a842bc 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -66,6 +66,7 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/context_menu",
     "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/material_components",
     "//ios/chrome/browser/ui/ntp/recent_tabs/views",
     "//ios/chrome/browser/ui/popup_menu",
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.mm b/ios/chrome/browser/ui/history/history_panel_view_controller.mm
index 41be2fa..158840f 100644
--- a/ios/chrome/browser/ui/history/history_panel_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_panel_view_controller.mm
@@ -6,12 +6,14 @@
 
 #include "base/ios/block_types.h"
 #include "base/ios/ios_util.h"
+#include "base/ios/weak_nsobject.h"
 #include "base/mac/scoped_nsobject.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/history/clear_browsing_bar.h"
 #import "ios/chrome/browser/ui/history/history_collection_view_controller.h"
 #import "ios/chrome/browser/ui/history/history_search_view_controller.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
+#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/material_components/utils.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.h"
 #import "ios/chrome/browser/ui/show_privacy_settings_util.h"
@@ -378,4 +380,16 @@
       [_historyCollectionController hasHistoryEntries];
 }
 
+#pragma mark - UIResponder
+
+- (NSArray*)keyCommands {
+  base::WeakNSObject<HistoryPanelViewController> weakSelf(self);
+  return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
+                                   modifierFlags:Cr_UIKeyModifierNone
+                                           title:nil
+                                          action:^{
+                                            [weakSelf closeHistory];
+                                          }] ];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
index 73ee56c7..8aee9c9 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
@@ -106,7 +106,7 @@
   DCHECK(browserState);
   [_label setText:text];
   self.accessibilityLabel = [_label accessibilityLabel];
-  ios_internal::GetFavicon(url, browserState, ^(UIImage* newIcon) {
+  TabSwitcherGetFavicon(url, browserState, ^(UIImage* newIcon) {
     [_favicon setImage:newIcon];
   });
 }
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn
index c7e7c071..abf601f 100644
--- a/ios/chrome/browser/ui/reading_list/BUILD.gn
+++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -61,6 +61,7 @@
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/collection_view/cells",
     "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/material_components",
     "//ios/chrome/browser/ui/reading_list:resources",
     "//ios/chrome/browser/ui/side_swipe",
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.h b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.h
index 4b11dd46..262f185 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.h
+++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.h
@@ -20,12 +20,15 @@
 @class TabModel;
 
 // Audience for the ReadingListViewController, managing the visibility of the
-// toolbar.
+// toolbar and dismissing the Reading List View.
 @protocol ReadingListViewControllerAudience<NSObject>
 
 // Whether the collection has items.
 - (void)setCollectionHasItems:(BOOL)hasItems;
 
+// Dismisses the Reading List View.
+- (void)dismiss;
+
 @end
 
 @interface ReadingListViewController
@@ -51,11 +54,4 @@
 
 @end
 
-@interface ReadingListViewController (Testing)
-
-// Dismisses this view controller.
-- (void)dismiss;
-
-@end
-
 #endif  // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
index 607efd35..8887f81 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
@@ -447,8 +447,7 @@
   // Reset observer to prevent further model update notifications.
   _modelBridge.reset();
   [_actionSheet stop];
-  [self.presentingViewController dismissViewControllerAnimated:YES
-                                                    completion:nil];
+  [self.audience dismiss];
 }
 
 - (void)loadModel {
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.mm
index e2155397..52ffd42 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.h"
 
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
+#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_toolbar.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_view_controller.h"
 
@@ -83,7 +84,7 @@
   constraint.active = YES;
 }
 
-#pragma mark - ReadingListViewControllerDelegate
+#pragma mark - ReadingListViewControllerAudience
 
 - (void)setCollectionHasItems:(BOOL)hasItems {
   if (hasItems) {
@@ -110,6 +111,11 @@
   }
 }
 
+- (void)dismiss {
+  [self.presentingViewController dismissViewControllerAnimated:YES
+                                                    completion:nil];
+}
+
 #pragma mark - ReadingListToolbarActionTarget
 
 - (void)markPressed {
@@ -144,4 +150,16 @@
   });
 }
 
+#pragma mark - UIResponder
+
+- (NSArray*)keyCommands {
+  __weak ReadingListViewControllerContainer* weakSelf = self;
+  return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
+                                   modifierFlags:Cr_UIKeyModifierNone
+                                           title:nil
+                                          action:^{
+                                            [weakSelf dismiss];
+                                          }] ];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/tab_switcher/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
index ded140ce..e5cfbf46 100644
--- a/ios/chrome/browser/ui/tab_switcher/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
@@ -51,8 +51,6 @@
 
 source_set("tab_switcher") {
   sources = [
-    "session_changes.h",
-    "session_changes.mm",
     "tab_model_snapshot.h",
     "tab_model_snapshot.mm",
     "tab_switcher.h",
@@ -81,6 +79,8 @@
     "tab_switcher_panel_view.mm",
     "tab_switcher_session_cell_data.h",
     "tab_switcher_session_cell_data.mm",
+    "tab_switcher_session_changes.h",
+    "tab_switcher_session_changes.mm",
     "tab_switcher_tab_strip_placeholder_view.h",
     "tab_switcher_tab_strip_placeholder_view.mm",
     "tab_switcher_transition_context.h",
diff --git a/ios/chrome/browser/ui/tab_switcher/session_changes.h b/ios/chrome/browser/ui/tab_switcher/session_changes.h
deleted file mode 100644
index a765f4f..0000000
--- a/ios/chrome/browser/ui/tab_switcher/session_changes.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 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.
-
-#ifndef IOS_CHROME_BROWSER_UI_TAB_SWITCHER_SESSION_CHANGES_H_
-#define IOS_CHROME_BROWSER_UI_TAB_SWITCHER_SESSION_CHANGES_H_
-
-#include <vector>
-
-namespace ios_internal {
-
-// This structure represents the changes a session undergoes.
-// It is used to update the UICollectionView showing a set of tabs.
-class SessionChanges {
- public:
-  SessionChanges(std::vector<size_t> const& tabHashesInInitialState,
-                 std::vector<size_t> const& tabHashesInFinalState);
-  ~SessionChanges();
-  SessionChanges(const SessionChanges& sessionChanges) = delete;
-  SessionChanges& operator=(const SessionChanges& sessionChanges) = delete;
-
-  std::vector<size_t> const& deletions() const;
-  std::vector<size_t> const& insertions() const;
-  std::vector<size_t> const& updates() const;
-
-  bool hasChanges() const;
-
- private:
-  // Those vectors contain indexes of tabs.
-  // The indexes are relative to a tab model snapshot, or a distant session.
-  // To be in accordance with the UICollectionView's |performBatchUpdates|
-  // method:
-  // -the indexes in |updates| are relative to the previous state of the
-  // session.
-  // -the indexes in |deletions| are relative to the previous state of the
-  // session.
-  // -the indexes in |insertions| are relative to the final state of the
-  // session.
-  std::vector<size_t> deletions_;
-  std::vector<size_t> insertions_;
-  std::vector<size_t> updates_;
-};
-
-}  // namespace ios_internal
-
-#endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_SESSION_CHANGES_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/session_changes.mm b/ios/chrome/browser/ui/tab_switcher/session_changes.mm
deleted file mode 100644
index 3e06b52..0000000
--- a/ios/chrome/browser/ui/tab_switcher/session_changes.mm
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 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.
-
-#import "ios/chrome/browser/ui/tab_switcher/session_changes.h"
-
-#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h"
-
-namespace ios_internal {
-
-SessionChanges::SessionChanges(
-    std::vector<size_t> const& tabHashesInInitialState,
-    std::vector<size_t> const& tabHashesInFinalState) {
-  ios_internal::MinimalReplacementOperations(tabHashesInInitialState,
-                                             tabHashesInFinalState, &updates_,
-                                             &deletions_, &insertions_);
-}
-
-SessionChanges::~SessionChanges() {}
-
-std::vector<size_t> const& SessionChanges::deletions() const {
-  return deletions_;
-}
-std::vector<size_t> const& SessionChanges::insertions() const {
-  return insertions_;
-}
-std::vector<size_t> const& SessionChanges::updates() const {
-  return updates_;
-}
-
-bool SessionChanges::hasChanges() const {
-  return updates_.size() || deletions_.size() || insertions_.size();
-}
-
-}  // namespace ios_internal
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
index 16060190..6fb47212 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
@@ -31,7 +31,6 @@
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_on_no_sessions_view.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_out_view.h"
-#import "ios/chrome/browser/ui/tab_switcher/session_changes.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_cache.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_model.h"
@@ -136,12 +135,12 @@
 - (NSInteger)currentPanelIndex;
 
 // Returns the session type of the panel and the given index.
-- (ios_internal::SessionType)sessionTypeForPanelIndex:(NSInteger)panelIndex;
+- (TabSwitcherSessionType)sessionTypeForPanelIndex:(NSInteger)panelIndex;
 
 // Returns the tab model corresponding to the given session type.
 // There is no tab model for distant sessions so it returns nil for distant
 // sessions type.
-- (TabModel*)tabModelForSessionType:(ios_internal::SessionType)sessionType;
+- (TabModel*)tabModelForSessionType:(TabSwitcherSessionType)sessionType;
 
 // Returns the tab model of the currently selected tab.
 - (TabModel*)currentSelectedModel;
@@ -207,13 +206,13 @@
     [self loadTabSwitcherView];
     _onTheRecordSession.reset([[TabSwitcherPanelController alloc]
                 initWithModel:_tabSwitcherModel
-        forLocalSessionOfType:ios_internal::SessionType::REGULAR_SESSION
+        forLocalSessionOfType:TabSwitcherSessionType::REGULAR_SESSION
                     withCache:_cache
                  browserState:_browserState]);
     [_onTheRecordSession setDelegate:self];
     _offTheRecordSession.reset([[TabSwitcherPanelController alloc]
                 initWithModel:_tabSwitcherModel
-        forLocalSessionOfType:ios_internal::SessionType::OFF_THE_RECORD_SESSION
+        forLocalSessionOfType:TabSwitcherSessionType::OFF_THE_RECORD_SESSION
                     withCache:_cache
                  browserState:_browserState]);
     [_offTheRecordSession setDelegate:self];
@@ -392,10 +391,10 @@
                                  : kLocalTabsOffTheRecordPanelIndex;
       [_tabSwitcherView selectPanelAtIndex:panelIndex];
 
-      const ios_internal::SessionType panelSessionType =
+      const TabSwitcherSessionType panelSessionType =
           (command == IDC_NEW_TAB)
-              ? ios_internal::SessionType::REGULAR_SESSION
-              : ios_internal::SessionType::OFF_THE_RECORD_SESSION;
+              ? TabSwitcherSessionType::REGULAR_SESSION
+              : TabSwitcherSessionType::OFF_THE_RECORD_SESSION;
 
       TabModel* model = [self tabModelForSessionType:panelSessionType];
       [self dismissWithNewTabAnimation:GURL(kChromeUINewTabURL)
@@ -737,23 +736,23 @@
   return kSignInPromoPanelIndex + 1;
 }
 
-- (ios_internal::SessionType)sessionTypeForPanelIndex:(NSInteger)panelIndex {
+- (TabSwitcherSessionType)sessionTypeForPanelIndex:(NSInteger)panelIndex {
   if (panelIndex == kLocalTabsOffTheRecordPanelIndex)
-    return ios_internal::SessionType::OFF_THE_RECORD_SESSION;
+    return TabSwitcherSessionType::OFF_THE_RECORD_SESSION;
   if (panelIndex == kLocalTabsOnTheRecordPanelIndex)
-    return ios_internal::SessionType::REGULAR_SESSION;
-  return ios_internal::SessionType::DISTANT_SESSION;
+    return TabSwitcherSessionType::REGULAR_SESSION;
+  return TabSwitcherSessionType::DISTANT_SESSION;
 }
 
-- (TabModel*)tabModelForSessionType:(ios_internal::SessionType)sessionType {
+- (TabModel*)tabModelForSessionType:(TabSwitcherSessionType)sessionType {
   switch (sessionType) {
-    case ios_internal::SessionType::REGULAR_SESSION:
+    case TabSwitcherSessionType::REGULAR_SESSION:
       return [_tabSwitcherModel mainTabModel];
       break;
-    case ios_internal::SessionType::OFF_THE_RECORD_SESSION:
+    case TabSwitcherSessionType::OFF_THE_RECORD_SESSION:
       return [_tabSwitcherModel otrTabModel];
       break;
-    case ios_internal::SessionType::DISTANT_SESSION:
+    case TabSwitcherSessionType::DISTANT_SESSION:
       return nil;
       break;
   }
@@ -761,7 +760,7 @@
 
 - (TabModel*)currentSelectedModel {
   const NSInteger currentPanelIndex = [self currentPanelIndex];
-  const ios_internal::SessionType sessionType =
+  const TabSwitcherSessionType sessionType =
       [self sessionTypeForPanelIndex:currentPanelIndex];
   TabModel* model = [self tabModelForSessionType:sessionType];
   if (!model)
@@ -1003,11 +1002,11 @@
   }
 }
 
-- (void)localSessionMayNeedUpdate:(ios_internal::SessionType)type {
-  if (type == ios_internal::SessionType::REGULAR_SESSION) {
+- (void)localSessionMayNeedUpdate:(TabSwitcherSessionType)type {
+  if (type == TabSwitcherSessionType::REGULAR_SESSION) {
     [_onTheRecordSession updateCollectionViewIfNeeded];
   } else {
-    DCHECK(type == ios_internal::SessionType::OFF_THE_RECORD_SESSION);
+    DCHECK(type == TabSwitcherSessionType::OFF_THE_RECORD_SESSION);
     [_offTheRecordSession updateCollectionViewIfNeeded];
   }
 }
@@ -1042,13 +1041,13 @@
 }
 
 - (CGSize)sizeForItemAtIndex:(NSUInteger)index
-                   inSession:(ios_internal::SessionType)session {
+                   inSession:(TabSwitcherSessionType)session {
   switch (session) {
-    case ios_internal::SessionType::OFF_THE_RECORD_SESSION:
+    case TabSwitcherSessionType::OFF_THE_RECORD_SESSION:
       return [[_offTheRecordSession view] cellSize];
-    case ios_internal::SessionType::REGULAR_SESSION:
+    case TabSwitcherSessionType::REGULAR_SESSION:
       return [[_onTheRecordSession view] cellSize];
-    case ios_internal::SessionType::DISTANT_SESSION:
+    case TabSwitcherSessionType::DISTANT_SESSION:
       NOTREACHED();
       return {};
   }
@@ -1085,16 +1084,16 @@
   return [_tabSwitcherModel sessionCount] + promoPanel;
 }
 
-- (SessionCellData*)sessionCellDataAtIndex:(NSUInteger)index {
+- (TabSwitcherSessionCellData*)sessionCellDataAtIndex:(NSUInteger)index {
   if (index == kLocalTabsOffTheRecordPanelIndex) {
     // If has incognito tabs return incognito cell data.
-    return [SessionCellData incognitoSessionCellData];
+    return [TabSwitcherSessionCellData incognitoSessionCellData];
   } else if (index == kLocalTabsOnTheRecordPanelIndex) {
-    return [SessionCellData openTabSessionCellData];
+    return [TabSwitcherSessionCellData openTabSessionCellData];
   } else {
     if (![_tabSwitcherModel distantSessionCount]) {
       // Display promo panel cell if there is no distant sessions.
-      return [SessionCellData otherDevicesSessionCellData];
+      return [TabSwitcherSessionCellData otherDevicesSessionCellData];
     } else {
       index -= kHeaderDistantSessionIndexOffset;
 
@@ -1110,20 +1109,21 @@
         deviceType = distantSession->device_type;
         cellTitle = base::SysUTF8ToNSString(distantSession->name);
       }
-      ios_internal::SessionCellType cellType;
+      TabSwitcherSessionCellType cellType;
       switch (deviceType) {
         case sync_sessions::SyncedSession::TYPE_PHONE:
-          cellType = ios_internal::kPhoneRemoteSessionCell;
+          cellType = kPhoneRemoteSessionCell;
           break;
         case sync_sessions::SyncedSession::TYPE_TABLET:
-          cellType = ios_internal::kTabletRemoteSessionCell;
+          cellType = kTabletRemoteSessionCell;
           break;
         default:
-          cellType = ios_internal::kLaptopRemoteSessionCell;
+          cellType = kLaptopRemoteSessionCell;
           break;
       }
-      SessionCellData* sessionData = [[[SessionCellData alloc]
-          initWithSessionCellType:cellType] autorelease];
+      TabSwitcherSessionCellData* sessionData =
+          [[[TabSwitcherSessionCellData alloc] initWithSessionCellType:cellType]
+              autorelease];
       sessionData.title = cellTitle;
       return sessionData;
     }
@@ -1207,14 +1207,14 @@
             (TabSwitcherPanelController*)tabSwitcherPanelController
                  didSelectLocalTab:(Tab*)tab {
   DCHECK(tab);
-  const ios_internal::SessionType panelSessionType =
+  const TabSwitcherSessionType panelSessionType =
       tabSwitcherPanelController.sessionType;
   TabModel* tabModel = [self tabModelForSessionType:panelSessionType];
   [tabModel setCurrentTab:tab];
   [self.delegate tabSwitcher:self
       dismissTransitionWillStartWithActiveModel:tabModel];
   [self tabSwitcherDismissWithModel:tabModel];
-  if (panelSessionType == ios_internal::SessionType::OFF_THE_RECORD_SESSION) {
+  if (panelSessionType == TabSwitcherSessionType::OFF_THE_RECORD_SESSION) {
     base::RecordAction(
         base::UserMetricsAction("MobileTabSwitcherOpenIncognitoTab"));
   } else {
@@ -1227,10 +1227,10 @@
             (TabSwitcherPanelController*)tabSwitcherPanelController
                   didCloseLocalTab:(Tab*)tab {
   DCHECK(tab);
-  const ios_internal::SessionType panelSessionType =
+  const TabSwitcherSessionType panelSessionType =
       tabSwitcherPanelController.sessionType;
   [tab close];
-  if (panelSessionType == ios_internal::SessionType::OFF_THE_RECORD_SESSION) {
+  if (panelSessionType == TabSwitcherSessionType::OFF_THE_RECORD_SESSION) {
     base::RecordAction(
         base::UserMetricsAction("MobileTabSwitcherCloseIncognitoTab"));
   } else {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.h
index d16157db..7b30d0669 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.h
@@ -7,7 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-@class SessionCellData;
+@class TabSwitcherSessionCellData;
 
 // This class is the cell class used in the table view of the tab switcher
 // header.
@@ -16,8 +16,8 @@
 // Default table view cell identifier.
 + (NSString*)identifier;
 
-// Load the cell content using the given SessionCellData object.
-- (void)loadSessionCellData:(SessionCellData*)sessionCellData;
+// Load the cell content using the given TabSwitcherSessionCellData object.
+- (void)loadSessionCellData:(TabSwitcherSessionCellData*)sessionCellData;
 
 @end
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.mm
index a45bad0..2638016 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_cell.mm
@@ -43,7 +43,7 @@
   return [[self class] identifier];
 }
 
-- (void)loadSessionCellData:(SessionCellData*)sessionCellData {
+- (void)loadSessionCellData:(TabSwitcherSessionCellData*)sessionCellData {
   [_imageView setImage:sessionCellData.image];
   [_label setText:sessionCellData.title];
   [self setNeedsLayout];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.h
index c37ad7b..374794c 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.h
@@ -9,7 +9,7 @@
 
 #include "base/ios/block_types.h"
 
-@class SessionCellData;
+@class TabSwitcherSessionCellData;
 @class TabSwitcherHeaderView;
 
 @protocol TabSwitcherHeaderViewDelegate<NSObject>
@@ -25,7 +25,7 @@
 @protocol TabSwitcherHeaderViewDataSource<NSObject>
 
 - (NSInteger)tabSwitcherHeaderViewSessionCount;
-- (SessionCellData*)sessionCellDataAtIndex:(NSUInteger)index;
+- (TabSwitcherSessionCellData*)sessionCellDataAtIndex:(NSUInteger)index;
 
 @end
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.mm
index bcaec65..140d6ead 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.mm
@@ -334,7 +334,7 @@
 
 - (NSString*)panelTitleAtIndex:(NSInteger)index {
   NSIndexPath* indexPath = [NSIndexPath indexPathForItem:index inSection:0];
-  SessionCellData* sessionCellData =
+  TabSwitcherSessionCellData* sessionCellData =
       [[self dataSource] sessionCellDataAtIndex:indexPath.row];
   return sessionCellData.title;
 }
@@ -373,7 +373,7 @@
   TabSwitcherHeaderCell* headerCell = [collectionView
       dequeueReusableCellWithReuseIdentifier:[TabSwitcherHeaderCell identifier]
                                 forIndexPath:indexPath];
-  SessionCellData* sessionCellData =
+  TabSwitcherSessionCellData* sessionCellData =
       [[self dataSource] sessionCellDataAtIndex:indexPath.row];
   [headerCell loadSessionCellData:sessionCellData];
   return headerCell;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.h
index a684735..d065e92 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.h
@@ -15,6 +15,7 @@
 #import "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions_bridge.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_model_snapshot.h"
 
+class ChromeBrowserState;
 @class TabModel;
 @class TabSwitcherCache;
 
@@ -26,21 +27,15 @@
   NO_PANEL,
 };
 
-namespace ios_internal {
-
-enum class SessionType {
+enum class TabSwitcherSessionType {
   OFF_THE_RECORD_SESSION,
   REGULAR_SESSION,
   DISTANT_SESSION
 };
 
-class ChromeBrowserState;
-
 // Returns true if the session type is a local session. A local session is a
 // "regular session" or an "off the record" session.
-bool IsLocalSession(SessionType sessionType);
-
-}  // namespace ios_internal
+bool TabSwitcherSessionTypeIsLocalSession(TabSwitcherSessionType sessionType);
 
 // Protocol to observe changes to the TabSwitcherModel.
 @protocol TabSwitcherModelDelegate<NSObject>
@@ -51,12 +46,12 @@
 // Called when the distant session with the tag |tag| may need to be updated.
 - (void)distantSessionMayNeedUpdate:(std::string const&)tag;
 // Called when a local session of type |type| needs to be updated.
-- (void)localSessionMayNeedUpdate:(ios_internal::SessionType)type;
+- (void)localSessionMayNeedUpdate:(TabSwitcherSessionType)type;
 // Called when the signed-in panel (if any) must change.
 - (void)signInPanelChangedTo:(TabSwitcherSignInPanelsType)panelType;
 // Called to retrieve the size of the item at the |index| in |session|.
 - (CGSize)sizeForItemAtIndex:(NSUInteger)index
-                   inSession:(ios_internal::SessionType)session;
+                   inSession:(TabSwitcherSessionType)session;
 @end
 
 // This class serves as a bridge between Chrome-level data (CLD), and what is
@@ -90,7 +85,7 @@
 - (ios::ChromeBrowserState*)browserState;
 // Returns the latest data for the local session of type |type|.
 - (std::unique_ptr<TabModelSnapshot>)tabModelSnapshotForLocalSession:
-    (ios_internal::SessionType)type;
+    (TabSwitcherSessionType)type;
 // Returns the latest data for the distant session of tag |tag|.
 - (std::unique_ptr<const synced_sessions::DistantSession>)distantSessionForTag:
     (std::string const&)tag;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.mm
index 6f1a4e5d..3024a2f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_model.mm
@@ -18,21 +18,16 @@
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
-#import "ios/chrome/browser/ui/tab_switcher/session_changes.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_model_snapshot.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_cache.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_model_private.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h"
 
-namespace ios_internal {
-
-bool IsLocalSession(SessionType sessionType) {
-  return sessionType == SessionType::OFF_THE_RECORD_SESSION ||
-         sessionType == SessionType::REGULAR_SESSION;
+bool TabSwitcherSessionTypeIsLocalSession(TabSwitcherSessionType sessionType) {
+  return sessionType == TabSwitcherSessionType::OFF_THE_RECORD_SESSION ||
+         sessionType == TabSwitcherSessionType::REGULAR_SESSION;
 }
 
-}  // namespace ios_internal
-
 namespace {
 
 class TagAndIndex {
@@ -77,7 +72,7 @@
 
 // Returns the type of the local session corresponding to the given |tabModel|.
 // |tabModel| MUST be equal to either |_mainTabModel|, or |_otrTabModel|.
-- (ios_internal::SessionType)typeOfLocalSessionForTabModel:(TabModel*)tabModel;
+- (TabSwitcherSessionType)typeOfLocalSessionForTabModel:(TabModel*)tabModel;
 @end
 
 @implementation TabSwitcherModel
@@ -153,33 +148,32 @@
   return _browserState;
 }
 
-- (TabModel*)tabModelForSessionOfType:(ios_internal::SessionType)type {
-  DCHECK(type == ios_internal::SessionType::OFF_THE_RECORD_SESSION ||
-         type == ios_internal::SessionType::REGULAR_SESSION);
-  return type == ios_internal::SessionType::OFF_THE_RECORD_SESSION
-             ? _otrTabModel
-             : _mainTabModel;
+- (TabModel*)tabModelForSessionOfType:(TabSwitcherSessionType)type {
+  DCHECK(type == TabSwitcherSessionType::OFF_THE_RECORD_SESSION ||
+         type == TabSwitcherSessionType::REGULAR_SESSION);
+  return type == TabSwitcherSessionType::OFF_THE_RECORD_SESSION ? _otrTabModel
+                                                                : _mainTabModel;
 }
 
-- (NSInteger)numberOfTabsInLocalSessionOfType:(ios_internal::SessionType)type {
+- (NSInteger)numberOfTabsInLocalSessionOfType:(TabSwitcherSessionType)type {
   TabModelSnapshot* tabModelSnapshot = [self tabModelSnapshotForSession:type];
   return tabModelSnapshot->tabs().size();
 }
 
 - (Tab*)tabAtIndex:(NSUInteger)index
-    inLocalSessionOfType:(ios_internal::SessionType)type {
+    inLocalSessionOfType:(TabSwitcherSessionType)type {
   TabModelSnapshot* tabModelSnapshot = [self tabModelSnapshotForSession:type];
   return tabModelSnapshot->tabs()[index];
 }
 
 - (std::unique_ptr<TabModelSnapshot>)tabModelSnapshotForLocalSession:
-    (ios_internal::SessionType)type {
+    (TabSwitcherSessionType)type {
   TabModel* tm = nullptr;
   switch (type) {
-    case ios_internal::SessionType::OFF_THE_RECORD_SESSION:
+    case TabSwitcherSessionType::OFF_THE_RECORD_SESSION:
       tm = _otrTabModel;
       break;
-    case ios_internal::SessionType::REGULAR_SESSION:
+    case TabSwitcherSessionType::REGULAR_SESSION:
       tm = _mainTabModel;
       break;
     default:
@@ -316,19 +310,18 @@
   }
 }
 
-- (ios_internal::SessionType)typeOfLocalSessionForTabModel:(TabModel*)tabModel {
+- (TabSwitcherSessionType)typeOfLocalSessionForTabModel:(TabModel*)tabModel {
   DCHECK(tabModel == _mainTabModel || tabModel == _otrTabModel);
   if (tabModel == _otrTabModel)
-    return ios_internal::SessionType::OFF_THE_RECORD_SESSION;
-  return ios_internal::SessionType::REGULAR_SESSION;
+    return TabSwitcherSessionType::OFF_THE_RECORD_SESSION;
+  return TabSwitcherSessionType::REGULAR_SESSION;
 }
 
-- (TabModelSnapshot*)tabModelSnapshotForSession:
-    (ios_internal::SessionType)type {
+- (TabModelSnapshot*)tabModelSnapshotForSession:(TabSwitcherSessionType)type {
   switch (type) {
-    case ios_internal::SessionType::OFF_THE_RECORD_SESSION:
+    case TabSwitcherSessionType::OFF_THE_RECORD_SESSION:
       return _otrTabModelSnapshot.get();
-    case ios_internal::SessionType::REGULAR_SESSION:
+    case TabSwitcherSessionType::REGULAR_SESSION:
       return _mainTabModelSnapshot.get();
     default:
       NOTREACHED();
@@ -338,12 +331,12 @@
 }
 
 - (void)setTabModelSnapshot:(std::unique_ptr<TabModelSnapshot>)tabModelSnapshot
-                 forSession:(ios_internal::SessionType)type {
+                 forSession:(TabSwitcherSessionType)type {
   switch (type) {
-    case ios_internal::SessionType::OFF_THE_RECORD_SESSION:
+    case TabSwitcherSessionType::OFF_THE_RECORD_SESSION:
       _otrTabModelSnapshot = std::move(tabModelSnapshot);
       break;
-    case ios_internal::SessionType::REGULAR_SESSION:
+    case TabSwitcherSessionType::REGULAR_SESSION:
       _mainTabModelSnapshot = std::move(tabModelSnapshot);
       break;
     default:
@@ -353,7 +346,7 @@
 }
 
 - (void)tabModelChanged:(TabModel*)tabModel {
-  ios_internal::SessionType sessionType =
+  TabSwitcherSessionType sessionType =
       [self typeOfLocalSessionForTabModel:tabModel];
   [_delegate localSessionMayNeedUpdate:sessionType];
 }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_model_unittest.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_model_unittest.mm
index 08e5726..7eccd8e 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_model_unittest.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_model_unittest.mm
@@ -9,7 +9,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
-#include "ios/chrome/browser/ui/tab_switcher/session_changes.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_model_private.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h"
 #include "testing/platform_test.h"
@@ -17,13 +16,6 @@
 
 namespace {
 
-// A lightweight SessionChanges.
-struct LightSessionChanges {
-  std::vector<int> updates;
-  std::vector<int> deletions;
-  std::vector<int> insertions;
-};
-
 // A lightweight DistantTab.
 class LightDT {
  public:
@@ -88,7 +80,7 @@
   EXPECT_EQ(1UL, _expectedTagsOfTheSessionsNeedingUpdates.erase(tag));
 }
 
-- (void)localSessionMayNeedUpdate:(ios_internal::SessionType)type {
+- (void)localSessionMayNeedUpdate:(TabSwitcherSessionType)type {
   NOTREACHED();
 }
 
@@ -96,7 +88,7 @@
   NOTREACHED();
 }
 - (CGSize)sizeForItemAtIndex:(NSUInteger)index
-                   inSession:(ios_internal::SessionType)session {
+                   inSession:(TabSwitcherSessionType)session {
   return CGSizeZero;
 }
 @end
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h
index 79be1ad2..42d3249 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h
@@ -43,7 +43,7 @@
 // Sets the cell's appearance using information in |tab|.
 - (void)setAppearanceForTab:(Tab*)tab cellSize:(CGSize)cellSize;
 // Sets the cell's appearance depending on |type|.
-- (void)setSessionType:(ios_internal::SessionType)type;
+- (void)setSessionType:(TabSwitcherSessionType)type;
 // Sets the cell's delegate.
 - (void)setDelegate:(id<SessionCellDelegate>)delegate;
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
index d38f3245..d0361e39 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
@@ -239,12 +239,12 @@
                           }];
 }
 
-- (void)setSessionType:(ios_internal::SessionType)type {
+- (void)setSessionType:(TabSwitcherSessionType)type {
   UIColor* topBarBackgroundColor;
   UIColor* closeButtonTintColor;
   UIColor* textColor;
   UIColor* snapshotBackgroundColor;
-  if (type == ios_internal::SessionType::OFF_THE_RECORD_SESSION) {
+  if (type == TabSwitcherSessionType::OFF_THE_RECORD_SESSION) {
     topBarBackgroundColor = [[MDCPalette greyPalette] tint700];
     closeButtonTintColor = [[MDCPalette greyPalette] tint100];
     textColor = [[MDCPalette greyPalette] tint100];
@@ -398,7 +398,7 @@
 
 - (void)setSessionGURL:(GURL const&)gurl
       withBrowserState:(ios::ChromeBrowserState*)browserState {
-  ios_internal::FaviconGetterCompletionBlock block = ^(UIImage* favicon) {
+  TabSwitcherFaviconGetterCompletionBlock block = ^(UIImage* favicon) {
     UIColor* imageDominantColor =
         DominantColorForImage(gfx::Image(favicon), 1.0);
     MDCPalette* dominantPalette =
@@ -424,7 +424,7 @@
   };
   GURL gurlCopy = gurl;
   _faviconObtainer.reset([[NSBlockOperation blockOperationWithBlock:^{
-    ios_internal::GetFavicon(gurlCopy, browserState, block);
+    TabSwitcherGetFavicon(gurlCopy, browserState, block);
   }] retain]);
   NSOperationQueue* operationQueue = [NSOperationQueue mainQueue];
   [operationQueue addOperation:_faviconObtainer];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h
index 402f74c..59f87c58 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h
@@ -52,13 +52,13 @@
 
 @property(nonatomic, readonly) TabSwitcherPanelView* view;
 @property(nonatomic, assign) id<TabSwitcherPanelControllerDelegate> delegate;
-@property(nonatomic, readonly) ios_internal::SessionType sessionType;
+@property(nonatomic, readonly) TabSwitcherSessionType sessionType;
 
 // Initializes a controller for a view showing local tabs. |offTheRecord|
 // determines whether the tabs will be shown for the incognito browser state or
 // not. |model| is used to populate the view and must not be nil.
 - (instancetype)initWithModel:(TabSwitcherModel*)model
-        forLocalSessionOfType:(ios_internal::SessionType)type
+        forLocalSessionOfType:(TabSwitcherSessionType)type
                     withCache:(TabSwitcherCache*)cache
                  browserState:(ios::ChromeBrowserState*)browserState;
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm
index 07f5ea19..112f0fd 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm
@@ -9,11 +9,11 @@
 #include "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
-#import "ios/chrome/browser/ui/tab_switcher/session_changes.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_cache.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.h"
+#include "ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.h"
 
 namespace {
 
@@ -35,7 +35,7 @@
   base::scoped_nsobject<TabSwitcherPanelView> _panelView;
   base::scoped_nsobject<TabSwitcherModel> _model;
   std::string _sessionTag;
-  ios_internal::SessionType _sessionType;
+  TabSwitcherSessionType _sessionType;
   base::scoped_nsobject<TabSwitcherCache> _cache;
   base::scoped_nsobject<TabSwitcherPanelOverlayView> _overlayView;
   std::unique_ptr<const synced_sessions::DistantSession> _distantSession;
@@ -58,7 +58,7 @@
   self = [super init];
   if (self) {
     DCHECK(model);
-    _sessionType = ios_internal::SessionType::DISTANT_SESSION;
+    _sessionType = TabSwitcherSessionType::DISTANT_SESSION;
     _model.reset([model retain]);
     _distantSession = [model distantSessionForTag:sessionTag];
     _sessionTag = sessionTag;
@@ -69,7 +69,7 @@
 }
 
 - (instancetype)initWithModel:(TabSwitcherModel*)model
-        forLocalSessionOfType:(ios_internal::SessionType)sessionType
+        forLocalSessionOfType:(TabSwitcherSessionType)sessionType
                     withCache:(TabSwitcherCache*)cache
                  browserState:(ios::ChromeBrowserState*)browserState {
   self = [super init];
@@ -99,7 +99,7 @@
 }
 
 - (BOOL)shouldShowNewTabButton {
-  if (_sessionType == ios_internal::SessionType::DISTANT_SESSION) {
+  if (_sessionType == TabSwitcherSessionType::DISTANT_SESSION) {
     return NO;
   } else {
     return ![self isOverlayVisible];
@@ -107,9 +107,9 @@
 }
 
 - (void)updateCollectionViewIfNeeded {
-  if (_sessionType == ios_internal::SessionType::DISTANT_SESSION) {
+  if (_sessionType == TabSwitcherSessionType::DISTANT_SESSION) {
     UICollectionView* collectionView = [_panelView collectionView];
-    // TODO(crbug.com/633928) Compute SessionChanges outside of the
+    // TODO(crbug.com/633928) Compute TabSwitcherSessionChanges outside of the
     // updateBlock.
     auto updateBlock = ^{
       std::unique_ptr<const synced_sessions::DistantSession> newDistantSession =
@@ -120,8 +120,8 @@
                                               &oldTabsHashes);
       FillVectorWithHashesUsingDistantSession(*newDistantSession.get(),
                                               &newTabsHashes);
-      ios_internal::SessionChanges changes(oldTabsHashes, newTabsHashes);
-      if (changes.hasChanges()) {
+      TabSwitcherSessionChanges changes(oldTabsHashes, newTabsHashes);
+      if (changes.HasChanges()) {
         _distantSession = std::move(newDistantSession);
         [self applyChanges:changes toCollectionView:collectionView];
       }
@@ -132,9 +132,9 @@
     auto updateBlock = ^{
       std::unique_ptr<const TabModelSnapshot> newLocalSession =
           [_model tabModelSnapshotForLocalSession:_sessionType];
-      ios_internal::SessionChanges changes(_localSession->hashes(),
-                                           newLocalSession->hashes());
-      if (changes.hasChanges()) {
+      TabSwitcherSessionChanges changes(_localSession->hashes(),
+                                        newLocalSession->hashes());
+      if (changes.HasChanges()) {
         _localSession = std::move(newLocalSession);
         [self applyChanges:changes toCollectionView:collectionView];
       }
@@ -143,7 +143,7 @@
   }
 }
 
-- (void)applyChanges:(ios_internal::SessionChanges&)changes
+- (void)applyChanges:(TabSwitcherSessionChanges&)changes
     toCollectionView:(UICollectionView*)collectionView {
   NSMutableArray* deletedIndexes = [NSMutableArray array];
   NSMutableArray* insertedIndexes = [NSMutableArray array];
@@ -202,7 +202,7 @@
 - (NSInteger)collectionView:(UICollectionView*)collectionView
      numberOfItemsInSection:(NSInteger)section {
   DCHECK_EQ(section, 0);
-  if (_sessionType == ios_internal::SessionType::DISTANT_SESSION) {
+  if (_sessionType == TabSwitcherSessionType::DISTANT_SESSION) {
     CHECK(_distantSession);
     return _distantSession->tabs.size();
   } else {
@@ -217,7 +217,7 @@
                  cellForItemAtIndexPath:(NSIndexPath*)indexPath {
   UICollectionViewCell* cell = nil;
   NSUInteger tabIndex = indexPath.item;
-  if (_sessionType == ios_internal::SessionType::DISTANT_SESSION) {
+  if (_sessionType == TabSwitcherSessionType::DISTANT_SESSION) {
     cell = [collectionView
         dequeueReusableCellWithReuseIdentifier:[TabSwitcherDistantSessionCell
                                                    identifier]
@@ -262,7 +262,7 @@
   const NSInteger tabIndex =
       [[_panelView collectionView] indexPathForCell:cell].item;
 
-  if (_sessionType == ios_internal::SessionType::DISTANT_SESSION) {
+  if (_sessionType == TabSwitcherSessionType::DISTANT_SESSION) {
     synced_sessions::DistantTab* tab = _distantSession->tabs[tabIndex].get();
     if (tab)
       [self.delegate tabSwitcherPanelController:self didSelectDistantTab:tab];
@@ -274,7 +274,7 @@
 }
 
 - (void)deleteButtonPressedForCell:(UICollectionViewCell*)cell {
-  DCHECK(_sessionType != ios_internal::SessionType::DISTANT_SESSION);
+  DCHECK(_sessionType != TabSwitcherSessionType::DISTANT_SESSION);
   const NSInteger tabIndex =
       [[_panelView collectionView] indexPathForCell:cell].item;
   Tab* tab = _localSession->tabs()[tabIndex];
@@ -292,7 +292,7 @@
   if (show == [self isOverlayVisible])
     return;
 
-  DCHECK(ios_internal::IsLocalSession(_sessionType));
+  DCHECK(TabSwitcherSessionTypeIsLocalSession(_sessionType));
 
   if (!_overlayView) {
     _overlayView.reset([[TabSwitcherPanelOverlayView alloc]
@@ -300,7 +300,7 @@
          browserState:_browserState]);
     [_overlayView
         setOverlayType:
-            (_sessionType == ios_internal::SessionType::OFF_THE_RECORD_SESSION)
+            (_sessionType == TabSwitcherSessionType::OFF_THE_RECORD_SESSION)
                 ? TabSwitcherPanelOverlayType::
                       OVERLAY_PANEL_USER_NO_INCOGNITO_TABS
                 : TabSwitcherPanelOverlayType::OVERLAY_PANEL_USER_NO_OPEN_TABS];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.h
index 16be52cd..3c11453 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.h
@@ -15,7 +15,7 @@
 
 @property(nonatomic, readonly) UICollectionView* collectionView;
 
-- (instancetype)initWithSessionType:(ios_internal::SessionType)sessionType
+- (instancetype)initWithSessionType:(TabSwitcherSessionType)sessionType
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.mm
index e53c52c..65245fd 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.mm
@@ -12,14 +12,14 @@
   base::scoped_nsobject<UICollectionView> _collectionView;
   base::scoped_nsobject<TabSwitcherPanelCollectionViewLayout>
       _collectionViewLayout;
-  ios_internal::SessionType _sessionType;
+  TabSwitcherSessionType _sessionType;
 }
 
 @end
 
 @implementation TabSwitcherPanelView
 
-- (instancetype)initWithSessionType:(ios_internal::SessionType)sessionType {
+- (instancetype)initWithSessionType:(TabSwitcherSessionType)sessionType {
   self = [super initWithFrame:CGRectZero];
   if (self) {
     _sessionType = sessionType;
@@ -62,7 +62,7 @@
   _collectionView.reset([[UICollectionView alloc]
              initWithFrame:self.bounds
       collectionViewLayout:_collectionViewLayout.get()]);
-  if (_sessionType == ios_internal::SessionType::DISTANT_SESSION) {
+  if (_sessionType == TabSwitcherSessionType::DISTANT_SESSION) {
     [_collectionView registerClass:[TabSwitcherDistantSessionCell class]
         forCellWithReuseIdentifier:[TabSwitcherDistantSessionCell identifier]];
   } else {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.h
index 2f8e4e80..d61b101 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.h
@@ -9,8 +9,7 @@
 
 @class TabSwitcherHeaderView;
 
-namespace ios_internal {
-enum SessionCellType {
+enum TabSwitcherSessionCellType {
   kIncognitoSessionCell,
   kOpenTabSessionCell,
   kGenericRemoteSessionCell,
@@ -18,11 +17,10 @@
   kTabletRemoteSessionCell,
   kLaptopRemoteSessionCell,
 };
-}
 
 // This class hold the data used to configure the content of a
 // TabSwitcherHeaderCell.
-@interface SessionCellData : NSObject
+@interface TabSwitcherSessionCellData : NSObject
 
 // Those two methods are used to create incognito and open tab cell data.
 // Each method create a SessionCellData object on the first call and returns
@@ -31,9 +29,9 @@
 + (instancetype)openTabSessionCellData;
 + (instancetype)otherDevicesSessionCellData;
 
-- (instancetype)initWithSessionCellType:(ios_internal::SessionCellType)type;
+- (instancetype)initWithSessionCellType:(TabSwitcherSessionCellType)type;
 
-@property(nonatomic, readonly) ios_internal::SessionCellType type;
+@property(nonatomic, readonly) TabSwitcherSessionCellType type;
 @property(nonatomic, copy) NSString* title;
 @property(nonatomic, retain) UIImage* image;
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.mm
index cbb8af2e..a304a26 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_cell_data.mm
@@ -6,43 +6,43 @@
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
-@implementation SessionCellData
+@implementation TabSwitcherSessionCellData
 
 @synthesize type = _type;
 @synthesize title = _title;
 @synthesize image = _image;
 
 + (instancetype)incognitoSessionCellData {
-  static SessionCellData* incognitoSessionCellData = nil;
+  static TabSwitcherSessionCellData* incognitoSessionCellData = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
-    incognitoSessionCellData = [[self alloc]
-        initWithSessionCellType:ios_internal::kIncognitoSessionCell];
+    incognitoSessionCellData =
+        [[self alloc] initWithSessionCellType:kIncognitoSessionCell];
   });
   return incognitoSessionCellData;
 }
 
 + (instancetype)openTabSessionCellData {
-  static SessionCellData* openTabSessionCellData = nil;
+  static TabSwitcherSessionCellData* openTabSessionCellData = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
-    openTabSessionCellData = [[self alloc]
-        initWithSessionCellType:ios_internal::kOpenTabSessionCell];
+    openTabSessionCellData =
+        [[self alloc] initWithSessionCellType:kOpenTabSessionCell];
   });
   return openTabSessionCellData;
 }
 
 + (instancetype)otherDevicesSessionCellData {
-  static SessionCellData* otherDevicesSessionCellData = nil;
+  static TabSwitcherSessionCellData* otherDevicesSessionCellData = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
-    otherDevicesSessionCellData = [[self alloc]
-        initWithSessionCellType:ios_internal::kGenericRemoteSessionCell];
+    otherDevicesSessionCellData =
+        [[self alloc] initWithSessionCellType:kGenericRemoteSessionCell];
   });
   return otherDevicesSessionCellData;
 }
 
-- (instancetype)initWithSessionCellType:(ios_internal::SessionCellType)type {
+- (instancetype)initWithSessionCellType:(TabSwitcherSessionCellType)type {
   self = [super init];
   if (self) {
     _type = type;
@@ -57,27 +57,27 @@
   NSString* imageName = nil;
   int messageId = 0;
   switch (self.type) {
-    case ios_internal::kIncognitoSessionCell:
+    case kIncognitoSessionCell:
       imageName = @"tabswitcher_incognito";
       messageId = IDS_IOS_TAB_SWITCHER_HEADER_INCOGNITO_TABS;
       break;
-    case ios_internal::kOpenTabSessionCell:
+    case kOpenTabSessionCell:
       imageName = @"tabswitcher_open_tabs";
       messageId = IDS_IOS_TAB_SWITCHER_HEADER_NON_INCOGNITO_TABS;
       break;
-    case ios_internal::kGenericRemoteSessionCell:
+    case kGenericRemoteSessionCell:
       imageName = @"tabswitcher_other_devices";
       messageId = IDS_IOS_TAB_SWITCHER_HEADER_OTHER_DEVICES_TABS;
       break;
-    case ios_internal::kPhoneRemoteSessionCell:
+    case kPhoneRemoteSessionCell:
       imageName = @"ntp_opentabs_phone";
       messageId = IDS_IOS_TAB_SWITCHER_HEADER_OTHER_DEVICES_TABS;
       break;
-    case ios_internal::kTabletRemoteSessionCell:
+    case kTabletRemoteSessionCell:
       imageName = @"ntp_opentabs_tablet";
       messageId = IDS_IOS_TAB_SWITCHER_HEADER_OTHER_DEVICES_TABS;
       break;
-    case ios_internal::kLaptopRemoteSessionCell:
+    case kLaptopRemoteSessionCell:
       imageName = @"ntp_opentabs_laptop";
       messageId = IDS_IOS_TAB_SWITCHER_HEADER_OTHER_DEVICES_TABS;
       break;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.h
new file mode 100644
index 0000000..44389529
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.h
@@ -0,0 +1,46 @@
+// Copyright 2016 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.
+
+#ifndef IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_SWITCHER_SESSION_CHANGES_H_
+#define IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_SWITCHER_SESSION_CHANGES_H_
+
+#include <vector>
+
+// This structure represents the changes a session undergoes.
+// It is used to update the UICollectionView showing a set of tabs.
+class TabSwitcherSessionChanges {
+ public:
+  TabSwitcherSessionChanges(std::vector<size_t> const& tabHashesInInitialState,
+                            std::vector<size_t> const& tabHashesInFinalState);
+  ~TabSwitcherSessionChanges();
+  TabSwitcherSessionChanges(const TabSwitcherSessionChanges& sessionChanges) =
+      delete;
+  TabSwitcherSessionChanges& operator=(
+      const TabSwitcherSessionChanges& sessionChanges) = delete;
+
+  std::vector<size_t> const& deletions() const { return deletions_; }
+
+  std::vector<size_t> const& insertions() const { return insertions_; }
+
+  std::vector<size_t> const& updates() const { return updates_; }
+
+  bool HasChanges() const;
+
+ private:
+  // Those vectors contain indexes of tabs.
+  // The indexes are relative to a tab model snapshot, or a distant session.
+  // To be in accordance with the UICollectionView's |performBatchUpdates|
+  // method:
+  // -the indexes in |updates| are relative to the previous state of the
+  // session.
+  // -the indexes in |deletions| are relative to the previous state of the
+  // session.
+  // -the indexes in |insertions| are relative to the final state of the
+  // session.
+  std::vector<size_t> deletions_;
+  std::vector<size_t> insertions_;
+  std::vector<size_t> updates_;
+};
+
+#endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_SWITCHER_SESSION_CHANGES_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.mm
new file mode 100644
index 0000000..5d94e05
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.mm
@@ -0,0 +1,21 @@
+// Copyright 2016 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 "ios/chrome/browser/ui/tab_switcher/tab_switcher_session_changes.h"
+
+#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h"
+
+TabSwitcherSessionChanges::TabSwitcherSessionChanges(
+    std::vector<size_t> const& tabHashesInInitialState,
+    std::vector<size_t> const& tabHashesInFinalState) {
+  TabSwitcherMinimalReplacementOperations(tabHashesInInitialState,
+                                          tabHashesInFinalState, &updates_,
+                                          &deletions_, &insertions_);
+}
+
+TabSwitcherSessionChanges::~TabSwitcherSessionChanges() {}
+
+bool TabSwitcherSessionChanges::HasChanges() const {
+  return updates_.size() || deletions_.size() || insertions_.size();
+}
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h
index cdae3c9..a183686f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h
@@ -9,18 +9,17 @@
 
 class GURL;
 @class UIImage;
+
 namespace ios {
 class ChromeBrowserState;
 }  // namespace ios
 
-namespace ios_internal {
-
-typedef void (^FaviconGetterCompletionBlock)(UIImage*);
+typedef void (^TabSwitcherFaviconGetterCompletionBlock)(UIImage*);
 
 // Favicon for |url|, calls |block| when loaded.
-void GetFavicon(GURL const& url,
-                ios::ChromeBrowserState* browserState,
-                FaviconGetterCompletionBlock block);
+void TabSwitcherGetFavicon(GURL const& url,
+                           ios::ChromeBrowserState* browserState,
+                           TabSwitcherFaviconGetterCompletionBlock block);
 
 // Returns the substitutions/deletions/insertions needed to go from |initial| to
 // |final|.
@@ -34,12 +33,10 @@
 // For example, AB => BC could be done with 2 substitutions, but doing
 // 1 insertion and 1 deletion is preferable because it better communicates the
 // changes to the user in the UICollectionViews.
-void MinimalReplacementOperations(std::vector<size_t> const& initial,
-                                  std::vector<size_t> const& final,
-                                  std::vector<size_t>* substitutions,
-                                  std::vector<size_t>* deletions,
-                                  std::vector<size_t>* insertions);
-
-}  // namespace ios_internal
+void TabSwitcherMinimalReplacementOperations(std::vector<size_t> const& initial,
+                                             std::vector<size_t> const& final,
+                                             std::vector<size_t>* substitutions,
+                                             std::vector<size_t>* deletions,
+                                             std::vector<size_t>* insertions);
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_SWITCHER_UTILS_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm
index c6a3afd..af2c65d 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm
@@ -18,15 +18,49 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 
-namespace ios_internal {
+namespace {
 
 UIImage* DefaultFaviconImage() {
   return NativeImage(IDR_IOS_OMNIBOX_HTTP);
 }
 
-void GetFavicon(GURL const& url,
-                ios::ChromeBrowserState* browser_state,
-                ios_internal::FaviconGetterCompletionBlock block) {
+enum BacktrackOperation { NOTHING, SUBSTITUTION, DELETION, INSERTION };
+
+BacktrackOperation BacktrackOperationInCostMatrix(
+    std::vector<std::vector<int>> const& costMatrix,
+    size_t finalIndex,
+    size_t initialIndex) {
+  DCHECK(finalIndex || initialIndex);
+  DCHECK(initialIndex < costMatrix.size());
+  DCHECK(finalIndex < costMatrix[initialIndex].size());
+
+  if (finalIndex == 0)
+    return DELETION;
+  if (initialIndex == 0)
+    return INSERTION;
+
+  int currentCost = costMatrix[initialIndex][finalIndex];
+
+  int costBeforeInsertion = costMatrix[initialIndex][finalIndex - 1];
+  if (costBeforeInsertion + 1 == currentCost)
+    return INSERTION;
+
+  int costBeforeDeletion = costMatrix[initialIndex - 1][finalIndex];
+  if (costBeforeDeletion + 1 == currentCost)
+    return DELETION;
+
+  int costBeforeSubstitution = costMatrix[initialIndex - 1][finalIndex - 1];
+  if (costBeforeSubstitution == currentCost)
+    return NOTHING;
+
+  return SUBSTITUTION;
+}
+
+}  // namespace
+
+void TabSwitcherGetFavicon(GURL const& url,
+                           ios::ChromeBrowserState* browser_state,
+                           TabSwitcherFaviconGetterCompletionBlock block) {
   DCHECK(browser_state);
   syncer::SyncService* sync_service =
       IOSChromeProfileSyncServiceFactory::GetForBrowserState(browser_state);
@@ -70,43 +104,11 @@
   block(DefaultFaviconImage());
 }
 
-enum BacktrackOperation { NOTHING, SUBSTITUTION, DELETION, INSERTION };
-
-BacktrackOperation BacktrackOperationInCostMatrix(
-    std::vector<std::vector<int>> const& costMatrix,
-    size_t finalIndex,
-    size_t initialIndex) {
-  DCHECK(finalIndex || initialIndex);
-  DCHECK(initialIndex < costMatrix.size());
-  DCHECK(finalIndex < costMatrix[initialIndex].size());
-
-  if (finalIndex == 0)
-    return DELETION;
-  if (initialIndex == 0)
-    return INSERTION;
-
-  int currentCost = costMatrix[initialIndex][finalIndex];
-
-  int costBeforeInsertion = costMatrix[initialIndex][finalIndex - 1];
-  if (costBeforeInsertion + 1 == currentCost)
-    return INSERTION;
-
-  int costBeforeDeletion = costMatrix[initialIndex - 1][finalIndex];
-  if (costBeforeDeletion + 1 == currentCost)
-    return DELETION;
-
-  int costBeforeSubstitution = costMatrix[initialIndex - 1][finalIndex - 1];
-  if (costBeforeSubstitution == currentCost)
-    return NOTHING;
-
-  return SUBSTITUTION;
-}
-
-void MinimalReplacementOperations(std::vector<size_t> const& initial,
-                                  std::vector<size_t> const& final,
-                                  std::vector<size_t>* substitutions,
-                                  std::vector<size_t>* deletions,
-                                  std::vector<size_t>* insertions) {
+void TabSwitcherMinimalReplacementOperations(std::vector<size_t> const& initial,
+                                             std::vector<size_t> const& final,
+                                             std::vector<size_t>* substitutions,
+                                             std::vector<size_t>* deletions,
+                                             std::vector<size_t>* insertions) {
   DCHECK(substitutions);
   DCHECK(deletions);
   DCHECK(insertions);
@@ -185,5 +187,3 @@
   std::reverse(std::begin(*deletions), std::end(*deletions));
   std::reverse(std::begin(*insertions), std::end(*insertions));
 }
-
-}  // namespace ios_internal
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils_unittest.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils_unittest.mm
index 37d4537..1ccdee3 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils_unittest.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils_unittest.mm
@@ -18,8 +18,8 @@
     std::vector<size_t> substitutions;
     std::vector<size_t> deletions;
     std::vector<size_t> insertions;
-    ios_internal::MinimalReplacementOperations(initial, final, &substitutions,
-                                               &deletions, &insertions);
+    TabSwitcherMinimalReplacementOperations(initial, final, &substitutions,
+                                            &deletions, &insertions);
     EXPECT_EQ(substitutions, expectedSubstitutions);
     EXPECT_EQ(deletions, expectedDeletions);
     EXPECT_EQ(insertions, expectedInsertions);
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h
index 58eec55..73ea0ab7 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -91,8 +91,6 @@
   virtual std::string GetDistributionBrandCode();
   // Returns risk data used in Wallet requests.
   virtual std::string GetRiskData();
-  // Returns whether there is an Off-The-Record session active.
-  virtual bool IsOffTheRecordSessionActive();
   // Get the favicon for |page_url| and run |callback| with result when loaded.
   // Note. |callback| is always run asynchronously.
   virtual void GetFaviconForURL(
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.mm b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
index 211c80a..dab8adf 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.mm
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
@@ -66,10 +66,6 @@
   return std::string();
 }
 
-bool ChromeBrowserProvider::IsOffTheRecordSessionActive() {
-  return false;
-}
-
 void ChromeBrowserProvider::GetFaviconForURL(
     ios::ChromeBrowserState* browser_state,
     const GURL& page_url,
diff --git a/jingle/BUILD.gn b/jingle/BUILD.gn
index 0fc2541..10345a4 100644
--- a/jingle/BUILD.gn
+++ b/jingle/BUILD.gn
@@ -100,8 +100,7 @@
 
     public_deps = [
       "//third_party/libjingle",
-      "//third_party/webrtc/libjingle/xmllite",
-      "//third_party/webrtc/libjingle/xmpp",
+      "//third_party/libjingle_xmpp",
     ]
     deps = [
       ":jingle_glue",
@@ -173,8 +172,7 @@
 
     public_deps = [
       "//third_party/libjingle",
-      "//third_party/webrtc/libjingle/xmllite",
-      "//third_party/webrtc/libjingle/xmpp",
+      "//third_party/libjingle_xmpp",
     ]
     deps = [
       ":jingle_glue",
diff --git a/jingle/DEPS b/jingle/DEPS
index 948e91d..5a5a3f9 100644
--- a/jingle/DEPS
+++ b/jingle/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+net",
   "+third_party/libjingle",
-  "+third_party/webrtc/libjingle",
+  "+third_party/libjingle_xmpp/xmllite",
+  "+third_party/libjingle_xmpp/xmpp",
 ]
diff --git a/jingle/glue/chrome_async_socket.h b/jingle/glue/chrome_async_socket.h
index a00069a..7d6c9aa9 100644
--- a/jingle/glue/chrome_async_socket.h
+++ b/jingle/glue/chrome_async_socket.h
@@ -23,7 +23,7 @@
 #include "base/memory/weak_ptr.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
-#include "third_party/webrtc/libjingle/xmpp/asyncsocket.h"
+#include "third_party/libjingle_xmpp/xmpp/asyncsocket.h"
 
 namespace net {
 class IOBufferWithSize;
diff --git a/jingle/notifier/DEPS b/jingle/notifier/DEPS
index 56600f5da..80bd8ce 100644
--- a/jingle/notifier/DEPS
+++ b/jingle/notifier/DEPS
@@ -1,8 +1,5 @@
 include_rules = [
-  # notifier depends on libjingle.
-  "+talk/base",
-  "+talk/xmpp",
-  "+talk/xmllite",
-  "+webrtc/libjingle",
   "+webrtc/base",
+  "+third_party/libjingle_xmpp/xmpp",
+  "+third_party/libjingle_xmpp/xmllite",
 ]
diff --git a/jingle/notifier/base/fake_base_task.cc b/jingle/notifier/base/fake_base_task.cc
index 89f5bf8..21b8c530 100644
--- a/jingle/notifier/base/fake_base_task.cc
+++ b/jingle/notifier/base/fake_base_task.cc
@@ -8,7 +8,7 @@
 #include "jingle/notifier/base/fake_base_task.h"
 #include "jingle/notifier/base/weak_xmpp_client.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "webrtc/libjingle/xmpp/asyncsocket.h"
+#include "third_party/libjingle_xmpp/xmpp/asyncsocket.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/base/gaia_token_pre_xmpp_auth.cc b/jingle/notifier/base/gaia_token_pre_xmpp_auth.cc
index 657fd3ff..26fbfc43 100644
--- a/jingle/notifier/base/gaia_token_pre_xmpp_auth.cc
+++ b/jingle/notifier/base/gaia_token_pre_xmpp_auth.cc
@@ -8,9 +8,9 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h"
 #include "webrtc/base/socketaddress.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/saslcookiemechanism.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/base/gaia_token_pre_xmpp_auth.h b/jingle/notifier/base/gaia_token_pre_xmpp_auth.h
index 7b86bd5..86da7a04 100644
--- a/jingle/notifier/base/gaia_token_pre_xmpp_auth.h
+++ b/jingle/notifier/base/gaia_token_pre_xmpp_auth.h
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "webrtc/libjingle/xmpp/prexmppauth.h"
+#include "third_party/libjingle_xmpp/xmpp/prexmppauth.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/base/notifier_options_util.cc b/jingle/notifier/base/notifier_options_util.cc
index a8615b1..9754b2c7 100644
--- a/jingle/notifier/base/notifier_options_util.cc
+++ b/jingle/notifier/base/notifier_options_util.cc
@@ -7,8 +7,8 @@
 #include "base/logging.h"
 #include "jingle/notifier/base/const_communicator.h"
 #include "jingle/notifier/base/notifier_options.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/base/notifier_options_util.h b/jingle/notifier/base/notifier_options_util.h
index 2d14429..9ecb3cf 100644
--- a/jingle/notifier/base/notifier_options_util.h
+++ b/jingle/notifier/base/notifier_options_util.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "jingle/notifier/base/server_information.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/base/weak_xmpp_client.h b/jingle/notifier/base/weak_xmpp_client.h
index ab0137a3..16a68dd 100644
--- a/jingle/notifier/base/weak_xmpp_client.h
+++ b/jingle/notifier/base/weak_xmpp_client.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
 
 namespace rtc {
 class TaskParent;
diff --git a/jingle/notifier/base/xmpp_connection.cc b/jingle/notifier/base/xmpp_connection.cc
index efa62bc..8d71e5d9 100644
--- a/jingle/notifier/base/xmpp_connection.cc
+++ b/jingle/notifier/base/xmpp_connection.cc
@@ -17,7 +17,7 @@
 #include "net/socket/client_socket_factory.h"
 #include "net/ssl/ssl_config_service.h"
 #include "net/url_request/url_request_context.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/base/xmpp_connection.h b/jingle/notifier/base/xmpp_connection.h
index e41d914..1e1c2db 100644
--- a/jingle/notifier/base/xmpp_connection.h
+++ b/jingle/notifier/base/xmpp_connection.h
@@ -15,8 +15,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 #include "webrtc/base/sigslot.h"
-#include "webrtc/libjingle/xmpp/xmppengine.h"
 
 namespace buzz {
 class PreXmppAuth;
diff --git a/jingle/notifier/base/xmpp_connection_unittest.cc b/jingle/notifier/base/xmpp_connection_unittest.cc
index ee1b44d..4e07fcf7 100644
--- a/jingle/notifier/base/xmpp_connection_unittest.cc
+++ b/jingle/notifier/base/xmpp_connection_unittest.cc
@@ -21,8 +21,8 @@
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/libjingle/xmpp/prexmppauth.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/prexmppauth.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 
 namespace buzz {
 class CaptchaChallenge;
diff --git a/jingle/notifier/communicator/connection_settings.cc b/jingle/notifier/communicator/connection_settings.cc
index 3e8bc420..0e848d7f 100644
--- a/jingle/notifier/communicator/connection_settings.cc
+++ b/jingle/notifier/communicator/connection_settings.cc
@@ -8,10 +8,10 @@
 
 #include "base/logging.h"
 
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
 // Ideally we shouldn't include anything from talk/p2p, but we need
 // the definition of ProtocolType.  Don't use any functions from
 // port.h, since it won't link.
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 #include "webrtc/p2p/base/port.h"
 
 namespace notifier {
diff --git a/jingle/notifier/communicator/login.cc b/jingle/notifier/communicator/login.cc
index aacfa41031..ce7f85a 100644
--- a/jingle/notifier/communicator/login.cc
+++ b/jingle/notifier/communicator/login.cc
@@ -10,17 +10,17 @@
 #include "base/rand_util.h"
 #include "base/time/time.h"
 #include "net/base/host_port_pair.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/asyncsocket.h"
+#include "third_party/libjingle_xmpp/xmpp/prexmppauth.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 #include "webrtc/base/common.h"
 #include "webrtc/base/firewallsocketserver.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/physicalsocketserver.h"
 #include "webrtc/base/taskrunner.h"
-#include "webrtc/libjingle/xmpp/asyncsocket.h"
-#include "webrtc/libjingle/xmpp/prexmppauth.h"
-#include "webrtc/libjingle/xmpp/xmppclient.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
-#include "webrtc/libjingle/xmpp/xmppengine.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/communicator/login.h b/jingle/notifier/communicator/login.h
index 8f115f4..06c06ac0 100644
--- a/jingle/notifier/communicator/login.h
+++ b/jingle/notifier/communicator/login.h
@@ -18,7 +18,7 @@
 #include "jingle/notifier/communicator/login_settings.h"
 #include "jingle/notifier/communicator/single_login_attempt.h"
 #include "net/base/network_change_notifier.h"
-#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 
 namespace buzz {
 class XmppClientSettings;
diff --git a/jingle/notifier/communicator/login_settings.h b/jingle/notifier/communicator/login_settings.h
index c797bdd..ae81e7f5 100644
--- a/jingle/notifier/communicator/login_settings.h
+++ b/jingle/notifier/communicator/login_settings.h
@@ -10,7 +10,7 @@
 #include "base/time/time.h"
 #include "jingle/notifier/base/server_information.h"
 #include "net/url_request/url_request_context_getter.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/communicator/login_settings_unittest.cc b/jingle/notifier/communicator/login_settings_unittest.cc
index 72e769a..fb0034f 100644
--- a/jingle/notifier/communicator/login_settings_unittest.cc
+++ b/jingle/notifier/communicator/login_settings_unittest.cc
@@ -7,7 +7,7 @@
 #include <cstddef>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/communicator/single_login_attempt.cc b/jingle/notifier/communicator/single_login_attempt.cc
index 5b24b5d..a8d0732 100644
--- a/jingle/notifier/communicator/single_login_attempt.cc
+++ b/jingle/notifier/communicator/single_login_attempt.cc
@@ -16,9 +16,9 @@
 #include "jingle/notifier/base/gaia_token_pre_xmpp_auth.h"
 #include "jingle/notifier/listener/xml_element_util.h"
 #include "net/base/host_port_pair.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/communicator/single_login_attempt.h b/jingle/notifier/communicator/single_login_attempt.h
index b31280b5..f5b05e6 100644
--- a/jingle/notifier/communicator/single_login_attempt.h
+++ b/jingle/notifier/communicator/single_login_attempt.h
@@ -12,7 +12,7 @@
 #include "jingle/notifier/base/xmpp_connection.h"
 #include "jingle/notifier/communicator/connection_settings.h"
 #include "jingle/notifier/communicator/login_settings.h"
-#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 
 namespace buzz {
 class XmppTaskParentInterface;
diff --git a/jingle/notifier/communicator/single_login_attempt_unittest.cc b/jingle/notifier/communicator/single_login_attempt_unittest.cc
index 298907c..f200d88 100644
--- a/jingle/notifier/communicator/single_login_attempt_unittest.cc
+++ b/jingle/notifier/communicator/single_login_attempt_unittest.cc
@@ -17,9 +17,9 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 
 namespace buzz {
 class XmppTaskParentInterface;
diff --git a/jingle/notifier/listener/push_notifications_listen_task.cc b/jingle/notifier/listener/push_notifications_listen_task.cc
index 4e6a276d..7aff7a2e 100644
--- a/jingle/notifier/listener/push_notifications_listen_task.cc
+++ b/jingle/notifier/listener/push_notifications_listen_task.cc
@@ -9,12 +9,12 @@
 #include "jingle/notifier/listener/notification_constants.h"
 #include "jingle/notifier/listener/notification_defines.h"
 #include "jingle/notifier/listener/xml_element_util.h"
-#include "third_party/webrtc/libjingle/xmllite/qname.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 #include "webrtc/base/task.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/xmppclient.h"
-#include "webrtc/libjingle/xmpp/xmppengine.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/listener/push_notifications_listen_task.h b/jingle/notifier/listener/push_notifications_listen_task.h
index 033827a..3f7028f 100644
--- a/jingle/notifier/listener/push_notifications_listen_task.h
+++ b/jingle/notifier/listener/push_notifications_listen_task.h
@@ -15,7 +15,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
 
 namespace buzz {
 class XmlElement;
diff --git a/jingle/notifier/listener/push_notifications_send_update_task.cc b/jingle/notifier/listener/push_notifications_send_update_task.cc
index 68d632a..87108d97 100644
--- a/jingle/notifier/listener/push_notifications_send_update_task.cc
+++ b/jingle/notifier/listener/push_notifications_send_update_task.cc
@@ -13,11 +13,11 @@
 #include "base/logging.h"
 #include "jingle/notifier/listener/notification_constants.h"
 #include "jingle/notifier/listener/xml_element_util.h"
-#include "third_party/webrtc/libjingle/xmllite/qname.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/jid.h"
-#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/listener/push_notifications_send_update_task.h b/jingle/notifier/listener/push_notifications_send_update_task.h
index d8fc7d0f..b0d111a 100644
--- a/jingle/notifier/listener/push_notifications_send_update_task.h
+++ b/jingle/notifier/listener/push_notifications_send_update_task.h
@@ -11,7 +11,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "jingle/notifier/listener/notification_defines.h"
-#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
 
 namespace buzz {
 class Jid;
diff --git a/jingle/notifier/listener/push_notifications_send_update_task_unittest.cc b/jingle/notifier/listener/push_notifications_send_update_task_unittest.cc
index edd80a2e..bf2b83b 100644
--- a/jingle/notifier/listener/push_notifications_send_update_task_unittest.cc
+++ b/jingle/notifier/listener/push_notifications_send_update_task_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/strings/stringprintf.h"
 #include "jingle/notifier/listener/xml_element_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/libjingle/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
 
 namespace buzz {
 class XmlElement;
diff --git a/jingle/notifier/listener/push_notifications_subscribe_task.cc b/jingle/notifier/listener/push_notifications_subscribe_task.cc
index ec7ec06..c7a324b5 100644
--- a/jingle/notifier/listener/push_notifications_subscribe_task.cc
+++ b/jingle/notifier/listener/push_notifications_subscribe_task.cc
@@ -10,12 +10,12 @@
 #include "base/logging.h"
 #include "jingle/notifier/listener/notification_constants.h"
 #include "jingle/notifier/listener/xml_element_util.h"
-#include "third_party/webrtc/libjingle/xmllite/qname.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 #include "webrtc/base/task.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/xmppclient.h"
-#include "webrtc/libjingle/xmpp/xmppengine.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/listener/push_notifications_subscribe_task.h b/jingle/notifier/listener/push_notifications_subscribe_task.h
index 3a90f70..4dad3c4 100644
--- a/jingle/notifier/listener/push_notifications_subscribe_task.h
+++ b/jingle/notifier/listener/push_notifications_subscribe_task.h
@@ -14,8 +14,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "jingle/notifier/listener/notification_defines.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
 
 namespace notifier {
 class PushNotificationsSubscribeTask : public buzz::XmppTask {
diff --git a/jingle/notifier/listener/push_notifications_subscribe_task_unittest.cc b/jingle/notifier/listener/push_notifications_subscribe_task_unittest.cc
index 11530b17..af638667 100644
--- a/jingle/notifier/listener/push_notifications_subscribe_task_unittest.cc
+++ b/jingle/notifier/listener/push_notifications_subscribe_task_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/strings/stringprintf.h"
 #include "jingle/notifier/listener/xml_element_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/libjingle/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
 
 namespace buzz {
 class XmlElement;
diff --git a/jingle/notifier/listener/send_ping_task.cc b/jingle/notifier/listener/send_ping_task.cc
index 2260adfb..0bf205e 100644
--- a/jingle/notifier/listener/send_ping_task.cc
+++ b/jingle/notifier/listener/send_ping_task.cc
@@ -9,11 +9,11 @@
 
 #include "base/logging.h"
 #include "jingle/notifier/listener/xml_element_util.h"
-#include "third_party/webrtc/libjingle/xmllite/qname.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "webrtc/libjingle/xmpp/constants.h"
-#include "webrtc/libjingle/xmpp/jid.h"
-#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/listener/send_ping_task.h b/jingle/notifier/listener/send_ping_task.h
index 75f9fb70..8f8ea78 100644
--- a/jingle/notifier/listener/send_ping_task.h
+++ b/jingle/notifier/listener/send_ping_task.h
@@ -10,7 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
 
 namespace buzz {
 class XmlElement;
diff --git a/jingle/notifier/listener/send_ping_task_unittest.cc b/jingle/notifier/listener/send_ping_task_unittest.cc
index 4f7f61d..e1b4296 100644
--- a/jingle/notifier/listener/send_ping_task_unittest.cc
+++ b/jingle/notifier/listener/send_ping_task_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "jingle/notifier/listener/xml_element_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/libjingle/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
 
 namespace buzz {
 class XmlElement;
diff --git a/jingle/notifier/listener/xml_element_util.cc b/jingle/notifier/listener/xml_element_util.cc
index 280485e..2224cccf5 100644
--- a/jingle/notifier/listener/xml_element_util.cc
+++ b/jingle/notifier/listener/xml_element_util.cc
@@ -8,10 +8,10 @@
 #include <string>
 
 #include "base/strings/string_number_conversions.h"
-#include "third_party/webrtc/libjingle/xmllite/qname.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlconstants.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlprinter.h"
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
 
 namespace notifier {
 
diff --git a/jingle/notifier/listener/xml_element_util_unittest.cc b/jingle/notifier/listener/xml_element_util_unittest.cc
index 3c4c0ad..e5212da 100644
--- a/jingle/notifier/listener/xml_element_util_unittest.cc
+++ b/jingle/notifier/listener/xml_element_util_unittest.cc
@@ -9,9 +9,9 @@
 #include <string>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/qname.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlprinter.h"
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
 
 namespace buzz {
 class XmlElement;
diff --git a/jingle/notifier/listener/xmpp_push_client.h b/jingle/notifier/listener/xmpp_push_client.h
index 5cd826f..6472a08 100644
--- a/jingle/notifier/listener/xmpp_push_client.h
+++ b/jingle/notifier/listener/xmpp_push_client.h
@@ -22,7 +22,7 @@
 #include "jingle/notifier/listener/push_notifications_listen_task.h"
 #include "jingle/notifier/listener/push_notifications_subscribe_task.h"
 #include "jingle/notifier/listener/send_ping_task.h"
-#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 
 namespace buzz {
 class XmppTaskParentInterface;
diff --git a/media/filters/decoder_stream_traits.cc b/media/filters/decoder_stream_traits.cc
index 645a1de4..fcbc19e 100644
--- a/media/filters/decoder_stream_traits.cc
+++ b/media/filters/decoder_stream_traits.cc
@@ -144,6 +144,7 @@
   UMA_HISTOGRAM_MEDIUM_TIMES(
       "Media.Video.KeyFrameDistance",
       current_frame_timestamp - last_keyframe_timestamp_);
+  last_keyframe_timestamp_ = current_frame_timestamp;
 }
 
 }  // namespace media
diff --git a/net/extras/sqlite/sqlite_channel_id_store.cc b/net/extras/sqlite/sqlite_channel_id_store.cc
index 238577fd..ebcf7ec7 100644
--- a/net/extras/sqlite/sqlite_channel_id_store.cc
+++ b/net/extras/sqlite/sqlite_channel_id_store.cc
@@ -227,8 +227,7 @@
     smt.ColumnBlobAsVector(2, &public_key_from_db);
     std::unique_ptr<crypto::ECPrivateKey> key(
         crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-            ChannelIDService::kEPKIPassword, private_key_from_db,
-            public_key_from_db));
+            private_key_from_db, public_key_from_db));
     if (!key)
       continue;
     std::unique_ptr<DefaultChannelIDStore::ChannelID> channel_id(
@@ -498,8 +497,7 @@
         add_statement.Reset(true);
         add_statement.BindString(0, po->channel_id().server_identifier());
         std::vector<uint8_t> private_key, public_key;
-        if (!po->channel_id().key()->ExportEncryptedPrivateKey(
-                ChannelIDService::kEPKIPassword, 1, &private_key))
+        if (!po->channel_id().key()->ExportEncryptedPrivateKey(&private_key))
           continue;
         if (!po->channel_id().key()->ExportPublicKey(&public_key))
           continue;
diff --git a/net/extras/sqlite/sqlite_channel_id_store_unittest.cc b/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
index 8cb2bb12..7c9b223 100644
--- a/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
@@ -65,8 +65,8 @@
     ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(*cert_data, &spki));
     std::vector<uint8_t> public_key(spki.size());
     memcpy(public_key.data(), spki.data(), spki.size());
-    *key = crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-        ChannelIDService::kEPKIPassword, private_key, public_key);
+    *key = crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(private_key,
+                                                                   public_key);
   }
 
   static base::Time GetTestCertExpirationTime() {
diff --git a/net/ssl/channel_id_service.cc b/net/ssl/channel_id_service.cc
index 53c3c636..74ab3816 100644
--- a/net/ssl/channel_id_service.cc
+++ b/net/ssl/channel_id_service.cc
@@ -201,9 +201,6 @@
   bool create_if_missing_;
 };
 
-// static
-const char ChannelIDService::kEPKIPassword[] = "";
-
 ChannelIDService::Request::Request() : service_(NULL) {
 }
 
diff --git a/net/ssl/channel_id_service.h b/net/ssl/channel_id_service.h
index d9de879..617a297 100644
--- a/net/ssl/channel_id_service.h
+++ b/net/ssl/channel_id_service.h
@@ -69,11 +69,6 @@
     ChannelIDServiceJob* job_;
   };
 
-  // Password used on EncryptedPrivateKeyInfo data stored in EC private_key
-  // values.  (This is not used to provide any security, but to workaround NSS
-  // being unable to import unencrypted PrivateKeyInfo for EC keys.)
-  static const char kEPKIPassword[];
-
   // This object owns |channel_id_store|.  |task_runner| will
   // be used to post channel ID generation worker tasks.  The tasks are
   // safe for use with WorkerPool and SequencedWorkerPool::CONTINUE_ON_SHUTDOWN.
diff --git a/net/ssl/ssl_platform_key_nss_unittest.cc b/net/ssl/ssl_platform_key_nss_unittest.cc
index 85799cae..350c462 100644
--- a/net/ssl/ssl_platform_key_nss_unittest.cc
+++ b/net/ssl/ssl_platform_key_nss_unittest.cc
@@ -74,7 +74,7 @@
         crypto::ECPrivateKey::CreateFromPrivateKeyInfo(pkcs8_vector);
     ASSERT_TRUE(ec_private_key);
     std::vector<uint8_t> encrypted;
-    ASSERT_TRUE(ec_private_key->ExportEncryptedPrivateKey("", 1, &encrypted));
+    ASSERT_TRUE(ec_private_key->ExportEncryptedPrivateKey(&encrypted));
 
     SECItem encrypted_item = {siBuffer, encrypted.data(),
                               static_cast<unsigned>(encrypted.size())};
diff --git a/remoting/DEPS b/remoting/DEPS
index 08af137..9dab5fcb 100644
--- a/remoting/DEPS
+++ b/remoting/DEPS
@@ -11,10 +11,10 @@
   "+third_party/libvpx",
   "+third_party/libyuv",
   "+third_party/webrtc/base",
-  "+third_party/webrtc/libjingle",
   "+third_party/webrtc/media",
   "+third_party/webrtc/p2p",
   "+third_party/webrtc/modules/desktop_capture",
+  "+third_party/libjingle_xmpp/xmllite",
   "+ui/base/keycodes",
   "+ui/base/l10n",
   "+ui/base/resource",
diff --git a/remoting/client/client_status_logger_unittest.cc b/remoting/client/client_status_logger_unittest.cc
index f63871e2..e308bf9 100644
--- a/remoting/client/client_status_logger_unittest.cc
+++ b/remoting/client/client_status_logger_unittest.cc
@@ -11,7 +11,7 @@
 #include "remoting/signaling/server_log_entry_unittest.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using buzz::XmlElement;
 using buzz::QName;
diff --git a/remoting/client/server_log_entry_client_unittest.cc b/remoting/client/server_log_entry_client_unittest.cc
index 294a97f..b9b1bfa 100644
--- a/remoting/client/server_log_entry_client_unittest.cc
+++ b/remoting/client/server_log_entry_client_unittest.cc
@@ -12,7 +12,7 @@
 #include "remoting/signaling/server_log_entry.h"
 #include "remoting/signaling/server_log_entry_unittest.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using base::SysInfo;
 using buzz::XmlAttr;
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 6a09a0c..4798ee17 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -471,8 +471,7 @@
   if (enable_webrtc) {
     public_deps += [
       "//third_party/libjingle/webrtc:libjingle_webrtc",
-      "//third_party/webrtc/libjingle/xmllite",
-      "//third_party/webrtc/libjingle/xmpp",
+      "//third_party/libjingle_xmpp",
       "//third_party/webrtc/modules/desktop_capture",
     ]
   }
@@ -625,8 +624,7 @@
     if (enable_webrtc) {
       deps += [
         "//third_party/libjingle/webrtc:libjingle_webrtc",
-        "//third_party/webrtc/libjingle/xmllite",
-        "//third_party/webrtc/libjingle/xmpp",
+        "//third_party/libjingle_xmpp",
       ]
     }
   }
@@ -742,8 +740,7 @@
     if (enable_webrtc) {
       deps += [
         "//third_party/libjingle/webrtc:libjingle_webrtc",
-        "//third_party/webrtc/libjingle/xmllite",
-        "//third_party/webrtc/libjingle/xmpp",
+        "//third_party/libjingle_xmpp",
       ]
     }
 
diff --git a/remoting/host/DEPS b/remoting/host/DEPS
index a9a7eb0..5ee2145 100644
--- a/remoting/host/DEPS
+++ b/remoting/host/DEPS
@@ -16,6 +16,7 @@
   "+third_party/jsoncpp",
   "+third_party/skia",
   "+third_party/webrtc",
+  "+third_party/libjingle_xmpp/xmpp",
   "+ui",
 ]
 
diff --git a/remoting/host/heartbeat_sender.cc b/remoting/host/heartbeat_sender.cc
index 5f641f6..e452b5e 100644
--- a/remoting/host/heartbeat_sender.cc
+++ b/remoting/host/heartbeat_sender.cc
@@ -22,8 +22,8 @@
 #include "remoting/signaling/jid_util.h"
 #include "remoting/signaling/server_log_entry.h"
 #include "remoting/signaling/signal_strategy.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/host/heartbeat_sender_unittest.cc b/remoting/host/heartbeat_sender_unittest.cc
index 9253ac6e..e537288 100644
--- a/remoting/host/heartbeat_sender_unittest.cc
+++ b/remoting/host/heartbeat_sender_unittest.cc
@@ -17,8 +17,8 @@
 #include "remoting/signaling/mock_signal_strategy.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/host/host_change_notification_listener.cc b/remoting/host/host_change_notification_listener.cc
index 421822bd..3c079f1 100644
--- a/remoting/host/host_change_notification_listener.cc
+++ b/remoting/host/host_change_notification_listener.cc
@@ -11,8 +11,8 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "remoting/base/constants.h"
 #include "remoting/protocol/jingle_messages.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/host/host_change_notification_listener_unittest.cc b/remoting/host/host_change_notification_listener_unittest.cc
index 1a1d466..7bbf290b 100644
--- a/remoting/host/host_change_notification_listener_unittest.cc
+++ b/remoting/host/host_change_notification_listener_unittest.cc
@@ -16,8 +16,8 @@
 #include "remoting/signaling/mock_signal_strategy.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/host/host_status_logger_unittest.cc b/remoting/host/host_status_logger_unittest.cc
index 6b24ccf7..fee9ae4 100644
--- a/remoting/host/host_status_logger_unittest.cc
+++ b/remoting/host/host_status_logger_unittest.cc
@@ -11,7 +11,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gmock_mutant.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using buzz::XmlElement;
 using buzz::QName;
diff --git a/remoting/host/pam_authorization_factory_posix.cc b/remoting/host/pam_authorization_factory_posix.cc
index 35da4cd3..1e7c2c5 100644
--- a/remoting/host/pam_authorization_factory_posix.cc
+++ b/remoting/host/pam_authorization_factory_posix.cc
@@ -15,7 +15,7 @@
 #include "remoting/base/logging.h"
 #include "remoting/host/username.h"
 #include "remoting/protocol/channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 
diff --git a/remoting/host/register_support_host_request.cc b/remoting/host/register_support_host_request.cc
index 48d42279..ef25c4a 100644
--- a/remoting/host/register_support_host_request.cc
+++ b/remoting/host/register_support_host_request.cc
@@ -17,8 +17,8 @@
 #include "remoting/signaling/iq_sender.h"
 #include "remoting/signaling/jid_util.h"
 #include "remoting/signaling/signal_strategy.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/host/register_support_host_request_unittest.cc b/remoting/host/register_support_host_request_unittest.cc
index a467476..aed7da0 100644
--- a/remoting/host/register_support_host_request_unittest.cc
+++ b/remoting/host/register_support_host_request_unittest.cc
@@ -19,8 +19,8 @@
 #include "remoting/signaling/mock_signal_strategy.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/host/server_log_entry_host_unittest.cc b/remoting/host/server_log_entry_host_unittest.cc
index f70d4311..b6376e266 100644
--- a/remoting/host/server_log_entry_host_unittest.cc
+++ b/remoting/host/server_log_entry_host_unittest.cc
@@ -11,7 +11,7 @@
 #include "remoting/signaling/server_log_entry.h"
 #include "remoting/signaling/server_log_entry_unittest.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using buzz::XmlAttr;
 using buzz::XmlElement;
diff --git a/remoting/protocol/BUILD.gn b/remoting/protocol/BUILD.gn
index 25742c8..9656bb8 100644
--- a/remoting/protocol/BUILD.gn
+++ b/remoting/protocol/BUILD.gn
@@ -243,8 +243,7 @@
     if (enable_webrtc) {
       deps += [
         "//third_party/libjingle/webrtc:libjingle_webrtc",
-        "//third_party/webrtc/libjingle/xmllite",
-        "//third_party/webrtc/libjingle/xmpp",
+        "//third_party/libjingle_xmpp",
       ]
     } else {
       sources -= [
diff --git a/remoting/protocol/DEPS b/remoting/protocol/DEPS
index 20afa9ee..b5d7cb4 100644
--- a/remoting/protocol/DEPS
+++ b/remoting/protocol/DEPS
@@ -8,8 +8,8 @@
   "+remoting/codec",
   "+remoting/signaling",
   "+third_party/boringssl",
-  "+third_party/libjingle",
-  "+third_party/webrtc",
+  "+third_party/libjingle_xmpp/xmpp",
   "+third_party/protobuf/src",
+  "+third_party/webrtc",
   "+ui/events/keycodes/dom",
 ]
diff --git a/remoting/protocol/authenticator.cc b/remoting/protocol/authenticator.cc
index 1b029c67..f8c1285 100644
--- a/remoting/protocol/authenticator.cc
+++ b/remoting/protocol/authenticator.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "remoting/base/constants.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/authenticator_test_base.cc b/remoting/protocol/authenticator_test_base.cc
index 879afc2..7b26f0a 100644
--- a/remoting/protocol/authenticator_test_base.cc
+++ b/remoting/protocol/authenticator_test_base.cc
@@ -20,7 +20,7 @@
 #include "remoting/protocol/fake_stream_socket.h"
 #include "remoting/protocol/p2p_stream_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using testing::_;
 using testing::SaveArg;
diff --git a/remoting/protocol/content_description.cc b/remoting/protocol/content_description.cc
index 6ac678d..96baafe 100644
--- a/remoting/protocol/content_description.cc
+++ b/remoting/protocol/content_description.cc
@@ -13,7 +13,7 @@
 #include "remoting/base/constants.h"
 #include "remoting/protocol/authenticator.h"
 #include "remoting/protocol/name_value_map.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/protocol/content_description_unittest.cc b/remoting/protocol/content_description_unittest.cc
index ca0eb56..8a88f22 100644
--- a/remoting/protocol/content_description_unittest.cc
+++ b/remoting/protocol/content_description_unittest.cc
@@ -11,7 +11,7 @@
 #include "remoting/protocol/authenticator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/fake_authenticator.cc b/remoting/protocol/fake_authenticator.cc
index 14bb06ae..a57845c 100644
--- a/remoting/protocol/fake_authenticator.cc
+++ b/remoting/protocol/fake_authenticator.cc
@@ -17,7 +17,7 @@
 #include "remoting/base/constants.h"
 #include "remoting/protocol/p2p_stream_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/fake_session.cc b/remoting/protocol/fake_session.cc
index 18c16ca..56cbd51 100644
--- a/remoting/protocol/fake_session.cc
+++ b/remoting/protocol/fake_session.cc
@@ -9,7 +9,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "remoting/protocol/fake_authenticator.h"
 #include "remoting/protocol/session_plugin.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/ice_transport_unittest.cc b/remoting/protocol/ice_transport_unittest.cc
index eea7878..ccb3d8d 100644
--- a/remoting/protocol/ice_transport_unittest.cc
+++ b/remoting/protocol/ice_transport_unittest.cc
@@ -25,7 +25,7 @@
 #include "remoting/protocol/transport_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using testing::_;
 
diff --git a/remoting/protocol/jingle_info_request.cc b/remoting/protocol/jingle_info_request.cc
index 7569dcc..b61b8c17 100644
--- a/remoting/protocol/jingle_info_request.cc
+++ b/remoting/protocol/jingle_info_request.cc
@@ -13,9 +13,9 @@
 #include "base/time/time.h"
 #include "remoting/protocol/ice_config.h"
 #include "remoting/signaling/iq_sender.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 #include "third_party/webrtc/base/socketaddress.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/jingle_messages.cc b/remoting/protocol/jingle_messages.cc
index 8c28fdf..e444a44 100644
--- a/remoting/protocol/jingle_messages.cc
+++ b/remoting/protocol/jingle_messages.cc
@@ -12,7 +12,7 @@
 #include "remoting/protocol/session_plugin.h"
 #include "remoting/signaling/jid_util.h"
 #include "remoting/signaling/remoting_bot.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/protocol/jingle_messages.h b/remoting/protocol/jingle_messages.h
index 019f35b..589a31e 100644
--- a/remoting/protocol/jingle_messages.h
+++ b/remoting/protocol/jingle_messages.h
@@ -10,7 +10,7 @@
 #include <string>
 
 #include "remoting/protocol/errors.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/webrtc/p2p/base/candidate.h"
 
 namespace remoting {
diff --git a/remoting/protocol/jingle_messages_unittest.cc b/remoting/protocol/jingle_messages_unittest.cc
index 38d4844..680900c 100644
--- a/remoting/protocol/jingle_messages_unittest.cc
+++ b/remoting/protocol/jingle_messages_unittest.cc
@@ -12,8 +12,8 @@
 #include "remoting/protocol/content_description.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlAttr;
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc
index bf86991..bb3eb73f 100644
--- a/remoting/protocol/jingle_session.cc
+++ b/remoting/protocol/jingle_session.cc
@@ -26,8 +26,8 @@
 #include "remoting/protocol/session_plugin.h"
 #include "remoting/protocol/transport.h"
 #include "remoting/signaling/iq_sender.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 #include "third_party/webrtc/p2p/base/candidate.h"
 
 using buzz::XmlElement;
diff --git a/remoting/protocol/jingle_session_manager.cc b/remoting/protocol/jingle_session_manager.cc
index a477cf4..5d564f7 100644
--- a/remoting/protocol/jingle_session_manager.cc
+++ b/remoting/protocol/jingle_session_manager.cc
@@ -14,9 +14,9 @@
 #include "remoting/protocol/transport.h"
 #include "remoting/signaling/iq_sender.h"
 #include "remoting/signaling/signal_strategy.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 #include "third_party/webrtc/base/socketaddress.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
 
 using buzz::QName;
 
diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc
index f97801c..4575e6e1 100644
--- a/remoting/protocol/jingle_session_unittest.cc
+++ b/remoting/protocol/jingle_session_unittest.cc
@@ -32,7 +32,7 @@
 #include "remoting/signaling/fake_signal_strategy.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using testing::_;
 using testing::AtLeast;
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc
index d80462f..6e63fbe 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.cc
+++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -15,7 +15,7 @@
 #include "remoting/protocol/rejecting_authenticator.h"
 #include "remoting/protocol/token_validator.h"
 #include "remoting/signaling/jid_util.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/negotiating_authenticator_base.cc b/remoting/protocol/negotiating_authenticator_base.cc
index 296d5ac..0c5a8018c 100644
--- a/remoting/protocol/negotiating_authenticator_base.cc
+++ b/remoting/protocol/negotiating_authenticator_base.cc
@@ -15,7 +15,7 @@
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/protocol/channel_authenticator.h"
 #include "remoting/protocol/name_value_map.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc
index cf3e96a..ae76795 100644
--- a/remoting/protocol/negotiating_authenticator_unittest.cc
+++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -19,7 +19,7 @@
 #include "remoting/protocol/protocol_mock_objects.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using testing::_;
 using testing::DeleteArg;
diff --git a/remoting/protocol/negotiating_client_authenticator.cc b/remoting/protocol/negotiating_client_authenticator.cc
index 9906b941..cc91e7e3 100644
--- a/remoting/protocol/negotiating_client_authenticator.cc
+++ b/remoting/protocol/negotiating_client_authenticator.cc
@@ -18,7 +18,7 @@
 #include "remoting/protocol/pairing_client_authenticator.h"
 #include "remoting/protocol/spake2_authenticator.h"
 #include "remoting/protocol/v2_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/negotiating_host_authenticator.cc b/remoting/protocol/negotiating_host_authenticator.cc
index bd896f0..c7b098e 100644
--- a/remoting/protocol/negotiating_host_authenticator.cc
+++ b/remoting/protocol/negotiating_host_authenticator.cc
@@ -19,7 +19,7 @@
 #include "remoting/protocol/spake2_authenticator.h"
 #include "remoting/protocol/token_validator.h"
 #include "remoting/protocol/v2_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/pairing_authenticator_base.h b/remoting/protocol/pairing_authenticator_base.h
index f1ccb3b2..81a8deaa 100644
--- a/remoting/protocol/pairing_authenticator_base.h
+++ b/remoting/protocol/pairing_authenticator_base.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "remoting/protocol/authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/pairing_client_authenticator.cc b/remoting/protocol/pairing_client_authenticator.cc
index b35e7fbf..9961035 100644
--- a/remoting/protocol/pairing_client_authenticator.cc
+++ b/remoting/protocol/pairing_client_authenticator.cc
@@ -9,7 +9,7 @@
 #include "remoting/base/constants.h"
 #include "remoting/protocol/auth_util.h"
 #include "remoting/protocol/channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/pairing_host_authenticator.cc b/remoting/protocol/pairing_host_authenticator.cc
index 7218530..173b263 100644
--- a/remoting/protocol/pairing_host_authenticator.cc
+++ b/remoting/protocol/pairing_host_authenticator.cc
@@ -8,7 +8,7 @@
 #include "base/logging.h"
 #include "remoting/base/constants.h"
 #include "remoting/protocol/channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/protocol_mock_objects.h b/remoting/protocol/protocol_mock_objects.h
index 0dc09e0..bb5a4572 100644
--- a/remoting/protocol/protocol_mock_objects.h
+++ b/remoting/protocol/protocol_mock_objects.h
@@ -31,7 +31,7 @@
 #include "remoting/protocol/transport.h"
 #include "remoting/protocol/video_stub.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 
diff --git a/remoting/protocol/rejecting_authenticator.cc b/remoting/protocol/rejecting_authenticator.cc
index b23f298..b332b1e 100644
--- a/remoting/protocol/rejecting_authenticator.cc
+++ b/remoting/protocol/rejecting_authenticator.cc
@@ -7,7 +7,7 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "remoting/protocol/channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/spake2_authenticator.cc b/remoting/protocol/spake2_authenticator.cc
index 55bbea32..7577f2e 100644
--- a/remoting/protocol/spake2_authenticator.cc
+++ b/remoting/protocol/spake2_authenticator.cc
@@ -16,7 +16,7 @@
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/protocol/ssl_hmac_channel_authenticator.h"
 #include "third_party/boringssl/src/include/openssl/curve25519.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/spake2_authenticator_unittest.cc b/remoting/protocol/spake2_authenticator_unittest.cc
index d203f00..9c8a40d 100644
--- a/remoting/protocol/spake2_authenticator_unittest.cc
+++ b/remoting/protocol/spake2_authenticator_unittest.cc
@@ -13,7 +13,7 @@
 #include "remoting/protocol/connection_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using testing::_;
 using testing::DeleteArg;
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc b/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
index cc93201..6b9aa21 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
+++ b/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
@@ -25,7 +25,7 @@
 #include "remoting/protocol/p2p_stream_socket.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using testing::_;
 using testing::NotNull;
diff --git a/remoting/protocol/third_party_authenticator_base.cc b/remoting/protocol/third_party_authenticator_base.cc
index ba03712..96b9796 100644
--- a/remoting/protocol/third_party_authenticator_base.cc
+++ b/remoting/protocol/third_party_authenticator_base.cc
@@ -11,7 +11,7 @@
 #include "remoting/base/constants.h"
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/protocol/channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/third_party_authenticator_base.h b/remoting/protocol/third_party_authenticator_base.h
index 6e2fe574..34905fb 100644
--- a/remoting/protocol/third_party_authenticator_base.h
+++ b/remoting/protocol/third_party_authenticator_base.h
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "remoting/protocol/authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
 
 namespace buzz {
 
diff --git a/remoting/protocol/third_party_authenticator_unittest.cc b/remoting/protocol/third_party_authenticator_unittest.cc
index 953bf45e..519f115a 100644
--- a/remoting/protocol/third_party_authenticator_unittest.cc
+++ b/remoting/protocol/third_party_authenticator_unittest.cc
@@ -22,7 +22,7 @@
 #include "remoting/protocol/v2_authenticator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using testing::_;
 using testing::DeleteArg;
diff --git a/remoting/protocol/third_party_client_authenticator.cc b/remoting/protocol/third_party_client_authenticator.cc
index dd21135..304865f 100644
--- a/remoting/protocol/third_party_client_authenticator.cc
+++ b/remoting/protocol/third_party_client_authenticator.cc
@@ -13,7 +13,7 @@
 #include "remoting/base/constants.h"
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/protocol/channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/third_party_host_authenticator.cc b/remoting/protocol/third_party_host_authenticator.cc
index 0024480..0d3972d 100644
--- a/remoting/protocol/third_party_host_authenticator.cc
+++ b/remoting/protocol/third_party_host_authenticator.cc
@@ -12,7 +12,7 @@
 #include "base/logging.h"
 #include "remoting/base/constants.h"
 #include "remoting/protocol/token_validator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/v2_authenticator.cc b/remoting/protocol/v2_authenticator.cc
index 9db2fef..42127bf3e 100644
--- a/remoting/protocol/v2_authenticator.cc
+++ b/remoting/protocol/v2_authenticator.cc
@@ -12,7 +12,7 @@
 #include "remoting/base/constants.h"
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/protocol/ssl_hmac_channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using crypto::P224EncryptedKeyExchange;
 
diff --git a/remoting/protocol/v2_authenticator_unittest.cc b/remoting/protocol/v2_authenticator_unittest.cc
index 1315ad3..689ea50 100644
--- a/remoting/protocol/v2_authenticator_unittest.cc
+++ b/remoting/protocol/v2_authenticator_unittest.cc
@@ -14,7 +14,7 @@
 #include "remoting/protocol/connection_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using testing::_;
 using testing::DeleteArg;
diff --git a/remoting/protocol/validating_authenticator.cc b/remoting/protocol/validating_authenticator.cc
index 0595cb25..ee622be 100644
--- a/remoting/protocol/validating_authenticator.cc
+++ b/remoting/protocol/validating_authenticator.cc
@@ -16,7 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "remoting/protocol/authenticator.h"
 #include "remoting/protocol/channel_authenticator.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/validating_authenticator_unittest.cc b/remoting/protocol/validating_authenticator_unittest.cc
index 32bed4c..dd23b72 100644
--- a/remoting/protocol/validating_authenticator_unittest.cc
+++ b/remoting/protocol/validating_authenticator_unittest.cc
@@ -17,7 +17,7 @@
 #include "remoting/protocol/validating_authenticator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc
index 5477e718b..e4ce98ae 100644
--- a/remoting/protocol/webrtc_transport.cc
+++ b/remoting/protocol/webrtc_transport.cc
@@ -28,8 +28,8 @@
 #include "remoting/protocol/transport_context.h"
 #include "remoting/protocol/webrtc_audio_module.h"
 #include "remoting/protocol/webrtc_dummy_video_encoder.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/webrtc/api/test/fakeconstraints.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/protocol/webrtc_transport_unittest.cc b/remoting/protocol/webrtc_transport_unittest.cc
index 59c644b..a2200c03 100644
--- a/remoting/protocol/webrtc_transport_unittest.cc
+++ b/remoting/protocol/webrtc_transport_unittest.cc
@@ -23,7 +23,7 @@
 #include "remoting/protocol/transport_context.h"
 #include "remoting/signaling/fake_signal_strategy.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 namespace protocol {
diff --git a/remoting/signaling/BUILD.gn b/remoting/signaling/BUILD.gn
index 7490c7ec..324f39d 100644
--- a/remoting/signaling/BUILD.gn
+++ b/remoting/signaling/BUILD.gn
@@ -35,8 +35,7 @@
   public_deps = [
     "//remoting/proto",
     "//third_party/libjingle",
-    "//third_party/webrtc/libjingle/xmllite",
-    "//third_party/webrtc/libjingle/xmpp",
+    "//third_party/libjingle_xmpp",
   ]
 
   deps = [
diff --git a/remoting/signaling/DEPS b/remoting/signaling/DEPS
index d6dad0c..735bee7 100644
--- a/remoting/signaling/DEPS
+++ b/remoting/signaling/DEPS
@@ -1,7 +1,7 @@
 include_rules = [
   "+net",
   "+jingle",
-  "+third_party/libjingle",
   "+third_party/webrtc/base",
-  "+third_party/webrtc/libjingle",
+  "+third_party/libjingle_xmpp/xmllite",
+  "+third_party/libjingle_xmpp/xmpp",
 ]
diff --git a/remoting/signaling/delegating_signal_strategy.cc b/remoting/signaling/delegating_signal_strategy.cc
index d0c10c05..83f23907 100644
--- a/remoting/signaling/delegating_signal_strategy.cc
+++ b/remoting/signaling/delegating_signal_strategy.cc
@@ -8,8 +8,8 @@
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 namespace remoting {
 
diff --git a/remoting/signaling/fake_signal_strategy.cc b/remoting/signaling/fake_signal_strategy.cc
index b0ecd38b..fed04e5 100644
--- a/remoting/signaling/fake_signal_strategy.cc
+++ b/remoting/signaling/fake_signal_strategy.cc
@@ -14,8 +14,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "remoting/signaling/jid_util.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 namespace remoting {
 
diff --git a/remoting/signaling/iq_sender.cc b/remoting/signaling/iq_sender.cc
index 725cc08..efa2528 100644
--- a/remoting/signaling/iq_sender.cc
+++ b/remoting/signaling/iq_sender.cc
@@ -17,8 +17,8 @@
 #include "base/time/time.h"
 #include "remoting/signaling/jid_util.h"
 #include "remoting/signaling/signal_strategy.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 namespace remoting {
 
diff --git a/remoting/signaling/iq_sender_unittest.cc b/remoting/signaling/iq_sender_unittest.cc
index 810d5df..c03abd6 100644
--- a/remoting/signaling/iq_sender_unittest.cc
+++ b/remoting/signaling/iq_sender_unittest.cc
@@ -14,8 +14,8 @@
 #include "remoting/signaling/mock_signal_strategy.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using ::testing::_;
 using ::testing::DeleteArg;
diff --git a/remoting/signaling/log_to_server.cc b/remoting/signaling/log_to_server.cc
index 0116cce6..5e05ace 100644
--- a/remoting/signaling/log_to_server.cc
+++ b/remoting/signaling/log_to_server.cc
@@ -9,8 +9,8 @@
 #include "remoting/base/constants.h"
 #include "remoting/signaling/iq_sender.h"
 #include "remoting/signaling/signal_strategy.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/remoting/signaling/mock_signal_strategy.h b/remoting/signaling/mock_signal_strategy.h
index 79c3ea5..e4455f4 100644
--- a/remoting/signaling/mock_signal_strategy.h
+++ b/remoting/signaling/mock_signal_strategy.h
@@ -7,7 +7,7 @@
 #include "remoting/signaling/iq_sender.h"
 #include "remoting/signaling/signal_strategy.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 
diff --git a/remoting/signaling/push_notification_subscriber.cc b/remoting/signaling/push_notification_subscriber.cc
index 0984df66..bbeb02b 100644
--- a/remoting/signaling/push_notification_subscriber.cc
+++ b/remoting/signaling/push_notification_subscriber.cc
@@ -10,7 +10,7 @@
 #include "remoting/base/logging.h"
 #include "remoting/signaling/iq_sender.h"
 #include "remoting/signaling/jid_util.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 
diff --git a/remoting/signaling/server_log_entry.cc b/remoting/signaling/server_log_entry.cc
index aa8651f9..0b7b54dd 100644
--- a/remoting/signaling/server_log_entry.cc
+++ b/remoting/signaling/server_log_entry.cc
@@ -8,7 +8,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/sys_info.h"
 #include "remoting/base/constants.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using base::SysInfo;
 using buzz::QName;
diff --git a/remoting/signaling/server_log_entry_unittest.cc b/remoting/signaling/server_log_entry_unittest.cc
index ac3506d..80b5b22 100644
--- a/remoting/signaling/server_log_entry_unittest.cc
+++ b/remoting/signaling/server_log_entry_unittest.cc
@@ -7,7 +7,7 @@
 #include <sstream>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 using buzz::QName;
 using buzz::XmlAttr;
diff --git a/remoting/signaling/xmpp_login_handler.cc b/remoting/signaling/xmpp_login_handler.cc
index 1e83af8..d47da51 100644
--- a/remoting/signaling/xmpp_login_handler.cc
+++ b/remoting/signaling/xmpp_login_handler.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "remoting/signaling/xmpp_stream_parser.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 // Undefine SendMessage and ERROR defined in Windows headers.
 #ifdef SendMessage
diff --git a/remoting/signaling/xmpp_login_handler_unittest.cc b/remoting/signaling/xmpp_login_handler_unittest.cc
index 885c4ce7..c25206a2 100644
--- a/remoting/signaling/xmpp_login_handler_unittest.cc
+++ b/remoting/signaling/xmpp_login_handler_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/run_loop.h"
 #include "remoting/signaling/xmpp_stream_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 #ifdef SendMessage
 #undef SendMessage
diff --git a/remoting/signaling/xmpp_signal_strategy.cc b/remoting/signaling/xmpp_signal_strategy.cc
index 8a019e4..32ab100 100644
--- a/remoting/signaling/xmpp_signal_strategy.cc
+++ b/remoting/signaling/xmpp_signal_strategy.cc
@@ -32,7 +32,7 @@
 #include "remoting/base/logging.h"
 #include "remoting/signaling/xmpp_login_handler.h"
 #include "remoting/signaling/xmpp_stream_parser.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 // Use 50 seconds keep-alive interval, in case routers terminate
 // connections that are idle for more than a minute.
diff --git a/remoting/signaling/xmpp_signal_strategy_unittest.cc b/remoting/signaling/xmpp_signal_strategy_unittest.cc
index e991ec0..53147bc 100644
--- a/remoting/signaling/xmpp_signal_strategy_unittest.cc
+++ b/remoting/signaling/xmpp_signal_strategy_unittest.cc
@@ -13,7 +13,7 @@
 #include "net/socket/socket_test_util.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 
diff --git a/remoting/signaling/xmpp_stream_parser.cc b/remoting/signaling/xmpp_stream_parser.cc
index ee029de..d43ed02 100644
--- a/remoting/signaling/xmpp_stream_parser.cc
+++ b/remoting/signaling/xmpp_stream_parser.cc
@@ -10,9 +10,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlbuilder.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlparser.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
 
 namespace remoting {
 
diff --git a/remoting/signaling/xmpp_stream_parser_unittest.cc b/remoting/signaling/xmpp_stream_parser_unittest.cc
index 0b6dc1b4..299d9f7 100644
--- a/remoting/signaling/xmpp_stream_parser_unittest.cc
+++ b/remoting/signaling/xmpp_stream_parser_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
 namespace remoting {
 
diff --git a/skia/ext/bitmap_platform_device_cairo.h b/skia/ext/bitmap_platform_device_cairo.h
index d1c9c350..5e6a6f3 100644
--- a/skia/ext/bitmap_platform_device_cairo.h
+++ b/skia/ext/bitmap_platform_device_cairo.h
@@ -46,8 +46,6 @@
 
 namespace skia {
 
-class ScopedPlatformPaint;
-
 // -----------------------------------------------------------------------------
 // This is the Linux bitmap backing for Skia. We create a Cairo image surface
 // to store the backing buffer. This buffer is BGRA in memory (on little-endian
@@ -98,14 +96,7 @@
   // Graphics context used to draw into the surface.
   cairo_t* cairo_;
 
-  // True when there is a transform or clip that has not been set to the
-  // context.  The context is retrieved for every text operation, and the
-  // transform and clip do not change as much. We can save time by not loading
-  // the clip and transform for every one.
-  bool config_dirty_;
-
   DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice);
-  friend class ScopedPlatformPaint;
 };
 
 }  // namespace skia
diff --git a/skia/ext/bitmap_platform_device_mac_unittest.cc b/skia/ext/bitmap_platform_device_mac_unittest.cc
index 9d8020b0..05d5089 100644
--- a/skia/ext/bitmap_platform_device_mac_unittest.cc
+++ b/skia/ext/bitmap_platform_device_mac_unittest.cc
@@ -36,8 +36,7 @@
       skia::CreateCanvas(bitmap_, CRASH_ON_FAILURE);
   canvas->setMatrix(transform);
 
-  ScopedPlatformPaint p(canvas.get());
-  CGContextRef context = p.GetNativeDrawingContext();
+  CGContextRef context = skia::GetNativeDrawingContext(canvas.get());
 
   SkRect clip_rect = skia::CGRectToSkRect(CGContextGetClipBoundingBox(context));
   transform.mapRect(&clip_rect);
@@ -55,8 +54,7 @@
       skia::CreateCanvas(bitmap_, CRASH_ON_FAILURE);
   canvas->setMatrix(transform);
 
-  ScopedPlatformPaint p(canvas.get());
-  CGContextRef context = p.GetNativeDrawingContext();
+  CGContextRef context = skia::GetNativeDrawingContext(canvas.get());
 
   SkRect clip_rect = skia::CGRectToSkRect(CGContextGetClipBoundingBox(context));
   transform.mapRect(&clip_rect);
diff --git a/skia/ext/bitmap_platform_device_skia.h b/skia/ext/bitmap_platform_device_skia.h
index 854de47..024064f 100644
--- a/skia/ext/bitmap_platform_device_skia.h
+++ b/skia/ext/bitmap_platform_device_skia.h
@@ -14,8 +14,6 @@
 
 namespace skia {
 
-class ScopedPlatformPaint;
-
 // -----------------------------------------------------------------------------
 // For now we just use SkBitmap for SkBitmapDevice
 //
@@ -50,8 +48,6 @@
                                           const SkIRect& clip_bounds) override;
 
   DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice);
-
-  friend class ScopedPlatformPaint;
 };
 
 }  // namespace skia
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc
index b792c0fd..8270be32 100644
--- a/skia/ext/bitmap_platform_device_win.cc
+++ b/skia/ext/bitmap_platform_device_win.cc
@@ -35,7 +35,6 @@
 
 void DrawToNativeContext(SkCanvas* canvas, HDC destination_hdc, int x, int y,
                          const RECT* src_rect) {
-  ScopedPlatformPaint p(canvas);
   RECT temp_rect;
   if (!src_rect) {
     temp_rect.left = 0;
@@ -44,7 +43,7 @@
     temp_rect.bottom = canvas->imageInfo().height();
     src_rect = &temp_rect;
   }
-  skia::CopyHDC(p.GetNativeDrawingContext(), destination_hdc, x, y,
+  skia::CopyHDC(skia::GetNativeDrawingContext(canvas), destination_hdc, x, y,
                 canvas->imageInfo().isOpaque(), *src_rect,
                 canvas->getTotalMatrix());
 }
diff --git a/skia/ext/bitmap_platform_device_win.h b/skia/ext/bitmap_platform_device_win.h
index b750e166..82f17ff3 100644
--- a/skia/ext/bitmap_platform_device_win.h
+++ b/skia/ext/bitmap_platform_device_win.h
@@ -11,8 +11,6 @@
 
 namespace skia {
 
-class ScopedPlatformPaint;
-
 // A device is basically a wrapper around SkBitmap that provides a surface for
 // SkCanvas to draw into. Our device provides a surface Windows can also write
 // to. BitmapPlatformDevice creates a bitmap using CreateDIBSection() in a
@@ -75,7 +73,6 @@
   void LoadConfig(const SkMatrix& transform, const SkIRect& clip_bounds);
 
   DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice);
-  friend class ScopedPlatformPaint;
 };
 
 }  // namespace skia
diff --git a/skia/ext/platform_canvas.cc b/skia/ext/platform_canvas.cc
index 52a11c7b..81093801 100644
--- a/skia/ext/platform_canvas.cc
+++ b/skia/ext/platform_canvas.cc
@@ -90,18 +90,17 @@
 }
 #endif
 
-ScopedPlatformPaint::ScopedPlatformPaint(SkCanvas* canvas) :
-    canvas_(canvas),
-    native_drawing_context_(nullptr) {
-  // TODO(tomhudson) we're assuming non-null canvas?
+NativeDrawingContext GetNativeDrawingContext(SkCanvas* canvas) {
   PlatformDevice* platform_device = GetPlatformDevice(canvas->getTopDevice(true));
-  if (platform_device) {
-    // Compensate for drawing to a layer rather than the entire canvas
-    SkMatrix ctm;
-    SkIRect clip_bounds;
-    canvas->temporary_internal_describeTopLayer(&ctm, &clip_bounds);
-    native_drawing_context_ = platform_device->BeginPlatformPaint(ctm, clip_bounds);
-  }
+  if (!platform_device)
+    return nullptr;
+
+  // Compensate for drawing to a layer rather than the entire canvas
+  SkMatrix ctm;
+  SkIRect clip_bounds;
+  canvas->temporary_internal_describeTopLayer(&ctm, &clip_bounds);
+
+  return platform_device->BeginPlatformPaint(ctm, clip_bounds);
 }
 
 }  // namespace skia
diff --git a/skia/ext/platform_canvas.h b/skia/ext/platform_canvas.h
index 4a9692f1..ef657837 100644
--- a/skia/ext/platform_canvas.h
+++ b/skia/ext/platform_canvas.h
@@ -123,29 +123,11 @@
 
 // Returns true if native platform routines can be used to draw on the
 // given canvas. If this function returns false,
-// ScopedPlatformPaint::GetNativeDrawingContext() should return NULL.
+// GetNativeDrawingContext() should return NULL.
 SK_API bool SupportsPlatformPaint(const SkCanvas* canvas);
 
-// This object guards calls to platform drawing routines. The surface
-// returned from GetNativeDrawingContext() can be used with the native platform
-// routines.
-class SK_API ScopedPlatformPaint {
- public:
-  explicit ScopedPlatformPaint(SkCanvas* canvas);
-
-  // Returns the NativeDrawingContext to use for native platform drawing calls.
-  NativeDrawingContext GetNativeDrawingContext() {
-    return native_drawing_context_;
-  }
-
- private:
-  SkCanvas* canvas_;
-  NativeDrawingContext native_drawing_context_;
-
-  // Disallow copy and assign
-  ScopedPlatformPaint(const ScopedPlatformPaint&);
-  ScopedPlatformPaint& operator=(const ScopedPlatformPaint&);
-};
+// Returns the NativeDrawingContext to use for native platform drawing calls.
+SK_API NativeDrawingContext GetNativeDrawingContext(SkCanvas* canvas);
 
 // Following routines are used in print preview workflow to mark the
 // preview metafile.
diff --git a/skia/ext/platform_canvas_unittest.cc b/skia/ext/platform_canvas_unittest.cc
index 38d574f..2282a8f 100644
--- a/skia/ext/platform_canvas_unittest.cc
+++ b/skia/ext/platform_canvas_unittest.cc
@@ -136,8 +136,7 @@
 
 #if defined(OS_WIN)
 void DrawNativeRect(SkCanvas& canvas, int x, int y, int w, int h) {
-  skia::ScopedPlatformPaint scoped_platform_paint(&canvas);
-  HDC dc = scoped_platform_paint.GetNativeDrawingContext();
+  HDC dc = skia::GetNativeDrawingContext(&canvas);
 
   RECT inner_rc;
   inner_rc.left = x;
@@ -148,8 +147,7 @@
 }
 #elif defined(OS_MACOSX)
 void DrawNativeRect(SkCanvas& canvas, int x, int y, int w, int h) {
-  skia::ScopedPlatformPaint scoped_platform_paint(&canvas);
-  CGContextRef context = scoped_platform_paint.GetNativeDrawingContext();
+  CGContextRef context = skia::GetNativeDrawingContext(&canvas);
 
   CGRect inner_rc = CGRectMake(x, y, w, h);
   // RGBA opaque black
@@ -160,8 +158,7 @@
 }
 #elif defined(USE_CAIRO)
 void DrawNativeRect(SkCanvas& canvas, int x, int y, int w, int h) {
-  skia::ScopedPlatformPaint scoped_platform_paint(&canvas);
-  cairo_t* context = scoped_platform_paint.GetNativeDrawingContext();
+  cairo_t* context = skia::GetNativeDrawingContext(&canvas);
 
   cairo_rectangle(context, x, y, w, h);
   cairo_set_source_rgb(context, 0.0, 0.0, 0.0);
diff --git a/skia/ext/platform_device.h b/skia/ext/platform_device.h
index 721893a..b756aa6 100644
--- a/skia/ext/platform_device.h
+++ b/skia/ext/platform_device.h
@@ -16,7 +16,6 @@
 namespace skia {
 
 class PlatformDevice;
-class ScopedPlatformPaint;
 
 // The following routines provide accessor points for the functionality
 // exported by the various PlatformDevice ports.  
@@ -47,14 +46,11 @@
  public:
   virtual ~PlatformDevice();
 
- private:
   // The DC that corresponds to the bitmap, used for GDI operations drawing
   // into the bitmap. This is possibly heavyweight, so it should be existant
   // only during one pass of rendering.
   virtual NativeDrawingContext BeginPlatformPaint(const SkMatrix& transform,
                                                   const SkIRect& clip_bounds) = 0;
-
-  friend class ScopedPlatformPaint;
 };
 
 }  // namespace skia
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
index 0937d1dc..eb96228 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
@@ -24,7 +24,6 @@
 
 class WrapperMarkingData {
  public:
-  friend class ScriptWrappableVisitor;
 
   WrapperMarkingData(void (*traceWrappersCallback)(const WrapperVisitor*,
                                                    const void*),
@@ -50,9 +49,7 @@
     return !m_rawObjectPointer || heapObjectHeader()->isWrapperHeaderMarked();
   }
 
-  // Returns raw object pointer. Beware it doesn't necessarily point to the
-  // beginning of the object.
-  const void* rawObjectPointer() { return m_rawObjectPointer; }
+  inline const void* rawObjectPointer() { return m_rawObjectPointer; }
 
  private:
   inline bool shouldBeInvalidated() {
@@ -69,6 +66,8 @@
   void (*m_traceWrappersCallback)(const WrapperVisitor*, const void*);
   HeapObjectHeader* (*m_heapObjectHeaderCallback)(const void*);
   const void* m_rawObjectPointer;
+
+  friend class ScriptWrappableVisitor;
 };
 
 // ScriptWrappableVisitor is able to trace through the objects to get all
@@ -107,6 +106,8 @@
 
   template <typename T>
   static void writeBarrier(const void* srcObject, const T* dstObject) {
+    static_assert(!NeedsAdjustAndMark<T>::value,
+                  "wrapper tracing is not supported within mixins");
     if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
       return;
     }
@@ -122,30 +123,13 @@
 
     const ThreadState* threadState = ThreadState::current();
     DCHECK(threadState);
-    // We can only safely check the marking state of |dstObject| for non-mixin
-    // objects or if we are outside of object construction.
-    if (!IsGarbageCollectedMixin<T>::value ||
-        !threadState->isMixinInConstruction()) {
-      // If the wrapper is already marked we can bail out here.
-      if (TraceTrait<T>::heapObjectHeader(dstObject)->isWrapperHeaderMarked())
-        return;
-      // Otherwise, eagerly mark the wrapper header and put the object on the
-      // marking deque for further processing.
-      WrapperVisitor* const visitor = currentVisitor(threadState->isolate());
-      if (visitor->pushToMarkingDeque(TraceTrait<T>::traceMarkedWrapper,
-                                      TraceTrait<T>::heapObjectHeader,
-                                      dstObject)) {
-        TraceTrait<T>::markWrapperNoTracing(visitor, dstObject);
-      }
+    // If the wrapper is already marked we can bail out here.
+    if (TraceTrait<T>::heapObjectHeader(dstObject)->isWrapperHeaderMarked())
       return;
-    }
-
-    // We cannot eagerly mark the wrapper header because of mixin
-    // construction. Delay further processing until AdvanceMarking, which has to
-    // be in a non-construction state. This path may result in duplicates.
-    currentVisitor(threadState->isolate())
-        ->pushToMarkingDeque(TraceTrait<T>::markAndTraceWrapper,
-                             TraceTrait<T>::heapObjectHeader, dstObject);
+    // Otherwise, eagerly mark the wrapper header and put the object on the
+    // marking deque for further processing.
+    WrapperVisitor* const visitor = currentVisitor(threadState->isolate());
+    visitor->markAndPushToMarkingDeque(dstObject);
   }
 
   void RegisterV8References(const std::vector<std::pair<void*, void*>>&
@@ -171,6 +155,21 @@
 
   void invalidateDeadObjectsInMarkingDeque();
 
+  bool markWrapperHeader(HeapObjectHeader*) const;
+
+  // Mark wrappers in all worlds for the given script wrappable as alive in
+  // V8.
+  void markWrappersInAllWorlds(const ScriptWrappable*) const override;
+
+  WTF::Deque<WrapperMarkingData>* getMarkingDeque() { return &m_markingDeque; }
+  WTF::Deque<WrapperMarkingData>* getVerifierDeque() {
+    return &m_verifierDeque;
+  }
+  WTF::Vector<HeapObjectHeader*>* getHeadersToUnmark() {
+    return &m_headersToUnmark;
+  }
+
+ protected:
   bool pushToMarkingDeque(
       void (*traceWrappersCallback)(const WrapperVisitor*, const void*),
       HeapObjectHeader* (*heapObjectHeaderCallback)(const void*),
@@ -189,20 +188,6 @@
     return true;
   }
 
-  bool markWrapperHeader(HeapObjectHeader*) const;
-
-  // Mark wrappers in all worlds for the given script wrappable as alive in
-  // V8.
-  void markWrappersInAllWorlds(const ScriptWrappable*) const override;
-
-  WTF::Deque<WrapperMarkingData>* getMarkingDeque() { return &m_markingDeque; }
-  WTF::Deque<WrapperMarkingData>* getVerifierDeque() {
-    return &m_verifierDeque;
-  }
-  WTF::Vector<HeapObjectHeader*>* getHeadersToUnmark() {
-    return &m_headersToUnmark;
-  }
-
  private:
   // Returns true if wrapper tracing is currently in progress, i.e.,
   // TracePrologue has been called, and TraceEpilogue has not yet been called.
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
index a3e2680..0cfb99f 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
@@ -189,9 +189,8 @@
   ScriptWrappableVisitor* visitor =
       V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor();
   visitor->TracePrologue();
-  visitor->pushToMarkingDeque(
-      TraceTrait<DeathAwareScriptWrappable>::markAndTraceWrapper,
-      TraceTrait<DeathAwareScriptWrappable>::heapObjectHeader, object);
+
+  visitor->markAndPushToMarkingDeque(object);
 
   EXPECT_EQ(visitor->getMarkingDeque()->first().rawObjectPointer(), object);
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index 8f5f5808..4455c27 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -91,13 +91,15 @@
   // Event listeners would keep DOMWrapperWorld objects alive for too long.
   // Also, they have references to JS objects, which become dangling once Heap
   // is destroyed.
-  for (auto it = m_eventListeners.begin(); it != m_eventListeners.end();) {
-    V8AbstractEventListener* listener = *it;
-    // clearListenerObject() will unregister the listener from
-    // m_eventListeners, and invalidate the iterator, so we have to advance
-    // it first.
-    ++it;
-    listener->clearListenerObject();
+  m_closing = true;
+  HeapHashSet<Member<V8AbstractEventListener>> listeners;
+  listeners.swap(m_eventListeners);
+  while (!listeners.isEmpty()) {
+    for (const auto& listener : listeners)
+      listener->clearListenerObject();
+    listeners.clear();
+    // Pick up any additions made while iterating.
+    listeners.swap(m_eventListeners);
   }
   removeAllEventListeners();
 
@@ -139,7 +141,7 @@
 void WorkerGlobalScope::deregisterEventListener(
     V8AbstractEventListener* eventListener) {
   auto it = m_eventListeners.find(eventListener);
-  CHECK(it != m_eventListeners.end());
+  CHECK(it != m_eventListeners.end() || m_closing);
   m_eventListeners.remove(it);
 }
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index 6b19d232..24101502 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -208,7 +208,7 @@
 
   const double m_timeOrigin;
 
-  HeapListHashSet<Member<V8AbstractEventListener>> m_eventListeners;
+  HeapHashSet<Member<V8AbstractEventListener>> m_eventListeners;
 
   HeapHashMap<int, Member<ErrorEvent>> m_pendingErrorEvents;
   int m_lastPendingErrorEventId;
diff --git a/third_party/WebKit/Source/platform/heap/TraceTraits.h b/third_party/WebKit/Source/platform/heap/TraceTraits.h
index 15e97551..e2e3146 100644
--- a/third_party/WebKit/Source/platform/heap/TraceTraits.h
+++ b/third_party/WebKit/Source/platform/heap/TraceTraits.h
@@ -188,7 +188,6 @@
   static void trace(Visitor*, void* self);
   static void trace(InlinedGlobalMarkingVisitor, void* self);
 
-  static void markAndTraceWrapper(const WrapperVisitor*, const void*);
   static void markWrapperNoTracing(const WrapperVisitor*, const void*);
   static void traceMarkedWrapper(const WrapperVisitor*, const void*);
   static HeapObjectHeader* heapObjectHeader(const void*);
@@ -234,16 +233,6 @@
 }
 
 template <typename T>
-void TraceTrait<T>::markAndTraceWrapper(const WrapperVisitor* visitor,
-                                        const void* t) {
-  const T* traceable = ToWrapperTracingType(t);
-  if (visitor->markWrapperHeader(heapObjectHeader(traceable))) {
-    visitor->markWrappersInAllWorlds(traceable);
-    visitor->dispatchTraceWrappers(traceable);
-  }
-}
-
-template <typename T>
 void TraceTrait<T>::markWrapperNoTracing(const WrapperVisitor* visitor,
                                          const void* t) {
   const T* traceable = ToWrapperTracingType(t);
diff --git a/third_party/WebKit/Source/platform/heap/WrapperVisitor.h b/third_party/WebKit/Source/platform/heap/WrapperVisitor.h
index bd63dc07..d93767a 100644
--- a/third_party/WebKit/Source/platform/heap/WrapperVisitor.h
+++ b/third_party/WebKit/Source/platform/heap/WrapperVisitor.h
@@ -105,10 +105,7 @@
       return;
     }
 
-    if (pushToMarkingDeque(TraceTrait<T>::traceMarkedWrapper,
-                           TraceTrait<T>::heapObjectHeader, traceable)) {
-      TraceTrait<T>::markWrapperNoTracing(this, traceable);
-    }
+    markAndPushToMarkingDeque(traceable);
   }
 
   /**
@@ -164,6 +161,15 @@
     // don't require marking wrappers in all worlds, so just nop on those.
   }
 
+  template <typename T>
+  void markAndPushToMarkingDeque(const T* traceable) const {
+    if (pushToMarkingDeque(TraceTrait<T>::traceMarkedWrapper,
+                           TraceTrait<T>::heapObjectHeader, traceable)) {
+      TraceTrait<T>::markWrapperNoTracing(this, traceable);
+    }
+  }
+
+ protected:
   // Returns true if pushing to the marking deque was successful.
   virtual bool pushToMarkingDeque(
       void (*traceWrappersCallback)(const WrapperVisitor*, const void*),
diff --git a/third_party/libjingle_xmpp/BUILD.gn b/third_party/libjingle_xmpp/BUILD.gn
new file mode 100644
index 0000000..6b01b4f
--- /dev/null
+++ b/third_party/libjingle_xmpp/BUILD.gn
@@ -0,0 +1,153 @@
+# Copyright 2016 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.
+
+# TODO(kjellander): Remove remaining dependencies on the WebRTC codebase.
+import("../webrtc/build/webrtc.gni")
+
+group("libjingle_xmpp") {
+  public_deps = [
+    ":rtc_xmllite",
+    ":rtc_xmpp",
+  ]
+}
+
+rtc_static_library("rtc_xmllite") {
+  sources = [
+    "xmllite/qname.cc",
+    "xmllite/qname.h",
+    "xmllite/xmlbuilder.cc",
+    "xmllite/xmlbuilder.h",
+    "xmllite/xmlconstants.cc",
+    "xmllite/xmlconstants.h",
+    "xmllite/xmlelement.cc",
+    "xmllite/xmlelement.h",
+    "xmllite/xmlnsstack.cc",
+    "xmllite/xmlnsstack.h",
+    "xmllite/xmlparser.cc",
+    "xmllite/xmlparser.h",
+    "xmllite/xmlprinter.cc",
+    "xmllite/xmlprinter.h",
+  ]
+
+  deps = [
+    "//third_party/webrtc/base:rtc_base",
+  ]
+  public_deps = [
+    "//third_party/expat",
+  ]
+}
+
+config("rtc_xmpp_warnings_config") {
+  # GN orders flags on a target before flags from configs. The default config
+  # adds these flags so to cancel them out they need to come from a config and
+  # cannot be on the target directly.
+  if (is_android) {
+    cflags = [ "-Wno-error" ]
+  }
+}
+
+config("rtc_xmpp_inherited_config") {
+  defines = [
+    "FEATURE_ENABLE_SSL",
+    "FEATURE_ENABLE_VOICEMAIL",
+  ]
+}
+
+rtc_static_library("rtc_xmpp") {
+  cflags = []
+  sources = [
+    "xmpp/asyncsocket.h",
+    "xmpp/constants.cc",
+    "xmpp/constants.h",
+    "xmpp/jid.cc",
+    "xmpp/jid.h",
+    "xmpp/plainsaslhandler.h",
+    "xmpp/prexmppauth.h",
+    "xmpp/saslcookiemechanism.h",
+    "xmpp/saslhandler.h",
+    "xmpp/saslmechanism.cc",
+    "xmpp/saslmechanism.h",
+    "xmpp/saslplainmechanism.h",
+    "xmpp/xmppclient.cc",
+    "xmpp/xmppclient.h",
+    "xmpp/xmppclientsettings.h",
+    "xmpp/xmppengine.h",
+    "xmpp/xmppengineimpl.cc",
+    "xmpp/xmppengineimpl.h",
+    "xmpp/xmppengineimpl_iq.cc",
+    "xmpp/xmpplogintask.cc",
+    "xmpp/xmpplogintask.h",
+    "xmpp/xmppstanzaparser.cc",
+    "xmpp/xmppstanzaparser.h",
+    "xmpp/xmpptask.cc",
+    "xmpp/xmpptask.h",
+  ]
+
+  defines = [ "FEATURE_ENABLE_SSL" ]
+
+  deps = [
+    ":rtc_xmllite",
+    "//third_party/webrtc/base:rtc_base",
+  ]
+  public_deps = [
+    "//third_party/expat",
+  ]
+  configs += [ ":rtc_xmpp_warnings_config" ]
+
+  public_configs = [ ":rtc_xmpp_inherited_config" ]
+
+  if (is_nacl) {
+    deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
+  }
+
+  if (is_posix && is_debug) {
+    # The Chromium configs defines this for all posix _except_ for ios & mac.
+    # We want it there as well, e.g. because ASSERT and friends trigger off of
+    # it.
+    defines += [ "_DEBUG" ]
+  }
+}
+
+config("libjingle_xmpp_unittests_config") {
+  # GN orders flags on a target before flags from configs. The default config
+  # adds -Wall, and this flag have to be after -Wall -- so they need to
+  # come from a config and can"t be on the target directly.
+  if (is_clang) {
+    cflags = [
+      "-Wno-missing-braces",
+      "-Wno-sign-compare",
+      "-Wno-unused-const-variable",
+    ]
+  }
+}
+
+rtc_test("libjingle_xmpp_unittests") {
+  configs += [ ":libjingle_xmpp_unittests_config" ]
+
+  deps = [
+    ":libjingle_xmpp",
+
+    # TODO(kjellander): Refactor/remove this dependency. It is needed by
+    # third_party/webrtc_overrides/webrtc/base/win32socketinit.cc.
+    "//net",
+    "//testing/gtest",
+  ]
+
+  sources = [
+    "run_all_unittests.cc",
+    "xmllite/qname_unittest.cc",
+    "xmllite/xmlbuilder_unittest.cc",
+    "xmllite/xmlelement_unittest.cc",
+    "xmllite/xmlnsstack_unittest.cc",
+    "xmllite/xmlparser_unittest.cc",
+    "xmllite/xmlprinter_unittest.cc",
+    "xmpp/fakexmppclient.h",
+    "xmpp/jid_unittest.cc",
+    "xmpp/util_unittest.cc",
+    "xmpp/util_unittest.h",
+    "xmpp/xmppengine_unittest.cc",
+    "xmpp/xmpplogintask_unittest.cc",
+    "xmpp/xmppstanzaparser_unittest.cc",
+  ]
+}
diff --git a/third_party/libjingle_xmpp/DEPS b/third_party/libjingle_xmpp/DEPS
new file mode 100644
index 0000000..4d25c08
--- /dev/null
+++ b/third_party/libjingle_xmpp/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "run_all_unittests\.cc": [
+    "+testing",
+  ]
+}
diff --git a/third_party/libjingle_xmpp/LICENSE b/third_party/libjingle_xmpp/LICENSE
new file mode 100644
index 0000000..4c41b7b2
--- /dev/null
+++ b/third_party/libjingle_xmpp/LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/libjingle_xmpp/OWNERS b/third_party/libjingle_xmpp/OWNERS
new file mode 100644
index 0000000..e5606c61a
--- /dev/null
+++ b/third_party/libjingle_xmpp/OWNERS
@@ -0,0 +1,6 @@
+henrika@chromium.org
+henrikg@chromium.org
+hta@chromium.org
+perkj@chromium.org
+sergeyu@chromium.org
+tommi@chromium.org
diff --git a/third_party/libjingle_xmpp/README.chromium b/third_party/libjingle_xmpp/README.chromium
new file mode 100644
index 0000000..2fa85aa
--- /dev/null
+++ b/third_party/libjingle_xmpp/README.chromium
@@ -0,0 +1,20 @@
+Name: libjingle XMPP and xmllite libraries
+URL: https://chromium.googlesource.com/external/webrtc
+Version: 5493b8a59deb16cf0481e24707a0ed72d19047dc
+License: BSD
+License File: LICENSE
+Security Critical: Yes
+License Android Compatible: Yes
+
+Description:
+XMPP (Extensible Messaging and Presence Protocol) is a communications protocol
+for messaging based on XML. xmllite is a minimalistic library for parsing and
+generating XML. The source for these libraries originates from the libjingle
+project, which was merged into the WebRTC codebase where it received minor
+updates. As time passed, the code was no longer used in WebRTC but is still used
+in Chromium. Only the parts that are used in Chromium are added here.
+
+Local Modifications:
+* Include paths in third_party/libjingle_xmpp/xmllite and
+  third_party/libjingle_xmpp/xmpp are updated to reflect the new
+  absolute paths to their own headers.
diff --git a/third_party/libjingle_xmpp/run_all_unittests.cc b/third_party/libjingle_xmpp/run_all_unittests.cc
new file mode 100644
index 0000000..49c887b
--- /dev/null
+++ b/third_party/libjingle_xmpp/run_all_unittests.cc
@@ -0,0 +1,10 @@
+// Copyright (c) 2016 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 "testing/gtest/include/gtest/gtest.h"
+
+int main(int argc, char* argv[]) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/third_party/libjingle_xmpp/xmllite/DEPS b/third_party/libjingle_xmpp/xmllite/DEPS
new file mode 100644
index 0000000..063f1fe
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+third_party/expat",
+  "+third_party/webrtc/base",
+]
diff --git a/third_party/libjingle_xmpp/xmllite/qname.cc b/third_party/libjingle_xmpp/xmllite/qname.cc
new file mode 100644
index 0000000..dee94093
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/qname.cc
@@ -0,0 +1,78 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+
+namespace buzz {
+
+QName::QName() {
+}
+
+QName::QName(const QName& qname)
+    : namespace_(qname.namespace_),
+      local_part_(qname.local_part_) {
+}
+
+QName::QName(const StaticQName& const_value)
+    : namespace_(const_value.ns),
+      local_part_(const_value.local) {
+}
+
+QName::QName(const std::string& ns, const std::string& local)
+    : namespace_(ns),
+      local_part_(local) {
+}
+
+QName::QName(const std::string& merged_or_local) {
+  size_t i = merged_or_local.rfind(':');
+  if (i == std::string::npos) {
+    local_part_ = merged_or_local;
+  } else {
+    namespace_ = merged_or_local.substr(0, i);
+    local_part_ = merged_or_local.substr(i + 1);
+  }
+}
+
+QName::~QName() {
+}
+
+std::string QName::Merged() const {
+  if (namespace_[0] == '\0')
+    return local_part_;
+
+  std::string result;
+  result.reserve(namespace_.length() + 1 + local_part_.length());
+  result += namespace_;
+  result += ':';
+  result += local_part_;
+  return result;
+}
+
+bool QName::IsEmpty() const {
+  return namespace_.empty() && local_part_.empty();
+}
+
+int QName::Compare(const StaticQName& other) const {
+  int result = local_part_.compare(other.local);
+  if (result != 0)
+    return result;
+
+  return namespace_.compare(other.ns);
+}
+
+int QName::Compare(const QName& other) const {
+  int result = local_part_.compare(other.local_part_);
+  if (result != 0)
+    return result;
+
+  return namespace_.compare(other.namespace_);
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmllite/qname.h b/third_party/libjingle_xmpp/xmllite/qname.h
new file mode 100644
index 0000000..1e772d3
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/qname.h
@@ -0,0 +1,83 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
+#define WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
+
+#include <string>
+
+namespace buzz {
+
+class QName;
+
+// StaticQName is used to represend constant quailified names. They
+// can be initialized statically and don't need intializers code, e.g.
+//   const StaticQName QN_FOO = { "foo_namespace", "foo" };
+//
+// Beside this use case, QName should be used everywhere
+// else. StaticQName instances are implicitly converted to QName
+// objects.
+struct StaticQName {
+  const char* const ns;
+  const char* const local;
+
+  bool operator==(const QName& other) const;
+  bool operator!=(const QName& other) const;
+};
+
+class QName {
+ public:
+  QName();
+  QName(const QName& qname);
+  QName(const StaticQName& const_value);
+  QName(const std::string& ns, const std::string& local);
+  explicit QName(const std::string& merged_or_local);
+  ~QName();
+
+  const std::string& Namespace() const { return namespace_; }
+  const std::string& LocalPart() const { return local_part_; }
+  std::string Merged() const;
+  bool IsEmpty() const;
+
+  int Compare(const StaticQName& other) const;
+  int Compare(const QName& other) const;
+
+  bool operator==(const StaticQName& other) const {
+    return Compare(other) == 0;
+  }
+  bool operator==(const QName& other) const {
+    return Compare(other) == 0;
+  }
+  bool operator!=(const StaticQName& other) const {
+    return Compare(other) != 0;
+  }
+  bool operator!=(const QName& other) const {
+    return Compare(other) != 0;
+  }
+  bool operator<(const QName& other) const {
+    return Compare(other) < 0;
+  }
+
+ private:
+  std::string namespace_;
+  std::string local_part_;
+};
+
+inline bool StaticQName::operator==(const QName& other) const {
+  return other.Compare(*this) == 0;
+}
+
+inline bool StaticQName::operator!=(const QName& other) const {
+  return other.Compare(*this) != 0;
+}
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
diff --git a/third_party/libjingle_xmpp/xmllite/qname_unittest.cc b/third_party/libjingle_xmpp/xmllite/qname_unittest.cc
new file mode 100644
index 0000000..e9009a1
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/qname_unittest.cc
@@ -0,0 +1,114 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::StaticQName;
+using buzz::QName;
+
+TEST(QNameTest, TestTrivial) {
+  QName name("test");
+  EXPECT_EQ(name.LocalPart(), "test");
+  EXPECT_EQ(name.Namespace(), "");
+}
+
+TEST(QNameTest, TestSplit) {
+  QName name("a:test");
+  EXPECT_EQ(name.LocalPart(), "test");
+  EXPECT_EQ(name.Namespace(), "a");
+  QName name2("a-very:long:namespace:test-this");
+  EXPECT_EQ(name2.LocalPart(), "test-this");
+  EXPECT_EQ(name2.Namespace(), "a-very:long:namespace");
+}
+
+TEST(QNameTest, TestMerge) {
+  QName name("a", "test");
+  EXPECT_EQ(name.LocalPart(), "test");
+  EXPECT_EQ(name.Namespace(), "a");
+  EXPECT_EQ(name.Merged(), "a:test");
+  QName name2("a-very:long:namespace", "test-this");
+  EXPECT_EQ(name2.LocalPart(), "test-this");
+  EXPECT_EQ(name2.Namespace(), "a-very:long:namespace");
+  EXPECT_EQ(name2.Merged(), "a-very:long:namespace:test-this");
+}
+
+TEST(QNameTest, TestAssignment) {
+  QName name("a", "test");
+  // copy constructor
+  QName namecopy(name);
+  EXPECT_EQ(namecopy.LocalPart(), "test");
+  EXPECT_EQ(namecopy.Namespace(), "a");
+  QName nameassigned("");
+  nameassigned = name;
+  EXPECT_EQ(nameassigned.LocalPart(), "test");
+  EXPECT_EQ(nameassigned.Namespace(), "a");
+}
+
+TEST(QNameTest, TestConstAssignment) {
+  StaticQName name = { "a", "test" };
+  QName namecopy(name);
+  EXPECT_EQ(namecopy.LocalPart(), "test");
+  EXPECT_EQ(namecopy.Namespace(), "a");
+  QName nameassigned("");
+  nameassigned = name;
+  EXPECT_EQ(nameassigned.LocalPart(), "test");
+  EXPECT_EQ(nameassigned.Namespace(), "a");
+}
+
+TEST(QNameTest, TestEquality) {
+  QName name("a-very:long:namespace:test-this");
+  QName name2("a-very:long:namespace", "test-this");
+  QName name3("a-very:long:namespaxe", "test-this");
+  EXPECT_TRUE(name == name2);
+  EXPECT_FALSE(name == name3);
+}
+
+TEST(QNameTest, TestCompare) {
+  QName name("a");
+  QName name2("nsa", "a");
+  QName name3("nsa", "b");
+  QName name4("nsb", "b");
+
+  EXPECT_TRUE(name < name2);
+  EXPECT_FALSE(name2 < name);
+
+  EXPECT_FALSE(name2 < name2);
+
+  EXPECT_TRUE(name2 < name3);
+  EXPECT_FALSE(name3 < name2);
+
+  EXPECT_TRUE(name3 < name4);
+  EXPECT_FALSE(name4 < name3);
+}
+
+TEST(QNameTest, TestStaticQName) {
+  const StaticQName const_name1 = { "namespace", "local-name1" };
+  const StaticQName const_name2 = { "namespace", "local-name2" };
+  const QName name("namespace", "local-name1");
+  const QName name1 = const_name1;
+  const QName name2 = const_name2;
+
+  EXPECT_TRUE(name == const_name1);
+  EXPECT_TRUE(const_name1 == name);
+  EXPECT_FALSE(name != const_name1);
+  EXPECT_FALSE(const_name1 != name);
+
+  EXPECT_TRUE(name == name1);
+  EXPECT_TRUE(name1 == name);
+  EXPECT_FALSE(name != name1);
+  EXPECT_FALSE(name1 != name);
+
+  EXPECT_FALSE(name == name2);
+  EXPECT_FALSE(name2 == name);
+  EXPECT_TRUE(name != name2);
+  EXPECT_TRUE(name2 != name);
+}
diff --git a/third_party/libjingle_xmpp/xmllite/xmlbuilder.cc b/third_party/libjingle_xmpp/xmllite/xmlbuilder.cc
new file mode 100644
index 0000000..68ef3d5a
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlbuilder.cc
@@ -0,0 +1,130 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
+
+#include <set>
+#include <vector>
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/webrtc/base/common.h"
+
+namespace buzz {
+
+XmlBuilder::XmlBuilder() :
+  pelCurrent_(NULL),
+  pelRoot_(),
+  pvParents_(new std::vector<XmlElement *>()) {
+}
+
+void
+XmlBuilder::Reset() {
+  pelRoot_.reset();
+  pelCurrent_ = NULL;
+  pvParents_->clear();
+}
+
+XmlElement *
+XmlBuilder::BuildElement(XmlParseContext * pctx,
+                              const char * name, const char ** atts) {
+  QName tagName(pctx->ResolveQName(name, false));
+  if (tagName.IsEmpty())
+    return NULL;
+
+  XmlElement * pelNew = new XmlElement(tagName);
+
+  if (!*atts)
+    return pelNew;
+
+  std::set<QName> seenNonlocalAtts;
+
+  while (*atts) {
+    QName attName(pctx->ResolveQName(*atts, true));
+    if (attName.IsEmpty()) {
+      delete pelNew;
+      return NULL;
+    }
+
+    // verify that namespaced names are unique
+    if (!attName.Namespace().empty()) {
+      if (seenNonlocalAtts.count(attName)) {
+        delete pelNew;
+        return NULL;
+      }
+      seenNonlocalAtts.insert(attName);
+    }
+
+    pelNew->AddAttr(attName, std::string(*(atts + 1)));
+    atts += 2;
+  }
+
+  return pelNew;
+}
+
+void
+XmlBuilder::StartElement(XmlParseContext * pctx,
+                              const char * name, const char ** atts) {
+  XmlElement * pelNew = BuildElement(pctx, name, atts);
+  if (pelNew == NULL) {
+    pctx->RaiseError(XML_ERROR_SYNTAX);
+    return;
+  }
+
+  if (!pelCurrent_) {
+    pelCurrent_ = pelNew;
+    pelRoot_.reset(pelNew);
+    pvParents_->push_back(NULL);
+  } else {
+    pelCurrent_->AddElement(pelNew);
+    pvParents_->push_back(pelCurrent_);
+    pelCurrent_ = pelNew;
+  }
+}
+
+void
+XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) {
+  RTC_UNUSED(pctx);
+  RTC_UNUSED(name);
+  pelCurrent_ = pvParents_->back();
+  pvParents_->pop_back();
+}
+
+void
+XmlBuilder::CharacterData(XmlParseContext * pctx,
+                               const char * text, int len) {
+  RTC_UNUSED(pctx);
+  if (pelCurrent_) {
+    pelCurrent_->AddParsedText(text, len);
+  }
+}
+
+void
+XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) {
+  RTC_UNUSED(pctx);
+  RTC_UNUSED(err);
+  pelRoot_.reset(NULL);
+  pelCurrent_ = NULL;
+  pvParents_->clear();
+}
+
+XmlElement *
+XmlBuilder::CreateElement() {
+  return pelRoot_.release();
+}
+
+XmlElement *
+XmlBuilder::BuiltElement() {
+  return pelRoot_.get();
+}
+
+XmlBuilder::~XmlBuilder() {
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmllite/xmlbuilder.h b/third_party/libjingle_xmpp/xmllite/xmlbuilder.h
new file mode 100644
index 0000000..4acf3fe
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlbuilder.h
@@ -0,0 +1,61 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef _xmlbuilder_h_
+#define _xmlbuilder_h_
+
+#include <memory>
+#include <string>
+#include <vector>
+#include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
+
+#ifdef EXPAT_RELATIVE_PATH
+#include "expat.h"
+#else
+#include "third_party/expat/v2_0_1/Source/lib/expat.h"
+#endif  // EXPAT_RELATIVE_PATH
+
+namespace buzz {
+
+class XmlElement;
+class XmlParseContext;
+
+
+class XmlBuilder : public XmlParseHandler {
+public:
+  XmlBuilder();
+
+  static XmlElement * BuildElement(XmlParseContext * pctx,
+                                  const char * name, const char ** atts);
+  virtual void StartElement(XmlParseContext * pctx,
+                            const char * name, const char ** atts);
+  virtual void EndElement(XmlParseContext * pctx, const char * name);
+  virtual void CharacterData(XmlParseContext * pctx,
+                             const char * text, int len);
+  virtual void Error(XmlParseContext * pctx, XML_Error);
+  virtual ~XmlBuilder();
+
+  void Reset();
+
+  // Take ownership of the built element; second call returns NULL
+  XmlElement * CreateElement();
+
+  // Peek at the built element without taking ownership
+  XmlElement * BuiltElement();
+
+private:
+  XmlElement * pelCurrent_;
+  std::unique_ptr<XmlElement> pelRoot_;
+  std::unique_ptr<std::vector<XmlElement*> > pvParents_;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
new file mode 100644
index 0000000..0a6f606
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
@@ -0,0 +1,177 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::XmlBuilder;
+using buzz::XmlElement;
+using buzz::XmlParser;
+
+TEST(XmlBuilderTest, TestTrivial) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing/>");
+  EXPECT_EQ("<testing/>", builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestAttributes1) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing a='b'/>");
+  EXPECT_EQ("<testing a=\"b\"/>", builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestAttributes2) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing e='' long='some text'/>");
+  EXPECT_EQ("<testing e=\"\" long=\"some text\"/>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestNesting1) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder,
+      "<top><first/><second><third></third></second></top>");
+  EXPECT_EQ("<top><first/><second><third/></second></top>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestNesting2) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder,
+    "<top><fifth><deeper><and><deeper/></and><sibling><leaf/>"
+    "</sibling></deeper></fifth><first/><second><third></third>"
+    "</second></top>");
+  EXPECT_EQ("<top><fifth><deeper><and><deeper/></and><sibling><leaf/>"
+    "</sibling></deeper></fifth><first/><second><third/>"
+    "</second></top>", builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestQuoting1) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing a='>'/>");
+  EXPECT_EQ("<testing a=\"&gt;\"/>", builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestQuoting2) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing a='&lt;>&amp;&quot;'/>");
+  EXPECT_EQ("<testing a=\"&lt;&gt;&amp;&quot;\"/>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestQuoting3) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing a='so &quot;important&quot;'/>");
+  EXPECT_EQ("<testing a=\"so &quot;important&quot;\"/>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestQuoting4) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing a='&quot;important&quot;, yes'/>");
+  EXPECT_EQ("<testing a=\"&quot;important&quot;, yes\"/>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestQuoting5) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder,
+      "<testing a='&lt;what is &quot;important&quot;&gt;'/>");
+  EXPECT_EQ("<testing a=\"&lt;what is &quot;important&quot;&gt;\"/>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestText1) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing>></testing>");
+  EXPECT_EQ("<testing>&gt;</testing>", builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestText2) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing>&lt;>&amp;&quot;</testing>");
+  EXPECT_EQ("<testing>&lt;&gt;&amp;\"</testing>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestText3) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing>so &lt;important&gt;</testing>");
+  EXPECT_EQ("<testing>so &lt;important&gt;</testing>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestText4) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing>&lt;important&gt;, yes</testing>");
+  EXPECT_EQ("<testing>&lt;important&gt;, yes</testing>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestText5) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder,
+      "<testing>importance &amp;&lt;important&gt;&amp;</testing>");
+  EXPECT_EQ("<testing>importance &amp;&lt;important&gt;&amp;</testing>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestNamespace1) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing xmlns='foo'/>");
+  EXPECT_EQ("<testing xmlns=\"foo\"/>", builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestNamespace2) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing xmlns:a='foo' a:b='c'/>");
+  EXPECT_EQ("<testing xmlns:a=\"foo\" a:b=\"c\"/>",
+      builder.BuiltElement()->Str());
+}
+
+TEST(XmlBuilderTest, TestNamespace3) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing xmlns:a=''/>");
+  EXPECT_TRUE(NULL == builder.BuiltElement());
+}
+
+TEST(XmlBuilderTest, TestNamespace4) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing a:b='c'/>");
+  EXPECT_TRUE(NULL == builder.BuiltElement());
+}
+
+TEST(XmlBuilderTest, TestAttrCollision1) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, "<testing a='first' a='second'/>");
+  EXPECT_TRUE(NULL == builder.BuiltElement());
+}
+
+TEST(XmlBuilderTest, TestAttrCollision2) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder,
+      "<testing xmlns:a='foo' xmlns:b='foo' a:x='c' b:x='d'/>");
+  EXPECT_TRUE(NULL == builder.BuiltElement());
+}
+
+TEST(XmlBuilderTest, TestAttrCollision3) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder,
+      "<testing xmlns:a='foo'><nested xmlns:b='foo' a:x='c' b:x='d'/>"
+      "</testing>");
+  EXPECT_TRUE(NULL == builder.BuiltElement());
+}
+
diff --git a/third_party/libjingle_xmpp/xmllite/xmlconstants.cc b/third_party/libjingle_xmpp/xmllite/xmlconstants.cc
new file mode 100644
index 0000000..c2e471c
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlconstants.cc
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+const char STR_EMPTY[] = "";
+const char NS_XML[] = "http://www.w3.org/XML/1998/namespace";
+const char NS_XMLNS[] = "http://www.w3.org/2000/xmlns/";
+const char STR_XMLNS[] = "xmlns";
+const char STR_XML[] = "xml";
+const char STR_VERSION[] = "version";
+const char STR_ENCODING[] = "encoding";
+
+const StaticQName QN_XMLNS = { STR_EMPTY, STR_XMLNS };
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmllite/xmlconstants.h b/third_party/libjingle_xmpp/xmllite/xmlconstants.h
new file mode 100644
index 0000000..1499a084
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlconstants.h
@@ -0,0 +1,30 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
+#define WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
+
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+
+namespace buzz {
+
+extern const char STR_EMPTY[];
+extern const char NS_XML[];
+extern const char NS_XMLNS[];
+extern const char STR_XMLNS[];
+extern const char STR_XML[];
+extern const char STR_VERSION[];
+extern const char STR_ENCODING[];
+
+extern const StaticQName QN_XMLNS;
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlelement.cc b/third_party/libjingle_xmpp/xmllite/xmlelement.cc
new file mode 100644
index 0000000..0ef5841
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlelement.cc
@@ -0,0 +1,496 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
+#include "third_party/webrtc/base/common.h"
+
+namespace buzz {
+
+XmlChild::~XmlChild() {
+}
+
+bool XmlText::IsTextImpl() const {
+  return true;
+}
+
+XmlElement* XmlText::AsElementImpl() const {
+  return NULL;
+}
+
+XmlText* XmlText::AsTextImpl() const {
+  return const_cast<XmlText *>(this);
+}
+
+void XmlText::SetText(const std::string& text) {
+  text_ = text;
+}
+
+void XmlText::AddParsedText(const char* buf, int len) {
+  text_.append(buf, len);
+}
+
+void XmlText::AddText(const std::string& text) {
+  text_ += text;
+}
+
+XmlText::~XmlText() {
+}
+
+XmlElement::XmlElement(const QName& name) :
+    name_(name),
+    first_attr_(NULL),
+    last_attr_(NULL),
+    first_child_(NULL),
+    last_child_(NULL),
+    cdata_(false) {
+}
+
+XmlElement::XmlElement(const XmlElement& elt) :
+    XmlChild(),
+    name_(elt.name_),
+    first_attr_(NULL),
+    last_attr_(NULL),
+    first_child_(NULL),
+    last_child_(NULL),
+    cdata_(false) {
+
+  // copy attributes
+  XmlAttr* attr;
+  XmlAttr ** plast_attr = &first_attr_;
+  XmlAttr* newAttr = NULL;
+  for (attr = elt.first_attr_; attr; attr = attr->NextAttr()) {
+    newAttr = new XmlAttr(*attr);
+    *plast_attr = newAttr;
+    plast_attr = &(newAttr->next_attr_);
+  }
+  last_attr_ = newAttr;
+
+  // copy children
+  XmlChild* pChild;
+  XmlChild ** ppLast = &first_child_;
+  XmlChild* newChild = NULL;
+
+  for (pChild = elt.first_child_; pChild; pChild = pChild->NextChild()) {
+    if (pChild->IsText()) {
+      newChild = new XmlText(*(pChild->AsText()));
+    } else {
+      newChild = new XmlElement(*(pChild->AsElement()));
+    }
+    *ppLast = newChild;
+    ppLast = &(newChild->next_child_);
+  }
+  last_child_ = newChild;
+
+  cdata_ = elt.cdata_;
+}
+
+XmlElement::XmlElement(const QName& name, bool useDefaultNs) :
+  name_(name),
+  first_attr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
+  last_attr_(first_attr_),
+  first_child_(NULL),
+  last_child_(NULL),
+  cdata_(false) {
+}
+
+bool XmlElement::IsTextImpl() const {
+  return false;
+}
+
+XmlElement* XmlElement::AsElementImpl() const {
+  return const_cast<XmlElement *>(this);
+}
+
+XmlText* XmlElement::AsTextImpl() const {
+  return NULL;
+}
+
+const std::string XmlElement::BodyText() const {
+  if (first_child_ && first_child_->IsText() && last_child_ == first_child_) {
+    return first_child_->AsText()->Text();
+  }
+
+  return std::string();
+}
+
+void XmlElement::SetBodyText(const std::string& text) {
+  if (text.empty()) {
+    ClearChildren();
+  } else if (first_child_ == NULL) {
+    AddText(text);
+  } else if (first_child_->IsText() && last_child_ == first_child_) {
+    first_child_->AsText()->SetText(text);
+  } else {
+    ClearChildren();
+    AddText(text);
+  }
+}
+
+const QName XmlElement::FirstElementName() const {
+  const XmlElement* element = FirstElement();
+  if (element == NULL)
+    return QName();
+  return element->Name();
+}
+
+XmlAttr* XmlElement::FirstAttr() {
+  return first_attr_;
+}
+
+const std::string XmlElement::Attr(const StaticQName& name) const {
+  XmlAttr* attr;
+  for (attr = first_attr_; attr; attr = attr->next_attr_) {
+    if (attr->name_ == name)
+      return attr->value_;
+  }
+  return std::string();
+}
+
+const std::string XmlElement::Attr(const QName& name) const {
+  XmlAttr* attr;
+  for (attr = first_attr_; attr; attr = attr->next_attr_) {
+    if (attr->name_ == name)
+      return attr->value_;
+  }
+  return std::string();
+}
+
+bool XmlElement::HasAttr(const StaticQName& name) const {
+  XmlAttr* attr;
+  for (attr = first_attr_; attr; attr = attr->next_attr_) {
+    if (attr->name_ == name)
+      return true;
+  }
+  return false;
+}
+
+bool XmlElement::HasAttr(const QName& name) const {
+  XmlAttr* attr;
+  for (attr = first_attr_; attr; attr = attr->next_attr_) {
+    if (attr->name_ == name)
+      return true;
+  }
+  return false;
+}
+
+void XmlElement::SetAttr(const QName& name, const std::string& value) {
+  XmlAttr* attr;
+  for (attr = first_attr_; attr; attr = attr->next_attr_) {
+    if (attr->name_ == name)
+      break;
+  }
+  if (!attr) {
+    attr = new XmlAttr(name, value);
+    if (last_attr_)
+      last_attr_->next_attr_ = attr;
+    else
+      first_attr_ = attr;
+    last_attr_ = attr;
+    return;
+  }
+  attr->value_ = value;
+}
+
+void XmlElement::ClearAttr(const QName& name) {
+  XmlAttr* attr;
+  XmlAttr* last_attr = NULL;
+  for (attr = first_attr_; attr; attr = attr->next_attr_) {
+    if (attr->name_ == name)
+      break;
+    last_attr = attr;
+  }
+  if (!attr)
+    return;
+  if (!last_attr)
+    first_attr_ = attr->next_attr_;
+  else
+    last_attr->next_attr_ = attr->next_attr_;
+  if (last_attr_ == attr)
+    last_attr_ = last_attr;
+  delete attr;
+}
+
+XmlChild* XmlElement::FirstChild() {
+  return first_child_;
+}
+
+XmlElement* XmlElement::FirstElement() {
+  XmlChild* pChild;
+  for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText())
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement* XmlElement::NextElement() {
+  XmlChild* pChild;
+  for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText())
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement* XmlElement::FirstWithNamespace(const std::string& ns) {
+  XmlChild* pChild;
+  for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement *
+XmlElement::NextWithNamespace(const std::string& ns) {
+  XmlChild* pChild;
+  for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement *
+XmlElement::FirstNamed(const QName& name) {
+  XmlChild* pChild;
+  for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement *
+XmlElement::FirstNamed(const StaticQName& name) {
+  XmlChild* pChild;
+  for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement *
+XmlElement::NextNamed(const QName& name) {
+  XmlChild* pChild;
+  for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement *
+XmlElement::NextNamed(const StaticQName& name) {
+  XmlChild* pChild;
+  for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+      return pChild->AsElement();
+  }
+  return NULL;
+}
+
+XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) {
+  XmlElement* child = FirstNamed(name);
+  if (!child) {
+    child = new XmlElement(name);
+    AddElement(child);
+  }
+
+  return child;
+}
+
+const std::string XmlElement::TextNamed(const QName& name) const {
+  XmlChild* pChild;
+  for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
+    if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+      return pChild->AsElement()->BodyText();
+  }
+  return std::string();
+}
+
+void XmlElement::InsertChildAfter(XmlChild* predecessor, XmlChild* next) {
+  if (predecessor == NULL) {
+    next->next_child_ = first_child_;
+    first_child_ = next;
+  }
+  else {
+    next->next_child_ = predecessor->next_child_;
+    predecessor->next_child_ = next;
+  }
+}
+
+void XmlElement::RemoveChildAfter(XmlChild* predecessor) {
+  XmlChild* next;
+
+  if (predecessor == NULL) {
+    next = first_child_;
+    first_child_ = next->next_child_;
+  }
+  else {
+    next = predecessor->next_child_;
+    predecessor->next_child_ = next->next_child_;
+  }
+
+  if (last_child_ == next)
+    last_child_ = predecessor;
+
+  delete next;
+}
+
+void XmlElement::AddAttr(const QName& name, const std::string& value) {
+  ASSERT(!HasAttr(name));
+
+  XmlAttr ** pprev = last_attr_ ? &(last_attr_->next_attr_) : &first_attr_;
+  last_attr_ = (*pprev = new XmlAttr(name, value));
+}
+
+void XmlElement::AddAttr(const QName& name, const std::string& value,
+                         int depth) {
+  XmlElement* element = this;
+  while (depth--) {
+    element = element->last_child_->AsElement();
+  }
+  element->AddAttr(name, value);
+}
+
+void XmlElement::AddParsedText(const char* cstr, int len) {
+  if (len == 0)
+    return;
+
+  if (last_child_ && last_child_->IsText()) {
+    last_child_->AsText()->AddParsedText(cstr, len);
+    return;
+  }
+  XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
+  last_child_ = *pprev = new XmlText(cstr, len);
+}
+
+void XmlElement::AddCDATAText(const char* buf, int len) {
+  cdata_ = true;
+  AddParsedText(buf, len);
+}
+
+void XmlElement::AddText(const std::string& text) {
+  if (text == STR_EMPTY)
+    return;
+
+  if (last_child_ && last_child_->IsText()) {
+    last_child_->AsText()->AddText(text);
+    return;
+  }
+  XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
+  last_child_ = *pprev = new XmlText(text);
+}
+
+void XmlElement::AddText(const std::string& text, int depth) {
+  // note: the first syntax is ambigious for msvc 6
+  // XmlElement* pel(this);
+  XmlElement* element = this;
+  while (depth--) {
+    element = element->last_child_->AsElement();
+  }
+  element->AddText(text);
+}
+
+void XmlElement::AddElement(XmlElement *child) {
+  if (child == NULL)
+    return;
+
+  XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
+  *pprev = child;
+  last_child_ = child;
+  child->next_child_ = NULL;
+}
+
+void XmlElement::AddElement(XmlElement *child, int depth) {
+  XmlElement* element = this;
+  while (depth--) {
+    element = element->last_child_->AsElement();
+  }
+  element->AddElement(child);
+}
+
+void XmlElement::ClearNamedChildren(const QName& name) {
+  XmlChild* prev_child = NULL;
+  XmlChild* next_child;
+  XmlChild* child;
+  for (child = FirstChild(); child; child = next_child) {
+    next_child = child->NextChild();
+    if (!child->IsText() && child->AsElement()->Name() == name)
+    {
+      RemoveChildAfter(prev_child);
+      continue;
+    }
+    prev_child = child;
+  }
+}
+
+void XmlElement::ClearAttributes() {
+  XmlAttr* attr;
+  for (attr = first_attr_; attr; ) {
+    XmlAttr* to_delete = attr;
+    attr = attr->next_attr_;
+    delete to_delete;
+  }
+  first_attr_ = last_attr_ = NULL;
+}
+
+void XmlElement::ClearChildren() {
+  XmlChild* pchild;
+  for (pchild = first_child_; pchild; ) {
+    XmlChild* to_delete = pchild;
+    pchild = pchild->next_child_;
+    delete to_delete;
+  }
+  first_child_ = last_child_ = NULL;
+}
+
+std::string XmlElement::Str() const {
+  std::stringstream ss;
+  XmlPrinter::PrintXml(&ss, this);
+  return ss.str();
+}
+
+XmlElement* XmlElement::ForStr(const std::string& str) {
+  XmlBuilder builder;
+  XmlParser::ParseXml(&builder, str);
+  return builder.CreateElement();
+}
+
+XmlElement::~XmlElement() {
+  XmlAttr* attr;
+  for (attr = first_attr_; attr; ) {
+    XmlAttr* to_delete = attr;
+    attr = attr->next_attr_;
+    delete to_delete;
+  }
+
+  XmlChild* pchild;
+  for (pchild = first_child_; pchild; ) {
+    XmlChild* to_delete = pchild;
+    pchild = pchild->next_child_;
+    delete to_delete;
+  }
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmllite/xmlelement.h b/third_party/libjingle_xmpp/xmllite/xmlelement.h
new file mode 100644
index 0000000..bec6f99
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlelement.h
@@ -0,0 +1,233 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
+#define WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+
+namespace buzz {
+
+class XmlChild;
+class XmlText;
+class XmlElement;
+class XmlAttr;
+
+class XmlChild {
+ public:
+  XmlChild* NextChild() { return next_child_; }
+  const XmlChild* NextChild() const { return next_child_; }
+
+  bool IsText() const { return IsTextImpl(); }
+
+  XmlElement* AsElement() { return AsElementImpl(); }
+  const XmlElement* AsElement() const { return AsElementImpl(); }
+
+  XmlText* AsText() { return AsTextImpl(); }
+  const XmlText* AsText() const { return AsTextImpl(); }
+
+
+ protected:
+  XmlChild() :
+    next_child_(NULL) {
+  }
+
+  virtual bool IsTextImpl() const = 0;
+  virtual XmlElement* AsElementImpl() const = 0;
+  virtual XmlText* AsTextImpl() const = 0;
+
+
+  virtual ~XmlChild();
+
+ private:
+  friend class XmlElement;
+
+  XmlChild(const XmlChild& noimpl);
+
+  XmlChild* next_child_;
+};
+
+class XmlText : public XmlChild {
+ public:
+  explicit XmlText(const std::string& text) :
+    XmlChild(),
+    text_(text) {
+  }
+  explicit XmlText(const XmlText& t) :
+    XmlChild(),
+    text_(t.text_) {
+  }
+  explicit XmlText(const char* cstr, size_t len) :
+    XmlChild(),
+    text_(cstr, len) {
+  }
+  virtual ~XmlText();
+
+  const std::string& Text() const { return text_; }
+  void SetText(const std::string& text);
+  void AddParsedText(const char* buf, int len);
+  void AddText(const std::string& text);
+
+ protected:
+  virtual bool IsTextImpl() const;
+  virtual XmlElement* AsElementImpl() const;
+  virtual XmlText* AsTextImpl() const;
+
+ private:
+  std::string text_;
+};
+
+class XmlAttr {
+ public:
+  XmlAttr* NextAttr() const { return next_attr_; }
+  const QName& Name() const { return name_; }
+  const std::string& Value() const { return value_; }
+
+ private:
+  friend class XmlElement;
+
+  explicit XmlAttr(const QName& name, const std::string& value) :
+    next_attr_(NULL),
+    name_(name),
+    value_(value) {
+  }
+  explicit XmlAttr(const XmlAttr& att) :
+    next_attr_(NULL),
+    name_(att.name_),
+    value_(att.value_) {
+  }
+
+  XmlAttr* next_attr_;
+  QName name_;
+  std::string value_;
+};
+
+class XmlElement : public XmlChild {
+ public:
+  explicit XmlElement(const QName& name);
+  explicit XmlElement(const QName& name, bool useDefaultNs);
+  explicit XmlElement(const XmlElement& elt);
+
+  virtual ~XmlElement();
+
+  const QName& Name() const { return name_; }
+  void SetName(const QName& name) { name_ = name; }
+
+  const std::string BodyText() const;
+  void SetBodyText(const std::string& text);
+
+  const QName FirstElementName() const;
+
+  XmlAttr* FirstAttr();
+  const XmlAttr* FirstAttr() const
+    { return const_cast<XmlElement *>(this)->FirstAttr(); }
+
+  // Attr will return an empty string if the attribute isn't there:
+  // use HasAttr to test presence of an attribute.
+  const std::string Attr(const StaticQName& name) const;
+  const std::string Attr(const QName& name) const;
+  bool HasAttr(const StaticQName& name) const;
+  bool HasAttr(const QName& name) const;
+  void SetAttr(const QName& name, const std::string& value);
+  void ClearAttr(const QName& name);
+
+  XmlChild* FirstChild();
+  const XmlChild* FirstChild() const {
+    return const_cast<XmlElement *>(this)->FirstChild();
+  }
+
+  XmlElement* FirstElement();
+  const XmlElement* FirstElement() const {
+    return const_cast<XmlElement *>(this)->FirstElement();
+  }
+
+  XmlElement* NextElement();
+  const XmlElement* NextElement() const {
+    return const_cast<XmlElement *>(this)->NextElement();
+  }
+
+  XmlElement* FirstWithNamespace(const std::string& ns);
+  const XmlElement* FirstWithNamespace(const std::string& ns) const {
+    return const_cast<XmlElement *>(this)->FirstWithNamespace(ns);
+  }
+
+  XmlElement* NextWithNamespace(const std::string& ns);
+  const XmlElement* NextWithNamespace(const std::string& ns) const {
+    return const_cast<XmlElement *>(this)->NextWithNamespace(ns);
+  }
+
+  XmlElement* FirstNamed(const StaticQName& name);
+  const XmlElement* FirstNamed(const StaticQName& name) const {
+    return const_cast<XmlElement *>(this)->FirstNamed(name);
+  }
+
+  XmlElement* FirstNamed(const QName& name);
+  const XmlElement* FirstNamed(const QName& name) const {
+    return const_cast<XmlElement *>(this)->FirstNamed(name);
+  }
+
+  XmlElement* NextNamed(const StaticQName& name);
+  const XmlElement* NextNamed(const StaticQName& name) const {
+    return const_cast<XmlElement *>(this)->NextNamed(name);
+  }
+
+  XmlElement* NextNamed(const QName& name);
+  const XmlElement* NextNamed(const QName& name) const {
+    return const_cast<XmlElement *>(this)->NextNamed(name);
+  }
+
+  // Finds the first element named 'name'.  If that element can't be found then
+  // adds one and returns it.
+  XmlElement* FindOrAddNamedChild(const QName& name);
+
+  const std::string TextNamed(const QName& name) const;
+
+  void InsertChildAfter(XmlChild* predecessor, XmlChild* new_child);
+  void RemoveChildAfter(XmlChild* predecessor);
+
+  void AddParsedText(const char* buf, int len);
+  // Note: CDATA is not supported by XMPP, therefore using this function will
+  // generate non-XMPP compatible XML.
+  void AddCDATAText(const char* buf, int len);
+  void AddText(const std::string& text);
+  void AddText(const std::string& text, int depth);
+  void AddElement(XmlElement* child);
+  void AddElement(XmlElement* child, int depth);
+  void AddAttr(const QName& name, const std::string& value);
+  void AddAttr(const QName& name, const std::string& value, int depth);
+  void ClearNamedChildren(const QName& name);
+  void ClearAttributes();
+  void ClearChildren();
+
+  static XmlElement* ForStr(const std::string& str);
+  std::string Str() const;
+
+  bool IsCDATA() const { return cdata_; }
+
+ protected:
+  virtual bool IsTextImpl() const;
+  virtual XmlElement* AsElementImpl() const;
+  virtual XmlText* AsTextImpl() const;
+
+ private:
+  QName name_;
+  XmlAttr* first_attr_;
+  XmlAttr* last_attr_;
+  XmlChild* first_child_;
+  XmlChild* last_child_;
+  bool cdata_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
new file mode 100644
index 0000000..f54ae95
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
@@ -0,0 +1,258 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/gunit.h"
+#include "third_party/webrtc/base/thread.h"
+
+using buzz::QName;
+using buzz::XmlAttr;
+using buzz::XmlChild;
+using buzz::XmlElement;
+
+std::ostream& operator<<(std::ostream& os, const QName& name) {
+  os << name.Namespace() << ":" << name.LocalPart();
+  return os;
+}
+
+TEST(XmlElementTest, TestConstructors) {
+  XmlElement elt(QName("google:test", "first"));
+  EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", elt.Str());
+
+  XmlElement elt2(QName("google:test", "first"), true);
+  EXPECT_EQ("<first xmlns=\"google:test\"/>", elt2.Str());
+}
+
+TEST(XmlElementTest, TestAdd) {
+  XmlElement elt(QName("google:test", "root"), true);
+  elt.AddElement(new XmlElement(QName("google:test", "first")));
+  elt.AddElement(new XmlElement(QName("google:test", "nested")), 1);
+  elt.AddText("nested-value", 2);
+  elt.AddText("between-", 1);
+  elt.AddText("value", 1);
+  elt.AddElement(new XmlElement(QName("google:test", "nested2")), 1);
+  elt.AddElement(new XmlElement(QName("google:test", "second")));
+  elt.AddText("init-value", 1);
+  elt.AddElement(new XmlElement(QName("google:test", "nested3")), 1);
+  elt.AddText("trailing-value", 1);
+
+  // make sure it looks ok overall
+  EXPECT_EQ("<root xmlns=\"google:test\">"
+        "<first><nested>nested-value</nested>between-value<nested2/></first>"
+        "<second>init-value<nested3/>trailing-value</second></root>",
+        elt.Str());
+
+  // make sure text was concatenated
+  XmlChild * pchild =
+    elt.FirstChild()->AsElement()->FirstChild()->NextChild();
+  EXPECT_TRUE(pchild->IsText());
+  EXPECT_EQ("between-value", pchild->AsText()->Text());
+}
+
+TEST(XmlElementTest, TestAttrs) {
+  XmlElement elt(QName("", "root"));
+  elt.SetAttr(QName("", "a"), "avalue");
+  EXPECT_EQ("<root a=\"avalue\"/>", elt.Str());
+
+  elt.SetAttr(QName("", "b"), "bvalue");
+  EXPECT_EQ("<root a=\"avalue\" b=\"bvalue\"/>", elt.Str());
+
+  elt.SetAttr(QName("", "a"), "avalue2");
+  EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue\"/>", elt.Str());
+
+  elt.SetAttr(QName("", "b"), "bvalue2");
+  EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\"/>", elt.Str());
+
+  elt.SetAttr(QName("", "c"), "cvalue");
+  EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\"/>", elt.Str());
+
+  XmlAttr * patt = elt.FirstAttr();
+  EXPECT_EQ(QName("", "a"), patt->Name());
+  EXPECT_EQ("avalue2", patt->Value());
+
+  patt = patt->NextAttr();
+  EXPECT_EQ(QName("", "b"), patt->Name());
+  EXPECT_EQ("bvalue2", patt->Value());
+
+  patt = patt->NextAttr();
+  EXPECT_EQ(QName("", "c"), patt->Name());
+  EXPECT_EQ("cvalue", patt->Value());
+
+  patt = patt->NextAttr();
+  EXPECT_TRUE(NULL == patt);
+
+  EXPECT_TRUE(elt.HasAttr(QName("", "a")));
+  EXPECT_TRUE(elt.HasAttr(QName("", "b")));
+  EXPECT_TRUE(elt.HasAttr(QName("", "c")));
+  EXPECT_FALSE(elt.HasAttr(QName("", "d")));
+
+  elt.SetAttr(QName("", "d"), "dvalue");
+  EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>",
+      elt.Str());
+  EXPECT_TRUE(elt.HasAttr(QName("", "d")));
+
+  elt.ClearAttr(QName("", "z"));  // not found, no effect
+  EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>",
+      elt.Str());
+
+  elt.ClearAttr(QName("", "b"));
+  EXPECT_EQ("<root a=\"avalue2\" c=\"cvalue\" d=\"dvalue\"/>", elt.Str());
+
+  elt.ClearAttr(QName("", "a"));
+  EXPECT_EQ("<root c=\"cvalue\" d=\"dvalue\"/>", elt.Str());
+
+  elt.ClearAttr(QName("", "d"));
+  EXPECT_EQ("<root c=\"cvalue\"/>", elt.Str());
+
+  elt.ClearAttr(QName("", "c"));
+  EXPECT_EQ("<root/>", elt.Str());
+}
+
+TEST(XmlElementTest, TestBodyText) {
+  XmlElement elt(QName("", "root"));
+  EXPECT_EQ("", elt.BodyText());
+
+  elt.AddText("body value text");
+
+  EXPECT_EQ("body value text", elt.BodyText());
+
+  elt.ClearChildren();
+  elt.AddText("more value ");
+  elt.AddText("text");
+
+  EXPECT_EQ("more value text", elt.BodyText());
+
+  elt.ClearChildren();
+  elt.AddText("decoy");
+  elt.AddElement(new XmlElement(QName("", "dummy")));
+  EXPECT_EQ("", elt.BodyText());
+
+  elt.SetBodyText("replacement");
+  EXPECT_EQ("replacement", elt.BodyText());
+
+  elt.SetBodyText("");
+  EXPECT_TRUE(NULL == elt.FirstChild());
+
+  elt.SetBodyText("goodbye");
+  EXPECT_EQ("goodbye", elt.FirstChild()->AsText()->Text());
+  EXPECT_EQ("goodbye", elt.BodyText());
+}
+
+TEST(XmlElementTest, TestCopyConstructor) {
+  XmlElement * element = XmlElement::ForStr(
+      "<root xmlns='test-foo'>This is a <em a='avalue' b='bvalue'>"
+      "little <b>little</b></em> test</root>");
+
+  XmlElement * pelCopy = new XmlElement(*element);
+  EXPECT_EQ("<root xmlns=\"test-foo\">This is a <em a=\"avalue\" b=\"bvalue\">"
+      "little <b>little</b></em> test</root>", pelCopy->Str());
+  delete pelCopy;
+
+  pelCopy = new XmlElement(*(element->FirstChild()->NextChild()->AsElement()));
+  EXPECT_EQ("<foo:em a=\"avalue\" b=\"bvalue\" xmlns:foo=\"test-foo\">"
+      "little <foo:b>little</foo:b></foo:em>", pelCopy->Str());
+
+  XmlAttr * patt = pelCopy->FirstAttr();
+  EXPECT_EQ(QName("", "a"), patt->Name());
+  EXPECT_EQ("avalue", patt->Value());
+
+  patt = patt->NextAttr();
+  EXPECT_EQ(QName("", "b"), patt->Name());
+  EXPECT_EQ("bvalue", patt->Value());
+
+  patt = patt->NextAttr();
+  EXPECT_TRUE(NULL == patt);
+  delete pelCopy;
+  delete element;
+}
+
+TEST(XmlElementTest, TestNameSearch) {
+  XmlElement * element = XmlElement::ForStr(
+    "<root xmlns='test-foo'>"
+      "<firstname>George</firstname>"
+      "<middlename>X.</middlename>"
+      "some text"
+      "<lastname>Harrison</lastname>"
+      "<firstname>John</firstname>"
+      "<middlename>Y.</middlename>"
+      "<lastname>Lennon</lastname>"
+    "</root>");
+  EXPECT_TRUE(NULL ==
+      element->FirstNamed(QName("", "firstname")));
+  EXPECT_EQ(element->FirstChild(),
+      element->FirstNamed(QName("test-foo", "firstname")));
+  EXPECT_EQ(element->FirstChild()->NextChild(),
+      element->FirstNamed(QName("test-foo", "middlename")));
+  EXPECT_EQ(element->FirstElement()->NextElement(),
+      element->FirstNamed(QName("test-foo", "middlename")));
+  EXPECT_EQ("Harrison",
+      element->TextNamed(QName("test-foo", "lastname")));
+  EXPECT_EQ(element->FirstElement()->NextElement()->NextElement(),
+      element->FirstNamed(QName("test-foo", "lastname")));
+  EXPECT_EQ("John", element->FirstNamed(QName("test-foo", "firstname"))->
+      NextNamed(QName("test-foo", "firstname"))->BodyText());
+  EXPECT_EQ("Y.", element->FirstNamed(QName("test-foo", "middlename"))->
+      NextNamed(QName("test-foo", "middlename"))->BodyText());
+  EXPECT_EQ("Lennon", element->FirstNamed(QName("test-foo", "lastname"))->
+      NextNamed(QName("test-foo", "lastname"))->BodyText());
+  EXPECT_TRUE(NULL == element->FirstNamed(QName("test-foo", "firstname"))->
+      NextNamed(QName("test-foo", "firstname"))->
+      NextNamed(QName("test-foo", "firstname")));
+
+  delete element;
+}
+
+class XmlElementCreatorThread : public rtc::Thread {
+ public:
+  XmlElementCreatorThread(int count, buzz::QName qname) :
+      count_(count), qname_(qname) {}
+
+  virtual ~XmlElementCreatorThread() {
+    Stop();
+  }
+
+  virtual void Run() {
+    std::vector<buzz::XmlElement*> elems;
+    for (int i = 0; i < count_; i++) {
+      elems.push_back(new XmlElement(qname_));
+    }
+    for (int i = 0; i < count_; i++) {
+      delete elems[i];
+    }
+  }
+
+ private:
+  int count_;
+  buzz::QName qname_;
+};
+
+// If XmlElement creation and destruction isn't thread safe,
+// this test should crash.
+TEST(XmlElementTest, TestMultithread) {
+  int thread_count = 2;  // Was 100, but that's too slow.
+  int elem_count = 100;  // Was 100000, but that's too slow.
+  buzz::QName qname("foo", "bar");
+
+  std::vector<rtc::Thread*> threads;
+  for (int i = 0; i < thread_count; i++) {
+    threads.push_back(
+        new XmlElementCreatorThread(elem_count, qname));
+    threads[i]->Start();
+  }
+
+  for (int i = 0; i < thread_count; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+  }
+}
diff --git a/third_party/libjingle_xmpp/xmllite/xmlnsstack.cc b/third_party/libjingle_xmpp/xmllite/xmlnsstack.cc
new file mode 100644
index 0000000..597dc9c0
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlnsstack.cc
@@ -0,0 +1,178 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+
+namespace buzz {
+
+XmlnsStack::XmlnsStack() :
+  pxmlnsStack_(new std::vector<std::string>),
+  pxmlnsDepthStack_(new std::vector<size_t>) {
+}
+
+XmlnsStack::~XmlnsStack() {}
+
+void XmlnsStack::PushFrame() {
+  pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
+}
+
+void XmlnsStack::PopFrame() {
+  size_t prev_size = pxmlnsDepthStack_->back();
+  pxmlnsDepthStack_->pop_back();
+  if (prev_size < pxmlnsStack_->size()) {
+    pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size,
+                        pxmlnsStack_->end());
+  }
+}
+
+std::pair<std::string, bool> XmlnsStack::NsForPrefix(
+    const std::string& prefix) {
+  if (prefix.length() >= 3 &&
+      (prefix[0] == 'x' || prefix[0] == 'X') &&
+      (prefix[1] == 'm' || prefix[1] == 'M') &&
+      (prefix[2] == 'l' || prefix[2] == 'L')) {
+    if (prefix == "xml")
+      return std::make_pair(NS_XML, true);
+    if (prefix == "xmlns")
+      return std::make_pair(NS_XMLNS, true);
+    // Other names with xml prefix are illegal.
+    return std::make_pair(STR_EMPTY, false);
+  }
+
+  std::vector<std::string>::iterator pos;
+  for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
+    pos -= 2;
+    if (*pos == prefix)
+      return std::make_pair(*(pos + 1), true);
+  }
+
+  if (prefix == STR_EMPTY)
+    return std::make_pair(STR_EMPTY, true);  // default namespace
+
+  return std::make_pair(STR_EMPTY, false);  // none found
+}
+
+bool XmlnsStack::PrefixMatchesNs(const std::string& prefix,
+                                 const std::string& ns) {
+  const std::pair<std::string, bool> match = NsForPrefix(prefix);
+  return match.second && (match.first == ns);
+}
+
+std::pair<std::string, bool> XmlnsStack::PrefixForNs(const std::string& ns,
+                                                     bool isattr) {
+  if (ns == NS_XML)
+    return std::make_pair(std::string("xml"), true);
+  if (ns == NS_XMLNS)
+    return std::make_pair(std::string("xmlns"), true);
+  if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns))
+    return std::make_pair(STR_EMPTY, true);
+
+  std::vector<std::string>::iterator pos;
+  for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
+    pos -= 2;
+    if (*(pos + 1) == ns &&
+        (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns))
+      return std::make_pair(*pos, true);
+  }
+
+  return std::make_pair(STR_EMPTY, false); // none found
+}
+
+std::string XmlnsStack::FormatQName(const QName& name, bool isAttr) {
+  std::string prefix(PrefixForNs(name.Namespace(), isAttr).first);
+  if (prefix == STR_EMPTY)
+    return name.LocalPart();
+  else
+    return prefix + ':' + name.LocalPart();
+}
+
+void XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
+  pxmlnsStack_->push_back(prefix);
+  pxmlnsStack_->push_back(ns);
+}
+
+void XmlnsStack::RemoveXmlns() {
+  pxmlnsStack_->pop_back();
+  pxmlnsStack_->pop_back();
+}
+
+static bool IsAsciiLetter(char ch) {
+  return ((ch >= 'a' && ch <= 'z') ||
+          (ch >= 'A' && ch <= 'Z'));
+}
+
+static std::string AsciiLower(const std::string & s) {
+  std::string result(s);
+  size_t i;
+  for (i = 0; i < result.length(); i++) {
+    if (result[i] >= 'A' && result[i] <= 'Z')
+      result[i] += 'a' - 'A';
+  }
+  return result;
+}
+
+static std::string SuggestPrefix(const std::string & ns) {
+  size_t len = ns.length();
+  size_t i = ns.find_last_of('.');
+  if (i != std::string::npos && len - i <= 4 + 1)
+    len = i; // chop off ".html" or ".xsd" or ".?{0,4}"
+  size_t last = len;
+  while (last > 0) {
+    last -= 1;
+    if (IsAsciiLetter(ns[last])) {
+      size_t first = last;
+      last += 1;
+      while (first > 0) {
+        if (!IsAsciiLetter(ns[first - 1]))
+          break;
+        first -= 1;
+      }
+      if (last - first > 4)
+        last = first + 3;
+      std::string candidate(AsciiLower(ns.substr(first, last - first)));
+      if (candidate.find("xml") != 0)
+        return candidate;
+      break;
+    }
+  }
+  return "ns";
+}
+
+std::pair<std::string, bool> XmlnsStack::AddNewPrefix(const std::string& ns,
+                                                      bool isAttr) {
+  if (PrefixForNs(ns, isAttr).second)
+    return std::make_pair(STR_EMPTY, false);
+
+  std::string base(SuggestPrefix(ns));
+  std::string result(base);
+  int i = 2;
+  while (NsForPrefix(result).second) {
+    std::stringstream ss;
+    ss << base;
+    ss << (i++);
+    ss >> result;
+  }
+  AddXmlns(result, ns);
+  return std::make_pair(result, true);
+}
+
+void XmlnsStack::Reset() {
+  pxmlnsStack_->clear();
+  pxmlnsDepthStack_->clear();
+}
+
+}
diff --git a/third_party/libjingle_xmpp/xmllite/xmlnsstack.h b/third_party/libjingle_xmpp/xmllite/xmlnsstack.h
new file mode 100644
index 0000000..c6200a9
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlnsstack.h
@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
+#define WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+
+namespace buzz {
+
+class XmlnsStack {
+public:
+  XmlnsStack();
+  ~XmlnsStack();
+
+  void AddXmlns(const std::string& prefix, const std::string& ns);
+  void RemoveXmlns();
+  void PushFrame();
+  void PopFrame();
+  void Reset();
+
+  std::pair<std::string, bool> NsForPrefix(const std::string& prefix);
+  bool PrefixMatchesNs(const std::string & prefix, const std::string & ns);
+  std::pair<std::string, bool> PrefixForNs(const std::string& ns, bool isAttr);
+  std::pair<std::string, bool> AddNewPrefix(const std::string& ns, bool isAttr);
+  std::string FormatQName(const QName & name, bool isAttr);
+
+private:
+
+  std::unique_ptr<std::vector<std::string> > pxmlnsStack_;
+  std::unique_ptr<std::vector<size_t> > pxmlnsDepthStack_;
+};
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
new file mode 100644
index 0000000..19372a6
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
@@ -0,0 +1,241 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::NS_XML;
+using buzz::NS_XMLNS;
+using buzz::QName;
+using buzz::XmlnsStack;
+
+TEST(XmlnsStackTest, TestBuiltin) {
+  XmlnsStack stack;
+
+  EXPECT_EQ(std::string(NS_XML), stack.NsForPrefix("xml").first);
+  EXPECT_EQ(std::string(NS_XMLNS), stack.NsForPrefix("xmlns").first);
+  EXPECT_EQ("", stack.NsForPrefix("").first);
+
+  EXPECT_EQ("xml", stack.PrefixForNs(NS_XML, false).first);
+  EXPECT_EQ("xmlns", stack.PrefixForNs(NS_XMLNS, false).first);
+  EXPECT_EQ("", stack.PrefixForNs("", false).first);
+  EXPECT_EQ("", stack.PrefixForNs("", true).first);
+}
+
+TEST(XmlnsStackTest, TestNsForPrefix) {
+ XmlnsStack stack;
+  stack.AddXmlns("pre1", "ns1");
+  stack.AddXmlns("pre2", "ns2");
+  stack.AddXmlns("pre1", "ns3");
+  stack.AddXmlns("", "ns4");
+
+  EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
+  EXPECT_TRUE(stack.NsForPrefix("pre1").second);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
+  EXPECT_EQ("ns4", stack.NsForPrefix("").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre3").first);
+  EXPECT_FALSE(stack.NsForPrefix("pre3").second);
+}
+
+TEST(XmlnsStackTest, TestPrefixForNs) {
+  XmlnsStack stack;
+  stack.AddXmlns("pre1", "ns1");
+  stack.AddXmlns("pre2", "ns2");
+  stack.AddXmlns("pre1", "ns3");
+  stack.AddXmlns("pre3", "ns2");
+  stack.AddXmlns("pre4", "ns4");
+  stack.AddXmlns("", "ns4");
+
+  EXPECT_EQ("", stack.PrefixForNs("ns1", false).first);
+  EXPECT_FALSE(stack.PrefixForNs("ns1", false).second);
+  EXPECT_EQ("", stack.PrefixForNs("ns1", true).first);
+  EXPECT_FALSE(stack.PrefixForNs("ns1", true).second);
+  EXPECT_EQ("pre3", stack.PrefixForNs("ns2", false).first);
+  EXPECT_TRUE(stack.PrefixForNs("ns2", false).second);
+  EXPECT_EQ("pre3", stack.PrefixForNs("ns2", true).first);
+  EXPECT_TRUE(stack.PrefixForNs("ns2", true).second);
+  EXPECT_EQ("pre1", stack.PrefixForNs("ns3", false).first);
+  EXPECT_EQ("pre1", stack.PrefixForNs("ns3", true).first);
+  EXPECT_EQ("", stack.PrefixForNs("ns4", false).first);
+  EXPECT_TRUE(stack.PrefixForNs("ns4", false).second);
+  EXPECT_EQ("pre4", stack.PrefixForNs("ns4", true).first);
+  EXPECT_EQ("", stack.PrefixForNs("ns5", false).first);
+  EXPECT_FALSE(stack.PrefixForNs("ns5", false).second);
+  EXPECT_EQ("", stack.PrefixForNs("ns5", true).first);
+  EXPECT_EQ("", stack.PrefixForNs("", false).first);
+  EXPECT_EQ("", stack.PrefixForNs("", true).first);
+
+  stack.AddXmlns("", "ns6");
+  EXPECT_EQ("", stack.PrefixForNs("ns6", false).first);
+  EXPECT_TRUE(stack.PrefixForNs("ns6", false).second);
+  EXPECT_EQ("", stack.PrefixForNs("ns6", true).first);
+  EXPECT_FALSE(stack.PrefixForNs("ns6", true).second);
+}
+
+TEST(XmlnsStackTest, TestFrames) {
+  XmlnsStack stack;
+  stack.PushFrame();
+  stack.AddXmlns("pre1", "ns1");
+  stack.AddXmlns("pre2", "ns2");
+
+  stack.PushFrame();
+  stack.AddXmlns("pre1", "ns3");
+  stack.AddXmlns("pre3", "ns2");
+  stack.AddXmlns("pre4", "ns4");
+
+  stack.PushFrame();
+  stack.PushFrame();
+  stack.AddXmlns("", "ns4");
+
+  // basic test
+  EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first);
+  EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre5").first);
+  EXPECT_FALSE(stack.NsForPrefix("pre5").second);
+  EXPECT_EQ("ns4", stack.NsForPrefix("").first);
+  EXPECT_TRUE(stack.NsForPrefix("").second);
+
+  // pop the default xmlns definition
+  stack.PopFrame();
+  EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first);
+  EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre5").first);
+  EXPECT_FALSE(stack.NsForPrefix("pre5").second);
+  EXPECT_EQ("", stack.NsForPrefix("").first);
+  EXPECT_TRUE(stack.NsForPrefix("").second);
+
+  // pop empty frame (nop)
+  stack.PopFrame();
+  EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first);
+  EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre5").first);
+  EXPECT_FALSE(stack.NsForPrefix("pre5").second);
+  EXPECT_EQ("", stack.NsForPrefix("").first);
+  EXPECT_TRUE(stack.NsForPrefix("").second);
+
+  // pop frame with three defs
+  stack.PopFrame();
+  EXPECT_EQ("ns1", stack.NsForPrefix("pre1").first);
+  EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre3").first);
+  EXPECT_FALSE(stack.NsForPrefix("pre3").second);
+  EXPECT_EQ("", stack.NsForPrefix("pre4").first);
+  EXPECT_FALSE(stack.NsForPrefix("pre4").second);
+  EXPECT_EQ("", stack.NsForPrefix("pre5").first);
+  EXPECT_FALSE(stack.NsForPrefix("pre5").second);
+  EXPECT_EQ("", stack.NsForPrefix("").first);
+  EXPECT_TRUE(stack.NsForPrefix("").second);
+
+  // pop frame with last two defs
+  stack.PopFrame();
+  EXPECT_FALSE(stack.NsForPrefix("pre1").second);
+  EXPECT_FALSE(stack.NsForPrefix("pre2").second);
+  EXPECT_FALSE(stack.NsForPrefix("pre3").second);
+  EXPECT_FALSE(stack.NsForPrefix("pre4").second);
+  EXPECT_FALSE(stack.NsForPrefix("pre5").second);
+  EXPECT_TRUE(stack.NsForPrefix("").second);
+  EXPECT_EQ("", stack.NsForPrefix("pre1").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre2").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre3").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre4").first);
+  EXPECT_EQ("", stack.NsForPrefix("pre5").first);
+  EXPECT_EQ("", stack.NsForPrefix("").first);
+}
+
+TEST(XmlnsStackTest, TestAddNewPrefix) {
+  XmlnsStack stack;
+
+  // builtin namespaces cannot be added
+  EXPECT_FALSE(stack.AddNewPrefix("", true).second);
+  EXPECT_FALSE(stack.AddNewPrefix("", false).second);
+  EXPECT_FALSE(stack.AddNewPrefix(NS_XML, true).second);
+  EXPECT_FALSE(stack.AddNewPrefix(NS_XML, false).second);
+  EXPECT_FALSE(stack.AddNewPrefix(NS_XMLNS, true).second);
+  EXPECT_FALSE(stack.AddNewPrefix(NS_XMLNS, false).second);
+
+  // namespaces already added cannot be added again.
+  EXPECT_EQ("foo", stack.AddNewPrefix("http://a.b.com/foo.htm", true).first);
+  EXPECT_EQ("bare", stack.AddNewPrefix("http://a.b.com/bare", false).first);
+  EXPECT_EQ("z", stack.AddNewPrefix("z", false).first);
+  EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/foo.htm", true).second);
+  EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/bare", true).second);
+  EXPECT_FALSE(stack.AddNewPrefix("z", true).second);
+  EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/foo.htm", false).second);
+  EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/bare", false).second);
+  EXPECT_FALSE(stack.AddNewPrefix("z", false).second);
+
+  // default namespace usable by non-attributes only
+  stack.AddXmlns("", "http://my/default");
+  EXPECT_FALSE(stack.AddNewPrefix("http://my/default", false).second);
+  EXPECT_EQ("def", stack.AddNewPrefix("http://my/default", true).first);
+
+  // namespace cannot start with 'xml'
+  EXPECT_EQ("ns", stack.AddNewPrefix("http://a.b.com/xmltest", true).first);
+  EXPECT_EQ("ns2", stack.AddNewPrefix("xmlagain", false).first);
+
+  // verify added namespaces are still defined
+  EXPECT_EQ("http://a.b.com/foo.htm", stack.NsForPrefix("foo").first);
+  EXPECT_TRUE(stack.NsForPrefix("foo").second);
+  EXPECT_EQ("http://a.b.com/bare", stack.NsForPrefix("bare").first);
+  EXPECT_TRUE(stack.NsForPrefix("bare").second);
+  EXPECT_EQ("z", stack.NsForPrefix("z").first);
+  EXPECT_TRUE(stack.NsForPrefix("z").second);
+  EXPECT_EQ("http://my/default", stack.NsForPrefix("").first);
+  EXPECT_TRUE(stack.NsForPrefix("").second);
+  EXPECT_EQ("http://my/default", stack.NsForPrefix("def").first);
+  EXPECT_TRUE(stack.NsForPrefix("def").second);
+  EXPECT_EQ("http://a.b.com/xmltest", stack.NsForPrefix("ns").first);
+  EXPECT_TRUE(stack.NsForPrefix("ns").second);
+  EXPECT_EQ("xmlagain", stack.NsForPrefix("ns2").first);
+  EXPECT_TRUE(stack.NsForPrefix("ns2").second);
+}
+
+TEST(XmlnsStackTest, TestFormatQName) {
+  XmlnsStack stack;
+  stack.AddXmlns("pre1", "ns1");
+  stack.AddXmlns("pre2", "ns2");
+  stack.AddXmlns("pre1", "ns3");
+  stack.AddXmlns("", "ns4");
+
+  EXPECT_EQ("zip",
+      stack.FormatQName(QName("ns1", "zip"), false));  // no match
+  EXPECT_EQ("pre2:abracadabra",
+      stack.FormatQName(QName("ns2", "abracadabra"), false));
+  EXPECT_EQ("pre1:a",
+      stack.FormatQName(QName("ns3", "a"), false));
+  EXPECT_EQ("simple",
+      stack.FormatQName(QName("ns4", "simple"), false));
+  EXPECT_EQ("root",
+      stack.FormatQName(QName("", "root"), false));  // no match
+
+  EXPECT_EQ("zip",
+      stack.FormatQName(QName("ns1", "zip"), true));  // no match
+  EXPECT_EQ("pre2:abracadabra",
+      stack.FormatQName(QName("ns2", "abracadabra"), true));
+  EXPECT_EQ("pre1:a",
+      stack.FormatQName(QName("ns3", "a"), true));
+  EXPECT_EQ("simple",
+      stack.FormatQName(QName("ns4", "simple"), true));  // no match
+  EXPECT_EQ("root",
+      stack.FormatQName(QName("", "root"), true));
+}
diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser.cc b/third_party/libjingle_xmpp/xmllite/xmlparser.cc
new file mode 100644
index 0000000..1f8153f
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlparser.cc
@@ -0,0 +1,261 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
+
+#include <string>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
+#include "third_party/webrtc/base/common.h"
+
+namespace buzz {
+
+
+static void
+StartElementCallback(void * userData, const char *name, const char **atts) {
+  (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts);
+}
+
+static void
+EndElementCallback(void * userData, const char *name) {
+  (static_cast<XmlParser *>(userData))->ExpatEndElement(name);
+}
+
+static void
+CharacterDataCallback(void * userData, const char *text, int len) {
+  (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len);
+}
+
+static void
+XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
+  (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st);
+}
+
+XmlParser::XmlParser(XmlParseHandler *pxph) :
+    pxph_(pxph), sentError_(false) {
+  expat_ = XML_ParserCreate(NULL);
+  XML_SetUserData(expat_, this);
+  XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
+  XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
+  XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
+}
+
+void
+XmlParser::Reset() {
+  if (!XML_ParserReset(expat_, NULL)) {
+    XML_ParserFree(expat_);
+    expat_ = XML_ParserCreate(NULL);
+  }
+  XML_SetUserData(expat_, this);
+  XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
+  XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
+  XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
+  context_.Reset();
+  sentError_ = false;
+}
+
+static bool
+XmlParser_StartsWithXmlns(const char *name) {
+  return name[0] == 'x' &&
+         name[1] == 'm' &&
+         name[2] == 'l' &&
+         name[3] == 'n' &&
+         name[4] == 's';
+}
+
+void
+XmlParser::ExpatStartElement(const char *name, const char **atts) {
+  if (context_.RaisedError() != XML_ERROR_NONE)
+    return;
+  const char **att;
+  context_.StartElement();
+  for (att = atts; *att; att += 2) {
+    if (XmlParser_StartsWithXmlns(*att)) {
+      if ((*att)[5] == '\0') {
+        context_.StartNamespace("", *(att + 1));
+      }
+      else if ((*att)[5] == ':') {
+        if (**(att + 1) == '\0') {
+          // In XML 1.0 empty namespace illegal with prefix (not in 1.1)
+          context_.RaiseError(XML_ERROR_SYNTAX);
+          return;
+        }
+        context_.StartNamespace((*att) + 6, *(att + 1));
+      }
+    }
+  }
+  context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+                       XML_GetCurrentColumnNumber(expat_),
+                       XML_GetCurrentByteIndex(expat_));
+  pxph_->StartElement(&context_, name, atts);
+}
+
+void
+XmlParser::ExpatEndElement(const char *name) {
+  if (context_.RaisedError() != XML_ERROR_NONE)
+    return;
+  context_.EndElement();
+  context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+                       XML_GetCurrentColumnNumber(expat_),
+                       XML_GetCurrentByteIndex(expat_));
+  pxph_->EndElement(&context_, name);
+}
+
+void
+XmlParser::ExpatCharacterData(const char *text, int len) {
+  if (context_.RaisedError() != XML_ERROR_NONE)
+    return;
+  context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+                       XML_GetCurrentColumnNumber(expat_),
+                       XML_GetCurrentByteIndex(expat_));
+  pxph_->CharacterData(&context_, text, len);
+}
+
+void
+XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) {
+  if (context_.RaisedError() != XML_ERROR_NONE)
+    return;
+
+  if (ver && std::string("1.0") != ver) {
+    context_.RaiseError(XML_ERROR_SYNTAX);
+    return;
+  }
+
+  if (standalone == 0) {
+    context_.RaiseError(XML_ERROR_SYNTAX);
+    return;
+  }
+
+  if (enc && !((enc[0] == 'U' || enc[0] == 'u') &&
+               (enc[1] == 'T' || enc[1] == 't') &&
+               (enc[2] == 'F' || enc[2] == 'f') &&
+                enc[3] == '-' && enc[4] =='8')) {
+    context_.RaiseError(XML_ERROR_INCORRECT_ENCODING);
+    return;
+  }
+
+}
+
+bool
+XmlParser::Parse(const char *data, size_t len, bool isFinal) {
+  if (sentError_)
+    return false;
+
+  if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) !=
+      XML_STATUS_OK) {
+    context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+                         XML_GetCurrentColumnNumber(expat_),
+                         XML_GetCurrentByteIndex(expat_));
+    context_.RaiseError(XML_GetErrorCode(expat_));
+  }
+
+  if (context_.RaisedError() != XML_ERROR_NONE) {
+    sentError_ = true;
+    pxph_->Error(&context_, context_.RaisedError());
+    return false;
+  }
+
+  return true;
+}
+
+XmlParser::~XmlParser() {
+  XML_ParserFree(expat_);
+}
+
+void
+XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
+  XmlParser parser(pxph);
+  parser.Parse(text.c_str(), text.length(), true);
+}
+
+XmlParser::ParseContext::ParseContext() :
+    xmlnsstack_(),
+    raised_(XML_ERROR_NONE),
+    line_number_(0),
+    column_number_(0),
+    byte_index_(0) {
+}
+
+void
+XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) {
+  xmlnsstack_.AddXmlns(*prefix ? prefix : STR_EMPTY, ns);
+}
+
+void
+XmlParser::ParseContext::StartElement() {
+  xmlnsstack_.PushFrame();
+}
+
+void
+XmlParser::ParseContext::EndElement() {
+  xmlnsstack_.PopFrame();
+}
+
+QName
+XmlParser::ParseContext::ResolveQName(const char* qname, bool isAttr) {
+  const char *c;
+  for (c = qname; *c; ++c) {
+    if (*c == ':') {
+      const std::pair<std::string, bool> result =
+          xmlnsstack_.NsForPrefix(std::string(qname, c - qname));
+      if (!result.second)
+        return QName();
+      return QName(result.first, c + 1);
+    }
+  }
+  if (isAttr)
+    return QName(STR_EMPTY, qname);
+
+  std::pair<std::string, bool> result = xmlnsstack_.NsForPrefix(STR_EMPTY);
+  if (!result.second)
+    return QName();
+
+  return QName(result.first, qname);
+}
+
+void
+XmlParser::ParseContext::Reset() {
+  xmlnsstack_.Reset();
+  raised_ = XML_ERROR_NONE;
+}
+
+void
+XmlParser::ParseContext::SetPosition(int line, int column,
+                                          long byte_index) {
+  line_number_ = line;
+  column_number_ = column;
+  byte_index_ = byte_index;
+}
+
+void
+XmlParser::ParseContext::GetPosition(unsigned long * line,
+                                     unsigned long * column,
+                                     unsigned long * byte_index) {
+  if (line != NULL) {
+    *line = static_cast<unsigned long>(line_number_);
+  }
+
+  if (column != NULL) {
+    *column = static_cast<unsigned long>(column_number_);
+  }
+
+  if (byte_index != NULL) {
+    *byte_index = static_cast<unsigned long>(byte_index_);
+  }
+}
+
+XmlParser::ParseContext::~ParseContext() {
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser.h b/third_party/libjingle_xmpp/xmllite/xmlparser.h
new file mode 100644
index 0000000..677dec6
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlparser.h
@@ -0,0 +1,103 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
+#define WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
+
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
+#ifdef EXPAT_RELATIVE_PATH
+#include "expat.h"
+#else
+#include "third_party/expat/v2_0_1/Source/lib/expat.h"
+#endif  // EXPAT_RELATIVE_PATH
+
+struct XML_ParserStruct;
+typedef struct XML_ParserStruct* XML_Parser;
+
+namespace buzz {
+
+class XmlParseHandler;
+class XmlParseContext;
+class XmlParser;
+
+class XmlParseContext {
+public:
+  virtual ~XmlParseContext() {}
+  virtual QName ResolveQName(const char * qname, bool isAttr) = 0;
+  virtual void RaiseError(XML_Error err) = 0;
+  virtual void GetPosition(unsigned long * line, unsigned long * column,
+                           unsigned long * byte_index) = 0;
+};
+
+class XmlParseHandler {
+public:
+  virtual ~XmlParseHandler() {}
+  virtual void StartElement(XmlParseContext * pctx,
+               const char * name, const char ** atts) = 0;
+  virtual void EndElement(XmlParseContext * pctx,
+               const char * name) = 0;
+  virtual void CharacterData(XmlParseContext * pctx,
+               const char * text, int len) = 0;
+  virtual void Error(XmlParseContext * pctx,
+               XML_Error errorCode) = 0;
+};
+
+class XmlParser {
+public:
+  static void ParseXml(XmlParseHandler * pxph, std::string text);
+
+  explicit XmlParser(XmlParseHandler * pxph);
+  bool Parse(const char * data, size_t len, bool isFinal);
+  void Reset();
+  virtual ~XmlParser();
+
+  // expat callbacks
+  void ExpatStartElement(const char * name, const char ** atts);
+  void ExpatEndElement(const char * name);
+  void ExpatCharacterData(const char * text, int len);
+  void ExpatXmlDecl(const char * ver, const char * enc, int standalone);
+
+private:
+
+  class ParseContext : public XmlParseContext {
+  public:
+    ParseContext();
+    virtual ~ParseContext();
+    virtual QName ResolveQName(const char * qname, bool isAttr);
+    virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; }
+    virtual void GetPosition(unsigned long * line, unsigned long * column,
+                             unsigned long * byte_index);
+    XML_Error RaisedError() { return raised_; }
+    void Reset();
+
+    void StartElement();
+    void EndElement();
+    void StartNamespace(const char * prefix, const char * ns);
+    void SetPosition(int line, int column, long byte_index);
+
+  private:
+    XmlnsStack xmlnsstack_;
+    XML_Error raised_;
+    XML_Size line_number_;
+    XML_Size column_number_;
+    XML_Index byte_index_;
+  };
+
+  ParseContext context_;
+  XML_Parser expat_;
+  XmlParseHandler * pxph_;
+  bool sentError_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
new file mode 100644
index 0000000..a0a6101
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
@@ -0,0 +1,285 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::QName;
+using buzz::XmlParser;
+using buzz::XmlParseContext;
+using buzz::XmlParseHandler;
+
+class XmlParserTestHandler : public XmlParseHandler {
+ public:
+  virtual void StartElement(XmlParseContext * pctx,
+                            const char * name, const char ** atts) {
+    ss_ << "START (" << pctx->ResolveQName(name, false).Merged();
+    while (*atts) {
+      ss_ << ", " << pctx->ResolveQName(*atts, true).Merged()
+          << "='" << *(atts+1) << "'";
+      atts += 2;
+    }
+    ss_ << ") ";
+  }
+  virtual void EndElement(XmlParseContext * pctx, const char * name) {
+    RTC_UNUSED(pctx);
+    RTC_UNUSED(name);
+    ss_ << "END ";
+  }
+  virtual void CharacterData(XmlParseContext * pctx,
+                             const char * text, int len) {
+    RTC_UNUSED(pctx);
+    ss_ << "TEXT (" << std::string(text, len) << ") ";
+  }
+  virtual void Error(XmlParseContext * pctx, XML_Error code) {
+    RTC_UNUSED(pctx);
+    ss_ << "ERROR (" << static_cast<int>(code) << ") ";
+  }
+  virtual ~XmlParserTestHandler() {
+  }
+
+  std::string Str() {
+    return ss_.str();
+  }
+
+  std::string StrClear() {
+    std::string result = ss_.str();
+    ss_.str("");
+    return result;
+  }
+
+ private:
+  std::stringstream ss_;
+};
+
+
+TEST(XmlParserTest, TestTrivial) {
+  XmlParserTestHandler handler;
+  XmlParser::ParseXml(&handler, "<testing/>");
+  EXPECT_EQ("START (testing) END ", handler.Str());
+}
+
+TEST(XmlParserTest, TestAttributes) {
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<testing a='b'/>");
+    EXPECT_EQ("START (testing, a='b') END ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<testing e='' long='some text'/>");
+    EXPECT_EQ("START (testing, e='', long='some text') END ", handler.Str());
+  }
+}
+
+TEST(XmlParserTest, TestNesting) {
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<top><first/><second><third></third></second></top>");
+    EXPECT_EQ("START (top) START (first) END START (second) START (third) "
+        "END END END ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<top><fifth><deeper><and><deeper/></and>"
+        "<sibling><leaf/></sibling></deeper></fifth><first/><second>"
+        "<third></third></second></top>");
+    EXPECT_EQ("START (top) START (fifth) START (deeper) START (and) START "
+            "(deeper) END END START (sibling) START (leaf) END END END "
+            "END START (first) END START (second) START (third) END END END ",
+            handler.Str());
+  }
+}
+
+TEST(XmlParserTest, TestXmlDecl) {
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<?xml version=\"1.0\"?><testing/>");
+    EXPECT_EQ("START (testing) END ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<?xml version=\"1.0\" encoding=\"utf-8\"?><testing/>");
+    EXPECT_EQ("START (testing) END ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+        "<testing/>");
+    EXPECT_EQ("START (testing) END ", handler.Str());
+  }
+}
+
+TEST(XmlParserTest, TestNamespace) {
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<top xmlns='my-namespace' a='b'/>");
+    EXPECT_EQ("START (my-namespace:top, xmlns='my-namespace', a='b') END ",
+        handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<foo:top xmlns:foo='my-namespace' "
+          "a='b' foo:c='d'/>");
+    EXPECT_EQ("START (my-namespace:top, "
+        "http://www.w3.org/2000/xmlns/:foo='my-namespace', "
+        "a='b', my-namespace:c='d') END ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<top><nested xmlns='my-namespace'><leaf/>"
+        "</nested><sibling/></top>");
+    EXPECT_EQ("START (top) START (my-namespace:nested, xmlns='my-namespace') "
+        "START (my-namespace:leaf) END END START (sibling) END END ",
+        handler.Str());
+  }
+}
+
+TEST(XmlParserTest, TestIncremental) {
+  XmlParserTestHandler handler;
+  XmlParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<stream:stream";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = " id=\"abcdefg\" xmlns=\"";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "j:c\" xmlns:stream='hm";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "ph'><test";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START (hmph:stream, id='abcdefg', xmlns='j:c', "
+      "http://www.w3.org/2000/xmlns/:stream='hmph') ", handler.StrClear());
+
+  fragment = "ing/><again/>abracad";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START (j:c:testing) END START (j:c:again) END TEXT (abracad) ",
+      handler.StrClear());
+
+  fragment = "abra</stream:";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("TEXT (abra) ", handler.StrClear());
+
+  fragment = "stream>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("END ", handler.StrClear());
+}
+
+TEST(XmlParserTest, TestReset) {
+  {
+    XmlParserTestHandler handler;
+    XmlParser parser(&handler);
+    std::string fragment;
+
+    fragment = "<top><first/><second><third></third>";
+    parser.Parse(fragment.c_str(), fragment.length(), false);
+    EXPECT_EQ("START (top) START (first) END START (second) START (third) END ",
+        handler.StrClear());
+
+    parser.Reset();
+    fragment = "<tip><first/><second><third></third>";
+    parser.Parse(fragment.c_str(), fragment.length(), false);
+    EXPECT_EQ("START (tip) START (first) END START (second) START (third) END ",
+        handler.StrClear());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser parser(&handler);
+    std::string fragment;
+
+    fragment = "<top xmlns='m'>";
+    parser.Parse(fragment.c_str(), fragment.length(), false);
+    EXPECT_EQ("START (m:top, xmlns='m') ", handler.StrClear());
+
+    fragment = "<testing/><frag";
+    parser.Parse(fragment.c_str(), fragment.length(), false);
+    EXPECT_EQ("START (m:testing) END ", handler.StrClear());
+
+    parser.Reset();
+    fragment = "<testing><fragment/";
+    parser.Parse(fragment.c_str(), fragment.length(), false);
+    EXPECT_EQ("START (testing) ", handler.StrClear());
+
+    fragment = ">";
+    parser.Parse(fragment.c_str(), fragment.length(), false);
+    EXPECT_EQ("START (fragment) END ", handler.StrClear());
+  }
+}
+
+TEST(XmlParserTest, TestError) {
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "junk");
+    EXPECT_EQ("ERROR (2) ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<top/> garbage ");
+    EXPECT_EQ("START (top) END ERROR (9) ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<-hm->");
+    EXPECT_EQ("ERROR (4) ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler, "<hello>&foobar;</hello>");
+    EXPECT_EQ("START (hello) ERROR (11) ", handler.Str());
+  }
+  {
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<!DOCTYPE HTML PUBLIC \"foobar\" \"barfoo\">");
+    EXPECT_EQ("ERROR (3) ", handler.Str());
+  }
+  {
+    // XmlParser requires utf-8
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><test/>");
+    EXPECT_EQ("ERROR (19) ", handler.Str());
+  }
+  {
+    // XmlParser requires version 1.0
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<?xml version=\"2.0\"?><test/>");
+    EXPECT_EQ("ERROR (2) ", handler.Str());
+  }
+  {
+    // XmlParser requires standalone documents
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<?xml version=\"1.0\" standalone=\"no\"?><test/>");
+    EXPECT_EQ("ERROR (2) ", handler.Str());
+  }
+  {
+    // XmlParser doesn't like empty namespace URIs
+    XmlParserTestHandler handler;
+    XmlParser::ParseXml(&handler,
+        "<test xmlns:foo='' foo:bar='huh?'>");
+    EXPECT_EQ("ERROR (2) ", handler.Str());
+  }
+}
diff --git a/third_party/libjingle_xmpp/xmllite/xmlprinter.cc b/third_party/libjingle_xmpp/xmllite/xmlprinter.cc
new file mode 100644
index 0000000..5245aa1
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlprinter.cc
@@ -0,0 +1,174 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
+
+namespace buzz {
+
+class XmlPrinterImpl {
+public:
+  XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack);
+  void PrintElement(const XmlElement* element);
+  void PrintQuotedValue(const std::string& text);
+  void PrintBodyText(const std::string& text);
+  void PrintCDATAText(const std::string& text);
+
+private:
+  std::ostream *pout_;
+  XmlnsStack* ns_stack_;
+};
+
+void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element) {
+  XmlnsStack ns_stack;
+  PrintXml(pout, element, &ns_stack);
+}
+
+void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element,
+                          XmlnsStack* ns_stack) {
+  XmlPrinterImpl printer(pout, ns_stack);
+  printer.PrintElement(element);
+}
+
+XmlPrinterImpl::XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack)
+    : pout_(pout),
+      ns_stack_(ns_stack) {
+}
+
+void XmlPrinterImpl::PrintElement(const XmlElement* element) {
+  ns_stack_->PushFrame();
+
+  // first go through attrs of pel to add xmlns definitions
+  const XmlAttr* attr;
+  for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
+    if (attr->Name() == QN_XMLNS) {
+      ns_stack_->AddXmlns(STR_EMPTY, attr->Value());
+    } else if (attr->Name().Namespace() == NS_XMLNS) {
+      ns_stack_->AddXmlns(attr->Name().LocalPart(),
+                          attr->Value());
+    }
+  }
+
+  // then go through qnames to make sure needed xmlns definitons are added
+  std::vector<std::string> new_ns;
+  std::pair<std::string, bool> prefix;
+  prefix = ns_stack_->AddNewPrefix(element->Name().Namespace(), false);
+  if (prefix.second) {
+    new_ns.push_back(prefix.first);
+    new_ns.push_back(element->Name().Namespace());
+  }
+
+  for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
+    prefix = ns_stack_->AddNewPrefix(attr->Name().Namespace(), true);
+    if (prefix.second) {
+      new_ns.push_back(prefix.first);
+      new_ns.push_back(attr->Name().Namespace());
+    }
+  }
+
+  // print the element name
+  *pout_ << '<' << ns_stack_->FormatQName(element->Name(), false);
+
+  // and the attributes
+  for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
+    *pout_ << ' ' << ns_stack_->FormatQName(attr->Name(), true) << "=\"";
+    PrintQuotedValue(attr->Value());
+    *pout_ << '"';
+  }
+
+  // and the extra xmlns declarations
+  std::vector<std::string>::iterator i(new_ns.begin());
+  while (i < new_ns.end()) {
+    if (*i == STR_EMPTY) {
+      *pout_ << " xmlns=\"" << *(i + 1) << '"';
+    } else {
+      *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"';
+    }
+    i += 2;
+  }
+
+  // now the children
+  const XmlChild* child = element->FirstChild();
+
+  if (child == NULL)
+    *pout_ << "/>";
+  else {
+    *pout_ << '>';
+    while (child) {
+      if (child->IsText()) {
+        if (element->IsCDATA()) {
+          PrintCDATAText(child->AsText()->Text());
+        } else {
+          PrintBodyText(child->AsText()->Text());
+        }
+      } else {
+        PrintElement(child->AsElement());
+      }
+      child = child->NextChild();
+    }
+    *pout_ << "</" << ns_stack_->FormatQName(element->Name(), false) << '>';
+  }
+
+  ns_stack_->PopFrame();
+}
+
+void XmlPrinterImpl::PrintQuotedValue(const std::string& text) {
+  size_t safe = 0;
+  for (;;) {
+    size_t unsafe = text.find_first_of("<>&\"", safe);
+    if (unsafe == std::string::npos)
+      unsafe = text.length();
+    *pout_ << text.substr(safe, unsafe - safe);
+    if (unsafe == text.length())
+      return;
+    switch (text[unsafe]) {
+      case '<': *pout_ << "&lt;"; break;
+      case '>': *pout_ << "&gt;"; break;
+      case '&': *pout_ << "&amp;"; break;
+      case '"': *pout_ << "&quot;"; break;
+    }
+    safe = unsafe + 1;
+    if (safe == text.length())
+      return;
+  }
+}
+
+void XmlPrinterImpl::PrintBodyText(const std::string& text) {
+  size_t safe = 0;
+  for (;;) {
+    size_t unsafe = text.find_first_of("<>&", safe);
+    if (unsafe == std::string::npos)
+      unsafe = text.length();
+    *pout_ << text.substr(safe, unsafe - safe);
+    if (unsafe == text.length())
+      return;
+    switch (text[unsafe]) {
+      case '<': *pout_ << "&lt;"; break;
+      case '>': *pout_ << "&gt;"; break;
+      case '&': *pout_ << "&amp;"; break;
+    }
+    safe = unsafe + 1;
+    if (safe == text.length())
+      return;
+  }
+}
+
+void XmlPrinterImpl::PrintCDATAText(const std::string& text) {
+  *pout_ << "<![CDATA[" << text << "]]>";
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmllite/xmlprinter.h b/third_party/libjingle_xmpp/xmllite/xmlprinter.h
new file mode 100644
index 0000000..40cf195
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlprinter.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
+#define WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
+
+#include <iosfwd>
+#include <string>
+
+namespace buzz {
+
+class XmlElement;
+class XmlnsStack;
+
+class XmlPrinter {
+ public:
+  static void PrintXml(std::ostream* pout, const XmlElement* pelt);
+
+  static void PrintXml(std::ostream* pout, const XmlElement* pelt,
+                       XmlnsStack* ns_stack);
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
new file mode 100644
index 0000000..f40491d0
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
+
+#include <sstream>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::QName;
+using buzz::XmlElement;
+using buzz::XmlnsStack;
+using buzz::XmlPrinter;
+
+TEST(XmlPrinterTest, TestBasicPrinting) {
+  XmlElement elt(QName("google:test", "first"));
+  std::stringstream ss;
+  XmlPrinter::PrintXml(&ss, &elt);
+  EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", ss.str());
+}
+
+TEST(XmlPrinterTest, TestNamespacedPrinting) {
+  XmlElement elt(QName("google:test", "first"));
+  elt.AddElement(new XmlElement(QName("nested:test", "second")));
+  std::stringstream ss;
+
+  XmlnsStack ns_stack;
+  ns_stack.AddXmlns("gg", "google:test");
+  ns_stack.AddXmlns("", "nested:test");
+
+  XmlPrinter::PrintXml(&ss, &elt, &ns_stack);
+  EXPECT_EQ("<gg:first><second/></gg:first>", ss.str());
+}
diff --git a/third_party/libjingle_xmpp/xmpp/DEPS b/third_party/libjingle_xmpp/xmpp/DEPS
new file mode 100644
index 0000000..30a60a4
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/DEPS
@@ -0,0 +1,10 @@
+include_rules = [
+  "+third_party/expat",
+  "+third_party/webrtc/base",
+  "+third_party/webrtc/p2p",
+]
+specific_include_rules = {
+  "xmpplogintask_unittest\.cc": [
+    "+third_party/webrtc/typedefs.h",
+  ],
+}
diff --git a/third_party/libjingle_xmpp/xmpp/asyncsocket.h b/third_party/libjingle_xmpp/xmpp/asyncsocket.h
new file mode 100644
index 0000000..b4f31e5
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/asyncsocket.h
@@ -0,0 +1,72 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
+#define WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
+
+#include <string>
+
+#include "third_party/webrtc/base/sigslot.h"
+
+namespace rtc {
+  class SocketAddress;
+}
+
+namespace buzz {
+
+class AsyncSocket {
+public:
+  enum State {
+    STATE_CLOSED = 0,      //!< Socket is not open.
+    STATE_CLOSING,         //!< Socket is closing but can have buffered data
+    STATE_CONNECTING,      //!< In the process of
+    STATE_OPEN,            //!< Socket is connected
+#if defined(FEATURE_ENABLE_SSL)
+    STATE_TLS_CONNECTING,  //!< Establishing TLS connection
+    STATE_TLS_OPEN,        //!< TLS connected
+#endif
+  };
+
+  enum Error {
+    ERROR_NONE = 0,         //!< No error
+    ERROR_WINSOCK,          //!< Winsock error
+    ERROR_DNS,              //!< Couldn't resolve host name
+    ERROR_WRONGSTATE,       //!< Call made while socket is in the wrong state
+#if defined(FEATURE_ENABLE_SSL)
+    ERROR_SSL,              //!< Something went wrong with OpenSSL
+#endif
+  };
+
+  virtual ~AsyncSocket() {}
+  virtual State state() = 0;
+  virtual Error error() = 0;
+  virtual int GetError() = 0;    // winsock error code
+
+  virtual bool Connect(const rtc::SocketAddress& addr) = 0;
+  virtual bool Read(char * data, size_t len, size_t* len_read) = 0;
+  virtual bool Write(const char * data, size_t len) = 0;
+  virtual bool Close() = 0;
+#if defined(FEATURE_ENABLE_SSL)
+  // We allow matching any passed domain.  This allows us to avoid
+  // handling the valuable certificates for logins into proxies.  If
+  // both names are passed as empty, we do not require a match.
+  virtual bool StartTls(const std::string & domainname) = 0;
+#endif
+
+  sigslot::signal0<> SignalConnected;
+  sigslot::signal0<> SignalSSLConnected;
+  sigslot::signal0<> SignalClosed;
+  sigslot::signal0<> SignalRead;
+  sigslot::signal0<> SignalError;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
diff --git a/third_party/libjingle_xmpp/xmpp/constants.cc b/third_party/libjingle_xmpp/xmpp/constants.cc
new file mode 100644
index 0000000..2d4c039
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/constants.cc
@@ -0,0 +1,613 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+
+namespace buzz {
+
+// TODO: Remove static objects of complex types, particularly
+// Jid and QName.
+
+const char NS_CLIENT[] = "jabber:client";
+const char NS_SERVER[] = "jabber:server";
+const char NS_STREAM[] = "http://etherx.jabber.org/streams";
+const char NS_XSTREAM[] = "urn:ietf:params:xml:ns:xmpp-streams";
+const char NS_TLS[] = "urn:ietf:params:xml:ns:xmpp-tls";
+const char NS_SASL[] = "urn:ietf:params:xml:ns:xmpp-sasl";
+const char NS_BIND[] = "urn:ietf:params:xml:ns:xmpp-bind";
+const char NS_DIALBACK[] = "jabber:server:dialback";
+const char NS_SESSION[] = "urn:ietf:params:xml:ns:xmpp-session";
+const char NS_STANZA[] = "urn:ietf:params:xml:ns:xmpp-stanzas";
+const char NS_PRIVACY[] = "jabber:iq:privacy";
+const char NS_ROSTER[] = "jabber:iq:roster";
+const char NS_VCARD[] = "vcard-temp";
+const char NS_AVATAR_HASH[] = "google:avatar";
+const char NS_VCARD_UPDATE[] = "vcard-temp:x:update";
+const char STR_CLIENT[] = "client";
+const char STR_SERVER[] = "server";
+const char STR_STREAM[] = "stream";
+
+const char STR_GET[] = "get";
+const char STR_SET[] = "set";
+const char STR_RESULT[] = "result";
+const char STR_ERROR[] = "error";
+
+const char STR_FORM[] = "form";
+const char STR_SUBMIT[] = "submit";
+const char STR_TEXT_SINGLE[] = "text-single";
+const char STR_LIST_SINGLE[] = "list-single";
+const char STR_LIST_MULTI[] = "list-multi";
+const char STR_HIDDEN[] = "hidden";
+const char STR_FORM_TYPE[] = "FORM_TYPE";
+
+const char STR_FROM[] = "from";
+const char STR_TO[] = "to";
+const char STR_BOTH[] = "both";
+const char STR_REMOVE[] = "remove";
+const char STR_TRUE[] = "true";
+
+const char STR_TYPE[] = "type";
+const char STR_NAME[] = "name";
+const char STR_ID[] = "id";
+const char STR_JID[] = "jid";
+const char STR_SUBSCRIPTION[] = "subscription";
+const char STR_ASK[] = "ask";
+const char STR_X[] = "x";
+const char STR_GOOGLE_COM[] = "google.com";
+const char STR_GMAIL_COM[] = "gmail.com";
+const char STR_GOOGLEMAIL_COM[] = "googlemail.com";
+const char STR_DEFAULT_DOMAIN[] = "default.talk.google.com";
+const char STR_TALK_GOOGLE_COM[] = "talk.google.com";
+const char STR_TALKX_L_GOOGLE_COM[] = "talkx.l.google.com";
+const char STR_XMPP_GOOGLE_COM[] = "xmpp.google.com";
+const char STR_XMPPX_L_GOOGLE_COM[] = "xmppx.l.google.com";
+
+#ifdef FEATURE_ENABLE_VOICEMAIL
+const char STR_VOICEMAIL[] = "voicemail";
+const char STR_OUTGOINGVOICEMAIL[] = "outgoingvoicemail";
+#endif
+
+const char STR_UNAVAILABLE[] = "unavailable";
+
+const char NS_PING[] = "urn:xmpp:ping";
+const StaticQName QN_PING = { NS_PING, "ping" };
+
+const char NS_MUC_UNIQUE[] = "http://jabber.org/protocol/muc#unique";
+const StaticQName QN_MUC_UNIQUE_QUERY = { NS_MUC_UNIQUE, "unique" };
+const StaticQName QN_HANGOUT_ID = { STR_EMPTY, "hangout-id" };
+
+const char STR_GOOGLE_MUC_LOOKUP_JID[] = "lookup.groupchat.google.com";
+
+const char STR_MUC_ROOMCONFIG_ROOMNAME[] = "muc#roomconfig_roomname";
+const char STR_MUC_ROOMCONFIG_FEATURES[] = "muc#roomconfig_features";
+const char STR_MUC_ROOM_FEATURE_ENTERPRISE[] = "muc_enterprise";
+const char STR_MUC_ROOMCONFIG[] = "http://jabber.org/protocol/muc#roomconfig";
+const char STR_MUC_ROOM_FEATURE_HANGOUT[] = "muc_es";
+const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[] = "muc_lite";
+const char STR_MUC_ROOM_FEATURE_BROADCAST[] = "broadcast";
+const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[] = "muc_muvc";
+const char STR_MUC_ROOM_FEATURE_RECORDABLE[] = "recordable";
+const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[] = "custom_recording";
+const char STR_MUC_ROOM_OWNER_PROFILE_ID[] = "muc#roominfo_owner_profile_id";
+const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[] = "abuse_recordable";
+
+const char STR_ID_TYPE_CONVERSATION[] = "conversation";
+const char NS_GOOGLE_MUC_HANGOUT[] = "google:muc#hangout";
+const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE =
+    { NS_GOOGLE_MUC_HANGOUT, "invite" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE =
+    { NS_GOOGLE_MUC_HANGOUT, "invite-type" };
+const StaticQName QN_ATTR_CREATE_ACTIVITY =
+    { STR_EMPTY, "create-activity" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC =
+    { NS_GOOGLE_MUC_HANGOUT, "public" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE =
+    { NS_GOOGLE_MUC_HANGOUT, "invitee" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS =
+    { NS_GOOGLE_MUC_HANGOUT, "notification-status" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE = {
+    NS_GOOGLE_MUC_HANGOUT, "notification-type" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT = {
+    NS_GOOGLE_MUC_HANGOUT, "hangout-start-context" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID = {
+    NS_GOOGLE_MUC_HANGOUT, "conversation-id" };
+
+const StaticQName QN_STREAM_STREAM = { NS_STREAM, STR_STREAM };
+const StaticQName QN_STREAM_FEATURES = { NS_STREAM, "features" };
+const StaticQName QN_STREAM_ERROR = { NS_STREAM, "error" };
+
+const StaticQName QN_XSTREAM_BAD_FORMAT = { NS_XSTREAM, "bad-format" };
+const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX =
+    { NS_XSTREAM, "bad-namespace-prefix" };
+const StaticQName QN_XSTREAM_CONFLICT = { NS_XSTREAM, "conflict" };
+const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT =
+    { NS_XSTREAM, "connection-timeout" };
+const StaticQName QN_XSTREAM_HOST_GONE = { NS_XSTREAM, "host-gone" };
+const StaticQName QN_XSTREAM_HOST_UNKNOWN = { NS_XSTREAM, "host-unknown" };
+const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING =
+     { NS_XSTREAM, "improper-addressing" };
+const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR =
+    { NS_XSTREAM, "internal-server-error" };
+const StaticQName QN_XSTREAM_INVALID_FROM = { NS_XSTREAM, "invalid-from" };
+const StaticQName QN_XSTREAM_INVALID_ID = { NS_XSTREAM, "invalid-id" };
+const StaticQName QN_XSTREAM_INVALID_NAMESPACE =
+    { NS_XSTREAM, "invalid-namespace" };
+const StaticQName QN_XSTREAM_INVALID_XML = { NS_XSTREAM, "invalid-xml" };
+const StaticQName QN_XSTREAM_NOT_AUTHORIZED = { NS_XSTREAM, "not-authorized" };
+const StaticQName QN_XSTREAM_POLICY_VIOLATION =
+    { NS_XSTREAM, "policy-violation" };
+const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED =
+    { NS_XSTREAM, "remote-connection-failed" };
+const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT =
+    { NS_XSTREAM, "resource-constraint" };
+const StaticQName QN_XSTREAM_RESTRICTED_XML = { NS_XSTREAM, "restricted-xml" };
+const StaticQName QN_XSTREAM_SEE_OTHER_HOST = { NS_XSTREAM, "see-other-host" };
+const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN =
+    { NS_XSTREAM, "system-shutdown" };
+const StaticQName QN_XSTREAM_UNDEFINED_CONDITION =
+    { NS_XSTREAM, "undefined-condition" };
+const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING =
+    { NS_XSTREAM, "unsupported-encoding" };
+const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE =
+    { NS_XSTREAM, "unsupported-stanza-type" };
+const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION =
+    { NS_XSTREAM, "unsupported-version" };
+const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED =
+    { NS_XSTREAM, "xml-not-well-formed" };
+const StaticQName QN_XSTREAM_TEXT = { NS_XSTREAM, "text" };
+
+const StaticQName QN_TLS_STARTTLS = { NS_TLS, "starttls" };
+const StaticQName QN_TLS_REQUIRED = { NS_TLS, "required" };
+const StaticQName QN_TLS_PROCEED = { NS_TLS, "proceed" };
+const StaticQName QN_TLS_FAILURE = { NS_TLS, "failure" };
+
+const StaticQName QN_SASL_MECHANISMS = { NS_SASL, "mechanisms" };
+const StaticQName QN_SASL_MECHANISM = { NS_SASL, "mechanism" };
+const StaticQName QN_SASL_AUTH = { NS_SASL, "auth" };
+const StaticQName QN_SASL_CHALLENGE = { NS_SASL, "challenge" };
+const StaticQName QN_SASL_RESPONSE = { NS_SASL, "response" };
+const StaticQName QN_SASL_ABORT = { NS_SASL, "abort" };
+const StaticQName QN_SASL_SUCCESS = { NS_SASL, "success" };
+const StaticQName QN_SASL_FAILURE = { NS_SASL, "failure" };
+const StaticQName QN_SASL_ABORTED = { NS_SASL, "aborted" };
+const StaticQName QN_SASL_INCORRECT_ENCODING =
+    { NS_SASL, "incorrect-encoding" };
+const StaticQName QN_SASL_INVALID_AUTHZID = { NS_SASL, "invalid-authzid" };
+const StaticQName QN_SASL_INVALID_MECHANISM = { NS_SASL, "invalid-mechanism" };
+const StaticQName QN_SASL_MECHANISM_TOO_WEAK =
+    { NS_SASL, "mechanism-too-weak" };
+const StaticQName QN_SASL_NOT_AUTHORIZED = { NS_SASL, "not-authorized" };
+const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE =
+    { NS_SASL, "temporary-auth-failure" };
+
+// These are non-standard.
+const char NS_GOOGLE_AUTH_PROTOCOL[] =
+    "http://www.google.com/talk/protocol/auth";
+const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT =
+    { NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result" };
+const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN =
+    { NS_GOOGLE_AUTH_PROTOCOL, "allow-non-google-login" };
+const StaticQName QN_GOOGLE_AUTH_SERVICE =
+    { NS_GOOGLE_AUTH_PROTOCOL, "service" };
+
+const StaticQName QN_DIALBACK_RESULT = { NS_DIALBACK, "result" };
+const StaticQName QN_DIALBACK_VERIFY = { NS_DIALBACK, "verify" };
+
+const StaticQName QN_STANZA_BAD_REQUEST = { NS_STANZA, "bad-request" };
+const StaticQName QN_STANZA_CONFLICT = { NS_STANZA, "conflict" };
+const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED =
+    { NS_STANZA, "feature-not-implemented" };
+const StaticQName QN_STANZA_FORBIDDEN = { NS_STANZA, "forbidden" };
+const StaticQName QN_STANZA_GONE = { NS_STANZA, "gone" };
+const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR =
+    { NS_STANZA, "internal-server-error" };
+const StaticQName QN_STANZA_ITEM_NOT_FOUND = { NS_STANZA, "item-not-found" };
+const StaticQName QN_STANZA_JID_MALFORMED = { NS_STANZA, "jid-malformed" };
+const StaticQName QN_STANZA_NOT_ACCEPTABLE = { NS_STANZA, "not-acceptable" };
+const StaticQName QN_STANZA_NOT_ALLOWED = { NS_STANZA, "not-allowed" };
+const StaticQName QN_STANZA_PAYMENT_REQUIRED =
+    { NS_STANZA, "payment-required" };
+const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE =
+    { NS_STANZA, "recipient-unavailable" };
+const StaticQName QN_STANZA_REDIRECT = { NS_STANZA, "redirect" };
+const StaticQName QN_STANZA_REGISTRATION_REQUIRED =
+    { NS_STANZA, "registration-required" };
+const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND =
+    { NS_STANZA, "remote-server-not-found" };
+const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT =
+    { NS_STANZA, "remote-server-timeout" };
+const StaticQName QN_STANZA_RESOURCE_CONSTRAINT =
+    { NS_STANZA, "resource-constraint" };
+const StaticQName QN_STANZA_SERVICE_UNAVAILABLE =
+    { NS_STANZA, "service-unavailable" };
+const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED =
+    { NS_STANZA, "subscription-required" };
+const StaticQName QN_STANZA_UNDEFINED_CONDITION =
+    { NS_STANZA, "undefined-condition" };
+const StaticQName QN_STANZA_UNEXPECTED_REQUEST =
+    { NS_STANZA, "unexpected-request" };
+const StaticQName QN_STANZA_TEXT = { NS_STANZA, "text" };
+
+const StaticQName QN_BIND_BIND = { NS_BIND, "bind" };
+const StaticQName QN_BIND_RESOURCE = { NS_BIND, "resource" };
+const StaticQName QN_BIND_JID = { NS_BIND, "jid" };
+
+const StaticQName QN_MESSAGE = { NS_CLIENT, "message" };
+const StaticQName QN_BODY = { NS_CLIENT, "body" };
+const StaticQName QN_SUBJECT = { NS_CLIENT, "subject" };
+const StaticQName QN_THREAD = { NS_CLIENT, "thread" };
+const StaticQName QN_PRESENCE = { NS_CLIENT, "presence" };
+const StaticQName QN_SHOW = { NS_CLIENT, "show" };
+const StaticQName QN_STATUS = { NS_CLIENT, "status" };
+const StaticQName QN_LANG = { NS_CLIENT, "lang" };
+const StaticQName QN_PRIORITY = { NS_CLIENT, "priority" };
+const StaticQName QN_IQ = { NS_CLIENT, "iq" };
+const StaticQName QN_ERROR = { NS_CLIENT, "error" };
+
+const StaticQName QN_SERVER_MESSAGE = { NS_SERVER, "message" };
+const StaticQName QN_SERVER_BODY = { NS_SERVER, "body" };
+const StaticQName QN_SERVER_SUBJECT = { NS_SERVER, "subject" };
+const StaticQName QN_SERVER_THREAD = { NS_SERVER, "thread" };
+const StaticQName QN_SERVER_PRESENCE = { NS_SERVER, "presence" };
+const StaticQName QN_SERVER_SHOW = { NS_SERVER, "show" };
+const StaticQName QN_SERVER_STATUS = { NS_SERVER, "status" };
+const StaticQName QN_SERVER_LANG = { NS_SERVER, "lang" };
+const StaticQName QN_SERVER_PRIORITY = { NS_SERVER, "priority" };
+const StaticQName QN_SERVER_IQ = { NS_SERVER, "iq" };
+const StaticQName QN_SERVER_ERROR = { NS_SERVER, "error" };
+
+const StaticQName QN_SESSION_SESSION = { NS_SESSION, "session" };
+
+const StaticQName QN_PRIVACY_QUERY = { NS_PRIVACY, "query" };
+const StaticQName QN_PRIVACY_ACTIVE = { NS_PRIVACY, "active" };
+const StaticQName QN_PRIVACY_DEFAULT = { NS_PRIVACY, "default" };
+const StaticQName QN_PRIVACY_LIST = { NS_PRIVACY, "list" };
+const StaticQName QN_PRIVACY_ITEM = { NS_PRIVACY, "item" };
+const StaticQName QN_PRIVACY_IQ = { NS_PRIVACY, "iq" };
+const StaticQName QN_PRIVACY_MESSAGE = { NS_PRIVACY, "message" };
+const StaticQName QN_PRIVACY_PRESENCE_IN = { NS_PRIVACY, "presence-in" };
+const StaticQName QN_PRIVACY_PRESENCE_OUT = { NS_PRIVACY, "presence-out" };
+
+const StaticQName QN_ROSTER_QUERY = { NS_ROSTER, "query" };
+const StaticQName QN_ROSTER_ITEM = { NS_ROSTER, "item" };
+const StaticQName QN_ROSTER_GROUP = { NS_ROSTER, "group" };
+
+const StaticQName QN_VCARD = { NS_VCARD, "vCard" };
+const StaticQName QN_VCARD_FN = { NS_VCARD, "FN" };
+const StaticQName QN_VCARD_PHOTO = { NS_VCARD, "PHOTO" };
+const StaticQName QN_VCARD_PHOTO_BINVAL = { NS_VCARD, "BINVAL" };
+const StaticQName QN_VCARD_AVATAR_HASH = { NS_AVATAR_HASH, "hash" };
+const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED =
+    { NS_AVATAR_HASH, "modified" };
+
+const StaticQName QN_NAME = { STR_EMPTY, "name" };
+const StaticQName QN_AFFILIATION = { STR_EMPTY, "affiliation" };
+const StaticQName QN_ROLE = { STR_EMPTY, "role" };
+
+#if defined(FEATURE_ENABLE_PSTN)
+const StaticQName QN_VCARD_TEL = { NS_VCARD, "TEL" };
+const StaticQName QN_VCARD_VOICE = { NS_VCARD, "VOICE" };
+const StaticQName QN_VCARD_HOME = { NS_VCARD, "HOME" };
+const StaticQName QN_VCARD_WORK = { NS_VCARD, "WORK" };
+const StaticQName QN_VCARD_CELL = { NS_VCARD, "CELL" };
+const StaticQName QN_VCARD_NUMBER = { NS_VCARD, "NUMBER" };
+#endif
+
+const StaticQName QN_XML_LANG = { NS_XML, "lang" };
+
+const StaticQName QN_ENCODING = { STR_EMPTY, STR_ENCODING };
+const StaticQName QN_VERSION = { STR_EMPTY, STR_VERSION };
+const StaticQName QN_TO = { STR_EMPTY, "to" };
+const StaticQName QN_FROM = { STR_EMPTY, "from" };
+const StaticQName QN_TYPE = { STR_EMPTY, "type" };
+const StaticQName QN_ID = { STR_EMPTY, "id" };
+const StaticQName QN_CODE = { STR_EMPTY, "code" };
+
+const StaticQName QN_VALUE = { STR_EMPTY, "value" };
+const StaticQName QN_ACTION = { STR_EMPTY, "action" };
+const StaticQName QN_ORDER = { STR_EMPTY, "order" };
+const StaticQName QN_MECHANISM = { STR_EMPTY, "mechanism" };
+const StaticQName QN_ASK = { STR_EMPTY, "ask" };
+const StaticQName QN_JID = { STR_EMPTY, "jid" };
+const StaticQName QN_NICK = { STR_EMPTY, "nick" };
+const StaticQName QN_SUBSCRIPTION = { STR_EMPTY, "subscription" };
+const StaticQName QN_TITLE1 = { STR_EMPTY, "title1" };
+const StaticQName QN_TITLE2 = { STR_EMPTY, "title2" };
+
+const StaticQName QN_XMLNS_CLIENT = { NS_XMLNS, STR_CLIENT };
+const StaticQName QN_XMLNS_SERVER = { NS_XMLNS, STR_SERVER };
+const StaticQName QN_XMLNS_STREAM = { NS_XMLNS, STR_STREAM };
+
+
+// Presence
+const char STR_SHOW_AWAY[] = "away";
+const char STR_SHOW_CHAT[] = "chat";
+const char STR_SHOW_DND[] = "dnd";
+const char STR_SHOW_XA[] = "xa";
+const char STR_SHOW_OFFLINE[] = "offline";
+
+const char NS_GOOGLE_PSTN_CONFERENCE[] = "http://www.google.com/pstn-conference";
+const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS = { NS_GOOGLE_PSTN_CONFERENCE, "status" };
+const StaticQName QN_ATTR_STATUS = { STR_EMPTY, "status" };
+
+// Presence connection status
+const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[] = "connecting";
+const char STR_PSTN_CONFERENCE_STATUS_JOINING[] = "joining";
+const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[] = "connected";
+const char STR_PSTN_CONFERENCE_STATUS_HANGUP[] = "hangup";
+
+// Subscription
+const char STR_SUBSCRIBE[] = "subscribe";
+const char STR_SUBSCRIBED[] = "subscribed";
+const char STR_UNSUBSCRIBE[] = "unsubscribe";
+const char STR_UNSUBSCRIBED[] = "unsubscribed";
+
+// Google Invite
+const char NS_GOOGLE_SUBSCRIBE[] = "google:subscribe";
+const StaticQName QN_INVITATION = { NS_GOOGLE_SUBSCRIBE, "invitation" };
+const StaticQName QN_INVITE_NAME = { NS_GOOGLE_SUBSCRIBE, "name" };
+const StaticQName QN_INVITE_SUBJECT = { NS_GOOGLE_SUBSCRIBE, "subject" };
+const StaticQName QN_INVITE_MESSAGE = { NS_GOOGLE_SUBSCRIBE, "body" };
+
+// Kick
+const char NS_GOOGLE_MUC_ADMIN[] = "google:muc#admin";
+const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY = { NS_GOOGLE_MUC_ADMIN, "query" };
+const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM =
+    { NS_GOOGLE_MUC_ADMIN, "item" };
+const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON =
+    { NS_GOOGLE_MUC_ADMIN, "reason" };
+
+// PubSub: http://xmpp.org/extensions/xep-0060.html
+const char NS_PUBSUB[] = "http://jabber.org/protocol/pubsub";
+const StaticQName QN_PUBSUB = { NS_PUBSUB, "pubsub" };
+const StaticQName QN_PUBSUB_ITEMS = { NS_PUBSUB, "items" };
+const StaticQName QN_PUBSUB_ITEM = { NS_PUBSUB, "item" };
+const StaticQName QN_PUBSUB_PUBLISH = { NS_PUBSUB, "publish" };
+const StaticQName QN_PUBSUB_RETRACT = { NS_PUBSUB, "retract" };
+const StaticQName QN_ATTR_PUBLISHER = { STR_EMPTY, "publisher" };
+
+const char NS_PUBSUB_EVENT[] = "http://jabber.org/protocol/pubsub#event";
+const StaticQName QN_NODE = { STR_EMPTY, "node" };
+const StaticQName QN_PUBSUB_EVENT = { NS_PUBSUB_EVENT, "event" };
+const StaticQName QN_PUBSUB_EVENT_ITEMS = { NS_PUBSUB_EVENT, "items" };
+const StaticQName QN_PUBSUB_EVENT_ITEM = { NS_PUBSUB_EVENT, "item" };
+const StaticQName QN_PUBSUB_EVENT_RETRACT = { NS_PUBSUB_EVENT, "retract" };
+const StaticQName QN_NOTIFY = { STR_EMPTY, "notify" };
+
+const char NS_PRESENTER[] = "google:presenter";
+const StaticQName QN_PRESENTER_PRESENTER = { NS_PRESENTER, "presenter" };
+const StaticQName QN_PRESENTER_PRESENTATION_ITEM =
+    { NS_PRESENTER, "presentation-item" };
+const StaticQName QN_PRESENTER_PRESENTATION_TYPE =
+    { NS_PRESENTER, "presentation-type" };
+const StaticQName QN_PRESENTER_PRESENTATION_ID =
+    { NS_PRESENTER, "presentation-id" };
+
+// JEP 0030
+const StaticQName QN_CATEGORY = { STR_EMPTY, "category" };
+const StaticQName QN_VAR = { STR_EMPTY, "var" };
+const char NS_DISCO_INFO[] = "http://jabber.org/protocol/disco#info";
+const char NS_DISCO_ITEMS[] = "http://jabber.org/protocol/disco#items";
+const StaticQName QN_DISCO_INFO_QUERY = { NS_DISCO_INFO, "query" };
+const StaticQName QN_DISCO_IDENTITY = { NS_DISCO_INFO, "identity" };
+const StaticQName QN_DISCO_FEATURE = { NS_DISCO_INFO, "feature" };
+
+const StaticQName QN_DISCO_ITEMS_QUERY = { NS_DISCO_ITEMS, "query" };
+const StaticQName QN_DISCO_ITEM = { NS_DISCO_ITEMS, "item" };
+
+// JEP 0020
+const char NS_FEATURE[] = "http://jabber.org/protocol/feature-neg";
+const StaticQName QN_FEATURE_FEATURE = { NS_FEATURE, "feature" };
+
+// JEP 0004
+const char NS_XDATA[] = "jabber:x:data";
+const StaticQName QN_XDATA_X = { NS_XDATA, "x" };
+const StaticQName QN_XDATA_INSTRUCTIONS = { NS_XDATA, "instructions" };
+const StaticQName QN_XDATA_TITLE = { NS_XDATA, "title" };
+const StaticQName QN_XDATA_FIELD = { NS_XDATA, "field" };
+const StaticQName QN_XDATA_REPORTED = { NS_XDATA, "reported" };
+const StaticQName QN_XDATA_ITEM = { NS_XDATA, "item" };
+const StaticQName QN_XDATA_DESC = { NS_XDATA, "desc" };
+const StaticQName QN_XDATA_REQUIRED = { NS_XDATA, "required" };
+const StaticQName QN_XDATA_VALUE = { NS_XDATA, "value" };
+const StaticQName QN_XDATA_OPTION = { NS_XDATA, "option" };
+
+// JEP 0045
+const char NS_MUC[] = "http://jabber.org/protocol/muc";
+const StaticQName QN_MUC_X = { NS_MUC, "x" };
+const StaticQName QN_MUC_ITEM = { NS_MUC, "item" };
+const StaticQName QN_MUC_AFFILIATION = { NS_MUC, "affiliation" };
+const StaticQName QN_MUC_ROLE = { NS_MUC, "role" };
+const char STR_AFFILIATION_NONE[] = "none";
+const char STR_ROLE_PARTICIPANT[] = "participant";
+
+const char NS_GOOGLE_SESSION[] = "http://www.google.com/session";
+const StaticQName QN_GOOGLE_CIRCLE_ID = { STR_EMPTY, "google-circle-id" };
+const StaticQName QN_GOOGLE_USER_ID = { STR_EMPTY, "google-user-id" };
+const StaticQName QN_GOOGLE_SESSION_BLOCKED = { NS_GOOGLE_SESSION, "blocked" };
+const StaticQName QN_GOOGLE_SESSION_BLOCKING =
+    { NS_GOOGLE_SESSION, "blocking" };
+
+const char NS_MUC_OWNER[] = "http://jabber.org/protocol/muc#owner";
+const StaticQName QN_MUC_OWNER_QUERY = { NS_MUC_OWNER, "query" };
+
+const char NS_MUC_USER[] = "http://jabber.org/protocol/muc#user";
+const StaticQName QN_MUC_USER_CONTINUE = { NS_MUC_USER, "continue" };
+const StaticQName QN_MUC_USER_X = { NS_MUC_USER, "x" };
+const StaticQName QN_MUC_USER_ITEM = { NS_MUC_USER, "item" };
+const StaticQName QN_MUC_USER_STATUS = { NS_MUC_USER, "status" };
+const StaticQName QN_MUC_USER_REASON = { NS_MUC_USER, "reason" };
+const StaticQName QN_MUC_USER_ABUSE_VIOLATION = { NS_MUC_USER, "abuse-violation" };
+
+// JEP 0055 - Jabber Search
+const char NS_SEARCH[] = "jabber:iq:search";
+const StaticQName QN_SEARCH_QUERY = { NS_SEARCH, "query" };
+const StaticQName QN_SEARCH_ITEM = { NS_SEARCH, "item" };
+const StaticQName QN_SEARCH_ROOM_NAME = { NS_SEARCH, "room-name" };
+const StaticQName QN_SEARCH_ROOM_DOMAIN = { NS_SEARCH, "room-domain" };
+const StaticQName QN_SEARCH_ROOM_JID = { NS_SEARCH, "room-jid" };
+const StaticQName QN_SEARCH_HANGOUT_ID = { NS_SEARCH, "hangout-id" };
+const StaticQName QN_SEARCH_EXTERNAL_ID = { NS_SEARCH, "external-id" };
+
+// JEP 0115
+const char NS_CAPS[] = "http://jabber.org/protocol/caps";
+const StaticQName QN_CAPS_C = { NS_CAPS, "c" };
+const StaticQName QN_VER = { STR_EMPTY, "ver" };
+const StaticQName QN_EXT = { STR_EMPTY, "ext" };
+
+// JEP 0153
+const char kNSVCard[] = "vcard-temp:x:update";
+const StaticQName kQnVCardX = { kNSVCard, "x" };
+const StaticQName kQnVCardPhoto = { kNSVCard, "photo" };
+
+// JEP 0172 User Nickname
+const char NS_NICKNAME[] = "http://jabber.org/protocol/nick";
+const StaticQName QN_NICKNAME = { NS_NICKNAME, "nick" };
+
+// JEP 0085 chat state
+const char NS_CHATSTATE[] = "http://jabber.org/protocol/chatstates";
+const StaticQName QN_CS_ACTIVE = { NS_CHATSTATE, "active" };
+const StaticQName QN_CS_COMPOSING = { NS_CHATSTATE, "composing" };
+const StaticQName QN_CS_PAUSED = { NS_CHATSTATE, "paused" };
+const StaticQName QN_CS_INACTIVE = { NS_CHATSTATE, "inactive" };
+const StaticQName QN_CS_GONE = { NS_CHATSTATE, "gone" };
+
+// JEP 0091 Delayed Delivery
+const char kNSDelay[] = "jabber:x:delay";
+const StaticQName kQnDelayX = { kNSDelay, "x" };
+const StaticQName kQnStamp = { STR_EMPTY, "stamp" };
+
+// Google time stamping (higher resolution)
+const char kNSTimestamp[] = "google:timestamp";
+const StaticQName kQnTime = { kNSTimestamp, "time" };
+const StaticQName kQnMilliseconds = { STR_EMPTY, "ms" };
+
+// Jingle Info
+const char NS_JINGLE_INFO[] = "google:jingleinfo";
+const StaticQName QN_JINGLE_INFO_QUERY = { NS_JINGLE_INFO, "query" };
+const StaticQName QN_JINGLE_INFO_STUN = { NS_JINGLE_INFO, "stun" };
+const StaticQName QN_JINGLE_INFO_RELAY = { NS_JINGLE_INFO, "relay" };
+const StaticQName QN_JINGLE_INFO_SERVER = { NS_JINGLE_INFO, "server" };
+const StaticQName QN_JINGLE_INFO_TOKEN = { NS_JINGLE_INFO, "token" };
+const StaticQName QN_JINGLE_INFO_HOST = { STR_EMPTY, "host" };
+const StaticQName QN_JINGLE_INFO_TCP = { STR_EMPTY, "tcp" };
+const StaticQName QN_JINGLE_INFO_UDP = { STR_EMPTY, "udp" };
+const StaticQName QN_JINGLE_INFO_TCPSSL = { STR_EMPTY, "tcpssl" };
+
+// Call Performance Logging
+const char NS_GOOGLE_CALLPERF_STATS[] = "google:call-perf-stats";
+const StaticQName QN_CALLPERF_STATS =
+    { NS_GOOGLE_CALLPERF_STATS, "callPerfStats" };
+const StaticQName QN_CALLPERF_SESSIONID = { STR_EMPTY, "sessionId" };
+const StaticQName QN_CALLPERF_LOCALUSER = { STR_EMPTY, "localUser" };
+const StaticQName QN_CALLPERF_REMOTEUSER = { STR_EMPTY, "remoteUser" };
+const StaticQName QN_CALLPERF_STARTTIME = { STR_EMPTY, "startTime" };
+const StaticQName QN_CALLPERF_CALL_LENGTH = { STR_EMPTY, "callLength" };
+const StaticQName QN_CALLPERF_CALL_ACCEPTED = { STR_EMPTY, "callAccepted" };
+const StaticQName QN_CALLPERF_CALL_ERROR_CODE = { STR_EMPTY, "callErrorCode" };
+const StaticQName QN_CALLPERF_TERMINATE_CODE = { STR_EMPTY, "terminateCode" };
+const StaticQName QN_CALLPERF_DATAPOINT =
+    { NS_GOOGLE_CALLPERF_STATS, "dataPoint" };
+const StaticQName QN_CALLPERF_DATAPOINT_TIME = { STR_EMPTY, "timeStamp" };
+const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST =
+    { STR_EMPTY, "fraction_lost" };
+const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST = { STR_EMPTY, "cum_lost" };
+const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX = { STR_EMPTY, "ext_max" };
+const StaticQName QN_CALLPERF_DATAPOINT_JITTER = { STR_EMPTY, "jitter" };
+const StaticQName QN_CALLPERF_DATAPOINT_RTT = { STR_EMPTY, "RTT" };
+const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R =
+    { STR_EMPTY, "bytesReceived" };
+const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R =
+    { STR_EMPTY, "packetsReceived" };
+const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S = { STR_EMPTY, "bytesSent" };
+const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S =
+    { STR_EMPTY, "packetsSent" };
+const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU =
+    { STR_EMPTY, "processCpu" };
+const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU = { STR_EMPTY, "systemCpu" };
+const StaticQName QN_CALLPERF_DATAPOINT_CPUS = { STR_EMPTY, "cpus" };
+const StaticQName QN_CALLPERF_CONNECTION =
+    { NS_GOOGLE_CALLPERF_STATS, "connection" };
+const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS =
+    { STR_EMPTY, "localAddress" };
+const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS =
+    { STR_EMPTY, "remoteAddress" };
+const StaticQName QN_CALLPERF_CONNECTION_FLAGS = { STR_EMPTY, "flags" };
+const StaticQName QN_CALLPERF_CONNECTION_RTT = { STR_EMPTY, "rtt" };
+const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S =
+    { STR_EMPTY, "totalBytesSent" };
+const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S =
+    { STR_EMPTY, "bytesSecondSent" };
+const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R =
+    { STR_EMPTY, "totalBytesRecv" };
+const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R =
+    { STR_EMPTY, "bytesSecondRecv" };
+const StaticQName QN_CALLPERF_CANDIDATE =
+    { NS_GOOGLE_CALLPERF_STATS, "candidate" };
+const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT = { STR_EMPTY, "endpoint" };
+const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL = { STR_EMPTY, "protocol" };
+const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS = { STR_EMPTY, "address" };
+const StaticQName QN_CALLPERF_MEDIA = { NS_GOOGLE_CALLPERF_STATS, "media" };
+const StaticQName QN_CALLPERF_MEDIA_DIRECTION = { STR_EMPTY, "direction" };
+const StaticQName QN_CALLPERF_MEDIA_SSRC = { STR_EMPTY, "SSRC" };
+const StaticQName QN_CALLPERF_MEDIA_ENERGY = { STR_EMPTY, "energy" };
+const StaticQName QN_CALLPERF_MEDIA_FIR = { STR_EMPTY, "fir" };
+const StaticQName QN_CALLPERF_MEDIA_NACK = { STR_EMPTY, "nack" };
+const StaticQName QN_CALLPERF_MEDIA_FPS = { STR_EMPTY, "fps" };
+const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK = { STR_EMPTY, "fpsNetwork" };
+const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED = { STR_EMPTY, "fpsDecoded" };
+const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE =
+    { STR_EMPTY, "jitterBufferSize" };
+const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE =
+    { STR_EMPTY, "preferredJitterBufferSize" };
+const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY =
+    { STR_EMPTY, "totalPlayoutDelay" };
+
+// Muc invites.
+const StaticQName QN_MUC_USER_INVITE = { NS_MUC_USER, "invite" };
+
+// Multiway audio/video.
+const char NS_GOOGLE_MUC_USER[] = "google:muc#user";
+const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA =
+    { NS_GOOGLE_MUC_USER, "available-media" };
+const StaticQName QN_GOOGLE_MUC_USER_ENTRY = { NS_GOOGLE_MUC_USER, "entry" };
+const StaticQName QN_GOOGLE_MUC_USER_MEDIA = { NS_GOOGLE_MUC_USER, "media" };
+const StaticQName QN_GOOGLE_MUC_USER_TYPE = { NS_GOOGLE_MUC_USER, "type" };
+const StaticQName QN_GOOGLE_MUC_USER_SRC_ID = { NS_GOOGLE_MUC_USER, "src-id" };
+const StaticQName QN_GOOGLE_MUC_USER_STATUS = { NS_GOOGLE_MUC_USER, "status" };
+const StaticQName QN_CLIENT_VERSION = { NS_GOOGLE_MUC_USER, "client-version" };
+const StaticQName QN_LOCALE = { NS_GOOGLE_MUC_USER, "locale" };
+const StaticQName QN_LABEL = { STR_EMPTY, "label" };
+
+const char NS_GOOGLE_MUC_MEDIA[] = "google:muc#media";
+const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE =
+    { NS_GOOGLE_MUC_MEDIA, "audio-mute" };
+const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE =
+    { NS_GOOGLE_MUC_MEDIA, "video-mute" };
+const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE =
+    { NS_GOOGLE_MUC_MEDIA, "video-pause" };
+const StaticQName QN_GOOGLE_MUC_RECORDING =
+    { NS_GOOGLE_MUC_MEDIA, "recording" };
+const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK = { NS_GOOGLE_MUC_MEDIA, "block" };
+const StaticQName QN_STATE_ATTR = { STR_EMPTY, "state" };
+
+const char AUTH_MECHANISM_GOOGLE_COOKIE[] = "X-GOOGLE-COOKIE";
+const char AUTH_MECHANISM_GOOGLE_TOKEN[] = "X-GOOGLE-TOKEN";
+const char AUTH_MECHANISM_OAUTH2[] = "X-OAUTH2";
+const char AUTH_MECHANISM_PLAIN[] = "PLAIN";
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmpp/constants.h b/third_party/libjingle_xmpp/xmpp/constants.h
new file mode 100644
index 0000000..dad55bf8
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/constants.h
@@ -0,0 +1,551 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
+#define WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
+
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+
+namespace buzz {
+
+extern const char NS_CLIENT[];
+extern const char NS_SERVER[];
+extern const char NS_STREAM[];
+extern const char NS_XSTREAM[];
+extern const char NS_TLS[];
+extern const char NS_SASL[];
+extern const char NS_BIND[];
+extern const char NS_DIALBACK[];
+extern const char NS_SESSION[];
+extern const char NS_STANZA[];
+extern const char NS_PRIVACY[];
+extern const char NS_ROSTER[];
+extern const char NS_VCARD[];
+extern const char NS_AVATAR_HASH[];
+extern const char NS_VCARD_UPDATE[];
+extern const char STR_CLIENT[];
+extern const char STR_SERVER[];
+extern const char STR_STREAM[];
+
+extern const char STR_GET[];
+extern const char STR_SET[];
+extern const char STR_RESULT[];
+extern const char STR_ERROR[];
+
+extern const char STR_FORM[];
+extern const char STR_SUBMIT[];
+extern const char STR_TEXT_SINGLE[];
+extern const char STR_LIST_SINGLE[];
+extern const char STR_LIST_MULTI[];
+extern const char STR_HIDDEN[];
+extern const char STR_FORM_TYPE[];
+
+extern const char STR_FROM[];
+extern const char STR_TO[];
+extern const char STR_BOTH[];
+extern const char STR_REMOVE[];
+extern const char STR_TRUE[];
+
+extern const char STR_TYPE[];
+extern const char STR_NAME[];
+extern const char STR_ID[];
+extern const char STR_JID[];
+extern const char STR_SUBSCRIPTION[];
+extern const char STR_ASK[];
+extern const char STR_X[];
+extern const char STR_GOOGLE_COM[];
+extern const char STR_GMAIL_COM[];
+extern const char STR_GOOGLEMAIL_COM[];
+extern const char STR_DEFAULT_DOMAIN[];
+extern const char STR_TALK_GOOGLE_COM[];
+extern const char STR_TALKX_L_GOOGLE_COM[];
+extern const char STR_XMPP_GOOGLE_COM[];
+extern const char STR_XMPPX_L_GOOGLE_COM[];
+
+#ifdef FEATURE_ENABLE_VOICEMAIL
+extern const char STR_VOICEMAIL[];
+extern const char STR_OUTGOINGVOICEMAIL[];
+#endif
+
+extern const char STR_UNAVAILABLE[];
+
+extern const char NS_PING[];
+extern const StaticQName QN_PING;
+
+extern const char NS_MUC_UNIQUE[];
+extern const StaticQName QN_MUC_UNIQUE_QUERY;
+extern const StaticQName QN_HANGOUT_ID;
+
+extern const char STR_GOOGLE_MUC_LOOKUP_JID[];
+extern const char STR_MUC_ROOMCONFIG_ROOMNAME[];
+extern const char STR_MUC_ROOMCONFIG_FEATURES[];
+extern const char STR_MUC_ROOM_FEATURE_ENTERPRISE[];
+extern const char STR_MUC_ROOMCONFIG[];
+extern const char STR_MUC_ROOM_FEATURE_HANGOUT[];
+extern const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[];
+extern const char STR_MUC_ROOM_FEATURE_BROADCAST[];
+extern const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[];
+extern const char STR_MUC_ROOM_FEATURE_RECORDABLE[];
+extern const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[];
+extern const char STR_MUC_ROOM_OWNER_PROFILE_ID[];
+extern const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[];
+
+extern const char STR_ID_TYPE_CONVERSATION[];
+extern const char NS_GOOGLE_MUC_HANGOUT[];
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE;
+extern const StaticQName QN_ATTR_CREATE_ACTIVITY;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID;
+
+extern const StaticQName QN_STREAM_STREAM;
+extern const StaticQName QN_STREAM_FEATURES;
+extern const StaticQName QN_STREAM_ERROR;
+
+extern const StaticQName QN_XSTREAM_BAD_FORMAT;
+extern const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX;
+extern const StaticQName QN_XSTREAM_CONFLICT;
+extern const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT;
+extern const StaticQName QN_XSTREAM_HOST_GONE;
+extern const StaticQName QN_XSTREAM_HOST_UNKNOWN;
+extern const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING;
+extern const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR;
+extern const StaticQName QN_XSTREAM_INVALID_FROM;
+extern const StaticQName QN_XSTREAM_INVALID_ID;
+extern const StaticQName QN_XSTREAM_INVALID_NAMESPACE;
+extern const StaticQName QN_XSTREAM_INVALID_XML;
+extern const StaticQName QN_XSTREAM_NOT_AUTHORIZED;
+extern const StaticQName QN_XSTREAM_POLICY_VIOLATION;
+extern const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED;
+extern const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT;
+extern const StaticQName QN_XSTREAM_RESTRICTED_XML;
+extern const StaticQName QN_XSTREAM_SEE_OTHER_HOST;
+extern const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN;
+extern const StaticQName QN_XSTREAM_UNDEFINED_CONDITION;
+extern const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING;
+extern const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE;
+extern const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION;
+extern const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED;
+extern const StaticQName QN_XSTREAM_TEXT;
+
+extern const StaticQName QN_TLS_STARTTLS;
+extern const StaticQName QN_TLS_REQUIRED;
+extern const StaticQName QN_TLS_PROCEED;
+extern const StaticQName QN_TLS_FAILURE;
+
+extern const StaticQName QN_SASL_MECHANISMS;
+extern const StaticQName QN_SASL_MECHANISM;
+extern const StaticQName QN_SASL_AUTH;
+extern const StaticQName QN_SASL_CHALLENGE;
+extern const StaticQName QN_SASL_RESPONSE;
+extern const StaticQName QN_SASL_ABORT;
+extern const StaticQName QN_SASL_SUCCESS;
+extern const StaticQName QN_SASL_FAILURE;
+extern const StaticQName QN_SASL_ABORTED;
+extern const StaticQName QN_SASL_INCORRECT_ENCODING;
+extern const StaticQName QN_SASL_INVALID_AUTHZID;
+extern const StaticQName QN_SASL_INVALID_MECHANISM;
+extern const StaticQName QN_SASL_MECHANISM_TOO_WEAK;
+extern const StaticQName QN_SASL_NOT_AUTHORIZED;
+extern const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE;
+
+// These are non-standard.
+extern const char NS_GOOGLE_AUTH[];
+extern const char NS_GOOGLE_AUTH_PROTOCOL[];
+extern const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT;
+extern const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN;
+extern const StaticQName QN_GOOGLE_AUTH_SERVICE;
+
+extern const StaticQName QN_DIALBACK_RESULT;
+extern const StaticQName QN_DIALBACK_VERIFY;
+
+extern const StaticQName QN_STANZA_BAD_REQUEST;
+extern const StaticQName QN_STANZA_CONFLICT;
+extern const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED;
+extern const StaticQName QN_STANZA_FORBIDDEN;
+extern const StaticQName QN_STANZA_GONE;
+extern const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR;
+extern const StaticQName QN_STANZA_ITEM_NOT_FOUND;
+extern const StaticQName QN_STANZA_JID_MALFORMED;
+extern const StaticQName QN_STANZA_NOT_ACCEPTABLE;
+extern const StaticQName QN_STANZA_NOT_ALLOWED;
+extern const StaticQName QN_STANZA_PAYMENT_REQUIRED;
+extern const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE;
+extern const StaticQName QN_STANZA_REDIRECT;
+extern const StaticQName QN_STANZA_REGISTRATION_REQUIRED;
+extern const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND;
+extern const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT;
+extern const StaticQName QN_STANZA_RESOURCE_CONSTRAINT;
+extern const StaticQName QN_STANZA_SERVICE_UNAVAILABLE;
+extern const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED;
+extern const StaticQName QN_STANZA_UNDEFINED_CONDITION;
+extern const StaticQName QN_STANZA_UNEXPECTED_REQUEST;
+extern const StaticQName QN_STANZA_TEXT;
+
+extern const StaticQName QN_BIND_BIND;
+extern const StaticQName QN_BIND_RESOURCE;
+extern const StaticQName QN_BIND_JID;
+
+extern const StaticQName QN_MESSAGE;
+extern const StaticQName QN_BODY;
+extern const StaticQName QN_SUBJECT;
+extern const StaticQName QN_THREAD;
+extern const StaticQName QN_PRESENCE;
+extern const StaticQName QN_SHOW;
+extern const StaticQName QN_STATUS;
+extern const StaticQName QN_LANG;
+extern const StaticQName QN_PRIORITY;
+extern const StaticQName QN_IQ;
+extern const StaticQName QN_ERROR;
+
+extern const StaticQName QN_SERVER_MESSAGE;
+extern const StaticQName QN_SERVER_BODY;
+extern const StaticQName QN_SERVER_SUBJECT;
+extern const StaticQName QN_SERVER_THREAD;
+extern const StaticQName QN_SERVER_PRESENCE;
+extern const StaticQName QN_SERVER_SHOW;
+extern const StaticQName QN_SERVER_STATUS;
+extern const StaticQName QN_SERVER_LANG;
+extern const StaticQName QN_SERVER_PRIORITY;
+extern const StaticQName QN_SERVER_IQ;
+extern const StaticQName QN_SERVER_ERROR;
+
+extern const StaticQName QN_SESSION_SESSION;
+
+extern const StaticQName QN_PRIVACY_QUERY;
+extern const StaticQName QN_PRIVACY_ACTIVE;
+extern const StaticQName QN_PRIVACY_DEFAULT;
+extern const StaticQName QN_PRIVACY_LIST;
+extern const StaticQName QN_PRIVACY_ITEM;
+extern const StaticQName QN_PRIVACY_IQ;
+extern const StaticQName QN_PRIVACY_MESSAGE;
+extern const StaticQName QN_PRIVACY_PRESENCE_IN;
+extern const StaticQName QN_PRIVACY_PRESENCE_OUT;
+
+extern const StaticQName QN_ROSTER_QUERY;
+extern const StaticQName QN_ROSTER_ITEM;
+extern const StaticQName QN_ROSTER_GROUP;
+
+extern const StaticQName QN_VCARD;
+extern const StaticQName QN_VCARD_FN;
+extern const StaticQName QN_VCARD_PHOTO;
+extern const StaticQName QN_VCARD_PHOTO_BINVAL;
+extern const StaticQName QN_VCARD_AVATAR_HASH;
+extern const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED;
+
+#if defined(FEATURE_ENABLE_PSTN)
+extern const StaticQName QN_VCARD_TEL;
+extern const StaticQName QN_VCARD_VOICE;
+extern const StaticQName QN_VCARD_HOME;
+extern const StaticQName QN_VCARD_WORK;
+extern const StaticQName QN_VCARD_CELL;
+extern const StaticQName QN_VCARD_NUMBER;
+#endif
+
+#if defined(FEATURE_ENABLE_RICHPROFILES)
+extern const StaticQName QN_USER_PROFILE_QUERY;
+extern const StaticQName QN_USER_PROFILE_URL;
+
+extern const StaticQName QN_ATOM_FEED;
+extern const StaticQName QN_ATOM_ENTRY;
+extern const StaticQName QN_ATOM_TITLE;
+extern const StaticQName QN_ATOM_ID;
+extern const StaticQName QN_ATOM_MODIFIED;
+extern const StaticQName QN_ATOM_IMAGE;
+extern const StaticQName QN_ATOM_LINK;
+extern const StaticQName QN_ATOM_HREF;
+#endif
+
+extern const StaticQName QN_XML_LANG;
+
+extern const StaticQName QN_ENCODING;
+extern const StaticQName QN_VERSION;
+extern const StaticQName QN_TO;
+extern const StaticQName QN_FROM;
+extern const StaticQName QN_TYPE;
+extern const StaticQName QN_ID;
+extern const StaticQName QN_CODE;
+extern const StaticQName QN_NAME;
+extern const StaticQName QN_VALUE;
+extern const StaticQName QN_ACTION;
+extern const StaticQName QN_ORDER;
+extern const StaticQName QN_MECHANISM;
+extern const StaticQName QN_ASK;
+extern const StaticQName QN_JID;
+extern const StaticQName QN_NICK;
+extern const StaticQName QN_SUBSCRIPTION;
+extern const StaticQName QN_TITLE1;
+extern const StaticQName QN_TITLE2;
+extern const StaticQName QN_AFFILIATION;
+extern const StaticQName QN_ROLE;
+extern const StaticQName QN_TIME;
+
+extern const StaticQName QN_XMLNS_CLIENT;
+extern const StaticQName QN_XMLNS_SERVER;
+extern const StaticQName QN_XMLNS_STREAM;
+
+// Presence
+extern const char STR_SHOW_AWAY[];
+extern const char STR_SHOW_CHAT[];
+extern const char STR_SHOW_DND[];
+extern const char STR_SHOW_XA[];
+extern const char STR_SHOW_OFFLINE[];
+
+extern const char NS_GOOGLE_PSTN_CONFERENCE[];
+extern const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS;
+extern const StaticQName QN_ATTR_STATUS;
+
+// Presence connection status
+extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[];
+extern const char STR_PSTN_CONFERENCE_STATUS_JOINING[];
+extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[];
+extern const char STR_PSTN_CONFERENCE_STATUS_HANGUP[];
+
+// Subscription
+extern const char STR_SUBSCRIBE[];
+extern const char STR_SUBSCRIBED[];
+extern const char STR_UNSUBSCRIBE[];
+extern const char STR_UNSUBSCRIBED[];
+
+// Google Invite
+extern const char NS_GOOGLE_SUBSCRIBE[];
+extern const StaticQName QN_INVITATION;
+extern const StaticQName QN_INVITE_NAME;
+extern const StaticQName QN_INVITE_SUBJECT;
+extern const StaticQName QN_INVITE_MESSAGE;
+
+// Kick
+extern const char NS_GOOGLE_MUC_ADMIN[];
+extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY;
+extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM;
+extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON;
+
+// PubSub: http://xmpp.org/extensions/xep-0060.html
+extern const char NS_PUBSUB[];
+extern const StaticQName QN_PUBSUB;
+extern const StaticQName QN_PUBSUB_ITEMS;
+extern const StaticQName QN_PUBSUB_ITEM;
+extern const StaticQName QN_PUBSUB_PUBLISH;
+extern const StaticQName QN_PUBSUB_RETRACT;
+extern const StaticQName QN_ATTR_PUBLISHER;
+
+extern const char NS_PUBSUB_EVENT[];
+extern const StaticQName QN_NODE;
+extern const StaticQName QN_PUBSUB_EVENT;
+extern const StaticQName QN_PUBSUB_EVENT_ITEMS;
+extern const StaticQName QN_PUBSUB_EVENT_ITEM;
+extern const StaticQName QN_PUBSUB_EVENT_RETRACT;
+extern const StaticQName QN_NOTIFY;
+
+extern const char NS_PRESENTER[];
+extern const StaticQName QN_PRESENTER_PRESENTER;
+extern const StaticQName QN_PRESENTER_PRESENTATION_ITEM;
+extern const StaticQName QN_PRESENTER_PRESENTATION_TYPE;
+extern const StaticQName QN_PRESENTER_PRESENTATION_ID;
+
+// JEP 0030
+extern const StaticQName QN_CATEGORY;
+extern const StaticQName QN_VAR;
+extern const char NS_DISCO_INFO[];
+extern const char NS_DISCO_ITEMS[];
+
+extern const StaticQName QN_DISCO_INFO_QUERY;
+extern const StaticQName QN_DISCO_IDENTITY;
+extern const StaticQName QN_DISCO_FEATURE;
+
+extern const StaticQName QN_DISCO_ITEMS_QUERY;
+extern const StaticQName QN_DISCO_ITEM;
+
+// JEP 0020
+extern const char NS_FEATURE[];
+extern const StaticQName QN_FEATURE_FEATURE;
+
+// JEP 0004
+extern const char NS_XDATA[];
+extern const StaticQName QN_XDATA_X;
+extern const StaticQName QN_XDATA_INSTRUCTIONS;
+extern const StaticQName QN_XDATA_TITLE;
+extern const StaticQName QN_XDATA_FIELD;
+extern const StaticQName QN_XDATA_REPORTED;
+extern const StaticQName QN_XDATA_ITEM;
+extern const StaticQName QN_XDATA_DESC;
+extern const StaticQName QN_XDATA_REQUIRED;
+extern const StaticQName QN_XDATA_VALUE;
+extern const StaticQName QN_XDATA_OPTION;
+
+// JEP 0045
+extern const char NS_MUC[];
+extern const StaticQName QN_MUC_X;
+extern const StaticQName QN_MUC_ITEM;
+extern const StaticQName QN_MUC_AFFILIATION;
+extern const StaticQName QN_MUC_ROLE;
+extern const StaticQName QN_CLIENT_VERSION;
+extern const StaticQName QN_LOCALE;
+extern const char STR_AFFILIATION_NONE[];
+extern const char STR_ROLE_PARTICIPANT[];
+
+extern const char NS_GOOGLE_SESSION[];
+extern const StaticQName QN_GOOGLE_USER_ID;
+extern const StaticQName QN_GOOGLE_CIRCLE_ID;
+extern const StaticQName QN_GOOGLE_SESSION_BLOCKED;
+extern const StaticQName QN_GOOGLE_SESSION_BLOCKING;
+
+extern const char NS_MUC_OWNER[];
+extern const StaticQName QN_MUC_OWNER_QUERY;
+
+extern const char NS_MUC_USER[];
+extern const StaticQName QN_MUC_USER_CONTINUE;
+extern const StaticQName QN_MUC_USER_X;
+extern const StaticQName QN_MUC_USER_ITEM;
+extern const StaticQName QN_MUC_USER_STATUS;
+extern const StaticQName QN_MUC_USER_REASON;
+extern const StaticQName QN_MUC_USER_ABUSE_VIOLATION;
+
+// JEP 0055 - Jabber Search
+extern const char NS_SEARCH[];
+extern const StaticQName QN_SEARCH_QUERY;
+extern const StaticQName QN_SEARCH_ITEM;
+extern const StaticQName QN_SEARCH_ROOM_NAME;
+extern const StaticQName QN_SEARCH_ROOM_JID;
+extern const StaticQName QN_SEARCH_ROOM_DOMAIN;
+extern const StaticQName QN_SEARCH_HANGOUT_ID;
+extern const StaticQName QN_SEARCH_EXTERNAL_ID;
+
+// JEP 0115
+extern const char NS_CAPS[];
+extern const StaticQName QN_CAPS_C;
+extern const StaticQName QN_VER;
+extern const StaticQName QN_EXT;
+
+
+// Avatar - JEP 0153
+extern const char kNSVCard[];
+extern const StaticQName kQnVCardX;
+extern const StaticQName kQnVCardPhoto;
+
+// JEP 0172 User Nickname
+extern const char NS_NICKNAME[];
+extern const StaticQName QN_NICKNAME;
+
+// JEP 0085 chat state
+extern const char NS_CHATSTATE[];
+extern const StaticQName QN_CS_ACTIVE;
+extern const StaticQName QN_CS_COMPOSING;
+extern const StaticQName QN_CS_PAUSED;
+extern const StaticQName QN_CS_INACTIVE;
+extern const StaticQName QN_CS_GONE;
+
+// JEP 0091 Delayed Delivery
+extern const char kNSDelay[];
+extern const StaticQName kQnDelayX;
+extern const StaticQName kQnStamp;
+
+// Google time stamping (higher resolution)
+extern const char kNSTimestamp[];
+extern const StaticQName kQnTime;
+extern const StaticQName kQnMilliseconds;
+
+extern const char NS_JINGLE_INFO[];
+extern const StaticQName QN_JINGLE_INFO_QUERY;
+extern const StaticQName QN_JINGLE_INFO_STUN;
+extern const StaticQName QN_JINGLE_INFO_RELAY;
+extern const StaticQName QN_JINGLE_INFO_SERVER;
+extern const StaticQName QN_JINGLE_INFO_TOKEN;
+extern const StaticQName QN_JINGLE_INFO_HOST;
+extern const StaticQName QN_JINGLE_INFO_TCP;
+extern const StaticQName QN_JINGLE_INFO_UDP;
+extern const StaticQName QN_JINGLE_INFO_TCPSSL;
+
+extern const char NS_GOOGLE_CALLPERF_STATS[];
+extern const StaticQName QN_CALLPERF_STATS;
+extern const StaticQName QN_CALLPERF_SESSIONID;
+extern const StaticQName QN_CALLPERF_LOCALUSER;
+extern const StaticQName QN_CALLPERF_REMOTEUSER;
+extern const StaticQName QN_CALLPERF_STARTTIME;
+extern const StaticQName QN_CALLPERF_CALL_LENGTH;
+extern const StaticQName QN_CALLPERF_CALL_ACCEPTED;
+extern const StaticQName QN_CALLPERF_CALL_ERROR_CODE;
+extern const StaticQName QN_CALLPERF_TERMINATE_CODE;
+extern const StaticQName QN_CALLPERF_DATAPOINT;
+extern const StaticQName QN_CALLPERF_DATAPOINT_TIME;
+extern const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST;
+extern const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST;
+extern const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX;
+extern const StaticQName QN_CALLPERF_DATAPOINT_JITTER;
+extern const StaticQName QN_CALLPERF_DATAPOINT_RTT;
+extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R;
+extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R;
+extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S;
+extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S;
+extern const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU;
+extern const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU;
+extern const StaticQName QN_CALLPERF_DATAPOINT_CPUS;
+extern const StaticQName QN_CALLPERF_CONNECTION;
+extern const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS;
+extern const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS;
+extern const StaticQName QN_CALLPERF_CONNECTION_FLAGS;
+extern const StaticQName QN_CALLPERF_CONNECTION_RTT;
+extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S;
+extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S;
+extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R;
+extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R;
+extern const StaticQName QN_CALLPERF_CANDIDATE;
+extern const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT;
+extern const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL;
+extern const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS;
+extern const StaticQName QN_CALLPERF_MEDIA;
+extern const StaticQName QN_CALLPERF_MEDIA_DIRECTION;
+extern const StaticQName QN_CALLPERF_MEDIA_SSRC;
+extern const StaticQName QN_CALLPERF_MEDIA_ENERGY;
+extern const StaticQName QN_CALLPERF_MEDIA_FIR;
+extern const StaticQName QN_CALLPERF_MEDIA_NACK;
+extern const StaticQName QN_CALLPERF_MEDIA_FPS;
+extern const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK;
+extern const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED;
+extern const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE;
+extern const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE;
+extern const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY;
+
+// Muc invites.
+extern const StaticQName QN_MUC_USER_INVITE;
+
+// Multiway audio/video.
+extern const char NS_GOOGLE_MUC_USER[];
+extern const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA;
+extern const StaticQName QN_GOOGLE_MUC_USER_ENTRY;
+extern const StaticQName QN_GOOGLE_MUC_USER_MEDIA;
+extern const StaticQName QN_GOOGLE_MUC_USER_TYPE;
+extern const StaticQName QN_GOOGLE_MUC_USER_SRC_ID;
+extern const StaticQName QN_GOOGLE_MUC_USER_STATUS;
+extern const StaticQName QN_LABEL;
+
+extern const char NS_GOOGLE_MUC_MEDIA[];
+extern const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE;
+extern const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE;
+extern const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE;
+extern const StaticQName QN_GOOGLE_MUC_RECORDING;
+extern const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK;
+extern const StaticQName QN_STATE_ATTR;
+
+
+extern const char AUTH_MECHANISM_GOOGLE_COOKIE[];
+extern const char AUTH_MECHANISM_GOOGLE_TOKEN[];
+extern const char AUTH_MECHANISM_OAUTH2[];
+extern const char AUTH_MECHANISM_PLAIN[];
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
diff --git a/third_party/libjingle_xmpp/xmpp/fakexmppclient.h b/third_party/libjingle_xmpp/xmpp/fakexmppclient.h
new file mode 100644
index 0000000..988fbe3
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/fakexmppclient.h
@@ -0,0 +1,107 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+// A fake XmppClient for use in unit tests.
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
+
+namespace buzz {
+
+class XmlElement;
+
+class FakeXmppClient : public XmppTaskParentInterface,
+                       public XmppClientInterface {
+ public:
+  explicit FakeXmppClient(rtc::TaskParent* parent)
+      : XmppTaskParentInterface(parent) {
+  }
+
+  // As XmppTaskParentInterface
+  virtual XmppClientInterface* GetClient() {
+    return this;
+  }
+
+  virtual int ProcessStart() {
+    return STATE_RESPONSE;
+  }
+
+  // As XmppClientInterface
+  virtual XmppEngine::State GetState() const {
+    return XmppEngine::STATE_OPEN;
+  }
+
+  virtual const Jid& jid() const {
+    return jid_;
+  }
+
+  virtual std::string NextId() {
+    // Implement if needed for tests.
+    return "0";
+  }
+
+  virtual XmppReturnStatus SendStanza(const XmlElement* stanza) {
+    sent_stanzas_.push_back(stanza);
+    return XMPP_RETURN_OK;
+  }
+
+  const std::vector<const XmlElement*>& sent_stanzas() {
+    return sent_stanzas_;
+  }
+
+  virtual XmppReturnStatus SendStanzaError(
+      const XmlElement * pelOriginal,
+      XmppStanzaError code,
+      const std::string & text) {
+    // Implement if needed for tests.
+    return XMPP_RETURN_OK;
+  }
+
+  virtual void AddXmppTask(XmppTask* task,
+                           XmppEngine::HandlerLevel level) {
+    tasks_.push_back(task);
+  }
+
+  virtual void RemoveXmppTask(XmppTask* task) {
+    std::remove(tasks_.begin(), tasks_.end(), task);
+  }
+
+  // As FakeXmppClient
+  void set_jid(const Jid& jid) {
+    jid_ = jid;
+  }
+
+  // Takes ownership of stanza.
+  void HandleStanza(XmlElement* stanza) {
+    for (std::vector<XmppTask*>::iterator task = tasks_.begin();
+         task != tasks_.end(); ++task) {
+      if ((*task)->HandleStanza(stanza)) {
+        delete stanza;
+        return;
+      }
+    }
+    delete stanza;
+  }
+
+ private:
+  Jid jid_;
+  std::vector<XmppTask*> tasks_;
+  std::vector<const XmlElement*> sent_stanzas_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
diff --git a/third_party/libjingle_xmpp/xmpp/jid.cc b/third_party/libjingle_xmpp/xmpp/jid.cc
new file mode 100644
index 0000000..53f7f8a
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/jid.cc
@@ -0,0 +1,379 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+
+#include <ctype.h>
+
+#include <algorithm>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc_overrides/webrtc/base/logging.h"
+
+namespace buzz {
+
+Jid::Jid() {
+}
+
+Jid::Jid(const std::string& jid_string) {
+  if (jid_string.empty())
+    return;
+
+  // First find the slash and slice off that part
+  size_t slash = jid_string.find('/');
+  resource_name_ = (slash == std::string::npos ? STR_EMPTY :
+                    jid_string.substr(slash + 1));
+
+  // Now look for the node
+  size_t at = jid_string.find('@');
+  size_t domain_begin;
+  if (at < slash && at != std::string::npos) {
+    node_name_ = jid_string.substr(0, at);
+    domain_begin = at + 1;
+  } else {
+    domain_begin = 0;
+  }
+
+  // Now take what is left as the domain
+  size_t domain_length = (slash == std::string::npos) ?
+      (jid_string.length() - domain_begin) : (slash - domain_begin);
+  domain_name_ = jid_string.substr(domain_begin, domain_length);
+
+  ValidateOrReset();
+}
+
+Jid::Jid(const std::string& node_name,
+         const std::string& domain_name,
+         const std::string& resource_name)
+    :  node_name_(node_name),
+       domain_name_(domain_name),
+       resource_name_(resource_name) {
+  ValidateOrReset();
+}
+
+void Jid::ValidateOrReset() {
+  bool valid_node;
+  bool valid_domain;
+  bool valid_resource;
+
+  node_name_ = PrepNode(node_name_, &valid_node);
+  domain_name_ = PrepDomain(domain_name_, &valid_domain);
+  resource_name_ = PrepResource(resource_name_, &valid_resource);
+
+  if (!valid_node || !valid_domain || !valid_resource) {
+    node_name_.clear();
+    domain_name_.clear();
+    resource_name_.clear();
+  }
+}
+
+std::string Jid::Str() const {
+  if (!IsValid())
+    return STR_EMPTY;
+
+  std::string ret;
+
+  if (!node_name_.empty())
+    ret = node_name_ + "@";
+
+  ASSERT(domain_name_ != STR_EMPTY);
+  ret += domain_name_;
+
+  if (!resource_name_.empty())
+    ret += "/" + resource_name_;
+
+  return ret;
+}
+
+Jid::~Jid() {
+}
+
+bool Jid::IsEmpty() const {
+  return (node_name_.empty() && domain_name_.empty() &&
+          resource_name_.empty());
+}
+
+bool Jid::IsValid() const {
+  return !domain_name_.empty();
+}
+
+bool Jid::IsBare() const {
+  if (IsEmpty()) {
+    LOG(LS_VERBOSE) << "Warning: Calling IsBare() on the empty jid.";
+    return true;
+  }
+  return IsValid() && resource_name_.empty();
+}
+
+bool Jid::IsFull() const {
+  return IsValid() && !resource_name_.empty();
+}
+
+Jid Jid::BareJid() const {
+  if (!IsValid())
+    return Jid();
+  if (!IsFull())
+    return *this;
+  return Jid(node_name_, domain_name_, STR_EMPTY);
+}
+
+bool Jid::BareEquals(const Jid& other) const {
+  return other.node_name_ == node_name_ &&
+      other.domain_name_ == domain_name_;
+}
+
+void Jid::CopyFrom(const Jid& jid) {
+  this->node_name_ = jid.node_name_;
+  this->domain_name_ = jid.domain_name_;
+  this->resource_name_ = jid.resource_name_;
+}
+
+bool Jid::operator==(const Jid& other) const {
+  return other.node_name_ == node_name_ &&
+      other.domain_name_ == domain_name_ &&
+      other.resource_name_ == resource_name_;
+}
+
+int Jid::Compare(const Jid& other) const {
+  int compare_result;
+  compare_result = node_name_.compare(other.node_name_);
+  if (0 != compare_result)
+    return compare_result;
+  compare_result = domain_name_.compare(other.domain_name_);
+  if (0 != compare_result)
+    return compare_result;
+  compare_result = resource_name_.compare(other.resource_name_);
+  return compare_result;
+}
+
+// --- JID parsing code: ---
+
+// Checks and normalizes the node part of a JID.
+std::string Jid::PrepNode(const std::string& node, bool* valid) {
+  *valid = false;
+  std::string result;
+
+  for (std::string::const_iterator i = node.begin(); i < node.end(); ++i) {
+    bool char_valid = true;
+    unsigned char ch = *i;
+    if (ch <= 0x7F) {
+      result += PrepNodeAscii(ch, &char_valid);
+    }
+    else {
+      // TODO: implement the correct stringprep protocol for these
+      result += tolower(ch);
+    }
+    if (!char_valid) {
+      return STR_EMPTY;
+    }
+  }
+
+  if (result.length() > 1023) {
+    return STR_EMPTY;
+  }
+  *valid = true;
+  return result;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a node.
+char Jid::PrepNodeAscii(char ch, bool* valid) {
+  *valid = true;
+  switch (ch) {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+    case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+    case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+    case 'V': case 'W': case 'X': case 'Y': case 'Z':
+      return (char)(ch + ('a' - 'A'));
+
+    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+    case ' ': case '&': case '/': case ':': case '<': case '>': case '@':
+    case '\"': case '\'':
+    case 0x7F:
+      *valid = false;
+      return 0;
+
+    default:
+      return ch;
+  }
+}
+
+
+// Checks and normalizes the resource part of a JID.
+std::string Jid::PrepResource(const std::string& resource, bool* valid) {
+  *valid = false;
+  std::string result;
+
+  for (std::string::const_iterator i = resource.begin();
+       i < resource.end(); ++i) {
+    bool char_valid = true;
+    unsigned char ch = *i;
+    if (ch <= 0x7F) {
+      result += PrepResourceAscii(ch, &char_valid);
+    }
+    else {
+      // TODO: implement the correct stringprep protocol for these
+      result += ch;
+    }
+  }
+
+  if (result.length() > 1023) {
+    return STR_EMPTY;
+  }
+  *valid = true;
+  return result;
+}
+
+// Returns the appropriate mapping for an ASCII character in a resource.
+char Jid::PrepResourceAscii(char ch, bool* valid) {
+  *valid = true;
+  switch (ch) {
+    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+    case 0x7F:
+      *valid = false;
+      return 0;
+
+    default:
+      return ch;
+  }
+}
+
+// Checks and normalizes the domain part of a JID.
+std::string Jid::PrepDomain(const std::string& domain, bool* valid) {
+  *valid = false;
+  std::string result;
+
+  // TODO: if the domain contains a ':', then we should parse it
+  // as an IPv6 address rather than giving an error about illegal domain.
+  PrepDomain(domain, &result, valid);
+  if (!*valid) {
+    return STR_EMPTY;
+  }
+
+  if (result.length() > 1023) {
+    return STR_EMPTY;
+  }
+  *valid = true;
+  return result;
+}
+
+
+// Checks and normalizes an IDNA domain.
+void Jid::PrepDomain(const std::string& domain, std::string* buf, bool* valid) {
+  *valid = false;
+  std::string::const_iterator last = domain.begin();
+  for (std::string::const_iterator i = domain.begin(); i < domain.end(); ++i) {
+    bool label_valid = true;
+    char ch = *i;
+    switch (ch) {
+      case 0x002E:
+#if 0 // FIX: This isn't UTF-8-aware.
+      case 0x3002:
+      case 0xFF0E:
+      case 0xFF61:
+#endif
+        PrepDomainLabel(last, i, buf, &label_valid);
+        *buf += '.';
+        last = i + 1;
+        break;
+    }
+    if (!label_valid) {
+      return;
+    }
+  }
+  PrepDomainLabel(last, domain.end(), buf, valid);
+}
+
+// Checks and normalizes a domain label.
+void Jid::PrepDomainLabel(
+    std::string::const_iterator start, std::string::const_iterator end,
+    std::string* buf, bool* valid) {
+  *valid = false;
+
+  int start_len = static_cast<int>(buf->length());
+  for (std::string::const_iterator i = start; i < end; ++i) {
+    bool char_valid = true;
+    unsigned char ch = *i;
+    if (ch <= 0x7F) {
+      *buf += PrepDomainLabelAscii(ch, &char_valid);
+    }
+    else {
+      // TODO: implement ToASCII for these
+      *buf += ch;
+    }
+    if (!char_valid) {
+      return;
+    }
+  }
+
+  int count = static_cast<int>(buf->length() - start_len);
+  if (count == 0) {
+    return;
+  }
+  else if (count > 63) {
+    return;
+  }
+
+  // Is this check needed? See comment in PrepDomainLabelAscii.
+  if ((*buf)[start_len] == '-') {
+    return;
+  }
+  if ((*buf)[buf->length() - 1] == '-') {
+    return;
+  }
+  *valid = true;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a domain label.
+char Jid::PrepDomainLabelAscii(char ch, bool* valid) {
+  *valid = true;
+  // TODO: A literal reading of the spec seems to say that we do
+  // not need to check for these illegal characters (an "internationalized
+  // domain label" runs ToASCII with UseSTD3... set to false).  But that
+  // can't be right.  We should at least be checking that there are no '/'
+  // or '@' characters in the domain.  Perhaps we should see what others
+  // do in this case.
+
+  switch (ch) {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+    case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+    case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+    case 'V': case 'W': case 'X': case 'Y': case 'Z':
+      return (char)(ch + ('a' - 'A'));
+
+    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+    case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D:
+    case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23:
+    case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29:
+    case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A:
+    case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40:
+    case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60:
+    case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
+      *valid = false;
+      return 0;
+
+    default:
+      return ch;
+  }
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmpp/jid.h b/third_party/libjingle_xmpp/xmpp/jid.h
new file mode 100644
index 0000000..5443b05
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/jid.h
@@ -0,0 +1,80 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_JID_H_
+#define WEBRTC_LIBJINGLE_XMPP_JID_H_
+
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+// The Jid class encapsulates and provides parsing help for Jids. A Jid
+// consists of three parts: the node, the domain and the resource, e.g.:
+//
+// node@domain/resource
+//
+// The node and resource are both optional. A valid jid is defined to have
+// a domain. A bare jid is defined to not have a resource and a full jid
+// *does* have a resource.
+class Jid {
+public:
+  explicit Jid();
+  explicit Jid(const std::string& jid_string);
+  explicit Jid(const std::string& node_name,
+               const std::string& domain_name,
+               const std::string& resource_name);
+  ~Jid();
+
+  const std::string & node() const { return node_name_; }
+  const std::string & domain() const { return domain_name_;  }
+  const std::string & resource() const { return resource_name_; }
+
+  std::string Str() const;
+  Jid BareJid() const;
+
+  bool IsEmpty() const;
+  bool IsValid() const;
+  bool IsBare() const;
+  bool IsFull() const;
+
+  bool BareEquals(const Jid& other) const;
+  void CopyFrom(const Jid& jid);
+  bool operator==(const Jid& other) const;
+  bool operator!=(const Jid& other) const { return !operator==(other); }
+
+  bool operator<(const Jid& other) const { return Compare(other) < 0; };
+  bool operator>(const Jid& other) const { return Compare(other) > 0; };
+
+  int Compare(const Jid & other) const;
+
+private:
+  void ValidateOrReset();
+
+  static std::string PrepNode(const std::string& node, bool* valid);
+  static char PrepNodeAscii(char ch, bool* valid);
+  static std::string PrepResource(const std::string& start, bool* valid);
+  static char PrepResourceAscii(char ch, bool* valid);
+  static std::string PrepDomain(const std::string& domain, bool* valid);
+  static void PrepDomain(const std::string& domain,
+                         std::string* buf, bool* valid);
+  static void PrepDomainLabel(
+      std::string::const_iterator start, std::string::const_iterator end,
+      std::string* buf, bool* valid);
+  static char PrepDomainLabelAscii(char ch, bool *valid);
+
+  std::string node_name_;
+  std::string domain_name_;
+  std::string resource_name_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_JID_H_
diff --git a/third_party/libjingle_xmpp/xmpp/jid_unittest.cc b/third_party/libjingle_xmpp/xmpp/jid_unittest.cc
new file mode 100644
index 0000000..2fd5ded
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/jid_unittest.cc
@@ -0,0 +1,122 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::Jid;
+
+TEST(JidTest, TestDomain) {
+  Jid jid("dude");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("dude", jid.Str());
+  EXPECT_EQ("dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestNodeDomain) {
+  Jid jid("walter@dude");
+  EXPECT_EQ("walter", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("walter@dude", jid.Str());
+  EXPECT_EQ("walter@dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestDomainResource) {
+  Jid jid("dude/bowlingalley");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("bowlingalley", jid.resource());
+  EXPECT_EQ("dude/bowlingalley", jid.Str());
+  EXPECT_EQ("dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
+
+TEST(JidTest, TestNodeDomainResource) {
+  Jid jid("walter@dude/bowlingalley");
+  EXPECT_EQ("walter", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("bowlingalley", jid.resource());
+  EXPECT_EQ("walter@dude/bowlingalley", jid.Str());
+  EXPECT_EQ("walter@dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
+
+TEST(JidTest, TestNode) {
+  Jid jid("walter@");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("", jid.Str());
+  EXPECT_EQ("", jid.BareJid().Str());
+  EXPECT_FALSE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestResource) {
+  Jid jid("/bowlingalley");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("", jid.Str());
+  EXPECT_EQ("", jid.BareJid().Str());
+  EXPECT_FALSE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestNodeResource) {
+  Jid jid("walter@/bowlingalley");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("", jid.Str());
+  EXPECT_EQ("", jid.BareJid().Str());
+  EXPECT_FALSE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestFunky) {
+  Jid jid("bowling@muchat/walter@dude");
+  EXPECT_EQ("bowling", jid.node());
+  EXPECT_EQ("muchat", jid.domain());
+  EXPECT_EQ("walter@dude", jid.resource());
+  EXPECT_EQ("bowling@muchat/walter@dude", jid.Str());
+  EXPECT_EQ("bowling@muchat", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
+
+TEST(JidTest, TestFunky2) {
+  Jid jid("muchat/walter@dude");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("muchat", jid.domain());
+  EXPECT_EQ("walter@dude", jid.resource());
+  EXPECT_EQ("muchat/walter@dude", jid.Str());
+  EXPECT_EQ("muchat", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
diff --git a/third_party/libjingle_xmpp/xmpp/jingleinfotask.cc b/third_party/libjingle_xmpp/xmpp/jingleinfotask.cc
new file mode 100644
index 0000000..ccad354b
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/jingleinfotask.cc
@@ -0,0 +1,115 @@
+/*
+ *  Copyright 2010 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/jingleinfotask.h"
+
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
+#include "third_party/webrtc/base/socketaddress.h"
+
+namespace buzz {
+
+class JingleInfoTask::JingleInfoGetTask : public XmppTask {
+ public:
+  explicit JingleInfoGetTask(XmppTaskParentInterface* parent)
+      : XmppTask(parent, XmppEngine::HL_SINGLE), done_(false) {}
+
+  virtual int ProcessStart() {
+    rtc::scoped_ptr<XmlElement> get(MakeIq(STR_GET, Jid(), task_id()));
+    get->AddElement(new XmlElement(QN_JINGLE_INFO_QUERY, true));
+    if (SendStanza(get.get()) != XMPP_RETURN_OK) {
+      return STATE_ERROR;
+    }
+    return STATE_RESPONSE;
+  }
+  virtual int ProcessResponse() {
+    if (done_)
+      return STATE_DONE;
+    return STATE_BLOCKED;
+  }
+
+ protected:
+  virtual bool HandleStanza(const XmlElement* stanza) {
+    if (!MatchResponseIq(stanza, Jid(), task_id()))
+      return false;
+
+    if (stanza->Attr(QN_TYPE) != STR_RESULT)
+      return false;
+
+    // Queue the stanza with the parent so these don't get handled out of order
+    JingleInfoTask* parent = static_cast<JingleInfoTask*>(GetParent());
+    parent->QueueStanza(stanza);
+
+    // Wake ourselves so we can go into the done state
+    done_ = true;
+    Wake();
+    return true;
+  }
+
+  bool done_;
+};
+
+void JingleInfoTask::RefreshJingleInfoNow() {
+  JingleInfoGetTask* get_task = new JingleInfoGetTask(this);
+  get_task->Start();
+}
+
+bool JingleInfoTask::HandleStanza(const XmlElement* stanza) {
+  if (!MatchRequestIq(stanza, "set", QN_JINGLE_INFO_QUERY))
+    return false;
+
+  // only respect relay push from the server
+  Jid from(stanza->Attr(QN_FROM));
+  if (!from.IsEmpty() && !from.BareEquals(GetClient()->jid()) &&
+      from != Jid(GetClient()->jid().domain()))
+    return false;
+
+  QueueStanza(stanza);
+  return true;
+}
+
+int JingleInfoTask::ProcessStart() {
+  std::vector<std::string> relay_hosts;
+  std::vector<rtc::SocketAddress> stun_hosts;
+  std::string relay_token;
+  const XmlElement* stanza = NextStanza();
+  if (stanza == NULL)
+    return STATE_BLOCKED;
+  const XmlElement* query = stanza->FirstNamed(QN_JINGLE_INFO_QUERY);
+  if (query == NULL)
+    return STATE_START;
+  const XmlElement* stun = query->FirstNamed(QN_JINGLE_INFO_STUN);
+  if (stun) {
+    for (const XmlElement* server = stun->FirstNamed(QN_JINGLE_INFO_SERVER);
+         server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) {
+      std::string host = server->Attr(QN_JINGLE_INFO_HOST);
+      std::string port = server->Attr(QN_JINGLE_INFO_UDP);
+      if (host != STR_EMPTY && host != STR_EMPTY) {
+        stun_hosts.push_back(rtc::SocketAddress(host, atoi(port.c_str())));
+      }
+    }
+  }
+
+  const XmlElement* relay = query->FirstNamed(QN_JINGLE_INFO_RELAY);
+  if (relay) {
+    relay_token = relay->TextNamed(QN_JINGLE_INFO_TOKEN);
+    for (const XmlElement* server = relay->FirstNamed(QN_JINGLE_INFO_SERVER);
+         server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) {
+      std::string host = server->Attr(QN_JINGLE_INFO_HOST);
+      if (host != STR_EMPTY) {
+        relay_hosts.push_back(host);
+      }
+    }
+  }
+  SignalJingleInfo(relay_token, relay_hosts, stun_hosts);
+  return STATE_START;
+}
+}
diff --git a/third_party/libjingle_xmpp/xmpp/jingleinfotask.h b/third_party/libjingle_xmpp/xmpp/jingleinfotask.h
new file mode 100644
index 0000000..da1fa9a81
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/jingleinfotask.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 2010 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef THIRD_PARTY_XMPP_JINGLEINFOTASK_H_
+#define THIRD_PARTY_XMPP_JINGLEINFOTASK_H_
+
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
+#include "third_party/webrtc/base/sigslot.h"
+#include "third_party/webrtc/p2p/client/httpportallocator.h"
+
+namespace buzz {
+
+class JingleInfoTask : public XmppTask {
+ public:
+  explicit JingleInfoTask(XmppTaskParentInterface* parent)
+      : XmppTask(parent, XmppEngine::HL_TYPE) {}
+
+  virtual int ProcessStart();
+  void RefreshJingleInfoNow();
+
+  sigslot::signal3<const std::string&,
+                   const std::vector<std::string>&,
+                   const std::vector<rtc::SocketAddress>&>
+      SignalJingleInfo;
+
+ protected:
+  class JingleInfoGetTask;
+  friend class JingleInfoGetTask;
+
+  virtual bool HandleStanza(const XmlElement* stanza);
+};
+}
+
+#endif  // THIRD_PARTY_XMPP_JINGLEINFOTASK_H_
diff --git a/third_party/libjingle_xmpp/xmpp/plainsaslhandler.h b/third_party/libjingle_xmpp/xmpp/plainsaslhandler.h
new file mode 100644
index 0000000..894570e9
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/plainsaslhandler.h
@@ -0,0 +1,64 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
+#define WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
+
+#include <algorithm>
+#include "third_party/libjingle_xmpp/xmpp/saslhandler.h"
+#include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
+#include "third_party/webrtc/base/cryptstring.h"
+
+namespace buzz {
+
+class PlainSaslHandler : public SaslHandler {
+public:
+  PlainSaslHandler(const Jid & jid, const rtc::CryptString & password,
+      bool allow_plain) : jid_(jid), password_(password),
+                          allow_plain_(allow_plain) {}
+
+  virtual ~PlainSaslHandler() {}
+
+  // Should pick the best method according to this handler
+  // returns the empty string if none are suitable
+  virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
+
+    if (!encrypted && !allow_plain_) {
+      return "";
+    }
+
+    std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
+    if (it == mechanisms.end()) {
+      return "";
+    }
+    else {
+      return "PLAIN";
+    }
+  }
+
+  // Creates a SaslMechanism for the given mechanism name (you own it
+  // once you get it).  If not handled, return NULL.
+  virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) {
+    if (mechanism == "PLAIN") {
+      return new SaslPlainMechanism(jid_, password_);
+    }
+    return NULL;
+  }
+
+private:
+  Jid jid_;
+  rtc::CryptString password_;
+  bool allow_plain_;
+};
+
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
diff --git a/third_party/libjingle_xmpp/xmpp/prexmppauth.h b/third_party/libjingle_xmpp/xmpp/prexmppauth.h
new file mode 100644
index 0000000..92cb6db
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/prexmppauth.h
@@ -0,0 +1,71 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
+#define WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
+
+#include "third_party/libjingle_xmpp/xmpp/saslhandler.h"
+#include "third_party/webrtc/base/cryptstring.h"
+#include "third_party/webrtc/base/sigslot.h"
+
+namespace rtc {
+  class SocketAddress;
+}
+
+namespace buzz {
+
+class Jid;
+class SaslMechanism;
+
+class CaptchaChallenge {
+ public:
+  CaptchaChallenge() : captcha_needed_(false) {}
+  CaptchaChallenge(const std::string& token, const std::string& url)
+    : captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) {
+  }
+
+  bool captcha_needed() const { return captcha_needed_; }
+  const std::string& captcha_token() const { return captcha_token_; }
+
+  // This url is relative to the gaia server.  Once we have better tools
+  // for cracking URLs, we should probably make this a full URL
+  const std::string& captcha_image_url() const { return captcha_image_url_; }
+
+ private:
+  bool captcha_needed_;
+  std::string captcha_token_;
+  std::string captcha_image_url_;
+};
+
+class PreXmppAuth : public SaslHandler {
+public:
+  virtual ~PreXmppAuth() {}
+
+  virtual void StartPreXmppAuth(
+    const Jid& jid,
+    const rtc::SocketAddress& server,
+    const rtc::CryptString& pass,
+    const std::string& auth_mechanism,
+    const std::string& auth_token) = 0;
+
+  sigslot::signal0<> SignalAuthDone;
+
+  virtual bool IsAuthDone() const = 0;
+  virtual bool IsAuthorized() const = 0;
+  virtual bool HadError() const = 0;
+  virtual int GetError() const = 0;
+  virtual CaptchaChallenge GetCaptchaChallenge() const = 0;
+  virtual std::string GetAuthMechanism() const = 0;
+  virtual std::string GetAuthToken() const = 0;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h b/third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h
new file mode 100644
index 0000000..83442b95
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
+
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/saslmechanism.h"
+
+namespace buzz {
+
+class SaslCookieMechanism : public SaslMechanism {
+
+public:
+  SaslCookieMechanism(const std::string & mechanism,
+                      const std::string & username,
+                      const std::string & cookie,
+                      const std::string & token_service)
+    : mechanism_(mechanism),
+      username_(username),
+      cookie_(cookie),
+      token_service_(token_service) {}
+
+  SaslCookieMechanism(const std::string & mechanism,
+                      const std::string & username,
+                      const std::string & cookie)
+    : mechanism_(mechanism),
+      username_(username),
+      cookie_(cookie),
+      token_service_("") {}
+
+  virtual std::string GetMechanismName() { return mechanism_; }
+
+  virtual XmlElement * StartSaslAuth() {
+    // send initial request
+    XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+    el->AddAttr(QN_MECHANISM, mechanism_);
+    if (!token_service_.empty()) {
+      el->AddAttr(QN_GOOGLE_AUTH_SERVICE, token_service_);
+    }
+
+    std::string credential;
+    credential.append("\0", 1);
+    credential.append(username_);
+    credential.append("\0", 1);
+    credential.append(cookie_);
+    el->AddText(Base64Encode(credential));
+    return el;
+  }
+
+private:
+  std::string mechanism_;
+  std::string username_;
+  std::string cookie_;
+  std::string token_service_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslhandler.h b/third_party/libjingle_xmpp/xmpp/saslhandler.h
new file mode 100644
index 0000000..0dccf41
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/saslhandler.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
+
+#include <string>
+#include <vector>
+
+namespace buzz {
+
+class XmlElement;
+class SaslMechanism;
+
+// Creates mechanisms to deal with a given mechanism
+class SaslHandler {
+
+public:
+
+  // Intended to be subclassed
+  virtual ~SaslHandler() {}
+
+  // Should pick the best method according to this handler
+  // returns the empty string if none are suitable
+  virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0;
+
+  // Creates a SaslMechanism for the given mechanism name (you own it
+  // once you get it).
+  // If not handled, return NULL.
+  virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslmechanism.cc b/third_party/libjingle_xmpp/xmpp/saslmechanism.cc
new file mode 100644
index 0000000..30ac9c77
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/saslmechanism.cc
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/saslmechanism.h"
+#include "third_party/webrtc/base/base64.h"
+
+using rtc::Base64;
+
+namespace buzz {
+
+XmlElement *
+SaslMechanism::StartSaslAuth() {
+  return new XmlElement(QN_SASL_AUTH, true);
+}
+
+XmlElement *
+SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) {
+  return new XmlElement(QN_SASL_ABORT, true);
+}
+
+void
+SaslMechanism::HandleSaslSuccess(const XmlElement * success) {
+}
+
+void
+SaslMechanism::HandleSaslFailure(const XmlElement * failure) {
+}
+
+std::string
+SaslMechanism::Base64Encode(const std::string & plain) {
+  return Base64::Encode(plain);
+}
+
+std::string
+SaslMechanism::Base64Decode(const std::string & encoded) {
+  return Base64::Decode(encoded, Base64::DO_LAX);
+}
+
+std::string
+SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) {
+  std::string result;
+  Base64::EncodeFromArray(plain, length, &result);
+  return result;
+}
+
+}
diff --git a/third_party/libjingle_xmpp/xmpp/saslmechanism.h b/third_party/libjingle_xmpp/xmpp/saslmechanism.h
new file mode 100644
index 0000000..14b93df
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/saslmechanism.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
+
+#include <string>
+
+namespace buzz {
+
+class XmlElement;
+
+
+// Defines a mechnanism to do SASL authentication.
+// Subclass instances should have a self-contained way to present
+// credentials.
+class SaslMechanism {
+
+public:
+
+  // Intended to be subclassed
+  virtual ~SaslMechanism() {}
+
+  // Should return the name of the SASL mechanism, e.g., "PLAIN"
+  virtual std::string GetMechanismName() = 0;
+
+  // Should generate the initial "auth" request.  Default is just <auth/>.
+  virtual XmlElement * StartSaslAuth();
+
+  // Should respond to a SASL "<challenge>" request.  Default is
+  // to abort (for mechanisms that do not do challenge-response)
+  virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge);
+
+  // Notification of a SASL "<success>".  Sometimes information
+  // is passed on success.
+  virtual void HandleSaslSuccess(const XmlElement * success);
+
+  // Notification of a SASL "<failure>".  Sometimes information
+  // for the user is passed on failure.
+  virtual void HandleSaslFailure(const XmlElement * failure);
+
+protected:
+  static std::string Base64Encode(const std::string & plain);
+  static std::string Base64Decode(const std::string & encoded);
+  static std::string Base64EncodeFromArray(const char * plain, size_t length);
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslplainmechanism.h b/third_party/libjingle_xmpp/xmpp/saslplainmechanism.h
new file mode 100644
index 0000000..b173c52
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/saslplainmechanism.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
+
+#include "third_party/libjingle_xmpp/xmpp/saslmechanism.h"
+#include "third_party/webrtc/base/cryptstring.h"
+
+namespace buzz {
+
+class SaslPlainMechanism : public SaslMechanism {
+
+public:
+  SaslPlainMechanism(const buzz::Jid user_jid, const rtc::CryptString & password) :
+    user_jid_(user_jid), password_(password) {}
+
+  virtual std::string GetMechanismName() { return "PLAIN"; }
+
+  virtual XmlElement * StartSaslAuth() {
+    // send initial request
+    XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+    el->AddAttr(QN_MECHANISM, "PLAIN");
+
+    rtc::FormatCryptString credential;
+    credential.Append("\0", 1);
+    credential.Append(user_jid_.node());
+    credential.Append("\0", 1);
+    credential.Append(&password_);
+    el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength()));
+    return el;
+  }
+
+private:
+  Jid user_jid_;
+  rtc::CryptString password_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
diff --git a/third_party/libjingle_xmpp/xmpp/util_unittest.cc b/third_party/libjingle_xmpp/xmpp/util_unittest.cc
new file mode 100644
index 0000000..bd2b349
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/util_unittest.cc
@@ -0,0 +1,109 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/webrtc/base/gunit.h"
+
+namespace buzz {
+
+void XmppTestHandler::WriteOutput(const char * bytes, size_t len) {
+  output_ << std::string(bytes, len);
+}
+
+void XmppTestHandler::StartTls(const std::string & cname) {
+  output_ << "[START-TLS " << cname << "]";
+}
+
+void XmppTestHandler::CloseConnection() {
+  output_ << "[CLOSED]";
+}
+
+void XmppTestHandler::OnStateChange(int state) {
+  switch (static_cast<XmppEngine::State>(state)) {
+  case XmppEngine::STATE_START:
+    session_ << "[START]";
+    break;
+  case XmppEngine::STATE_OPENING:
+    session_ << "[OPENING]";
+    break;
+  case XmppEngine::STATE_OPEN:
+    session_ << "[OPEN]";
+    break;
+  case XmppEngine::STATE_CLOSED:
+    session_ << "[CLOSED]";
+    switch (engine_->GetError(NULL)) {
+    case XmppEngine::ERROR_NONE:
+      // do nothing
+      break;
+    case XmppEngine::ERROR_XML:
+      session_ << "[ERROR-XML]";
+      break;
+    case XmppEngine::ERROR_STREAM:
+      session_ << "[ERROR-STREAM]";
+      break;
+    case XmppEngine::ERROR_VERSION:
+      session_ << "[ERROR-VERSION]";
+      break;
+    case XmppEngine::ERROR_UNAUTHORIZED:
+      session_ << "[ERROR-UNAUTHORIZED]";
+      break;
+    case XmppEngine::ERROR_TLS:
+      session_ << "[ERROR-TLS]";
+      break;
+    case XmppEngine::ERROR_AUTH:
+      session_ << "[ERROR-AUTH]";
+      break;
+    case XmppEngine::ERROR_BIND:
+      session_ << "[ERROR-BIND]";
+      break;
+    case XmppEngine::ERROR_CONNECTION_CLOSED:
+      session_ << "[ERROR-CONNECTION-CLOSED]";
+      break;
+    case XmppEngine::ERROR_DOCUMENT_CLOSED:
+      session_ << "[ERROR-DOCUMENT-CLOSED]";
+      break;
+    default:
+      break;
+    }
+    break;
+  default:
+    break;
+  }
+}
+
+bool XmppTestHandler::HandleStanza(const XmlElement * stanza) {
+  stanza_ << stanza->Str();
+  return true;
+}
+
+std::string XmppTestHandler::OutputActivity() {
+  std::string result = output_.str();
+  output_.str("");
+  return result;
+}
+
+std::string XmppTestHandler::SessionActivity() {
+  std::string result = session_.str();
+  session_.str("");
+  return result;
+}
+
+std::string XmppTestHandler::StanzaActivity() {
+  std::string result = stanza_.str();
+  stanza_.str("");
+  return result;
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmpp/util_unittest.h b/third_party/libjingle_xmpp/xmpp/util_unittest.h
new file mode 100644
index 0000000..c0f796aa
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/util_unittest.h
@@ -0,0 +1,58 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
+#define WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
+
+#include <sstream>
+#include <string>
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+
+namespace buzz {
+
+// This class captures callbacks from engine.
+class XmppTestHandler : public XmppOutputHandler,  public XmppSessionHandler,
+                        public XmppStanzaHandler {
+ public:
+  explicit XmppTestHandler(XmppEngine* engine) : engine_(engine) {}
+  virtual ~XmppTestHandler() {}
+
+  void SetEngine(XmppEngine* engine);
+
+  // Output handler
+  virtual void WriteOutput(const char * bytes, size_t len);
+  virtual void StartTls(const std::string & cname);
+  virtual void CloseConnection();
+
+  // Session handler
+  virtual void OnStateChange(int state);
+
+  // Stanza handler
+  virtual bool HandleStanza(const XmlElement* stanza);
+
+  std::string OutputActivity();
+  std::string SessionActivity();
+  std::string StanzaActivity();
+
+ private:
+  XmppEngine* engine_;
+  std::stringstream output_;
+  std::stringstream session_;
+  std::stringstream stanza_;
+};
+
+}  // namespace buzz
+
+inline std::ostream& operator<<(std::ostream& os, const buzz::Jid& jid) {
+  os << jid.Str();
+  return os;
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppclient.cc b/third_party/libjingle_xmpp/xmpp/xmppclient.cc
new file mode 100644
index 0000000..c8b0265
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppclient.cc
@@ -0,0 +1,423 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
+
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/plainsaslhandler.h"
+#include "third_party/libjingle_xmpp/xmpp/prexmppauth.h"
+#include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
+#include "third_party/webrtc/base/sigslot.h"
+#include "third_party/webrtc/base/stringutils.h"
+#include "third_party/webrtc_overrides/webrtc/base/logging.h"
+#include "xmpptask.h"
+
+namespace buzz {
+
+class XmppClient::Private :
+    public sigslot::has_slots<>,
+    public XmppSessionHandler,
+    public XmppOutputHandler {
+public:
+
+  explicit Private(XmppClient* client) :
+    client_(client),
+    socket_(),
+    engine_(),
+    proxy_port_(0),
+    pre_engine_error_(XmppEngine::ERROR_NONE),
+    pre_engine_subcode_(0),
+    signal_closed_(false),
+    allow_plain_(false) {}
+
+  virtual ~Private() {
+    // We need to disconnect from socket_ before engine_ is destructed (by
+    // the auto-generated destructor code).
+    ResetSocket();
+  }
+
+  // the owner
+  XmppClient* const client_;
+
+  // the two main objects
+  std::unique_ptr<AsyncSocket> socket_;
+  std::unique_ptr<XmppEngine> engine_;
+  std::unique_ptr<PreXmppAuth> pre_auth_;
+  rtc::CryptString pass_;
+  std::string auth_mechanism_;
+  std::string auth_token_;
+  rtc::SocketAddress server_;
+  std::string proxy_host_;
+  int proxy_port_;
+  XmppEngine::Error pre_engine_error_;
+  int pre_engine_subcode_;
+  CaptchaChallenge captcha_challenge_;
+  bool signal_closed_;
+  bool allow_plain_;
+
+  void ResetSocket() {
+    if (socket_) {
+      socket_->SignalConnected.disconnect(this);
+      socket_->SignalRead.disconnect(this);
+      socket_->SignalClosed.disconnect(this);
+      socket_.reset(NULL);
+    }
+  }
+
+  // implementations of interfaces
+  void OnStateChange(int state);
+  void WriteOutput(const char* bytes, size_t len);
+  void StartTls(const std::string& domainname);
+  void CloseConnection();
+
+  // slots for socket signals
+  void OnSocketConnected();
+  void OnSocketRead();
+  void OnSocketClosed();
+};
+
+bool IsTestServer(const std::string& server_name,
+                  const std::string& test_server_domain) {
+  return (!test_server_domain.empty() &&
+          rtc::ends_with(server_name.c_str(),
+                               test_server_domain.c_str()));
+}
+
+XmppReturnStatus XmppClient::Connect(
+    const XmppClientSettings& settings,
+    const std::string& lang, AsyncSocket* socket, PreXmppAuth* pre_auth) {
+  if (socket == NULL)
+    return XMPP_RETURN_BADARGUMENT;
+  if (d_->socket_)
+    return XMPP_RETURN_BADSTATE;
+
+  d_->socket_.reset(socket);
+
+  d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected);
+  d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead);
+  d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed);
+
+  d_->engine_.reset(XmppEngine::Create());
+  d_->engine_->SetSessionHandler(d_.get());
+  d_->engine_->SetOutputHandler(d_.get());
+  if (!settings.resource().empty()) {
+    d_->engine_->SetRequestedResource(settings.resource());
+  }
+  d_->engine_->SetTls(settings.use_tls());
+
+  // The talk.google.com server returns a certificate with common-name:
+  //   CN="gmail.com" for @gmail.com accounts,
+  //   CN="googlemail.com" for @googlemail.com accounts,
+  //   CN="talk.google.com" for other accounts (such as @example.com),
+  // so we tweak the tls server setting for those other accounts to match the
+  // returned certificate CN of "talk.google.com".
+  // For other servers, we leave the strings empty, which causes the jid's
+  // domain to be used.  We do the same for gmail.com and googlemail.com as the
+  // returned CN matches the account domain in those cases.
+  std::string server_name = settings.server().HostAsURIString();
+  if (server_name == buzz::STR_TALK_GOOGLE_COM ||
+      server_name == buzz::STR_TALKX_L_GOOGLE_COM ||
+      server_name == buzz::STR_XMPP_GOOGLE_COM ||
+      server_name == buzz::STR_XMPPX_L_GOOGLE_COM ||
+      IsTestServer(server_name, settings.test_server_domain())) {
+    if (settings.host() != STR_GMAIL_COM &&
+        settings.host() != STR_GOOGLEMAIL_COM) {
+      d_->engine_->SetTlsServer("", STR_TALK_GOOGLE_COM);
+    }
+  }
+
+  // Set language
+  d_->engine_->SetLanguage(lang);
+
+  d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY));
+
+  d_->pass_ = settings.pass();
+  d_->auth_mechanism_ = settings.auth_mechanism();
+  d_->auth_token_ = settings.auth_token();
+  d_->server_ = settings.server();
+  d_->proxy_host_ = settings.proxy_host();
+  d_->proxy_port_ = settings.proxy_port();
+  d_->allow_plain_ = settings.allow_plain();
+  d_->pre_auth_.reset(pre_auth);
+
+  return XMPP_RETURN_OK;
+}
+
+XmppEngine::State XmppClient::GetState() const {
+  if (!d_->engine_)
+    return XmppEngine::STATE_NONE;
+  return d_->engine_->GetState();
+}
+
+XmppEngine::Error XmppClient::GetError(int* subcode) {
+  if (subcode) {
+    *subcode = 0;
+  }
+  if (!d_->engine_)
+    return XmppEngine::ERROR_NONE;
+  if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE) {
+    if (subcode) {
+      *subcode = d_->pre_engine_subcode_;
+    }
+    return d_->pre_engine_error_;
+  }
+  return d_->engine_->GetError(subcode);
+}
+
+const XmlElement* XmppClient::GetStreamError() {
+  if (!d_->engine_) {
+    return NULL;
+  }
+  return d_->engine_->GetStreamError();
+}
+
+CaptchaChallenge XmppClient::GetCaptchaChallenge() {
+  if (!d_->engine_)
+    return CaptchaChallenge();
+  return d_->captcha_challenge_;
+}
+
+std::string XmppClient::GetAuthMechanism() {
+  if (!d_->engine_)
+    return "";
+  return d_->auth_mechanism_;
+}
+
+std::string XmppClient::GetAuthToken() {
+  if (!d_->engine_)
+    return "";
+  return d_->auth_token_;
+}
+
+int XmppClient::ProcessStart() {
+  // Should not happen, but was observed in crash reports
+  if (!d_->socket_) {
+    LOG(LS_ERROR) << "socket_ already reset";
+    return STATE_DONE;
+  }
+
+  if (d_->pre_auth_) {
+    d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone);
+    d_->pre_auth_->StartPreXmppAuth(
+        d_->engine_->GetUser(), d_->server_, d_->pass_,
+        d_->auth_mechanism_, d_->auth_token_);
+    d_->pass_.Clear(); // done with this;
+    return STATE_PRE_XMPP_LOGIN;
+  }
+  else {
+    d_->engine_->SetSaslHandler(new PlainSaslHandler(
+              d_->engine_->GetUser(), d_->pass_, d_->allow_plain_));
+    d_->pass_.Clear(); // done with this;
+    return STATE_START_XMPP_LOGIN;
+  }
+}
+
+void XmppClient::OnAuthDone() {
+  Wake();
+}
+
+int XmppClient::ProcessTokenLogin() {
+  // Should not happen, but was observed in crash reports
+  if (!d_->socket_) {
+    LOG(LS_ERROR) << "socket_ already reset";
+    return STATE_DONE;
+  }
+
+  // Don't know how this could happen, but crash reports show it as NULL
+  if (!d_->pre_auth_) {
+    d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+    EnsureClosed();
+    return STATE_ERROR;
+  }
+
+  // Wait until pre authentication is done is done
+  if (!d_->pre_auth_->IsAuthDone())
+    return STATE_BLOCKED;
+
+  if (!d_->pre_auth_->IsAuthorized()) {
+    // maybe split out a case when gaia is down?
+    if (d_->pre_auth_->HadError()) {
+      d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+      d_->pre_engine_subcode_ = d_->pre_auth_->GetError();
+    }
+    else {
+      d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED;
+      d_->pre_engine_subcode_ = 0;
+      d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge();
+    }
+    d_->pre_auth_.reset(NULL); // done with this
+    EnsureClosed();
+    return STATE_ERROR;
+  }
+
+  // Save auth token as a result
+
+  d_->auth_mechanism_ = d_->pre_auth_->GetAuthMechanism();
+  d_->auth_token_ = d_->pre_auth_->GetAuthToken();
+
+  // transfer ownership of pre_auth_ to engine
+  d_->engine_->SetSaslHandler(d_->pre_auth_.release());
+  return STATE_START_XMPP_LOGIN;
+}
+
+int XmppClient::ProcessStartXmppLogin() {
+  // Should not happen, but was observed in crash reports
+  if (!d_->socket_) {
+    LOG(LS_ERROR) << "socket_ already reset";
+    return STATE_DONE;
+  }
+
+  // Done with pre-connect tasks - connect!
+  if (!d_->socket_->Connect(d_->server_)) {
+    EnsureClosed();
+    return STATE_ERROR;
+  }
+
+  return STATE_RESPONSE;
+}
+
+int XmppClient::ProcessResponse() {
+  // Hang around while we are connected.
+  if (!delivering_signal_ &&
+      (!d_->engine_ || d_->engine_->GetState() == XmppEngine::STATE_CLOSED))
+    return STATE_DONE;
+  return STATE_BLOCKED;
+}
+
+XmppReturnStatus XmppClient::Disconnect() {
+  if (!d_->socket_)
+    return XMPP_RETURN_BADSTATE;
+  Abort();
+  d_->engine_->Disconnect();
+  d_->ResetSocket();
+  return XMPP_RETURN_OK;
+}
+
+XmppClient::XmppClient(TaskParent* parent)
+    : XmppTaskParentInterface(parent),
+      delivering_signal_(false),
+      valid_(false) {
+  d_.reset(new Private(this));
+  valid_ = true;
+}
+
+XmppClient::~XmppClient() {
+  valid_ = false;
+}
+
+const Jid& XmppClient::jid() const {
+  return d_->engine_->FullJid();
+}
+
+
+std::string XmppClient::NextId() {
+  return d_->engine_->NextId();
+}
+
+XmppReturnStatus XmppClient::SendStanza(const XmlElement* stanza) {
+  return d_->engine_->SendStanza(stanza);
+}
+
+XmppReturnStatus XmppClient::SendStanzaError(
+    const XmlElement* old_stanza, XmppStanzaError xse,
+    const std::string& message) {
+  return d_->engine_->SendStanzaError(old_stanza, xse, message);
+}
+
+XmppReturnStatus XmppClient::SendRaw(const std::string& text) {
+  return d_->engine_->SendRaw(text);
+}
+
+XmppEngine* XmppClient::engine() {
+  return d_->engine_.get();
+}
+
+void XmppClient::Private::OnSocketConnected() {
+  engine_->Connect();
+}
+
+void XmppClient::Private::OnSocketRead() {
+  char bytes[4096];
+  size_t bytes_read;
+  for (;;) {
+    // Should not happen, but was observed in crash reports
+    if (!socket_) {
+      LOG(LS_ERROR) << "socket_ already reset";
+      return;
+    }
+
+    if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) {
+      // TODO: deal with error information
+      return;
+    }
+
+    if (bytes_read == 0)
+      return;
+
+//#if !defined(NDEBUG)
+    client_->SignalLogInput(bytes, static_cast<int>(bytes_read));
+//#endif
+
+    engine_->HandleInput(bytes, bytes_read);
+  }
+}
+
+void XmppClient::Private::OnSocketClosed() {
+  int code = socket_->GetError();
+  engine_->ConnectionClosed(code);
+}
+
+void XmppClient::Private::OnStateChange(int state) {
+  if (state == XmppEngine::STATE_CLOSED) {
+    client_->EnsureClosed();
+  }
+  else {
+    client_->SignalStateChange((XmppEngine::State)state);
+  }
+  client_->Wake();
+}
+
+void XmppClient::Private::WriteOutput(const char* bytes, size_t len) {
+//#if !defined(NDEBUG)
+  client_->SignalLogOutput(bytes, static_cast<int>(len));
+//#endif
+
+  socket_->Write(bytes, len);
+  // TODO: deal with error information
+}
+
+void XmppClient::Private::StartTls(const std::string& domain) {
+#if defined(FEATURE_ENABLE_SSL)
+  socket_->StartTls(domain);
+#endif
+}
+
+void XmppClient::Private::CloseConnection() {
+  socket_->Close();
+}
+
+void XmppClient::AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) {
+  d_->engine_->AddStanzaHandler(task, level);
+}
+
+void XmppClient::RemoveXmppTask(XmppTask* task) {
+  d_->engine_->RemoveStanzaHandler(task);
+}
+
+void XmppClient::EnsureClosed() {
+  if (!d_->signal_closed_) {
+    d_->signal_closed_ = true;
+    delivering_signal_ = true;
+    SignalStateChange(XmppEngine::STATE_CLOSED);
+    delivering_signal_ = false;
+  }
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmpp/xmppclient.h b/third_party/libjingle_xmpp/xmpp/xmppclient.h
new file mode 100644
index 0000000..e3acb63a
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppclient.h
@@ -0,0 +1,149 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
+
+#include <memory>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmpp/asyncsocket.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
+#include "third_party/webrtc/base/sigslot.h"
+#include "third_party/webrtc/base/task.h"
+
+namespace buzz {
+
+class PreXmppAuth;
+class CaptchaChallenge;
+
+// Just some non-colliding number.  Could have picked "1".
+#define XMPP_CLIENT_TASK_CODE 0x366c1e47
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPCLIENT
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task first.  XmppClient is a parent task for XmppTasks.
+//
+// XmppClient is a task which is designed to be the parent task for
+// all tasks that depend on a single Xmpp connection.  If you want to,
+// for example, listen for subscription requests forever, then your
+// listener should be a task that is a child of the XmppClient that owns
+// the connection you are using.  XmppClient has all the utility methods
+// that basically drill through to XmppEngine.
+//
+// XmppClient is just a wrapper for XmppEngine, and if I were writing it
+// all over again, I would make XmppClient == XmppEngine.  Why?
+// XmppEngine needs tasks too, for example it has an XmppLoginTask which
+// should just be the same kind of Task instead of an XmppEngine specific
+// thing.  It would help do certain things like GAIA auth cleaner.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppClient : public XmppTaskParentInterface,
+                   public XmppClientInterface,
+                   public sigslot::has_slots<>
+{
+public:
+  explicit XmppClient(rtc::TaskParent * parent);
+  virtual ~XmppClient();
+
+  XmppReturnStatus Connect(const XmppClientSettings & settings,
+                           const std::string & lang,
+                           AsyncSocket * socket,
+                           PreXmppAuth * preauth);
+
+  virtual int ProcessStart();
+  virtual int ProcessResponse();
+  XmppReturnStatus Disconnect();
+
+  sigslot::signal1<XmppEngine::State> SignalStateChange;
+  XmppEngine::Error GetError(int *subcode);
+
+  // When there is a <stream:error> stanza, return the stanza
+  // so that they can be handled.
+  const XmlElement *GetStreamError();
+
+  // When there is an authentication error, we may have captcha info
+  // that the user can use to unlock their account
+  CaptchaChallenge GetCaptchaChallenge();
+
+  // When authentication is successful, this returns the service token
+  // (if we used GAIA authentication)
+  std::string GetAuthMechanism();
+  std::string GetAuthToken();
+
+  XmppReturnStatus SendRaw(const std::string & text);
+
+  XmppEngine* engine();
+
+  sigslot::signal2<const char *, int> SignalLogInput;
+  sigslot::signal2<const char *, int> SignalLogOutput;
+
+  // As XmppTaskParentIntreface
+  virtual XmppClientInterface* GetClient() { return this; }
+
+  // As XmppClientInterface
+  virtual XmppEngine::State GetState() const;
+  virtual const Jid& jid() const;
+  virtual std::string NextId();
+  virtual XmppReturnStatus SendStanza(const XmlElement *stanza);
+  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+                                           XmppStanzaError code,
+                                           const std::string & text);
+  virtual void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
+  virtual void RemoveXmppTask(XmppTask *);
+
+ private:
+  friend class XmppTask;
+
+  void OnAuthDone();
+
+  // Internal state management
+  enum {
+    STATE_PRE_XMPP_LOGIN = STATE_NEXT,
+    STATE_START_XMPP_LOGIN = STATE_NEXT + 1,
+  };
+  int Process(int state) {
+    switch (state) {
+      case STATE_PRE_XMPP_LOGIN: return ProcessTokenLogin();
+      case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin();
+      default: return Task::Process(state);
+    }
+  }
+
+  std::string GetStateName(int state) const {
+    switch (state) {
+      case STATE_PRE_XMPP_LOGIN:      return "PRE_XMPP_LOGIN";
+      case STATE_START_XMPP_LOGIN:  return "START_XMPP_LOGIN";
+      default: return Task::GetStateName(state);
+    }
+  }
+
+  int ProcessTokenLogin();
+  int ProcessStartXmppLogin();
+  void EnsureClosed();
+
+  class Private;
+  friend class Private;
+  std::unique_ptr<Private> d_;
+
+  bool delivering_signal_;
+  bool valid_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppclientsettings.h b/third_party/libjingle_xmpp/xmpp/xmppclientsettings.h
new file mode 100644
index 0000000..a60ab97
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppclientsettings.h
@@ -0,0 +1,111 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
+
+#include "third_party/webrtc/p2p/base/port.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/webrtc/base/cryptstring.h"
+
+namespace buzz {
+
+class XmppUserSettings {
+ public:
+  XmppUserSettings()
+    : use_tls_(buzz::TLS_DISABLED),
+      allow_plain_(false) {
+  }
+
+  void set_user(const std::string& user) { user_ = user; }
+  void set_host(const std::string& host) { host_ = host; }
+  void set_pass(const rtc::CryptString& pass) { pass_ = pass; }
+  void set_auth_token(const std::string& mechanism,
+                      const std::string& token) {
+    auth_mechanism_ = mechanism;
+    auth_token_ = token;
+  }
+  void set_resource(const std::string& resource) { resource_ = resource; }
+  void set_use_tls(const TlsOptions use_tls) { use_tls_ = use_tls; }
+  void set_allow_plain(bool f) { allow_plain_ = f; }
+  void set_test_server_domain(const std::string& test_server_domain) {
+    test_server_domain_ = test_server_domain;
+  }
+  void set_token_service(const std::string& token_service) {
+    token_service_ = token_service;
+  }
+
+  const std::string& user() const { return user_; }
+  const std::string& host() const { return host_; }
+  const rtc::CryptString& pass() const { return pass_; }
+  const std::string& auth_mechanism() const { return auth_mechanism_; }
+  const std::string& auth_token() const { return auth_token_; }
+  const std::string& resource() const { return resource_; }
+  TlsOptions use_tls() const { return use_tls_; }
+  bool allow_plain() const { return allow_plain_; }
+  const std::string& test_server_domain() const { return test_server_domain_; }
+  const std::string& token_service() const { return token_service_; }
+
+ private:
+  std::string user_;
+  std::string host_;
+  rtc::CryptString pass_;
+  std::string auth_mechanism_;
+  std::string auth_token_;
+  std::string resource_;
+  TlsOptions use_tls_;
+  bool allow_plain_;
+  std::string test_server_domain_;
+  std::string token_service_;
+};
+
+class XmppClientSettings : public XmppUserSettings {
+ public:
+  XmppClientSettings()
+    : protocol_(cricket::PROTO_TCP),
+      proxy_(rtc::PROXY_NONE),
+      proxy_port_(80),
+      use_proxy_auth_(false) {
+  }
+
+  void set_server(const rtc::SocketAddress& server) {
+      server_ = server;
+  }
+  void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; }
+  void set_proxy(rtc::ProxyType f) { proxy_ = f; }
+  void set_proxy_host(const std::string& host) { proxy_host_ = host; }
+  void set_proxy_port(int port) { proxy_port_ = port; };
+  void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; }
+  void set_proxy_user(const std::string& user) { proxy_user_ = user; }
+  void set_proxy_pass(const rtc::CryptString& pass) { proxy_pass_ = pass; }
+
+  const rtc::SocketAddress& server() const { return server_; }
+  cricket::ProtocolType protocol() const { return protocol_; }
+  rtc::ProxyType proxy() const { return proxy_; }
+  const std::string& proxy_host() const { return proxy_host_; }
+  int proxy_port() const { return proxy_port_; }
+  bool use_proxy_auth() const { return use_proxy_auth_; }
+  const std::string& proxy_user() const { return proxy_user_; }
+  const rtc::CryptString& proxy_pass() const { return proxy_pass_; }
+
+ private:
+  rtc::SocketAddress server_;
+  cricket::ProtocolType protocol_;
+  rtc::ProxyType proxy_;
+  std::string proxy_host_;
+  int proxy_port_;
+  bool use_proxy_auth_;
+  std::string proxy_user_;
+  rtc::CryptString proxy_pass_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengine.h b/third_party/libjingle_xmpp/xmpp/xmppengine.h
new file mode 100644
index 0000000..fbbcf08
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppengine.h
@@ -0,0 +1,332 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
+
+// also part of the API
+#include "third_party/libjingle_xmpp/xmllite/qname.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+
+
+namespace buzz {
+
+class XmppEngine;
+class SaslHandler;
+typedef void * XmppIqCookie;
+
+//! XMPP stanza error codes.
+//! Used in XmppEngine.SendStanzaError().
+enum XmppStanzaError {
+  XSE_BAD_REQUEST,
+  XSE_CONFLICT,
+  XSE_FEATURE_NOT_IMPLEMENTED,
+  XSE_FORBIDDEN,
+  XSE_GONE,
+  XSE_INTERNAL_SERVER_ERROR,
+  XSE_ITEM_NOT_FOUND,
+  XSE_JID_MALFORMED,
+  XSE_NOT_ACCEPTABLE,
+  XSE_NOT_ALLOWED,
+  XSE_PAYMENT_REQUIRED,
+  XSE_RECIPIENT_UNAVAILABLE,
+  XSE_REDIRECT,
+  XSE_REGISTRATION_REQUIRED,
+  XSE_SERVER_NOT_FOUND,
+  XSE_SERVER_TIMEOUT,
+  XSE_RESOURCE_CONSTRAINT,
+  XSE_SERVICE_UNAVAILABLE,
+  XSE_SUBSCRIPTION_REQUIRED,
+  XSE_UNDEFINED_CONDITION,
+  XSE_UNEXPECTED_REQUEST,
+};
+
+// XmppReturnStatus
+//    This is used by API functions to synchronously return status.
+enum XmppReturnStatus {
+  XMPP_RETURN_OK,
+  XMPP_RETURN_BADARGUMENT,
+  XMPP_RETURN_BADSTATE,
+  XMPP_RETURN_PENDING,
+  XMPP_RETURN_UNEXPECTED,
+  XMPP_RETURN_NOTYETIMPLEMENTED,
+};
+
+// TlsOptions
+//    This is used by API to identify TLS setting.
+enum TlsOptions {
+  TLS_DISABLED,
+  TLS_ENABLED,
+  TLS_REQUIRED
+};
+
+//! Callback for socket output for an XmppEngine connection.
+//! Register via XmppEngine.SetOutputHandler.  An XmppEngine
+//! can call back to this handler while it is processing
+//! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
+class XmppOutputHandler {
+public:
+  virtual ~XmppOutputHandler() {}
+
+  //! Deliver the specified bytes to the XMPP socket.
+  virtual void WriteOutput(const char * bytes, size_t len) = 0;
+
+  //! Initiate TLS encryption on the socket.
+  //! The implementation must verify that the SSL
+  //! certificate matches the given domainname.
+  virtual void StartTls(const std::string & domainname) = 0;
+
+  //! Called when engine wants the connecton closed.
+  virtual void CloseConnection() = 0;
+};
+
+//! Callback to deliver engine state change notifications
+//! to the object managing the engine.
+class XmppSessionHandler {
+public:
+  virtual ~XmppSessionHandler() {}
+  //! Called when engine changes state. Argument is new state.
+  virtual void OnStateChange(int state) = 0;
+};
+
+//! Callback to deliver stanzas to an Xmpp application module.
+//! Register via XmppEngine.SetDefaultSessionHandler or via
+//! XmppEngine.AddSessionHAndler.
+class XmppStanzaHandler {
+public:
+  virtual ~XmppStanzaHandler() {}
+  //! Process the given stanza.
+  //! The handler must return true if it has handled the stanza.
+  //! A false return value causes the stanza to be passed on to
+  //! the next registered handler.
+  virtual bool HandleStanza(const XmlElement * stanza) = 0;
+};
+
+//! Callback to deliver iq responses (results and errors).
+//! Register while sending an iq via XmppEngine.SendIq.
+//! Iq responses are routed to matching XmppIqHandlers in preference
+//! to sending to any registered SessionHandlers.
+class XmppIqHandler {
+public:
+  virtual ~XmppIqHandler() {}
+  //! Called to handle the iq response.
+  //! The response may be either a result or an error, and will have
+  //! an 'id' that matches the request and a 'from' that matches the
+  //! 'to' of the request.  Called no more than once; once this is
+  //! called, the handler is automatically unregistered.
+  virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
+};
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput.  Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngine {
+public:
+  static XmppEngine * Create();
+  virtual ~XmppEngine() {}
+
+  //! Error codes. See GetError().
+  enum Error {
+    ERROR_NONE = 0,         //!< No error
+    ERROR_XML,              //!< Malformed XML or encoding error
+    ERROR_STREAM,           //!< XMPP stream error - see GetStreamError()
+    ERROR_VERSION,          //!< XMPP version error
+    ERROR_UNAUTHORIZED,     //!< User is not authorized (rejected credentials)
+    ERROR_TLS,              //!< TLS could not be negotiated
+    ERROR_AUTH,             //!< Authentication could not be negotiated
+    ERROR_BIND,             //!< Resource or session binding could not be negotiated
+    ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
+    ERROR_DOCUMENT_CLOSED,  //!< Closed by </stream:stream>
+    ERROR_SOCKET,           //!< Socket error
+    ERROR_NETWORK_TIMEOUT,  //!< Some sort of timeout (eg., we never got the roster)
+    ERROR_MISSING_USERNAME  //!< User has a Google Account but no nickname
+  };
+
+  //! States.  See GetState().
+  enum State {
+    STATE_NONE = 0,        //!< Nonexistent state
+    STATE_START,           //!< Initial state.
+    STATE_OPENING,         //!< Exchanging stream headers, authenticating and so on.
+    STATE_OPEN,            //!< Authenticated and bound.
+    STATE_CLOSED,          //!< Session closed, possibly due to error.
+  };
+
+  // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+  //! Registers the handler for socket output
+  virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
+
+  //! Provides socket input to the engine
+  virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
+
+  //! Advises the engine that the socket has closed
+  virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
+
+  // SESSION SETUP ---------------------------------------------------------
+
+  //! Indicates the (bare) JID for the user to use.
+  virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
+
+  //! Get the login (bare) JID.
+  virtual const Jid & GetUser() = 0;
+
+  //! Provides different methods for credentials for login.
+  //! Takes ownership of this object; deletes when login is done
+  virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
+
+  //! Sets whether TLS will be used within the connection (default true).
+  virtual XmppReturnStatus SetTls(TlsOptions useTls) = 0;
+
+  //! Sets an alternate domain from which we allows TLS certificates.
+  //! This is for use in the case where a we want to allow a proxy to
+  //! serve up its own certificate rather than one owned by the underlying
+  //! domain.
+  virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
+                                        const std::string & proxy_domain) = 0;
+
+  //! Gets whether TLS will be used within the connection.
+  virtual TlsOptions GetTls() = 0;
+
+  //! Sets the request resource name, if any (optional).
+  //! Note that the resource name may be overridden by the server; after
+  //! binding, the actual resource name is available as part of FullJid().
+  virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
+
+  //! Gets the request resource name.
+  virtual const std::string & GetRequestedResource() = 0;
+
+  //! Sets language
+  virtual void SetLanguage(const std::string & lang) = 0;
+
+  // SESSION MANAGEMENT ---------------------------------------------------
+
+  //! Set callback for state changes.
+  virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
+
+  //! Initiates the XMPP connection.
+  //! After supplying connection settings, call this once to initiate,
+  //! (optionally) encrypt, authenticate, and bind the connection.
+  virtual XmppReturnStatus Connect() = 0;
+
+  //! The current engine state.
+  virtual State GetState() = 0;
+
+  //! Returns true if the connection is encrypted (under TLS)
+  virtual bool IsEncrypted() = 0;
+
+  //! The error code.
+  //! Consult this after XmppOutputHandler.OnClose().
+  virtual Error GetError(int *subcode) = 0;
+
+  //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
+  //! Notice the stanza returned is owned by the XmppEngine and
+  //! is deleted when the engine is destroyed.
+  virtual const XmlElement * GetStreamError() = 0;
+
+  //! Closes down the connection.
+  //! Sends CloseConnection to output, and disconnects and registered
+  //! session handlers.  After Disconnect completes, it is guaranteed
+  //! that no further callbacks will be made.
+  virtual XmppReturnStatus Disconnect() = 0;
+
+  // APPLICATION USE -------------------------------------------------------
+
+  enum HandlerLevel {
+    HL_NONE = 0,
+    HL_PEEK,   //!< Sees messages before all other processing; cannot abort
+    HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
+    HL_SENDER, //!< Watches for a type of message from a specific sender
+    HL_TYPE,   //!< Watches a type of message, e.g., all groupchat msgs
+    HL_ALL,    //!< Watches all messages - gets last shot
+    HL_COUNT,  //!< Count of handler levels
+  };
+
+  //! Adds a listener for session events.
+  //! Stanza delivery is chained to session handlers; the first to
+  //! return 'true' is the last to get each stanza.
+  virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
+
+  //! Removes a listener for session events.
+  virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
+
+  //! Sends a stanza to the server.
+  virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
+
+  //! Sends raw text to the server
+  virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
+
+  //! Sends an iq to the server, and registers a callback for the result.
+  //! Returns the cookie passed to the result handler.
+  virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
+                                  XmppIqHandler* iq_handler,
+                                  XmppIqCookie* cookie) = 0;
+
+  //! Unregisters an iq callback handler given its cookie.
+  //! No callback will come to this handler after it's unregistered.
+  virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+                                      XmppIqHandler** iq_handler) = 0;
+
+
+  //! Forms and sends an error in response to the given stanza.
+  //! Swaps to and from, sets type to "error", and adds error information
+  //! based on the passed code.  Text is optional and may be STR_EMPTY.
+  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+                                           XmppStanzaError code,
+                                           const std::string & text) = 0;
+
+  //! The fullly bound JID.
+  //! This JID is only valid after binding has succeeded.  If the value
+  //! is JID_NULL, the binding has not succeeded.
+  virtual const Jid & FullJid() = 0;
+
+  //! The next unused iq id for this connection.
+  //! Call this when building iq stanzas, to ensure that each iq
+  //! gets its own unique id.
+  virtual std::string NextId() = 0;
+
+};
+
+}
+
+
+// Move these to a better location
+
+#define XMPP_FAILED(x)                      \
+  ( (x) == buzz::XMPP_RETURN_OK ? false : true)   \
+
+
+#define XMPP_SUCCEEDED(x)                   \
+  ( (x) == buzz::XMPP_RETURN_OK ? true : false)   \
+
+#define IFR(x)                        \
+  do {                                \
+    xmpp_status = (x);                \
+    if (XMPP_FAILED(xmpp_status)) {   \
+      return xmpp_status;             \
+    }                                 \
+  } while (false)                     \
+
+
+#define IFC(x)                        \
+  do {                                \
+    xmpp_status = (x);                \
+    if (XMPP_FAILED(xmpp_status)) {   \
+      goto Cleanup;                   \
+    }                                 \
+  } while (false)                     \
+
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
new file mode 100644
index 0000000..93c8189
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
@@ -0,0 +1,327 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/plainsaslhandler.h"
+#include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
+#include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::Jid;
+using buzz::QName;
+using buzz::XmlElement;
+using buzz::XmppEngine;
+using buzz::XmppIqCookie;
+using buzz::XmppIqHandler;
+using buzz::XmppTestHandler;
+using buzz::QN_ID;
+using buzz::QN_IQ;
+using buzz::QN_TYPE;
+using buzz::QN_ROSTER_QUERY;
+using buzz::XMPP_RETURN_OK;
+using buzz::XMPP_RETURN_BADARGUMENT;
+
+// XmppEngineTestIqHandler
+//    This class grabs the response to an IQ stanza and stores it in a string.
+class XmppEngineTestIqHandler : public XmppIqHandler {
+ public:
+  virtual void IqResponse(XmppIqCookie, const XmlElement * stanza) {
+    ss_ << stanza->Str();
+  }
+
+  std::string IqResponseActivity() {
+    std::string result = ss_.str();
+    ss_.str("");
+    return result;
+  }
+
+ private:
+  std::stringstream ss_;
+};
+
+class XmppEngineTest : public testing::Test {
+ public:
+  XmppEngine* engine() { return engine_.get(); }
+  XmppTestHandler* handler() { return handler_.get(); }
+  virtual void SetUp() {
+    engine_.reset(XmppEngine::Create());
+    handler_.reset(new XmppTestHandler(engine_.get()));
+
+    Jid jid("david@my-server");
+    rtc::InsecureCryptStringImpl pass;
+    pass.password() = "david";
+    engine_->SetSessionHandler(handler_.get());
+    engine_->SetOutputHandler(handler_.get());
+    engine_->AddStanzaHandler(handler_.get());
+    engine_->SetUser(jid);
+    engine_->SetSaslHandler(
+        new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true));
+  }
+  virtual void TearDown() {
+    handler_.reset();
+    engine_.reset();
+  }
+  void RunLogin();
+
+ private:
+  std::unique_ptr<XmppEngine> engine_;
+  std::unique_ptr<XmppTestHandler> handler_;
+};
+
+void XmppEngineTest::RunLogin() {
+  // Connect
+  EXPECT_EQ(XmppEngine::STATE_START, engine()->GetState());
+  engine()->Connect();
+  EXPECT_EQ(XmppEngine::STATE_OPENING, engine()->GetState());
+
+  EXPECT_EQ("[OPENING]", handler_->SessionActivity());
+
+  EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" "
+           "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+           "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+
+  std::string input =
+    "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+    "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+    "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  input =
+    "<stream:features>"
+      "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>"
+        "<required/>"
+      "</starttls>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+    "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
+      handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("[START-TLS my-server]"
+           "<stream:stream to=\"my-server\" xml:lang=\"*\" "
+           "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+           "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<stream:stream id=\"01234567\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  input =
+    "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+    "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" "
+      "auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>",
+      handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<stream:stream id=\"01234567\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  input = "<stream:features>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
+          "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
+          "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<iq type=\"set\" id=\"0\">"
+           "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>",
+           handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<iq type='result' id='0'>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>"
+          "david@my-server/test</jid></bind></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<iq type=\"set\" id=\"1\">"
+           "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>",
+           handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<iq type='result' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[OPEN]", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+  EXPECT_EQ(Jid("david@my-server/test"), engine()->FullJid());
+}
+
+// TestSuccessfulLogin()
+//    This function simply tests to see if a login works.  This includes
+//    encryption and authentication
+TEST_F(XmppEngineTest, TestSuccessfulLoginAndDisconnect) {
+  RunLogin();
+  engine()->Disconnect();
+  EXPECT_EQ("</stream:stream>[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppEngineTest, TestSuccessfulLoginAndConnectionClosed) {
+  RunLogin();
+  engine()->ConnectionClosed(0);
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-CONNECTION-CLOSED]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+
+// TestNotXmpp()
+//    This tests the error case when connecting to a non XMPP service
+TEST_F(XmppEngineTest, TestNotXmpp) {
+  // Connect
+  engine()->Connect();
+  EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler()->OutputActivity());
+
+  // Send garbage response (courtesy of apache)
+  std::string input = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[OPENING][CLOSED][ERROR-XML]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+// TestPassthrough()
+//    This tests that arbitrary stanzas can be passed to the server through
+//    the engine.
+TEST_F(XmppEngineTest, TestPassthrough) {
+  // Queue up an app stanza
+  XmlElement application_stanza(QName("test", "app-stanza"));
+  application_stanza.AddText("this-is-a-test");
+  engine()->SendStanza(&application_stanza);
+
+  // Do the whole login handshake
+  RunLogin();
+
+  EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test"
+          "</test:app-stanza>", handler()->OutputActivity());
+
+  // do another stanza
+  XmlElement roster_get(QN_IQ);
+  roster_get.AddAttr(QN_TYPE, "get");
+  roster_get.AddAttr(QN_ID, engine()->NextId());
+  roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+  engine()->SendStanza(&roster_get);
+  EXPECT_EQ("<iq type=\"get\" id=\"2\"><query xmlns=\"jabber:iq:roster\"/>"
+          "</iq>", handler()->OutputActivity());
+
+  // now say the server ends the stream
+  engine()->HandleInput("</stream:stream>", 16);
+  EXPECT_EQ("[CLOSED][ERROR-DOCUMENT-CLOSED]", handler()->SessionActivity());
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+// TestIqCallback()
+//    This tests the routing of Iq stanzas and responses.
+TEST_F(XmppEngineTest, TestIqCallback) {
+  XmppEngineTestIqHandler iq_response;
+  XmppIqCookie cookie;
+
+  // Do the whole login handshake
+  RunLogin();
+
+  // Build an iq request
+  XmlElement roster_get(QN_IQ);
+  roster_get.AddAttr(QN_TYPE, "get");
+  roster_get.AddAttr(QN_ID, engine()->NextId());
+  roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+  engine()->SendIq(&roster_get, &iq_response, &cookie);
+  EXPECT_EQ("<iq type=\"get\" id=\"2\"><query xmlns=\"jabber:iq:roster\"/>"
+          "</iq>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+  EXPECT_EQ("", iq_response.IqResponseActivity());
+
+  // now say the server responds to the iq
+  std::string input = "<iq type='result' id='2'>"
+                      "<query xmlns='jabber:iq:roster'><item>foo</item>"
+                      "</query></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+  EXPECT_EQ("<cli:iq type=\"result\" id=\"2\" xmlns:cli=\"jabber:client\">"
+          "<query xmlns=\"jabber:iq:roster\"><item>foo</item></query>"
+          "</cli:iq>", iq_response.IqResponseActivity());
+
+  EXPECT_EQ(XMPP_RETURN_BADARGUMENT, engine()->RemoveIqHandler(cookie, NULL));
+
+  // Do it again with another id to test cancel
+  roster_get.SetAttr(QN_ID, engine()->NextId());
+  engine()->SendIq(&roster_get, &iq_response, &cookie);
+  EXPECT_EQ("<iq type=\"get\" id=\"3\"><query xmlns=\"jabber:iq:roster\"/>"
+          "</iq>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+  EXPECT_EQ("", iq_response.IqResponseActivity());
+
+  // cancel the handler this time
+  EXPECT_EQ(XMPP_RETURN_OK, engine()->RemoveIqHandler(cookie, NULL));
+
+  // now say the server responds to the iq: the iq handler should not get it.
+  input = "<iq type='result' id='3'><query xmlns='jabber:iq:roster'><item>bar"
+          "</item></query></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<cli:iq type=\"result\" id=\"3\" xmlns:cli=\"jabber:client\">"
+          "<query xmlns=\"jabber:iq:roster\"><item>bar</item></query>"
+          "</cli:iq>", handler()->StanzaActivity());
+  EXPECT_EQ("", iq_response.IqResponseActivity());
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+}
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc
new file mode 100644
index 0000000..8ba57a64
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc
@@ -0,0 +1,446 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/xmppengineimpl.h"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/saslhandler.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpplogintask.h"
+#include "third_party/webrtc/base/common.h"
+
+namespace buzz {
+
+XmppEngine* XmppEngine::Create() {
+  return new XmppEngineImpl();
+}
+
+
+XmppEngineImpl::XmppEngineImpl()
+    : stanza_parse_handler_(this),
+      stanza_parser_(&stanza_parse_handler_),
+      engine_entered_(0),
+      password_(),
+      requested_resource_(STR_EMPTY),
+      tls_option_(buzz::TLS_REQUIRED),
+      login_task_(new XmppLoginTask(this)),
+      next_id_(0),
+      state_(STATE_START),
+      encrypted_(false),
+      error_code_(ERROR_NONE),
+      subcode_(0),
+      stream_error_(),
+      raised_reset_(false),
+      output_handler_(NULL),
+      session_handler_(NULL),
+      iq_entries_(new IqEntryVector()),
+      sasl_handler_(),
+      output_(new std::stringstream()) {
+  for (int i = 0; i < HL_COUNT; i+= 1) {
+    stanza_handlers_[i].reset(new StanzaHandlerVector());
+  }
+
+  // Add XMPP namespaces to XML namespaces stack.
+  xmlns_stack_.AddXmlns("stream", "http://etherx.jabber.org/streams");
+  xmlns_stack_.AddXmlns("", "jabber:client");
+}
+
+XmppEngineImpl::~XmppEngineImpl() {
+  DeleteIqCookies();
+}
+
+XmppReturnStatus XmppEngineImpl::SetOutputHandler(
+    XmppOutputHandler* output_handler) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  output_handler_ = output_handler;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetSessionHandler(
+    XmppSessionHandler* session_handler) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  session_handler_ = session_handler;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::HandleInput(
+    const char* bytes, size_t len) {
+  if (state_ < STATE_OPENING || state_ > STATE_OPEN)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  // TODO: The return value of the xml parser is not checked.
+  stanza_parser_.Parse(bytes, len, false);
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::ConnectionClosed(int subcode) {
+  if (state_ != STATE_CLOSED) {
+    EnterExit ee(this);
+    // If told that connection closed and not already closed,
+    // then connection was unpexectedly dropped.
+    if (subcode) {
+      SignalError(ERROR_SOCKET, subcode);
+    } else {
+      SignalError(ERROR_CONNECTION_CLOSED, 0);  // no subcode
+    }
+  }
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetTls(TlsOptions use_tls) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+  tls_option_ = use_tls;
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetTlsServer(
+    const std::string& tls_server_hostname,
+    const std::string& tls_server_domain) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  tls_server_hostname_ = tls_server_hostname;
+  tls_server_domain_= tls_server_domain;
+
+  return XMPP_RETURN_OK;
+}
+
+TlsOptions XmppEngineImpl::GetTls() {
+  return tls_option_;
+}
+
+XmppReturnStatus XmppEngineImpl::SetUser(const Jid& jid) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  user_jid_ = jid;
+
+  return XMPP_RETURN_OK;
+}
+
+const Jid& XmppEngineImpl::GetUser() {
+  return user_jid_;
+}
+
+XmppReturnStatus XmppEngineImpl::SetSaslHandler(SaslHandler* sasl_handler) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  sasl_handler_.reset(sasl_handler);
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetRequestedResource(
+    const std::string& resource) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  requested_resource_ = resource;
+
+  return XMPP_RETURN_OK;
+}
+
+const std::string& XmppEngineImpl::GetRequestedResource() {
+  return requested_resource_;
+}
+
+XmppReturnStatus XmppEngineImpl::AddStanzaHandler(
+    XmppStanzaHandler* stanza_handler,
+    XmppEngine::HandlerLevel level) {
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+
+  stanza_handlers_[level]->push_back(stanza_handler);
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::RemoveStanzaHandler(
+    XmppStanzaHandler* stanza_handler) {
+  bool found = false;
+
+  for (int level = 0; level < HL_COUNT; level += 1) {
+    StanzaHandlerVector::iterator new_end =
+      std::remove(stanza_handlers_[level]->begin(),
+      stanza_handlers_[level]->end(),
+      stanza_handler);
+
+    if (new_end != stanza_handlers_[level]->end()) {
+      stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end());
+      found = true;
+    }
+  }
+
+  if (!found)
+    return XMPP_RETURN_BADARGUMENT;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::Connect() {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  // get the login task started
+  state_ = STATE_OPENING;
+  if (login_task_) {
+    login_task_->IncomingStanza(NULL, false);
+    if (login_task_->IsDone())
+      login_task_.reset();
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SendStanza(const XmlElement* element) {
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  if (login_task_) {
+    // still handshaking - then outbound stanzas are queued
+    login_task_->OutgoingStanza(element);
+  } else {
+    // handshake done - send straight through
+    InternalSendStanza(element);
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SendRaw(const std::string& text) {
+  if (state_ == STATE_CLOSED || login_task_)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  (*output_) << text;
+
+  return XMPP_RETURN_OK;
+}
+
+std::string XmppEngineImpl::NextId() {
+  std::stringstream ss;
+  ss << next_id_++;
+  return ss.str();
+}
+
+XmppReturnStatus XmppEngineImpl::Disconnect() {
+  if (state_ != STATE_CLOSED) {
+    EnterExit ee(this);
+    if (state_ == STATE_OPEN)
+      *output_ << "</stream:stream>";
+    state_ = STATE_CLOSED;
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+void XmppEngineImpl::IncomingStart(const XmlElement* start) {
+  if (HasError() || raised_reset_)
+    return;
+
+  if (login_task_) {
+    // start-stream should go to login task
+    login_task_->IncomingStanza(start, true);
+    if (login_task_->IsDone())
+      login_task_.reset();
+  }
+  else {
+    // if not logging in, it's an error to see a start
+    SignalError(ERROR_XML, 0);
+  }
+}
+
+void XmppEngineImpl::IncomingStanza(const XmlElement* stanza) {
+  if (HasError() || raised_reset_)
+    return;
+
+  if (stanza->Name() == QN_STREAM_ERROR) {
+    // Explicit XMPP stream error
+    SignalStreamError(stanza);
+  } else if (login_task_) {
+    // Handle login handshake
+    login_task_->IncomingStanza(stanza, false);
+    if (login_task_->IsDone())
+      login_task_.reset();
+  } else if (HandleIqResponse(stanza)) {
+    // iq is handled by above call
+  } else {
+    // give every "peek" handler a shot at all stanzas
+    for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) {
+      (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza);
+    }
+
+    // give other handlers a shot in precedence order, stopping after handled
+    for (int level = HL_SINGLE; level <= HL_ALL; level += 1) {
+      for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) {
+        if ((*stanza_handlers_[level])[i]->HandleStanza(stanza))
+          return;
+      }
+    }
+
+    // If nobody wants to handle a stanza then send back an error.
+    // Only do this for IQ stanzas as messages should probably just be dropped
+    // and presence stanzas should certainly be dropped.
+    std::string type = stanza->Attr(QN_TYPE);
+    if (stanza->Name() == QN_IQ &&
+        !(type == "error" || type == "result")) {
+      SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY);
+    }
+  }
+}
+
+void XmppEngineImpl::IncomingEnd(bool isError) {
+  if (HasError() || raised_reset_)
+    return;
+
+  SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED, 0);
+}
+
+void XmppEngineImpl::InternalSendStart(const std::string& to) {
+  std::string hostname = tls_server_hostname_;
+  if (hostname.empty())
+    hostname = to;
+
+  // If not language is specified, the spec says use *
+  std::string lang = lang_;
+  if (lang.length() == 0)
+    lang = "*";
+
+  // send stream-beginning
+  // note, we put a \r\n at tne end fo the first line to cause non-XMPP
+  // line-oriented servers (e.g., Apache) to reveal themselves more quickly.
+  *output_ << "<stream:stream to=\"" << hostname << "\" "
+           << "xml:lang=\"" << lang << "\" "
+           << "version=\"1.0\" "
+           << "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+           << "xmlns=\"jabber:client\">\r\n";
+}
+
+void XmppEngineImpl::InternalSendStanza(const XmlElement* element) {
+  // It should really never be necessary to set a FROM attribute on a stanza.
+  // It is implied by the bind on the stream and if you get it wrong
+  // (by flipping from/to on a message?) the server will close the stream.
+  ASSERT(!element->HasAttr(QN_FROM));
+
+  XmlPrinter::PrintXml(output_.get(), element, &xmlns_stack_);
+}
+
+std::string XmppEngineImpl::ChooseBestSaslMechanism(
+    const std::vector<std::string>& mechanisms, bool encrypted) {
+  return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted);
+}
+
+SaslMechanism* XmppEngineImpl::GetSaslMechanism(const std::string& name) {
+  return sasl_handler_->CreateSaslMechanism(name);
+}
+
+void XmppEngineImpl::SignalBound(const Jid& fullJid) {
+  if (state_ == STATE_OPENING) {
+    bound_jid_ = fullJid;
+    state_ = STATE_OPEN;
+  }
+}
+
+void XmppEngineImpl::SignalStreamError(const XmlElement* stream_error) {
+  if (state_ != STATE_CLOSED) {
+    stream_error_.reset(new XmlElement(*stream_error));
+    SignalError(ERROR_STREAM, 0);
+  }
+}
+
+void XmppEngineImpl::SignalError(Error error_code, int sub_code) {
+  if (state_ != STATE_CLOSED) {
+    error_code_ = error_code;
+    subcode_ = sub_code;
+    state_ = STATE_CLOSED;
+  }
+}
+
+bool XmppEngineImpl::HasError() {
+  return error_code_ != ERROR_NONE;
+}
+
+void XmppEngineImpl::StartTls(const std::string& domain) {
+  if (output_handler_) {
+    // As substitute for the real (login jid's) domain, we permit
+    // verifying a tls_server_domain_ instead, if one was passed.
+    // This allows us to avoid running a proxy that needs to handle
+    // valuable certificates.
+    output_handler_->StartTls(
+      tls_server_domain_.empty() ? domain : tls_server_domain_);
+    encrypted_ = true;
+  }
+}
+
+XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
+    : engine_(engine),
+      state_(engine->state_) {
+  engine->engine_entered_ += 1;
+}
+
+XmppEngineImpl::EnterExit::~EnterExit()  {
+ XmppEngineImpl* engine = engine_;
+
+ engine->engine_entered_ -= 1;
+
+ bool closing = (engine->state_ != state_ &&
+       engine->state_ == STATE_CLOSED);
+ bool flushing = closing || (engine->engine_entered_ == 0);
+
+ if (engine->output_handler_ && flushing) {
+   std::string output = engine->output_->str();
+   if (output.length() > 0)
+     engine->output_handler_->WriteOutput(output.c_str(), output.length());
+   engine->output_->str("");
+
+   if (closing) {
+     engine->output_handler_->CloseConnection();
+     engine->output_handler_ = 0;
+   }
+ }
+
+ if (engine->engine_entered_)
+   return;
+
+ if (engine->raised_reset_) {
+   engine->stanza_parser_.Reset();
+   engine->raised_reset_ = false;
+ }
+
+ if (engine->session_handler_) {
+   if (engine->state_ != state_)
+     engine->session_handler_->OnStateChange(engine->state_);
+   // Note: Handling of OnStateChange(CLOSED) should allow for the
+   // deletion of the engine, so no members should be accessed
+   // after this line.
+ }
+}
+
+}  // namespace buzz
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengineimpl.h b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.h
new file mode 100644
index 0000000..2f8f2c6
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.h
@@ -0,0 +1,267 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
+
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h"
+
+namespace buzz {
+
+class XmppLoginTask;
+class XmppEngine;
+class XmppIqEntry;
+class SaslHandler;
+class SaslMechanism;
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput.  Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngineImpl : public XmppEngine {
+ public:
+  XmppEngineImpl();
+  virtual ~XmppEngineImpl();
+
+  // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+  //! Registers the handler for socket output
+  virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh);
+
+  //! Provides socket input to the engine
+  virtual XmppReturnStatus HandleInput(const char* bytes, size_t len);
+
+  //! Advises the engine that the socket has closed
+  virtual XmppReturnStatus ConnectionClosed(int subcode);
+
+  // SESSION SETUP ---------------------------------------------------------
+
+  //! Indicates the (bare) JID for the user to use.
+  virtual XmppReturnStatus SetUser(const Jid& jid);
+
+  //! Get the login (bare) JID.
+  virtual const Jid& GetUser();
+
+  //! Indicates the autentication to use.  Takes ownership of the object.
+  virtual XmppReturnStatus SetSaslHandler(SaslHandler* sasl_handler);
+
+  //! Sets whether TLS will be used within the connection (default true).
+  virtual XmppReturnStatus SetTls(TlsOptions use_tls);
+
+  //! Sets an alternate domain from which we allows TLS certificates.
+  //! This is for use in the case where a we want to allow a proxy to
+  //! serve up its own certificate rather than one owned by the underlying
+  //! domain.
+  virtual XmppReturnStatus SetTlsServer(const std::string& proxy_hostname,
+                                        const std::string& proxy_domain);
+
+  //! Gets whether TLS will be used within the connection.
+  virtual TlsOptions GetTls();
+
+  //! Sets the request resource name, if any (optional).
+  //! Note that the resource name may be overridden by the server; after
+  //! binding, the actual resource name is available as part of FullJid().
+  virtual XmppReturnStatus SetRequestedResource(const std::string& resource);
+
+  //! Gets the request resource name.
+  virtual const std::string& GetRequestedResource();
+
+  //! Sets language
+  virtual void SetLanguage(const std::string& lang) {
+    lang_ = lang;
+  }
+
+  // SESSION MANAGEMENT ---------------------------------------------------
+
+  //! Set callback for state changes.
+  virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler);
+
+  //! Initiates the XMPP connection.
+  //! After supplying connection settings, call this once to initiate,
+  //! (optionally) encrypt, authenticate, and bind the connection.
+  virtual XmppReturnStatus Connect();
+
+  //! The current engine state.
+  virtual State GetState() { return state_; }
+
+  //! Returns true if the connection is encrypted (under TLS)
+  virtual bool IsEncrypted() { return encrypted_; }
+
+  //! The error code.
+  //! Consult this after XmppOutputHandler.OnClose().
+  virtual Error GetError(int *subcode) {
+     if (subcode) {
+       *subcode = subcode_;
+     }
+     return error_code_;
+  }
+
+  //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
+  //! Notice the stanza returned is owned by the XmppEngine and
+  //! is deleted when the engine is destroyed.
+  virtual const XmlElement* GetStreamError() { return stream_error_.get(); }
+
+  //! Closes down the connection.
+  //! Sends CloseConnection to output, and disconnects and registered
+  //! session handlers.  After Disconnect completes, it is guaranteed
+  //! that no further callbacks will be made.
+  virtual XmppReturnStatus Disconnect();
+
+  // APPLICATION USE -------------------------------------------------------
+
+  //! Adds a listener for session events.
+  //! Stanza delivery is chained to session handlers; the first to
+  //! return 'true' is the last to get each stanza.
+  virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler,
+                                            XmppEngine::HandlerLevel level);
+
+  //! Removes a listener for session events.
+  virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler);
+
+  //! Sends a stanza to the server.
+  virtual XmppReturnStatus SendStanza(const XmlElement* stanza);
+
+  //! Sends raw text to the server
+  virtual XmppReturnStatus SendRaw(const std::string& text);
+
+  //! Sends an iq to the server, and registers a callback for the result.
+  //! Returns the cookie passed to the result handler.
+  virtual XmppReturnStatus SendIq(const XmlElement* stanza,
+                                  XmppIqHandler* iq_handler,
+                                  XmppIqCookie* cookie);
+
+  //! Unregisters an iq callback handler given its cookie.
+  //! No callback will come to this handler after it's unregistered.
+  virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+                                      XmppIqHandler** iq_handler);
+
+  //! Forms and sends an error in response to the given stanza.
+  //! Swaps to and from, sets type to "error", and adds error information
+  //! based on the passed code.  Text is optional and may be STR_EMPTY.
+  virtual XmppReturnStatus SendStanzaError(const XmlElement* pelOriginal,
+                                           XmppStanzaError code,
+                                           const std::string& text);
+
+  //! The fullly bound JID.
+  //! This JID is only valid after binding has succeeded.  If the value
+  //! is JID_NULL, the binding has not succeeded.
+  virtual const Jid& FullJid() { return bound_jid_; }
+
+  //! The next unused iq id for this connection.
+  //! Call this when building iq stanzas, to ensure that each iq
+  //! gets its own unique id.
+  virtual std::string NextId();
+
+ private:
+  friend class XmppLoginTask;
+  friend class XmppIqEntry;
+
+  void IncomingStanza(const XmlElement *stanza);
+  void IncomingStart(const XmlElement *stanza);
+  void IncomingEnd(bool isError);
+
+  void InternalSendStart(const std::string& domainName);
+  void InternalSendStanza(const XmlElement* stanza);
+  std::string ChooseBestSaslMechanism(
+      const std::vector<std::string>& mechanisms, bool encrypted);
+  SaslMechanism* GetSaslMechanism(const std::string& name);
+  void SignalBound(const Jid& fullJid);
+  void SignalStreamError(const XmlElement* streamError);
+  void SignalError(Error errorCode, int subCode);
+  bool HasError();
+  void DeleteIqCookies();
+  bool HandleIqResponse(const XmlElement* element);
+  void StartTls(const std::string& domain);
+  void RaiseReset() { raised_reset_ = true; }
+
+  class StanzaParseHandler : public XmppStanzaParseHandler {
+   public:
+    StanzaParseHandler(XmppEngineImpl* outer) : outer_(outer) {}
+    virtual ~StanzaParseHandler() {}
+
+    virtual void StartStream(const XmlElement* stream) {
+      outer_->IncomingStart(stream);
+    }
+    virtual void Stanza(const XmlElement* stanza) {
+      outer_->IncomingStanza(stanza);
+    }
+    virtual void EndStream() {
+      outer_->IncomingEnd(false);
+    }
+    virtual void XmlError() {
+      outer_->IncomingEnd(true);
+    }
+
+   private:
+    XmppEngineImpl* const outer_;
+  };
+
+  class EnterExit {
+   public:
+    EnterExit(XmppEngineImpl* engine);
+    ~EnterExit();
+   private:
+    XmppEngineImpl* engine_;
+    State state_;
+  };
+
+  friend class StanzaParseHandler;
+  friend class EnterExit;
+
+  StanzaParseHandler stanza_parse_handler_;
+  XmppStanzaParser stanza_parser_;
+
+  // state
+  int engine_entered_;
+  Jid user_jid_;
+  std::string password_;
+  std::string requested_resource_;
+  TlsOptions tls_option_;
+  std::string tls_server_hostname_;
+  std::string tls_server_domain_;
+  std::unique_ptr<XmppLoginTask> login_task_;
+  std::string lang_;
+
+  int next_id_;
+  Jid bound_jid_;
+  State state_;
+  bool encrypted_;
+  Error error_code_;
+  int subcode_;
+  std::unique_ptr<XmlElement> stream_error_;
+  bool raised_reset_;
+  XmppOutputHandler* output_handler_;
+  XmppSessionHandler* session_handler_;
+
+  XmlnsStack xmlns_stack_;
+
+  typedef std::vector<XmppStanzaHandler*> StanzaHandlerVector;
+  std::unique_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT];
+
+  typedef std::vector<XmppIqEntry*> IqEntryVector;
+  std::unique_ptr<IqEntryVector> iq_entries_;
+
+  std::unique_ptr<SaslHandler> sasl_handler_;
+
+  std::unique_ptr<std::stringstream> output_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengineimpl_iq.cc b/third_party/libjingle_xmpp/xmpp/xmppengineimpl_iq.cc
new file mode 100644
index 0000000..a5b5714
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppengineimpl_iq.cc
@@ -0,0 +1,260 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <algorithm>
+#include <vector>
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengineimpl.h"
+#include "third_party/webrtc/base/common.h"
+
+namespace buzz {
+
+class XmppIqEntry {
+  XmppIqEntry(const std::string & id, const std::string & to,
+               XmppEngine * pxce, XmppIqHandler * iq_handler) :
+    id_(id),
+    to_(to),
+    engine_(pxce),
+    iq_handler_(iq_handler) {
+  }
+
+private:
+  friend class XmppEngineImpl;
+
+  const std::string id_;
+  const std::string to_;
+  XmppEngine * const engine_;
+  XmppIqHandler * const iq_handler_;
+};
+
+
+XmppReturnStatus
+XmppEngineImpl::SendIq(const XmlElement * element, XmppIqHandler * iq_handler,
+  XmppIqCookie* cookie) {
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+  if (NULL == iq_handler)
+    return XMPP_RETURN_BADARGUMENT;
+  if (!element || element->Name() != QN_IQ)
+    return XMPP_RETURN_BADARGUMENT;
+
+  const std::string& type = element->Attr(QN_TYPE);
+  if (type != "get" && type != "set")
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!element->HasAttr(QN_ID))
+    return XMPP_RETURN_BADARGUMENT;
+  const std::string& id = element->Attr(QN_ID);
+
+  XmppIqEntry * iq_entry = new XmppIqEntry(id,
+                                              element->Attr(QN_TO),
+                                              this, iq_handler);
+  iq_entries_->push_back(iq_entry);
+  SendStanza(element);
+
+  if (cookie)
+    *cookie = iq_entry;
+
+  return XMPP_RETURN_OK;
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::RemoveIqHandler(XmppIqCookie cookie,
+    XmppIqHandler ** iq_handler) {
+
+  std::vector<XmppIqEntry*, std::allocator<XmppIqEntry*> >::iterator pos;
+
+  pos = std::find(iq_entries_->begin(),
+                  iq_entries_->end(),
+                  reinterpret_cast<XmppIqEntry*>(cookie));
+
+  if (pos == iq_entries_->end())
+    return XMPP_RETURN_BADARGUMENT;
+
+  XmppIqEntry* entry = *pos;
+  iq_entries_->erase(pos);
+  if (iq_handler)
+    *iq_handler = entry->iq_handler_;
+  delete entry;
+
+  return XMPP_RETURN_OK;
+}
+
+void
+XmppEngineImpl::DeleteIqCookies() {
+  for (size_t i = 0; i < iq_entries_->size(); i += 1) {
+    XmppIqEntry * iq_entry_ = (*iq_entries_)[i];
+    (*iq_entries_)[i] = NULL;
+    delete iq_entry_;
+  }
+  iq_entries_->clear();
+}
+
+static void
+AecImpl(XmlElement * error_element, const QName & name,
+        const char * type, const char * code) {
+  error_element->AddElement(new XmlElement(QN_ERROR));
+  error_element->AddAttr(QN_CODE, code, 1);
+  error_element->AddAttr(QN_TYPE, type, 1);
+  error_element->AddElement(new XmlElement(name, true), 1);
+}
+
+
+static void
+AddErrorCode(XmlElement * error_element, XmppStanzaError code) {
+  switch (code) {
+    case XSE_BAD_REQUEST:
+      AecImpl(error_element, QN_STANZA_BAD_REQUEST, "modify", "400");
+      break;
+    case XSE_CONFLICT:
+      AecImpl(error_element, QN_STANZA_CONFLICT, "cancel", "409");
+      break;
+    case XSE_FEATURE_NOT_IMPLEMENTED:
+      AecImpl(error_element, QN_STANZA_FEATURE_NOT_IMPLEMENTED,
+              "cancel", "501");
+      break;
+    case XSE_FORBIDDEN:
+      AecImpl(error_element, QN_STANZA_FORBIDDEN, "auth", "403");
+      break;
+    case XSE_GONE:
+      AecImpl(error_element, QN_STANZA_GONE, "modify", "302");
+      break;
+    case XSE_INTERNAL_SERVER_ERROR:
+      AecImpl(error_element, QN_STANZA_INTERNAL_SERVER_ERROR, "wait", "500");
+      break;
+    case XSE_ITEM_NOT_FOUND:
+      AecImpl(error_element, QN_STANZA_ITEM_NOT_FOUND, "cancel", "404");
+      break;
+    case XSE_JID_MALFORMED:
+      AecImpl(error_element, QN_STANZA_JID_MALFORMED, "modify", "400");
+      break;
+    case XSE_NOT_ACCEPTABLE:
+      AecImpl(error_element, QN_STANZA_NOT_ACCEPTABLE, "cancel", "406");
+      break;
+    case XSE_NOT_ALLOWED:
+      AecImpl(error_element, QN_STANZA_NOT_ALLOWED, "cancel", "405");
+      break;
+    case XSE_PAYMENT_REQUIRED:
+      AecImpl(error_element, QN_STANZA_PAYMENT_REQUIRED, "auth", "402");
+      break;
+    case XSE_RECIPIENT_UNAVAILABLE:
+      AecImpl(error_element, QN_STANZA_RECIPIENT_UNAVAILABLE, "wait", "404");
+      break;
+    case XSE_REDIRECT:
+      AecImpl(error_element, QN_STANZA_REDIRECT, "modify", "302");
+      break;
+    case XSE_REGISTRATION_REQUIRED:
+      AecImpl(error_element, QN_STANZA_REGISTRATION_REQUIRED, "auth", "407");
+      break;
+    case XSE_SERVER_NOT_FOUND:
+      AecImpl(error_element, QN_STANZA_REMOTE_SERVER_NOT_FOUND,
+              "cancel", "404");
+      break;
+    case XSE_SERVER_TIMEOUT:
+      AecImpl(error_element, QN_STANZA_REMOTE_SERVER_TIMEOUT, "wait", "502");
+      break;
+    case XSE_RESOURCE_CONSTRAINT:
+      AecImpl(error_element, QN_STANZA_RESOURCE_CONSTRAINT, "wait", "500");
+      break;
+    case XSE_SERVICE_UNAVAILABLE:
+      AecImpl(error_element, QN_STANZA_SERVICE_UNAVAILABLE, "cancel", "503");
+      break;
+    case XSE_SUBSCRIPTION_REQUIRED:
+      AecImpl(error_element, QN_STANZA_SUBSCRIPTION_REQUIRED, "auth", "407");
+      break;
+    case XSE_UNDEFINED_CONDITION:
+      AecImpl(error_element, QN_STANZA_UNDEFINED_CONDITION, "wait", "500");
+      break;
+    case XSE_UNEXPECTED_REQUEST:
+      AecImpl(error_element, QN_STANZA_UNEXPECTED_REQUEST, "wait", "400");
+      break;
+  }
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::SendStanzaError(const XmlElement * element_original,
+                                XmppStanzaError code,
+                                const std::string & text) {
+
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement error_element(element_original->Name());
+  error_element.AddAttr(QN_TYPE, "error");
+
+  // copy attrs, copy 'from' to 'to' and strip 'from'
+  for (const XmlAttr * attribute = element_original->FirstAttr();
+       attribute; attribute = attribute->NextAttr()) {
+    QName name = attribute->Name();
+    if (name == QN_TO)
+      continue; // no need to put a from attr.  Server will stamp stanza
+    else if (name == QN_FROM)
+      name = QN_TO;
+    else if (name == QN_TYPE)
+      continue;
+    error_element.AddAttr(name, attribute->Value());
+  }
+
+  // copy children
+  for (const XmlChild * child = element_original->FirstChild();
+       child;
+       child = child->NextChild()) {
+    if (child->IsText()) {
+      error_element.AddText(child->AsText()->Text());
+    } else {
+      error_element.AddElement(new XmlElement(*(child->AsElement())));
+    }
+  }
+
+  // add error information
+  AddErrorCode(&error_element, code);
+  if (text != STR_EMPTY) {
+    XmlElement * text_element = new XmlElement(QN_STANZA_TEXT, true);
+    text_element->AddText(text);
+    error_element.AddElement(text_element);
+  }
+
+  SendStanza(&error_element);
+
+  return XMPP_RETURN_OK;
+}
+
+
+bool
+XmppEngineImpl::HandleIqResponse(const XmlElement * element) {
+  if (iq_entries_->empty())
+    return false;
+  if (element->Name() != QN_IQ)
+    return false;
+  std::string type = element->Attr(QN_TYPE);
+  if (type != "result" && type != "error")
+    return false;
+  if (!element->HasAttr(QN_ID))
+    return false;
+  std::string id = element->Attr(QN_ID);
+  std::string from = element->Attr(QN_FROM);
+
+  for (std::vector<XmppIqEntry *>::iterator it = iq_entries_->begin();
+       it != iq_entries_->end(); it += 1) {
+    XmppIqEntry * iq_entry = *it;
+    if (iq_entry->id_ == id && iq_entry->to_ == from) {
+      iq_entries_->erase(it);
+      iq_entry->iq_handler_->IqResponse(iq_entry, element);
+      delete iq_entry;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+}
diff --git a/third_party/libjingle_xmpp/xmpp/xmpplogintask.cc b/third_party/libjingle_xmpp/xmpp/xmpplogintask.cc
new file mode 100644
index 0000000..6936b77
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmpplogintask.cc
@@ -0,0 +1,380 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/xmpplogintask.h"
+
+#include <string>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/saslmechanism.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengineimpl.h"
+#include "third_party/webrtc/base/base64.h"
+#include "third_party/webrtc/base/common.h"
+
+using rtc::ConstantLabel;
+
+namespace buzz {
+
+#if !defined(NDEBUG)
+const ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
+  KLABEL(LOGINSTATE_INIT),
+  KLABEL(LOGINSTATE_STREAMSTART_SENT),
+  KLABEL(LOGINSTATE_STARTED_XMPP),
+  KLABEL(LOGINSTATE_TLS_INIT),
+  KLABEL(LOGINSTATE_AUTH_INIT),
+  KLABEL(LOGINSTATE_BIND_INIT),
+  KLABEL(LOGINSTATE_TLS_REQUESTED),
+  KLABEL(LOGINSTATE_SASL_RUNNING),
+  KLABEL(LOGINSTATE_BIND_REQUESTED),
+  KLABEL(LOGINSTATE_SESSION_REQUESTED),
+  KLABEL(LOGINSTATE_DONE),
+  LASTLABEL
+};
+#endif
+XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
+  pctx_(pctx),
+  authNeeded_(true),
+  allowNonGoogleLogin_(true),
+  state_(LOGINSTATE_INIT),
+  pelStanza_(NULL),
+  isStart_(false),
+  iqId_(STR_EMPTY),
+  pelFeatures_(),
+  fullJid_(STR_EMPTY),
+  streamId_(STR_EMPTY),
+  pvecQueuedStanzas_(new std::vector<XmlElement *>()),
+  sasl_mech_() {
+}
+
+XmppLoginTask::~XmppLoginTask() {
+  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
+    delete (*pvecQueuedStanzas_)[i];
+}
+
+void
+XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
+  pelStanza_ = element;
+  isStart_ = isStart;
+  Advance();
+  pelStanza_ = NULL;
+  isStart_ = false;
+}
+
+const XmlElement *
+XmppLoginTask::NextStanza() {
+  const XmlElement * result = pelStanza_;
+  pelStanza_ = NULL;
+  return result;
+}
+
+bool
+XmppLoginTask::Advance() {
+
+  for (;;) {
+
+    const XmlElement * element = NULL;
+
+#if !defined(NDEBUG)
+    LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
+      << rtc::ErrorName(state_, LOGINTASK_STATES);
+#endif
+
+    switch (state_) {
+
+      case LOGINSTATE_INIT: {
+        pctx_->RaiseReset();
+        pelFeatures_.reset(NULL);
+
+        // The proper domain to verify against is the real underlying
+        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
+        // also allows matching against a proxy domain instead, if it is told
+        // to do so - see the implementation of XmppEngineImpl::StartTls and
+        // XmppEngine::SetTlsServerDomain to see how you can use that feature
+        pctx_->InternalSendStart(pctx_->user_jid_.domain());
+        state_ = LOGINSTATE_STREAMSTART_SENT;
+        break;
+      }
+
+      case LOGINSTATE_STREAMSTART_SENT: {
+        if (NULL == (element = NextStanza()))
+          return true;
+
+        if (!isStart_ || !HandleStartStream(element))
+          return Failure(XmppEngine::ERROR_VERSION);
+
+        state_ = LOGINSTATE_STARTED_XMPP;
+        return true;
+      }
+
+      case LOGINSTATE_STARTED_XMPP: {
+        if (NULL == (element = NextStanza()))
+          return true;
+
+        if (!HandleFeatures(element))
+          return Failure(XmppEngine::ERROR_VERSION);
+
+        bool tls_present = (GetFeature(QN_TLS_STARTTLS) != NULL);
+        // Error if TLS required but not present.
+        if (pctx_->tls_option_ == buzz::TLS_REQUIRED && !tls_present) {
+          return Failure(XmppEngine::ERROR_TLS);
+        }
+        // Use TLS if required or enabled, and also available
+        if ((pctx_->tls_option_ == buzz::TLS_REQUIRED ||
+            pctx_->tls_option_ == buzz::TLS_ENABLED) && tls_present) {
+          state_ = LOGINSTATE_TLS_INIT;
+          continue;
+        }
+
+        if (authNeeded_) {
+          state_ = LOGINSTATE_AUTH_INIT;
+          continue;
+        }
+
+        state_ = LOGINSTATE_BIND_INIT;
+        continue;
+      }
+
+      case LOGINSTATE_TLS_INIT: {
+        const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
+        if (!pelTls)
+          return Failure(XmppEngine::ERROR_TLS);
+
+        XmlElement el(QN_TLS_STARTTLS, true);
+        pctx_->InternalSendStanza(&el);
+        state_ = LOGINSTATE_TLS_REQUESTED;
+        continue;
+      }
+
+      case LOGINSTATE_TLS_REQUESTED: {
+        if (NULL == (element = NextStanza()))
+          return true;
+        if (element->Name() != QN_TLS_PROCEED)
+          return Failure(XmppEngine::ERROR_TLS);
+
+        // The proper domain to verify against is the real underlying
+        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
+        // also allows matching against a proxy domain instead, if it is told
+        // to do so - see the implementation of XmppEngineImpl::StartTls and
+        // XmppEngine::SetTlsServerDomain to see how you can use that feature
+        pctx_->StartTls(pctx_->user_jid_.domain());
+        pctx_->tls_option_ = buzz::TLS_ENABLED;
+        state_ = LOGINSTATE_INIT;
+        continue;
+      }
+
+      case LOGINSTATE_AUTH_INIT: {
+        const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
+        if (!pelSaslAuth) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+
+        // Collect together the SASL auth mechanisms presented by the server
+        std::vector<std::string> mechanisms;
+        for (const XmlElement * pelMech =
+             pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
+             pelMech;
+             pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
+
+          mechanisms.push_back(pelMech->BodyText());
+        }
+
+        // Given all the mechanisms, choose the best
+        std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
+        if (choice.empty()) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+
+        // No recognized auth mechanism - that's an error
+        sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
+        if (!sasl_mech_) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+
+        // OK, let's start it.
+        XmlElement * auth = sasl_mech_->StartSaslAuth();
+        if (auth == NULL) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+        if (allowNonGoogleLogin_) {
+          // Setting the following two attributes is required to support
+          // non-google ids.
+
+          // Allow login with non-google id accounts.
+          auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true");
+
+          // Allow login with either the non-google id or the friendly email.
+          auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
+        }
+
+        pctx_->InternalSendStanza(auth);
+        delete auth;
+        state_ = LOGINSTATE_SASL_RUNNING;
+        continue;
+      }
+
+      case LOGINSTATE_SASL_RUNNING: {
+        if (NULL == (element = NextStanza()))
+          return true;
+        if (element->Name().Namespace() != NS_SASL)
+          return Failure(XmppEngine::ERROR_AUTH);
+        if (element->Name() == QN_SASL_CHALLENGE) {
+          XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
+          if (response == NULL) {
+            return Failure(XmppEngine::ERROR_AUTH);
+          }
+          pctx_->InternalSendStanza(response);
+          delete response;
+          state_ = LOGINSTATE_SASL_RUNNING;
+          continue;
+        }
+        if (element->Name() != QN_SASL_SUCCESS) {
+          return Failure(XmppEngine::ERROR_UNAUTHORIZED);
+        }
+
+        // Authenticated!
+        authNeeded_ = false;
+        state_ = LOGINSTATE_INIT;
+        continue;
+      }
+
+      case LOGINSTATE_BIND_INIT: {
+        const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
+        const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
+        if (!pelBindFeature || !pelSessionFeature)
+          return Failure(XmppEngine::ERROR_BIND);
+
+        XmlElement iq(QN_IQ);
+        iq.AddAttr(QN_TYPE, "set");
+
+        iqId_ = pctx_->NextId();
+        iq.AddAttr(QN_ID, iqId_);
+        iq.AddElement(new XmlElement(QN_BIND_BIND, true));
+
+        if (pctx_->requested_resource_ != STR_EMPTY) {
+          iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
+          iq.AddText(pctx_->requested_resource_, 2);
+        }
+        pctx_->InternalSendStanza(&iq);
+        state_ = LOGINSTATE_BIND_REQUESTED;
+        continue;
+      }
+
+      case LOGINSTATE_BIND_REQUESTED: {
+        if (NULL == (element = NextStanza()))
+          return true;
+
+        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+          return true;
+
+        if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
+            element->FirstElement()->Name() != QN_BIND_BIND)
+          return Failure(XmppEngine::ERROR_BIND);
+
+        fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
+        if (!fullJid_.IsFull()) {
+          return Failure(XmppEngine::ERROR_BIND);
+        }
+
+        // now request session
+        XmlElement iq(QN_IQ);
+        iq.AddAttr(QN_TYPE, "set");
+
+        iqId_ = pctx_->NextId();
+        iq.AddAttr(QN_ID, iqId_);
+        iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
+        pctx_->InternalSendStanza(&iq);
+
+        state_ = LOGINSTATE_SESSION_REQUESTED;
+        continue;
+      }
+
+      case LOGINSTATE_SESSION_REQUESTED: {
+        if (NULL == (element = NextStanza()))
+          return true;
+        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+          return false;
+
+        if (element->Attr(QN_TYPE) != "result")
+          return Failure(XmppEngine::ERROR_BIND);
+
+        pctx_->SignalBound(fullJid_);
+        FlushQueuedStanzas();
+        state_ = LOGINSTATE_DONE;
+        return true;
+      }
+
+      case LOGINSTATE_DONE:
+        return false;
+    }
+  }
+}
+
+bool
+XmppLoginTask::HandleStartStream(const XmlElement *element) {
+
+  if (element->Name() != QN_STREAM_STREAM)
+    return false;
+
+  if (element->Attr(QN_XMLNS) != "jabber:client")
+    return false;
+
+  if (element->Attr(QN_VERSION) != "1.0")
+    return false;
+
+  if (!element->HasAttr(QN_ID))
+    return false;
+
+  streamId_ = element->Attr(QN_ID);
+
+  return true;
+}
+
+bool
+XmppLoginTask::HandleFeatures(const XmlElement *element) {
+  if (element->Name() != QN_STREAM_FEATURES)
+    return false;
+
+  pelFeatures_.reset(new XmlElement(*element));
+  return true;
+}
+
+const XmlElement *
+XmppLoginTask::GetFeature(const QName & name) {
+  return pelFeatures_->FirstNamed(name);
+}
+
+bool
+XmppLoginTask::Failure(XmppEngine::Error reason) {
+  state_ = LOGINSTATE_DONE;
+  pctx_->SignalError(reason, 0);
+  return false;
+}
+
+void
+XmppLoginTask::OutgoingStanza(const XmlElement * element) {
+  XmlElement * pelCopy = new XmlElement(*element);
+  pvecQueuedStanzas_->push_back(pelCopy);
+}
+
+void
+XmppLoginTask::FlushQueuedStanzas() {
+  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
+    pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
+    delete (*pvecQueuedStanzas_)[i];
+  }
+  pvecQueuedStanzas_->clear();
+}
+
+}
diff --git a/third_party/libjingle_xmpp/xmpp/xmpplogintask.h b/third_party/libjingle_xmpp/xmpp/xmpplogintask.h
new file mode 100644
index 0000000..82fa3420
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmpplogintask.h
@@ -0,0 +1,87 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "third_party/libjingle_xmpp/xmpp/jid.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/webrtc_overrides/webrtc/base/logging.h"
+
+namespace buzz {
+
+class XmlElement;
+class XmppEngineImpl;
+class SaslMechanism;
+
+
+// TODO: Rename to LoginTask.
+class XmppLoginTask {
+
+public:
+  XmppLoginTask(XmppEngineImpl *pctx);
+  ~XmppLoginTask();
+
+  bool IsDone()
+    { return state_ == LOGINSTATE_DONE; }
+  void IncomingStanza(const XmlElement * element, bool isStart);
+  void OutgoingStanza(const XmlElement *element);
+  void set_allow_non_google_login(bool b)
+    { allowNonGoogleLogin_ = b; }
+
+private:
+  enum LoginTaskState {
+    LOGINSTATE_INIT = 0,
+    LOGINSTATE_STREAMSTART_SENT,
+    LOGINSTATE_STARTED_XMPP,
+    LOGINSTATE_TLS_INIT,
+    LOGINSTATE_AUTH_INIT,
+    LOGINSTATE_BIND_INIT,
+    LOGINSTATE_TLS_REQUESTED,
+    LOGINSTATE_SASL_RUNNING,
+    LOGINSTATE_BIND_REQUESTED,
+    LOGINSTATE_SESSION_REQUESTED,
+    LOGINSTATE_DONE,
+  };
+
+  const XmlElement * NextStanza();
+  bool Advance();
+  bool HandleStartStream(const XmlElement * element);
+  bool HandleFeatures(const XmlElement * element);
+  const XmlElement * GetFeature(const QName & name);
+  bool Failure(XmppEngine::Error reason);
+  void FlushQueuedStanzas();
+
+  XmppEngineImpl * pctx_;
+  bool authNeeded_;
+  bool allowNonGoogleLogin_;
+  LoginTaskState state_;
+  const XmlElement * pelStanza_;
+  bool isStart_;
+  std::string iqId_;
+  std::unique_ptr<XmlElement> pelFeatures_;
+  Jid fullJid_;
+  std::string streamId_;
+  std::unique_ptr<std::vector<XmlElement *> > pvecQueuedStanzas_;
+
+  std::unique_ptr<SaslMechanism> sasl_mech_;
+
+#if !defined(NDEBUG)
+  static const rtc::ConstantLabel LOGINTASK_STATES[];
+#endif
+};
+
+}
+
+#endif  //  WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
new file mode 100644
index 0000000..2a70faee
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
@@ -0,0 +1,637 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/plainsaslhandler.h"
+#include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
+#include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/cryptstring.h"
+#include "third_party/webrtc/base/gunit.h"
+#include "third_party/webrtc/typedefs.h"
+
+using buzz::Jid;
+using buzz::QName;
+using buzz::XmlElement;
+using buzz::XmppEngine;
+using buzz::XmppTestHandler;
+
+enum XlttStage {
+  XLTT_STAGE_CONNECT = 0,
+  XLTT_STAGE_STREAMSTART,
+  XLTT_STAGE_TLS_FEATURES,
+  XLTT_STAGE_TLS_PROCEED,
+  XLTT_STAGE_ENCRYPTED_START,
+  XLTT_STAGE_AUTH_FEATURES,
+  XLTT_STAGE_AUTH_SUCCESS,
+  XLTT_STAGE_AUTHENTICATED_START,
+  XLTT_STAGE_BIND_FEATURES,
+  XLTT_STAGE_BIND_SUCCESS,
+  XLTT_STAGE_SESSION_SUCCESS,
+};
+
+class XmppLoginTaskTest : public testing::Test {
+ public:
+  XmppEngine* engine() { return engine_.get(); }
+  XmppTestHandler* handler() { return handler_.get(); }
+  virtual void SetUp() {
+    engine_.reset(XmppEngine::Create());
+    handler_.reset(new XmppTestHandler(engine_.get()));
+
+    Jid jid("david@my-server");
+    rtc::InsecureCryptStringImpl pass;
+    pass.password() = "david";
+    engine_->SetSessionHandler(handler_.get());
+    engine_->SetOutputHandler(handler_.get());
+    engine_->AddStanzaHandler(handler_.get());
+    engine_->SetUser(jid);
+    engine_->SetSaslHandler(
+        new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true));
+  }
+  virtual void TearDown() {
+    handler_.reset();
+    engine_.reset();
+  }
+  void RunPartialLogin(XlttStage startstage, XlttStage endstage);
+  void SetTlsOptions(buzz::TlsOptions option);
+
+ private:
+  std::unique_ptr<XmppEngine> engine_;
+  std::unique_ptr<XmppTestHandler> handler_;
+};
+
+void XmppLoginTaskTest::SetTlsOptions(buzz::TlsOptions option) {
+  engine_->SetTls(option);
+}
+void XmppLoginTaskTest::RunPartialLogin(XlttStage startstage,
+                                        XlttStage endstage) {
+  std::string input;
+
+  switch (startstage) {
+    case XLTT_STAGE_CONNECT: {
+      engine_->Connect();
+      XmlElement appStanza(QName("test", "app-stanza"));
+      appStanza.AddText("this-is-a-test");
+      engine_->SendStanza(&appStanza);
+
+      EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" "
+          "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+      EXPECT_EQ("[OPENING]", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      if (endstage == XLTT_STAGE_CONNECT)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_STREAMSTART: {
+      input = "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->OutputActivity());
+      if (endstage == XLTT_STAGE_STREAMSTART)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_TLS_FEATURES: {
+      input = "<stream:features>"
+        "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
+       "</stream:features>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_TLS_FEATURES)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_TLS_PROCEED: {
+      input = std::string("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("[START-TLS my-server]"
+          "<stream:stream to=\"my-server\" xml:lang=\"*\" "
+          "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_TLS_PROCEED)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_ENCRYPTED_START: {
+      input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">");
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->OutputActivity());
+      if (endstage == XLTT_STAGE_ENCRYPTED_START)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_AUTH_FEATURES: {
+      input = "<stream:features>"
+        "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+          "<mechanism>DIGEST-MD5</mechanism>"
+          "<mechanism>PLAIN</mechanism>"
+        "</mechanisms>"
+       "</stream:features>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+          "mechanism=\"PLAIN\" "
+          "auth:allow-non-google-login=\"true\" "
+          "auth:client-uses-full-bind-result=\"true\" "
+          "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+          ">AGRhdmlkAGRhdmlk</auth>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_AUTH_FEATURES)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_AUTH_SUCCESS: {
+      input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" "
+          "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_AUTH_SUCCESS)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_AUTHENTICATED_START: {
+      input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">");
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->OutputActivity());
+      if (endstage == XLTT_STAGE_AUTHENTICATED_START)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_BIND_FEATURES: {
+      input = "<stream:features>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
+          "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
+        "</stream:features>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<iq type=\"set\" id=\"0\">"
+          "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_BIND_FEATURES)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_BIND_SUCCESS: {
+      input = "<iq type='result' id='0'>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
+          "<jid>david@my-server/test</jid></bind></iq>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<iq type=\"set\" id=\"1\">"
+          "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_BIND_SUCCESS)
+        return;
+      FALLTHROUGH();
+    }
+
+    case XLTT_STAGE_SESSION_SUCCESS: {
+      input = "<iq type='result' id='1'/>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test"
+          "</test:app-stanza>", handler_->OutputActivity());
+      EXPECT_EQ("[OPEN]", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      if (endstage == XLTT_STAGE_SESSION_SUCCESS)
+        return;
+      FALLTHROUGH();
+    }
+    default:
+      break;
+  }
+}
+
+TEST_F(XmppLoginTaskTest, TestUtf8Good) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT);
+
+  std::string input = "<?xml version='1.0' encoding='UTF-8'?>"
+      "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestNonUtf8Bad) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT);
+
+  std::string input = "<?xml version='1.0' encoding='ISO-8859-1'?>"
+      "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestNoFeatures) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<iq type='get' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsRequiredNotPresent) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsRequeiredAndPresent) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>"
+        "<required/>"
+      "</starttls>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>X-GOOGLE-TOKEN</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+        "<mechanism>X-OAUTH2</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
+      handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsEnabledNotPresent) {
+  SetTlsOptions(buzz::TLS_ENABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsEnabledAndPresent) {
+  SetTlsOptions(buzz::TLS_ENABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>X-GOOGLE-TOKEN</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+        "<mechanism>X-OAUTH2</mechanism>"
+      "</mechanisms>"
+      "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsDisabledNotPresent) {
+  SetTlsOptions(buzz::TLS_DISABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+    std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsDisabledAndPresent) {
+  SetTlsOptions(buzz::TLS_DISABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>X-GOOGLE-TOKEN</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+        "<mechanism>X-OAUTH2</mechanism>"
+      "</mechanisms>"
+      "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsFailure) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_FEATURES);
+
+  std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsBadStream) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_PROCEED);
+
+  std::string input = "<wrongtag>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestMissingSaslPlain) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_ENCRYPTED_START);
+
+  std::string input = "<stream:features>"
+        "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+          "<mechanism>DIGEST-MD5</mechanism>"
+        "</mechanisms>"
+       "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-AUTH]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestWrongPassword) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_FEATURES);
+
+  std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-UNAUTHORIZED]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestAuthBadStream) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_SUCCESS);
+
+  std::string input = "<wrongtag>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestMissingBindFeature) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START);
+
+  std::string input = "<stream:features>"
+          "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
+        "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestMissingSessionFeature) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START);
+
+  std::string input = "<stream:features>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
+        "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+/* TODO: Handle this case properly inside XmppLoginTask.
+TEST_F(XmppLoginTaskTest, TestBindFailure1) {
+  // check wrong JID
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='result' id='0'>"
+      "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
+      "<jid>davey@my-server/test</jid></bind></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+*/
+
+TEST_F(XmppLoginTaskTest, TestBindFailure2) {
+  // check missing JID
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='result' id='0'>"
+      "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestBindFailure3) {
+  // check plain failure
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='error' id='0'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestBindFailure4) {
+  // check wrong id to ignore
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='error' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  // continue after an ignored iq
+  RunPartialLogin(XLTT_STAGE_BIND_SUCCESS, XLTT_STAGE_SESSION_SUCCESS);
+}
+
+TEST_F(XmppLoginTaskTest, TestSessionFailurePlain1) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS);
+
+  std::string input = "<iq type='error' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestSessionFailurePlain2) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS);
+
+  // check reverse iq to ignore
+  // TODO: consider queueing or passing through?
+  std::string input = "<iq type='get' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+
+  // continue after an ignored iq
+  RunPartialLogin(XLTT_STAGE_SESSION_SUCCESS, XLTT_STAGE_SESSION_SUCCESS);
+}
+
+TEST_F(XmppLoginTaskTest, TestBadXml) {
+  int errorKind = 0;
+  for (XlttStage stage = XLTT_STAGE_CONNECT;
+      stage <= XLTT_STAGE_SESSION_SUCCESS;
+      stage = static_cast<XlttStage>(stage + 1)) {
+    RunPartialLogin(XLTT_STAGE_CONNECT, stage);
+
+    std::string input;
+    switch (errorKind++ % 5) {
+      case 0: input = "&syntax;"; break;
+      case 1: input = "<nons:iq/>"; break;
+      case 2: input = "<iq a='b' a='dupe'/>"; break;
+      case 3: input = "<>"; break;
+      case 4: input = "<iq a='<wrong>'>"; break;
+    }
+
+    engine()->HandleInput(input.c_str(), input.length());
+
+    EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+    EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity());
+
+    TearDown();
+    SetUp();
+  }
+}
+
+TEST_F(XmppLoginTaskTest, TestStreamError) {
+  for (XlttStage stage = XLTT_STAGE_CONNECT;
+      stage <= XLTT_STAGE_SESSION_SUCCESS;
+      stage = static_cast<XlttStage>(stage + 1)) {
+    switch (stage) {
+      case XLTT_STAGE_CONNECT:
+      case XLTT_STAGE_TLS_PROCEED:
+      case XLTT_STAGE_AUTH_SUCCESS:
+        continue;
+      default:
+        break;
+    }
+
+    RunPartialLogin(XLTT_STAGE_CONNECT, stage);
+
+    std::string input = "<stream:error>"
+        "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
+        "<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>"
+        "Some special application diagnostic information!"
+        "</text>"
+        "<escape-your-data xmlns='application-ns'/>"
+        "</stream:error>";
+
+    engine()->HandleInput(input.c_str(), input.length());
+
+    EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+    EXPECT_EQ("[CLOSED][ERROR-STREAM]", handler()->SessionActivity());
+
+    EXPECT_EQ("<str:error xmlns:str=\"http://etherx.jabber.org/streams\">"
+        "<xml-not-well-formed xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>"
+        "<text xml:lang=\"en\" xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\">"
+        "Some special application diagnostic information!"
+        "</text>"
+        "<escape-your-data xmlns=\"application-ns\"/>"
+        "</str:error>", engine()->GetStreamError()->Str());
+
+    TearDown();
+    SetUp();
+  }
+}
+
diff --git a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.cc b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.cc
new file mode 100644
index 0000000..278b988
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.cc
@@ -0,0 +1,89 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h"
+
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/webrtc/base/common.h"
+#ifdef EXPAT_RELATIVE_PATH
+#include "expat.h"
+#else
+#include "third_party/expat/v2_0_1/Source/lib/expat.h"
+#endif
+
+namespace buzz {
+
+XmppStanzaParser::XmppStanzaParser(XmppStanzaParseHandler *psph) :
+  psph_(psph),
+  innerHandler_(this),
+  parser_(&innerHandler_),
+  depth_(0),
+  builder_() {
+}
+
+void
+XmppStanzaParser::Reset() {
+  parser_.Reset();
+  depth_ = 0;
+  builder_.Reset();
+}
+
+void
+XmppStanzaParser::IncomingStartElement(
+    XmlParseContext * pctx, const char * name, const char ** atts) {
+  if (depth_++ == 0) {
+    XmlElement * pelStream = XmlBuilder::BuildElement(pctx, name, atts);
+    if (pelStream == NULL) {
+      pctx->RaiseError(XML_ERROR_SYNTAX);
+      return;
+    }
+    psph_->StartStream(pelStream);
+    delete pelStream;
+    return;
+  }
+
+  builder_.StartElement(pctx, name, atts);
+}
+
+void
+XmppStanzaParser::IncomingCharacterData(
+    XmlParseContext * pctx, const char * text, int len) {
+  if (depth_ > 1) {
+    builder_.CharacterData(pctx, text, len);
+  }
+}
+
+void
+XmppStanzaParser::IncomingEndElement(
+    XmlParseContext * pctx, const char * name) {
+  if (--depth_ == 0) {
+    psph_->EndStream();
+    return;
+  }
+
+  builder_.EndElement(pctx, name);
+
+  if (depth_ == 1) {
+    XmlElement *element = builder_.CreateElement();
+    psph_->Stanza(element);
+    delete element;
+  }
+}
+
+void
+XmppStanzaParser::IncomingError(
+    XmlParseContext * pctx, XML_Error errCode) {
+  RTC_UNUSED(pctx);
+  RTC_UNUSED(errCode);
+  psph_->XmlError();
+}
+
+}
diff --git a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h
new file mode 100644
index 0000000..0c67bf1
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h
@@ -0,0 +1,80 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
+
+#include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
+#include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
+
+
+namespace buzz {
+
+class XmlElement;
+
+class XmppStanzaParseHandler {
+public:
+  virtual ~XmppStanzaParseHandler() {}
+  virtual void StartStream(const XmlElement * pelStream) = 0;
+  virtual void Stanza(const XmlElement * pelStanza) = 0;
+  virtual void EndStream() = 0;
+  virtual void XmlError() = 0;
+};
+
+class XmppStanzaParser {
+public:
+  XmppStanzaParser(XmppStanzaParseHandler *psph);
+  bool Parse(const char * data, size_t len, bool isFinal)
+    { return parser_.Parse(data, len, isFinal); }
+  void Reset();
+
+private:
+  class ParseHandler : public XmlParseHandler {
+  public:
+    ParseHandler(XmppStanzaParser * outer) : outer_(outer) {}
+    virtual void StartElement(XmlParseContext * pctx,
+               const char * name, const char ** atts)
+      { outer_->IncomingStartElement(pctx, name, atts); }
+    virtual void EndElement(XmlParseContext * pctx,
+               const char * name)
+      { outer_->IncomingEndElement(pctx, name); }
+    virtual void CharacterData(XmlParseContext * pctx,
+               const char * text, int len)
+      { outer_->IncomingCharacterData(pctx, text, len); }
+    virtual void Error(XmlParseContext * pctx,
+               XML_Error errCode)
+      { outer_->IncomingError(pctx, errCode); }
+  private:
+    XmppStanzaParser * const outer_;
+  };
+
+  friend class ParseHandler;
+
+  void IncomingStartElement(XmlParseContext * pctx,
+               const char * name, const char ** atts);
+  void IncomingEndElement(XmlParseContext * pctx,
+               const char * name);
+  void IncomingCharacterData(XmlParseContext * pctx,
+               const char * text, int len);
+  void IncomingError(XmlParseContext * pctx,
+               XML_Error errCode);
+
+  XmppStanzaParseHandler * psph_;
+  ParseHandler innerHandler_;
+  XmlParser parser_;
+  int depth_;
+  XmlBuilder builder_;
+
+ };
+
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
new file mode 100644
index 0000000..109701b3
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
@@ -0,0 +1,175 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h"
+#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/gunit.h"
+
+using buzz::QName;
+using buzz::XmlElement;
+using buzz::XmppStanzaParser;
+using buzz::XmppStanzaParseHandler;
+
+class XmppStanzaParserTestHandler : public XmppStanzaParseHandler {
+ public:
+  virtual void StartStream(const XmlElement * element) {
+    ss_ << "START" << element->Str();
+  }
+  virtual void Stanza(const XmlElement * element) {
+    ss_ << "STANZA" << element->Str();
+  }
+  virtual void EndStream() {
+    ss_ << "END";
+  }
+  virtual void XmlError() {
+    ss_ << "ERROR";
+  }
+
+  std::string Str() {
+    return ss_.str();
+  }
+
+  std::string StrClear() {
+    std::string result = ss_.str();
+    ss_.str("");
+    return result;
+  }
+
+ private:
+  std::stringstream ss_;
+};
+
+
+TEST(XmppStanzaParserTest, TestTrivial) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<trivial/>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<trivial/>END", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestStanzaAtATime) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xmlns:stream='str'>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+
+  fragment = "<message type='foo'><body>hello</body></message>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">"
+      "<c:body>hello</c:body></c:message>", handler.StrClear());
+
+  fragment = " SOME TEXT TO IGNORE ";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "<iq type='set' id='123'><abc xmlns='def'/></iq>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:iq type=\"set\" id=\"123\" xmlns:c=\"j:c\">"
+      "<abc xmlns=\"def\"/></c:iq>", handler.StrClear());
+
+  fragment = "</stream:stream>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("END", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestFragmentedStanzas) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xml";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "ns:stream='str'><message type='foo'><body>hel";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+
+  fragment = "lo</body></message> IGNORE ME <iq type='set' id='123'>"
+      "<abc xmlns='def'/></iq></st";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">"
+      "<c:body>hello</c:body></c:message>STANZA<c:iq type=\"set\" id=\"123\" "
+      "xmlns:c=\"j:c\"><abc xmlns=\"def\"/></c:iq>", handler.StrClear());
+
+  fragment = "ream:stream>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("END", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestReset) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xml";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  parser.Reset();
+  fragment = "<stream:stream id='abc' xmlns='j:c' xml";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "ns:stream='str'><message type='foo'><body>hel";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+  parser.Reset();
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xmlns:stream='str'>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+
+  fragment = "<message type='foo'><body>hello</body></message>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">"
+      "<c:body>hello</c:body></c:message>", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestError) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<-foobar/>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("ERROR", handler.StrClear());
+
+  parser.Reset();
+  fragment = "<stream:stream/>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("ERROR", handler.StrClear());
+  parser.Reset();
+
+  fragment = "ns:stream='str'><message type='foo'><body>hel";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("ERROR", handler.StrClear());
+  parser.Reset();
+
+  fragment = "<stream:stream xmlns:stream='st' xmlns='jc'>"
+      "<foo/><bar><st:foobar/></bar>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream xmlns:stream=\"st\" xmlns=\"jc\"/>STANZA"
+      "<jc:foo xmlns:jc=\"jc\"/>ERROR", handler.StrClear());
+}
diff --git a/third_party/libjingle_xmpp/xmpp/xmpptask.cc b/third_party/libjingle_xmpp/xmpp/xmpptask.cc
new file mode 100644
index 0000000..40b6e53a
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmpptask.cc
@@ -0,0 +1,158 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "third_party/libjingle_xmpp/xmpp/constants.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/libjingle_xmpp/xmpp/xmpptask.h"
+
+namespace buzz {
+
+XmppClientInterface::XmppClientInterface() {
+}
+
+XmppClientInterface::~XmppClientInterface() {
+}
+
+XmppTask::XmppTask(XmppTaskParentInterface* parent,
+                   XmppEngine::HandlerLevel level)
+    : XmppTaskBase(parent), stopped_(false) {
+#if !defined(NDEBUG)
+  debug_force_timeout_ = false;
+#endif
+
+  id_ = GetClient()->NextId();
+  GetClient()->AddXmppTask(this, level);
+  GetClient()->SignalDisconnected.connect(this, &XmppTask::OnDisconnect);
+}
+
+XmppTask::~XmppTask() {
+  StopImpl();
+}
+
+void XmppTask::StopImpl() {
+  while (NextStanza() != NULL) {}
+  if (!stopped_) {
+    GetClient()->RemoveXmppTask(this);
+    GetClient()->SignalDisconnected.disconnect(this);
+    stopped_ = true;
+  }
+}
+
+XmppReturnStatus XmppTask::SendStanza(const XmlElement* stanza) {
+  if (stopped_)
+    return XMPP_RETURN_BADSTATE;
+  return GetClient()->SendStanza(stanza);
+}
+
+XmppReturnStatus XmppTask::SendStanzaError(const XmlElement* element_original,
+                                           XmppStanzaError code,
+                                           const std::string& text) {
+  if (stopped_)
+    return XMPP_RETURN_BADSTATE;
+  return GetClient()->SendStanzaError(element_original, code, text);
+}
+
+void XmppTask::Stop() {
+  StopImpl();
+  Task::Stop();
+}
+
+void XmppTask::OnDisconnect() {
+  Error();
+}
+
+void XmppTask::QueueStanza(const XmlElement* stanza) {
+#if !defined(NDEBUG)
+  if (debug_force_timeout_)
+    return;
+#endif
+
+  stanza_queue_.push_back(new XmlElement(*stanza));
+  Wake();
+}
+
+const XmlElement* XmppTask::NextStanza() {
+  XmlElement* result = NULL;
+  if (!stanza_queue_.empty()) {
+    result = stanza_queue_.front();
+    stanza_queue_.pop_front();
+  }
+  next_stanza_.reset(result);
+  return result;
+}
+
+XmlElement* XmppTask::MakeIq(const std::string& type,
+                             const buzz::Jid& to,
+                             const std::string& id) {
+  XmlElement* result = new XmlElement(QN_IQ);
+  if (!type.empty())
+    result->AddAttr(QN_TYPE, type);
+  if (!to.IsEmpty())
+    result->AddAttr(QN_TO, to.Str());
+  if (!id.empty())
+    result->AddAttr(QN_ID, id);
+  return result;
+}
+
+XmlElement* XmppTask::MakeIqResult(const XmlElement * query) {
+  XmlElement* result = new XmlElement(QN_IQ);
+  result->AddAttr(QN_TYPE, STR_RESULT);
+  if (query->HasAttr(QN_FROM)) {
+    result->AddAttr(QN_TO, query->Attr(QN_FROM));
+  }
+  result->AddAttr(QN_ID, query->Attr(QN_ID));
+  return result;
+}
+
+bool XmppTask::MatchResponseIq(const XmlElement* stanza,
+                               const Jid& to,
+                               const std::string& id) {
+  if (stanza->Name() != QN_IQ)
+    return false;
+
+  if (stanza->Attr(QN_ID) != id)
+    return false;
+
+  return MatchStanzaFrom(stanza, to);
+}
+
+bool XmppTask::MatchStanzaFrom(const XmlElement* stanza,
+                               const Jid& to) {
+  Jid from(stanza->Attr(QN_FROM));
+  if (from == to)
+    return true;
+
+  // We address the server as "", check if we are doing so here.
+  if (!to.IsEmpty())
+    return false;
+
+  // It is legal for the server to identify itself with "domain" or
+  // "myself@domain"
+  Jid me = GetClient()->jid();
+  return (from == Jid(me.domain())) || (from == me.BareJid());
+}
+
+bool XmppTask::MatchRequestIq(const XmlElement* stanza,
+                              const std::string& type,
+                              const QName& qn) {
+  if (stanza->Name() != QN_IQ)
+    return false;
+
+  if (stanza->Attr(QN_TYPE) != type)
+    return false;
+
+  if (stanza->FirstNamed(qn) == NULL)
+    return false;
+
+  return true;
+}
+
+}
diff --git a/third_party/libjingle_xmpp/xmpp/xmpptask.h b/third_party/libjingle_xmpp/xmpp/xmpptask.h
new file mode 100644
index 0000000..e302686
--- /dev/null
+++ b/third_party/libjingle_xmpp/xmpp/xmpptask.h
@@ -0,0 +1,175 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
+
+#include <deque>
+#include <memory>
+#include <string>
+
+#include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
+#include "third_party/webrtc/base/constructormagic.h"
+#include "third_party/webrtc/base/sigslot.h"
+#include "third_party/webrtc/base/task.h"
+#include "third_party/webrtc/base/taskparent.h"
+
+namespace buzz {
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPTASK
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task and XmppClient first.
+//
+// XmppTask is a task that is designed to go underneath XmppClient and be
+// useful there.  It has a way of finding its XmppClient parent so you
+// can have it nested arbitrarily deep under an XmppClient and it can
+// still find the XMPP services.
+//
+// Tasks register themselves to listen to particular kinds of stanzas
+// that are sent out by the client.  Rather than processing stanzas
+// right away, they should decide if they own the sent stanza,
+// and if so, queue it and Wake() the task, or if a stanza does not belong
+// to you, return false right away so the next XmppTask can take a crack.
+// This technique (synchronous recognize, but asynchronous processing)
+// allows you to have arbitrary logic for recognizing stanzas yet still,
+// for example, disconnect a client while processing a stanza -
+// without reentrancy problems.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppTask;
+
+// XmppClientInterface is an abstract interface for sending and
+// handling stanzas.  It can be implemented for unit tests or
+// different network environments.  It will usually be implemented by
+// XmppClient.
+class XmppClientInterface {
+ public:
+  XmppClientInterface();
+  virtual ~XmppClientInterface();
+
+  virtual XmppEngine::State GetState() const = 0;
+  virtual const Jid& jid() const = 0;
+  virtual std::string NextId() = 0;
+  virtual XmppReturnStatus SendStanza(const XmlElement* stanza) = 0;
+  virtual XmppReturnStatus SendStanzaError(const XmlElement* original_stanza,
+                                           XmppStanzaError error_code,
+                                           const std::string& message) = 0;
+  virtual void AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) = 0;
+  virtual void RemoveXmppTask(XmppTask* task) = 0;
+  sigslot::signal0<> SignalDisconnected;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(XmppClientInterface);
+};
+
+// XmppTaskParentInterface is the interface require for any parent of
+// an XmppTask.  It needs, for example, a way to get an
+// XmppClientInterface.
+
+// We really ought to inherit from a TaskParentInterface, but we tried
+// that and it's way too complicated to change
+// Task/TaskParent/TaskRunner.  For now, this works.
+class XmppTaskParentInterface : public rtc::Task {
+ public:
+  explicit XmppTaskParentInterface(rtc::TaskParent* parent)
+      : Task(parent) {
+  }
+  virtual ~XmppTaskParentInterface() {}
+
+  virtual XmppClientInterface* GetClient() = 0;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(XmppTaskParentInterface);
+};
+
+class XmppTaskBase : public XmppTaskParentInterface {
+ public:
+  explicit XmppTaskBase(XmppTaskParentInterface* parent)
+      : XmppTaskParentInterface(parent),
+        parent_(parent) {
+  }
+  virtual ~XmppTaskBase() {}
+
+  virtual XmppClientInterface* GetClient() {
+    return parent_->GetClient();
+  }
+
+ protected:
+  XmppTaskParentInterface* parent_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(XmppTaskBase);
+};
+
+class XmppTask : public XmppTaskBase,
+                 public XmppStanzaHandler,
+                 public sigslot::has_slots<>
+{
+ public:
+  XmppTask(XmppTaskParentInterface* parent,
+           XmppEngine::HandlerLevel level = XmppEngine::HL_NONE);
+  virtual ~XmppTask();
+
+  std::string task_id() const { return id_; }
+  void set_task_id(std::string id) { id_ = id; }
+
+#if !defined(NDEBUG)
+  void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; }
+#endif
+
+  virtual bool HandleStanza(const XmlElement* stanza) { return false; }
+
+ protected:
+  XmppReturnStatus SendStanza(const XmlElement* stanza);
+  XmppReturnStatus SetResult(const std::string& code);
+  XmppReturnStatus SendStanzaError(const XmlElement* element_original,
+                                   XmppStanzaError code,
+                                   const std::string& text);
+
+  virtual void Stop();
+  virtual void OnDisconnect();
+
+  virtual void QueueStanza(const XmlElement* stanza);
+  const XmlElement* NextStanza();
+
+  bool MatchStanzaFrom(const XmlElement* stanza, const Jid& match_jid);
+
+  bool MatchResponseIq(const XmlElement* stanza, const Jid& to,
+                       const std::string& task_id);
+
+  static bool MatchRequestIq(const XmlElement* stanza, const std::string& type,
+                             const QName& qn);
+  static XmlElement *MakeIqResult(const XmlElement* query);
+  static XmlElement *MakeIq(const std::string& type,
+                            const Jid& to, const std::string& task_id);
+
+  // Returns true if the task is under the specified rate limit and updates the
+  // rate limit accordingly
+  bool VerifyTaskRateLimit(const std::string task_name, int max_count,
+                           int per_x_seconds);
+
+private:
+  void StopImpl();
+
+  bool stopped_;
+  std::deque<XmlElement*> stanza_queue_;
+  std::unique_ptr<XmlElement> next_stanza_;
+  std::string id_;
+
+#if !defined(NDEBUG)
+  bool debug_force_timeout_;
+#endif
+};
+
+}  // namespace buzz
+
+#endif // WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py
index dc2629f..d4c691c7 100644
--- a/tools/perf/page_sets/system_health/browsing_stories.py
+++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -89,7 +89,6 @@
         repeat_count=self.MAIN_PAGE_SCROLL_REPEAT)
 
 
-@decorators.Disabled('android')  # crbug.com/676338
 class CnnStory(_NewsBrowsingStory):
   """The second top website in http://www.alexa.com/topsites/category/News"""
   NAME = 'browse:news:cnn'
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc
index 76ecba7..344951e 100644
--- a/ui/base/clipboard/clipboard_win.cc
+++ b/ui/base/clipboard/clipboard_win.cc
@@ -616,8 +616,7 @@
                      1.0f,
                      false);
   {
-    skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
-    HDC dc = scoped_platform_paint.GetNativeDrawingContext();
+    HDC dc = skia::GetNativeDrawingContext(canvas.sk_canvas());
     ::SetDIBitsToDevice(dc, 0, 0, bitmap->bmiHeader.biWidth,
                         bitmap->bmiHeader.biHeight, 0, 0, 0,
                         bitmap->bmiHeader.biHeight, bitmap_bits, bitmap,
diff --git a/ui/gfx/canvas_paint_mac.mm b/ui/gfx/canvas_paint_mac.mm
index f29a6af..9d2bbb3 100644
--- a/ui/gfx/canvas_paint_mac.mm
+++ b/ui/gfx/canvas_paint_mac.mm
@@ -25,9 +25,8 @@
     canvas->restoreToCount(1);
 
     // Blit the dirty rect to the current context.
-    skia::ScopedPlatformPaint spp(canvas);
     CGImageRef image =
-        CGBitmapContextCreateImage(spp.GetNativeDrawingContext());
+        CGBitmapContextCreateImage(skia::GetNativeDrawingContext(canvas));
     CGRect dest_rect = NSRectToCGRect(rectangle_);
 
     CGContextRef destination_context =
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index e811036b..46108aad 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -278,8 +278,7 @@
       break;
   }
 
-  skia::ScopedPlatformPaint paint(canvas);
-  HDC surface = paint.GetNativeDrawingContext();
+  HDC surface = skia::GetNativeDrawingContext(canvas);
 
   // When drawing the task manager or the bookmark editor, we draw into an
   // offscreen buffer, where we can use OS-specific drawing routines for