mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Merge mozilla-central and b2g-inbound
This commit is contained in:
commit
b1d4cc4939
@ -249,13 +249,8 @@ ContentPermissionPrompt.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// When it's an app, get the manifest to add the l10n application name.
|
||||
let app = DOMApplicationRegistry.getAppByLocalId(principal.appId);
|
||||
DOMApplicationRegistry.getManifestFor(app.manifestURL, function getManifest(aManifest) {
|
||||
let helper = new ManifestHelper(aManifest, app.origin);
|
||||
details.appName = helper.name;
|
||||
browser.shell.sendChromeEvent(details);
|
||||
});
|
||||
details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId);
|
||||
browser.shell.sendChromeEvent(details);
|
||||
},
|
||||
|
||||
classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "4ab5602bc5338c921426cf44e8fbc1b2ddd69290",
|
||||
"revision": "092d3aabd1ec799c748809a484009f0bdde8c51f",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -471,6 +471,8 @@
|
||||
@BINPATH@/components/NetworkInterfaceListService.js
|
||||
@BINPATH@/components/TelephonyProvider.manifest
|
||||
@BINPATH@/components/TelephonyProvider.js
|
||||
@BINPATH@/components/NetworkStatsServiceProxy.manifest
|
||||
@BINPATH@/components/NetworkStatsServiceProxy.js
|
||||
#endif
|
||||
#ifdef MOZ_ENABLE_DBUS
|
||||
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
|
||||
|
@ -156,10 +156,10 @@ this.webappsUI = {
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(aData, localDir,
|
||||
(aManifest) => {
|
||||
(aManifest, aZipPath) => {
|
||||
Task.spawn(function() {
|
||||
try {
|
||||
yield WebappsInstaller.install(aData, aManifest);
|
||||
yield WebappsInstaller.install(aData, aManifest, aZipPath);
|
||||
if (this.downloads[manifestURL]) {
|
||||
yield this.downloads[manifestURL].promise;
|
||||
}
|
||||
|
@ -9,9 +9,10 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/WebappOSUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
|
||||
return Cc["@mozilla.org/network/util;1"]
|
||||
@ -187,7 +188,9 @@ this.AppsUtils = {
|
||||
},
|
||||
|
||||
getAppInfo: function getAppInfo(aApps, aAppId) {
|
||||
if (!aApps[aAppId]) {
|
||||
let app = aApps[aAppId];
|
||||
|
||||
if (!app) {
|
||||
debug("No webapp for " + aAppId);
|
||||
return null;
|
||||
}
|
||||
@ -196,12 +199,12 @@ this.AppsUtils = {
|
||||
// so we can't use the 'removable' property for isCoreApp
|
||||
// Instead, we check if the app is installed under /system/b2g
|
||||
let isCoreApp = false;
|
||||
let app = aApps[aAppId];
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
isCoreApp = app.basePath == this.getCoreAppsBasePath();
|
||||
#endif
|
||||
debug(app.basePath + " isCoreApp: " + isCoreApp);
|
||||
return { "basePath": app.basePath + "/",
|
||||
return { "path": WebappOSUtils.getInstallPath(app),
|
||||
"isCoreApp": isCoreApp };
|
||||
},
|
||||
|
||||
|
@ -1950,8 +1950,8 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
|
||||
// Disallow reinstalls from the same manifest URL for now.
|
||||
if (this._appIdForManifestURL(app.manifestURL) !== null &&
|
||||
this._isLaunchable(app)) {
|
||||
let id = this._appIdForManifestURL(app.manifestURL);
|
||||
if (id !== null && this._isLaunchable(this.webapps[id])) {
|
||||
sendError("REINSTALL_FORBIDDEN");
|
||||
return;
|
||||
}
|
||||
@ -2069,7 +2069,7 @@ this.DOMApplicationRegistry = {
|
||||
app: app,
|
||||
manifest: aManifest });
|
||||
if (installSuccessCallback) {
|
||||
installSuccessCallback(aManifest);
|
||||
installSuccessCallback(aManifest, zipFile.path);
|
||||
}
|
||||
}).bind(this));
|
||||
}).bind(this));
|
||||
@ -2209,6 +2209,11 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
_nextLocalId: function() {
|
||||
let id = Services.prefs.getIntPref("dom.mozApps.maxLocalId") + 1;
|
||||
|
||||
while (this.getManifestURLByLocalId(id)) {
|
||||
id++;
|
||||
}
|
||||
|
||||
Services.prefs.setIntPref("dom.mozApps.maxLocalId", id);
|
||||
Services.prefs.savePrefFile(null);
|
||||
return id;
|
||||
@ -2938,7 +2943,8 @@ this.DOMApplicationRegistry = {
|
||||
let tmp = [];
|
||||
|
||||
for (let appId in this.webapps) {
|
||||
if (this.webapps[appId].manifestURL == aData.manifestURL) {
|
||||
if (this.webapps[appId].manifestURL == aData.manifestURL &&
|
||||
this._isLaunchable(this.webapps[appId])) {
|
||||
aData.app = AppsUtils.cloneAppObject(this.webapps[appId]);
|
||||
tmp.push({ id: appId });
|
||||
break;
|
||||
|
@ -26,6 +26,7 @@ if CONFIG['MOZ_B2G_RIL']:
|
||||
'nsIDOMNetworkStats.idl',
|
||||
'nsIDOMNetworkStatsManager.idl',
|
||||
'nsIMobileConnectionProvider.idl',
|
||||
'nsINetworkStatsServiceProxy.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_network'
|
||||
|
@ -12,9 +12,15 @@ interface nsIDOMMozNetworkStatsData : nsISupports
|
||||
readonly attribute jsval date; // Date.
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(037435a6-f563-48f3-99b3-a0106d8ba5bd)]
|
||||
[scriptable, builtinclass, uuid(6613ea55-b99c-44f9-91bf-d07da10b9b74)]
|
||||
interface nsIDOMMozNetworkStats : nsISupports
|
||||
{
|
||||
/**
|
||||
* Manifest URL of an application for specifying the per-app
|
||||
* stats of the specified app. If null, system stats are returned.
|
||||
*/
|
||||
readonly attribute DOMString manifestURL;
|
||||
|
||||
/**
|
||||
* Can be 'mobile', 'wifi' or null.
|
||||
* If null, stats for both mobile and wifi are returned.
|
||||
|
@ -12,8 +12,12 @@ dictionary NetworkStatsOptions
|
||||
* Connection type used to filter which network stats will be returned:
|
||||
* 'mobile', 'wifi' or null.
|
||||
* If null, stats for both mobile and wifi are returned.
|
||||
*
|
||||
* Manifest URL used to retrieve network stats per app.
|
||||
* If null, system stats (regardless of the app) are returned.
|
||||
*/
|
||||
DOMString connectionType;
|
||||
DOMString manifestURL;
|
||||
jsval start; // date
|
||||
jsval end; // date
|
||||
};
|
||||
@ -22,11 +26,13 @@ dictionary NetworkStatsOptions
|
||||
interface nsIDOMMozNetworkStatsManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Query network interface statistics.
|
||||
* Query network statistics.
|
||||
*
|
||||
* If options.connectionType is not provided, return statistics for all known
|
||||
* network interfaces.
|
||||
*
|
||||
* If options.manifestURL is not provided, return statistics regardless of the app.
|
||||
*
|
||||
* If successful, the request result will be an nsIDOMMozNetworkStats object.
|
||||
*
|
||||
* If network stats are not available for some dates, then rxBytes &
|
||||
|
35
dom/network/interfaces/nsINetworkStatsServiceProxy.idl
Normal file
35
dom/network/interfaces/nsINetworkStatsServiceProxy.idl
Normal file
@ -0,0 +1,35 @@
|
||||
/* 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, function, uuid(5f821529-1d80-4ab5-a933-4e1b3585b6bc)]
|
||||
interface nsINetworkStatsServiceProxyCallback : nsISupports
|
||||
{
|
||||
/*
|
||||
* @param aResult callback result with boolean value
|
||||
* @param aMessage message
|
||||
*/
|
||||
void notify(in boolean aResult, in jsval aMessage);
|
||||
};
|
||||
|
||||
[scriptable, uuid(8fbd115d-f590-474c-96dc-e2b6803ca975)]
|
||||
interface nsINetworkStatsServiceProxy : nsISupports
|
||||
{
|
||||
/*
|
||||
* An interface used to record per-app traffic data.
|
||||
* @param aAppId app id
|
||||
* @param aConnectionType network connection type (0 for wifi, 1 for mobile)
|
||||
* @param aTimeStamp time stamp
|
||||
* @param aRxBytes received data amount
|
||||
* @param aTxBytes transmitted data amount
|
||||
* @param aCallback an optional callback
|
||||
*/
|
||||
void saveAppStats(in unsigned long aAppId,
|
||||
in long aConnectionType,
|
||||
in unsigned long long aTimeStamp,
|
||||
in unsigned long long aRxBytes,
|
||||
in unsigned long long aTxBytes,
|
||||
[optional] in nsINetworkStatsServiceProxyCallback aCallback);
|
||||
};
|
@ -15,8 +15,9 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
||||
|
||||
const DB_NAME = "net_stats";
|
||||
const DB_VERSION = 1;
|
||||
const STORE_NAME = "net_stats";
|
||||
const DB_VERSION = 2;
|
||||
const STORE_NAME = "net_stats"; // Deprecated. Use "net_stats_v2" instead.
|
||||
const STORE_NAME_V2 = "net_stats_v2";
|
||||
|
||||
// Constant defining the maximum values allowed per interface. If more, older
|
||||
// will be erased.
|
||||
@ -30,7 +31,7 @@ this.NetworkStatsDB = function NetworkStatsDB(aGlobal, aConnectionTypes) {
|
||||
debug("Constructor");
|
||||
}
|
||||
this._connectionTypes = aConnectionTypes;
|
||||
this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME], aGlobal);
|
||||
this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME_V2], aGlobal);
|
||||
}
|
||||
|
||||
NetworkStatsDB.prototype = {
|
||||
@ -43,7 +44,7 @@ NetworkStatsDB.prototype = {
|
||||
function errorCb(error) {
|
||||
txnCb(error, null);
|
||||
}
|
||||
return this.newTxn(txn_type, STORE_NAME, callback, successCb, errorCb);
|
||||
return this.newTxn(txn_type, STORE_NAME_V2, callback, successCb, errorCb);
|
||||
},
|
||||
|
||||
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
|
||||
@ -89,14 +90,52 @@ NetworkStatsDB.prototype = {
|
||||
if (DEBUG) {
|
||||
debug("Database initialized");
|
||||
}
|
||||
} else if (currVersion == 1) {
|
||||
// In order to support per-app traffic data storage, the original
|
||||
// objectStore needs to be replaced by a new objectStore with new
|
||||
// key path ("appId") and new index ("appId").
|
||||
let newObjectStore;
|
||||
newObjectStore = db.createObjectStore(STORE_NAME_V2, { keyPath: ["appId", "connectionType", "timestamp"] });
|
||||
newObjectStore.createIndex("appId", "appId", { unique: false });
|
||||
newObjectStore.createIndex("connectionType", "connectionType", { unique: false });
|
||||
newObjectStore.createIndex("timestamp", "timestamp", { unique: false });
|
||||
newObjectStore.createIndex("rxBytes", "rxBytes", { unique: false });
|
||||
newObjectStore.createIndex("txBytes", "txBytes", { unique: false });
|
||||
newObjectStore.createIndex("rxTotalBytes", "rxTotalBytes", { unique: false });
|
||||
newObjectStore.createIndex("txTotalBytes", "txTotalBytes", { unique: false });
|
||||
if (DEBUG) {
|
||||
debug("Created new object stores and indexes");
|
||||
}
|
||||
|
||||
// Copy the data from the original objectStore to the new objectStore.
|
||||
objectStore = aTransaction.objectStore(STORE_NAME);
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
// Delete the original object store.
|
||||
db.deleteObjectStore(STORE_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
let oldStats = cursor.value;
|
||||
let newStats = { appId: 0,
|
||||
connectionType: oldStats.connectionType,
|
||||
timestamp: oldStats.timestamp,
|
||||
rxBytes: oldStats.rxBytes,
|
||||
txBytes: oldStats.txBytes,
|
||||
rxTotalBytes: oldStats.rxTotalBytes,
|
||||
txTotalBytes: oldStats.txTotalBytes };
|
||||
this._saveStats(aTransaction, newObjectStore, newStats);
|
||||
cursor.continue();
|
||||
}.bind(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
normalizeDate: function normalizeDate(aDate) {
|
||||
normalizeDate: function normalizeDate(aDate) {
|
||||
// Convert to UTC according to timezone and
|
||||
// filter timestamp to get SAMPLE_RATE precission
|
||||
let timestamp = aDate.getTime() - (new Date()).getTimezoneOffset() * 60 * 1000;
|
||||
let timestamp = aDate.getTime() - aDate.getTimezoneOffset() * 60 * 1000;
|
||||
timestamp = Math.floor(timestamp / SAMPLE_RATE) * SAMPLE_RATE;
|
||||
return timestamp;
|
||||
},
|
||||
@ -104,12 +143,13 @@ NetworkStatsDB.prototype = {
|
||||
saveStats: function saveStats(stats, aResultCb) {
|
||||
let timestamp = this.normalizeDate(stats.date);
|
||||
|
||||
stats = {connectionType: stats.connectionType,
|
||||
timestamp: timestamp,
|
||||
rxBytes: 0,
|
||||
txBytes: 0,
|
||||
rxTotalBytes: stats.rxBytes,
|
||||
txTotalBytes: stats.txBytes};
|
||||
stats = { appId: stats.appId,
|
||||
connectionType: stats.connectionType,
|
||||
timestamp: timestamp,
|
||||
rxBytes: (stats.appId == 0) ? 0 : stats.rxBytes,
|
||||
txBytes: (stats.appId == 0) ? 0 : stats.txBytes,
|
||||
rxTotalBytes: (stats.appId == 0) ? stats.rxBytes : 0,
|
||||
txTotalBytes: (stats.appId == 0) ? stats.txBytes : 0 };
|
||||
|
||||
this.dbNewTxn("readwrite", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
@ -126,13 +166,18 @@ NetworkStatsDB.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stats.appId != cursor.value.appId) {
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
// There are old samples
|
||||
if (DEBUG) {
|
||||
debug("Last value " + JSON.stringify(cursor.value));
|
||||
}
|
||||
|
||||
// Remove stats previous to now - VALUE_MAX_LENGTH
|
||||
this._removeOldStats(txn, store, stats.connectionType, stats.timestamp);
|
||||
this._removeOldStats(txn, store, stats.appId, stats.connectionType, stats.timestamp);
|
||||
|
||||
// Process stats before save
|
||||
this._processSamplesDiff(txn, store, cursor, stats);
|
||||
@ -160,17 +205,32 @@ NetworkStatsDB.prototype = {
|
||||
debug("New: " + newSample.timestamp + " - Last: " + lastSample.timestamp + " - diff: " + diff);
|
||||
}
|
||||
|
||||
let rxDiff = newSample.rxTotalBytes - lastSample.rxTotalBytes;
|
||||
let txDiff = newSample.txTotalBytes - lastSample.txTotalBytes;
|
||||
if (rxDiff < 0 || txDiff < 0) {
|
||||
rxDiff = newSample.rxTotalBytes;
|
||||
txDiff = newSample.txTotalBytes;
|
||||
// If the incoming data is obtained from netd (|newSample.appId| is 0),
|
||||
// the new |txBytes|/|rxBytes| is assigend by the differnce between the new
|
||||
// |txTotalBytes|/|rxTotalBytes| and the last |txTotalBytes|/|rxTotalBytes|.
|
||||
// Else, the incoming data is per-app data (|newSample.appId| is not 0),
|
||||
// the |txBytes|/|rxBytes| is directly the new |txBytes|/|rxBytes|.
|
||||
if (newSample.appId == 0) {
|
||||
let rxDiff = newSample.rxTotalBytes - lastSample.rxTotalBytes;
|
||||
let txDiff = newSample.txTotalBytes - lastSample.txTotalBytes;
|
||||
if (rxDiff < 0 || txDiff < 0) {
|
||||
rxDiff = newSample.rxTotalBytes;
|
||||
txDiff = newSample.txTotalBytes;
|
||||
}
|
||||
newSample.rxBytes = rxDiff;
|
||||
newSample.txBytes = txDiff;
|
||||
}
|
||||
newSample.rxBytes = rxDiff;
|
||||
newSample.txBytes = txDiff;
|
||||
|
||||
if (diff == 1) {
|
||||
// New element.
|
||||
|
||||
// If the incoming data is per-data data, new |rxTotalBytes|/|txTotalBytes|
|
||||
// needs to be obtained by adding new |rxBytes|/|txBytes| to last
|
||||
// |rxTotalBytes|/|txTotalBytes|.
|
||||
if (newSample.appId != 0) {
|
||||
newSample.rxTotalBytes = newSample.rxBytes + lastSample.rxTotalBytes;
|
||||
newSample.txTotalBytes = newSample.txBytes + lastSample.txTotalBytes;
|
||||
}
|
||||
this._saveStats(txn, store, newSample);
|
||||
return;
|
||||
}
|
||||
@ -185,7 +245,8 @@ NetworkStatsDB.prototype = {
|
||||
let data = [];
|
||||
for (let i = diff - 2; i >= 0; i--) {
|
||||
let time = newSample.timestamp - SAMPLE_RATE * (i + 1);
|
||||
let sample = {connectionType: newSample.connectionType,
|
||||
let sample = {appId: newSample.appId,
|
||||
connectionType: newSample.connectionType,
|
||||
timestamp: time,
|
||||
rxBytes: 0,
|
||||
txBytes: 0,
|
||||
@ -205,10 +266,21 @@ NetworkStatsDB.prototype = {
|
||||
|
||||
// If diff < 0, clock or timezone changed back. Place data in the last sample.
|
||||
|
||||
lastSample.rxBytes += rxDiff;
|
||||
lastSample.txBytes += txDiff;
|
||||
lastSample.rxTotalBytes = newSample.rxTotalBytes;
|
||||
lastSample.txTotalBytes = newSample.txTotalBytes;
|
||||
lastSample.rxBytes += newSample.rxBytes;
|
||||
lastSample.txBytes += newSample.txBytes;
|
||||
|
||||
// If incoming data is obtained from netd, last |rxTotalBytes|/|txTotalBytes|
|
||||
// needs to get updated by replacing the new |rxTotalBytes|/|txTotalBytes|.
|
||||
if (newSample.appId == 0) {
|
||||
lastSample.rxTotalBytes = newSample.rxTotalBytes;
|
||||
lastSample.txTotalBytes = newSample.txTotalBytes;
|
||||
} else {
|
||||
// Else, the incoming data is per-app data, old |rxTotalBytes|/
|
||||
// |txTotalBytes| needs to get updated by adding the new
|
||||
// |rxBytes|/|txBytes| to last |rxTotalBytes|/|txTotalBytes|.
|
||||
lastSample.rxTotalBytes += newSample.rxBytes;
|
||||
lastSample.txTotalBytes += newSample.txBytes;
|
||||
}
|
||||
if (DEBUG) {
|
||||
debug("Update: " + JSON.stringify(lastSample));
|
||||
}
|
||||
@ -231,12 +303,12 @@ NetworkStatsDB.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_removeOldStats: function _removeOldStats(txn, store, connType, date) {
|
||||
_removeOldStats: function _removeOldStats(txn, store, appId, connType, date) {
|
||||
// Callback function to remove old items when new ones are added.
|
||||
let filterDate = date - (SAMPLE_RATE * VALUES_MAX_LENGTH - 1);
|
||||
let lowFilter = [connType, 0];
|
||||
let upFilter = [connType, filterDate];
|
||||
let range = this.dbGlobal.IDBKeyRange.bound(lowFilter, upFilter, false, false);
|
||||
let lowerFilter = [appId, connType, 0];
|
||||
let upperFilter = [appId, connType, filterDate];
|
||||
let range = this.dbGlobal.IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
|
||||
store.openCursor(range).onsuccess = function(event) {
|
||||
var cursor = event.target.result;
|
||||
if (cursor) {
|
||||
@ -261,15 +333,16 @@ NetworkStatsDB.prototype = {
|
||||
let end = this.normalizeDate(aOptions.end);
|
||||
|
||||
if (DEBUG) {
|
||||
debug("Find: connectionType:" + aOptions.connectionType + " start: " + start + " end: " + end);
|
||||
debug("Find: appId: " + aOptions.appId + " connectionType:" +
|
||||
aOptions.connectionType + " start: " + start + " end: " + end);
|
||||
debug("Start time: " + new Date(start));
|
||||
debug("End time: " + new Date(end));
|
||||
}
|
||||
|
||||
this.dbNewTxn("readonly", function(txn, store) {
|
||||
let lowFilter = [aOptions.connectionType, start];
|
||||
let upFilter = [aOptions.connectionType, end];
|
||||
let range = this.dbGlobal.IDBKeyRange.bound(lowFilter, upFilter, false, false);
|
||||
let lowerFilter = [aOptions.appId, aOptions.connectionType, start];
|
||||
let upperFilter = [aOptions.appId, aOptions.connectionType, end];
|
||||
let range = this.dbGlobal.IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
|
||||
|
||||
let data = [];
|
||||
|
||||
@ -291,6 +364,7 @@ NetworkStatsDB.prototype = {
|
||||
// now - VALUES_MAX_LENGTH, fill with empty samples.
|
||||
this.fillResultSamples(start + offset, end + offset, data);
|
||||
|
||||
txn.result.manifestURL = aOptions.manifestURL;
|
||||
txn.result.connectionType = aOptions.connectionType;
|
||||
txn.result.start = aOptions.start;
|
||||
txn.result.end = aOptions.end;
|
||||
@ -305,14 +379,15 @@ NetworkStatsDB.prototype = {
|
||||
let end = this.normalizeDate(aOptions.end);
|
||||
|
||||
if (DEBUG) {
|
||||
debug("FindAll: start: " + start + " end: " + end + "\n");
|
||||
debug("FindAll: appId: " + aOptions.appId +
|
||||
" start: " + start + " end: " + end + "\n");
|
||||
}
|
||||
|
||||
let self = this;
|
||||
this.dbNewTxn("readonly", function(txn, store) {
|
||||
let lowFilter = start;
|
||||
let upFilter = end;
|
||||
let range = this.dbGlobal.IDBKeyRange.bound(lowFilter, upFilter, false, false);
|
||||
let lowerFilter = start;
|
||||
let upperFilter = end;
|
||||
let range = this.dbGlobal.IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
|
||||
|
||||
let data = [];
|
||||
|
||||
@ -323,6 +398,11 @@ NetworkStatsDB.prototype = {
|
||||
let request = store.index("timestamp").openCursor(range).onsuccess = function(event) {
|
||||
var cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor.value.appId != aOptions.appId) {
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.length > 0 &&
|
||||
data[data.length - 1].date.getTime() == cursor.value.timestamp + offset) {
|
||||
// Time is the same, so add values.
|
||||
@ -339,6 +419,7 @@ NetworkStatsDB.prototype = {
|
||||
|
||||
this.fillResultSamples(start + offset, end + offset, data);
|
||||
|
||||
txn.result.manifestURL = aOptions.manifestURL;
|
||||
txn.result.connectionType = aOptions.connectionType;
|
||||
txn.result.start = aOptions.start;
|
||||
txn.result.end = aOptions.end;
|
||||
|
@ -57,13 +57,14 @@ NetworkStatsData.prototype = {
|
||||
|
||||
// NetworkStats
|
||||
const NETWORKSTATS_CONTRACTID = "@mozilla.org/networkstats;1";
|
||||
const NETWORKSTATS_CID = Components.ID("{037435a6-f563-48f3-99b3-a0106d8ba5bd}");
|
||||
const NETWORKSTATS_CID = Components.ID("{6613ea55-b99c-44f9-91bf-d07da10b9b74}");
|
||||
const nsIDOMMozNetworkStats = Components.interfaces.nsIDOMMozNetworkStats;
|
||||
|
||||
function NetworkStats(aWindow, aStats) {
|
||||
if (DEBUG) {
|
||||
debug("NetworkStats Constructor");
|
||||
}
|
||||
this.manifestURL = aStats.manifestURL || null;
|
||||
this.connectionType = aStats.connectionType || null;
|
||||
this.start = aStats.start || null;
|
||||
this.end = aStats.end || null;
|
||||
@ -76,6 +77,7 @@ function NetworkStats(aWindow, aStats) {
|
||||
|
||||
NetworkStats.prototype = {
|
||||
__exposedProps__: {
|
||||
manifestURL: 'r',
|
||||
connectionType: 'r',
|
||||
start: 'r',
|
||||
end: 'r',
|
||||
|
@ -1,8 +1,8 @@
|
||||
component {3b16fe17-5583-483a-b486-b64a3243221c} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkStatsdata;1 {3b16fe17-5583-483a-b486-b64a3243221c}
|
||||
|
||||
component {037435a6-f563-48f3-99b3-a0106d8ba5bd} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkStats;1 {037435a6-f563-48f3-99b3-a0106d8ba5bd}
|
||||
component {6613ea55-b99c-44f9-91bf-d07da10b9b74} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkStats;1 {6613ea55-b99c-44f9-91bf-d07da10b9b74}
|
||||
|
||||
component {87529a6c-aef6-11e1-a595-4f034275cfa6} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkStatsManager;1 {87529a6c-aef6-11e1-a595-4f034275cfa6}
|
||||
|
@ -23,6 +23,9 @@ const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
|
||||
const NET_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
|
||||
const NET_TYPE_MOBILE = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE;
|
||||
|
||||
// The maximum traffic amount can be saved in the |cachedAppStats|.
|
||||
const MAX_CACHED_TRAFFIC = 500 * 1000 * 1000; // 500 MB
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gIDBManager",
|
||||
"@mozilla.org/dom/indexeddb/manager;1",
|
||||
"nsIIndexedDatabaseManager");
|
||||
@ -35,6 +38,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "networkManager",
|
||||
"@mozilla.org/network/manager;1",
|
||||
"nsINetworkManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||
"@mozilla.org/AppsService;1",
|
||||
"nsIAppsService");
|
||||
|
||||
let myGlobal = this;
|
||||
|
||||
this.NetworkStatsService = {
|
||||
@ -74,6 +81,10 @@ this.NetworkStatsService = {
|
||||
this.timer.initWithCallback(this, this._db.sampleRate,
|
||||
Ci.nsITimer.TYPE_REPEATING_PRECISE);
|
||||
|
||||
// App stats are firstly stored in the cached.
|
||||
this.cachedAppStats = Object.create(null);
|
||||
this.cachedAppStatsDate = new Date();
|
||||
|
||||
this.updateQueue = [];
|
||||
this.isQueueRunning = false;
|
||||
},
|
||||
@ -164,15 +175,38 @@ this.NetworkStatsService = {
|
||||
* In order to return updated stats, first is performed a call to
|
||||
* updateAllStats function, which will get last stats from netd
|
||||
* and update the database.
|
||||
* Then, depending on the request (stats per interface or total stats)
|
||||
* Then, depending on the request (stats per appId or total stats)
|
||||
* it retrieve them from database and return to the manager.
|
||||
*/
|
||||
getStats: function getStats(mm, msg) {
|
||||
this.updateAllStats(function onStatsUpdated(aResult, aMessage) {
|
||||
|
||||
let options = msg.data;
|
||||
let data = msg.data;
|
||||
|
||||
let options = { appId: 0,
|
||||
connectionType: data.connectionType,
|
||||
start: data.start,
|
||||
end: data.end };
|
||||
|
||||
let manifestURL = data.manifestURL;
|
||||
if (manifestURL) {
|
||||
let appId = appsService.getAppLocalIdByManifestURL(manifestURL);
|
||||
if (DEBUG) {
|
||||
debug("get appId: " + appId + " from manifestURL: " + manifestURL);
|
||||
}
|
||||
|
||||
if (!appId) {
|
||||
mm.sendAsyncMessage("NetworkStats:Get:Return",
|
||||
{ id: msg.id, error: "Invalid manifestURL", result: null });
|
||||
return;
|
||||
}
|
||||
|
||||
options.appId = appId;
|
||||
options.manifestURL = manifestURL;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
debug("getstats for: - " + options.connectionType + " -");
|
||||
debug("getStats for options: " + JSON.stringify(options));
|
||||
}
|
||||
|
||||
if (!options.connectionType || options.connectionType.length == 0) {
|
||||
@ -207,6 +241,9 @@ this.NetworkStatsService = {
|
||||
},
|
||||
|
||||
updateAllStats: function updateAllStats(callback) {
|
||||
// Update |cachedAppStats|.
|
||||
this.updateCachedAppStats();
|
||||
|
||||
let elements = [];
|
||||
let lastElement;
|
||||
|
||||
@ -356,10 +393,11 @@ this.NetworkStatsService = {
|
||||
return;
|
||||
}
|
||||
|
||||
let stats = { connectionType: this._connectionTypes[connType].name,
|
||||
let stats = { appId: 0,
|
||||
connectionType: this._connectionTypes[connType].name,
|
||||
date: date,
|
||||
rxBytes: txBytes,
|
||||
txBytes: rxBytes};
|
||||
rxBytes: rxBytes,
|
||||
txBytes: txBytes };
|
||||
|
||||
if (DEBUG) {
|
||||
debug("Update stats for " + stats.connectionType + ": rx=" + stats.rxBytes +
|
||||
@ -377,6 +415,130 @@ this.NetworkStatsService = {
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Function responsible for receiving per-app stats.
|
||||
*/
|
||||
saveAppStats: function saveAppStats(aAppId, aConnectionType, aTimeStamp, aRxBytes, aTxBytes, aCallback) {
|
||||
if (DEBUG) {
|
||||
debug("saveAppStats: " + aAppId + " " + aConnectionType + " " +
|
||||
aTimeStamp + " " + aRxBytes + " " + aTxBytes);
|
||||
}
|
||||
|
||||
// |aAppId| can not be 0 or null in this case.
|
||||
if (!aAppId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let stats = { appId: aAppId,
|
||||
connectionType: this._connectionTypes[aConnectionType].name,
|
||||
date: new Date(aTimeStamp),
|
||||
rxBytes: aRxBytes,
|
||||
txBytes: aTxBytes };
|
||||
|
||||
// Generate an unique key from |appId| and |connectionType|,
|
||||
// which is used to retrieve data in |cachedAppStats|.
|
||||
let key = stats.appId + stats.connectionType;
|
||||
|
||||
// |cachedAppStats| only keeps the data with the same date.
|
||||
// If the incoming date is different from |cachedAppStatsDate|,
|
||||
// both |cachedAppStats| and |cachedAppStatsDate| will get updated.
|
||||
let diff = (this._db.normalizeDate(stats.date) -
|
||||
this._db.normalizeDate(this.cachedAppStatsDate)) /
|
||||
this._db.sampleRate;
|
||||
if (diff != 0) {
|
||||
this.updateCachedAppStats(function onUpdated(success, message) {
|
||||
this.cachedAppStatsDate = stats.date;
|
||||
this.cachedAppStats[key] = stats;
|
||||
|
||||
if (!aCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
aCallback.notify(false, message);
|
||||
return;
|
||||
}
|
||||
|
||||
aCallback.notify(true, "ok");
|
||||
}.bind(this));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to find the matched row in the cached by |appId| and |connectionType|.
|
||||
// If not found, save the incoming data into the cached.
|
||||
let appStats = this.cachedAppStats[key];
|
||||
if (!appStats) {
|
||||
this.cachedAppStats[key] = stats;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find matched row, accumulate the traffic amount.
|
||||
appStats.rxBytes += stats.rxBytes;
|
||||
appStats.txBytes += stats.txBytes;
|
||||
|
||||
// If new rxBytes or txBytes exceeds MAX_CACHED_TRAFFIC
|
||||
// the corresponding row will be saved to indexedDB.
|
||||
// Then, the row will be removed from the cached.
|
||||
if (appStats.rxBytes > MAX_CACHED_TRAFFIC ||
|
||||
appStats.txBytes > MAX_CACHED_TRAFFIC) {
|
||||
this._db.saveStats(appStats,
|
||||
function (error, result) {
|
||||
if (DEBUG) {
|
||||
debug("Application stats inserted in indexedDB");
|
||||
}
|
||||
}
|
||||
);
|
||||
delete this.cachedAppStats[key];
|
||||
}
|
||||
},
|
||||
|
||||
updateCachedAppStats: function updateCachedAppStats(callback) {
|
||||
if (DEBUG) {
|
||||
debug("updateCachedAppStats: " + this.cachedAppStatsDate);
|
||||
}
|
||||
|
||||
let stats = Object.keys(this.cachedAppStats);
|
||||
if (stats.length == 0) {
|
||||
// |cachedAppStats| is empty, no need to update.
|
||||
return;
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
this._db.saveStats(this.cachedAppStats[stats[index]],
|
||||
function onSavedStats(error, result) {
|
||||
if (DEBUG) {
|
||||
debug("Application stats inserted in indexedDB");
|
||||
}
|
||||
|
||||
// Clean up the |cachedAppStats| after updating.
|
||||
if (index == stats.length - 1) {
|
||||
this.cachedAppStats = Object.create(null);
|
||||
|
||||
if (!callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
callback(false, error);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(true, "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update is not finished, keep updating.
|
||||
index += 1;
|
||||
this._db.saveStats(this.cachedAppStats[stats[index]],
|
||||
onSavedStats.bind(this, error, result));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
get maxCachedTraffic () {
|
||||
return MAX_CACHED_TRAFFIC;
|
||||
},
|
||||
|
||||
logAllRecords: function logAllRecords() {
|
||||
this._db.logAllRecords(function onResult(error, result) {
|
||||
if (error) {
|
||||
|
47
dom/network/src/NetworkStatsServiceProxy.js
Normal file
47
dom/network/src/NetworkStatsServiceProxy.js
Normal file
@ -0,0 +1,47 @@
|
||||
/* 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 DEBUG = false;
|
||||
function debug(s) { dump("-*- NetworkStatsServiceProxy: " + s + "\n"); }
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["NetworkStatsServiceProxy"];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetworkStatsService.jsm");
|
||||
|
||||
const NETWORKSTATSSERVICEPROXY_CONTRACTID = "@mozilla.org/networkstatsServiceProxy;1";
|
||||
const NETWORKSTATSSERVICEPROXY_CID = Components.ID("8fbd115d-f590-474c-96dc-e2b6803ca975");
|
||||
const nsINetworkStatsServiceProxy = Ci.nsINetworkStatsServiceProxy;
|
||||
|
||||
function NetworkStatsServiceProxy() {
|
||||
if (DEBUG) {
|
||||
debug("Proxy started");
|
||||
}
|
||||
}
|
||||
|
||||
NetworkStatsServiceProxy.prototype = {
|
||||
/*
|
||||
* Function called in the protocol layer (HTTP, FTP, WebSocket ...etc)
|
||||
* to pass the per-app stats to NetworkStatsService.
|
||||
*/
|
||||
saveAppStats: function saveAppStats(aAppId, aConnectionType, aTimeStamp,
|
||||
aRxBytes, aTxBytes, aCallback) {
|
||||
if (DEBUG) {
|
||||
debug("saveAppStats: " + aAppId + " " + aConnectionType + " " +
|
||||
aTimeStamp + " " + aRxBytes + " " + aTxBytes);
|
||||
}
|
||||
|
||||
NetworkStatsService.saveAppStats(aAppId, aConnectionType, aTimeStamp,
|
||||
aRxBytes, aTxBytes, aCallback);
|
||||
},
|
||||
|
||||
classID : NETWORKSTATSSERVICEPROXY_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([nsINetworkStatsServiceProxy]),
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsServiceProxy]);
|
2
dom/network/src/NetworkStatsServiceProxy.manifest
Normal file
2
dom/network/src/NetworkStatsServiceProxy.manifest
Normal file
@ -0,0 +1,2 @@
|
||||
component {8fbd115d-f590-474c-96dc-e2b6803ca975} NetworkStatsServiceProxy.js
|
||||
contract @mozilla.org/networkstatsServiceProxy;1 {8fbd115d-f590-474c-96dc-e2b6803ca975}
|
@ -41,6 +41,8 @@ if CONFIG['MOZ_B2G_RIL']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'NetworkStatsManager.js',
|
||||
'NetworkStatsManager.manifest',
|
||||
'NetworkStatsServiceProxy.js',
|
||||
'NetworkStatsServiceProxy.manifest',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
|
@ -143,7 +143,7 @@ var steps = [
|
||||
}, 1000);
|
||||
},
|
||||
function () {
|
||||
ok(true, "Get stats for a connectionType and dates adapted to samplerate");
|
||||
ok(true, "Get system stats for a connectionType and dates adapted to samplerate");
|
||||
// Prepare get params
|
||||
var type = netStats.connectionTypes[0];
|
||||
var diff = 2;
|
||||
@ -161,7 +161,8 @@ var steps = [
|
||||
// Launch request
|
||||
req = netStats.getNetworkStats({start: startDate, end: endDate, connectionType: type});
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Get stats request ok");
|
||||
ok(true, "Get system stats request ok");
|
||||
ok(req.result.manifestURL == null, "manifestURL should be null");
|
||||
ok(req.result.connectionType == type, "connectionTypes should be equals");
|
||||
ok(req.result.start.getTime() == startDate.getTime(), "starts should be equals");
|
||||
ok(req.result.end.getTime() == endDate.getTime(), "ends should be equals");
|
||||
@ -172,11 +173,11 @@ var steps = [
|
||||
next();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "Get stats for a connectionType failure!");
|
||||
ok(false, "Get system stats for a connectionType failure!");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
ok(true, "Get stats for all connectionTypes and dates adapted to samplerate");
|
||||
ok(true, "Get system stats for all connectionTypes and dates adapted to samplerate");
|
||||
// Prepare get params
|
||||
var diff = 2;
|
||||
// Get samplerate in millis
|
||||
@ -194,6 +195,7 @@ var steps = [
|
||||
req = netStats.getNetworkStats({start: startDate, end: endDate});
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Get stats request ok");
|
||||
ok(req.result.manifestURL == null, "manifestURL should be null");
|
||||
ok(req.result.connectionType == null, "connectionTypes should be null");
|
||||
ok(req.result.start.getTime() == startDate.getTime(), "starts should be equals");
|
||||
ok(req.result.end.getTime() == endDate.getTime(), "ends should be equals");
|
||||
@ -204,11 +206,85 @@ var steps = [
|
||||
next();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "Get stats for all connectionTypes failure!");
|
||||
ok(false, "Get system stats for all connectionTypes failure!");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
ok(true, "Get stats for a connectionType and dates not adapted to samplerate");
|
||||
ok(true, "Get app stats for a connectionType and dates adapted to samplerate");
|
||||
// Prepare get params
|
||||
var url = 'app://browser.gaiamobile.org/manifest.webapp';
|
||||
var type = netStats.connectionTypes[0];
|
||||
var diff = 2;
|
||||
// Get samplerate in millis
|
||||
var sampleRate = netStats.sampleRate * 1000;
|
||||
// Get date with samplerate's precision
|
||||
var offset = new Date().getTimezoneOffset() * 60 * 1000;
|
||||
var endDate = new Date(Math.floor((new Date().getTime() - offset) / sampleRate)
|
||||
* sampleRate + offset);
|
||||
var startDate = new Date(endDate.getTime() - (sampleRate * diff));
|
||||
// Calculate the number of samples that should be returned based on the
|
||||
// the samplerate and including final and initial samples.
|
||||
var samples = (endDate.getTime() - startDate.getTime()) / sampleRate + 1;
|
||||
|
||||
// Launch request
|
||||
req = netStats.getNetworkStats({start: startDate,
|
||||
end: endDate,
|
||||
connectionType: type,
|
||||
manifestURL: url});
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Get app stats request ok");
|
||||
ok(req.result.manifestURL == url, "manifestURL should be equals");
|
||||
ok(req.result.connectionType == type, "connectionTypes should be equals");
|
||||
ok(req.result.start.getTime() == startDate.getTime(), "starts should be equals");
|
||||
ok(req.result.end.getTime() == endDate.getTime(), "ends should be equals");
|
||||
var data = req.result.data;
|
||||
ok(Array.isArray(data) && data.length == samples,
|
||||
"data is an array of length " + samples);
|
||||
checkDataDates(data, startDate, endDate, sampleRate);
|
||||
next();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "Get app stats for a connectionType failure!");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
ok(true, "Get app stats for all connectionTypes and dates adapted to samplerate");
|
||||
// Prepare get params
|
||||
var url = 'app://browser.gaiamobile.org/manifest.webapp';
|
||||
var diff = 2;
|
||||
// Get samplerate in millis
|
||||
var sampleRate = netStats.sampleRate * 1000;
|
||||
// Get date with samplerate's precision
|
||||
var offset = new Date().getTimezoneOffset() * 60 * 1000;
|
||||
var endDate = new Date(Math.floor((new Date().getTime() - offset) / sampleRate)
|
||||
* sampleRate + offset);
|
||||
var startDate = new Date(endDate.getTime() - (sampleRate * diff));
|
||||
// Calculate the number of samples that should be returned based on the
|
||||
// the samplerate and including final and initial samples.
|
||||
var samples = (endDate.getTime() - startDate.getTime()) / sampleRate + 1;
|
||||
|
||||
// Launch request
|
||||
req = netStats.getNetworkStats({start: startDate,
|
||||
end: endDate,
|
||||
manifestURL: url});
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Get app stats request ok");
|
||||
ok(req.result.manifestURL == url, "manifestURL should be equals");
|
||||
ok(req.result.connectionType == null, "connectionTypes should be null");
|
||||
ok(req.result.start.getTime() == startDate.getTime(), "starts should be equals");
|
||||
ok(req.result.end.getTime() == endDate.getTime(), "ends should be equals");
|
||||
var data = req.result.data;
|
||||
ok(Array.isArray(data) && data.length == samples,
|
||||
"data is an array of length " + samples);
|
||||
checkDataDates(data, startDate, endDate, sampleRate);
|
||||
next();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "Get app stats for all connectionTypes failure!");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
ok(true, "Get system stats for a connectionType and dates not adapted to samplerate");
|
||||
// Prepare get params
|
||||
var type = netStats.connectionTypes[0];
|
||||
var diff = 2;
|
||||
@ -225,7 +301,8 @@ var steps = [
|
||||
// Launch request
|
||||
req = netStats.getNetworkStats({start: startDate, end: endDate, connectionType: type});
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Get stats request ok");
|
||||
ok(true, "Get system stats request ok");
|
||||
ok(req.result.manifestURL == null, "manifestURL should be null");
|
||||
ok(req.result.connectionType == type, "connectionTypes should be equals");
|
||||
ok(req.result.start.getTime() == startDate.getTime(), "starts should be equals");
|
||||
ok(req.result.end.getTime() == endDate.getTime(), "ends should be equals");
|
||||
@ -236,11 +313,11 @@ var steps = [
|
||||
next();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "Get stats for a connectionType failure!");
|
||||
ok(false, "Get system stats for a connectionType failure!");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
ok(true, "Get stats for all connectionTypes and dates not adapted to samplerate");
|
||||
ok(true, "Get system stats for all connectionTypes and dates not adapted to samplerate");
|
||||
// Prepare get params
|
||||
var diff = 2;
|
||||
// Get samplerate in millis
|
||||
@ -258,6 +335,7 @@ var steps = [
|
||||
req = netStats.getNetworkStats({start: startDate, end: endDate});
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Get stats request ok");
|
||||
ok(req.result.manifestURL == null, "manifestURL should be null");
|
||||
ok(req.result.connectionType == null, "connectionTypes should be null");
|
||||
ok(req.result.start.getTime() == startDate.getTime(), "starts should be equals");
|
||||
ok(req.result.end.getTime() == endDate.getTime(), "ends should be equals");
|
||||
@ -268,7 +346,7 @@ var steps = [
|
||||
next();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "Get stats for all connectionType failure!");
|
||||
ok(false, "Get system stats for all connectionType failure!");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
/* Any: copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
@ -96,7 +96,8 @@ add_test(function test_clear() {
|
||||
});
|
||||
|
||||
add_test(function test_internalSaveStats_singleSample() {
|
||||
var stats = {connectionType: "wifi",
|
||||
var stats = {appId: 0,
|
||||
connectionType: "wifi",
|
||||
timestamp: Date.now(),
|
||||
rxBytes: 0,
|
||||
txBytes: 0,
|
||||
@ -111,6 +112,7 @@ add_test(function test_internalSaveStats_singleSample() {
|
||||
netStatsDb.logAllRecords(function(error, result) {
|
||||
do_check_eq(error, null);
|
||||
do_check_eq(result.length, 1);
|
||||
do_check_eq(result[0].appId, stats.appId);
|
||||
do_check_eq(result[0].connectionType, stats.connectionType);
|
||||
do_check_eq(result[0].timestamp, stats.timestamp);
|
||||
do_check_eq(result[0].rxBytes, stats.rxBytes);
|
||||
@ -129,7 +131,8 @@ add_test(function test_internalSaveStats_arraySamples() {
|
||||
var samples = 2;
|
||||
var stats = [];
|
||||
for (var i = 0; i < samples; i++) {
|
||||
stats.push({connectionType: "wifi",
|
||||
stats.push({appId: 0,
|
||||
connectionType: "wifi",
|
||||
timestamp: Date.now() + (10 * i),
|
||||
rxBytes: 0,
|
||||
txBytes: 0,
|
||||
@ -148,7 +151,8 @@ add_test(function test_internalSaveStats_arraySamples() {
|
||||
|
||||
var success = true;
|
||||
for (var i = 0; i < samples; i++) {
|
||||
if (result[i].connectionType != stats[i].connectionType ||
|
||||
if (result[i].appId != stats[i].appId ||
|
||||
result[i].connectionType != stats[i].connectionType ||
|
||||
result[i].timestamp != stats[i].timestamp ||
|
||||
result[i].rxBytes != stats[i].rxBytes ||
|
||||
result[i].txBytes != stats[i].txBytes ||
|
||||
@ -172,20 +176,22 @@ add_test(function test_internalRemoveOldStats() {
|
||||
var samples = 10;
|
||||
var stats = [];
|
||||
for (var i = 0; i < samples - 1; i++) {
|
||||
stats.push({connectionType: "wifi", timestamp: Date.now() + (10 * i),
|
||||
stats.push({appId: 0,
|
||||
connectionType: "wifi", timestamp: Date.now() + (10 * i),
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 1234, txTotalBytes: 1234});
|
||||
}
|
||||
|
||||
stats.push({connectionType: "wifi", timestamp: Date.now() + (10 * samples),
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 1234, txTotalBytes: 1234});
|
||||
stats.push({appId: 0,
|
||||
connectionType: "wifi", timestamp: Date.now() + (10 * samples),
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 1234, txTotalBytes: 1234});
|
||||
|
||||
netStatsDb.dbNewTxn("readwrite", function(txn, store) {
|
||||
netStatsDb._saveStats(txn, store, stats);
|
||||
var date = stats[stats.length -1].timestamp
|
||||
+ (netStatsDb.sampleRate * netStatsDb.maxStorageSamples - 1) - 1;
|
||||
netStatsDb._removeOldStats(txn, store, "wifi", date);
|
||||
netStatsDb._removeOldStats(txn, store, 0, "wifi", date);
|
||||
}, function(error, result) {
|
||||
do_check_eq(error, null);
|
||||
|
||||
@ -226,16 +232,19 @@ function processSamplesDiff(lastStat, newStat, callback) {
|
||||
add_test(function test_processSamplesDiffSameSample() {
|
||||
var sampleRate = netStatsDb.sampleRate;
|
||||
var date = filterTimestamp(new Date());
|
||||
var lastStat = {connectionType: "wifi", timestamp: date,
|
||||
var lastStat = {appId: 0,
|
||||
connectionType: "wifi", timestamp: date,
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 1234, txTotalBytes: 1234};
|
||||
|
||||
var newStat = {connectionType: "wifi", timestamp: date,
|
||||
var newStat = {appId: 0,
|
||||
connectionType: "wifi", timestamp: date,
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 2234, txTotalBytes: 2234};
|
||||
|
||||
processSamplesDiff(lastStat, newStat, function(result) {
|
||||
do_check_eq(result.length, 1);
|
||||
do_check_eq(result[0].appId, newStat.appId);
|
||||
do_check_eq(result[0].connectionType, newStat.connectionType);
|
||||
do_check_eq(result[0].timestamp, newStat.timestamp);
|
||||
do_check_eq(result[0].rxBytes, newStat.rxTotalBytes - lastStat.rxTotalBytes);
|
||||
@ -249,16 +258,19 @@ add_test(function test_processSamplesDiffSameSample() {
|
||||
add_test(function test_processSamplesDiffNextSample() {
|
||||
var sampleRate = netStatsDb.sampleRate;
|
||||
var date = filterTimestamp(new Date());
|
||||
var lastStat = {connectionType: "wifi", timestamp: date,
|
||||
var lastStat = {appId: 0,
|
||||
connectionType: "wifi", timestamp: date,
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 1234, txTotalBytes: 1234};
|
||||
|
||||
var newStat = {connectionType: "wifi", timestamp: date + sampleRate,
|
||||
var newStat = {appId: 0,
|
||||
connectionType: "wifi", timestamp: date + sampleRate,
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 500, txTotalBytes: 500};
|
||||
|
||||
processSamplesDiff(lastStat, newStat, function(result) {
|
||||
do_check_eq(result.length, 2);
|
||||
do_check_eq(result[1].appId, newStat.appId);
|
||||
do_check_eq(result[1].connectionType, newStat.connectionType);
|
||||
do_check_eq(result[1].timestamp, newStat.timestamp);
|
||||
do_check_eq(result[1].rxBytes, newStat.rxTotalBytes);
|
||||
@ -273,16 +285,19 @@ add_test(function test_processSamplesDiffSamplesLost() {
|
||||
var samples = 5;
|
||||
var sampleRate = netStatsDb.sampleRate;
|
||||
var date = filterTimestamp(new Date());
|
||||
var lastStat = {connectionType: "wifi", timestamp: date,
|
||||
var lastStat = {appId: 0,
|
||||
connectionType: "wifi", timestamp: date,
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 1234, txTotalBytes: 1234};
|
||||
|
||||
var newStat = {connectionType: "wifi", timestamp: date + (sampleRate * samples),
|
||||
rxBytes: 0, txBytes: 0,
|
||||
var newStat = {appId: 0,
|
||||
connectionType: "wifi", timestamp: date + (sampleRate * samples),
|
||||
rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 2234, txTotalBytes: 2234};
|
||||
|
||||
processSamplesDiff(lastStat, newStat, function(result) {
|
||||
do_check_eq(result.length, samples + 1);
|
||||
do_check_eq(result[0].appId, newStat.appId);
|
||||
do_check_eq(result[samples].connectionType, newStat.connectionType);
|
||||
do_check_eq(result[samples].timestamp, newStat.timestamp);
|
||||
do_check_eq(result[samples].rxBytes, newStat.rxTotalBytes - lastStat.rxTotalBytes);
|
||||
@ -294,10 +309,11 @@ add_test(function test_processSamplesDiffSamplesLost() {
|
||||
});
|
||||
|
||||
add_test(function test_saveStats() {
|
||||
var stats = { connectionType: "wifi",
|
||||
date: new Date(),
|
||||
rxBytes: 2234,
|
||||
txBytes: 2234};
|
||||
var stats = {appId: 0,
|
||||
connectionType: "wifi",
|
||||
date: new Date(),
|
||||
rxBytes: 2234,
|
||||
txBytes: 2234};
|
||||
|
||||
netStatsDb.clear(function (error, result) {
|
||||
do_check_eq(error, null);
|
||||
@ -306,6 +322,7 @@ add_test(function test_saveStats() {
|
||||
netStatsDb.logAllRecords(function(error, result) {
|
||||
do_check_eq(error, null);
|
||||
do_check_eq(result.length, 1);
|
||||
do_check_eq(result[0].appId, stats.appId);
|
||||
do_check_eq(result[0].connectionType, stats.connectionType);
|
||||
let timestamp = filterTimestamp(stats.date);
|
||||
do_check_eq(result[0].timestamp, timestamp);
|
||||
@ -319,6 +336,34 @@ add_test(function test_saveStats() {
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_saveAppStats() {
|
||||
var stats = {appId: 1,
|
||||
connectionType: "wifi",
|
||||
date: new Date(),
|
||||
rxBytes: 2234,
|
||||
txBytes: 2234};
|
||||
|
||||
netStatsDb.clear(function (error, result) {
|
||||
do_check_eq(error, null);
|
||||
netStatsDb.saveStats(stats, function(error, result) {
|
||||
do_check_eq(error, null);
|
||||
netStatsDb.logAllRecords(function(error, result) {
|
||||
do_check_eq(error, null);
|
||||
do_check_eq(result.length, 1);
|
||||
do_check_eq(result[0].appId, stats.appId);
|
||||
do_check_eq(result[0].connectionType, stats.connectionType);
|
||||
let timestamp = filterTimestamp(stats.date);
|
||||
do_check_eq(result[0].timestamp, timestamp);
|
||||
do_check_eq(result[0].rxBytes, stats.rxBytes);
|
||||
do_check_eq(result[0].txBytes, stats.txBytes);
|
||||
do_check_eq(result[0].rxTotalBytes, 0);
|
||||
do_check_eq(result[0].txTotalBytes, 0);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function prepareFind(stats, callback) {
|
||||
netStatsDb.clear(function (error, result) {
|
||||
do_check_eq(error, null);
|
||||
@ -338,14 +383,16 @@ add_test(function test_find () {
|
||||
var end = new Date(start + (sampleRate * (samples - 1)));
|
||||
start = new Date(start - sampleRate);
|
||||
var stats = [];
|
||||
for (var i = 0; i < samples; i++) {i
|
||||
stats.push({connectionType: "wifi", timestamp: saveDate + (sampleRate * i),
|
||||
for (var i = 0; i < samples; i++) {
|
||||
stats.push({appId: 0,
|
||||
connectionType: "wifi", timestamp: saveDate + (sampleRate * i),
|
||||
rxBytes: 0, txBytes: 10,
|
||||
rxTotalBytes: 0, txTotalBytes: 0});
|
||||
|
||||
stats.push({connectionType: "mobile", timestamp: saveDate + (sampleRate * i),
|
||||
rxBytes: 0, txBytes: 10,
|
||||
rxTotalBytes: 0, txTotalBytes: 0});
|
||||
stats.push({appId: 0,
|
||||
connectionType: "mobile", timestamp: saveDate + (sampleRate * i),
|
||||
rxBytes: 0, txBytes: 10,
|
||||
rxTotalBytes: 0, txTotalBytes: 0});
|
||||
}
|
||||
|
||||
prepareFind(stats, function(error, result) {
|
||||
@ -371,8 +418,103 @@ add_test(function test_find () {
|
||||
do_check_eq(result.data[1].txBytes, 20);
|
||||
do_check_eq(result.data[samples].rxBytes, 0);
|
||||
run_next_test();
|
||||
}, {start: start, end: end});
|
||||
}, {start: start, end: end, connectionType: "wifi"});
|
||||
}, {appId: 0, start: start, end: end});
|
||||
}, {start: start, end: end, connectionType: "wifi", appId: 0});
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_findAppStats () {
|
||||
var samples = 5;
|
||||
var sampleRate = netStatsDb.sampleRate;
|
||||
var start = Date.now();
|
||||
var saveDate = filterTimestamp(new Date());
|
||||
var end = new Date(start + (sampleRate * (samples - 1)));
|
||||
start = new Date(start - sampleRate);
|
||||
var stats = [];
|
||||
for (var i = 0; i < samples; i++) {
|
||||
stats.push({appId: 1,
|
||||
connectionType: "wifi", timestamp: saveDate + (sampleRate * i),
|
||||
rxBytes: 0, txBytes: 10,
|
||||
rxTotalBytes: 0, txTotalBytes: 0});
|
||||
|
||||
stats.push({appId: 1,
|
||||
connectionType: "mobile", timestamp: saveDate + (sampleRate * i),
|
||||
rxBytes: 0, txBytes: 10,
|
||||
rxTotalBytes: 0, txTotalBytes: 0});
|
||||
}
|
||||
|
||||
prepareFind(stats, function(error, result) {
|
||||
do_check_eq(error, null);
|
||||
netStatsDb.find(function (error, result) {
|
||||
do_check_eq(error, null);
|
||||
do_check_eq(result.connectionType, "wifi");
|
||||
do_check_eq(result.start.getTime(), start.getTime());
|
||||
do_check_eq(result.end.getTime(), end.getTime());
|
||||
do_check_eq(result.data.length, samples + 1);
|
||||
do_check_eq(result.data[0].rxBytes, null);
|
||||
do_check_eq(result.data[1].rxBytes, 0);
|
||||
do_check_eq(result.data[samples].rxBytes, 0);
|
||||
|
||||
netStatsDb.findAll(function (error, result) {
|
||||
do_check_eq(error, null);
|
||||
do_check_eq(result.connectionType, null);
|
||||
do_check_eq(result.start.getTime(), start.getTime());
|
||||
do_check_eq(result.end.getTime(), end.getTime());
|
||||
do_check_eq(result.data.length, samples + 1);
|
||||
do_check_eq(result.data[0].rxBytes, null);
|
||||
do_check_eq(result.data[1].rxBytes, 0);
|
||||
do_check_eq(result.data[1].txBytes, 20);
|
||||
do_check_eq(result.data[samples].rxBytes, 0);
|
||||
run_next_test();
|
||||
}, {start: start, end: end, appId: 1});
|
||||
}, {start: start, end: end, connectionType: "wifi", appId: 1});
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_saveMultipleAppStats () {
|
||||
var saveDate = filterTimestamp(new Date());
|
||||
var cached = Object.create(null);
|
||||
|
||||
cached['1wifi'] = {appId: 1,
|
||||
connectionType: "wifi", date: new Date(),
|
||||
rxBytes: 0, txBytes: 10};
|
||||
|
||||
cached['1mobile'] = {appId: 1,
|
||||
connectionType: "mobile", date: new Date(),
|
||||
rxBytes: 0, txBytes: 10};
|
||||
|
||||
cached['2wifi'] = {appId: 2,
|
||||
connectionType: "wifi", date: new Date(),
|
||||
rxBytes: 0, txBytes: 10};
|
||||
|
||||
cached['2mobile'] = {appId: 2,
|
||||
connectionType: "mobile", date: new Date(),
|
||||
rxBytes: 0, txBytes: 10};
|
||||
|
||||
let keys = Object.keys(cached);
|
||||
let index = 0;
|
||||
|
||||
netStatsDb.clear(function (error, result) {
|
||||
do_check_eq(error, null);
|
||||
netStatsDb.saveStats(cached[keys[index]],
|
||||
function callback(error, result) {
|
||||
do_check_eq(error, null);
|
||||
|
||||
if (index == keys.length - 1) {
|
||||
netStatsDb.logAllRecords(function(error, result) {
|
||||
do_check_eq(error, null);
|
||||
do_check_eq(result.length, 4);
|
||||
do_check_eq(result[0].appId, 1);
|
||||
do_check_eq(result[0].connectionType, 'mobile');
|
||||
do_check_eq(result[0].rxBytes, 0);
|
||||
do_check_eq(result[0].txBytes, 10);
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
index += 1;
|
||||
netStatsDb.saveStats(cached[keys[index]], callback);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
119
dom/network/tests/unit_stats/test_networkstats_service_proxy.js
Normal file
119
dom/network/tests/unit_stats/test_networkstats_service_proxy.js
Normal file
@ -0,0 +1,119 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "nssProxy",
|
||||
"@mozilla.org/networkstatsServiceProxy;1",
|
||||
"nsINetworkStatsServiceProxy");
|
||||
|
||||
add_test(function test_saveAppStats() {
|
||||
var cachedAppStats = NetworkStatsService.cachedAppStats;
|
||||
var timestamp = NetworkStatsService.cachedAppStatsDate.getTime();
|
||||
var samples = 5;
|
||||
|
||||
do_check_eq(Object.keys(cachedAppStats).length, 0);
|
||||
|
||||
for (var i = 0; i < samples; i++) {
|
||||
nssProxy.saveAppStats(1, Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
timestamp, 10, 20);
|
||||
|
||||
nssProxy.saveAppStats(1, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
|
||||
timestamp, 10, 20);
|
||||
}
|
||||
|
||||
var key1 = 1 + 'wifi';
|
||||
var key2 = 1 + 'mobile';
|
||||
|
||||
do_check_eq(Object.keys(cachedAppStats).length, 2);
|
||||
do_check_eq(cachedAppStats[key1].appId, 1);
|
||||
do_check_eq(cachedAppStats[key1].connectionType, 'wifi');
|
||||
do_check_eq(new Date(cachedAppStats[key1].date).getTime() / 1000,
|
||||
Math.floor(timestamp / 1000));
|
||||
do_check_eq(cachedAppStats[key1].rxBytes, 50);
|
||||
do_check_eq(cachedAppStats[key1].txBytes, 100);
|
||||
do_check_eq(cachedAppStats[key2].appId, 1);
|
||||
do_check_eq(cachedAppStats[key2].connectionType, 'mobile');
|
||||
do_check_eq(new Date(cachedAppStats[key2].date).getTime() / 1000,
|
||||
Math.floor(timestamp / 1000));
|
||||
do_check_eq(cachedAppStats[key2].rxBytes, 50);
|
||||
do_check_eq(cachedAppStats[key2].txBytes, 100);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_saveAppStatsWithDifferentDates() {
|
||||
var today = NetworkStatsService.cachedAppStatsDate;
|
||||
var tomorrow = new Date(today.getTime() + (24 * 60 * 60 * 1000));
|
||||
var key = 1 + 'wifi';
|
||||
|
||||
NetworkStatsService.updateCachedAppStats(
|
||||
function (success, msg) {
|
||||
do_check_eq(success, true);
|
||||
|
||||
do_check_eq(Object.keys(NetworkStatsService.cachedAppStats).length, 0);
|
||||
|
||||
nssProxy.saveAppStats(1, Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
today.getTime(), 10, 20);
|
||||
|
||||
nssProxy.saveAppStats(1, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
|
||||
today.getTime(), 10, 20);
|
||||
|
||||
var saveAppStatsCb = {
|
||||
notify: function notify(success, message) {
|
||||
do_check_eq(success, true);
|
||||
|
||||
var cachedAppStats = NetworkStatsService.cachedAppStats;
|
||||
var key = 2 + 'mobile';
|
||||
do_check_eq(Object.keys(cachedAppStats).length, 1);
|
||||
do_check_eq(cachedAppStats[key].appId, 2);
|
||||
do_check_eq(cachedAppStats[key].connectionType, 'mobile');
|
||||
do_check_eq(new Date(cachedAppStats[key].date).getTime() / 1000,
|
||||
Math.floor(tomorrow.getTime() / 1000));
|
||||
do_check_eq(cachedAppStats[key].rxBytes, 30);
|
||||
do_check_eq(cachedAppStats[key].txBytes, 40);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
};
|
||||
|
||||
nssProxy.saveAppStats(2, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
|
||||
tomorrow.getTime(), 30, 40, saveAppStatsCb);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_test(function test_saveAppStatsWithMaxCachedTraffic() {
|
||||
var timestamp = NetworkStatsService.cachedAppStatsDate.getTime();
|
||||
var maxtraffic = NetworkStatsService.maxCachedTraffic;
|
||||
|
||||
NetworkStatsService.updateCachedAppStats(
|
||||
function (success, msg) {
|
||||
do_check_eq(success, true);
|
||||
|
||||
var cachedAppStats = NetworkStatsService.cachedAppStats;
|
||||
do_check_eq(Object.keys(cachedAppStats).length, 0);
|
||||
|
||||
nssProxy.saveAppStats(1, Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
timestamp, 10, 20);
|
||||
|
||||
do_check_eq(Object.keys(cachedAppStats).length, 1);
|
||||
|
||||
nssProxy.saveAppStats(1, Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
timestamp, maxtraffic, 20);
|
||||
|
||||
do_check_eq(Object.keys(cachedAppStats).length, 0);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
Cu.import("resource://gre/modules/NetworkStatsService.jsm");
|
||||
|
||||
run_next_test();
|
||||
}
|
@ -3,4 +3,5 @@ head =
|
||||
tail =
|
||||
|
||||
[test_networkstats_service.js]
|
||||
[test_networkstats_service_proxy.js]
|
||||
[test_networkstats_db.js]
|
||||
|
@ -481,6 +481,8 @@ pref("devtools.debugger.force-local", true);
|
||||
pref("devtools.debugger.prompt-connection", true);
|
||||
// Temporary setting to enable webapps actors
|
||||
pref("devtools.debugger.enable-content-actors", true);
|
||||
// Block tools from seeing / interacting with certified apps
|
||||
pref("devtools.debugger.forbid-certified-apps", true);
|
||||
|
||||
// view source
|
||||
pref("view_source.syntax_highlight", true);
|
||||
|
@ -70,10 +70,10 @@ AppProtocolHandler.prototype = {
|
||||
let uri;
|
||||
if (this._runningInParent || appInfo.isCoreApp) {
|
||||
// In-parent and CoreApps can directly access files, so use jar:file://
|
||||
uri = "jar:file://" + appInfo.basePath + appId + "/application.zip!" + fileSpec;
|
||||
uri = "jar:file://" + appInfo.path + "/application.zip!" + fileSpec;
|
||||
} else {
|
||||
// non-CoreApps in child need to ask parent for file handle, use jar:ipcfile://
|
||||
uri = "jar:remoteopenfile://" + appInfo.basePath + appId + "/application.zip!" + fileSpec;
|
||||
uri = "jar:remoteopenfile://" + appInfo.path + "/application.zip!" + fileSpec;
|
||||
}
|
||||
let channel = Services.io.newChannel(uri, null, null);
|
||||
channel.QueryInterface(Ci.nsIJARChannel).setAppURI(aURI);
|
||||
|
@ -3,6 +3,7 @@ head = head_apps.js
|
||||
tail = tail_apps.js
|
||||
|
||||
[test_webappsActor.js]
|
||||
skip-if = (os == "win" || "linux" || "mac")
|
||||
[test_appInstall.js]
|
||||
# Persistent failures.
|
||||
skip-if = true
|
||||
|
@ -500,13 +500,36 @@ WebappsActor.prototype = {
|
||||
|
||||
let defer = promise.defer();
|
||||
let reg = DOMApplicationRegistry;
|
||||
reg.getAll(function onsuccess(apps) {
|
||||
defer.resolve({ apps: apps });
|
||||
reg.getAll(apps => {
|
||||
defer.resolve({ apps: this._filterAllowedApps(apps) });
|
||||
});
|
||||
|
||||
return defer.promise;
|
||||
},
|
||||
|
||||
_areCertifiedAppsAllowed: function wa__areCertifiedAppsAllowed() {
|
||||
let pref = "devtools.debugger.forbid-certified-apps";
|
||||
return !Services.prefs.getBoolPref(pref);
|
||||
},
|
||||
|
||||
_isAppAllowedForManifest: function wa__isAppAllowedForManifest(aManifest) {
|
||||
if (this._areCertifiedAppsAllowed()) {
|
||||
return true;
|
||||
}
|
||||
let type = this._getAppType(aManifest.type);
|
||||
return type !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED;
|
||||
},
|
||||
|
||||
_filterAllowedApps: function wa__filterAllowedApps(aApps) {
|
||||
return aApps.filter(app => this._isAppAllowedForManifest(app.manifest));
|
||||
},
|
||||
|
||||
_isAppAllowedForURL: function wa__isAppAllowedForURL(aManifestURL) {
|
||||
return this._findManifestByURL(aManifestURL).then(manifest => {
|
||||
return this._isAppAllowedForManifest(manifest);
|
||||
});
|
||||
},
|
||||
|
||||
uninstall: function wa_actorUninstall(aRequest) {
|
||||
debug("uninstall");
|
||||
|
||||
@ -531,6 +554,19 @@ WebappsActor.prototype = {
|
||||
return defer.promise;
|
||||
},
|
||||
|
||||
_findManifestByURL: function wa__findManifestByURL(aManifestURL) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let reg = DOMApplicationRegistry;
|
||||
let id = reg._appIdForManifestURL(aManifestURL);
|
||||
|
||||
reg._readManifests([{ id: id }], function (aResults) {
|
||||
deferred.resolve(aResults[0].manifest);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
getIconAsDataURL: function (aRequest) {
|
||||
debug("getIconAsDataURL");
|
||||
|
||||
@ -549,9 +585,7 @@ WebappsActor.prototype = {
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
let id = reg._appIdForManifestURL(manifestURL);
|
||||
reg._readManifests([{ id: id }], function (aResults) {
|
||||
let jsonManifest = aResults[0].manifest;
|
||||
this._findManifestByURL(manifestURL).then(jsonManifest => {
|
||||
let manifest = new ManifestHelper(jsonManifest, app.origin);
|
||||
let iconURL = manifest.iconURLForSize(aRequest.size || 128);
|
||||
if (!iconURL) {
|
||||
@ -665,14 +699,22 @@ WebappsActor.prototype = {
|
||||
listRunningApps: function (aRequest) {
|
||||
debug("listRunningApps\n");
|
||||
|
||||
let appPromises = [];
|
||||
let apps = [];
|
||||
|
||||
for each (let frame in this._appFrames()) {
|
||||
let manifestURL = frame.getAttribute("mozapp");
|
||||
apps.push(manifestURL);
|
||||
|
||||
appPromises.push(this._isAppAllowedForURL(manifestURL).then(allowed => {
|
||||
if (allowed) {
|
||||
apps.push(manifestURL);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
return { apps: apps };
|
||||
return promise.all(appPromises).then(() => {
|
||||
return { apps: apps };
|
||||
});
|
||||
},
|
||||
|
||||
_connectToApp: function (aFrame) {
|
||||
@ -745,24 +787,34 @@ WebappsActor.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
let notFoundError = {
|
||||
error: "appNotFound",
|
||||
message: "Unable to find any opened app whose manifest " +
|
||||
"is '" + manifestURL + "'"
|
||||
};
|
||||
|
||||
if (!appFrame) {
|
||||
return { error: "appNotFound",
|
||||
message: "Unable to find any opened app whose manifest " +
|
||||
"is '" + manifestURL + "'" };
|
||||
return notFoundError;
|
||||
}
|
||||
|
||||
// Only create a new actor, if we haven't already
|
||||
// instanciated one for this connection.
|
||||
let mm = appFrame.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader
|
||||
.messageManager;
|
||||
let actor = this._appActorsMap.get(mm);
|
||||
if (!actor) {
|
||||
return this._connectToApp(appFrame)
|
||||
.then(function (actor) ({ actor: actor }));
|
||||
}
|
||||
return this._isAppAllowedForURL(manifestURL).then(allowed => {
|
||||
if (!allowed) {
|
||||
return notFoundError;
|
||||
}
|
||||
|
||||
return { actor: actor };
|
||||
// Only create a new actor, if we haven't already
|
||||
// instanciated one for this connection.
|
||||
let mm = appFrame.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader
|
||||
.messageManager;
|
||||
let actor = this._appActorsMap.get(mm);
|
||||
if (!actor) {
|
||||
return this._connectToApp(appFrame)
|
||||
.then(function (actor) ({ actor: actor }));
|
||||
}
|
||||
|
||||
return { actor: actor };
|
||||
});
|
||||
},
|
||||
|
||||
watchApps: function () {
|
||||
@ -800,19 +852,30 @@ WebappsActor.prototype = {
|
||||
}
|
||||
this._openedApps.add(manifestURL);
|
||||
|
||||
this.conn.send({ from: this.actorID,
|
||||
type: "appOpen",
|
||||
manifestURL: manifestURL
|
||||
});
|
||||
this._isAppAllowedForURL(manifestURL).then(allowed => {
|
||||
if (allowed) {
|
||||
this.conn.send({ from: this.actorID,
|
||||
type: "appOpen",
|
||||
manifestURL: manifestURL
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case "appterminated":
|
||||
manifestURL = event.detail.manifestURL;
|
||||
this._openedApps.delete(manifestURL);
|
||||
this.conn.send({ from: this.actorID,
|
||||
type: "appClose",
|
||||
manifestURL: manifestURL
|
||||
});
|
||||
|
||||
this._isAppAllowedForURL(manifestURL).then(allowed => {
|
||||
if (allowed) {
|
||||
this.conn.send({ from: this.actorID,
|
||||
type: "appClose",
|
||||
manifestURL: manifestURL
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -8,31 +8,38 @@ const CC = Components.Constructor;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["WebappOSUtils"];
|
||||
|
||||
// Returns the MD5 hash of a string.
|
||||
function computeHash(aString) {
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
let result = {};
|
||||
// Data is an array of bytes.
|
||||
let data = converter.convertToByteArray(aString, result);
|
||||
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(hasher.MD5);
|
||||
hasher.update(data, data.length);
|
||||
// We're passing false to get the binary hash and not base64.
|
||||
let hash = hasher.finish(false);
|
||||
|
||||
function toHexString(charCode) {
|
||||
return ("0" + charCode.toString(16)).slice(-2);
|
||||
}
|
||||
|
||||
// Convert the binary hash data to a hex string.
|
||||
return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
|
||||
}
|
||||
|
||||
this.WebappOSUtils = {
|
||||
getUniqueName: function(aApp) {
|
||||
let name;
|
||||
|
||||
// During the installation of a new app, the aApp object
|
||||
// doesn't have a name property. We then need to use the manifest.
|
||||
// For some mozApps calls, the aApp object doesn't have a manifest
|
||||
// associated, and so we need to use the name property.
|
||||
// They're guaranteed to be always identical to the application
|
||||
// name in the user locale.
|
||||
if (aApp.name) {
|
||||
name = aApp.name;
|
||||
} else {
|
||||
let manifest =
|
||||
new ManifestHelper(aApp.updateManifest || aApp.manifest, aApp.origin);
|
||||
name = manifest.name;
|
||||
}
|
||||
|
||||
return this.sanitizeStringForFilename(name).toLowerCase() + "-" +
|
||||
AppsUtils.computeHash(aApp.manifestURL);
|
||||
return this.sanitizeStringForFilename(aApp.name).toLowerCase() + "-" +
|
||||
computeHash(aApp.manifestURL);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -87,15 +94,20 @@ this.WebappOSUtils = {
|
||||
.createInstance(Ci.nsIMacWebAppUtils);
|
||||
|
||||
try {
|
||||
if (mwaUtils.pathForAppWithIdentifier(uniqueName)) {
|
||||
return uniqueName;
|
||||
}
|
||||
if (mwaUtils.pathForAppWithIdentifier(aApp.origin)) {
|
||||
return aApp.origin;
|
||||
let path;
|
||||
if (path = mwaUtils.pathForAppWithIdentifier(uniqueName)) {
|
||||
return [ uniqueName, path ];
|
||||
}
|
||||
} catch(ex) {}
|
||||
|
||||
return null;
|
||||
try {
|
||||
let path;
|
||||
if (path = mwaUtils.pathForAppWithIdentifier(aApp.origin)) {
|
||||
return [ aApp.origin, path ];
|
||||
}
|
||||
} catch(ex) {}
|
||||
|
||||
return [ null, null ];
|
||||
#elifdef XP_UNIX
|
||||
let exeFile = Services.dirsvc.get("Home", Ci.nsIFile);
|
||||
exeFile.append("." + uniqueName);
|
||||
@ -121,6 +133,31 @@ this.WebappOSUtils = {
|
||||
#endif
|
||||
},
|
||||
|
||||
getInstallPath: function(aApp) {
|
||||
#ifdef XP_WIN
|
||||
let execFile = this.getLaunchTarget(aApp);
|
||||
if (!execFile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return execFile.parent.path;
|
||||
#elifdef XP_MACOSX
|
||||
let [ bundleID, path ] = this.getLaunchTarget(aApp);
|
||||
return path;
|
||||
#elifdef MOZ_B2G
|
||||
return aApp.basePath + "/" + aApp.id;
|
||||
#elifdef MOZ_FENNEC
|
||||
return aApp.basePath + "/" + aApp.id;
|
||||
#elifdef XP_UNIX
|
||||
let execFile = this.getLaunchTarget(aApp);
|
||||
if (!execFile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return execFile.parent.path;
|
||||
#endif
|
||||
},
|
||||
|
||||
launch: function(aApp) {
|
||||
let uniqueName = this.getUniqueName(aApp);
|
||||
|
||||
@ -142,7 +179,7 @@ this.WebappOSUtils = {
|
||||
|
||||
return true;
|
||||
#elifdef XP_MACOSX
|
||||
let launchIdentifier = this.getLaunchTarget(aApp);
|
||||
let [ launchIdentifier, path ] = this.getLaunchTarget(aApp);
|
||||
if (!launchIdentifier) {
|
||||
return false;
|
||||
}
|
||||
@ -215,7 +252,7 @@ this.WebappOSUtils = {
|
||||
|
||||
return true;
|
||||
#elifdef XP_MACOSX
|
||||
if (!this.getLaunchTarget(aApp)) {
|
||||
if (!this.getInstallPath(aApp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -61,8 +61,10 @@ this.WebappsInstaller = {
|
||||
*
|
||||
* @param aData the data provided to the install function
|
||||
* @param aManifest the manifest data provided by the web app
|
||||
* @param aZipPath path to the zip file for packaged apps (undefined for
|
||||
* hosted apps)
|
||||
*/
|
||||
install: function(aData, aManifest) {
|
||||
install: function(aData, aManifest, aZipPath) {
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("browser.mozApps.installer.dry_run")) {
|
||||
return Promise.resolve();
|
||||
@ -71,7 +73,7 @@ this.WebappsInstaller = {
|
||||
|
||||
this.shell.init(aData, aManifest);
|
||||
|
||||
return this.shell.install().then(() => {
|
||||
return this.shell.install(aZipPath).then(() => {
|
||||
let data = {
|
||||
"installDir": this.shell.installDir.path,
|
||||
"app": {
|
||||
@ -96,11 +98,12 @@ this.WebappsInstaller = {
|
||||
*
|
||||
*/
|
||||
function NativeApp(aData) {
|
||||
this.uniqueName = WebappOSUtils.getUniqueName(aData.app);
|
||||
|
||||
let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
|
||||
let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
|
||||
|
||||
aData.app.name = manifest.name;
|
||||
this.uniqueName = WebappOSUtils.getUniqueName(aData.app);
|
||||
|
||||
this.appName = sanitize(manifest.name);
|
||||
this.appNameAsFilename = stripStringForFilename(this.appName);
|
||||
}
|
||||
@ -126,10 +129,11 @@ NativeApp.prototype = {
|
||||
*
|
||||
*/
|
||||
init: function(aData, aManifest) {
|
||||
let app = aData.app;
|
||||
let manifest = this.manifest = new ManifestHelper(aManifest,
|
||||
aData.app.origin);
|
||||
app.origin);
|
||||
|
||||
let origin = Services.io.newURI(aData.app.origin, null, null);
|
||||
let origin = Services.io.newURI(app.origin, null, null);
|
||||
|
||||
let biggestIcon = getBiggestIconURL(manifest.icons);
|
||||
try {
|
||||
@ -169,7 +173,7 @@ NativeApp.prototype = {
|
||||
this.shortDescription = this.appName;
|
||||
}
|
||||
|
||||
this.categories = aData.app.categories.slice(0);
|
||||
this.categories = app.categories.slice(0);
|
||||
|
||||
// The app registry is the Firefox profile from which the app
|
||||
// was installed.
|
||||
@ -179,11 +183,27 @@ NativeApp.prototype = {
|
||||
"registryDir": registryFolder.path,
|
||||
"app": {
|
||||
"manifest": aManifest,
|
||||
"origin": aData.app.origin,
|
||||
"manifestURL": aData.app.manifestURL
|
||||
"origin": app.origin,
|
||||
"manifestURL": app.manifestURL,
|
||||
"installOrigin": app.installOrigin,
|
||||
"categories": app.categories,
|
||||
"receipts": app.receipts,
|
||||
"installTime": app.installTime,
|
||||
}
|
||||
};
|
||||
|
||||
if (app.etag) {
|
||||
this.webappJson.app.etag = app.etag;
|
||||
}
|
||||
|
||||
if (app.packageEtag) {
|
||||
this.webappJson.app.packageEtag = app.packageEtag;
|
||||
}
|
||||
|
||||
if (app.updateManifest) {
|
||||
this.webappJson.app.updateManifest = app.updateManifest;
|
||||
}
|
||||
|
||||
this.runtimeFolder = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||
},
|
||||
|
||||
@ -193,6 +213,23 @@ NativeApp.prototype = {
|
||||
*/
|
||||
getIcon: function() {
|
||||
try {
|
||||
// If the icon is in the zip package, we should modify the url
|
||||
// to point to the zip file (we can't use the app protocol yet
|
||||
// because the app isn't installed yet).
|
||||
if (this.iconURI.scheme == "app") {
|
||||
let zipFile = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsIFile);
|
||||
zipFile.initWithPath(OS.Path.join(this.installDir.path,
|
||||
"application.zip"));
|
||||
let zipUrl = Services.io.newFileURI(zipFile).spec;
|
||||
|
||||
let filePath = this.iconURI.QueryInterface(Ci.nsIURL).filePath;
|
||||
|
||||
this.iconURI = Services.io.newURI("jar:" + zipUrl + "!" + filePath,
|
||||
null, null);
|
||||
}
|
||||
|
||||
|
||||
let [ mimeType, icon ] = yield downloadIcon(this.iconURI);
|
||||
yield this.processIcon(mimeType, icon);
|
||||
}
|
||||
@ -271,13 +308,19 @@ WinNativeApp.prototype = {
|
||||
* Install the app in the system
|
||||
*
|
||||
*/
|
||||
install: function() {
|
||||
install: function(aZipPath) {
|
||||
return Task.spawn(function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createShortcutFiles();
|
||||
this._createConfigFiles();
|
||||
this._writeSystemKeys();
|
||||
|
||||
if (aZipPath) {
|
||||
yield OS.File.move(aZipPath, OS.Path.join(this.installDir.path,
|
||||
"application.zip"));
|
||||
}
|
||||
|
||||
yield this.getIcon();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
@ -624,11 +667,17 @@ MacNativeApp.prototype = {
|
||||
this._createDirectoryStructure();
|
||||
},
|
||||
|
||||
install: function() {
|
||||
install: function(aZipPath) {
|
||||
return Task.spawn(function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
|
||||
if (aZipPath) {
|
||||
yield OS.File.move(aZipPath, OS.Path.join(this.installDir.path,
|
||||
"application.zip"));
|
||||
}
|
||||
|
||||
yield this.getIcon();
|
||||
this._moveToApplicationsFolder();
|
||||
} catch (ex) {
|
||||
@ -821,11 +870,17 @@ LinuxNativeApp.prototype = {
|
||||
this._createDirectoryStructure();
|
||||
},
|
||||
|
||||
install: function() {
|
||||
install: function(aZipPath) {
|
||||
return Task.spawn(function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
|
||||
if (aZipPath) {
|
||||
yield OS.File.move(aZipPath, OS.Path.join(this.installDir.path,
|
||||
"application.zip"));
|
||||
}
|
||||
|
||||
yield this.getIcon();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
|
@ -29,6 +29,9 @@
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <hardware/hardware.h>
|
||||
#if ANDROID_VERSION == 17
|
||||
#include <gui/SurfaceTextureClient.h>
|
||||
#endif
|
||||
#include <ui/GraphicBuffer.h>
|
||||
|
||||
#include "FramebufferSurface.h"
|
||||
|
@ -14,7 +14,11 @@
|
||||
*/
|
||||
|
||||
#include "GonkDisplayJB.h"
|
||||
#if ANDROID_VERSION == 17
|
||||
#include <gui/SurfaceTextureClient.h>
|
||||
#else
|
||||
#include <gui/Surface.h>
|
||||
#endif
|
||||
|
||||
#include <hardware/hardware.h>
|
||||
#include <hardware/hwcomposer.h>
|
||||
@ -46,10 +50,10 @@ GonkDisplayJB::GonkDisplayJB()
|
||||
ALOGW_IF(err, "could not open framebuffer");
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (!err && mFBDevice) {
|
||||
mWidth = mFBDevice->width;
|
||||
mHeight = mFBDevice->height;
|
||||
xdpi = mFBDevice->xdpi;
|
||||
mHeight = mFBDevice->height;
|
||||
xdpi = mFBDevice->xdpi;
|
||||
/* The emulator actually reports RGBA_8888, but EGL doesn't return
|
||||
* any matching configuration. We force RGBX here to fix it. */
|
||||
surfaceformat = HAL_PIXEL_FORMAT_RGBX_8888;
|
||||
@ -99,7 +103,11 @@ GonkDisplayJB::GonkDisplayJB()
|
||||
mAlloc = new GraphicBufferAlloc();
|
||||
mFBSurface = new FramebufferSurface(0, mWidth, mHeight, surfaceformat, mAlloc);
|
||||
|
||||
#if ANDROID_VERSION == 17
|
||||
sp<SurfaceTextureClient> stc = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(mFBSurface->getBufferQueue()));
|
||||
#else
|
||||
sp<Surface> stc = new Surface(static_cast<sp<IGraphicBufferProducer> >(mFBSurface->getBufferQueue()));
|
||||
#endif
|
||||
mSTClient = stc;
|
||||
|
||||
mList = (hwc_display_contents_1_t *)malloc(sizeof(*mList) + (sizeof(hwc_layer_1_t)*2));
|
||||
@ -108,7 +116,10 @@ GonkDisplayJB::GonkDisplayJB()
|
||||
|
||||
status_t error;
|
||||
mBootAnimBuffer = mAlloc->createGraphicBuffer(mWidth, mHeight, surfaceformat, GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER, &error);
|
||||
StartBootAnimation();
|
||||
if (error == NO_ERROR && mBootAnimBuffer.get())
|
||||
StartBootAnimation();
|
||||
else
|
||||
ALOGW("Couldn't show bootanimation (%s)", strerror(-error));
|
||||
}
|
||||
|
||||
GonkDisplayJB::~GonkDisplayJB()
|
||||
@ -173,8 +184,14 @@ GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur)
|
||||
if (mFBDevice && mFBDevice->compositionComplete) {
|
||||
mFBDevice->compositionComplete(mFBDevice);
|
||||
}
|
||||
|
||||
#if ANDROID_VERSION == 17
|
||||
mList->dpy = dpy;
|
||||
mList->sur = sur;
|
||||
#else
|
||||
mList->outbuf = nullptr;
|
||||
mList->outbufAcquireFenceFd = -1;
|
||||
#endif
|
||||
eglSwapBuffers(dpy, sur);
|
||||
return Post(mFBSurface->lastHandle, mFBSurface->lastFenceFD);
|
||||
}
|
||||
@ -213,7 +230,9 @@ GonkDisplayJB::Post(buffer_handle_t buf, int fence)
|
||||
mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[1].sourceCrop;
|
||||
mList->hwLayers[1].acquireFenceFd = fence;
|
||||
mList->hwLayers[1].releaseFenceFd = -1;
|
||||
#if ANDROID_VERSION == 18
|
||||
mList->hwLayers[1].planeAlpha = 0xFF;
|
||||
#endif
|
||||
mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
|
||||
int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
|
||||
mFBSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd);
|
||||
|
@ -20,7 +20,7 @@ CPP_SOURCES += [
|
||||
'BootAnimation.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['ANDROID_VERSION'] == '18':
|
||||
if CONFIG['ANDROID_VERSION'] >= '17':
|
||||
CPP_SOURCES += [
|
||||
'FramebufferSurface.cpp',
|
||||
'GraphicBufferAlloc.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user