Bug 1200851 - DataStoreService should update its permission map when the homescreen changes, r=fabrice
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 18 Sep 2015 13:49:24 +0800
changeset 295797 a29c301d7bc4f1bf5197ae1548c3092e2da67103
parent 295796 4821738e72af0f4dbc682ae6b5cf112283195e4f
child 295798 dc97158a13f10990503d0d8ffa554f6f74659018
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs1200851
milestone43.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 1200851 - DataStoreService should update its permission map when the homescreen changes, r=fabrice
dom/apps/AppsService.js
dom/apps/AppsServiceChild.jsm
dom/apps/Webapps.jsm
dom/datastore/DataStoreService.cpp
dom/datastore/DataStoreService.h
dom/interfaces/apps/nsIAppsService.idl
--- a/dom/apps/AppsService.js
+++ b/dom/apps/AppsService.js
@@ -161,13 +161,17 @@ AppsService.prototype = {
     // properly in child processes.
     if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
       throw Cr.NS_ERROR_FAILURE;
     }
 
     return UserCustomizations.isFromExtension(aURI);
   },
 
+  updateDataStoreEntriesFromLocalId: function(aLocalId) {
+    return DOMApplicationRegistry.updateDataStoreEntriesFromLocalId(aLocalId);
+  },
+
   classID : APPS_SERVICE_CID,
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AppsService])
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -409,12 +409,16 @@ this.DOMApplicationRegistry = {
 
   getWebAppsBasePath: function getWebAppsBasePath() {
     debug("getWebAppsBasePath() not yet supported on child!");
     return null;
   },
 
   getAppInfo: function getAppInfo(aAppId) {
     return AppsUtils.getAppInfo(this.webapps, aAppId);
+  },
+
+  updateDataStoreEntriesFromLocalId: function(aLocalId) {
+    debug("updateDataStoreEntriesFromLocalId() not yet supported on child!");
   }
 }
 
 DOMApplicationRegistry.init();
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -4692,16 +4692,23 @@ this.DOMApplicationRegistry = {
   getCoreAppsBasePath: function() {
     return AppsUtils.getCoreAppsBasePath();
   },
 
   getWebAppsBasePath: function() {
     return OS.Path.dirname(this.appsFile);
   },
 
+  updateDataStoreEntriesFromLocalId: function(aLocalId) {
+    let app = appsService.getAppByLocalId(aLocalId);
+    if (app) {
+      this.updateDataStoreForApp(app.id);
+    }
+  },
+
   _isLaunchable: function(aApp) {
     if (this.allAppsLaunchable)
       return true;
 
     return WebappOSUtils.isLaunchable(aApp);
   },
 
   _notifyCategoryAndObservers: function(subject, topic, data,  msg) {
--- a/dom/datastore/DataStoreService.cpp
+++ b/dom/datastore/DataStoreService.cpp
@@ -120,16 +120,17 @@ public:
   // A DataStore is enabled when it has its first revision.
   bool mEnabled;
 };
 
 namespace {
 
 // Singleton for DataStoreService.
 StaticRefPtr<DataStoreService> gDataStoreService;
+nsString gHomeScreenManifestURL;
 static uint64_t gCounterID = 0;
 
 typedef nsClassHashtable<nsUint32HashKey, DataStoreInfo> HashApp;
 
 void
 RejectPromise(nsPIDOMWindow* aWindow, Promise* aPromise, nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -444,16 +445,28 @@ AddAccessPermissionsEnumerator(const uin
   bool readOnly = aInfo->mReadOnly || data->mReadOnly;
 
   data->mResult = ResetPermission(data->mAppId, data->mOriginURL,
                                   aInfo->mManifestURL,
                                   permission, readOnly);
   return NS_FAILED(data->mResult) ? PL_DHASH_STOP : PL_DHASH_NEXT;
 }
 
+void
+HomeScreenPrefCallback(const char* aPrefName, void* /* aClosure */)
+{
+  MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
+  nsRefPtr<DataStoreService> service = DataStoreService::Get();
+  if (!service) {
+    return;
+  }
+
+  service->HomeScreenPrefChanged();
+}
+
 } /* anonymous namespace */
 
 // A PendingRequest is created when a content code wants a list of DataStores
 // but some of them are not enabled yet.
 class PendingRequest
 {
 public:
   void Init(nsPIDOMWindow* aWindow, Promise* aPromise,
@@ -800,16 +813,22 @@ DataStoreService::Shutdown()
   MOZ_ASSERT(NS_IsMainThread());
 
   if (gDataStoreService) {
     if (XRE_IsParentProcess()) {
       nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
       if (obs) {
         obs->RemoveObserver(gDataStoreService, "webapps-clear-data");
       }
+
+      nsresult rv =
+        Preferences::UnregisterCallback(HomeScreenPrefCallback,
+                                        "dom.mozApps.homescreenURL",
+                                        nullptr);
+      NS_WARN_IF(NS_FAILED(rv));
     }
 
     gDataStoreService = nullptr;
   }
 }
 
 NS_INTERFACE_MAP_BEGIN(DataStoreService)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDataStoreService)
@@ -842,16 +861,23 @@ DataStoreService::Init()
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = obs->AddObserver(this, "webapps-clear-data", false);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  rv = Preferences::RegisterCallback(HomeScreenPrefCallback,
+                                     "dom.mozApps.homescreenURL",
+                                     nullptr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DataStoreService::InstallDataStore(uint32_t aAppId,
                                    const nsAString& aName,
                                    const nsAString& aOriginURL,
                                    const nsAString& aManifestURL,
@@ -1490,10 +1516,95 @@ DataStoreService::GenerateUUID(nsAString
 
   char chars[NSID_LENGTH];
   id.ToProvidedString(chars);
   CopyASCIItoUTF16(chars, aID);
 
   return NS_OK;
 }
 
+void
+DataStoreService::HomeScreenPrefChanged()
+{
+  MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
+
+  nsAdoptingString homescreen =
+    Preferences::GetString("dom.mozApps.homescreenURL");
+  if (homescreen == gHomeScreenManifestURL) {
+    return;
+  }
+
+  // Remove datastores of the old homescreen.
+  if (!gHomeScreenManifestURL.IsEmpty()) {
+    DeleteDataStoresIfNotAllowed(gHomeScreenManifestURL);
+  }
+
+  gHomeScreenManifestURL = homescreen;
+  if (gHomeScreenManifestURL.IsEmpty()) {
+    return;
+  }
+
+  // Add datastores for the new homescreen.
+  AddDataStoresIfAllowed(gHomeScreenManifestURL);
+}
+
+void
+DataStoreService::DeleteDataStoresIfNotAllowed(const nsAString& aManifestURL)
+{
+  nsCOMPtr<nsIAppsService> appsService =
+    do_GetService("@mozilla.org/AppsService;1");
+  if (NS_WARN_IF(!appsService)) {
+    return;
+  }
+
+  nsCOMPtr<mozIApplication> app;
+  nsresult rv = appsService->GetAppByManifestURL(aManifestURL,
+                                                 getter_AddRefs(app));
+  if (NS_WARN_IF(NS_FAILED(rv)) || !app) {
+    return;
+  }
+
+  uint32_t localId;
+  rv = app->GetLocalId(&localId);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = app->GetPrincipal(getter_AddRefs(principal));
+
+  // We delete all the dataStores for this app here.
+  if (NS_WARN_IF(NS_FAILED(rv)) || !principal ||
+      !CheckPermission(principal)) {
+    DeleteDataStores(localId);
+  }
+}
+
+void
+DataStoreService::AddDataStoresIfAllowed(const nsAString& aManifestURL)
+{
+  nsCOMPtr<nsIAppsService> appsService =
+    do_GetService("@mozilla.org/AppsService;1");
+  if (NS_WARN_IF(!appsService)) {
+    return;
+  }
+
+  nsCOMPtr<mozIApplication> app;
+  nsresult rv = appsService->GetAppByManifestURL(aManifestURL,
+                                                 getter_AddRefs(app));
+  if (NS_WARN_IF(NS_FAILED(rv)) || !app) {
+    return;
+  }
+
+  uint32_t localId;
+  rv = app->GetLocalId(&localId);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  rv = appsService->UpdateDataStoreEntriesFromLocalId(localId);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/datastore/DataStoreService.h
+++ b/dom/datastore/DataStoreService.h
@@ -52,16 +52,18 @@ public:
 
   nsresult GenerateUUID(nsAString& aID);
 
   nsresult GetDataStoresFromIPC(const nsAString& aName,
                                 const nsAString& aOwner,
                                 nsIPrincipal* aPrincipal,
                                 nsTArray<DataStoreSetting>* aValue);
 
+  void HomeScreenPrefChanged();
+
 private:
   DataStoreService();
   ~DataStoreService();
 
   nsresult Init();
 
   typedef nsClassHashtable<nsUint32HashKey, DataStoreInfo> HashApp;
 
@@ -92,16 +94,19 @@ private:
 
   nsresult EnableDataStore(uint32_t aAppId, const nsAString& aName,
                            const nsAString& aManifestURL);
 
   already_AddRefed<RetrieveRevisionsCounter> GetCounter(uint32_t aId) const;
 
   void RemoveCounter(uint32_t aId);
 
+  void DeleteDataStoresIfNotAllowed(const nsAString& aManifestURL);
+  void AddDataStoresIfAllowed(const nsAString& aManifestURL);
+
   nsClassHashtable<nsStringHashKey, HashApp> mStores;
   nsClassHashtable<nsStringHashKey, HashApp> mAccessStores;
 
   typedef nsTArray<PendingRequest> PendingRequests;
   nsClassHashtable<nsStringHashKey, PendingRequests> mPendingRequests;
 
   nsRefPtrHashtable<nsUint32HashKey, RetrieveRevisionsCounter> mPendingCounters;
 
--- a/dom/interfaces/apps/nsIAppsService.idl
+++ b/dom/interfaces/apps/nsIAppsService.idl
@@ -11,17 +11,17 @@ interface nsIURI;
 #define APPS_SERVICE_CID { 0x05072afa, 0x92fe, 0x45bf, { 0xae, 0x22, 0x39, 0xb6, 0x9c, 0x11, 0x70, 0x58 } }
 #define APPS_SERVICE_CONTRACTID "@mozilla.org/AppsService;1"
 %}
 
 /*
  * This service allows accessing some DOMApplicationRegistry methods from
  * non-javascript code.
  */
-[scriptable, uuid(8a035714-ed14-446f-8bd7-837e91cdce9e)]
+[scriptable, uuid(711cfab6-7b72-4aa2-a60c-17952ea05661)]
 interface nsIAppsService : nsISupports
 {
   mozIApplication getAppByManifestURL(in DOMString manifestURL);
 
   /**
    * Returns a Promise for the manifest for a given manifestURL.
    * This is only supported in the parent process: the promise will be rejected
    * in content processes.
@@ -84,10 +84,15 @@ interface nsIAppsService : nsISupports
    */
   DOMString getScopeByLocalId(in unsigned long localId);
 
   /**
    * Returns true if this uri is a script or css resource loaded
    * from an extension.
    * Available only in the parent process.
    */
-   bool isExtensionResource(in nsIURI uri);
+  bool isExtensionResource(in nsIURI uri);
+
+  /**
+   * Reads the manifest file for this app and update the DataStore map
+   */
+  void updateDataStoreEntriesFromLocalId(in unsigned long localId);
 };