diff --git a/browser/devtools/framework/toolbox.js b/browser/devtools/framework/toolbox.js index 682e453df37f..2b02ef74b001 100644 --- a/browser/devtools/framework/toolbox.js +++ b/browser/devtools/framework/toolbox.js @@ -717,6 +717,10 @@ Toolbox.prototype = { 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 = { environment: CommandUtils.createEnvironment(this, '_target') }; diff --git a/browser/devtools/performance/modules/actors.js b/browser/devtools/performance/modules/actors.js new file mode 100644 index 000000000000..61fec66b177f --- /dev/null +++ b/browser/devtools/performance/modules/actors.js @@ -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; diff --git a/browser/devtools/performance/modules/compatibility.js b/browser/devtools/performance/modules/compatibility.js index 2cf4fa39a77a..fd792878c13f 100644 --- a/browser/devtools/performance/modules/compatibility.js +++ b/browser/devtools/performance/modules/compatibility.js @@ -4,72 +4,9 @@ "use strict"; const { Task } = require("resource://gre/modules/Task.jsm"); -loader.lazyRequireGetter(this, "promise"); +const { Promise } = require("resource://gre/modules/Promise.jsm"); loader.lazyRequireGetter(this, "EventEmitter", "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. @@ -87,7 +24,8 @@ function MockFront (blueprint) { function MockMemoryFront () { MockFront.call(this, [ - ["initialize"], + ["start", 0], // for facade + ["stop", 0], // for facade ["destroy"], ["attach"], ["detach"], @@ -101,7 +39,6 @@ exports.MockMemoryFront = MockMemoryFront; function MockTimelineFront () { MockFront.call(this, [ - ["initialize"], ["destroy"], ["start", 0], ["stop", 0], @@ -169,12 +106,66 @@ function timelineActorSupported(target) { exports.timelineActorSupported = Task.async(timelineActorSupported); /** - * Returns a promise resolved with a listing of all the tabs in the - * provided thread client. + * Returns a promise resolving to the location of the profiler actor + * within this context. + * + * @param {TabTarget} target + * @return {Promise} */ -function listTabs(client) { - let deferred = promise.defer(); - client.listTabs(deferred.resolve); - return deferred.promise; +function getProfiler (target) { + let { promise, resolve } = Promise.defer(); + // Chrome and content process targets already have obtained a reference + // 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; diff --git a/browser/devtools/performance/modules/front.js b/browser/devtools/performance/modules/front.js index 63d5da7fc358..0ce6e8307c8a 100644 --- a/browser/devtools/performance/modules/front.js +++ b/browser/devtools/performance/modules/front.js @@ -9,24 +9,15 @@ const { extend } = require("sdk/util/object"); const { RecordingModel } = require("devtools/performance/recording-model"); loader.lazyRequireGetter(this, "Services"); -loader.lazyRequireGetter(this, "promise"); loader.lazyRequireGetter(this, "EventEmitter", "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", "devtools/toolkit/DevToolsUtils"); -loader.lazyRequireGetter(this, "compatibility", - "devtools/performance/compatibility"); +loader.lazyRequireGetter(this, "actors", + "devtools/performance/actors"); loader.lazyImporter(this, "gDevTools", "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", "resource://gre/modules/Promise.jsm"); @@ -41,9 +32,6 @@ const CONNECTION_PIPE_EVENTS = [ "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. * The keys are Target objects. @@ -84,17 +72,15 @@ function PerformanceActorsConnection(target) { this._target = target; this._client = this._target.client; - this._request = this._request.bind(this); this._pendingConsoleRecordings = []; this._sitesPullTimeout = 0; this._recordings = []; - this._onTimelineMarkers = this._onTimelineMarkers.bind(this); - this._onTimelineFrames = this._onTimelineFrames.bind(this); - this._onTimelineMemory = this._onTimelineMemory.bind(this); - this._onTimelineTicks = this._onTimelineTicks.bind(this); - this._onProfilerEvent = this._onProfilerEvent.bind(this); - this._pullAllocationSites = this._pullAllocationSites.bind(this); + this._pipeToConnection = this._pipeToConnection.bind(this); + this._onTimelineData = this._onTimelineData.bind(this); + this._onConsoleProfileStart = this._onConsoleProfileStart.bind(this); + this._onConsoleProfileEnd = this._onConsoleProfileEnd.bind(this); + this._onProfilerUnexpectedlyStopped = this._onProfilerUnexpectedlyStopped.bind(this); 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 // are available. Older Gecko versions don't have existing implementations, // in which case all the methods we need can be easily mocked. - yield this._connectProfilerActor(); - yield this._connectTimelineActor(); - yield this._connectMemoryActor(); - + yield this._connectActors(); yield this._registerListeners(); this._connected = true; @@ -159,132 +142,64 @@ PerformanceActorsConnection.prototype = { }), /** - * Initializes a connection to the profiler actor. Uses a facade around the ProfilerFront - * for similarity to the other actors in the shared connection. + * Initializes fronts and connects to the underlying actors using the facades + * found in ./actors.js. */ - _connectProfilerActor: Task.async(function*() { - this._profiler = new compatibility.ProfilerFront(this._target); - yield this._profiler.connect(); - }), + _connectActors: Task.async(function*() { + this._profiler = new actors.ProfilerFront(this._target); + this._memory = new actors.MemoryFront(this._target); + this._timeline = new actors.TimelineFront(this._target); - /** - * Initializes a connection to a timeline actor. - */ - _connectTimelineActor: function() { - 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; - }, + yield Promise.all([ + this._profiler.connect(), + this._memory.connect(), + this._timeline.connect() + ]); - /** - * Initializes a connection to a memory actor. - */ - _connectMemoryActor: Task.async(function* () { - 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; + // Expose server support status of underlying actors + // after connecting. + this._memorySupported = !this._memory.IS_MOCK; + this._timelineSupported = !this._timeline.IS_MOCK; }), /** * Registers listeners on events from the underlying * actors, so the connection can handle them. */ - _registerListeners: Task.async(function*() { - // Pipe events from TimelineActor to the PerformanceFront - this._timeline.on("markers", this._onTimelineMarkers); - this._timeline.on("frames", this._onTimelineFrames); - this._timeline.on("memory", this._onTimelineMemory); - this._timeline.on("ticks", this._onTimelineTicks); - - // Register events on the profiler actor to hook into `console.profile*` calls. - yield this._request("profiler", "registerEventNotifications", { events: PROFILER_EVENTS }); - this._client.addListener("eventNotification", this._onProfilerEvent); - }), + _registerListeners: function () { + this._timeline.on("timeline-data", this._onTimelineData); + this._memory.on("timeline-data", this._onTimelineData); + this._profiler.on("console-profile-start", this._onConsoleProfileStart); + this._profiler.on("console-profile-end", this._onConsoleProfileEnd); + this._profiler.on("profiler-stopped", this._onProfilerUnexpectedlyStopped); + this._profiler.on("profiler-already-active", this._pipeToConnection); + this._profiler.on("profiler-activated", this._pipeToConnection); + }, /** * Unregisters listeners on events on the underlying actors. */ - _unregisterListeners: Task.async(function*() { - this._timeline.off("markers", this._onTimelineMarkers); - this._timeline.off("frames", this._onTimelineFrames); - this._timeline.off("memory", this._onTimelineMemory); - this._timeline.off("ticks", this._onTimelineTicks); - - yield this._request("profiler", "unregisterEventNotifications", { events: PROFILER_EVENTS }); - this._client.removeListener("eventNotification", this._onProfilerEvent); - }), + _unregisterListeners: function () { + this._timeline.off("timeline-data", this._onTimelineData); + this._memory.off("timeline-data", this._onTimelineData); + this._profiler.off("console-profile-start", this._onConsoleProfileStart); + this._profiler.off("console-profile-end", this._onConsoleProfileEnd); + this._profiler.off("profiler-stopped", this._onProfilerUnexpectedlyStopped); + this._profiler.off("profiler-already-active", this._pipeToConnection); + this._profiler.off("profiler-activated", this._pipeToConnection); + }, /** * Closes the connections to non-profiler actors. */ _disconnectActors: Task.async(function* () { - yield this._timeline.destroy(); - yield this._memory.destroy(); + yield Promise.all([ + 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. * @@ -294,7 +209,7 @@ PerformanceActorsConnection.prototype = { * The time (in milliseconds) when the call was made, relative to when * the nsIProfiler module was started. */ - _onConsoleProfileStart: Task.async(function *({ profileLabel, currentTime: startTime }) { + _onConsoleProfileStart: Task.async(function *(_, { profileLabel, currentTime: startTime }) { let recordings = this._recordings; // 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 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 // call to console.profileEnd() if (!data) { @@ -361,14 +276,12 @@ PerformanceActorsConnection.prototype = { this.emit("console-profile-end", model); }), - /** - * Handlers for TimelineActor events. All pipe to `_onTimelineData` - * with the appropriate event name. - */ - _onTimelineMarkers: function (markers) { this._onTimelineData("markers", markers); }, - _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); }, + /** + * TODO handle bug 1144438 + */ + _onProfilerUnexpectedlyStopped: function () { + Cu.reportError("Profiler unexpectedly stopped.", arguments); + }, /** * 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. */ - - _onTimelineData: function (...data) { + _onTimelineData: function (_, ...data) { this._recordings.forEach(e => e.addTimelineData.apply(e, data)); this.emit("timeline-data", ...data); }, @@ -399,15 +311,13 @@ PerformanceActorsConnection.prototype = { let model = new RecordingModel(options); // All actors are started asynchronously over the remote debugging protocol. // Get the corresponding start times from each one of them. - let profilerStartTime = yield this._startProfiler(options); - let timelineStartTime = yield this._startTimeline(options); - let memoryStartTime = yield this._startMemory(options); + // The timeline and memory actors are target-dependent, so start those as well, + // even though these are mocked in older Geckos (FF < 35) + let profilerStartTime = yield this._profiler.start(options); + let timelineStartTime = yield this._timeline.start(options); + let memoryStartTime = yield this._memory.start(options); - let data = { - profilerStartTime, - timelineStartTime, - memoryStartTime - }; + let data = { profilerStartTime, timelineStartTime, memoryStartTime }; // Signify to the model that the recording has started, // populate with data and store the recording model here. @@ -445,7 +355,7 @@ PerformanceActorsConnection.prototype = { let config = model.getConfiguration(); let startTime = model.getProfilerStartTime(); - let profilerData = yield this._request("profiler", "getProfile", { startTime }); + let profilerData = yield this._profiler.getProfile({ startTime }); let memoryEndTime = 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 // are only used in tests. if (!this.isRecording()) { - memoryEndTime = yield this._stopMemory(config); - timelineEndTime = yield this._stopTimeline(config); + memoryEndTime = yield this._memory.stop(config); + timelineEndTime = yield this._timeline.stop(config); } // 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={}) { - // 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._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(); - }), + _pipeToConnection: function (eventName, ...args) { + this.emit(eventName, ...args); + }, toString: () => "[object PerformanceActorsConnection]" }; @@ -620,7 +415,6 @@ function PerformanceFront(connection) { EventEmitter.decorate(this); this._connection = connection; - this._request = connection._request; // Set when mocks are being used this._memorySupported = connection._memorySupported; @@ -680,6 +474,17 @@ PerformanceFront.prototype = { */ isRecording: function () { 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); } }; diff --git a/browser/devtools/performance/moz.build b/browser/devtools/performance/moz.build index 7b83784b013c..0662e080c984 100644 --- a/browser/devtools/performance/moz.build +++ b/browser/devtools/performance/moz.build @@ -4,6 +4,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXTRA_JS_MODULES.devtools.performance += [ + 'modules/actors.js', 'modules/compatibility.js', 'modules/front.js', 'modules/graphs.js', diff --git a/browser/devtools/performance/test/browser_perf-shared-connection-02.js b/browser/devtools/performance/test/browser_perf-shared-connection-02.js index 5df422a1d333..7e2c9edc3622 100644 --- a/browser/devtools/performance/test/browser_perf-shared-connection-02.js +++ b/browser/devtools/performance/test/browser_perf-shared-connection-02.js @@ -18,7 +18,7 @@ function spawnTest () { ok(sharedConnection, "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."); yield sharedConnection.open(); diff --git a/config/recurse.mk b/config/recurse.mk index 8a0a5a7bdf97..bd22bbe7222c 100644 --- a/config/recurse.mk +++ b/config/recurse.mk @@ -124,7 +124,9 @@ endef $(foreach subtier,$(filter-out compile,$(TIERS)),$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier)))) ifndef TOPLEVEL_BUILD +ifdef COMPILE_ENVIRONMENT libs:: target host +endif # COMPILE_ENVIRONMENT endif endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL)) diff --git a/configure.in b/configure.in index e26147e485ea..3b74b011e65f 100644 --- a/configure.in +++ b/configure.in @@ -367,6 +367,15 @@ dnl ======================================================== dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269) 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 "$target" != "$host"; then @@ -1965,7 +1974,7 @@ case "$target" in TARGET_COMPILER_ABI="ibmc" 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 }'` - fi + fi # COMPILE_ENVIRONMENT fi case "${target_os}" in aix4.1*) @@ -1974,7 +1983,7 @@ case "$target" in esac if test "$COMPILE_ENVIRONMENT"; then MOZ_CHECK_HEADERS(sys/inttypes.h) - fi + fi # COMPILE_ENVIRONMENT AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) ;; @@ -2101,7 +2110,9 @@ ia64*-hpux*) MOZ_SYNTH_PICO=1 else _PLATFORM_DEFAULT_TOOLKIT=cairo-android - MOZ_LINKER=1 + if test "$COMPILE_ENVIRONMENT"; then + MOZ_LINKER=1 + fi fi TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' @@ -2587,7 +2598,7 @@ if test -z "$COMPILE_ENVIRONMENT"; then SKIP_LIBRARY_CHECKS=1 else MOZ_COMPILER_OPTS -fi +fi # COMPILE_ENVIRONMENT if test -z "$SKIP_COMPILER_CHECKS"; then dnl Checks for typedefs, structures, and compiler characteristics. @@ -3919,7 +3930,9 @@ case "${target}" in NSS_DISABLE_DBM=1 MOZ_THEME_FASTSTRIPE=1 MOZ_TREE_FREETYPE=1 - MOZ_MEMORY=1 + if test "$COMPILE_ENVIRONMENT"; then + MOZ_MEMORY=1 + fi 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_X86_ASM=1 dnl The encoder needs obj_int_extract to get asm offsets. - fi + fi # COMPILE_ENVIRONMENT and others ;; *:arm*) 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 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 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= fi fi -fi +fi # COMPILE_ENVIRONMENT and others. dnl ======================================================== dnl = libstdc++ compatibility hacks diff --git a/mobile/android/base/adjust/adjust.rst b/mobile/android/base/adjust/adjust.rst deleted file mode 100644 index ca9fa49e4860..000000000000 --- a/mobile/android/base/adjust/adjust.rst +++ /dev/null @@ -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. diff --git a/mobile/android/base/distribution/ReferrerReceiver.java b/mobile/android/base/distribution/ReferrerReceiver.java index 019ec4a6dfd3..dfa79fc3ed5c 100644 --- a/mobile/android/base/distribution/ReferrerReceiver.java +++ b/mobile/android/base/distribution/ReferrerReceiver.java @@ -30,7 +30,13 @@ public class ReferrerReceiver extends BroadcastReceiver { 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"; diff --git a/mobile/android/base/docs/adjust.rst b/mobile/android/base/docs/adjust.rst new file mode 100644 index 000000000000..4e83320f0806 --- /dev/null +++ b/mobile/android/base/docs/adjust.rst @@ -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 + 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 + V/Adjust ( 6508): screen_density high + V/Adjust ( 6508): language en + V/Adjust ( 6508): display_height 1184 + V/Adjust ( 6508): gps_adid + + V/Adjust ( 6508): Parameters: + V/Adjust ( 6508): needs_attribution_data 0 + V/Adjust ( 6508): app_token + V/Adjust ( 6508): environment production + V/Adjust ( 6508): android_uuid + V/Adjust ( 6508): tracking_enabled 1 + V/Adjust ( 6508): gps_adid + +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 diff --git a/mobile/android/base/docs/index.rst b/mobile/android/base/docs/index.rst index 205ac1aa00c2..69bd9b1efb30 100644 --- a/mobile/android/base/docs/index.rst +++ b/mobile/android/base/docs/index.rst @@ -7,4 +7,5 @@ Firefox for Android localeswitching uitelemetry + adjust gradle diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 5431a777c19a..feb92072debe 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -760,6 +760,10 @@ for var in ('ANDROID_PACKAGE_NAME', 'ANDROID_CPU_ARCH', # Mangle our package name to avoid Bug 750548. DEFINES['MANGLED_ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME'].replace('fennec', 'f3nn3c') 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']: DEFINES['MOZ_MIN_CPU_VERSION'] = 7 diff --git a/mobile/android/base/resources/values-large-v11/dimens.xml b/mobile/android/base/resources/values-large-v11/dimens.xml index ab1a7e458a86..05d688c8f2ff 100644 --- a/mobile/android/base/resources/values-large-v11/dimens.xml +++ b/mobile/android/base/resources/values-large-v11/dimens.xml @@ -6,7 +6,7 @@ 400dp - 124dp + 100dp 56dp 60dp diff --git a/mobile/android/base/resources/values-large-v16/dimens.xml b/mobile/android/base/resources/values-large-v16/dimens.xml new file mode 100644 index 000000000000..80ce7118d7fd --- /dev/null +++ b/mobile/android/base/resources/values-large-v16/dimens.xml @@ -0,0 +1,8 @@ + + + + + 124dp + diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh index abed93626830..e3f68e90a4e6 100644 --- a/mobile/android/confvars.sh +++ b/mobile/android/confvars.sh @@ -46,8 +46,11 @@ MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea25febc110} 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 +fi # Enable navigator.mozPay MOZ_PAY=1 diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py index 72e697829439..e770530dffe2 100644 --- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -1122,9 +1122,9 @@ class AndroidCommands(MachCommandBase): '--robocop-ini=' + os.path.join( self.topobjdir, - 'build', - 'mobile', - 'robocop', + '_tests', + 'testing', + 'mochitest', 'robocop.ini'), '--log-mach=-', ] diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 0739b1897d61..52b7eb1adcec 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -66,7 +66,7 @@ RUN_MOCHITEST_ROBOCOP = \ $(PYTHON) _tests/testing/mochitest/runtestsremote.py \ --robocop-apk=$(DEPTH)/build/mobile/robocop/robocop-debug.apk \ --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) \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS) diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/preliminary_bootstrap_2.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/preliminary_bootstrap_2.xpi index a62faf1c52b3..ec38fcc651ee 100644 Binary files a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/preliminary_bootstrap_2.xpi and b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/preliminary_bootstrap_2.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_1.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_1.xpi index 5444b951a48a..fc2842399721 100644 Binary files a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_1.xpi and b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_1.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_2.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_2.xpi index 122c4d56b3d3..327c8a1875c0 100644 Binary files a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_2.xpi and b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_2.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_badid_2.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_badid_2.xpi index 150918a8c157..efad21d1b655 100644 Binary files a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_badid_2.xpi and b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_badid_2.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_2.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_2.xpi index 3c6cd647031e..d6ddbcec38c8 100644 Binary files a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_2.xpi and b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_2.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_badid_2.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_badid_2.xpi index cdf4325acde4..5898d83e499d 100644 Binary files a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_badid_2.xpi and b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_badid_2.xpi differ diff --git a/toolkit/mozapps/update/tests/chrome/chrome.ini b/toolkit/mozapps/update/tests/chrome/chrome.ini index 64fa0754f082..e6c3cbbb2cd5 100644 --- a/toolkit/mozapps/update/tests/chrome/chrome.ini +++ b/toolkit/mozapps/update/tests/chrome/chrome.ini @@ -3,6 +3,7 @@ ; file, You can obtain one at http://mozilla.org/MPL/2.0/. [DEFAULT] +tags = appupdate skip-if = (buildapp == 'b2g' || buildapp == 'mulet') support-files = utils.js diff --git a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini index 4ff7e3ac4ed2..3087d54eab63 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini +++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini @@ -3,6 +3,7 @@ ; file, You can obtain one at http://mozilla.org/MPL/2.0/. [DEFAULT] +tags = appupdate head = head_update.js tail = diff --git a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini index a33a507aa723..3a26ac222d6d 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini +++ b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini @@ -7,6 +7,7 @@ ; from running the tests in the moz.build file. [DEFAULT] +tags = appupdate head = head_update.js tail = diff --git a/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini b/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini index 76b2d68dc77f..4c380ad79964 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini +++ b/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini @@ -5,6 +5,7 @@ ; Tests that require the updater binary and the maintenance service. [DEFAULT] +tags = appupdate head = head_update.js tail =