Bug 1287107 - Making transition alive with gaia as chrome:// r=bholley,fabrice
☠☠ backed out by 35921a0c3857 ☠ ☠
authorFabrice Desré <fabrice@mozilla.com>
Thu, 03 Mar 2016 09:58:47 -0800
changeset 346169 16aa7041c00965e0ead9e03b5f2ff2d8329c4e7d
parent 346168 aaf2540b99a332ebdd19e3b1ce830bc8b07ac635
child 346170 2868c140a299dfb3f036e1404c3ee2741938a525
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley, fabrice
bugs1287107
milestone50.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 1287107 - Making transition alive with gaia as chrome:// r=bholley,fabrice MozReview-Commit-ID: 9uVUrmuVFXQ
b2g/chrome/content/shell.js
b2g/components/Bootstraper.jsm
b2g/components/GaiaChrome.cpp
b2g/components/GaiaChrome.h
b2g/components/SafeMode.jsm
b2g/components/moz.build
b2g/components/nsIGaiaChrome.idl
b2g/installer/package-manifest.in
caps/tests/mochitest/chrome.ini
devtools/shared/apps/tests/mochitest.ini
dom/apps/AppsServiceChild.jsm
dom/apps/PermissionsTable.jsm
dom/apps/Webapps.jsm
dom/apps/tests/mochitest.ini
dom/broadcastchannel/tests/mochitest.ini
dom/cache/test/mochitest/mochitest.ini
dom/indexedDB/test/mochitest.ini
dom/ipc/tests/mochitest.ini
dom/security/test/csp/chrome.ini
dom/security/test/csp/mochitest.ini
dom/tests/mochitest/fetch/mochitest.ini
dom/tests/mochitest/localstorage/mochitest.ini
extensions/cookie/test/chrome.ini
js/xpconnect/src/nsXPConnect.cpp
netwerk/test/mochitests/mochitest.ini
testing/mochitest/tests/Harness_sanity/mochitest.ini
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -33,18 +33,16 @@ Cu.import('resource://gre/modules/Presen
 Cu.import('resource://gre/modules/AboutServiceWorkers.jsm');
 
 XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
                                   "resource://gre/modules/SystemAppProxy.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Screenshot",
                                   "resource://gre/modules/Screenshot.jsm");
 
-Cu.import('resource://gre/modules/Webapps.jsm');
-
 XPCOMUtils.defineLazyServiceGetter(Services, 'env',
                                    '@mozilla.org/process/environment;1',
                                    'nsIEnvironment');
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'ss',
                                    '@mozilla.org/content/style-sheet-service;1',
                                    'nsIStyleSheetService');
 
@@ -351,16 +349,17 @@ var shell = {
     }
 
     let homeURL = this.homeURL;
     if (!homeURL) {
       let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN';
       alert(msg);
       return;
     }
+
     let manifestURL = this.manifestURL;
     // <html:iframe id="systemapp"
     //              mozbrowser="true" allowfullscreen="true"
     //              style="overflow: hidden; height: 100%; width: 100%; border: none;"
     //              src="data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;'>"/>
     let systemAppFrame =
       document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe');
     systemAppFrame.setAttribute('id', 'systemapp');
@@ -417,21 +416,21 @@ var shell = {
     window.addEventListener('MozAfterPaint', this);
     window.addEventListener('sizemodechange', this);
     window.addEventListener('unload', this);
     this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
     this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this);
 
     CustomEventManager.init();
-    WebappsHelper.init();
     UserAgentOverrides.init();
     CaptivePortalLoginHelper.init();
 
     this.contentBrowser.src = homeURL;
+
     this._isEventListenerReady = false;
 
     window.performance.mark('gecko-shell-system-frame-set');
 
     ppmm.addMessageListener("content-handler", this);
     ppmm.addMessageListener("dial-handler", this);
     ppmm.addMessageListener("sms-handler", this);
     ppmm.addMessageListener("mail-handler", this);
@@ -776,25 +775,16 @@ var shell = {
   }
 };
 
 Services.obs.addObserver(function onFullscreenOriginChange(subject, topic, data) {
   shell.sendChromeEvent({ type: "fullscreenoriginchange",
                           fullscreenorigin: data });
 }, "fullscreen-origin-change", false);
 
-DOMApplicationRegistry.registryReady.then(function () {
-  // This event should be sent before System app returns with
-  // system-message-listener-ready mozContentEvent, because it's on
-  // the critical launch path of the app.
-  SystemAppProxy._sendCustomEvent('mozChromeEvent', {
-    type: 'webapps-registry-ready'
-  }, /* noPending */ true);
-});
-
 Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) {
   shell.sendChromeEvent({
     type: "bluetooth-volumeset",
     value: data
   });
 }, 'bluetooth-volume-change', false);
 
 Services.obs.addObserver(function(subject, topic, data) {
@@ -821,22 +811,16 @@ var CustomEventManager = {
     }).bind(this), false);
   },
 
   handleEvent: function custevt_handleEvent(evt) {
     let detail = evt.detail;
     dump('XXX FIXME : Got a mozContentEvent: ' + detail.type + "\n");
 
     switch(detail.type) {
-      case 'webapps-install-granted':
-      case 'webapps-install-denied':
-      case 'webapps-uninstall-granted':
-      case 'webapps-uninstall-denied':
-        WebappsHelper.handleEvent(detail);
-        break;
       case 'system-message-listener-ready':
         Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
         break;
       case 'captive-portal-login-cancel':
         CaptivePortalLoginHelper.handleEvent(detail);
         break;
       case 'inputmethod-update-layouts':
       case 'inputregistry-add':
@@ -885,102 +869,16 @@ var CustomEventManager = {
         break;
       case 'restart':
         restart();
         break;
     }
   }
 }
 
-var WebappsHelper = {
-  _installers: {},
-  _count: 0,
-
-  init: function webapps_init() {
-    Services.obs.addObserver(this, "webapps-launch", false);
-    Services.obs.addObserver(this, "webapps-ask-install", false);
-    Services.obs.addObserver(this, "webapps-ask-uninstall", false);
-    Services.obs.addObserver(this, "webapps-close", false);
-  },
-
-  registerInstaller: function webapps_registerInstaller(data) {
-    let id = "installer" + this._count++;
-    this._installers[id] = data;
-    return id;
-  },
-
-  handleEvent: function webapps_handleEvent(detail) {
-    if (!detail || !detail.id)
-      return;
-
-    let installer = this._installers[detail.id];
-    delete this._installers[detail.id];
-    switch (detail.type) {
-      case "webapps-install-granted":
-        DOMApplicationRegistry.confirmInstall(installer);
-        break;
-      case "webapps-install-denied":
-        DOMApplicationRegistry.denyInstall(installer);
-        break;
-      case "webapps-uninstall-granted":
-        DOMApplicationRegistry.confirmUninstall(installer);
-        break;
-      case "webapps-uninstall-denied":
-        DOMApplicationRegistry.denyUninstall(installer);
-        break;
-    }
-  },
-
-  observe: function webapps_observe(subject, topic, data) {
-    let json = JSON.parse(data);
-    json.mm = subject;
-
-    let id;
-
-    switch(topic) {
-      case "webapps-launch":
-        DOMApplicationRegistry.getManifestFor(json.manifestURL).then((aManifest) => {
-          if (!aManifest)
-            return;
-
-          let manifest = new ManifestHelper(aManifest, json.origin,
-                                            json.manifestURL);
-          let payload = {
-            timestamp: json.timestamp,
-            url: manifest.fullLaunchPath(json.startPoint),
-            manifestURL: json.manifestURL
-          };
-          shell.sendCustomEvent("webapps-launch", payload);
-        });
-        break;
-      case "webapps-ask-install":
-        id = this.registerInstaller(json);
-        shell.sendChromeEvent({
-          type: "webapps-ask-install",
-          id: id,
-          app: json.app
-        });
-        break;
-      case "webapps-ask-uninstall":
-        id = this.registerInstaller(json);
-        shell.sendChromeEvent({
-          type: "webapps-ask-uninstall",
-          id: id,
-          app: json.app
-        });
-        break;
-      case "webapps-close":
-        shell.sendCustomEvent("webapps-close", {
-          "manifestURL": json.manifestURL
-        });
-        break;
-    }
-  }
-}
-
 var KeyboardHelper = {
   handleEvent: function keyboard_handleEvent(detail) {
     switch (detail.type) {
       case 'inputmethod-update-layouts':
         Keyboard.setLayouts(detail.layouts);
 
         break;
       case 'inputregistry-add':
--- a/b2g/components/Bootstraper.jsm
+++ b/b2g/components/Bootstraper.jsm
@@ -7,17 +7,16 @@
 this.EXPORTED_SYMBOLS = ["Bootstraper"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const CC = Components.Constructor;
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Webapps.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 
 function debug(aMsg) {
   //dump("-*- Bootstraper: " + aMsg + "\n");
 }
 
 /**
   * This module loads the manifest for app from the --start-url enpoint and
@@ -54,17 +53,17 @@ this.Bootstraper = {
           manifestHash: AppsUtils.computeHash(JSON.stringify(aManifest)),
           appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED
         },
         appId: 1,
         isBrowser: false,
         isPackage: false
       };
 
-      DOMApplicationRegistry.confirmInstall(appData, null, aResolve);
+      //DOMApplicationRegistry.confirmInstall(appData, null, aResolve);
     });
   },
 
   /**
     * Resolves to a json manifest.
     */
   loadManifest: function() {
     return new Promise((aResolve, aReject) => {
@@ -97,16 +96,19 @@ this.Bootstraper = {
     return Promise.resolve();
   },
 
   /**
     * If a system app is already installed, uninstall it so that we can
     * cleanly replace it by the current one.
     */
   uninstallPreviousSystemApp: function() {
+    // TODO: FIXME
+    return Promise.resolve();
+
     let oldManifestURL;
     try{
       oldManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url");
     } catch(e) {
       // No preference set, so nothing to uninstall.
       return Promise.resolve();
     }
 
@@ -138,18 +140,17 @@ this.Bootstraper = {
     debug("Installing app from " + this._manifestURL);
 
     if (!this.isInstallRequired(this._manifestURL)) {
       debug("Already configured for " + this._manifestURL);
       return Promise.resolve();
     }
 
     return new Promise((aResolve, aReject) => {
-      DOMApplicationRegistry.registryReady
-          .then(this.uninstallPreviousSystemApp.bind(this))
+      this.uninstallPreviousSystemApp.bind(this)
           .then(this.loadManifest.bind(this))
           .then(this.installSystemApp.bind(this))
           .then(this.configure.bind(this))
           .then(aResolve)
           .catch(aReject);
     });
   }
 };
new file mode 100644
--- /dev/null
+++ b/b2g/components/GaiaChrome.cpp
@@ -0,0 +1,188 @@
+/* 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 "GaiaChrome.h"
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsChromeRegistry.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsLocalFile.h"
+#include "nsXULAppAPI.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/ModuleUtils.h"
+#include "mozilla/Services.h"
+#include "mozilla/FileLocation.h"
+
+#define NS_GAIACHROME_CID \
+  { 0x83f8f999, 0x6b87, 0x4dd8, { 0xa0, 0x93, 0x72, 0x0b, 0xfb, 0x67, 0x4d, 0x38 } }
+
+using namespace mozilla;
+
+StaticRefPtr<GaiaChrome> gGaiaChrome;
+
+NS_IMPL_ISUPPORTS(GaiaChrome, nsIGaiaChrome)
+
+GaiaChrome::GaiaChrome()
+  : mPackageName(NS_LITERAL_CSTRING("gaia"))
+  , mAppsDir(NS_LITERAL_STRING("apps"))
+  , mDataRoot(NS_LITERAL_STRING("/data/local"))
+  , mSystemRoot(NS_LITERAL_STRING("/system/b2g"))
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  GetProfileDir();
+  Register();
+}
+
+//virtual
+GaiaChrome::~GaiaChrome()
+{
+}
+
+nsresult
+GaiaChrome::GetProfileDir()
+{
+  nsCOMPtr<nsIFile> profDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                       getter_AddRefs(profDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = profDir->Clone(getter_AddRefs(mProfDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+GaiaChrome::ComputeAppsPath(nsIFile* aPath)
+{
+#if defined(MOZ_MULET)
+  aPath->InitWithFile(mProfDir);
+#elif defined(MOZ_WIDGET_GONK)
+  nsCOMPtr<nsIFile> locationDetection = new nsLocalFile();
+  locationDetection->InitWithPath(mSystemRoot);
+  locationDetection->Append(mAppsDir);
+  bool appsInSystem = EnsureIsDirectory(locationDetection);
+  locationDetection->InitWithPath(mDataRoot);
+  locationDetection->Append(mAppsDir);
+  bool appsInData = EnsureIsDirectory(locationDetection);
+
+  if (!appsInData && !appsInSystem) {
+    printf_stderr("!!! NO root directory with apps found\n");
+    MOZ_ASSERT(false);
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  aPath->InitWithPath(appsInData ? mDataRoot : mSystemRoot);
+#else
+  return NS_ERROR_UNEXPECTED;
+#endif
+
+  aPath->Append(mAppsDir);
+  aPath->Append(NS_LITERAL_STRING("."));
+
+  nsresult rv = EnsureValidPath(aPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+bool
+GaiaChrome::EnsureIsDirectory(nsIFile* aPath)
+{
+  bool isDir = false;
+  aPath->IsDirectory(&isDir);
+  return isDir;
+}
+
+nsresult
+GaiaChrome::EnsureValidPath(nsIFile* appsDir)
+{
+  // Ensure there is a valid "apps/system" directory
+  nsCOMPtr<nsIFile> systemAppDir = new nsLocalFile();
+  systemAppDir->InitWithFile(appsDir);
+  systemAppDir->Append(NS_LITERAL_STRING("system"));
+
+  bool hasSystemAppDir = EnsureIsDirectory(systemAppDir);
+  if (!hasSystemAppDir) {
+    nsCString path; appsDir->GetNativePath(path);
+    // We don't want to continue if the apps path does not exists ...
+    printf_stderr("!!! Gaia chrome package is not a directory: %s\n", path.get());
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GaiaChrome::Register()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(nsChromeRegistry::gChromeRegistry != nullptr);
+
+  nsCOMPtr<nsIFile> aPath = new nsLocalFile();
+  nsresult rv = ComputeAppsPath(aPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  FileLocation appsLocation(aPath);
+  nsCString uri;
+  appsLocation.GetURIString(uri);
+
+  char* argv[2];
+  argv[0] = (char*)mPackageName.get();
+  argv[1] = (char*)uri.get();
+
+  nsChromeRegistry::ManifestProcessingContext cx(NS_APP_LOCATION, appsLocation);
+  nsChromeRegistry::gChromeRegistry->ManifestContent(cx, 0, argv, 0);
+
+  return NS_OK;
+}
+
+already_AddRefed<GaiaChrome>
+GaiaChrome::FactoryCreate()
+{
+  if (!XRE_IsParentProcess()) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gGaiaChrome) {
+    gGaiaChrome = new GaiaChrome();
+    ClearOnShutdown(&gGaiaChrome);
+  }
+
+  RefPtr<GaiaChrome> service = gGaiaChrome.get();
+  return service.forget();
+}
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(GaiaChrome,
+                                         GaiaChrome::FactoryCreate)
+
+NS_DEFINE_NAMED_CID(NS_GAIACHROME_CID);
+
+static const mozilla::Module::CIDEntry kGaiaChromeCIDs[] = {
+  { &kNS_GAIACHROME_CID, false, nullptr, GaiaChromeConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kGaiaChromeContracts[] = {
+  { "@mozilla.org/b2g/gaia-chrome;1", &kNS_GAIACHROME_CID },
+  { nullptr }
+};
+
+static const mozilla::Module::CategoryEntry kGaiaChromeCategories[] = {
+  { "profile-after-change", "Gaia Chrome Registration", GAIACHROME_CONTRACTID },
+  { nullptr }
+};
+
+static const mozilla::Module kGaiaChromeModule = {
+  mozilla::Module::kVersion,
+  kGaiaChromeCIDs,
+  kGaiaChromeContracts,
+  kGaiaChromeCategories
+};
+
+NSMODULE_DEFN(GaiaChromeModule) = &kGaiaChromeModule;
new file mode 100644
--- /dev/null
+++ b/b2g/components/GaiaChrome.h
@@ -0,0 +1,44 @@
+/* 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/. */
+
+#ifndef __GAIACHROME_H__
+#define __GAIACHROME_H__
+
+#include "nsIGaiaChrome.h"
+
+#include "nsIFile.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+using namespace mozilla;
+
+class GaiaChrome final : public nsIGaiaChrome
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIGAIACHROME
+
+  static already_AddRefed<GaiaChrome>
+  FactoryCreate();
+
+private:
+  nsCString mPackageName;
+
+  nsAutoString mAppsDir;
+  nsAutoString mDataRoot;
+  nsAutoString mSystemRoot;
+
+  nsCOMPtr<nsIFile> mProfDir;
+
+  GaiaChrome();
+  ~GaiaChrome();
+
+  nsresult ComputeAppsPath(nsIFile*);
+  bool EnsureIsDirectory(nsIFile*);
+  nsresult EnsureValidPath(nsIFile*);
+  nsresult GetProfileDir();
+};
+
+#endif  // __GAIACHROME_H__
--- a/b2g/components/SafeMode.jsm
+++ b/b2g/components/SafeMode.jsm
@@ -5,17 +5,16 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["SafeMode"];
 
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/Webapps.jsm");
 
 const kSafeModePref = "b2g.safe_mode";
 const kSafeModePage = "safe_mode.html";
 
 function debug(aStr) {
   //dump("-*- SafeMode: " + aStr + "\n");
 }
 
@@ -63,81 +62,80 @@ this.SafeMode = {
     let isSafeMode = Services.prefs.getCharPref(kSafeModePref) === "yes";
     if (!isSafeMode) {
       return Promise.resolve();
     }
     debug("Starting in Safe Mode!");
 
     // Load $system_app/safe_mode.html as a full screen iframe, and wait for
     // the user to make a choice.
-    return DOMApplicationRegistry.registryReady.then(() => {
-      let shell = SafeMode.window.shell;
-      let document = SafeMode.window.document;
-      SafeMode.window.screen.mozLockOrientation("portrait");
+    let shell = SafeMode.window.shell;
+    let document = SafeMode.window.document;
+    SafeMode.window.screen.mozLockOrientation("portrait");
+
+    let url = Services.io.newURI(shell.homeURL, null, null)
+                         .resolve(kSafeModePage);
+    debug("Registry is ready, loading " + url);
+    let frame = document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe");
+    frame.setAttribute("mozbrowser", "true");
+    frame.setAttribute("mozapp", shell.manifestURL);
+    frame.setAttribute("id", "systemapp"); // To keep screen.js happy.
+    let contentBrowser = document.body.appendChild(frame);
 
-      let url = Services.io.newURI(shell.homeURL, null, null)
-                           .resolve(kSafeModePage);
-      debug("Registry is ready, loading " + url);
-      let frame = document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe");
-      frame.setAttribute("mozbrowser", "true");
-      frame.setAttribute("mozapp", shell.manifestURL);
-      frame.setAttribute("id", "systemapp"); // To keep screen.js happy.
-      let contentBrowser = document.body.appendChild(frame);
+    return new Promise((aResolve, aReject) => {
+      let content = contentBrowser.contentWindow;
 
-      return new Promise((aResolve, aReject) => {
-        let content = contentBrowser.contentWindow;
-
-        // Stripped down version of the system app bootstrap.
-        function handleEvent(e) {
-          switch(e.type) {
-            case "mozbrowserloadstart":
-              if (content.document.location == "about:blank") {
-                contentBrowser.addEventListener("mozbrowserlocationchange", handleEvent, true);
-                contentBrowser.removeEventListener("mozbrowserloadstart", handleEvent, true);
-                return;
-              }
+      // Stripped down version of the system app bootstrap.
+      function handleEvent(e) {
+        switch(e.type) {
+          case "mozbrowserloadstart":
+            if (content.document.location == "about:blank") {
+              contentBrowser.addEventListener("mozbrowserlocationchange", handleEvent, true);
+              contentBrowser.removeEventListener("mozbrowserloadstart", handleEvent, true);
+              return;
+            }
 
-              notifyContentStart();
-              break;
-            case "mozbrowserlocationchange":
-              if (content.document.location == "about:blank") {
-                return;
-              }
+            notifyContentStart();
+            break;
+          case "mozbrowserlocationchange":
+            if (content.document.location == "about:blank") {
+              return;
+            }
 
-              contentBrowser.removeEventListener("mozbrowserlocationchange", handleEvent, true);
-              notifyContentStart();
-              break;
-            case "mozContentEvent":
-              content.removeEventListener("mozContentEvent", handleEvent, true);
-              contentBrowser.parentNode.removeChild(contentBrowser);
+            contentBrowser.removeEventListener("mozbrowserlocationchange", handleEvent, true);
+            notifyContentStart();
+            break;
+          case "mozContentEvent":
+            content.removeEventListener("mozContentEvent", handleEvent, true);
+            contentBrowser.parentNode.removeChild(contentBrowser);
 
-              if (e.detail == "safemode-yes")  {
-                // Really starting in safe mode, let's disable add-ons first.
-                DOMApplicationRegistry.disableAllAddons().then(aResolve);
-              } else {
-                aResolve();
-              }
-              break;
-          }
+            if (e.detail == "safemode-yes")  {
+              // Really starting in safe mode, let's disable add-ons first.
+              // TODO: disable add-ons
+              aResolve();
+            } else {
+              aResolve();
+            }
+            break;
         }
+      }
 
-        function notifyContentStart() {
-          let window = SafeMode.window;
-          window.shell.sendEvent(window, "SafeModeStart");
-          contentBrowser.setVisible(true);
+      function notifyContentStart() {
+        let window = SafeMode.window;
+        window.shell.sendEvent(window, "SafeModeStart");
+        contentBrowser.setVisible(true);
 
-          // browser-ui-startup-complete is used by the AppShell to stop the
-          // boot animation and start gecko rendering.
-          Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
-          content.addEventListener("mozContentEvent", handleEvent, true);
-        }
+        // browser-ui-startup-complete is used by the AppShell to stop the
+        // boot animation and start gecko rendering.
+        Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
+        content.addEventListener("mozContentEvent", handleEvent, true);
+      }
 
-        contentBrowser.addEventListener("mozbrowserloadstart", handleEvent, true);
-        contentBrowser.src = url;
-      });
+      contentBrowser.addEventListener("mozbrowserloadstart", handleEvent, true);
+      contentBrowser.src = url;
     });
   },
 
   // Returns a Promise that resolves once we have decided to run in safe mode
   // or not. All the safe mode switching actions happen before resolving the
   // promise.
   check: function(aWindow) {
     debug("check");
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -74,12 +74,23 @@ EXTRA_JS_MODULES += [
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
     EXTRA_JS_MODULES += [
       'GlobalSimulatorScreen.jsm'
     ]
 
 XPIDL_SOURCES += [
+    'nsIGaiaChrome.idl',
     'nsISystemMessagesInternal.idl'
 ]
 
 XPIDL_MODULE = 'gaia_chrome'
+
+UNIFIED_SOURCES += [
+    'GaiaChrome.cpp'
+]
+
+LOCAL_INCLUDES += [
+    '/chrome'
+]
+
+FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/b2g/components/nsIGaiaChrome.idl
@@ -0,0 +1,15 @@
+/* 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 "nsISupports.idl"
+
+[scriptable, uuid(92a18a98-ab5d-4d02-a024-bdbb3bc89ce1)]
+interface nsIGaiaChrome : nsISupports
+{
+    void register();
+};
+
+%{ C++
+#define GAIACHROME_CONTRACTID "@mozilla.org/b2g/gaia-chrome;1"
+%}
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -226,16 +226,17 @@
 @RESPATH@/components/exthelper.xpt
 @RESPATH@/components/fastfind.xpt
 @RESPATH@/components/feeds.xpt
 #ifdef MOZ_GTK
 @RESPATH@/components/filepicker.xpt
 #endif
 @RESPATH@/components/find.xpt
 @RESPATH@/components/gfx.xpt
+@RESPATH@/components/gaia_chrome.xpt
 @RESPATH@/components/hal.xpt
 @RESPATH@/components/html5.xpt
 @RESPATH@/components/htmlparser.xpt
 @RESPATH@/components/identity.xpt
 @RESPATH@/components/imglib2.xpt
 @RESPATH@/components/inspector.xpt
 @RESPATH@/components/intl.xpt
 @RESPATH@/components/jar.xpt
--- a/caps/tests/mochitest/chrome.ini
+++ b/caps/tests/mochitest/chrome.ini
@@ -4,9 +4,9 @@ support-files =
   file_disableScript.html
   !/caps/tests/mochitest/file_disableScript.html
 
 [test_bug995943.xul]
 [test_addonMayLoad.html]
 [test_disableScript.xul]
 [test_principal_jarprefix_origin_appid_appstatus.html]
 # jarPrefix test doesn't work on Windows, see bug 776296.
-skip-if = os == "win"
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
--- a/devtools/shared/apps/tests/mochitest.ini
+++ b/devtools/shared/apps/tests/mochitest.ini
@@ -1,7 +1,7 @@
 [DEFAULT]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
   debugger-protocol-helper.js
   redirect.sjs
 
 [test_webapps_actor.html]
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -104,17 +104,17 @@ this.DOMApplicationRegistry = {
     }).bind(this));
 
     this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
       messages: APPS_IPC_MSG_NAMES
     });
 
     // We need to prime the cache with the list of apps.
     let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
-    this.webapps = list.webapps;
+    this.webapps = list ? list.webapps : { };
     // We need a fast mapping from localId -> app, so we add an index.
     // We also add the manifest to the app object.
     this.localIdIndex = { };
     for (let id in this.webapps) {
       let app = this.webapps[id];
       this.localIdIndex[app.localId] = app;
       app.manifest = list.manifests[id];
     }
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -497,16 +497,22 @@ this.PermissionsTable =  { geolocation: 
                               trusted: DENY_ACTION,
                               privileged: ALLOW_ACTION,
                               certified: ALLOW_ACTION
                            },
                            "system-app-only-audio-channels-in-app": {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
+                           },
+                           "previously-certified-app": {
+                             app: DENY_ACTION,
+                             trusted: DENY_ACTION,
+                             privileged: DENY_ACTION,
+                             certified: ALLOW_ACTION
                            }
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -4809,9 +4809,10 @@ AppcacheObserver.prototype = {
     }
   },
 
   applicationCacheAvailable: function appObs_CacheAvail(aApplicationCache) {
     // Nothing to do.
   }
 };
 
-DOMApplicationRegistry.init();
+// FIXME: Properly remove Cu.import(Webapps.jsm) from every place.
+//DOMApplicationRegistry.init();
--- a/dom/apps/tests/mochitest.ini
+++ b/dom/apps/tests/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp != 'b2g' && buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
   addons/application.zip
   addons/invalid.webapp
   addons/invalid.webapp^headers^
   addons/update.webapp
   addons/update.webapp^headers^
   addons/index.html
   chromeAddCert.js
--- a/dom/broadcastchannel/tests/mochitest.ini
+++ b/dom/broadcastchannel/tests/mochitest.ini
@@ -16,15 +16,15 @@ support-files =
 [test_broadcastchannel_basic.html]
 [test_broadcastchannel_close.html]
 [test_broadcastchannel_close2.html]
 [test_broadcastchannel_self.html]
 [test_broadcastchannel_sharedWorker.html]
 [test_broadcastchannel_worker.html]
 [test_broadcastchannel_worker_alive.html]
 [test_broadcastchannel_mozbrowser.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_broadcastchannel_mozbrowser2.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_bfcache.html]
 [test_invalidState.html]
 [test_ordering.html]
 [test_dataCloning.html]
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -37,13 +37,13 @@ support-files =
 [test_cache_requestCache.html]
 [test_cache_delete.html]
 [test_cache_put_reorder.html]
 [test_cache_https.html]
   skip-if = buildapp == 'b2g' # bug 1162353
 [test_cache_restart.html]
 [test_cache_shrink.html]
 [test_cache_clear_on_app_uninstall.html]
-  skip-if = buildapp != 'mulet' || e10s # bug 1178685
+  skip-if = true || e10s # bug 1178685 ### Bug 1255339: blacklist because no more mozApps
 [test_cache_orphaned_cache.html]
 [test_cache_orphaned_body.html]
 [test_cache_untrusted.html]
 [test_chrome_constructor.html]
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -379,19 +379,19 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_transaction_ordering.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_unique_index_update.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_webapp_clearBrowserData_inproc_inproc.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
-skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_webapp_clearBrowserData_inproc_oop.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
-skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_webapp_clearBrowserData_oop_inproc.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
-skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_serviceworker.html]
 skip-if = buildapp == 'b2g'
--- a/dom/ipc/tests/mochitest.ini
+++ b/dom/ipc/tests/mochitest.ini
@@ -17,43 +17,43 @@ skip-if = buildapp == 'b2g' || buildapp 
 skip-if = toolkit != 'gonk'
 [test_NuwaProcessDeadlock.html]
 skip-if = toolkit != 'gonk'
 [test_child_docshell.html]
 skip-if = toolkit == 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
 [test_CrashService_crash.html]
 skip-if = !(crashreporter && !e10s && (toolkit == 'gtk2' || toolkit == 'gtk3' || toolkit == 'cocoa' || toolkit == 'windows') && (buildapp != 'b2g' || toolkit == 'gonk') && (buildapp != 'mulet')) # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
 [test_permission_for_in_process_app.html]
-skip-if = e10s || (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = e10s || true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   test_permission_helper.js
 [test_permission_for_oop_app.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
 [test_permission_for_nested_oop_app.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
 [test_permission_for_two_oop_apps.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
 [test_permission_when_oop_app_crashes.html]
-skip-if = buildapp != 'b2g' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
--- a/dom/security/test/csp/chrome.ini
+++ b/dom/security/test/csp/chrome.ini
@@ -1,7 +1,7 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || os == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
   !/dom/security/test/csp/file_bug768029.html
 
 [test_bug768029.html]
 [test_bug773891.html]
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -215,17 +215,17 @@ skip-if = (buildapp == 'b2g' && (toolkit
 skip-if = buildapp == 'b2g' # http-on-opening-request observers are not available in child processes
 [test_hash_source.html]
 skip-if = buildapp == 'b2g' # can't compute hashes in child process (bug 958702)
 [test_scheme_relative_sources.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_ignore_unsafe_inline.html]
 [test_self_none_as_hostname_confusion.html]
 [test_bug949549.html]
-skip-if = buildapp != 'b2g' && buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_path_matching.html]
 [test_path_matching_redirect.html]
 [test_report_uri_missing_in_report_only_header.html]
 [test_report.html]
 [test_301_redirect.html]
 skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
 [test_302_redirect.html]
 skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -30,17 +30,17 @@ support-files =
   !/dom/html/test/form_submit_server.sjs
   !/dom/security/test/cors/file_CrossSiteXHR_server.sjs
 
 [test_headers.html]
 [test_headers_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_headers_mainthread.html]
 [test_fetch_app_protocol.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_fetch_basic.html]
 [test_fetch_basic_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_fetch_basic_sw_empty_reroute.html]
 skip-if = buildapp == 'b2g'
 [test_fetch_basic_http.html]
 [test_fetch_basic_http_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
--- a/dom/tests/mochitest/localstorage/mochitest.ini
+++ b/dom/tests/mochitest/localstorage/mochitest.ini
@@ -14,17 +14,17 @@ support-files =
   frameSlaveNotEqual.html
   interOriginFrame.js
   interOriginTest.js
   interOriginTest2.js
   localStorageCommon.js
   frameLocalStorageSessionOnly.html
 
 [test_appIsolation.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 793211 # b2g(needs https to work) b2g-debug(needs https to work) b2g-desktop(needs https to work)
+skip-if = true || buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s #bug 793211 # b2g(needs https to work) b2g-debug(needs https to work) b2g-desktop(needs https to work) ### Bug 1255339: blacklist because no more mozApps
 [test_brokenUTF-16.html]
 [test_bug600307-DBOps.html]
 [test_bug746272-1.html]
 [test_bug746272-2.html]
 skip-if = os == "android" || toolkit == 'gonk' # bug 962029
 [test_cookieBlock.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(bug 913706) b2g-desktop(bug 913706)
 [test_cookieSession.html]
--- a/extensions/cookie/test/chrome.ini
+++ b/extensions/cookie/test/chrome.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || os == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files = channel_utils.js
 
 [test_app_uninstall_cookies.html]
 skip-if = buildapp != 'mulet'
 [test_app_uninstall_permissions.html]
 skip-if = buildapp != 'mulet'
 
 [test_permissionmanager_app_isolation.html]
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -26,18 +26,18 @@
 #include "mozilla/dom/Promise.h"
 
 #include "nsDOMMutationObserver.h"
 #include "nsICycleCollectorListener.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsScriptSecurityManager.h"
+#include "nsIPermissionManager.h"
 #include "nsContentUtils.h"
-
 #include "jsfriendapi.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace xpc;
 using namespace JS;
 
 NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)
@@ -437,17 +437,23 @@ InitGlobalObjectOptions(JS::CompartmentO
     if (isSystem) {
         // Make sure [SecureContext] APIs are visible:
         aOptions.creationOptions().setSecureContext(true);
     }
 
     short status = aPrincipal->GetAppStatus();
 
     // Enable the ECMA-402 experimental formatToParts in certified apps.
-    if (status == nsIPrincipal::APP_STATUS_CERTIFIED) {
+    uint32_t perm = nsIPermissionManager::DENY_ACTION;
+    nsCOMPtr<nsIPermissionManager> permissionManager = services::GetPermissionManager();
+    if (permissionManager) {
+        permissionManager->TestPermissionFromPrincipal(aPrincipal, "previously-certified-app", &perm);
+    }
+
+    if (perm == nsIPermissionManager::ALLOW_ACTION) {
         aOptions.creationOptions()
                 .setExperimentalDateTimeFormatFormatToPartsEnabled(true);
     }
 
     if (shouldDiscardSystemSource) {
         bool discardSource = isSystem ||
                              (status == nsIPrincipal::APP_STATUS_PRIVILEGED ||
                               status == nsIPrincipal::APP_STATUS_CERTIFIED);
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -20,13 +20,13 @@ support-files =
 [test_rel_preconnect.html]
 [test_uri_scheme.html]
 [test_user_agent_overrides.html]
 [test_user_agent_updates.html]
 [test_user_agent_updates_reset.html]
 [test_viewsource_unlinkable.html]
 [test_xhr_method_case.html]
 [test_web_packaged_app.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_loadinfo_redirectchain.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_idn_redirect.html]
 [test_redirect_ref.html]
--- a/testing/mochitest/tests/Harness_sanity/mochitest.ini
+++ b/testing/mochitest/tests/Harness_sanity/mochitest.ini
@@ -17,30 +17,30 @@ support-files = empty.js
 [test_sanityWindowSnapshot.html]
 [test_SpecialPowersExtension.html]
 [test_SpecialPowersExtension2.html]
 support-files = file_SpecialPowersFrame1.html
 [test_SpecialPowersPushPermissions.html]
 support-files =
     specialPowers_framescript.js
 [test_SpecialPowersPushAppPermissions.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
     file_app.sjs
     file_app.template.webapp
     app.html
 [test_SpecialPowersPushPrefEnv.html]
 [test_SimpletestGetTestFileURL.html]
 [test_SpecialPowersLoadChromeScript.html]
 support-files = SpecialPowersLoadChromeScript.js
 [test_SpecialPowersLoadChromeScript_function.html]
 [test_SpecialPowersLoadPrivilegedScript.html]
 [test_bug649012.html]
 [test_bug816847.html]
-skip-if = toolkit == 'android' || e10s #No test app installed
+skip-if = true || toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet' || e10s #No test app installed ### Bug 1255339: blacklist because no more mozApps
 [test_sanity_cleanup.html]
 [test_sanity_cleanup2.html]
 [test_sanityEventUtils.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 688052
 [test_sanitySimpletest.html]
 subsuite = clipboard
 skip-if = toolkit == 'android' #bug 688052
 [test_sanity_manifest.html]