Bug 1522137 - Move resource://android handler to C++. r=mayhemer
authorAgi Sferro <agi@mozilla.com>
Mon, 25 Feb 2019 15:38:21 +0000
changeset 460918 c79d6bd85dd8b07ac3e6f1cf7c02d5d2b708302f
parent 460917 b9a1181a0f15eeedf907456d939cb3b4e36bc8f4
child 460919 54102692d3852d6e42a3cf24828750682eaf91d9
push id35613
push usernerli@mozilla.com
push dateTue, 26 Feb 2019 03:52:35 +0000
treeherdermozilla-central@faec87a80ed1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1522137
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1522137 - Move resource://android handler to C++. r=mayhemer This is needed to make the handler to avoid race conditions where some code tries to access a resource://android URI before the handler has been registered. Depends on D18739 Differential Revision: https://phabricator.services.mozilla.com/D18740
mobile/android/components/BrowserCLH.js
mobile/android/components/geckoview/GeckoViewStartup.js
netwerk/protocol/res/nsResProtocolHandler.cpp
netwerk/protocol/res/nsResProtocolHandler.h
--- a/mobile/android/components/BrowserCLH.js
+++ b/mobile/android/components/BrowserCLH.js
@@ -15,37 +15,19 @@ XPCOMUtils.defineLazyModuleGetters(this,
   Services: "resource://gre/modules/Services.jsm",
 });
 
 function BrowserCLH() {
   this.wrappedJSObject = this;
 }
 
 BrowserCLH.prototype = {
-  /**
-   * Register resource://android as the APK root.
-   *
-   * Consumers can access Android assets using resource://android/assets/FILENAME.
-   */
-  setResourceSubstitutions: function() {
-    let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
-    // Like jar:jar:file:///data/app/org.mozilla.fennec-2.apk!/assets/omni.ja!/chrome/chrome/content/aboutHome.xhtml
-    let url = registry.convertChromeURL(Services.io.newURI("chrome://browser/content/aboutHome.xhtml")).spec;
-    // Like jar:file:///data/app/org.mozilla.fennec-2.apk!/
-    url = url.substring(4, url.indexOf("!/") + 2);
-
-    let protocolHandler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
-    protocolHandler.setSubstitution("android", Services.io.newURI(url));
-  },
-
   observe: function(subject, topic, data) {
     switch (topic) {
       case "app-startup": {
-        this.setResourceSubstitutions();
-
         Services.obs.addObserver(this, "chrome-document-interactive");
         Services.obs.addObserver(this, "content-document-interactive");
 
         ActorManagerParent.flush();
 
         GeckoViewUtils.addLazyGetter(this, "DownloadNotifications", {
           module: "resource://gre/modules/DownloadNotifications.jsm",
           observers: ["chrome-document-loaded"],
--- a/mobile/android/components/geckoview/GeckoViewStartup.js
+++ b/mobile/android/components/geckoview/GeckoViewStartup.js
@@ -20,32 +20,16 @@ const {debug, warn} = GeckoViewUtils.ini
 function GeckoViewStartup() {
 }
 
 GeckoViewStartup.prototype = {
   classID: Components.ID("{8e993c34-fdd6-432c-967e-f995d888777f}"),
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
-  /**
-   * Register resource://android as the APK root.
-   *
-   * Consumers can access Android assets using resource://android/assets/FILENAME.
-   */
-  setResourceSubstitutions: function() {
-    let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
-    // Like jar:jar:file:///data/app/org.mozilla.geckoview.test.apk!/assets/omni.ja!/chrome/geckoview/content/geckoview.js
-    let url = registry.convertChromeURL(Services.io.newURI("chrome://geckoview/content/geckoview.js")).spec;
-    // Like jar:file:///data/app/org.mozilla.geckoview.test.apk!/
-    url = url.substring(4, url.indexOf("!/") + 2);
-
-    let protocolHandler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
-    protocolHandler.setSubstitution("android", Services.io.newURI(url));
-  },
-
   /* ----------  nsIObserver  ---------- */
   observe: function(aSubject, aTopic, aData) {
     debug `observe: ${aTopic}`;
     switch (aTopic) {
       case "app-startup": {
         // Parent and content process.
         GeckoViewUtils.addLazyGetter(this, "GeckoViewPermission", {
           service: "@mozilla.org/content-permission/prompt;1",
@@ -79,19 +63,16 @@ GeckoViewStartup.prototype = {
           notifyInvalidSubmit: (form, element) => {
             // We should show the validation message here, bug 1510450.
           },
         }, "invalidformsubmit");
 
         if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) {
           ActorManagerParent.flush();
 
-          // Parent process only.
-          this.setResourceSubstitutions();
-
           Services.mm.loadFrameScript(
               "chrome://geckoview/content/GeckoViewPromptChild.js", true);
 
           GeckoViewUtils.addLazyGetter(this, "ContentCrashHandler", {
             module: "resource://gre/modules/ContentCrashHandler.jsm",
             observers: [
               "ipc:content-shutdown",
             ],
--- a/netwerk/protocol/res/nsResProtocolHandler.cpp
+++ b/netwerk/protocol/res/nsResProtocolHandler.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/Omnijar.h"
 
 using mozilla::LogLevel;
 using mozilla::Unused;
 using mozilla::dom::ContentParent;
 
 #define kAPP "app"
 #define kGRE "gre"
+#define kAndroid "android"
 
 nsresult nsResProtocolHandler::Init() {
   nsresult rv;
   rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, mAppURI);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, mGREURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -35,26 +36,59 @@ nsresult nsResProtocolHandler::Init() {
   // and we want to remove it.
   mGREURI.Truncate(mGREURI.Length() - 1);
   if (mAppURI.Length()) {
     mAppURI.Truncate(mAppURI.Length() - 1);
   } else {
     mAppURI = mGREURI;
   }
 
+#ifdef ANDROID
+  rv = GetApkURI(mApkURI);
+#endif
+
   // XXXbsmedberg Neil wants a resource://pchrome/ for the profile chrome dir...
   // but once I finish multiple chrome registration I'm not sure that it is
   // needed
 
   // XXX dveditz: resource://pchrome/ defeats profile directory salting
   // if web content can load it. Tread carefully.
 
   return rv;
 }
 
+#ifdef ANDROID
+nsresult nsResProtocolHandler::GetApkURI(nsACString& aResult) {
+  nsCString::const_iterator start, iter;
+  mGREURI.BeginReading(start);
+  mGREURI.EndReading(iter);
+  nsCString::const_iterator start_iter = start;
+
+  // This is like jar:jar:file://path/to/apk/base.apk!/path/to/omni.ja!/
+  bool found = FindInReadable(NS_LITERAL_CSTRING("!/"), start_iter, iter);
+  NS_ENSURE_TRUE(found, NS_ERROR_UNEXPECTED);
+
+  // like jar:jar:file://path/to/apk/base.apk!/
+  const nsDependentCSubstring& withoutPath = Substring(start, iter);
+  NS_ENSURE_TRUE(withoutPath.Length() >= 4, NS_ERROR_UNEXPECTED);
+
+  // Let's make sure we're removing what we expect to remove
+  NS_ENSURE_TRUE(Substring(withoutPath, 0, 4).EqualsLiteral("jar:"),
+                 NS_ERROR_UNEXPECTED);
+
+  // like jar:file://path/to/apk/base.apk!/
+  aResult = ToNewCString(Substring(withoutPath, 4));
+
+  // Remove the trailing /
+  NS_ENSURE_TRUE(aResult.Length() >= 1, NS_ERROR_UNEXPECTED);
+  aResult.Truncate(aResult.Length() - 1);
+  return NS_OK;
+}
+#endif
+
 //----------------------------------------------------------------------------
 // nsResProtocolHandler::nsISupports
 //----------------------------------------------------------------------------
 
 NS_IMPL_QUERY_INTERFACE(nsResProtocolHandler, nsIResProtocolHandler,
                         nsISubstitutingProtocolHandler, nsIProtocolHandler,
                         nsISupportsWeakReference)
 NS_IMPL_ADDREF_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
@@ -93,43 +127,53 @@ nsresult nsResProtocolHandler::GetSubsti
 bool nsResProtocolHandler::ResolveSpecialCases(const nsACString& aHost,
                                                const nsACString& aPath,
                                                const nsACString& aPathname,
                                                nsACString& aResult) {
   if (aHost.EqualsLiteral("") || aHost.EqualsLiteral(kAPP)) {
     aResult.Assign(mAppURI);
   } else if (aHost.Equals(kGRE)) {
     aResult.Assign(mGREURI);
+#ifdef ANDROID
+  } else if (aHost.Equals(kAndroid)) {
+    aResult.Assign(mApkURI);
+#endif
   } else {
     return false;
   }
   aResult.Append(aPath);
   return true;
 }
 
 nsresult nsResProtocolHandler::SetSubstitution(const nsACString& aRoot,
                                                nsIURI* aBaseURI) {
   MOZ_ASSERT(!aRoot.EqualsLiteral(""));
   MOZ_ASSERT(!aRoot.EqualsLiteral(kAPP));
   MOZ_ASSERT(!aRoot.EqualsLiteral(kGRE));
+  MOZ_ASSERT(!aRoot.EqualsLiteral(kAndroid));
   return SubstitutingProtocolHandler::SetSubstitution(aRoot, aBaseURI);
 }
 
 nsresult nsResProtocolHandler::SetSubstitutionWithFlags(const nsACString& aRoot,
                                                         nsIURI* aBaseURI,
                                                         uint32_t aFlags) {
   MOZ_ASSERT(!aRoot.EqualsLiteral(""));
   MOZ_ASSERT(!aRoot.EqualsLiteral(kAPP));
   MOZ_ASSERT(!aRoot.EqualsLiteral(kGRE));
+  MOZ_ASSERT(!aRoot.EqualsLiteral(kAndroid));
   return SubstitutingProtocolHandler::SetSubstitutionWithFlags(aRoot, aBaseURI,
                                                                aFlags);
 }
 
 nsresult nsResProtocolHandler::HasSubstitution(const nsACString& aRoot,
                                                bool* aResult) {
-  if (aRoot.EqualsLiteral(kAPP) || aRoot.EqualsLiteral(kGRE)) {
+  if (aRoot.EqualsLiteral(kAPP) || aRoot.EqualsLiteral(kGRE)
+#ifdef ANDROID
+      || aRoot.EqualsLiteral(kAndroid)
+#endif
+  ) {
     *aResult = true;
     return NS_OK;
   }
 
   return mozilla::net::SubstitutingProtocolHandler::HasSubstitution(aRoot,
                                                                     aResult);
 }
--- a/netwerk/protocol/res/nsResProtocolHandler.h
+++ b/netwerk/protocol/res/nsResProtocolHandler.h
@@ -68,11 +68,16 @@ class nsResProtocolHandler final
   MOZ_MUST_USE bool ResolveSpecialCases(const nsACString& aHost,
                                         const nsACString& aPath,
                                         const nsACString& aPathname,
                                         nsACString& aResult) override;
 
  private:
   nsCString mAppURI;
   nsCString mGREURI;
+#ifdef ANDROID
+  // Used for resource://android URIs
+  nsCString mApkURI;
+  nsresult GetApkURI(nsACString& aResult);
+#endif
 };
 
 #endif /* nsResProtocolHandler_h___ */