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 331203 16aa7041c00965e0ead9e03b5f2ff2d8329c4e7d
parent 331202 aaf2540b99a332ebdd19e3b1ce830bc8b07ac635
child 331204 2868c140a299dfb3f036e1404c3ee2741938a525
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley, fabrice
bugs1287107
milestone50.0a1
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]