Bug 1178533 - Add nsIInstallPackagedWebapp for registering permissions when navigating to signed packages. r=bholley, r=fabrice, r=valentin
☠☠ backed out by f721299f9dca ☠ ☠
authorStephanie Ouillon <stephouillon@mozilla.com>
Tue, 22 Sep 2015 11:55:00 +0200
changeset 263958 8bbdb80f67e0f0b9a8af914b77f92992e27a3a4d
parent 263957 acce23926d0720a69e9a970948434482da70917f
child 263959 39b57a8b21d5cdea08c1633f68a47fb34a939c62
push id29423
push userkwierso@gmail.com
push dateWed, 23 Sep 2015 20:13:47 +0000
treeherdermozilla-central@bcbfa80a0dc7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley, fabrice, valentin
bugs1178533
milestone44.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 1178533 - Add nsIInstallPackagedWebapp for registering permissions when navigating to signed packages. r=bholley, r=fabrice, r=valentin
b2g/installer/package-manifest.in
browser/components/preferences/in-content/advanced.js
browser/components/preferences/translation.js
browser/components/sessionstore/SessionStorage.jsm
browser/installer/package-manifest.in
caps/BasePrincipal.cpp
caps/BasePrincipal.h
caps/nsIScriptSecurityManager.idl
caps/nsScriptSecurityManager.cpp
caps/tests/unit/test_origin.js
dom/apps/PermissionsInstaller.jsm
dom/moz.build
dom/newapps/InstallPackagedWebapp.js
dom/newapps/InstallPackagedWebapp.manifest
dom/newapps/interfaces/moz.build
dom/newapps/interfaces/nsIInstallPackagedWebapp.idl
dom/newapps/moz.build
dom/newapps/test/xpcshell/test_install.js
dom/newapps/test/xpcshell/xpcshell.ini
dom/permission/PermissionSettings.jsm
dom/push/PushRecord.jsm
dom/requestsync/RequestSyncService.jsm
mobile/android/b2gdroid/installer/package-manifest.in
netwerk/protocol/http/PackagedAppService.cpp
netwerk/protocol/http/PackagedAppService.h
toolkit/modules/BrowserUtils.jsm
toolkit/modules/PermissionsUtils.jsm
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -180,16 +180,17 @@
 @RESPATH@/components/cookie.xpt
 @RESPATH@/components/devtools_security.xpt
 @RESPATH@/components/directory.xpt
 @RESPATH@/components/diskspacewatcher.xpt
 @RESPATH@/components/docshell.xpt
 @RESPATH@/components/dom.xpt
 @RESPATH@/components/dom_activities.xpt
 @RESPATH@/components/dom_apps.xpt
+@RESPATH@/components/dom_newapps.xpt
 @RESPATH@/components/dom_audiochannel.xpt
 @RESPATH@/components/dom_base.xpt
 @RESPATH@/components/dom_system.xpt
 #ifdef MOZ_WIDGET_GONK
 @RESPATH@/components/dom_wifi.xpt
 @RESPATH@/components/dom_system_gonk.xpt
 #endif
 #ifdef MOZ_B2G_RIL
@@ -722,16 +723,20 @@
 @RESPATH@/components/PrivateBrowsing.manifest
 @RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
 
 ; GNOME hooks
 #ifdef MOZ_ENABLE_GNOME_COMPONENT
 @RESPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
 #endif
 
+; Signed Packaged Content
+@RESPATH@/components/InstallPackagedWebapp.manifest
+@RESPATH@/components/InstallPackagedWebapp.js
+
 ; ANGLE on Win32
 #ifdef XP_WIN32
 #ifndef HAVE_64BIT_BUILD
 @BINPATH@/libEGL.dll
 @BINPATH@/libGLESv2.dll
 #endif
 #endif
 
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -1,17 +1,16 @@
 /* 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/. */
 
 // Load DownloadUtils module for convertByteUnits
 Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
 Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
 
 var gAdvancedPane = {
   _inited: false,
 
   /**
    * Brings the appropriate tab to the front and initializes various bits of UI.
    */
   init: function ()
@@ -567,17 +566,17 @@ var gAdvancedPane = {
     }
   },
 
   removeOfflineApp: function()
   {
     var list = document.getElementById("offlineAppsList");
     var item = list.selectedItem;
     var origin = item.getAttribute("origin");
-    var principal = BrowserUtils.principalFromOrigin(origin);
+    var principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin);
 
     var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                             .getService(Components.interfaces.nsIPromptService);
     var flags = prompts.BUTTON_TITLE_IS_STRING * prompts.BUTTON_POS_0 +
                 prompts.BUTTON_TITLE_CANCEL * prompts.BUTTON_POS_1;
 
     var bundle = document.getElementById("bundlePreferences");
     var title = bundle.getString("offlineAppRemoveTitle");
--- a/browser/components/preferences/translation.js
+++ b/browser/components/preferences/translation.js
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/BrowserUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gLangBundle", () =>
   Services.strings.createBundle("chrome://global/locale/languageNames.properties"));
 
 const kPermissionType = "translate";
 const kLanguagesPref = "browser.translation.neverForLanguages";
 
 function Tree(aId, aData)
@@ -185,30 +184,30 @@ var gTranslationExceptions = {
 
   onAllLanguagesDeleted: function() {
     Services.prefs.setCharPref(kLanguagesPref, "");
   },
 
   onSiteDeleted: function() {
     let removedSites = this._siteTree.getSelectedItems();
     for (let origin of removedSites) {
-      let principal = BrowserUtils.principalFromOrigin(origin);
+      let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin);
       Services.perms.removeFromPrincipal(principal, kPermissionType);
     }
   },
 
   onAllSitesDeleted: function() {
     if (this._siteTree.isEmpty)
       return;
 
     let removedSites = this._sites.splice(0, this._sites.length);
     this._siteTree.boxObject.rowCountChanged(0, -removedSites.length);
 
     for (let origin of removedSites) {
-      let principal = BrowserUtils.principalFromOrigin(origin);
+      let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin);
       Services.perms.removeFromPrincipal(principal, kPermissionType);
     }
 
     this.onSiteSelected();
   },
 
   onSiteKeyPress: function(aEvent) {
     if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE)
--- a/browser/components/sessionstore/SessionStorage.jsm
+++ b/browser/components/sessionstore/SessionStorage.jsm
@@ -4,17 +4,16 @@
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["SessionStorage"];
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 
-Cu.import("resource://gre/modules/BrowserUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "console",
   "resource://gre/modules/devtools/shared/Console.jsm");
 
 // Returns the principal for a given |frame| contained in a given |docShell|.
 function getPrincipalForFrame(docShell, frame) {
@@ -100,17 +99,17 @@ var SessionStorageInternal = {
    * @param aStorageData
    *        A nested object with storage data to be restored that has hosts as
    *        keys and per-host session storage data as values. For example:
    *        {"example.com": {"key": "value", "my_number": 123}}
    */
   restore: function (aDocShell, aStorageData) {
     for (let origin of Object.keys(aStorageData)) {
       let data = aStorageData[origin];
-      let principal = BrowserUtils.principalFromOrigin(origin);
+      let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin);
       let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
       let window = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
 
       // There is no need to pass documentURI, it's only used to fill documentURI property of
       // domstorage event, which in this case has no consumer. Prevention of events in case
       // of missing documentURI will be solved in a followup bug to bug 600307.
       let storage = storageManager.createStorage(window, principal, "", aDocShell.usePrivateBrowsing);
 
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -188,16 +188,17 @@
 @RESPATH@/components/directory.xpt
 @RESPATH@/components/docshell.xpt
 @RESPATH@/components/dom.xpt
 #ifdef MOZ_ACTIVITIES
 @RESPATH@/components/dom_activities.xpt
 @RESPATH@/components/dom_messages.xpt
 #endif
 @RESPATH@/components/dom_apps.xpt
+@RESPATH@/components/dom_newapps.xpt
 @RESPATH@/components/dom_base.xpt
 @RESPATH@/components/dom_system.xpt
 #ifdef MOZ_B2G_BT
 @RESPATH@/components/dom_bluetooth.xpt
 #endif
 @RESPATH@/components/dom_canvas.xpt
 @RESPATH@/components/dom_alarm.xpt
 @RESPATH@/components/dom_core.xpt
@@ -631,16 +632,20 @@
 @RESPATH@/components/url-classifier.xpt
 #endif
 
 ; Private Browsing
 @RESPATH@/components/privatebrowsing.xpt
 @RESPATH@/components/PrivateBrowsing.manifest
 @RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
 
+; Signed Packaged Content
+@RESPATH@/components/InstallPackagedWebapp.manifest
+@RESPATH@/components/InstallPackagedWebapp.js
+
 ; ANGLE GLES-on-D3D rendering library
 #ifdef MOZ_ANGLE_RENDERER
 @BINPATH@/libEGL.dll
 @BINPATH@/libGLESv2.dll
 
 #ifdef MOZ_D3DCOMPILER_VISTA_DLL
 @BINPATH@/@MOZ_D3DCOMPILER_VISTA_DLL@
 #endif
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -398,16 +398,38 @@ BasePrincipal::CreateCodebasePrincipal(n
 
   // Mint a codebase principal.
   nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
   rv = codebase->Init(aURI, aAttrs);
   NS_ENSURE_SUCCESS(rv, nullptr);
   return codebase.forget();
 }
 
+already_AddRefed<BasePrincipal>
+BasePrincipal::CreateCodebasePrincipal(const nsACString& aOrigin)
+{
+  MOZ_ASSERT(!StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("[")),
+             "CreateCodebasePrincipal does not support System and Expanded principals");
+
+  MOZ_ASSERT(!StringBeginsWith(aOrigin, NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":")),
+             "CreateCodebasePrincipal does not support nsNullPrincipal");
+
+  nsAutoCString originNoSuffix;
+  mozilla::OriginAttributes attrs;
+  if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  return BasePrincipal::CreateCodebasePrincipal(uri, attrs);
+}
+
 bool
 BasePrincipal::AddonAllowsLoad(nsIURI* aURI)
 {
   if (mOriginAttributes.mAddonId.IsEmpty()) {
     return false;
   }
 
   nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -132,16 +132,17 @@ public:
   NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
 
   virtual bool IsOnCSSUnprefixingWhitelist() override { return false; }
 
   virtual bool IsCodebasePrincipal() const { return false; };
 
   static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
   static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(nsIURI* aURI, OriginAttributes& aAttrs);
+  static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(const nsACString& aOrigin);
 
   const OriginAttributes& OriginAttributesRef() { return mOriginAttributes; }
   uint32_t AppId() const { return mOriginAttributes.mAppId; }
   uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
   bool IsInBrowserElement() const { return mOriginAttributes.mInBrowser; }
 
 protected:
   virtual ~BasePrincipal();
--- a/caps/nsIScriptSecurityManager.idl
+++ b/caps/nsIScriptSecurityManager.idl
@@ -21,17 +21,17 @@ class DomainPolicyClone;
 }
 }
 %}
 
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSObjectPtr(JSObject);
 [ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
 
-[scriptable, uuid(6e8a4d1e-d9c6-4d86-bf53-d73f58f36148)]
+[scriptable, uuid(b7ae2310-576e-11e5-a837-0800200c9a66)]
 interface nsIScriptSecurityManager : nsISupports
 {
     /**
      * For each of these hooks returning NS_OK means 'let the action continue'.
      * Returning an error code means 'veto the action'. XPConnect will return
      * false to the js engine if the action is vetoed. The implementor of this
      * interface is responsible for setting a JS exception into the JSContext
      * if that is appropriate.
@@ -193,16 +193,23 @@ interface nsIScriptSecurityManager : nsI
      * Returns a principal whose origin is composed of |uri| and |originAttributes|.
      * See nsIPrincipal.idl for a description of origin attributes, and
      * ChromeUtils.webidl for a list of origin attributes and their defaults.
      */
     [implicit_jscontext]
     nsIPrincipal createCodebasePrincipal(in nsIURI uri, in jsval originAttributes);
 
     /**
+     * Returns a principal whose origin is the one we pass in.
+     * See nsIPrincipal.idl for a description of origin attributes, and
+     * ChromeUtils.webidl for a list of origin attributes and their defaults.
+     */
+    nsIPrincipal createCodebasePrincipalFromOrigin(in ACString origin);
+
+    /**
      * Returns a unique nonce principal with |originAttributes|.
      * See nsIPrincipal.idl for a description of origin attributes, and
      * ChromeUtils.webidl for a list of origin attributes and their defaults.
      */
     [implicit_jscontext]
     nsIPrincipal createNullPrincipal(in jsval originAttributes);
 
     /**
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -62,16 +62,17 @@
 #include "mozilla/dom/BindingUtils.h"
 #include <stdint.h>
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsILoadInfo.h"
+#include "nsXPCOMStrings.h"
 
 // This should be probably defined on some other place... but I couldn't find it
 #define WEBAPPS_PERM_NAME "webapps-manage"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
@@ -1039,16 +1040,33 @@ nsScriptSecurityManager::CreateCodebaseP
       return NS_ERROR_INVALID_ARG;
   }
   nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
   prin.forget(aPrincipal);
   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
+nsScriptSecurityManager::CreateCodebasePrincipalFromOrigin(const nsACString& aOrigin,
+                                                           nsIPrincipal** aPrincipal)
+{
+  if (StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("["))) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  if (StringBeginsWith(aOrigin, NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":"))) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aOrigin);
+  prin.forget(aPrincipal);
+  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
 nsScriptSecurityManager::CreateNullPrincipal(JS::Handle<JS::Value> aOriginAttributes,
                                              JSContext* aCx, nsIPrincipal** aPrincipal)
 {
   OriginAttributes attrs;
   if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
       return NS_ERROR_INVALID_ARG;
   }
   nsCOMPtr<nsIPrincipal> prin = nsNullPrincipal::Create(attrs);
--- a/caps/tests/unit/test_origin.js
+++ b/caps/tests/unit/test_origin.js
@@ -1,14 +1,13 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/BrowserUtils.jsm");
 var ssm = Services.scriptSecurityManager;
 function makeURI(uri) { return Services.io.newURI(uri, null, null); }
 
 function checkThrows(f) {
   var threw = false;
   try { f(); } catch (e) { threw = true }
   do_check_true(threw);
 }
@@ -23,19 +22,19 @@ function checkCrossOrigin(a, b) {
 }
 
 function checkOriginAttributes(prin, attrs, suffix) {
   attrs = attrs || {};
   do_check_eq(prin.originAttributes.appId, attrs.appId || 0);
   do_check_eq(prin.originAttributes.inBrowser, attrs.inBrowser || false);
   do_check_eq(prin.originSuffix, suffix || '');
   if (!prin.isNullPrincipal && !prin.origin.startsWith('[')) {
-    do_check_true(BrowserUtils.principalFromOrigin(prin.origin).equals(prin));
+    do_check_true(ssm.createCodebasePrincipalFromOrigin(prin.origin).equals(prin));
   } else {
-    checkThrows(() => BrowserUtils.principalFromOrigin(prin.origin));
+    checkThrows(() => ssm.createCodebasePrincipalFromOrigin(prin.origin));
   }
 }
 
 function run_test() {
   // Attributeless origins.
   do_check_eq(ssm.getSystemPrincipal().origin, '[System Principal]');
   checkOriginAttributes(ssm.getSystemPrincipal());
   var exampleOrg = ssm.createCodebasePrincipal(makeURI('http://example.org'), {});
--- a/dom/apps/PermissionsInstaller.jsm
+++ b/dom/apps/PermissionsInstaller.jsm
@@ -159,17 +159,18 @@ this.PermissionsInstaller = {
             // work even on a system update, with the caveat that if a
             // ALLOW/DENY permission is changed to PROMPT then the system should
             // inform the user that he can now change a permission that he could
             // not change before.
             permValue =
               PermissionSettingsModule.getPermission(expandedPermNames[idx],
                                                      aApp.manifestURL,
                                                      aApp.origin,
-                                                     false);
+                                                     false,
+                                                     aApp.isCachedPackage);
             if (permValue === "unknown") {
               permValue = PERM_TO_STRING[permission];
             }
           }
 
           this._setPermission(expandedPermNames[idx], permValue, aApp);
         }
       }
@@ -187,21 +188,23 @@ this.PermissionsInstaller = {
   /**
    * Set a permission value.
    * @param string aPermName
    *        The permission name.
    * @param string aPermValue
    *        The permission value.
    * @param object aApp
    *        The just-installed app configuration.
-   *        The properties used are manifestURL and origin.
+   *        The properties used are manifestURL, origin, appId, isCachedPackage.
    * @returns void
    **/
   _setPermission: function setPermission(aPermName, aPermValue, aApp) {
     PermissionSettingsModule.addPermission({
       type: aPermName,
       origin: aApp.origin,
       manifestURL: aApp.manifestURL,
       value: aPermValue,
-      browserFlag: false
+      browserFlag: false,
+      localId: aApp.localId,
+      isCachedPackage: aApp.isCachedPackage,
     });
   }
 };
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -108,16 +108,17 @@ DIRS += [
     'webidl',
     'xbl',
     'xml',
     'xslt',
     'xul',
     'resourcestats',
     'manifest',
     'vr',
+    'newapps',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['plugins/ipc/hangui']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += [
         'speakermanager',
new file mode 100644
--- /dev/null
+++ b/dom/newapps/InstallPackagedWebapp.js
@@ -0,0 +1,63 @@
+/* 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/. */
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr, Constructor: CC } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PermissionsInstaller",
+    "resource://gre/modules/PermissionsInstaller.jsm");
+
+function debug(aMsg) {
+  dump("-*-*- InstallPackagedWebapps.js : " + aMsg + "\n");
+}
+
+function InstallPackagedWebapp() {
+}
+
+InstallPackagedWebapp.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIInstallPackagedWebapp]),
+  classID:          Components.ID("{5cc6554a-5421-4a5e-b8c2-c62e8b7f4f3f}"),
+
+  /**
+   * Install permissions for signed packaged web content
+   * @param string manifestContent
+   *        The manifest content of the cached package.
+   * @param string aOrigin
+   *        The package origin.
+   * @param string aManifestURL
+   *        The manifest URL of the package.
+   * @returns boolean
+   **/
+
+  installPackagedWebapp: function(aManifestContent, aOrigin, aManifestURL) {
+
+    try {
+      let isSuccess = true;
+      let manifest = JSON.parse(aManifestContent);
+
+      PermissionsInstaller.installPermissions({
+        manifest: manifest,
+        manifestURL: aManifestURL,
+        origin: aOrigin,
+        isPreinstalled: false,
+        isCachedPackage: true
+      }, false, function() {
+        Cu.reportError(ex);
+      });
+
+      // TODO Bug 1206058 - Register app handlers (system msg) on navigation
+      // to signed packages.
+
+      return isSuccess;
+    }
+    catch(ex) {
+      Cu.reportError(ex);
+      return false;
+    }
+  },
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InstallPackagedWebapp]);
new file mode 100644
--- /dev/null
+++ b/dom/newapps/InstallPackagedWebapp.manifest
@@ -0,0 +1,2 @@
+component {5cc6554a-5421-4a5e-b8c2-c62e8b7f4f3f} InstallPackagedWebapp.js
+contract  @mozilla.org/newapps/installpackagedwebapp;1 {5cc6554a-5421-4a5e-b8c2-c62e8b7f4f3f}
new file mode 100644
--- /dev/null
+++ b/dom/newapps/interfaces/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPIDL_SOURCES += [
+    'nsIInstallPackagedWebapp.idl'
+]
+
+XPIDL_MODULE = 'dom_newapps'
new file mode 100644
--- /dev/null
+++ b/dom/newapps/interfaces/nsIInstallPackagedWebapp.idl
@@ -0,0 +1,13 @@
+/* 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(3b4b69a0-56dc-11e5-a837-0800200c9a66)]
+interface nsIInstallPackagedWebapp : nsISupports
+{
+  boolean installPackagedWebapp(in string aManifestContent,
+                                in string aOrigin,
+                                in string aManifestURL);
+};
new file mode 100644
--- /dev/null
+++ b/dom/newapps/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DIRS += ['interfaces']
+
+EXTRA_COMPONENTS += [
+    'InstallPackagedWebapp.js',
+    'InstallPackagedWebapp.manifest',
+]
+
+XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
new file mode 100644
--- /dev/null
+++ b/dom/newapps/test/xpcshell/test_install.js
@@ -0,0 +1,121 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+'use strict';
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+Cu.import("resource://gre/modules/PermissionSettings.jsm");
+Cu.import("resource://gre/modules/PermissionsTable.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+
+const mod = Cc['@mozilla.org/newapps/installpackagedwebapp;1']
+                  .getService(Ci.nsIInstallPackagedWebapp);
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "appsService",
+                                   "@mozilla.org/AppsService;1",
+                                   "nsIAppsService");
+
+function run_test() {
+
+  let manifestWithPerms = {
+    name: "Test App",
+    launch_path: "/index.html",
+    type: "privileged",
+    permissions: {
+      "alarms": { },
+      "wifi-manage": { },
+      "tcp-socket": { },
+      "desktop-notification": { },
+      "geolocation": { },
+    },
+  };
+
+  let manifestNoPerms = {
+    name: "Test App",
+    launch_path: "/index.html",
+    type: "privileged",
+  };
+
+  let appStatus = "privileged";
+
+  // Triggering error due to bad manifest
+  let origin = "";
+  let manifestURL = "";
+  let manifestString = "boum";
+
+  let res = mod.installPackagedWebapp(manifestString, origin, manifestURL);
+  equal(res, false);
+
+  // Install a package with permissions
+  origin = "http://test.com^appId=1019&inBrowser=1";
+  manifestURL = "http://test.com/manifest.json";
+  manifestString = JSON.stringify(manifestWithPerms);
+  let manifestHelper = new ManifestHelper(manifestWithPerms, origin, manifestURL);
+
+  cleanDB(manifestHelper, origin, manifestURL);
+
+  res = mod.installPackagedWebapp(manifestString, origin, manifestURL);
+  equal(res, true);
+  checkPermissions(manifestHelper, origin, manifestURL, appStatus);
+
+  // Install a package with permissions
+  origin = "http://test.com";
+  manifestHelper = new ManifestHelper(manifestWithPerms, origin, manifestURL);
+
+  cleanDB(manifestHelper, origin, manifestURL);
+
+  res = mod.installPackagedWebapp(manifestString, origin, manifestURL);
+  equal(res, true);
+  checkPermissions(manifestHelper, origin, manifestURL, appStatus);
+
+
+  // Install a package with no permission
+  origin = "http://bar.com^appId=1337&inBrowser=1";
+  manifestURL = "http://bar.com/manifest.json";
+  manifestString = JSON.stringify(manifestNoPerms);
+  manifestHelper = new ManifestHelper(manifestNoPerms, origin, manifestURL);
+
+  cleanDB(manifestHelper, origin, manifestURL);
+
+  res = mod.installPackagedWebapp(manifestString, origin, manifestURL);
+  equal(res, true);
+  checkPermissions(manifestHelper, origin, manifestURL, appStatus);
+}
+
+// Cleaning permissions database before running a test
+function cleanDB(manifestHelper, origin, manifestURL) {
+  for (let permName in manifestHelper.permissions) {
+    PermissionSettingsModule.removePermission(permName, manifestURL, origin, "", true);
+  }
+}
+
+// Check permissions are correctly set in the database
+function checkPermissions(manifestHelper, origin, manifestURL, appStatus) {
+  let perm;
+  for (let permName in manifestHelper.permissions) {
+    let permValue = PermissionSettingsModule.getPermission(
+        permName, manifestURL, origin, "", true);
+    switch (PermissionsTable[permName][appStatus]) {
+      case Ci.nsIPermissionManager.UNKNOWN_ACTION:
+        perm = "unknown";
+        break;
+      case Ci.nsIPermissionManager.ALLOW_ACTION:
+        perm = "allow";
+        break;
+      case Ci.nsIPermissionManager.DENY_ACTION:
+        perm = "deny";
+        break;
+      case Ci.nsIPermissionManager.PROMPT_ACTION:
+        perm = "prompt";
+        break;
+      default:
+        break;
+    }
+    equal(permValue, perm);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/newapps/test/xpcshell/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head =
+tail =
+
+[test_install.js]
--- a/dom/permission/PermissionSettings.jsm
+++ b/dom/permission/PermissionSettings.jsm
@@ -62,23 +62,33 @@ this.PermissionSettingsModule = {
   addPermission: function addPermission(aData, aCallbacks) {
 
     this._internalAddPermission(aData, true, aCallbacks);
 
   },
 
 
   _internalAddPermission: function _internalAddPermission(aData, aAllowAllChanges, aCallbacks) {
-    // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm
-    let uri = Services.io.newURI(aData.origin, null, null);
-    let app = appsService.getAppByManifestURL(aData.manifestURL);
-    let principal =
-      Services.scriptSecurityManager.createCodebasePrincipal(uri,
-                                                             {appId: app.localId,
-                                                              inBrowser: aData.browserFlag});
+    // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm.
+    let app;
+    let principal;
+    // Test if app is cached (signed streamable package) or installed via DOMApplicationRegistry
+    if (aData.isCachedPackage) {
+      // If the app is from packaged web app, the origin includes origin attributes already.
+      principal =
+        Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aData.origin);
+      app = {localId: principal.appId};
+    } else {
+      app = appsService.getAppByManifestURL(aData.manifestURL);
+      let uri = Services.io.newURI(aData.origin, null, null);
+      principal =
+        Services.scriptSecurityManager.createCodebasePrincipal(uri,
+                                                               {appId: app.localId,
+                                                                inBrowser: aData.browserFlag});
+    }
 
     let action;
     switch (aData.value)
     {
       case "unknown":
         action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
         break;
       case "allow":
@@ -101,50 +111,58 @@ this.PermissionSettingsModule = {
       Services.perms.addFromPrincipal(principal, aData.type, action);
       return true;
     } else {
       debug("add Failure: " + aData.origin + " " + app.localId + " " + action);
       return false; // This isn't currently used, see comment on setPermission
     }
   },
 
-  getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
+  getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag, aIsCachedPackage) {
     // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm
     debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
-    let uri = Services.io.newURI(aOrigin, null, null);
-    let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
-    let principal =
-      Services.scriptSecurityManager.createCodebasePrincipal(uri,
-                                                             {appId: appID,
-                                                              inBrowser: aBrowserFlag});
+    let principal;
+    // Test if app is cached (signed streamable package) or installed via DOMApplicationRegistry
+    if (aIsCachedPackage) {
+      // If the app is from packaged web app, the origin includes origin attributes already.
+      principal =
+        Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aOrigin);
+    } else {
+      let uri = Services.io.newURI(aOrigin, null, null);
+      let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
+      principal =
+        Services.scriptSecurityManager.createCodebasePrincipal(uri,
+                                                               {appId: appID,
+                                                                inBrowser: aBrowserFlag});
+    }
     let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName);
-
     switch (result)
     {
       case Ci.nsIPermissionManager.UNKNOWN_ACTION:
         return "unknown";
       case Ci.nsIPermissionManager.ALLOW_ACTION:
         return "allow";
       case Ci.nsIPermissionManager.DENY_ACTION:
         return "deny";
       case Ci.nsIPermissionManager.PROMPT_ACTION:
         return "prompt";
       default:
         dump("Unsupported PermissionSettings Action!\n");
         return "unknown";
     }
   },
 
-  removePermission: function removePermission(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
+  removePermission: function removePermission(aPermName, aManifestURL, aOrigin, aBrowserFlag, aIsCachedPackage) {
     let data = {
       type: aPermName,
       origin: aOrigin,
       manifestURL: aManifestURL,
       value: "unknown",
-      browserFlag: aBrowserFlag
+      browserFlag: aBrowserFlag,
+      isCachedPackage: aIsCachedPackage
     };
     this._internalAddPermission(data, true);
   },
 
   observe: function observe(aSubject, aTopic, aData) {
     ppmm.removeMessageListener("PermissionSettings:AddPermission", this);
     Services.obs.removeObserver(this, "profile-before-change");
     ppmm = null;
--- a/dom/push/PushRecord.jsm
+++ b/dom/push/PushRecord.jsm
@@ -14,18 +14,16 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
-                                  "resource://gre/modules/BrowserUtils.jsm");
 
 this.EXPORTED_SYMBOLS = ["PushRecord"];
 
 const prefs = new Preferences("dom.push.");
 
 // History transition types that can fire a `pushsubscriptionchange` event
 // when the user visits a site with expired push registrations. Visits only
 // count if the user sees the origin in the address bar. This excludes embedded
@@ -213,17 +211,17 @@ Object.defineProperties(PushRecord.proto
     get() {
       let principal = principals.get(this);
       if (!principal) {
         let url = this.scope;
         if (this.originAttributes) {
           // Allow tests to omit origin attributes.
           url += this.originAttributes;
         }
-        principal = BrowserUtils.principalFromOrigin(url);
+        principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(url);
         principals.set(this, principal);
       }
       return principal;
     },
     configurable: true,
   },
 
   uri: {
--- a/dom/requestsync/RequestSyncService.jsm
+++ b/dom/requestsync/RequestSyncService.jsm
@@ -15,17 +15,16 @@ const RSYNCDB_NAME = "requestSync";
 const RSYNC_MIN_INTERVAL = 100;
 
 const RSYNC_OPERATION_TIMEOUT = 120000 // 2 minutes
 
 const RSYNC_STATE_ENABLED = "enabled";
 const RSYNC_STATE_DISABLED = "disabled";
 const RSYNC_STATE_WIFIONLY = "wifiOnly";
 
-Cu.import("resource://gre/modules/BrowserUtils.jsm");
 Cu.import('resource://gre/modules/IndexedDBHelper.jsm');
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.importGlobalProperties(["indexedDB"]);
 
 
 XPCOMUtils.defineLazyServiceGetter(this, "appsService",
                                    "@mozilla.org/AppsService;1",
@@ -170,17 +169,17 @@ this.RequestSyncService = {
     if (!aData) {
       return;
     }
 
     let pattern = JSON.parse(aData);
     let dbKeys = [];
 
     for (let key in this._registrations) {
-      let prin = BrowserUtils.principalFromOrigin(key);
+      let prin = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(key);
       if (!ChromeUtils.originAttributesMatchPattern(prin.originAttributes, pattern)) {
         continue;
       }
 
       for (let task in this._registrations[key]) {
         dbKeys = this._registrations[key][task].dbKey;
         this.removeRegistrationInternal(task, key);
       }
--- a/mobile/android/b2gdroid/installer/package-manifest.in
+++ b/mobile/android/b2gdroid/installer/package-manifest.in
@@ -133,16 +133,17 @@
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/devtools_security.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_activities.xpt
 @BINPATH@/components/dom_apps.xpt
+@BINPATH@/components/dom_newapps.xpt
 @BINPATH@/components/dom_base.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_media.xpt
 @BINPATH@/components/dom_messages.xpt
@@ -672,16 +673,19 @@ bin/libfreebl_32int64_3.so
 @BINPATH@/components/nsIDService.js
 @BINPATH@/components/Identity.manifest
 
 @BINPATH@/components/SystemMessageInternal.js
 @BINPATH@/components/SystemMessageManager.js
 @BINPATH@/components/SystemMessageCache.js
 @BINPATH@/components/SystemMessageManager.manifest
 
+@BINPATH@/components/InstallPackagedWebapp.manifest
+@BINPATH@/components/InstallPackagedWebapp.js
+
 @BINPATH@/components/B2GComponents.manifest
 @BINPATH@/components/AlertsService.js
 @BINPATH@/components/ContentPermissionPrompt.js
 @BINPATH@/components/ActivitiesGlue.js
 @BINPATH@/components/InterAppCommUIGlue.js
 @BINPATH@/components/SystemMessageGlue.js
 @BINPATH@/components/ProcessGlobal.js
 @BINPATH@/components/OMAContentHandler.js
--- a/netwerk/protocol/http/PackagedAppService.cpp
+++ b/netwerk/protocol/http/PackagedAppService.cpp
@@ -12,16 +12,17 @@
 #include "nsIResponseHeadProvider.h"
 #include "nsIMultiPartChannel.h"
 #include "../../cache2/CacheFileUtils.h"
 #include "nsStreamUtils.h"
 #include "mozilla/Logging.h"
 #include "mozilla/DebugOnly.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "mozilla/LoadContext.h"
+#include "nsIInstallPackagedWebapp.h"
 
 namespace mozilla {
 namespace net {
 
 static PackagedAppService *gPackagedAppService = nullptr;
 
 static PRLogModuleInfo *gPASLog = nullptr;
 #undef LOG
@@ -425,16 +426,17 @@ PackagedAppService::PackagedAppDownloade
   rv = cacheStorageService->DiskCacheStorage(aInfo, false,
                                              getter_AddRefs(mCacheStorage));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   mPackageKey = aKey;
   mPackageOrigin = aPackageOrigin;
+  mProcessingFirstRequest = true;
 
   return NS_OK;
 }
 
 void
 PackagedAppService::PackagedAppDownloader::EnsureVerifier(nsIRequest *aRequest)
 {
   if (mVerifier) {
@@ -618,16 +620,18 @@ PackagedAppService::PackagedAppDownloade
                                                          nsresult aStatusCode)
 {
   nsCOMPtr<nsIMultiPartChannel> multiChannel(do_QueryInterface(aRequest));
   nsresult rv;
 
   LOG(("[%p] PackagedAppDownloader::OnStopRequest > status:%X multiChannel:%p\n",
        this, aStatusCode, multiChannel.get()));
 
+  mProcessingFirstRequest = false;
+
   // lastPart will be true if this is the last part in the package,
   // or if aRequest isn't a multipart channel
   bool lastPart = true;
   if (multiChannel) {
     multiChannel->GetIsLastPart(&lastPart);
   }
 
   // The request is normally a multiPartChannel. If it isn't, it generally means
@@ -698,16 +702,21 @@ PackagedAppService::PackagedAppDownloade
 
   if (!self->mWriter) {
     *aWriteCount = aCount;
     return NS_OK;
   }
 
   self->mWriter->ConsumeData(aFromRawSegment, aCount, aWriteCount);
 
+  if (self->mProcessingFirstRequest) {
+    // mProcessingFirstRequest will be set to false on the first OnStopRequest.
+    self->mManifestContent.Append(aFromRawSegment, aCount);
+  }
+
   nsCOMPtr<nsIInputStream> stream = CreateSharedStringStream(aFromRawSegment, aCount);
   return self->mVerifier->OnDataAvailable(nullptr, nullptr, stream, 0, aCount);
 }
 
 NS_IMETHODIMP
 PackagedAppService::PackagedAppDownloader::OnDataAvailable(nsIRequest *aRequest,
                                                            nsISupports *aContext,
                                                            nsIInputStream *aInputStream,
@@ -853,21 +862,49 @@ PackagedAppService::PackagedAppDownloade
 void
 PackagedAppService::PackagedAppDownloader::NotifyOnStartSignedPackageRequest(const nsACString& aPackageOrigin)
 {
   // TODO: Bug 1186290 to notify whoever wants to know when the signed package is
   //       about to load.
   LOG(("Notifying the signed package is ready to load."));
 }
 
-void PackagedAppService::PackagedAppDownloader::InstallSignedPackagedApp()
+void PackagedAppService::PackagedAppDownloader::InstallSignedPackagedApp(const ResourceCacheInfo* aInfo)
 {
   // TODO: Bug 1178533 to register permissions, system messages etc on navigation to
   //       signed packages.
   LOG(("Install this packaged app."));
+  bool isSuccess = false;
+
+  nsCOMPtr<nsIInstallPackagedWebapp> installer =
+    do_GetService("@mozilla.org/newapps/installpackagedwebapp;1");
+
+  if (!installer) {
+    LOG(("InstallSignedPackagedApp: fail to get InstallPackagedWebapp service"));
+    return OnError(ERROR_GET_INSTALLER_FAILED);
+  }
+
+  nsCString manifestURL;
+  aInfo->mURI->GetAsciiSpec(manifestURL);
+
+  // Use the origin stored in the verifier since the signed packaged app would
+  // have a specifi package identifer defined in the manifest file.
+  nsCString packageOrigin;
+  mVerifier->GetPackageOrigin(packageOrigin);
+
+  installer->InstallPackagedWebapp(mManifestContent.get(),
+                                   packageOrigin.get(),
+                                   manifestURL.get(),
+                                   &isSuccess);
+  if (!isSuccess) {
+    LOG(("InstallSignedPackagedApp: failed to install permissions"));
+    return OnError(ERROR_INSTALL_RESOURCE_FAILED);
+  }
+
+  LOG(("InstallSignedPackagedApp: success."));
 }
 
 //------------------------------------------------------------------
 // nsIPackagedAppVerifierListener
 //------------------------------------------------------------------
 NS_IMETHODIMP
 PackagedAppService::PackagedAppDownloader::OnVerified(bool aIsManifest,
                                                       nsIURI* aUri,
@@ -915,17 +952,17 @@ PackagedAppService::PackagedAppDownloade
     // A verified but unsigned manifest means this package has no signature.
     LOG(("No signature in the package. Just run normally."));
     return;
   }
 
   nsCString packageOrigin;
   mVerifier->GetPackageOrigin(packageOrigin);
   NotifyOnStartSignedPackageRequest(packageOrigin);
-  InstallSignedPackagedApp();
+  InstallSignedPackagedApp(aInfo);
 }
 
 void
 PackagedAppService::PackagedAppDownloader::OnResourceVerified(const ResourceCacheInfo* aInfo,
                                                               bool aSuccess)
 {
   if (!aSuccess) {
     return OnError(ERROR_RESOURCE_VERIFIED_FAILED);
@@ -1082,17 +1119,17 @@ PackagedAppService::GetResource(nsIChann
     // Each resource in the package will be put in its own cache entry
     // during the first load of the package, so we only want the channel to
     // cache the response head, not the entire content of the package.
     cacheChan->SetCacheOnlyMetadata(true);
   }
 
   downloader = new PackagedAppDownloader();
   nsCString packageOrigin;
-  principal->GetOriginNoSuffix(packageOrigin);
+  principal->GetOrigin(packageOrigin);
   rv = downloader->Init(loadContextInfo, key, packageOrigin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   downloader->AddCallback(uri, aCallback);
 
   nsCOMPtr<nsIStreamConverterService> streamconv =
--- a/netwerk/protocol/http/PackagedAppService.h
+++ b/netwerk/protocol/http/PackagedAppService.h
@@ -101,16 +101,18 @@ private:
   {
   public:
     typedef PackagedAppVerifier::ResourceCacheInfo ResourceCacheInfo;
 
   private:
     enum EErrorType {
       ERROR_MANIFEST_VERIFIED_FAILED,
       ERROR_RESOURCE_VERIFIED_FAILED,
+      ERROR_GET_INSTALLER_FAILED,
+      ERROR_INSTALL_RESOURCE_FAILED,
     };
 
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSIPACKAGEDAPPVERIFIERLISTENER
 
@@ -167,17 +169,17 @@ private:
     // Start off a resource hash computation and feed the HTTP response header.
     nsresult BeginHashComputation(nsIURI* aURI, nsIRequest* aRequest);
 
     // Ensure a packaged app verifier is created.
     void EnsureVerifier(nsIRequest *aRequest);
 
     // Handle all tasks about app installation like permission and system message
     // registration.
-    void InstallSignedPackagedApp();
+    void InstallSignedPackagedApp(const ResourceCacheInfo* aInfo);
 
     // Calls all the callbacks registered for the given URI.
     // aURI is the full URI of a subresource, composed of packageURI + !// + subresourcePath
     // It passes the cache entry and the result when calling OnCacheEntryAvailable
     nsresult CallCallbacks(nsIURI *aURI, nsICacheEntry *aEntry, nsresult aResult);
     // Clears all the callbacks for this package
     // This would get called at the end of downloading the package and would
     // cause us to call OnCacheEntryAvailable with a null entry. This would be
@@ -206,16 +208,25 @@ private:
 
     // Deal with verification and delegate callbacks to the downloader.
     nsRefPtr<PackagedAppVerifier> mVerifier;
 
     // The package origin without signed package origin identifier.
     // If you need the origin with the signity taken into account, use
     // PackagedAppVerifier::GetPackageOrigin().
     nsCString mPackageOrigin;
+
+    //The app id of the package loaded from the LoadContextInfo
+    uint32_t mAppId;
+
+    // A flag to indicate if we are processing the first request.
+    bool mProcessingFirstRequest;
+
+    // A in-memory copy of the manifest content.
+    nsCString mManifestContent;
   };
 
   // Intercepts OnStartRequest, OnDataAvailable*, OnStopRequest method calls
   // and forwards them to the listener.
   // The target is a `mListener` which converts the package to individual
   // resources and serves them to mDownloader.
   // This class is able to perform conditional actions based on whether the
   // underlying nsIHttpChannel is served from the cache.
--- a/toolkit/modules/BrowserUtils.jsm
+++ b/toolkit/modules/BrowserUtils.jsm
@@ -95,40 +95,16 @@ this.BrowserUtils = {
   makeFileURI: function(aFile) {
     return Services.io.newFileURI(aFile);
   },
 
   makeURIFromCPOW: function(aCPOWURI) {
     return Services.io.newURI(aCPOWURI.spec, aCPOWURI.originCharset, null);
   },
 
-  // Creates a codebase principal from a canonical origin string. This is
-  // the inverse operation of .origin on a codebase principal.
-  principalFromOrigin: function(aOriginString) {
-    if (aOriginString.startsWith('[')) {
-      throw new Error("principalFromOrigin does not support System and Expanded principals");
-    }
-
-    if (aOriginString.startsWith("moz-nullprincipal:")) {
-      throw new Error("principalFromOrigin does not support nsNullPrincipal");
-    }
-
-    var parts = aOriginString.split('^');
-    if (parts.length > 2) {
-      throw new Error("bad origin string: " + aOriginString);
-    }
-
-    var uri = Services.io.newURI(parts[0], null, null);
-    var attrs = {};
-    // Parse the parameters string into a dictionary.
-    (parts[1] || "").split("&").map((x) => x.split('=')).forEach((x) => attrs[x[0]] = x[1]);
-
-    return Services.scriptSecurityManager.createCodebasePrincipal(uri, attrs);
-  },
-
   /**
    * For a given DOM element, returns its position in "screen"
    * coordinates. In a content process, the coordinates returned will
    * be relative to the left/top of the tab. In the chrome process,
    * the coordinates are relative to the user's screen.
    */
   getElementBoundingScreenRect: function(aElement) {
     let rect = aElement.getBoundingClientRect();
--- a/toolkit/modules/PermissionsUtils.jsm
+++ b/toolkit/modules/PermissionsUtils.jsm
@@ -2,18 +2,16 @@
 // 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/.
 
 this.EXPORTED_SYMBOLS = ["PermissionsUtils"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/BrowserUtils.jsm")
-
 
 var gImportedPrefBranches = new Set();
 
 function importPrefBranch(aPrefBranch, aPermission, aAction) {
   let list = Services.prefs.getChildList(aPrefBranch, {});
 
   for (let pref of list) {
     let origins = "";
@@ -24,17 +22,17 @@ function importPrefBranch(aPrefBranch, a
     if (!origins)
       continue;
 
     origins = origins.split(",");
 
     for (let origin of origins) {
       let principals = [];
       try {
-        principals = [ BrowserUtils.principalFromOrigin(origin) ];
+        principals = [ Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin) ];
       } catch (e) {
         // This preference used to contain a list of hosts. For back-compat
         // reasons, we convert these hosts into http:// and https:// permissions
         // on default ports.
         try {
           let httpURI = Services.io.newURI("http://" + origin, null, null);
           let httpsURI = Services.io.newURI("https://" + origin, null, null);