Bug 1287107 - Move gaia to chrome:// URLs r? draft
authorAlexandre Lissy <lissyx@lissyx.dyndns.org>
Wed, 16 Mar 2016 12:41:47 +0100
changeset 388378 c46d7c4e9cd8e4f0dfda3cf21cb3da12a897baf9
parent 388377 4cb75863dd3f1635ad46453a8775ac9d66d4f91b
child 388379 25a35aa9e269aa5f6fa8d630b5e7db4f32c43a61
push id23144
push userbmo:lissyx+mozillians@lissyx.dyndns.org
push dateFri, 15 Jul 2016 13:56:30 +0000
bugs1287107
milestone50.0a1
Bug 1287107 - Move gaia to chrome:// URLs r? MozReview-Commit-ID: HguO5sUeZx5
b2g/chrome/content/shell.js
b2g/components/AppPermissions.jsm
b2g/components/GaiaChrome.cpp
b2g/components/GaiaChrome.h
b2g/components/moz.build
b2g/components/nsIGaiaChrome.idl
b2g/installer/package-manifest.in
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -419,20 +419,17 @@ var shell = {
     this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
     this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this);
 
     CustomEventManager.init();
     UserAgentOverrides.init();
     CaptivePortalLoginHelper.init();
 
-    Cu.import("resource://gre/modules/AppPermissions.jsm");
-    PermissionsInstaller.setAllPermissions().then(() => {
-      this.contentBrowser.src = homeURL;
-    });
+    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);
deleted file mode 100644
--- a/b2g/components/AppPermissions.jsm
+++ /dev/null
@@ -1,257 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cc = Components.classes;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/PermissionSettings.jsm");
-Cu.import("resource://gre/modules/PermissionsTable.jsm");
-
-this.EXPORTED_SYMBOLS = ["PermissionsInstaller"];
-const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
-const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
-const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
-const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
-
-// Permission access flags
-const READONLY = "readonly";
-const CREATEONLY = "createonly";
-const READCREATE = "readcreate";
-const READWRITE = "readwrite";
-
-const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
-
-function debug(aMsg) {
-  //dump("-*-*- AppPermissions.jsm : " + aMsg + "\n");
-}
-
- /**
-  * Resolves to a json file.
-  */
-function loadJSON(url) {
-  return new Promise((aResolve, aReject) => {
-    debug("Loading resource " + url);
-
-    let xhr =  Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
-               .createInstance(Ci.nsIXMLHttpRequest);
-    xhr.mozBackgroundRequest = true;
-    xhr.open("GET", url);
-    xhr.responseType = "json";
-    xhr.addEventListener("load", () => {
-      if (xhr.status >= 200 && xhr.status < 400) {
-        debug("Success loading " + url);
-        aResolve(xhr.response);
-      } else {
-        aReject("Error loading " + url);
-      }
-    });
-    xhr.addEventListener("error", () => {
-      aReject("Error loading " + url);
-    });
-    xhr.send(null);
-  });
-}
-
-this.PermissionsInstaller = {
-  /**
-   * Install permissisions or remove deprecated permissions upon re-install.
-   * @param object aApp
-   *        The just-installed app configuration.
-   *        The properties used are manifestURL, origin and manifest.
-   * @param boolean aIsReinstall
-   *        Indicates the app was just re-installed
-   * @returns bool indicating whether an error occured or not.
-   **/
-  installPermissions: function installPermissions(aApp, aIsReinstall) {
-    try {
-      let newManifest = aApp.manifest;
-      if (!newManifest.permissions && !aIsReinstall) {
-        return;
-      }
-
-      if (aIsReinstall) {
-        // Compare the original permissions against the new permissions
-        // Remove any deprecated Permissions
-
-        if (newManifest.permissions) {
-          // Expand permission names.
-          let newPermNames = [];
-          for (let permName in newManifest.permissions) {
-            let expandedPermNames =
-              expandPermissions(permName,
-                                newManifest.permissions[permName].access);
-            newPermNames = newPermNames.concat(expandedPermNames);
-          }
-
-          newPermNames.push("indexedDB");
-
-          // Add the appcache related permissions.
-          if (newManifest.appcache_path) {
-            newPermNames = newPermNames.concat(["offline-app", "pin-app"]);
-          }
-
-          for (let idx in AllPossiblePermissions) {
-            let permName = AllPossiblePermissions[idx];
-            let index = newPermNames.indexOf(permName);
-            if (index == -1) {
-              // See if the permission was installed previously.
-              let permValue =
-                PermissionSettingsModule.getPermission(permName,
-                                                       aApp.manifestURL,
-                                                       aApp.origin,
-                                                       false);
-              if (permValue == "unknown" || permValue == "deny") {
-                // All 'deny' permissions should be preserved
-                continue;
-              }
-              // Remove the deprecated permission
-              PermissionSettingsModule.removePermission(permName,
-                                                        aApp.manifestURL,
-                                                        aApp.origin,
-                                                        false);
-            }
-          }
-        }
-      }
-
-      // Check to see if the 'webapp' is app/privileged/certified.
-      let appStatus = newManifest.type;
-
-      this._setPermission("indexedDB", "allow", aApp);
-
-      // Add the appcache related permissions. We allow it for all kinds of
-      // apps.
-      if (newManifest.appcache_path) {
-        this._setPermission("offline-app", "allow", aApp);
-        this._setPermission("pin-app", "allow", aApp);
-      }
-
-      for (let permName in newManifest.permissions) {
-        if (!PermissionsTable[permName]) {
-          Cu.reportError("PermissionsInstaller.jsm: '" + permName + "'" +
-                         " is not a valid Webapps permission name.");
-          dump("PermissionsInstaller.jsm: '" + permName + "'" +
-               " is not a valid Webapps permission name. " + aApp.origin);
-          continue;
-        }
-
-        let expandedPermNames =
-          expandPermissions(permName,
-                            newManifest.permissions[permName].access);
-        for (let idx in expandedPermNames) {
-
-          let isPromptPermission =
-            PermissionsTable[permName][appStatus] === PROMPT_ACTION;
-
-          // We silently upgrade the permission to whatever the permission
-          // is for certified apps (ALLOW or PROMPT) only if the
-          // following holds true:
-          // * The app is preinstalled
-          // * The permission that would be granted is PROMPT
-          // * The app is privileged
-          let permission =
-            aApp.isPreinstalled && isPromptPermission &&
-            appStatus === "privileged"
-                ? PermissionsTable[permName]["certified"]
-                : PermissionsTable[permName][appStatus];
-
-          let permValue = PERM_TO_STRING[permission];
-          if (isPromptPermission) {
-            // If the permission is prompt, keep the current value. This will
-            // 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,
-                                                     aApp.isCachedPackage);
-            if (permValue === "unknown") {
-              permValue = PERM_TO_STRING[permission];
-            }
-          }
-
-          this._setPermission(expandedPermNames[idx], permValue, aApp);
-        }
-      }
-    }
-    catch (ex) {
-      dump("Caught webapps install permissions error for " + aApp.origin +
-        " : " + ex + "\n");
-      Cu.reportError(ex);
-      return false;
-    }
-    return true;
-  },
-
-  /**
-   * 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, origin, appId, isCachedPackage.
-   * @returns void
-   **/
-  _setPermission: function setPermission(aPermName, aPermValue, aApp) {
-    debug(`setPermission ${aPermName} -> ${aPermValue} for ${aApp.origin}`);
-    PermissionSettingsModule.addPermission({
-      type: aPermName,
-      origin: aApp.origin,
-      manifestURL: aApp.manifestURL,
-      value: aPermValue,
-      browserFlag: false,
-      localId: aApp.localId,
-      isCachedPackage: aApp.isCachedPackage,
-    });
-  },
-
-  processApp: function(aApp) {
-    return new Promise((aResolve, aReject) => {
-      debug(`Processing ${aApp}`);
-      loadJSON(`http://localhost/${aApp}/manifest.webapp`)
-        .then(aManifest => {
-          debug(`Got manifest for ${aApp}`);
-          let data = {
-            isCachedPackage: true,
-            origin: "http://localhost/^inBrowser=1", // welcome to hack-land.
-            manifest: aManifest
-          }
-          if (this.installPermissions(data, false)) {
-            aResolve();
-          } else {
-            aReject();
-          }
-        })
-        .catch(err => {
-          aReject(err);
-        })
-    });
-  },
-
-  setAllPermissions(aRootURL) {
-    debug("setAllPermissions");
-    return loadJSON("file:///system/b2g/apps/webapps.json")
-      .then(apps => {
-        let promises = [];
-        for (let app in apps) {
-          // For each app, load the webapps.manifest file and process the
-          // permissions.
-          promises.push(this.processApp(app));
-        }
-        return Promise.all(promises);
-      })
-      .catch(err => {
-        debug(`Error loading webapps.json : ${err}`);
-      });
-  }
-};
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/moz.build
+++ b/b2g/components/moz.build
@@ -50,17 +50,16 @@ if CONFIG['MOZ_UPDATER']:
     EXTRA_COMPONENTS += [
         'UpdatePrompt.js',
     ]
 
 EXTRA_JS_MODULES += [
     'AboutServiceWorkers.jsm',
     'ActivityChannel.jsm',
     'AlertsHelper.jsm',
-    'AppPermissions.jsm',
     'Bootstraper.jsm',
     'ContentRequestHelper.jsm',
     'DebuggerActors.js',
     'ErrorPage.jsm',
     'Frames.jsm',
     'FxAccountsMgmtService.jsm',
     'LogCapture.jsm',
     'LogParser.jsm',
@@ -75,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