Bug 1018320 - RequestSync API - patch 6 - Manager API, r=ehsan
☠☠ backed out by 636498d041b5 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Sun, 04 Jan 2015 10:37:18 +0100
changeset 221958 bce9ed290dddb7492cf3b333751589af21c4a563
parent 221957 8c01c134e40f0c73b8841e2210b17333944e4804
child 221959 2ef1c26d77d3f892e385b828f0694a41a3740006
push id53474
push useramarchesini@mozilla.com
push dateSun, 04 Jan 2015 09:38:35 +0000
treeherdermozilla-inbound@2ef1c26d77d3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1018320
milestone37.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 1018320 - RequestSync API - patch 6 - Manager API, r=ehsan
dom/requestsync/RequestSyncApp.jsm
dom/requestsync/RequestSyncManager.js
dom/requestsync/RequestSyncService.jsm
dom/requestsync/RequestSyncTask.jsm
dom/requestsync/moz.build
dom/requestsync/tests/common_basic.js
dom/requestsync/tests/test_basic.html
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/RequestSyncManager.webidl
dom/webidl/RequestSyncScheduler.webidl
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncApp.jsm
@@ -0,0 +1,48 @@
+/* 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';
+
+this.EXPORTED_SYMBOLS = ['RequestSyncApp'];
+
+function debug(s) {
+  //dump('DEBUG RequestSyncApp: ' + s + '\n');
+}
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+this.RequestSyncApp = function(aData) {
+  debug('created');
+
+  let keys = [ 'origin', 'manifestURL', 'isInBrowserElement' ];
+  for (let i = 0; i < keys.length; ++i) {
+    if (!(keys[i] in aData)) {
+      dump("ERROR - RequestSyncApp must receive a full app object: " + keys[i] + " missing.");
+      throw "ERROR!";
+    }
+
+    this["_" + keys[i]] = aData[keys[i]];
+  }
+}
+
+this.RequestSyncApp.prototype = {
+  classDescription: 'RequestSyncApp XPCOM Component',
+  classID: Components.ID('{5a0b64db-a2be-4f08-a6c5-8bf2e3ae0c57}'),
+  contractID: '@mozilla.org/dom/request-sync-manager;1',
+  QueryInterface: XPCOMUtils.generateQI([]),
+
+  get origin() {
+    return this._origin;
+  },
+
+  get manifestURL() {
+    return this._manifestURL;
+  },
+
+  get isInBrowserElement() {
+    return this._isInBrowserElement;
+  }
+};
--- a/dom/requestsync/RequestSyncManager.js
+++ b/dom/requestsync/RequestSyncManager.js
@@ -7,16 +7,18 @@
 function debug(s) {
   //dump('DEBUG RequestSyncManager: ' + s + '\n');
 }
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/RequestSyncApp.jsm');
+Cu.import('resource://gre/modules/RequestSyncTask.jsm');
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 function RequestSyncManager() {
   debug('created');
 }
@@ -26,17 +28,18 @@ RequestSyncManager.prototype = {
 
   classDescription: 'RequestSyncManager XPCOM Component',
   classID: Components.ID('{e6f55080-e549-4e30-9d00-15f240fb763c}'),
   contractID: '@mozilla.org/dom/request-sync-manager;1',
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
                                          Ci.nsIObserver,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 
-  _messages: [ "RequestSyncManager:Registrations:Return" ],
+  _messages: [ "RequestSyncManager:Registrations:Return",
+               "RequestSyncManager:SetPolicy:Return" ],
 
   init: function(aWindow) {
     debug("init");
 
     // DOMRequestIpcHelper.initHelper sets this._window
     this.initDOMRequestHelper(aWindow, this._messages);
   },
 
@@ -50,29 +53,70 @@ RequestSyncManager.prototype = {
     });
   },
 
   registrations: function() {
     debug('registrations');
     return this.sendMessage("RequestSyncManager:Registrations", {});
   },
 
+  setPolicy: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement,
+                      aState, aOverwrittenMinInterval) {
+    debug('setPolicy');
+
+    return this.sendMessage("RequestSyncManager:SetPolicy",
+      { task: aTask,
+        origin: aOrigin,
+        manifestURL: aManifestURL,
+        isInBrowserElement: aIsInBrowserElement,
+        state: aState,
+        overwrittenMinInterval: aOverwrittenMinInterval });
+  },
+
+  registrationsResult: function(aData) {
+    debug("registrationsResult");
+
+    let results = new this._window.Array();
+    for (let i = 0; i < aData.length; ++i) {
+      if (!("app" in aData[i])) {
+        dump("ERROR - Serialization error in RequestSyncManager.\n");
+        continue;
+      }
+
+      let app = new RequestSyncApp(aData[i].app);
+      let exposedApp =
+        this._window.RequestSyncApp._create(this._window, app);
+
+      let task = new RequestSyncTask(this, this._window, exposedApp, aData[i]);
+      let exposedTask =
+        this._window.RequestSyncTask._create(this._window, task);
+
+      results.push(exposedTask);
+    }
+    return results;
+  },
+
   receiveMessage: function(aMessage) {
     debug('receiveMessage');
 
     let req = this.getPromiseResolver(aMessage.data.requestID);
     if (!req) {
       return;
     }
 
     if ('error' in aMessage.data) {
       req.reject(Cu.cloneInto(aMessage.data.error, this._window));
       return;
     }
 
+    if (aMessage.name == 'RequestSyncManager:Registrations:Return') {
+      req.resolve(this.registrationsResult(aMessage.data.results));
+      return;
+    }
+
     if ('results' in aMessage.data) {
       req.resolve(Cu.cloneInto(aMessage.data.results, this._window));
       return;
     }
 
     req.resolve();
   }
 };
--- a/dom/requestsync/RequestSyncService.jsm
+++ b/dom/requestsync/RequestSyncService.jsm
@@ -11,16 +11,20 @@ function debug(s) {
 }
 
 const RSYNCDB_VERSION = 1;
 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/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",
@@ -42,19 +46,22 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/scriptsecuritymanager;1",
                                    "nsIScriptSecurityManager");
 
 this.RequestSyncService = {
   __proto__: IndexedDBHelper.prototype,
 
   children: [],
 
-  _messages: [ "RequestSync:Register", "RequestSync:Unregister",
-               "RequestSync:Registrations", "RequestSync:Registration",
-               "RequestSyncManager:Registrations" ],
+  _messages: [ "RequestSync:Register",
+               "RequestSync:Unregister",
+               "RequestSync:Registrations",
+               "RequestSync:Registration",
+               "RequestSyncManager:Registrations",
+               "RequestSyncManager:SetPolicy" ],
 
   _pendingOperation: false,
   _pendingMessages: [],
 
   _registrations: {},
 
   _wifi: false,
 
@@ -311,16 +318,20 @@ this.RequestSyncService = {
       case "RequestSync:Registration":
         this.registration(aMessage.target, aMessage.data, principal);
         break;
 
       case "RequestSyncManager:Registrations":
         this.managerRegistrations(aMessage.target, aMessage.data, principal);
         break;
 
+      case "RequestSyncManager:SetPolicy":
+        this.managerSetPolicy(aMessage.target, aMessage.data, principal);
+        break;
+
       default:
         debug("Wrong message: " + aMessage.name);
         break;
     }
   },
 
   // Basic validation.
   validateRegistrationParams: function(aParams) {
@@ -365,16 +376,23 @@ this.RequestSyncService = {
       this.removeRegistrationInternal(aData.task, key);
     }
 
     // This creates a RequestTaskFull object.
     aData.params.task = aData.task;
     aData.params.lastSync = 0;
     aData.params.principal = aPrincipal;
 
+    aData.params.state = RSYNC_STATE_ENABLED;
+    if (aData.params.wifiOnly) {
+      aData.params.state = RSYNC_STATE_WIFIONLY;
+    }
+
+    aData.params.overwrittenMinInterval = 0;
+
     let dbKey = aData.task + "|" +
                 aPrincipal.appId + '|' +
                 aPrincipal.isInBrowserElement + '|' +
                 aPrincipal.origin;
 
     let data = { principal: aPrincipal,
                  dbKey: dbKey,
                  data: aData.params,
@@ -473,16 +491,61 @@ this.RequestSyncService = {
       results.push(self.createFullTaskObject(aObj.data));
     });
 
     aTarget.sendAsyncMessage("RequestSyncManager:Registrations:Return",
                              { requestID: aData.requestID,
                                results: results });
   },
 
+  // Set a policy to a task.
+  managerSetPolicy: function(aTarget, aData, aPrincipal) {
+    debug("managerSetPolicy");
+
+    let toSave = null;
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      if (aObj.principal.isInBrowserElement != aData.isInBrowserElement ||
+          aObj.principal.origin != aData.origin) {
+        return;
+      }
+
+      let app = appsService.getAppByLocalId(aObj.principal.appId);
+      if (app && app.manifestURL != aData.manifestURL ||
+          (!app && aData.manifestURL != "")) {
+        return;
+      }
+
+      if ("overwrittenMinInterval" in aData) {
+        aObj.data.overwrittenMinInterval = aData.overwrittenMinInterval;
+      }
+
+      aObj.data.state = aData.state;
+
+      if (toSave) {
+        dump("ERROR!! RequestSyncService - SetPolicy matches more than 1 task.\n");
+        return;
+      }
+
+      toSave = aObj;
+    });
+
+    if (!toSave) {
+      aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return",
+                               { requestID: aData.requestID, error: "UnknownTaskError" });
+      return;
+    }
+
+    this.updateObjectInDB(toSave, function() {
+      self.scheduleTimer(toSave);
+      aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return",
+                               { requestID: aData.requestID });
+    });
+  },
+
   // We cannot expose the full internal object to content but just a subset.
   // This method creates this subset.
   createPartialTaskObject: function(aObj) {
     return { task: aObj.task,
              lastSync: aObj.lastSync,
              oneShot: aObj.oneShot,
              minInterval: aObj.minInterval,
              wakeUpPage: aObj.wakeUpPage,
@@ -497,38 +560,54 @@ this.RequestSyncService = {
                 origin: aObj.principal.origin,
                 isInBrowserElement: aObj.principal.isInBrowserElement };
 
     let app = appsService.getAppByLocalId(aObj.principal.appId);
     if (app) {
       obj.app.manifestURL = app.manifestURL;
     }
 
+    obj.state = aObj.state;
+    obj.overwrittenMinInterval = aObj.overwrittenMinInterval;
     return obj;
   },
 
   // Creation of the timer for a particular task object.
   scheduleTimer: function(aObj) {
     debug("scheduleTimer");
 
+    if (aObj.timer) {
+      aObj.timer.cancel();
+      aObj.timer = null;
+    }
+
     // A  registration can be already inactive if it was 1 shot.
     if (!aObj.active) {
       return;
     }
 
+    if (aObj.data.state == RSYNC_STATE_DISABLED) {
+      return;
+    }
+
     // WifiOnly check.
-    if (aObj.data.wifiOnly && !this._wifi) {
+    if (aObj.data.state == RSYNC_STATE_WIFIONLY && !this._wifi) {
       return;
     }
 
     aObj.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
+    let interval = aObj.data.minInterval;
+    if (aObj.data.overwrittenMinInterval > 0) {
+      interval = aObj.data.overwrittenMinInterval;
+    }
+
     let self = this;
     aObj.timer.initWithCallback(function() { self.timeout(aObj); },
-                                aObj.data.minInterval * 1000,
+                                interval * 1000,
                                 Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   timeout: function(aObj) {
     debug("timeout");
 
     if (this._activeTask) {
       debug("queueing tasks");
@@ -734,17 +813,17 @@ this.RequestSyncService = {
   wifiStateChanged: function(aEnabled) {
     debug("onWifiStateChanged");
     this._wifi = aEnabled;
 
     if (!this._wifi) {
       // Disable all the wifiOnly tasks.
       let self = this;
       this.forEachRegistration(function(aObj) {
-        if (aObj.data.wifiOnly && aObj.timer) {
+        if (aObj.data.state == RSYNC_STATE_WIFIONLY && aObj.timer) {
           aObj.timer.cancel();
           aObj.timer = null;
 
           // It can be that this task has been already schedulated.
           self.removeTaskFromQueue(aObj);
         }
       });
       return;
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncTask.jsm
@@ -0,0 +1,101 @@
+/* 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';
+
+this.EXPORTED_SYMBOLS = ['RequestSyncTask'];
+
+function debug(s) {
+  //dump('DEBUG RequestSyncTask: ' + s + '\n');
+}
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+this.RequestSyncTask = function(aManager, aWindow, aApp, aData) {
+  debug('created');
+
+  this._manager = aManager;
+  this._window = aWindow;
+  this._app = aApp;
+
+  let keys = [ 'task', 'lastSync', 'oneShot', 'minInterval', 'wakeUpPage',
+               'wifiOnly', 'data', 'state', 'overwrittenMinInterval' ];
+  for (let i = 0; i < keys.length; ++i) {
+    if (!(keys[i] in aData)) {
+      dump("ERROR - RequestSyncTask must receive a fully app object: " + keys[i] + " missing.");
+      throw "ERROR!";
+    }
+
+    this["_" + keys[i]] = aData[keys[i]];
+  }
+}
+
+this.RequestSyncTask.prototype = {
+  classDescription: 'RequestSyncTask XPCOM Component',
+  classID: Components.ID('{a1e1c9c6-ce42-49d4-b8b4-fbd686d8fdd9}'),
+  contractID: '@mozilla.org/dom/request-sync-manager;1',
+  QueryInterface: XPCOMUtils.generateQI([]),
+
+  get app() {
+    return this._app;
+  },
+
+  get state() {
+    return this._state;
+  },
+
+  get overwrittenMinInterval() {
+    return this._overwrittenMinInterval;
+  },
+
+  get task() {
+    return this._task;
+  },
+
+  get lastSync() {
+    return this._lastSync;
+  },
+
+  get wakeUpPage() {
+    return this._wakeUpPage;
+  },
+
+  get oneShot() {
+    return this._oneShot;
+  },
+
+  get minInterval() {
+    return this._minInterval;
+  },
+
+  get wifiOnly() {
+    return this._wifiOnly;
+  },
+
+  get data() {
+    return this._data;
+  },
+
+  setPolicy: function(aState, aOverwrittenMinInterval) {
+    debug("setPolicy");
+    let self = this;
+
+    return new this._window.Promise(function(aResolve, aReject) {
+      let p = self._manager.setPolicy(self._task, self._app.origin,
+                                      self._app.manifestURL,
+                                      self._app.isInBrowserElement,
+                                      aState,
+                                      aOverwrittenMinInterval);
+
+      // Set the new value only when the promise is resolved.
+      p.then(function() {
+        self._state = aState;
+        self._overwrittenMinInterval = aOverwrittenMinInterval;
+        aResolve();
+      }, aReject);
+    });
+  }
+};
--- a/dom/requestsync/moz.build
+++ b/dom/requestsync/moz.build
@@ -12,17 +12,19 @@ EXPORTS.mozilla.dom += [
 
 EXTRA_COMPONENTS += [
     'RequestSync.manifest',
     'RequestSyncManager.js',
     'RequestSyncScheduler.js',
 ]
 
 EXTRA_JS_MODULES += [
+    'RequestSyncApp.jsm',
     'RequestSyncService.jsm',
+    'RequestSyncTask.jsm',
 ]
 
 SOURCES += [
     'RequestSyncWifiService.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/dom/requestsync/tests/common_basic.js
+++ b/dom/requestsync/tests/common_basic.js
@@ -146,27 +146,42 @@ function test_managerRegistrationsEmpty(
   navigator.syncManager.registrations().then(
   function(results) {
     is(results.length, 0, "navigator.syncManager.registrations() should return an empty array.");
     runTests();
   },
   genericError);
 }
 
-function test_managerRegistrations() {
+function test_managerRegistrations(state, overwrittenMinInterval) {
   navigator.syncManager.registrations().then(
   function(results) {
     is(results.length, 1, "navigator.sync.registrations() should not return an empty array.");
     is(results[0].task, 'foobar', "navigator.sync.registrations()[0].task is correct");
     ok("lastSync" in results[0], "navigator.sync.registrations()[0].lastSync is correct");
     is(results[0].oneShot, true, "navigator.sync.registrations()[0].oneShot is correct");
     is(results[0].minInterval, 5, "navigator.sync.registrations()[0].minInterval is correct");
     ok("wakeUpPage" in results[0], "navigator.sync.registration()[0].wakeUpPage is correct");
     ok("wifiOnly" in results[0], "navigator.sync.registrations()[0].wifiOnly is correct");
     ok("data" in results[0], "navigator.sync.registrations()[0].data is correct");
     ok("app" in results[0], "navigator.sync.registrations()[0].app is correct");
     ok("manifestURL" in results[0].app, "navigator.sync.registrations()[0].app.manifestURL is correct");
     is(results[0].app.origin, 'http://mochi.test:8888', "navigator.sync.registrations()[0].app.origin is correct");
     is(results[0].app.isInBrowserElement, false, "navigator.sync.registrations()[0].app.isInBrowserElement is correct");
+    is(results[0].state, state, "navigator.sync.registrations()[0].state is correct");
+    is(results[0].overwrittenMinInterval, overwrittenMinInterval, "navigator.sync.registrations()[0].overwrittenMinInterval is correct");
+    ok("setPolicy" in results[0], "navigator.sync.registrations()[0].setPolicy is correct");
     runTests();
   },
   genericError);
 }
+
+function test_managerSetPolicy(state, overwrittenMinInterval) {
+  navigator.syncManager.registrations().then(
+  function(results) {
+    results[0].setPolicy(state, overwrittenMinInterval).then(
+    function() {
+      ok(state, results[0].state, "State matches");
+      ok(overwrittenMinInterval, results[0].overwrittenMinInterval, "OverwrittenMinInterval matches");
+      runTests();
+    }, genericError);
+  }).catch(genericError);
+}
--- a/dom/requestsync/tests/test_basic.html
+++ b/dom/requestsync/tests/test_basic.html
@@ -33,22 +33,28 @@
     test_managerRegistrationsEmpty,
     test_registrationsEmpty,
 
     test_registerFailure,
     test_register,
     // overwrite the same registration.
     test_register,
 
-    test_managerRegistrations,
+    function() { test_managerRegistrations('wifiOnly', 0); },
     test_registrations,
 
     test_registrationEmpty,
     test_registration,
 
+    function() { test_managerSetPolicy('disabled', 123); },
+    function() { test_managerRegistrations('disabled', 123); },
+
+    function() { test_managerSetPolicy('enabled', 42); },
+    function() { test_managerRegistrations('enabled', 42); },
+
     test_unregister,
     test_unregisterDuplicate,
 
     test_managerRegistrationsEmpty,
     test_registrationsEmpty,
   ];
 
   function runTests() {
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1209,16 +1209,20 @@ var interfaceNamesInGlobalScope =
     "SVGZoomAndPan",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SVGZoomEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RequestSyncManager", b2g: true, pref: "dom.requestSync.enabled", premission: "requestsync-manager" },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RequestSyncScheduler", b2g: true, pref: "dom.requestSync.enabled" },
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "RequestSyncApp", b2g: true, pref: "dom.requestSync.enabled", premission: "requestsync-manager" },
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "RequestSyncTask", b2g: true, pref: "dom.requestSync.enabled", premission: "requestsync-manager" },
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Telephony", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCall", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCallGroup", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCallId", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/RequestSyncManager.webidl
+++ b/dom/webidl/RequestSyncManager.webidl
@@ -1,27 +1,54 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  */
 
-// Rappresentation of the app in the RequestTaskFull.
-dictionary RequestTaskApp {
-  USVString origin;
-  USVString manifestURL;
-  boolean isInBrowserElement;
+[AvailableIn=CertifiedApps,
+ Pref="dom.requestSync.enabled",
+ CheckPermissions="requestsync-manager",
+ JSImplementation="@mozilla.org/dom/request-sync-task-app;1"]
+interface RequestSyncApp {
+  readonly attribute USVString origin;
+  readonly attribute USVString manifestURL;
+  readonly attribute boolean isInBrowserElement;
 };
 
+enum RequestSyncTaskPolicyState { "enabled", "disabled", "wifiOnly" };
+
 // Like a normal task, but with info about the app.
-dictionary RequestTaskFull : RequestTask {
-  RequestTaskApp app;
+[AvailableIn=CertifiedApps,
+ Pref="dom.requestSync.enabled",
+ CheckPermissions="requestsync-manager",
+ JSImplementation="@mozilla.org/dom/request-sync-task-manager;1"]
+interface RequestSyncTask {
+  // This object describes the app that is owning the task.
+  readonly attribute RequestSyncApp app;
+
+  // Using setPolicy it's possible to owerwrite the state and the minInterval.
+  readonly attribute RequestSyncTaskPolicyState state;
+  readonly attribute long overwrittenMinInterval;
+
+  // These attributes are taken from the configuration of the task:
+
+  readonly attribute USVString task;
+  readonly attribute DOMTimeStamp lastSync;
+  readonly attribute USVString wakeUpPage;
+  readonly attribute boolean oneShot;
+  readonly attribute long minInterval;
+  readonly attribute boolean wifiOnly;
+  readonly attribute any data;
+
+  Promise<void> setPolicy(RequestSyncTaskPolicyState aState,
+                          optional long ovewrittenMinInterval);
 };
 
 [NavigatorProperty="syncManager",
  AvailableIn=CertifiedApps,
  Pref="dom.requestSync.enabled",
  CheckPermissions="requestsync-manager",
  JSImplementation="@mozilla.org/dom/request-sync-manager;1"]
 // This interface will be used only by the B2G SystemApp
 interface RequestSyncManager {
-    Promise<sequence<RequestTaskFull>> registrations();
+    Promise<sequence<RequestSyncTask>> registrations();
 };
--- a/dom/webidl/RequestSyncScheduler.webidl
+++ b/dom/webidl/RequestSyncScheduler.webidl
@@ -10,17 +10,17 @@ dictionary RequestTaskParams {
   boolean oneShot = true;
   required long minInterval; // in seconds >= dom.requestSync.minInterval or 100 secs
   boolean wifiOnly = true;
   any data = null;
 };
 
 
 // This is the dictionary you can have back from registration{s}().
-dictionary RequestTask : RequestTaskParams {
+dictionary RequestTaskFull : RequestTaskParams {
   USVString task = "";
 
   // Last synchonization date.. maybe it's useful to know.
   DOMTimeStamp lastSync;
 };
 
 [NavigatorProperty="sync",
  AvailableIn=CertifiedApps,
@@ -28,11 +28,11 @@ dictionary RequestTask : RequestTaskPara
  JSImplementation="@mozilla.org/dom/request-sync-scheduler;1"]
 interface RequestSyncScheduler {
 
   Promise<void> register(USVString task,
                          optional RequestTaskParams params);
   Promise<void> unregister(USVString task);
 
   // Useful methods to get registrations
-  Promise<sequence<RequestTask>> registrations();
-  Promise<RequestTask> registration(USVString task);
+  Promise<sequence<RequestTaskFull>> registrations();
+  Promise<RequestTaskFull> registration(USVString task);
 };