зеркало из https://github.com/mozilla/gecko-dev.git
Merge f-t to m-c, a=merge
This commit is contained in:
Коммит
a73745d7eb
|
@ -717,6 +717,10 @@ Toolbox.prototype = {
|
||||||
this._buildPickerButton();
|
this._buildPickerButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the visibility of the built in buttons before adding more buttons
|
||||||
|
// so they are shown before calling into the GCLI actor.
|
||||||
|
this.setToolboxButtonsVisibility();
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
environment: CommandUtils.createEnvironment(this, '_target')
|
environment: CommandUtils.createEnvironment(this, '_target')
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,293 @@
|
||||||
|
/* 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 { Task } = require("resource://gre/modules/Task.jsm");
|
||||||
|
const { Promise } = require("resource://gre/modules/Promise.jsm");
|
||||||
|
const {
|
||||||
|
actorCompatibilityBridge, getProfiler,
|
||||||
|
MockMemoryFront, MockTimelineFront,
|
||||||
|
memoryActorSupported, timelineActorSupported
|
||||||
|
} = require("devtools/performance/compatibility");
|
||||||
|
|
||||||
|
loader.lazyRequireGetter(this, "EventEmitter",
|
||||||
|
"devtools/toolkit/event-emitter");
|
||||||
|
loader.lazyRequireGetter(this, "RecordingUtils",
|
||||||
|
"devtools/performance/recording-utils", true);
|
||||||
|
loader.lazyRequireGetter(this, "TimelineFront",
|
||||||
|
"devtools/server/actors/timeline", true);
|
||||||
|
loader.lazyRequireGetter(this, "MemoryFront",
|
||||||
|
"devtools/server/actors/memory", true);
|
||||||
|
loader.lazyRequireGetter(this, "timers",
|
||||||
|
"resource://gre/modules/Timer.jsm");
|
||||||
|
|
||||||
|
// how often do we pull allocation sites from the memory actor
|
||||||
|
const ALLOCATION_SITE_POLL_TIMER = 200; // ms
|
||||||
|
|
||||||
|
const MEMORY_ACTOR_METHODS = [
|
||||||
|
"destroy", "attach", "detach", "getState", "getAllocationsSettings",
|
||||||
|
"getAllocations", "startRecordingAllocations", "stopRecordingAllocations"
|
||||||
|
];
|
||||||
|
|
||||||
|
const TIMELINE_ACTOR_METHODS = [
|
||||||
|
"start", "stop",
|
||||||
|
];
|
||||||
|
|
||||||
|
const PROFILER_ACTOR_METHODS = [
|
||||||
|
"isActive", "startProfiler", "getStartOptions", "stopProfiler",
|
||||||
|
"registerEventNotifications", "unregisterEventNotifications"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a facade around an underlying ProfilerFront.
|
||||||
|
*/
|
||||||
|
function ProfilerFrontFacade (target) {
|
||||||
|
this._target = target;
|
||||||
|
this._onProfilerEvent = this._onProfilerEvent.bind(this);
|
||||||
|
EventEmitter.decorate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfilerFrontFacade.prototype = {
|
||||||
|
EVENTS: ["console-api-profiler", "profiler-stopped"],
|
||||||
|
|
||||||
|
// Connects to the targets underlying real ProfilerFront.
|
||||||
|
connect: Task.async(function*() {
|
||||||
|
let target = this._target;
|
||||||
|
this._actor = yield getProfiler(target);
|
||||||
|
|
||||||
|
// Fetch and store information about the SPS profiler and
|
||||||
|
// server profiler.
|
||||||
|
this.traits = {};
|
||||||
|
this.traits.filterable = target.getTrait("profilerDataFilterable");
|
||||||
|
|
||||||
|
// Directly register to event notifications when connected
|
||||||
|
// to hook into `console.profile|profileEnd` calls.
|
||||||
|
yield this.registerEventNotifications({ events: this.EVENTS });
|
||||||
|
// TODO bug 1159389, listen directly to actor if supporting new front
|
||||||
|
target.client.addListener("eventNotification", this._onProfilerEvent);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters events for the underlying profiler actor.
|
||||||
|
*/
|
||||||
|
destroy: Task.async(function *() {
|
||||||
|
yield this.unregisterEventNotifications({ events: this.EVENTS });
|
||||||
|
// TODO bug 1159389, listen directly to actor if supporting new front
|
||||||
|
this._target.client.removeListener("eventNotification", this._onProfilerEvent);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the profiler actor, if necessary.
|
||||||
|
*/
|
||||||
|
start: Task.async(function *(options={}) {
|
||||||
|
// Start the profiler only if it wasn't already active. The built-in
|
||||||
|
// nsIPerformance module will be kept recording, because it's the same instance
|
||||||
|
// for all targets and interacts with the whole platform, so we don't want
|
||||||
|
// to affect other clients by stopping (or restarting) it.
|
||||||
|
let profilerStatus = yield this.isActive();
|
||||||
|
if (profilerStatus.isActive) {
|
||||||
|
this.emit("profiler-already-active");
|
||||||
|
return profilerStatus.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate options from the recording model into profiler-specific
|
||||||
|
// options for the nsIProfiler
|
||||||
|
let profilerOptions = {
|
||||||
|
entries: options.bufferSize,
|
||||||
|
interval: options.sampleFrequency ? (1000 / (options.sampleFrequency * 1000)) : void 0
|
||||||
|
};
|
||||||
|
|
||||||
|
yield this.startProfiler(profilerOptions);
|
||||||
|
|
||||||
|
this.emit("profiler-activated");
|
||||||
|
return 0;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns profile data from now since `startTime`.
|
||||||
|
*/
|
||||||
|
getProfile: Task.async(function *(options) {
|
||||||
|
let profilerData = yield (actorCompatibilityBridge("getProfile").call(this, options));
|
||||||
|
// If the backend does not support filtering by start and endtime on platform (< Fx40),
|
||||||
|
// do it on the client (much slower).
|
||||||
|
if (!this.traits.filterable) {
|
||||||
|
RecordingUtils.filterSamples(profilerData.profile, options.startTime || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return profilerData;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked whenever a registered event was emitted by the profiler actor.
|
||||||
|
*
|
||||||
|
* @param object response
|
||||||
|
* The data received from the backend.
|
||||||
|
*/
|
||||||
|
_onProfilerEvent: function (_, { topic, subject, details }) {
|
||||||
|
if (topic === "console-api-profiler") {
|
||||||
|
if (subject.action === "profile") {
|
||||||
|
this.emit("console-profile-start", details);
|
||||||
|
} else if (subject.action === "profileEnd") {
|
||||||
|
this.emit("console-profile-end", details);
|
||||||
|
}
|
||||||
|
} else if (topic === "profiler-stopped") {
|
||||||
|
this.emit("profiler-stopped");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: () => "[object ProfilerFrontFacade]"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind all the methods that directly proxy to the actor
|
||||||
|
PROFILER_ACTOR_METHODS.forEach(method => ProfilerFrontFacade.prototype[method] = actorCompatibilityBridge(method));
|
||||||
|
exports.ProfilerFront = ProfilerFrontFacade;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a facade around an underlying TimelineFront.
|
||||||
|
*/
|
||||||
|
function TimelineFrontFacade (target) {
|
||||||
|
this._target = target;
|
||||||
|
EventEmitter.decorate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineFrontFacade.prototype = {
|
||||||
|
EVENTS: ["markers", "frames", "memory", "ticks"],
|
||||||
|
|
||||||
|
connect: Task.async(function*() {
|
||||||
|
let supported = yield timelineActorSupported(this._target);
|
||||||
|
this._actor = supported ?
|
||||||
|
new TimelineFront(this._target.client, this._target.form) :
|
||||||
|
new MockTimelineFront();
|
||||||
|
|
||||||
|
this.IS_MOCK = !supported;
|
||||||
|
|
||||||
|
// Binds underlying actor events and consolidates them to a `timeline-data`
|
||||||
|
// exposed event.
|
||||||
|
this.EVENTS.forEach(type => {
|
||||||
|
let handler = this[`_on${type}`] = this._onTimelineData.bind(this, type);
|
||||||
|
this._actor.on(type, handler);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override actor's destroy, so we can unregister listeners before
|
||||||
|
* destroying the underlying actor.
|
||||||
|
*/
|
||||||
|
destroy: Task.async(function *() {
|
||||||
|
this.EVENTS.forEach(type => this._actor.off(type, this[`_on${type}`]));
|
||||||
|
yield this._actor.destroy();
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An aggregate of all events (markers, frames, memory, ticks) and exposes
|
||||||
|
* to PerformanceActorsConnection as a single event.
|
||||||
|
*/
|
||||||
|
_onTimelineData: function (type, ...data) {
|
||||||
|
this.emit("timeline-data", type, ...data);
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: () => "[object TimelineFrontFacade]"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind all the methods that directly proxy to the actor
|
||||||
|
TIMELINE_ACTOR_METHODS.forEach(method => TimelineFrontFacade.prototype[method] = actorCompatibilityBridge(method));
|
||||||
|
exports.TimelineFront = TimelineFrontFacade;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a facade around an underlying ProfilerFront.
|
||||||
|
*/
|
||||||
|
function MemoryFrontFacade (target) {
|
||||||
|
this._target = target;
|
||||||
|
this._pullAllocationSites = this._pullAllocationSites.bind(this);
|
||||||
|
EventEmitter.decorate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryFrontFacade.prototype = {
|
||||||
|
connect: Task.async(function*() {
|
||||||
|
let supported = yield memoryActorSupported(this._target);
|
||||||
|
this._actor = supported ?
|
||||||
|
new MemoryFront(this._target.client, this._target.form) :
|
||||||
|
new MockMemoryFront();
|
||||||
|
|
||||||
|
this.IS_MOCK = !supported;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts polling for allocation information.
|
||||||
|
*/
|
||||||
|
start: Task.async(function *(options) {
|
||||||
|
if (!options.withAllocations) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield this.attach();
|
||||||
|
|
||||||
|
let startTime = yield this.startRecordingAllocations({
|
||||||
|
probability: options.allocationsSampleProbability,
|
||||||
|
maxLogLength: options.allocationsMaxLogLength
|
||||||
|
});
|
||||||
|
|
||||||
|
yield this._pullAllocationSites();
|
||||||
|
|
||||||
|
return startTime;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops polling for allocation information.
|
||||||
|
*/
|
||||||
|
stop: Task.async(function *(options) {
|
||||||
|
if (!options.withAllocations) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since `_pullAllocationSites` is usually running inside a timeout, and
|
||||||
|
// it's performing asynchronous requests to the server, a recording may
|
||||||
|
// be stopped before that method finishes executing. Therefore, we need to
|
||||||
|
// wait for the last request to `getAllocations` to finish before actually
|
||||||
|
// stopping recording allocations.
|
||||||
|
yield this._lastPullAllocationSitesFinished;
|
||||||
|
timers.clearTimeout(this._sitesPullTimeout);
|
||||||
|
|
||||||
|
let endTime = yield this.stopRecordingAllocations();
|
||||||
|
yield this.detach();
|
||||||
|
|
||||||
|
return endTime;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* At regular intervals, pull allocations from the memory actor, and
|
||||||
|
* forward them on this Front facade as "timeline-data" events. This
|
||||||
|
* gives the illusion that the MemoryActor supports an EventEmitter-style
|
||||||
|
* event stream.
|
||||||
|
*/
|
||||||
|
_pullAllocationSites: Task.async(function *() {
|
||||||
|
let { promise, resolve } = Promise.defer();
|
||||||
|
this._lastPullAllocationSitesFinished = promise;
|
||||||
|
|
||||||
|
if ((yield this.getState()) !== "attached") {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let memoryData = yield this.getAllocations();
|
||||||
|
// Match the signature of the TimelineFront events, with "timeline-data"
|
||||||
|
// being the event name, and the second argument describing the type.
|
||||||
|
this.emit("timeline-data", "allocations", {
|
||||||
|
sites: memoryData.allocations,
|
||||||
|
timestamps: memoryData.allocationsTimestamps,
|
||||||
|
frames: memoryData.frames,
|
||||||
|
counts: memoryData.counts
|
||||||
|
});
|
||||||
|
|
||||||
|
this._sitesPullTimeout = timers.setTimeout(this._pullAllocationSites, ALLOCATION_SITE_POLL_TIMER);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}),
|
||||||
|
|
||||||
|
toString: () => "[object MemoryFrontFacade]"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind all the methods that directly proxy to the actor
|
||||||
|
MEMORY_ACTOR_METHODS.forEach(method => MemoryFrontFacade.prototype[method] = actorCompatibilityBridge(method));
|
||||||
|
exports.MemoryFront = MemoryFrontFacade;
|
|
@ -4,72 +4,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Task } = require("resource://gre/modules/Task.jsm");
|
const { Task } = require("resource://gre/modules/Task.jsm");
|
||||||
loader.lazyRequireGetter(this, "promise");
|
const { Promise } = require("resource://gre/modules/Promise.jsm");
|
||||||
loader.lazyRequireGetter(this, "EventEmitter",
|
loader.lazyRequireGetter(this, "EventEmitter",
|
||||||
"devtools/toolkit/event-emitter");
|
"devtools/toolkit/event-emitter");
|
||||||
loader.lazyRequireGetter(this, "RecordingUtils",
|
|
||||||
"devtools/performance/recording-utils", true);
|
|
||||||
|
|
||||||
const REQUIRED_MEMORY_ACTOR_METHODS = [
|
|
||||||
"attach", "detach", "startRecordingAllocations", "stopRecordingAllocations", "getAllocations"
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a facade around an underlying ProfilerFront.
|
|
||||||
*/
|
|
||||||
function ProfilerFront (target) {
|
|
||||||
this._target = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfilerFront.prototype = {
|
|
||||||
// Connects to the targets underlying real ProfilerFront.
|
|
||||||
connect: Task.async(function*() {
|
|
||||||
let target = this._target;
|
|
||||||
// Chrome and content process targets already have obtained a reference
|
|
||||||
// to the profiler tab actor. Use it immediately.
|
|
||||||
if (target.form && target.form.profilerActor) {
|
|
||||||
this._profiler = target.form.profilerActor;
|
|
||||||
}
|
|
||||||
// Check if we already have a grip to the `listTabs` response object
|
|
||||||
// and, if we do, use it to get to the profiler actor.
|
|
||||||
else if (target.root && target.root.profilerActor) {
|
|
||||||
this._profiler = target.root.profilerActor;
|
|
||||||
}
|
|
||||||
// Otherwise, call `listTabs`.
|
|
||||||
else {
|
|
||||||
this._profiler = (yield listTabs(target.client)).profilerActor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch and store information about the SPS profiler and
|
|
||||||
// server profiler.
|
|
||||||
this.traits = {};
|
|
||||||
this.traits.filterable = target.getTrait("profilerDataFilterable");
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes a request to the underlying real profiler actor. Handles
|
|
||||||
* backwards compatibility differences based off of the features
|
|
||||||
* and traits of the actor.
|
|
||||||
*/
|
|
||||||
_request: function (method, ...args) {
|
|
||||||
let deferred = promise.defer();
|
|
||||||
let data = args[0] || {};
|
|
||||||
data.to = this._profiler;
|
|
||||||
data.type = method;
|
|
||||||
this._target.client.request(data, res => {
|
|
||||||
// If the backend does not support filtering by start and endtime on platform (< Fx40),
|
|
||||||
// do it on the client (much slower).
|
|
||||||
if (method === "getProfile" && !this.traits.filterable) {
|
|
||||||
RecordingUtils.filterSamples(res.profile, data.startTime || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
deferred.resolve(res);
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.ProfilerFront = ProfilerFront;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dummy front decorated with the provided methods.
|
* A dummy front decorated with the provided methods.
|
||||||
|
@ -87,7 +24,8 @@ function MockFront (blueprint) {
|
||||||
|
|
||||||
function MockMemoryFront () {
|
function MockMemoryFront () {
|
||||||
MockFront.call(this, [
|
MockFront.call(this, [
|
||||||
["initialize"],
|
["start", 0], // for facade
|
||||||
|
["stop", 0], // for facade
|
||||||
["destroy"],
|
["destroy"],
|
||||||
["attach"],
|
["attach"],
|
||||||
["detach"],
|
["detach"],
|
||||||
|
@ -101,7 +39,6 @@ exports.MockMemoryFront = MockMemoryFront;
|
||||||
|
|
||||||
function MockTimelineFront () {
|
function MockTimelineFront () {
|
||||||
MockFront.call(this, [
|
MockFront.call(this, [
|
||||||
["initialize"],
|
|
||||||
["destroy"],
|
["destroy"],
|
||||||
["start", 0],
|
["start", 0],
|
||||||
["stop", 0],
|
["stop", 0],
|
||||||
|
@ -169,12 +106,66 @@ function timelineActorSupported(target) {
|
||||||
exports.timelineActorSupported = Task.async(timelineActorSupported);
|
exports.timelineActorSupported = Task.async(timelineActorSupported);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise resolved with a listing of all the tabs in the
|
* Returns a promise resolving to the location of the profiler actor
|
||||||
* provided thread client.
|
* within this context.
|
||||||
|
*
|
||||||
|
* @param {TabTarget} target
|
||||||
|
* @return {Promise<ProfilerActor>}
|
||||||
*/
|
*/
|
||||||
function listTabs(client) {
|
function getProfiler (target) {
|
||||||
let deferred = promise.defer();
|
let { promise, resolve } = Promise.defer();
|
||||||
client.listTabs(deferred.resolve);
|
// Chrome and content process targets already have obtained a reference
|
||||||
return deferred.promise;
|
// to the profiler tab actor. Use it immediately.
|
||||||
|
if (target.form && target.form.profilerActor) {
|
||||||
|
resolve(target.form.profilerActor);
|
||||||
|
}
|
||||||
|
// Check if we already have a grip to the `listTabs` response object
|
||||||
|
// and, if we do, use it to get to the profiler actor.
|
||||||
|
else if (target.root && target.root.profilerActor) {
|
||||||
|
resolve(target.root.profilerActor);
|
||||||
|
}
|
||||||
|
// Otherwise, call `listTabs`.
|
||||||
|
else {
|
||||||
|
target.client.listTabs(({ profilerActor }) => resolve(profilerActor));
|
||||||
|
}
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
exports.getProfiler = Task.async(getProfiler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a request to an actor that does not have the modern `Front`
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
function legacyRequest (target, actor, method, args) {
|
||||||
|
let { promise, resolve } = Promise.defer();
|
||||||
|
let data = args[0] || {};
|
||||||
|
data.to = actor;
|
||||||
|
data.type = method;
|
||||||
|
target.client.request(data, resolve);
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a function to be used as a method on an "Actor" in ./actors.
|
||||||
|
* Calls the underlying actor's method, supporting the modern `Front`
|
||||||
|
* interface if possible, otherwise, falling back to using
|
||||||
|
* `legacyRequest`.
|
||||||
|
*/
|
||||||
|
function actorCompatibilityBridge (method) {
|
||||||
|
return function () {
|
||||||
|
// Check to see if this is a modern ActorFront, which has its
|
||||||
|
// own `request` method. Also, check if its a mock actor, as it mimicks
|
||||||
|
// the ActorFront interface.
|
||||||
|
// The profiler actor does not currently support the modern `Front`
|
||||||
|
// interface, so we have to manually push packets to it.
|
||||||
|
// TODO bug 1159389, fix up profiler actor to not need this, however
|
||||||
|
// we will need it for backwards compat
|
||||||
|
if (this.IS_MOCK || this._actor.request) {
|
||||||
|
return this._actor[method].apply(this._actor, arguments);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return legacyRequest(this._target, this._actor, method, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
exports.actorCompatibilityBridge = actorCompatibilityBridge;
|
||||||
|
|
|
@ -9,24 +9,15 @@ const { extend } = require("sdk/util/object");
|
||||||
const { RecordingModel } = require("devtools/performance/recording-model");
|
const { RecordingModel } = require("devtools/performance/recording-model");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "Services");
|
loader.lazyRequireGetter(this, "Services");
|
||||||
loader.lazyRequireGetter(this, "promise");
|
|
||||||
loader.lazyRequireGetter(this, "EventEmitter",
|
loader.lazyRequireGetter(this, "EventEmitter",
|
||||||
"devtools/toolkit/event-emitter");
|
"devtools/toolkit/event-emitter");
|
||||||
loader.lazyRequireGetter(this, "TimelineFront",
|
|
||||||
"devtools/server/actors/timeline", true);
|
|
||||||
loader.lazyRequireGetter(this, "MemoryFront",
|
|
||||||
"devtools/server/actors/memory", true);
|
|
||||||
loader.lazyRequireGetter(this, "DevToolsUtils",
|
loader.lazyRequireGetter(this, "DevToolsUtils",
|
||||||
"devtools/toolkit/DevToolsUtils");
|
"devtools/toolkit/DevToolsUtils");
|
||||||
loader.lazyRequireGetter(this, "compatibility",
|
loader.lazyRequireGetter(this, "actors",
|
||||||
"devtools/performance/compatibility");
|
"devtools/performance/actors");
|
||||||
|
|
||||||
loader.lazyImporter(this, "gDevTools",
|
loader.lazyImporter(this, "gDevTools",
|
||||||
"resource:///modules/devtools/gDevTools.jsm");
|
"resource:///modules/devtools/gDevTools.jsm");
|
||||||
loader.lazyImporter(this, "setTimeout",
|
|
||||||
"resource://gre/modules/Timer.jsm");
|
|
||||||
loader.lazyImporter(this, "clearTimeout",
|
|
||||||
"resource://gre/modules/Timer.jsm");
|
|
||||||
loader.lazyImporter(this, "Promise",
|
loader.lazyImporter(this, "Promise",
|
||||||
"resource://gre/modules/Promise.jsm");
|
"resource://gre/modules/Promise.jsm");
|
||||||
|
|
||||||
|
@ -41,9 +32,6 @@ const CONNECTION_PIPE_EVENTS = [
|
||||||
"recording-started", "recording-stopped"
|
"recording-started", "recording-stopped"
|
||||||
];
|
];
|
||||||
|
|
||||||
// Events to listen to from the profiler actor
|
|
||||||
const PROFILER_EVENTS = ["console-api-profiler", "profiler-stopped"];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache of all PerformanceActorsConnection instances.
|
* A cache of all PerformanceActorsConnection instances.
|
||||||
* The keys are Target objects.
|
* The keys are Target objects.
|
||||||
|
@ -84,17 +72,15 @@ function PerformanceActorsConnection(target) {
|
||||||
|
|
||||||
this._target = target;
|
this._target = target;
|
||||||
this._client = this._target.client;
|
this._client = this._target.client;
|
||||||
this._request = this._request.bind(this);
|
|
||||||
this._pendingConsoleRecordings = [];
|
this._pendingConsoleRecordings = [];
|
||||||
this._sitesPullTimeout = 0;
|
this._sitesPullTimeout = 0;
|
||||||
this._recordings = [];
|
this._recordings = [];
|
||||||
|
|
||||||
this._onTimelineMarkers = this._onTimelineMarkers.bind(this);
|
this._pipeToConnection = this._pipeToConnection.bind(this);
|
||||||
this._onTimelineFrames = this._onTimelineFrames.bind(this);
|
this._onTimelineData = this._onTimelineData.bind(this);
|
||||||
this._onTimelineMemory = this._onTimelineMemory.bind(this);
|
this._onConsoleProfileStart = this._onConsoleProfileStart.bind(this);
|
||||||
this._onTimelineTicks = this._onTimelineTicks.bind(this);
|
this._onConsoleProfileEnd = this._onConsoleProfileEnd.bind(this);
|
||||||
this._onProfilerEvent = this._onProfilerEvent.bind(this);
|
this._onProfilerUnexpectedlyStopped = this._onProfilerUnexpectedlyStopped.bind(this);
|
||||||
this._pullAllocationSites = this._pullAllocationSites.bind(this);
|
|
||||||
|
|
||||||
Services.obs.notifyObservers(null, "performance-actors-connection-created", null);
|
Services.obs.notifyObservers(null, "performance-actors-connection-created", null);
|
||||||
}
|
}
|
||||||
|
@ -128,10 +114,7 @@ PerformanceActorsConnection.prototype = {
|
||||||
// Only initialize the timeline and memory fronts if the respective actors
|
// Only initialize the timeline and memory fronts if the respective actors
|
||||||
// are available. Older Gecko versions don't have existing implementations,
|
// are available. Older Gecko versions don't have existing implementations,
|
||||||
// in which case all the methods we need can be easily mocked.
|
// in which case all the methods we need can be easily mocked.
|
||||||
yield this._connectProfilerActor();
|
yield this._connectActors();
|
||||||
yield this._connectTimelineActor();
|
|
||||||
yield this._connectMemoryActor();
|
|
||||||
|
|
||||||
yield this._registerListeners();
|
yield this._registerListeners();
|
||||||
|
|
||||||
this._connected = true;
|
this._connected = true;
|
||||||
|
@ -159,132 +142,64 @@ PerformanceActorsConnection.prototype = {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a connection to the profiler actor. Uses a facade around the ProfilerFront
|
* Initializes fronts and connects to the underlying actors using the facades
|
||||||
* for similarity to the other actors in the shared connection.
|
* found in ./actors.js.
|
||||||
*/
|
*/
|
||||||
_connectProfilerActor: Task.async(function*() {
|
_connectActors: Task.async(function*() {
|
||||||
this._profiler = new compatibility.ProfilerFront(this._target);
|
this._profiler = new actors.ProfilerFront(this._target);
|
||||||
yield this._profiler.connect();
|
this._memory = new actors.MemoryFront(this._target);
|
||||||
}),
|
this._timeline = new actors.TimelineFront(this._target);
|
||||||
|
|
||||||
/**
|
yield Promise.all([
|
||||||
* Initializes a connection to a timeline actor.
|
this._profiler.connect(),
|
||||||
*/
|
this._memory.connect(),
|
||||||
_connectTimelineActor: function() {
|
this._timeline.connect()
|
||||||
let supported = yield compatibility.timelineActorSupported(this._target);
|
]);
|
||||||
if (supported) {
|
|
||||||
this._timeline = new TimelineFront(this._target.client, this._target.form);
|
|
||||||
} else {
|
|
||||||
this._timeline = new compatibility.MockTimelineFront();
|
|
||||||
}
|
|
||||||
this._timelineSupported = supported;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
// Expose server support status of underlying actors
|
||||||
* Initializes a connection to a memory actor.
|
// after connecting.
|
||||||
*/
|
this._memorySupported = !this._memory.IS_MOCK;
|
||||||
_connectMemoryActor: Task.async(function* () {
|
this._timelineSupported = !this._timeline.IS_MOCK;
|
||||||
let supported = yield compatibility.memoryActorSupported(this._target);
|
|
||||||
if (supported) {
|
|
||||||
this._memory = new MemoryFront(this._target.client, this._target.form);
|
|
||||||
} else {
|
|
||||||
this._memory = new compatibility.MockMemoryFront();
|
|
||||||
}
|
|
||||||
this._memorySupported = supported;
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers listeners on events from the underlying
|
* Registers listeners on events from the underlying
|
||||||
* actors, so the connection can handle them.
|
* actors, so the connection can handle them.
|
||||||
*/
|
*/
|
||||||
_registerListeners: Task.async(function*() {
|
_registerListeners: function () {
|
||||||
// Pipe events from TimelineActor to the PerformanceFront
|
this._timeline.on("timeline-data", this._onTimelineData);
|
||||||
this._timeline.on("markers", this._onTimelineMarkers);
|
this._memory.on("timeline-data", this._onTimelineData);
|
||||||
this._timeline.on("frames", this._onTimelineFrames);
|
this._profiler.on("console-profile-start", this._onConsoleProfileStart);
|
||||||
this._timeline.on("memory", this._onTimelineMemory);
|
this._profiler.on("console-profile-end", this._onConsoleProfileEnd);
|
||||||
this._timeline.on("ticks", this._onTimelineTicks);
|
this._profiler.on("profiler-stopped", this._onProfilerUnexpectedlyStopped);
|
||||||
|
this._profiler.on("profiler-already-active", this._pipeToConnection);
|
||||||
// Register events on the profiler actor to hook into `console.profile*` calls.
|
this._profiler.on("profiler-activated", this._pipeToConnection);
|
||||||
yield this._request("profiler", "registerEventNotifications", { events: PROFILER_EVENTS });
|
},
|
||||||
this._client.addListener("eventNotification", this._onProfilerEvent);
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregisters listeners on events on the underlying actors.
|
* Unregisters listeners on events on the underlying actors.
|
||||||
*/
|
*/
|
||||||
_unregisterListeners: Task.async(function*() {
|
_unregisterListeners: function () {
|
||||||
this._timeline.off("markers", this._onTimelineMarkers);
|
this._timeline.off("timeline-data", this._onTimelineData);
|
||||||
this._timeline.off("frames", this._onTimelineFrames);
|
this._memory.off("timeline-data", this._onTimelineData);
|
||||||
this._timeline.off("memory", this._onTimelineMemory);
|
this._profiler.off("console-profile-start", this._onConsoleProfileStart);
|
||||||
this._timeline.off("ticks", this._onTimelineTicks);
|
this._profiler.off("console-profile-end", this._onConsoleProfileEnd);
|
||||||
|
this._profiler.off("profiler-stopped", this._onProfilerUnexpectedlyStopped);
|
||||||
yield this._request("profiler", "unregisterEventNotifications", { events: PROFILER_EVENTS });
|
this._profiler.off("profiler-already-active", this._pipeToConnection);
|
||||||
this._client.removeListener("eventNotification", this._onProfilerEvent);
|
this._profiler.off("profiler-activated", this._pipeToConnection);
|
||||||
}),
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the connections to non-profiler actors.
|
* Closes the connections to non-profiler actors.
|
||||||
*/
|
*/
|
||||||
_disconnectActors: Task.async(function* () {
|
_disconnectActors: Task.async(function* () {
|
||||||
yield this._timeline.destroy();
|
yield Promise.all([
|
||||||
yield this._memory.destroy();
|
this._profiler.destroy(),
|
||||||
|
this._timeline.destroy(),
|
||||||
|
this._memory.destroy()
|
||||||
|
]);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the request over the remote debugging protocol to the
|
|
||||||
* specified actor.
|
|
||||||
*
|
|
||||||
* @param string actor
|
|
||||||
* Currently supported: "profiler", "timeline", "memory".
|
|
||||||
* @param string method
|
|
||||||
* Method to call on the backend.
|
|
||||||
* @param any args [optional]
|
|
||||||
* Additional data or arguments to send with the request.
|
|
||||||
* @return object
|
|
||||||
* A promise resolved with the response once the request finishes.
|
|
||||||
*/
|
|
||||||
_request: function(actor, method, ...args) {
|
|
||||||
// Handle requests to the profiler actor.
|
|
||||||
if (actor == "profiler") {
|
|
||||||
return this._profiler._request(method, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle requests to the timeline actor.
|
|
||||||
if (actor == "timeline") {
|
|
||||||
return this._timeline[method].apply(this._timeline, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle requests to the memory actor.
|
|
||||||
if (actor == "memory") {
|
|
||||||
return this._memory[method].apply(this._memory, args);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked whenever a registered event was emitted by the profiler actor.
|
|
||||||
*
|
|
||||||
* @param object response
|
|
||||||
* The data received from the backend.
|
|
||||||
*/
|
|
||||||
_onProfilerEvent: function (_, { topic, subject, details }) {
|
|
||||||
if (topic === "console-api-profiler") {
|
|
||||||
if (subject.action === "profile") {
|
|
||||||
this._onConsoleProfileStart(details);
|
|
||||||
} else if (subject.action === "profileEnd") {
|
|
||||||
this._onConsoleProfileEnd(details);
|
|
||||||
}
|
|
||||||
} else if (topic === "profiler-stopped") {
|
|
||||||
this._onProfilerUnexpectedlyStopped();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO handle bug 1144438
|
|
||||||
*/
|
|
||||||
_onProfilerUnexpectedlyStopped: function () {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked whenever `console.profile` is called.
|
* Invoked whenever `console.profile` is called.
|
||||||
*
|
*
|
||||||
|
@ -294,7 +209,7 @@ PerformanceActorsConnection.prototype = {
|
||||||
* The time (in milliseconds) when the call was made, relative to when
|
* The time (in milliseconds) when the call was made, relative to when
|
||||||
* the nsIProfiler module was started.
|
* the nsIProfiler module was started.
|
||||||
*/
|
*/
|
||||||
_onConsoleProfileStart: Task.async(function *({ profileLabel, currentTime: startTime }) {
|
_onConsoleProfileStart: Task.async(function *(_, { profileLabel, currentTime: startTime }) {
|
||||||
let recordings = this._recordings;
|
let recordings = this._recordings;
|
||||||
|
|
||||||
// Abort if a profile with this label already exists.
|
// Abort if a profile with this label already exists.
|
||||||
|
@ -325,7 +240,7 @@ PerformanceActorsConnection.prototype = {
|
||||||
* The time (in milliseconds) when the call was made, relative to when
|
* The time (in milliseconds) when the call was made, relative to when
|
||||||
* the nsIProfiler module was started.
|
* the nsIProfiler module was started.
|
||||||
*/
|
*/
|
||||||
_onConsoleProfileEnd: Task.async(function *(data) {
|
_onConsoleProfileEnd: Task.async(function *(_, data) {
|
||||||
// If no data, abort; can occur if profiler isn't running and we get a surprise
|
// If no data, abort; can occur if profiler isn't running and we get a surprise
|
||||||
// call to console.profileEnd()
|
// call to console.profileEnd()
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -361,14 +276,12 @@ PerformanceActorsConnection.prototype = {
|
||||||
this.emit("console-profile-end", model);
|
this.emit("console-profile-end", model);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handlers for TimelineActor events. All pipe to `_onTimelineData`
|
* TODO handle bug 1144438
|
||||||
* with the appropriate event name.
|
*/
|
||||||
*/
|
_onProfilerUnexpectedlyStopped: function () {
|
||||||
_onTimelineMarkers: function (markers) { this._onTimelineData("markers", markers); },
|
Cu.reportError("Profiler unexpectedly stopped.", arguments);
|
||||||
_onTimelineFrames: function (delta, frames) { this._onTimelineData("frames", delta, frames); },
|
},
|
||||||
_onTimelineMemory: function (delta, measurement) { this._onTimelineData("memory", delta, measurement); },
|
|
||||||
_onTimelineTicks: function (delta, timestamps) { this._onTimelineData("ticks", delta, timestamps); },
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever there is timeline data of any of the following types:
|
* Called whenever there is timeline data of any of the following types:
|
||||||
|
@ -380,8 +293,7 @@ PerformanceActorsConnection.prototype = {
|
||||||
*
|
*
|
||||||
* Populate our internal store of recordings for all currently recording sessions.
|
* Populate our internal store of recordings for all currently recording sessions.
|
||||||
*/
|
*/
|
||||||
|
_onTimelineData: function (_, ...data) {
|
||||||
_onTimelineData: function (...data) {
|
|
||||||
this._recordings.forEach(e => e.addTimelineData.apply(e, data));
|
this._recordings.forEach(e => e.addTimelineData.apply(e, data));
|
||||||
this.emit("timeline-data", ...data);
|
this.emit("timeline-data", ...data);
|
||||||
},
|
},
|
||||||
|
@ -399,15 +311,13 @@ PerformanceActorsConnection.prototype = {
|
||||||
let model = new RecordingModel(options);
|
let model = new RecordingModel(options);
|
||||||
// All actors are started asynchronously over the remote debugging protocol.
|
// All actors are started asynchronously over the remote debugging protocol.
|
||||||
// Get the corresponding start times from each one of them.
|
// Get the corresponding start times from each one of them.
|
||||||
let profilerStartTime = yield this._startProfiler(options);
|
// The timeline and memory actors are target-dependent, so start those as well,
|
||||||
let timelineStartTime = yield this._startTimeline(options);
|
// even though these are mocked in older Geckos (FF < 35)
|
||||||
let memoryStartTime = yield this._startMemory(options);
|
let profilerStartTime = yield this._profiler.start(options);
|
||||||
|
let timelineStartTime = yield this._timeline.start(options);
|
||||||
|
let memoryStartTime = yield this._memory.start(options);
|
||||||
|
|
||||||
let data = {
|
let data = { profilerStartTime, timelineStartTime, memoryStartTime };
|
||||||
profilerStartTime,
|
|
||||||
timelineStartTime,
|
|
||||||
memoryStartTime
|
|
||||||
};
|
|
||||||
|
|
||||||
// Signify to the model that the recording has started,
|
// Signify to the model that the recording has started,
|
||||||
// populate with data and store the recording model here.
|
// populate with data and store the recording model here.
|
||||||
|
@ -445,7 +355,7 @@ PerformanceActorsConnection.prototype = {
|
||||||
|
|
||||||
let config = model.getConfiguration();
|
let config = model.getConfiguration();
|
||||||
let startTime = model.getProfilerStartTime();
|
let startTime = model.getProfilerStartTime();
|
||||||
let profilerData = yield this._request("profiler", "getProfile", { startTime });
|
let profilerData = yield this._profiler.getProfile({ startTime });
|
||||||
let memoryEndTime = Date.now();
|
let memoryEndTime = Date.now();
|
||||||
let timelineEndTime = Date.now();
|
let timelineEndTime = Date.now();
|
||||||
|
|
||||||
|
@ -454,8 +364,8 @@ PerformanceActorsConnection.prototype = {
|
||||||
// juse use Date.now() for the memory and timeline end times, as those
|
// juse use Date.now() for the memory and timeline end times, as those
|
||||||
// are only used in tests.
|
// are only used in tests.
|
||||||
if (!this.isRecording()) {
|
if (!this.isRecording()) {
|
||||||
memoryEndTime = yield this._stopMemory(config);
|
memoryEndTime = yield this._memory.stop(config);
|
||||||
timelineEndTime = yield this._stopTimeline(config);
|
timelineEndTime = yield this._timeline.stop(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the results on the RecordingModel itself.
|
// Set the results on the RecordingModel itself.
|
||||||
|
@ -484,127 +394,12 @@ PerformanceActorsConnection.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the profiler actor, if necessary.
|
* An event from an underlying actor that we just want
|
||||||
|
* to pipe to the connection itself.
|
||||||
*/
|
*/
|
||||||
_startProfiler: Task.async(function *(options={}) {
|
_pipeToConnection: function (eventName, ...args) {
|
||||||
// Start the profiler only if it wasn't already active. The built-in
|
this.emit(eventName, ...args);
|
||||||
// nsIPerformance module will be kept recording, because it's the same instance
|
},
|
||||||
// for all targets and interacts with the whole platform, so we don't want
|
|
||||||
// to affect other clients by stopping (or restarting) it.
|
|
||||||
let profilerStatus = yield this._request("profiler", "isActive");
|
|
||||||
if (profilerStatus.isActive) {
|
|
||||||
this.emit("profiler-already-active");
|
|
||||||
return profilerStatus.currentTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate options from the recording model into profiler-specific
|
|
||||||
// options for the nsIProfiler
|
|
||||||
let profilerOptions = {
|
|
||||||
entries: options.bufferSize,
|
|
||||||
interval: options.sampleFrequency ? (1000 / (options.sampleFrequency * 1000)) : void 0
|
|
||||||
};
|
|
||||||
|
|
||||||
yield this._request("profiler", "startProfiler", profilerOptions);
|
|
||||||
|
|
||||||
this.emit("profiler-activated");
|
|
||||||
return 0;
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the timeline actor.
|
|
||||||
*/
|
|
||||||
_startTimeline: Task.async(function *(options) {
|
|
||||||
// The timeline actor is target-dependent, so just make sure it's recording.
|
|
||||||
// It won't, however, be available in older Geckos (FF < 35).
|
|
||||||
return (yield this._request("timeline", "start", options));
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the timeline actor.
|
|
||||||
*/
|
|
||||||
_stopTimeline: Task.async(function *(options) {
|
|
||||||
return (yield this._request("timeline", "stop"));
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts polling for allocations from the memory actor, if necessary.
|
|
||||||
*/
|
|
||||||
_startMemory: Task.async(function *(options) {
|
|
||||||
if (!options.withAllocations) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let memoryStartTime = yield this._startRecordingAllocations(options);
|
|
||||||
yield this._pullAllocationSites();
|
|
||||||
return memoryStartTime;
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops polling for allocations from the memory actor, if necessary.
|
|
||||||
*/
|
|
||||||
_stopMemory: Task.async(function *(options) {
|
|
||||||
if (!options.withAllocations) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// Since `_pullAllocationSites` is usually running inside a timeout, and
|
|
||||||
// it's performing asynchronous requests to the server, a recording may
|
|
||||||
// be stopped before that method finishes executing. Therefore, we need to
|
|
||||||
// wait for the last request to `getAllocations` to finish before actually
|
|
||||||
// stopping recording allocations.
|
|
||||||
yield this._lastPullAllocationSitesFinished;
|
|
||||||
clearTimeout(this._sitesPullTimeout);
|
|
||||||
|
|
||||||
return yield this._stopRecordingAllocations();
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts recording allocations in the memory actor.
|
|
||||||
*/
|
|
||||||
_startRecordingAllocations: Task.async(function*(options) {
|
|
||||||
yield this._request("memory", "attach");
|
|
||||||
let memoryStartTime = yield this._request("memory", "startRecordingAllocations", {
|
|
||||||
probability: options.allocationsSampleProbability,
|
|
||||||
maxLogLength: options.allocationsMaxLogLength
|
|
||||||
});
|
|
||||||
return memoryStartTime;
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops recording allocations in the memory actor.
|
|
||||||
*/
|
|
||||||
_stopRecordingAllocations: Task.async(function*() {
|
|
||||||
let memoryEndTime = yield this._request("memory", "stopRecordingAllocations");
|
|
||||||
yield this._request("memory", "detach");
|
|
||||||
return memoryEndTime;
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* At regular intervals, pull allocations from the memory actor, and forward
|
|
||||||
* them to consumers.
|
|
||||||
*/
|
|
||||||
_pullAllocationSites: Task.async(function *() {
|
|
||||||
let deferred = promise.defer();
|
|
||||||
this._lastPullAllocationSitesFinished = deferred.promise;
|
|
||||||
|
|
||||||
let isDetached = (yield this._request("memory", "getState")) !== "attached";
|
|
||||||
if (isDetached) {
|
|
||||||
deferred.resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let memoryData = yield this._request("memory", "getAllocations");
|
|
||||||
|
|
||||||
this._onTimelineData("allocations", {
|
|
||||||
sites: memoryData.allocations,
|
|
||||||
timestamps: memoryData.allocationsTimestamps,
|
|
||||||
frames: memoryData.frames,
|
|
||||||
counts: memoryData.counts
|
|
||||||
});
|
|
||||||
|
|
||||||
let delay = DEFAULT_ALLOCATION_SITES_PULL_TIMEOUT;
|
|
||||||
this._sitesPullTimeout = setTimeout(this._pullAllocationSites, delay);
|
|
||||||
|
|
||||||
deferred.resolve();
|
|
||||||
}),
|
|
||||||
|
|
||||||
toString: () => "[object PerformanceActorsConnection]"
|
toString: () => "[object PerformanceActorsConnection]"
|
||||||
};
|
};
|
||||||
|
@ -620,7 +415,6 @@ function PerformanceFront(connection) {
|
||||||
EventEmitter.decorate(this);
|
EventEmitter.decorate(this);
|
||||||
|
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._request = connection._request;
|
|
||||||
|
|
||||||
// Set when mocks are being used
|
// Set when mocks are being used
|
||||||
this._memorySupported = connection._memorySupported;
|
this._memorySupported = connection._memorySupported;
|
||||||
|
@ -680,6 +474,17 @@ PerformanceFront.prototype = {
|
||||||
*/
|
*/
|
||||||
isRecording: function () {
|
isRecording: function () {
|
||||||
return this._connection.isRecording();
|
return this._connection.isRecording();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interacts with the connection's actors. Should only be used in tests.
|
||||||
|
*/
|
||||||
|
_request: function (actorName, method, ...args) {
|
||||||
|
if (!gDevTools.testing) {
|
||||||
|
throw new Error("PerformanceFront._request may only be used in tests.");
|
||||||
|
}
|
||||||
|
let actor = this._connection[`_${actorName}`];
|
||||||
|
return actor[method].apply(actor, args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
EXTRA_JS_MODULES.devtools.performance += [
|
EXTRA_JS_MODULES.devtools.performance += [
|
||||||
|
'modules/actors.js',
|
||||||
'modules/compatibility.js',
|
'modules/compatibility.js',
|
||||||
'modules/front.js',
|
'modules/front.js',
|
||||||
'modules/graphs.js',
|
'modules/graphs.js',
|
||||||
|
|
|
@ -18,7 +18,7 @@ function spawnTest () {
|
||||||
|
|
||||||
ok(sharedConnection,
|
ok(sharedConnection,
|
||||||
"A shared profiler connection for the current toolbox was retrieved.");
|
"A shared profiler connection for the current toolbox was retrieved.");
|
||||||
is(sharedConnection._request, panel.panelWin.gFront._request,
|
is(panel.panelWin.gFront._connection, sharedConnection,
|
||||||
"The same shared profiler connection is used by the panel's front.");
|
"The same shared profiler connection is used by the panel's front.");
|
||||||
|
|
||||||
yield sharedConnection.open();
|
yield sharedConnection.open();
|
||||||
|
|
|
@ -124,7 +124,9 @@ endef
|
||||||
$(foreach subtier,$(filter-out compile,$(TIERS)),$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
|
$(foreach subtier,$(filter-out compile,$(TIERS)),$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
|
||||||
|
|
||||||
ifndef TOPLEVEL_BUILD
|
ifndef TOPLEVEL_BUILD
|
||||||
|
ifdef COMPILE_ENVIRONMENT
|
||||||
libs:: target host
|
libs:: target host
|
||||||
|
endif # COMPILE_ENVIRONMENT
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
|
endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
|
||||||
|
|
29
configure.in
29
configure.in
|
@ -367,6 +367,15 @@ dnl ========================================================
|
||||||
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269)
|
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269)
|
||||||
AR_FLAGS='crs $@'
|
AR_FLAGS='crs $@'
|
||||||
|
|
||||||
|
if test -z "$COMPILE_ENVIRONMENT"; then
|
||||||
|
if test "$target" != "$host"; then
|
||||||
|
# Assert that we're cross compiling, but don't require a compile toolchain (as
|
||||||
|
# MOZ_CROSS_COMPILER does below).
|
||||||
|
CROSS_COMPILE=1
|
||||||
|
AC_DEFINE(CROSS_COMPILE)
|
||||||
|
fi
|
||||||
|
fi # !COMPILE_ENVIRONMENT
|
||||||
|
|
||||||
if test "$COMPILE_ENVIRONMENT"; then
|
if test "$COMPILE_ENVIRONMENT"; then
|
||||||
|
|
||||||
if test "$target" != "$host"; then
|
if test "$target" != "$host"; then
|
||||||
|
@ -1965,7 +1974,7 @@ case "$target" in
|
||||||
TARGET_COMPILER_ABI="ibmc"
|
TARGET_COMPILER_ABI="ibmc"
|
||||||
CC_VERSION=`lslpp -Lcq vac.C 2>/dev/null | awk -F: '{ print $3 }'`
|
CC_VERSION=`lslpp -Lcq vac.C 2>/dev/null | awk -F: '{ print $3 }'`
|
||||||
CXX_VERSION=`lslpp -Lcq vacpp.cmp.core 2>/dev/null | awk -F: '{ print $3 }'`
|
CXX_VERSION=`lslpp -Lcq vacpp.cmp.core 2>/dev/null | awk -F: '{ print $3 }'`
|
||||||
fi
|
fi # COMPILE_ENVIRONMENT
|
||||||
fi
|
fi
|
||||||
case "${target_os}" in
|
case "${target_os}" in
|
||||||
aix4.1*)
|
aix4.1*)
|
||||||
|
@ -1974,7 +1983,7 @@ case "$target" in
|
||||||
esac
|
esac
|
||||||
if test "$COMPILE_ENVIRONMENT"; then
|
if test "$COMPILE_ENVIRONMENT"; then
|
||||||
MOZ_CHECK_HEADERS(sys/inttypes.h)
|
MOZ_CHECK_HEADERS(sys/inttypes.h)
|
||||||
fi
|
fi # COMPILE_ENVIRONMENT
|
||||||
AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES)
|
AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES)
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -2101,7 +2110,9 @@ ia64*-hpux*)
|
||||||
MOZ_SYNTH_PICO=1
|
MOZ_SYNTH_PICO=1
|
||||||
else
|
else
|
||||||
_PLATFORM_DEFAULT_TOOLKIT=cairo-android
|
_PLATFORM_DEFAULT_TOOLKIT=cairo-android
|
||||||
MOZ_LINKER=1
|
if test "$COMPILE_ENVIRONMENT"; then
|
||||||
|
MOZ_LINKER=1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"'
|
TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"'
|
||||||
|
|
||||||
|
@ -2587,7 +2598,7 @@ if test -z "$COMPILE_ENVIRONMENT"; then
|
||||||
SKIP_LIBRARY_CHECKS=1
|
SKIP_LIBRARY_CHECKS=1
|
||||||
else
|
else
|
||||||
MOZ_COMPILER_OPTS
|
MOZ_COMPILER_OPTS
|
||||||
fi
|
fi # COMPILE_ENVIRONMENT
|
||||||
|
|
||||||
if test -z "$SKIP_COMPILER_CHECKS"; then
|
if test -z "$SKIP_COMPILER_CHECKS"; then
|
||||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
|
@ -3919,7 +3930,9 @@ case "${target}" in
|
||||||
NSS_DISABLE_DBM=1
|
NSS_DISABLE_DBM=1
|
||||||
MOZ_THEME_FASTSTRIPE=1
|
MOZ_THEME_FASTSTRIPE=1
|
||||||
MOZ_TREE_FREETYPE=1
|
MOZ_TREE_FREETYPE=1
|
||||||
MOZ_MEMORY=1
|
if test "$COMPILE_ENVIRONMENT"; then
|
||||||
|
MOZ_MEMORY=1
|
||||||
|
fi
|
||||||
MOZ_RAW=1
|
MOZ_RAW=1
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -5451,7 +5464,7 @@ if test -n "$MOZ_VPX" -a -z "$MOZ_NATIVE_LIBVPX"; then
|
||||||
VPX_ASFLAGS="-f win32 -rnasm -pnasm -DPIC"
|
VPX_ASFLAGS="-f win32 -rnasm -pnasm -DPIC"
|
||||||
VPX_X86_ASM=1
|
VPX_X86_ASM=1
|
||||||
dnl The encoder needs obj_int_extract to get asm offsets.
|
dnl The encoder needs obj_int_extract to get asm offsets.
|
||||||
fi
|
fi # COMPILE_ENVIRONMENT and others
|
||||||
;;
|
;;
|
||||||
*:arm*)
|
*:arm*)
|
||||||
if test -n "$GNU_AS" ; then
|
if test -n "$GNU_AS" ; then
|
||||||
|
@ -5481,7 +5494,7 @@ if test -n "$MOZ_VPX" -a -z "$MOZ_NATIVE_LIBVPX"; then
|
||||||
|
|
||||||
if test -n "$COMPILE_ENVIRONMENT" -a -n "$VPX_X86_ASM" -a -z "$VPX_AS"; then
|
if test -n "$COMPILE_ENVIRONMENT" -a -n "$VPX_X86_ASM" -a -z "$VPX_AS"; then
|
||||||
AC_MSG_ERROR([yasm is a required build tool for this architecture when webm is enabled. You may either install yasm or --disable-webm (which disables the WebM video format). See https://developer.mozilla.org/en/YASM for more details.])
|
AC_MSG_ERROR([yasm is a required build tool for this architecture when webm is enabled. You may either install yasm or --disable-webm (which disables the WebM video format). See https://developer.mozilla.org/en/YASM for more details.])
|
||||||
fi
|
fi # COMPILE_ENVIRONMENT and others
|
||||||
|
|
||||||
if test -z "$GNU_CC" -a -z "$INTEL_CC" -a -z "$CLANG_CC" ; then
|
if test -z "$GNU_CC" -a -z "$INTEL_CC" -a -z "$CLANG_CC" ; then
|
||||||
dnl We prefer to get asm offsets using inline assembler, which the above
|
dnl We prefer to get asm offsets using inline assembler, which the above
|
||||||
|
@ -7339,7 +7352,7 @@ if test -n "$COMPILE_ENVIRONMENT" -a -n "$USE_ELF_HACK"; then
|
||||||
USE_ELF_HACK=
|
USE_ELF_HACK=
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi # COMPILE_ENVIRONMENT and others.
|
||||||
|
|
||||||
dnl ========================================================
|
dnl ========================================================
|
||||||
dnl = libstdc++ compatibility hacks
|
dnl = libstdc++ compatibility hacks
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
Adjust SDK integration
|
|
||||||
======================
|
|
||||||
|
|
||||||
The *Adjust install tracking SDK* is a pure-Java library that is conditionally
|
|
||||||
compiled into Fennec. It's not trivial to integrate such conditional feature
|
|
||||||
libraries into Fennec without pre-processing. To minimize such pre-processing,
|
|
||||||
we define a trivial ``AdjustHelperInterface`` and define two implementations:
|
|
||||||
the real ``AdjustHelper``, which requires the Adjust SDK, and a no-op
|
|
||||||
``StubAdjustHelper``, which has no additional requirements. We use the existing
|
|
||||||
pre-processed ``AppConstants.java.in`` to switch, at build-time, between the two
|
|
||||||
implementations.
|
|
||||||
|
|
||||||
An alternative approach would be to build three jars -- one interface jar and
|
|
||||||
two implementation jars -- and include one of the implementation jars at
|
|
||||||
build-time. The implementation jars could either define a common symbol, or the
|
|
||||||
appropriate symbol could be determined at build-time. That's a rather heavier
|
|
||||||
approach than the one chosen. If the helper class were to grow to multiple
|
|
||||||
classes, with a non-trivial exposed API, this approach could be better. It
|
|
||||||
would also be easier to integrate into the parallel Gradle build system.
|
|
|
@ -30,7 +30,13 @@ public class ReferrerReceiver extends BroadcastReceiver {
|
||||||
public static final String ACTION_REFERRER_RECEIVED = "org.mozilla.fennec.REFERRER_RECEIVED";
|
public static final String ACTION_REFERRER_RECEIVED = "org.mozilla.fennec.REFERRER_RECEIVED";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the install intent has this source, we'll track the campaign ID.
|
* If the install intent has this source, it is a Mozilla specific or over
|
||||||
|
* the air distribution referral. We'll track the campaign ID using
|
||||||
|
* Mozilla's metrics systems.
|
||||||
|
*
|
||||||
|
* If the install intent has a source different than this one, it is a
|
||||||
|
* referral from an advertising network. We may track these campaigns using
|
||||||
|
* third-party tracking and metrics systems.
|
||||||
*/
|
*/
|
||||||
private static final String MOZILLA_UTM_SOURCE = "mozilla";
|
private static final String MOZILLA_UTM_SOURCE = "mozilla";
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
.. -*- Mode: rst; fill-column: 100; -*-
|
||||||
|
|
||||||
|
======================================
|
||||||
|
Install tracking with the Adjust SDK
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Fennec (Firefox for Android) tracks certain types of installs using a third party install tracking
|
||||||
|
framework called Adjust. The intention is to determine the origin of Fennec installs by answering
|
||||||
|
the question, "Did this user on this device install Fennec in response to a specific advertising
|
||||||
|
campaign performed by Mozilla?"
|
||||||
|
|
||||||
|
Mozilla is using a third party framework in order to answer this question for the Firefox for
|
||||||
|
Android 38.0.5 release. We hope to remove the framework from Fennec in the future.
|
||||||
|
|
||||||
|
The framework consists of a software development kit (SDK) built into Fennec and a
|
||||||
|
data-collecting Internet service backend run by the German company `adjust GmbH`_. The Adjust SDK
|
||||||
|
is open source and MIT licensed: see the `github repository`_. Fennec ships a copy of the SDK
|
||||||
|
(currently not modified from upstream) in ``mobile/android/thirdparty/com/adjust/sdk``. The SDK is
|
||||||
|
documented at https://docs.adjust.com.
|
||||||
|
|
||||||
|
Data collection
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When is data collected and sent to the Adjust backend?
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
Data is never collected (or sent to the Adjust backend) unless
|
||||||
|
|
||||||
|
* the Fennec binary is an official Mozilla binary [#official]_; and
|
||||||
|
* the release channel is Release or Beta [#channel]_.
|
||||||
|
|
||||||
|
If both of the above conditions are true, then data is collected and sent to the Adjust backend in
|
||||||
|
the following two circumstances: first, when
|
||||||
|
|
||||||
|
* Fennec is started on the device [#started]_.
|
||||||
|
|
||||||
|
Second, when
|
||||||
|
|
||||||
|
* the Fennec binary was installed from the Google Play Store; and
|
||||||
|
* the Google Play Store sends the installed Fennec binary an `INSTALL_REFERRER Intent`_, and the
|
||||||
|
received Intent includes Google Play Store campaign tracking information. This happens when thea
|
||||||
|
Google Play Store install is in response to a campaign-specific Google Play Store link. For
|
||||||
|
details, see the developer documentation at
|
||||||
|
https://developers.google.com/analytics/devguides/collection/android/v4/campaigns.
|
||||||
|
|
||||||
|
In these two limited circumstances, data is collected and sent to the Adjust backend.
|
||||||
|
|
||||||
|
Where does data sent to the Adjust backend go?
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
The Adjust SDK is hard-coded to send data to the endpoint https://app.adjust.com. The endpoint is
|
||||||
|
defined by ``com.adjust.sdk.Constants.BASE_URL`` at
|
||||||
|
https://hg.mozilla.org/mozilla-central/file/f76f02793f7a/mobile/android/thirdparty/com/adjust/sdk/Constants.java#l27.
|
||||||
|
|
||||||
|
The Adjust backend then sends a limited subset of the collected data -- limited but sufficient to
|
||||||
|
uniquely identify the submitting device -- to a set of advertising network providers that Mozilla
|
||||||
|
elects to share the collected data with. Those advertising networks then confirm or deny that the
|
||||||
|
identifying information corresponds to a specific advertising campaign performed by Mozilla.
|
||||||
|
|
||||||
|
What data is collected and sent to the Adjust backend?
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
The Adjust SDK collects and sends two messages to the Adjust backend. The messages have the
|
||||||
|
following parameters::
|
||||||
|
|
||||||
|
V/Adjust ( 6508): Parameters:
|
||||||
|
V/Adjust ( 6508): screen_format normal
|
||||||
|
V/Adjust ( 6508): device_manufacturer samsung
|
||||||
|
V/Adjust ( 6508): session_count 1
|
||||||
|
V/Adjust ( 6508): device_type phone
|
||||||
|
V/Adjust ( 6508): screen_size normal
|
||||||
|
V/Adjust ( 6508): package_name org.mozilla.firefox
|
||||||
|
V/Adjust ( 6508): app_version 39.0a1
|
||||||
|
V/Adjust ( 6508): android_uuid <guid>
|
||||||
|
V/Adjust ( 6508): display_width 720
|
||||||
|
V/Adjust ( 6508): country GB
|
||||||
|
V/Adjust ( 6508): os_version 18
|
||||||
|
V/Adjust ( 6508): needs_attribution_data 0
|
||||||
|
V/Adjust ( 6508): environment sandbox
|
||||||
|
V/Adjust ( 6508): device_name Galaxy Nexus
|
||||||
|
V/Adjust ( 6508): os_name android
|
||||||
|
V/Adjust ( 6508): tracking_enabled 1
|
||||||
|
V/Adjust ( 6508): created_at 2015-03-24T17:53:38.452Z-0400
|
||||||
|
V/Adjust ( 6508): app_token <private>
|
||||||
|
V/Adjust ( 6508): screen_density high
|
||||||
|
V/Adjust ( 6508): language en
|
||||||
|
V/Adjust ( 6508): display_height 1184
|
||||||
|
V/Adjust ( 6508): gps_adid <guid>
|
||||||
|
|
||||||
|
V/Adjust ( 6508): Parameters:
|
||||||
|
V/Adjust ( 6508): needs_attribution_data 0
|
||||||
|
V/Adjust ( 6508): app_token <private>
|
||||||
|
V/Adjust ( 6508): environment production
|
||||||
|
V/Adjust ( 6508): android_uuid <guid>
|
||||||
|
V/Adjust ( 6508): tracking_enabled 1
|
||||||
|
V/Adjust ( 6508): gps_adid <guid>
|
||||||
|
|
||||||
|
The available parameters (including ones not exposed to Mozilla) are documented at
|
||||||
|
https://partners.adjust.com/placeholders/.
|
||||||
|
|
||||||
|
Notes on what data is collected
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The *android_uuid* uniquely identifies the device.
|
||||||
|
|
||||||
|
The *gps_adid* is a Google Advertising ID. It is capable of uniquely identifying a device to any
|
||||||
|
advertiser, across all applications. If a Google Advertising ID is not available, Adjust may fall
|
||||||
|
back to an Android ID, or, as a last resort, the device's WiFi MAC address.
|
||||||
|
|
||||||
|
The *tracking_enabled* flag is only used to allow or disallow contextual advertising to be sent to a
|
||||||
|
user. It can be, and is, ignored for general install tracking of the type Mozilla is using the
|
||||||
|
Adjust SDK for. (This flag might be used by consumers using the Adjust SDK to provide in-App
|
||||||
|
advertising.)
|
||||||
|
|
||||||
|
It is not clear how much entropy their is in the set of per-device parameters that do not
|
||||||
|
*explicitly* uniquely identify the device. That is, it is not known if the device parameters are
|
||||||
|
likely to uniquely fingerprint the device, in the way that user agent capabilities are likely to
|
||||||
|
uniquely fingerprint the user.
|
||||||
|
|
||||||
|
Technical notes
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Build flags controlling the Adjust SDK integration
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
The Adjust SDK feature is controlled by the build flag ``MOZ_INSTALL_TRACKING``. No trace of the
|
||||||
|
Adjust SDK should be present in Fennec if this is not defined.
|
||||||
|
|
||||||
|
Access to the Adjust backend is controlled by a private App-specific token. Fennec's token is
|
||||||
|
managed by Release Engineering and should not be exposed if at all possible; for example, it should
|
||||||
|
*not* leak to build logs. The value of the token is read from the file specified using the
|
||||||
|
``configure`` flag ``--with-adjust-sdk-keyfile=KEYFILE`` and stored in the build variable
|
||||||
|
``MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN``. Nota bene: if ``MOZ_INSTALL_TRACKING`` is defined
|
||||||
|
but the App-specific token is not specified, Fennec will submit data to a special Adjust sandbox.
|
||||||
|
This makes it possible to test the Adjust flow without submitting false data to the install tracking
|
||||||
|
backend.
|
||||||
|
|
||||||
|
Technical notes on the Adjust SDK integration
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The *Adjust install tracking SDK* is a pure-Java library that is conditionally compiled into Fennec.
|
||||||
|
It's not trivial to integrate such conditional feature libraries into Fennec without pre-processing.
|
||||||
|
To minimize such pre-processing, we define a trivial ``AdjustHelperInterface`` and define two
|
||||||
|
implementations: the real ``AdjustHelper``, which requires the Adjust SDK, and a no-op
|
||||||
|
``StubAdjustHelper``, which has no additional requirements. We use the existing pre-processed
|
||||||
|
``AppConstants.java.in`` to switch, at build-time, between the two implementations.
|
||||||
|
|
||||||
|
Notes and links
|
||||||
|
===============
|
||||||
|
|
||||||
|
.. _adjust GmbH: http://www.adjust.com
|
||||||
|
.. _github repository: https://github.com/adjust/android_sdk
|
||||||
|
.. [#official] Data is not sent for builds not produced by Mozilla: this would include
|
||||||
|
redistributors such as the Palemoon project.
|
||||||
|
.. [#channel] Data is not sent for Aurora, Nightly, or custom builds.
|
||||||
|
.. [#started] *Started* means more than just when the user taps the Fennec icon or otherwise causes
|
||||||
|
the Fennec user interface to appear directly. It includes, for example, when a Fennec service
|
||||||
|
(like the Update Service, or Background Sync), starts and Fennec was not previously running on the
|
||||||
|
device. See http://developer.android.com/reference/android/app/Application.html#onCreate%28%29
|
||||||
|
for details.
|
||||||
|
.. _INSTALL_REFERRER Intent: https://developer.android.com/reference/com/google/android/gms/tagmanager/InstallReferrerReceiver.html
|
|
@ -7,4 +7,5 @@ Firefox for Android
|
||||||
|
|
||||||
localeswitching
|
localeswitching
|
||||||
uitelemetry
|
uitelemetry
|
||||||
|
adjust
|
||||||
gradle
|
gradle
|
||||||
|
|
|
@ -760,6 +760,10 @@ for var in ('ANDROID_PACKAGE_NAME', 'ANDROID_CPU_ARCH',
|
||||||
# Mangle our package name to avoid Bug 750548.
|
# Mangle our package name to avoid Bug 750548.
|
||||||
DEFINES['MANGLED_ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME'].replace('fennec', 'f3nn3c')
|
DEFINES['MANGLED_ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME'].replace('fennec', 'f3nn3c')
|
||||||
DEFINES['MOZ_APP_ABI'] = CONFIG['TARGET_XPCOM_ABI']
|
DEFINES['MOZ_APP_ABI'] = CONFIG['TARGET_XPCOM_ABI']
|
||||||
|
if not CONFIG['COMPILE_ENVIRONMENT']:
|
||||||
|
# These should really come from the included binaries, but that's not easy.
|
||||||
|
DEFINES['MOZ_APP_ABI'] = 'arm-eabi-gcc3' # Observe quote differences here ...
|
||||||
|
DEFINES['TARGET_XPCOM_ABI'] = '"arm-eabi-gcc3"' # ... and here.
|
||||||
|
|
||||||
if '-march=armv7' in CONFIG['OS_CFLAGS']:
|
if '-march=armv7' in CONFIG['OS_CFLAGS']:
|
||||||
DEFINES['MOZ_MIN_CPU_VERSION'] = 7
|
DEFINES['MOZ_MIN_CPU_VERSION'] = 7
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<dimen name="arrow_popup_container_width">400dp</dimen>
|
<dimen name="arrow_popup_container_width">400dp</dimen>
|
||||||
<dimen name="doorhanger_offsetY">124dp</dimen>
|
<dimen name="doorhanger_offsetY">100dp</dimen>
|
||||||
|
|
||||||
<dimen name="browser_toolbar_height">56dp</dimen>
|
<dimen name="browser_toolbar_height">56dp</dimen>
|
||||||
<dimen name="browser_toolbar_height_flipper">60dp</dimen>
|
<dimen name="browser_toolbar_height_flipper">60dp</dimen>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<dimen name="doorhanger_offsetY">124dp</dimen>
|
||||||
|
</resources>
|
|
@ -46,8 +46,11 @@ MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea25febc110}
|
||||||
|
|
||||||
MOZ_APP_STATIC_INI=1
|
MOZ_APP_STATIC_INI=1
|
||||||
|
|
||||||
# Enable on-demand decompression
|
# Enable on-demand decompression. This requires a host compile toolchain to
|
||||||
|
# build szip to use during packaging.
|
||||||
|
if test "$COMPILE_ENVIRONMENT"; then
|
||||||
MOZ_ENABLE_SZIP=1
|
MOZ_ENABLE_SZIP=1
|
||||||
|
fi
|
||||||
|
|
||||||
# Enable navigator.mozPay
|
# Enable navigator.mozPay
|
||||||
MOZ_PAY=1
|
MOZ_PAY=1
|
||||||
|
|
|
@ -1122,9 +1122,9 @@ class AndroidCommands(MachCommandBase):
|
||||||
'--robocop-ini=' +
|
'--robocop-ini=' +
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.topobjdir,
|
self.topobjdir,
|
||||||
'build',
|
'_tests',
|
||||||
'mobile',
|
'testing',
|
||||||
'robocop',
|
'mochitest',
|
||||||
'robocop.ini'),
|
'robocop.ini'),
|
||||||
'--log-mach=-',
|
'--log-mach=-',
|
||||||
]
|
]
|
||||||
|
|
|
@ -66,7 +66,7 @@ RUN_MOCHITEST_ROBOCOP = \
|
||||||
$(PYTHON) _tests/testing/mochitest/runtestsremote.py \
|
$(PYTHON) _tests/testing/mochitest/runtestsremote.py \
|
||||||
--robocop-apk=$(DEPTH)/build/mobile/robocop/robocop-debug.apk \
|
--robocop-apk=$(DEPTH)/build/mobile/robocop/robocop-debug.apk \
|
||||||
--robocop-ids=$(DEPTH)/mobile/android/base/fennec_ids.txt \
|
--robocop-ids=$(DEPTH)/mobile/android/base/fennec_ids.txt \
|
||||||
--robocop-ini=$(DEPTH)/build/mobile/robocop/robocop.ini \
|
--robocop-ini=_tests/testing/mochitest/robocop.ini \
|
||||||
--console-level=INFO --log-tbpl=./$@.log $(DM_FLAGS) --dm_trans=$(DM_TRANS) \
|
--console-level=INFO --log-tbpl=./$@.log $(DM_FLAGS) --dm_trans=$(DM_TRANS) \
|
||||||
--app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
|
--app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
|
||||||
$(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
|
$(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
|
||||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -3,6 +3,7 @@
|
||||||
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
|
tags = appupdate
|
||||||
skip-if = (buildapp == 'b2g' || buildapp == 'mulet')
|
skip-if = (buildapp == 'b2g' || buildapp == 'mulet')
|
||||||
support-files =
|
support-files =
|
||||||
utils.js
|
utils.js
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
|
tags = appupdate
|
||||||
head = head_update.js
|
head = head_update.js
|
||||||
tail =
|
tail =
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
; from running the tests in the moz.build file.
|
; from running the tests in the moz.build file.
|
||||||
|
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
|
tags = appupdate
|
||||||
head = head_update.js
|
head = head_update.js
|
||||||
tail =
|
tail =
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
; Tests that require the updater binary and the maintenance service.
|
; Tests that require the updater binary and the maintenance service.
|
||||||
|
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
|
tags = appupdate
|
||||||
head = head_update.js
|
head = head_update.js
|
||||||
tail =
|
tail =
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче