Bug 1232348 - adjust nested-frame checking condition. r=baku. draft
authorAlastor Wu <alwu@mozilla.com>
Tue, 22 Dec 2015 10:24:49 +0800
changeset 316767 1da2c189dc708458e0790243f5e44be08bdc4ae8
parent 316653 45929dd5f2b019a03defb052b4ba4ebc668d1026
child 512215 86c9c5025d91b080c5a3b867d294af87e1c7ee2c
push id8608
push useralwu@mozilla.com
push dateTue, 22 Dec 2015 02:25:01 +0000
reviewersbaku
bugs1232348
milestone45.0a1
Bug 1232348 - adjust nested-frame checking condition. r=baku.
dom/browser-element/BrowserElementAudioChannel.cpp
dom/browser-element/BrowserElementAudioChannel.h
--- a/dom/browser-element/BrowserElementAudioChannel.cpp
+++ b/dom/browser-element/BrowserElementAudioChannel.cpp
@@ -1,23 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BrowserElementAudioChannel.h"
 
+#include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/BrowserElementAudioChannelBinding.h"
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "AudioChannelService.h"
+#include "nsIAppsService.h"
 #include "nsIBrowserElementAPI.h"
 #include "nsIDocShell.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsIObserverService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITabParent.h"
@@ -571,35 +573,24 @@ BrowserElementAudioChannel::Observe(nsIS
     if (mTabParent == aSubject) {
       ProcessStateChanged(aData);
     }
 
     return NS_OK;
   }
 
   nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
-  // This can be a nested iframe.
   if (!wrapper) {
-    nsCOMPtr<nsITabParent> iTabParent = do_QueryInterface(aSubject);
-    if (!iTabParent) {
-      return NS_ERROR_FAILURE;
+    bool isNested = false;
+    nsresult rv = IsFromNestedFrame(aSubject, isNested);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
     }
 
-    RefPtr<TabParent> tabParent = TabParent::GetFrom(iTabParent);
-    if (!tabParent) {
-      return NS_ERROR_FAILURE;
-    }
-
-    Element* element = tabParent->GetOwnerElement();
-    if (!element) {
-      return NS_ERROR_FAILURE;
-    }
-
-    nsCOMPtr<nsPIDOMWindow> window = element->OwnerDoc()->GetWindow();
-    if (window == mFrameWindow) {
+    if (isNested) {
       ProcessStateChanged(aData);
     }
 
     return NS_OK;
   }
 
   uint64_t windowID;
   nsresult rv = wrapper->GetData(&windowID);
@@ -622,10 +613,83 @@ BrowserElementAudioChannel::ProcessState
          ("BrowserElementAudioChannel, ProcessStateChanged, this = %p, "
           "type = %d\n", this, mAudioChannel));
 
   nsAutoString value(aData);
   mState = value.EqualsASCII("active") ? eStateActive : eStateInactive;
   DispatchTrustedEvent(NS_LITERAL_STRING("activestatechanged"));
 }
 
+bool
+BrowserElementAudioChannel::IsSystemAppWindow(nsPIDOMWindow* aWindow) const
+{
+  nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
+  if (!doc) {
+    return false;
+  }
+
+  uint32_t appId;
+  nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
+  nsresult rv = principal->GetAppId(&appId);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  if (appId == nsIScriptSecurityManager::NO_APP_ID ||
+      appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
+    return false;
+  }
+
+  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
+  if (NS_WARN_IF(!appsService)) {
+    return false;
+  }
+
+  nsAdoptingString systemAppManifest =
+    mozilla::Preferences::GetString("b2g.system_manifest_url");
+  if (!systemAppManifest) {
+    return false;
+  }
+
+  uint32_t systemAppId;
+  appsService->GetAppLocalIdByManifestURL(systemAppManifest, &systemAppId);
+
+  if (systemAppId == appId) {
+    return true;
+  }
+
+  return false;
+}
+
+nsresult
+BrowserElementAudioChannel::IsFromNestedFrame(nsISupports* aSubject,
+                                              bool& aIsNested) const
+{
+  aIsNested = false;
+  nsCOMPtr<nsITabParent> iTabParent = do_QueryInterface(aSubject);
+  if (!iTabParent) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<TabParent> tabParent = TabParent::GetFrom(iTabParent);
+  if (!tabParent) {
+    return NS_ERROR_FAILURE;
+  }
+
+  Element* element = tabParent->GetOwnerElement();
+  if (!element) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Since the normal OOP processes are opened out from b2g process, the owner
+  // of their tabParent are the same - system app window. Therefore, in order
+  // to find the case of nested MozFrame, we need to exclude this situation.
+  nsCOMPtr<nsPIDOMWindow> window = element->OwnerDoc()->GetWindow();
+  if (window == mFrameWindow && !IsSystemAppWindow(window)) {
+    aIsNested = true;
+    return NS_OK;
+  }
+
+  return NS_OK;
+}
+
 } // dom namespace
 } // mozilla namespace
--- a/dom/browser-element/BrowserElementAudioChannel.h
+++ b/dom/browser-element/BrowserElementAudioChannel.h
@@ -65,16 +65,23 @@ public:
 
 private:
   BrowserElementAudioChannel(nsPIDOMWindow* aWindow,
                              nsIFrameLoader* aFrameLoader,
                              nsIBrowserElementAPI* aAPI,
                              AudioChannel aAudioChannel,
                              const nsAString& aManifestURL);
 
+  bool IsSystemAppWindow(nsPIDOMWindow* aWindow) const;
+
+  // This method is used to check whether we're in the nested-mozbrower-frame
+  // situation, see bug1214148.
+  nsresult IsFromNestedFrame(nsISupports* aSubject,
+                             bool& aIsNested) const;
+
   ~BrowserElementAudioChannel();
 
   nsresult Initialize();
 
   void ProcessStateChanged(const char16_t* aData);
 
   nsCOMPtr<nsIFrameLoader> mFrameLoader;
   nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;