This commit is contained in:
Ryan VanderMeulen 2015-08-31 15:22:43 -04:00
Родитель 3fd16e37a0 0f38752ebc
Коммит 1022db7d1e
107 изменённых файлов: 4449 добавлений и 3114 удалений

Просмотреть файл

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

Просмотреть файл

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

Просмотреть файл

@ -19,8 +19,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>

Просмотреть файл

@ -17,8 +17,8 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>

Просмотреть файл

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

Просмотреть файл

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

Просмотреть файл

@ -19,8 +19,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>

Просмотреть файл

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

Просмотреть файл

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "31e595f86f6bf159b3a9a46816a6ac00a55ca9f9",
"git_revision": "c80e8ff25425b007181fd6e3de0500a0358fab37",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "15ba43fc66bdea9bfe6397bb992c0918d9d3d77c",
"revision": "617c2b44e26a8bd8c79d96a12fb9fd373c873e44",
"repo_path": "integration/gaia-central"
}

Просмотреть файл

@ -17,8 +17,8 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>

Просмотреть файл

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

Просмотреть файл

@ -48,7 +48,7 @@ AppValidator.prototype._getPackagedManifestFile = function () {
let hasJsonManifest = jsonManifestFile.exists() && jsonManifestFile.isFile();
if (!hasAppManifest && !hasJsonManifest) {
this.error(strings.GetStringFromName("validator.wrongManifestFileName"));
this.error(strings.GetStringFromName("validator.noManifestFile"));
return null;
}

Просмотреть файл

@ -338,7 +338,7 @@ let PerformanceController = {
*/
exportRecording: Task.async(function*(_, recording, file) {
yield recording.exportRecording(file);
this.emit(EVENTS.RECORDING_EXPORTED, recording);
this.emit(EVENTS.RECORDING_EXPORTED, recording, file);
}),
/**

Просмотреть файл

@ -7,7 +7,7 @@
let test = Task.async(function*() {
var { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
var { EVENTS, PerformanceController, PerformanceView, DetailsView, DetailsSubview } = panel.panelWin;
var { $, EVENTS, PerformanceController, PerformanceView, DetailsView, DetailsSubview } = panel.panelWin;
// Enable allocations to test the memory-calltree and memory-flamegraph.
Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
@ -45,6 +45,13 @@ let test = Task.async(function*() {
yield exported;
ok(true, "The recording data appears to have been successfully saved.");
// Check if the imported file name has tmpprofile in it as the file
// names also has different suffix to avoid conflict
let displayedName = $(".recording-item-title").getAttribute("value");
ok(/^tmpprofile/.test(displayedName), "File has expected display name after import");
ok(!/\.json$/.test(displayedName), "Display name does not have .json in it");
// Import recording.
let rerendered = waitForWidgetsRendered(panel);

Просмотреть файл

@ -18,12 +18,14 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
this._onNewRecording = this._onNewRecording.bind(this);
this._onSaveButtonClick = this._onSaveButtonClick.bind(this);
this._onRecordingsCleared = this._onRecordingsCleared.bind(this);
this._onRecordingExported = this._onRecordingExported.bind(this);
this.emptyText = L10N.getStr("noRecordingsText");
PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
PerformanceController.on(EVENTS.NEW_RECORDING, this._onNewRecording);
PerformanceController.on(EVENTS.RECORDINGS_CLEARED, this._onRecordingsCleared);
PerformanceController.on(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
this.widget.addEventListener("select", this._onSelect, false);
},
@ -34,6 +36,7 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
PerformanceController.off(EVENTS.NEW_RECORDING, this._onNewRecording);
PerformanceController.off(EVENTS.RECORDINGS_CLEARED, this._onRecordingsCleared);
PerformanceController.off(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
this.widget.removeEventListener("select", this._onSelect, false);
},
@ -197,6 +200,15 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
}});
},
_onRecordingExported: function (_, recording, file) {
if (recording.isConsole()) {
return;
}
let recordingItem = this.getItemForPredicate(e => e.attachment === recording);
let titleNode = $(".recording-item-title", recordingItem.target);
titleNode.setAttribute("value", file.leafName.replace(/\..+$/, ""));
},
toString: () => "[object RecordingsView]"
});

Просмотреть файл

@ -18,7 +18,7 @@ project.installing=Installing…
project.installed=Installed!
validator.nonExistingFolder=The project folder doesn't exists
validator.expectProjectFolder=The project folder ends up being a file
validator.wrongManifestFileName=A manifest file is required at project root folder, named either 'manifest.webapp' for packaged apps or 'manifest.json' for addons.
validator.noManifestFile=A manifest file is required at project root folder, named either 'manifest.webapp' for packaged apps or 'manifest.json' for add-ons.
validator.invalidManifestURL=Invalid manifest URL '%S'
# LOCALIZATION NOTE (validator.invalidManifestJSON, validator.noAccessManifestURL):
# %1$S is the error message, %2$S is the URI of the manifest.

Просмотреть файл

@ -96,6 +96,7 @@
#include "nsSHistory.h"
#include "nsDocShellEditorData.h"
#include "GeckoProfiler.h"
#include "timeline/JavascriptTimelineMarker.h"
// Helper Classes
#include "nsError.h"
@ -1601,7 +1602,7 @@ nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
(void)aLoadInfo->GetLoadType(&lt);
// Get the appropriate LoadType from nsIDocShellLoadInfo type
loadType = ConvertDocShellLoadInfoToLoadType(lt);
nsCOMPtr<nsISupports> owner;
aLoadInfo->GetOwner(getter_AddRefs(owner));
requestingPrincipal = do_QueryInterface(owner);
@ -13763,51 +13764,6 @@ nsDocShell::GetOpener()
return opener;
}
class JavascriptTimelineMarker : public TimelineMarker
{
public:
JavascriptTimelineMarker(nsDocShell* aDocShell, const char* aName,
const char* aReason,
const char16_t* aFunctionName,
const char16_t* aFileName,
uint32_t aLineNumber)
: TimelineMarker(aDocShell, aName, TRACING_INTERVAL_START,
NS_ConvertUTF8toUTF16(aReason),
NO_STACK)
, mFunctionName(aFunctionName)
, mFileName(aFileName)
, mLineNumber(aLineNumber)
{
}
void AddDetails(JSContext* aCx, mozilla::dom::ProfileTimelineMarker& aMarker)
override
{
aMarker.mCauseName.Construct(GetCause());
if (!mFunctionName.IsEmpty() || !mFileName.IsEmpty()) {
RootedDictionary<ProfileTimelineStackFrame> stackFrame(aCx);
stackFrame.mLine.Construct(mLineNumber);
stackFrame.mSource.Construct(mFileName);
stackFrame.mFunctionDisplayName.Construct(mFunctionName);
JS::Rooted<JS::Value> newStack(aCx);
if (ToJSValue(aCx, stackFrame, &newStack)) {
if (newStack.isObject()) {
aMarker.mStack = &newStack.toObject();
}
} else {
JS_ClearPendingException(aCx);
}
}
}
private:
nsString mFunctionName;
nsString mFileName;
uint32_t mLineNumber;
};
void
nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
const char16_t* aFunctionName,
@ -13818,10 +13774,8 @@ nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
// If first start, mark interval start.
if (timelineOn && mJSRunToCompletionDepth == 0) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<JavascriptTimelineMarker>(this, "Javascript", aReason,
aFunctionName, aFilename,
aLineNumber);
UniquePtr<TimelineMarker> marker = MakeUnique<JavascriptTimelineMarker>(
aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START);
TimelineConsumers::AddMarkerForDocShell(this, Move(marker));
}
mJSRunToCompletionDepth++;
@ -13835,7 +13789,7 @@ nsDocShell::NotifyJSRunToCompletionStop()
// If last stop, mark interval end.
mJSRunToCompletionDepth--;
if (timelineOn && mJSRunToCompletionDepth == 0) {
TimelineConsumers::AddMarkerForDocShell(this, "Javascript", TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END);
}
}

Просмотреть файл

@ -33,9 +33,9 @@
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "timeline/TimelineMarker.h"
#include "timeline/TimelineConsumers.h"
#include "timeline/ObservedDocShell.h"
#include "timeline/TimelineConsumers.h"
#include "timeline/TimelineMarker.h"
// Threshold value in ms for META refresh based redirects
#define REFRESH_REDIRECT_TIMER 15000
@ -275,14 +275,14 @@ private:
// be very fast, so instead of using a Map or having to search for some
// docshell-specific markers storage, a pointer to an `ObservedDocShell` is
// is stored on docshells directly.
friend void mozilla::TimelineConsumers::AddConsumer(nsDocShell* aDocShell);
friend void mozilla::TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell);
friend void mozilla::TimelineConsumers::AddConsumer(nsDocShell*);
friend void mozilla::TimelineConsumers::RemoveConsumer(nsDocShell*);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell* aDocShell, const char* aName, TracingMetadata aMetaData);
nsDocShell*, const char*, MarkerTracingType);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell* aDocShell, const char* aName, const TimeStamp& aTime, TracingMetadata aMetaData);
nsDocShell*, const char*, const TimeStamp&, MarkerTracingType);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell* aDocShell, UniquePtr<TimelineMarker>&& aMarker);
nsDocShell*, UniquePtr<TimelineMarker>&&);
public:
// Tell the favicon service that aNewURI has the same favicon as aOldURI.

Просмотреть файл

@ -22,7 +22,7 @@ AutoGlobalTimelineMarker::AutoGlobalTimelineMarker(const char* aName
return;
}
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, TRACING_INTERVAL_START);
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, MarkerTracingType::START);
}
AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
@ -31,7 +31,7 @@ AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
return;
}
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, MarkerTracingType::END);
}
} // namespace mozilla

Просмотреть файл

@ -19,7 +19,7 @@ namespace mozilla {
// Similar to `AutoTimelineMarker`, but adds its traced marker to all docshells,
// not a single particular one. This is useful for operations that aren't
// associated with any one particular doc shell, or when it isn't clear which
// doc shell triggered the operation.
// docshell triggered the operation.
//
// Example usage:
//

Просмотреть файл

@ -25,7 +25,7 @@ AutoTimelineMarker::AutoTimelineMarker(nsIDocShell* aDocShell, const char* aName
}
mDocShell = static_cast<nsDocShell*>(aDocShell);
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, TRACING_INTERVAL_START);
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::START);
}
AutoTimelineMarker::~AutoTimelineMarker()
@ -34,7 +34,7 @@ AutoTimelineMarker::~AutoTimelineMarker()
return;
}
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::END);
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_ConsoleTimelineMarker_h_
#define mozilla_ConsoleTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class ConsoleTimelineMarker : public TimelineMarker
{
public:
explicit ConsoleTimelineMarker(const nsAString& aCause,
MarkerTracingType aTracingType)
: TimelineMarker("ConsoleTime", aTracingType)
, mCause(aCause)
{
// Stack is captured by default on the "start" marker. Explicitly also
// capture stack on the "end" marker.
if (aTracingType == MarkerTracingType::END) {
CaptureStack();
}
}
virtual bool Equals(const TimelineMarker& aOther) override
{
if (!TimelineMarker::Equals(aOther)) {
return false;
}
// Console markers must have matching causes as well. It is safe to perform
// a static_cast here as the previous equality check ensures that this is
// a console marker instance.
return mCause == static_cast<const ConsoleTimelineMarker*>(&aOther)->mCause;
}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mCauseName.Construct(mCause);
} else {
aMarker.mEndStack = GetStack();
}
}
private:
nsString mCause;
};
} // namespace mozilla
#endif // mozilla_ConsoleTimelineMarker_h_

Просмотреть файл

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_EventTimelineMarker_h_
#define mozilla_EventTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class EventTimelineMarker : public TimelineMarker
{
public:
explicit EventTimelineMarker(const nsAString& aType,
uint16_t aPhase,
MarkerTracingType aTracingType)
: TimelineMarker("DOMEvent", aTracingType)
, mType(aType)
, mPhase(aPhase)
{}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mType.Construct(mType);
aMarker.mEventPhase.Construct(mPhase);
}
}
private:
nsString mType;
uint16_t mPhase;
};
} // namespace mozilla
#endif // mozilla_EventTimelineMarker_h_

Просмотреть файл

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_JavascriptTimelineMarker_h_
#define mozilla_JavascriptTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/ToJSValue.h"
namespace mozilla {
class JavascriptTimelineMarker : public TimelineMarker
{
public:
explicit JavascriptTimelineMarker(const char* aReason,
const char16_t* aFunctionName,
const char16_t* aFileName,
uint32_t aLineNumber,
MarkerTracingType aTracingType)
: TimelineMarker("Javascript", aTracingType, MarkerStackRequest::NO_STACK)
, mCause(NS_ConvertUTF8toUTF16(aReason))
, mFunctionName(aFunctionName)
, mFileName(aFileName)
, mLineNumber(aLineNumber)
{}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
aMarker.mCauseName.Construct(mCause);
if (!mFunctionName.IsEmpty() || !mFileName.IsEmpty()) {
dom::RootedDictionary<dom::ProfileTimelineStackFrame> stackFrame(aCx);
stackFrame.mLine.Construct(mLineNumber);
stackFrame.mSource.Construct(mFileName);
stackFrame.mFunctionDisplayName.Construct(mFunctionName);
JS::Rooted<JS::Value> newStack(aCx);
if (ToJSValue(aCx, stackFrame, &newStack)) {
if (newStack.isObject()) {
aMarker.mStack = &newStack.toObject();
}
} else {
JS_ClearPendingException(aCx);
}
}
}
private:
nsString mCause;
nsString mFunctionName;
nsString mFileName;
uint32_t mLineNumber;
};
} // namespace mozilla
#endif // mozilla_JavascriptTimelineMarker_h_

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_LayerTimelineMarker_h_
#define mozilla_LayerTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class LayerTimelineMarker : public TimelineMarker
{
public:
explicit LayerTimelineMarker(const nsIntRegion& aRegion)
: TimelineMarker("Layer", MarkerTracingType::HELPER_EVENT)
, mRegion(aRegion)
{}
~LayerTimelineMarker()
{}
void AddLayerRectangles(dom::Sequence<dom::ProfileTimelineLayerRect>& aRectangles)
{
nsIntRegionRectIterator it(mRegion);
while (const nsIntRect* iterRect = it.Next()) {
dom::ProfileTimelineLayerRect rect;
rect.mX = iterRect->X();
rect.mY = iterRect->Y();
rect.mWidth = iterRect->Width();
rect.mHeight = iterRect->Height();
aRectangles.AppendElement(rect, fallible);
}
}
private:
nsIntRegion mRegion;
};
} // namespace mozilla
#endif // mozilla_LayerTimelineMarker_h_

Просмотреть файл

@ -7,6 +7,7 @@
#include "ObservedDocShell.h"
#include "TimelineMarker.h"
#include "LayerTimelineMarker.h"
#include "mozilla/Move.h"
namespace mozilla {
@ -38,9 +39,9 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
UniquePtr<TimelineMarker>& startPayload = mTimelineMarkers[i];
// If this is a TRACING_TIMESTAMP marker, there's no corresponding END
// If this is a TIMESTAMP marker, there's no corresponding END,
// as it's a single unit of time, not a duration.
if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
if (startPayload->GetTracingType() == MarkerTracingType::TIMESTAMP) {
dom::ProfileTimelineMarker* marker = aStore.AppendElement();
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
marker->mStart = startPayload->GetTime();
@ -52,7 +53,7 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
// Whenever a START marker is found, look for the corresponding END
// and build a {name,start,end} JS object.
if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
if (startPayload->GetTracingType() == MarkerTracingType::START) {
bool hasSeenEnd = false;
// "Paint" markers are different because painting is handled at root
@ -80,17 +81,18 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
// Look for "Layer" markers to stream out "Paint" markers.
if (startIsPaintType && endIsLayerType) {
LayerTimelineMarker* layerPayload = static_cast<LayerTimelineMarker*>(endPayload.get());
layerPayload->AddLayerRectangles(layerRectangles);
hasSeenLayerType = true;
endPayload->AddLayerRectangles(layerRectangles);
}
if (!startPayload->Equals(*endPayload)) {
continue;
}
if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
if (endPayload->GetTracingType() == MarkerTracingType::START) {
++markerDepth;
continue;
}
if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
if (endPayload->GetTracingType() == MarkerTracingType::END) {
if (markerDepth > 0) {
--markerDepth;
continue;

Просмотреть файл

@ -4,16 +4,17 @@
* 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/. */
#ifndef ObservedDocShell_h_
#define ObservedDocShell_h_
#ifndef mozilla_ObservedDocShell_h_
#define mozilla_ObservedDocShell_h_
#include "nsTArray.h"
#include "mozilla/nsRefPtr.h"
class nsDocShell;
class TimelineMarker;
namespace mozilla {
class TimelineMarker;
namespace dom {
struct ProfileTimelineMarker;
}
@ -39,4 +40,4 @@ public:
} // namespace mozilla
#endif /* ObservedDocShell_h_ */
#endif /* mozilla_ObservedDocShell_h_ */

Просмотреть файл

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_RestyleTimelineMarker_h_
#define mozilla_RestyleTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class RestyleTimelineMarker : public TimelineMarker
{
public:
explicit RestyleTimelineMarker(nsRestyleHint aRestyleHint,
MarkerTracingType aTracingType)
: TimelineMarker("Styles", aTracingType)
{
if (aRestyleHint) {
mRestyleHint.AssignWithConversion(RestyleManager::RestyleHintToString(aRestyleHint));
}
}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mRestyleHint.Construct(mRestyleHint);
}
}
private:
nsAutoString mRestyleHint;
};
} // namespace mozilla
#endif // mozilla_RestyleTimelineMarker_h_

Просмотреть файл

@ -68,10 +68,10 @@ TimelineConsumers::GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore)
void
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData)
MarkerTracingType aTracingType)
{
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aDocShell, aName, aMetaData)));
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTracingType)));
}
}
@ -79,10 +79,10 @@ void
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData)
MarkerTracingType aTracingType)
{
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aDocShell, aName, aTime, aMetaData)));
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTime, aTracingType)));
}
}
@ -98,18 +98,18 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
void
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData)
MarkerTracingType aTracingType)
{
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aMetaData);
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTracingType);
}
void
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData)
MarkerTracingType aTracingType)
{
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aMetaData);
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aTracingType);
}
void
@ -122,18 +122,18 @@ TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
void
TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
TracingMetadata aMetaData)
MarkerTracingType aTracingType)
{
for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
!range.empty();
range.popFront()) {
AddMarkerForDocShell(range.front(), aName, aMetaData);
AddMarkerForDocShell(range.front(), aName, aTracingType);
}
}
void
TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
TracingMetadata aMetaData)
MarkerTracingType aTracingType)
{
Vector<nsRefPtr<nsDocShell>> docShells;
if (!GetKnownDocShells(docShells)) {
@ -142,7 +142,7 @@ TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
return;
}
AddMarkerForDocShellsList(docShells, aName, aMetaData);
AddMarkerForDocShellsList(docShells, aName, aTracingType);
}
} // namespace mozilla

Просмотреть файл

@ -10,14 +10,16 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Vector.h"
#include "GeckoProfiler.h"
#include "mozilla/TimeStamp.h"
#include "TimelineMarkerEnums.h"
class nsDocShell;
class nsIDocShell;
class TimelineMarker;
namespace mozilla {
class ObservedDocShell;
class TimelineMarker;
class TimelineConsumers
{
@ -46,19 +48,19 @@ public:
// relevant for a specific docshell.
static void AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData);
MarkerTracingType aTracingType);
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData);
MarkerTracingType aTracingType);
static void AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData);
MarkerTracingType aTracingType);
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData);
MarkerTracingType aTracingType);
// These methods register and receive ownership of an already created marker,
// relevant for a specific docshell.
@ -70,12 +72,12 @@ public:
// This method creates custom markers, relevant for a list of docshells.
static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
TracingMetadata aMetaData);
MarkerTracingType aTracingType);
// This method creates custom markers, none of which have to be tied to a
// particular docshell.
static void AddMarkerForAllObservedDocShells(const char* aName,
TracingMetadata aMetaData);
MarkerTracingType aTracingType);
};
} // namespace mozilla

Просмотреть файл

@ -4,50 +4,61 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDocShell.h"
#include "TimelineMarker.h"
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
TracingMetadata aMetaData)
namespace mozilla {
TimelineMarker::TimelineMarker(const char* aName,
MarkerTracingType aTracingType,
MarkerStackRequest aStackRequest)
: mName(aName)
, mMetaData(aMetaData)
, mTracingType(aTracingType)
{
MOZ_COUNT_CTOR(TimelineMarker);
MOZ_ASSERT(aName);
aDocShell->Now(&mTime);
if (aMetaData == TRACING_INTERVAL_START || aMetaData == TRACING_TIMESTAMP) {
CaptureStack();
}
SetCurrentTime();
CaptureStackIfNecessary(aTracingType, aStackRequest);
}
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
const mozilla::TimeStamp& aTime,
TracingMetadata aMetaData)
: TimelineMarker(aDocShell, aName, aMetaData)
{
bool isInconsistent = false;
mTime = (aTime - mozilla::TimeStamp::ProcessCreation(isInconsistent)).ToMilliseconds();
}
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
TracingMetadata aMetaData,
const nsAString& aCause,
TimelineStackRequest aStackRequest)
TimelineMarker::TimelineMarker(const char* aName,
const TimeStamp& aTime,
MarkerTracingType aTracingType,
MarkerStackRequest aStackRequest)
: mName(aName)
, mMetaData(aMetaData)
, mCause(aCause)
, mTracingType(aTracingType)
{
MOZ_COUNT_CTOR(TimelineMarker);
MOZ_ASSERT(aName);
aDocShell->Now(&mTime);
if ((aMetaData == TRACING_INTERVAL_START ||
aMetaData == TRACING_TIMESTAMP) &&
aStackRequest != NO_STACK) {
CaptureStack();
}
SetCustomTime(aTime);
CaptureStackIfNecessary(aTracingType, aStackRequest);
}
TimelineMarker::~TimelineMarker()
{
MOZ_COUNT_DTOR(TimelineMarker);
}
void
TimelineMarker::SetCurrentTime()
{
TimeStamp now = TimeStamp::Now();
SetCustomTime(now);
}
void
TimelineMarker::SetCustomTime(const TimeStamp& aTime)
{
bool isInconsistent = false;
mTime = (aTime - TimeStamp::ProcessCreation(isInconsistent)).ToMilliseconds();
}
void
TimelineMarker::CaptureStackIfNecessary(MarkerTracingType aTracingType,
MarkerStackRequest aStackRequest)
{
if ((aTracingType == MarkerTracingType::START ||
aTracingType == MarkerTracingType::TIMESTAMP) &&
aStackRequest != MarkerStackRequest::NO_STACK) {
CaptureStack();
}
}
} // namespace mozilla

Просмотреть файл

@ -4,66 +4,54 @@
* 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/. */
#ifndef TimelineMarker_h_
#define TimelineMarker_h_
#ifndef mozilla_TimelineMarker_h_
#define mozilla_TimelineMarker_h_
#include "nsString.h"
#include "GeckoProfiler.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
#include "nsContentUtils.h"
#include "jsapi.h"
#include "TimelineMarkerEnums.h"
class nsDocShell;
// Objects of this type can be added to the timeline. The class can
// also be subclassed to let a given marker creator provide custom
// details.
namespace mozilla {
namespace dom {
struct ProfileTimelineMarker;
}
// Objects of this type can be added to the timeline if there is an interested
// consumer. The class can also be subclassed to let a given marker creator
// provide custom details.
class TimelineMarker
{
public:
enum TimelineStackRequest { STACK, NO_STACK };
TimelineMarker(const char* aName,
MarkerTracingType aTracingType,
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
TimelineMarker(nsDocShell* aDocShell, const char* aName,
TracingMetadata aMetaData);
TimelineMarker(nsDocShell* aDocShell, const char* aName,
const mozilla::TimeStamp& aTime,
TracingMetadata aMetaData);
TimelineMarker(nsDocShell* aDocShell, const char* aName,
TracingMetadata aMetaData,
const nsAString& aCause,
TimelineStackRequest aStackRequest = STACK);
TimelineMarker(const char* aName,
const TimeStamp& aTime,
MarkerTracingType aTracingType,
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
virtual ~TimelineMarker();
// Check whether two markers should be considered the same,
// for the purpose of pairing start and end markers. Normally
// this definition suffices.
// Check whether two markers should be considered the same, for the purpose
// of pairing start and end markers. Normally this definition suffices.
virtual bool Equals(const TimelineMarker& aOther)
{
return strcmp(mName, aOther.mName) == 0;
}
// Add details specific to this marker type to aMarker. The
// standard elements have already been set. This method is
// called on both the starting and ending markers of a pair.
// Ordinarily the ending marker doesn't need to do anything
// here.
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker)
// Add details specific to this marker type to aMarker. The standard elements
// have already been set. This method is called on both the starting and
// ending markers of a pair. Ordinarily the ending marker doesn't need to do
// anything here.
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker)
{}
virtual void AddLayerRectangles(
mozilla::dom::Sequence<mozilla::dom::ProfileTimelineLayerRect>&)
{
MOZ_ASSERT_UNREACHABLE("can only be called on layer markers");
}
const char* GetName() const { return mName; }
TracingMetadata GetMetaData() const { return mMetaData; }
DOMHighResTimeStamp GetTime() const { return mTime; }
const nsString& GetCause() const { return mCause; }
MarkerTracingType GetTracingType() const { return mTracingType; }
JSObject* GetStack()
{
@ -89,15 +77,21 @@ protected:
private:
const char* mName;
TracingMetadata mMetaData;
DOMHighResTimeStamp mTime;
nsString mCause;
MarkerTracingType mTracingType;
// While normally it is not a good idea to make a persistent root,
// in this case changing nsDocShell to participate in cycle
// collection was deemed too invasive, and the markers are only held
// here temporarily to boot.
JS::PersistentRooted<JSObject*> mStackTrace;
void SetCurrentTime();
void SetCustomTime(const TimeStamp& aTime);
void CaptureStackIfNecessary(MarkerTracingType aTracingType,
MarkerStackRequest aStackRequest);
};
#endif /* TimelineMarker_h_ */
} // namespace mozilla
#endif /* mozilla_TimelineMarker_h_ */

Просмотреть файл

@ -0,0 +1,26 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_TimelineMarkerEnums_h_
#define mozilla_TimelineMarkerEnums_h_
namespace mozilla {
enum class MarkerTracingType {
START,
END,
TIMESTAMP,
HELPER_EVENT
};
enum class MarkerStackRequest {
STACK,
NO_STACK
};
} // namespace mozilla
#endif // mozilla_TimelineMarkerEnums_h_

Просмотреть файл

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_TimestampTimelineMarker_h_
#define mozilla_TimestampTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class TimestampTimelineMarker : public TimelineMarker
{
public:
explicit TimestampTimelineMarker(const nsAString& aCause)
: TimelineMarker("TimeStamp", MarkerTracingType::TIMESTAMP)
, mCause(aCause)
{}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (!mCause.IsEmpty()) {
aMarker.mCauseName.Construct(mCause);
}
}
private:
nsString mCause;
};
} // namespace mozilla
#endif // mozilla_TimestampTimelineMarker_h_

Просмотреть файл

@ -7,9 +7,16 @@
EXPORTS.mozilla += [
'AutoGlobalTimelineMarker.h',
'AutoTimelineMarker.h',
'ConsoleTimelineMarker.h',
'EventTimelineMarker.h',
'JavascriptTimelineMarker.h',
'LayerTimelineMarker.h',
'ObservedDocShell.h',
'RestyleTimelineMarker.h',
'TimelineConsumers.h',
'TimelineMarker.h',
'TimelineMarkerEnums.h',
'TimestampTimelineMarker.h',
]
UNIFIED_SOURCES += [

Просмотреть файл

@ -26,6 +26,8 @@
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsProxyRelease.h"
#include "mozilla/ConsoleTimelineMarker.h"
#include "mozilla/TimestampTimelineMarker.h"
#include "nsIConsoleAPIStorage.h"
#include "nsIDOMWindowUtils.h"
@ -985,59 +987,6 @@ ReifyStack(nsIStackFrame* aStack, nsTArray<ConsoleStackEntry>& aRefiedStack)
return NS_OK;
}
class ConsoleTimelineMarker : public TimelineMarker
{
public:
ConsoleTimelineMarker(nsDocShell* aDocShell,
TracingMetadata aMetaData,
const nsAString& aCause)
: TimelineMarker(aDocShell, "ConsoleTime", aMetaData, aCause)
{
if (aMetaData == TRACING_INTERVAL_END) {
CaptureStack();
}
}
virtual bool Equals(const TimelineMarker& aOther) override
{
if (!TimelineMarker::Equals(aOther)) {
return false;
}
// Console markers must have matching causes as well.
return GetCause() == aOther.GetCause();
}
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mCauseName.Construct(GetCause());
} else {
aMarker.mEndStack = GetStack();
}
}
};
class TimestampTimelineMarker : public TimelineMarker
{
public:
TimestampTimelineMarker(nsDocShell* aDocShell,
TracingMetadata aMetaData,
const nsAString& aCause)
: TimelineMarker(aDocShell, "TimeStamp", aMetaData, aCause)
{
MOZ_ASSERT(aMetaData == TRACING_TIMESTAMP);
}
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker) override
{
if (!GetCause().IsEmpty()) {
aMarker.mCauseName.Construct(GetCause());
}
}
};
// Queue a call to a console method. See the CALL_DELAY constant.
void
Console::Method(JSContext* aCx, MethodName aMethodName,
@ -1144,8 +1093,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
key.init(aCx, jsString);
}
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<TimestampTimelineMarker>(docShell, TRACING_TIMESTAMP, key);
UniquePtr<TimelineMarker> marker = MakeUnique<TimestampTimelineMarker>(key);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
// For `console.time(foo)` and `console.timeEnd(foo)`
@ -1155,10 +1103,9 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
if (jsString) {
nsAutoJSString key;
if (key.init(aCx, jsString)) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<ConsoleTimelineMarker>(docShell,
aMethodName == MethodTime ? TRACING_INTERVAL_START : TRACING_INTERVAL_END,
key);
UniquePtr<TimelineMarker> marker = MakeUnique<ConsoleTimelineMarker>(
key, aMethodName == MethodTime ? MarkerTracingType::START
: MarkerTracingType::END);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
}

Просмотреть файл

@ -33,60 +33,8 @@ namespace {
StaticRefPtr<BluetoothA2dpManager> sBluetoothA2dpManager;
bool sInShutdown = false;
static BluetoothA2dpInterface* sBtA2dpInterface;
static BluetoothAvrcpInterface* sBtAvrcpInterface;
} // namespace
/*
* This function maps attribute id and returns corresponding values
*/
static void
ConvertAttributeString(BluetoothAvrcpMediaAttribute aAttrId,
nsAString& aAttrStr)
{
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE_VOID(a2dp);
switch (aAttrId) {
case AVRCP_MEDIA_ATTRIBUTE_TITLE:
a2dp->GetTitle(aAttrStr);
/*
* bluedroid can only send string length AVRC_MAX_ATTR_STR_LEN - 1
*/
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
BT_WARNING("Truncate media item attribute title, length is over 255");
}
break;
case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
a2dp->GetArtist(aAttrStr);
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
BT_WARNING("Truncate media item attribute artist, length is over 255");
}
break;
case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
a2dp->GetAlbum(aAttrStr);
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
BT_WARNING("Truncate media item attribute album, length is over 255");
}
break;
case AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM:
aAttrStr.AppendInt(a2dp->GetMediaNumber());
break;
case AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS:
aAttrStr.AppendInt(a2dp->GetTotalMediaNumber());
break;
case AVRCP_MEDIA_ATTRIBUTE_GENRE:
// TODO: we currently don't support genre from music player
aAttrStr.Truncate();
break;
case AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME:
aAttrStr.AppendInt(a2dp->GetDuration());
break;
}
}
NS_IMETHODIMP
BluetoothA2dpManager::Observe(nsISupports* aSubject,
const char* aTopic,
@ -111,8 +59,9 @@ BluetoothA2dpManager::BluetoothA2dpManager()
void
BluetoothA2dpManager::Reset()
{
ResetA2dp();
ResetAvrcp();
mA2dpConnected = false;
mSinkState = SinkState::SINK_DISCONNECTED;
mController = nullptr;
}
static void
@ -137,42 +86,6 @@ AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
}
}
class BluetoothA2dpManager::InitAvrcpResultHandler final
: public BluetoothAvrcpResultHandler
{
public:
InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
(int)aStatus);
if (mRes) {
if (aStatus == STATUS_UNSUPPORTED) {
/* Not all versions of Bluedroid support AVRCP. So if the
* initialization fails with STATUS_UNSUPPORTED, we still
* signal success.
*/
mRes->Init();
} else {
mRes->OnError(NS_ERROR_FAILURE);
}
}
}
void Init() override
{
if (mRes) {
mRes->Init();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothA2dpManager::InitA2dpResultHandler final
: public BluetoothA2dpResultHandler
{
@ -192,20 +105,9 @@ public:
void Init() override
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
mRes->OnError(NS_ERROR_FAILURE);
return;
if (mRes) {
mRes->Init();
}
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
if (NS_WARN_IF(!sBtAvrcpInterface)) {
mRes->OnError(NS_ERROR_FAILURE);
return;
}
BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
sBtAvrcpInterface->Init(a2dpManager, new InitAvrcpResultHandler(mRes));
}
private:
@ -282,25 +184,6 @@ BluetoothA2dpManager::~BluetoothA2dpManager()
}
}
void
BluetoothA2dpManager::ResetA2dp()
{
mA2dpConnected = false;
mSinkState = SinkState::SINK_DISCONNECTED;
mController = nullptr;
}
void
BluetoothA2dpManager::ResetAvrcp()
{
mAvrcpConnected = false;
mDuration = 0;
mMediaNumber = 0;
mTotalMediaCount = 0;
mPosition = 0;
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
}
/*
* Static functions
*/
@ -344,46 +227,6 @@ BluetoothA2dpManager::Get()
return sBluetoothA2dpManager;
}
class BluetoothA2dpManager::CleanupAvrcpResultHandler final
: public BluetoothAvrcpResultHandler
{
public:
CleanupAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
(int)aStatus);
sBtAvrcpInterface = nullptr;
if (mRes) {
if (aStatus == STATUS_UNSUPPORTED) {
/* Not all versions of Bluedroid support AVRCP. So if the
* cleanup fails with STATUS_UNSUPPORTED, we still signal
* success.
*/
mRes->Deinit();
} else {
mRes->OnError(NS_ERROR_FAILURE);
}
}
}
void Cleanup() override
{
sBtAvrcpInterface = nullptr;
if (mRes) {
mRes->Deinit();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothA2dpManager::CleanupA2dpResultHandler final
: public BluetoothA2dpResultHandler
{
@ -407,12 +250,8 @@ public:
void Cleanup() override
{
sBtA2dpInterface = nullptr;
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
} else if (mRes) {
/* Not all backends support AVRCP. If it's not available
* we signal success from here.
*/
if (mRes) {
mRes->Deinit();
}
}
@ -432,15 +271,10 @@ public:
NS_IMETHOD Run() override
{
sBtA2dpInterface = nullptr;
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
} else if (mRes) {
/* Not all backends support AVRCP. If it's not available
* we signal success from here.
*/
if (mRes) {
mRes->Deinit();
}
return NS_OK;
}
@ -784,233 +618,7 @@ BluetoothA2dpManager::IsConnected()
}
/*
* In bluedroid stack case, there is no interface to know exactly
* avrcp connection status. All connection are managed by bluedroid stack.
*/
void
BluetoothA2dpManager::SetAvrcpConnected(bool aConnected)
{
mAvrcpConnected = aConnected;
if (!aConnected) {
ResetAvrcp();
}
}
bool
BluetoothA2dpManager::IsAvrcpConnected()
{
return mAvrcpConnected;
}
/*
* This function only updates meta data in BluetoothA2dpManager
* Send "Get Element Attributes response" in AvrcpGetElementAttrCallback
*/
void
BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
// Send track changed and position changed if track num is not the same.
// See also AVRCP 1.3 Spec 5.4.2
if (mMediaNumber != aMediaNumber &&
mTrackChangedNotifyType == AVRCP_NTF_INTERIM) {
BluetoothAvrcpNotificationParam param;
// convert to network big endian format
// since track stores as uint8[8]
// 56 = 8 * (AVRCP_UID_SIZE -1)
for (int i = 0; i < AVRCP_UID_SIZE; ++i) {
param.mTrack[i] = (aMediaNumber >> (56 - 8 * i));
}
mTrackChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_TRACK_CHANGE,
AVRCP_NTF_CHANGED,
param, nullptr);
if (mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
param.mSongPos = mPosition;
// EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
AVRCP_NTF_CHANGED,
param, nullptr);
}
}
mTitle.Assign(aTitle);
mArtist.Assign(aArtist);
mAlbum.Assign(aAlbum);
mMediaNumber = aMediaNumber;
mTotalMediaCount = aTotalMediaCount;
mDuration = aDuration;
}
/*
* This function is to reply AvrcpGetPlayStatusCallback (play-status-request)
* from media player application (Gaia side)
*/
void
BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
// always update playstatus first
sBtAvrcpInterface->GetPlayStatusRsp(aPlayStatus, aDuration,
aPosition, nullptr);
// when play status changed, send both play status and position
if (mPlayStatus != aPlayStatus &&
mPlayStatusChangedNotifyType == AVRCP_NTF_INTERIM) {
BluetoothAvrcpNotificationParam param;
param.mPlayStatus = aPlayStatus;
mPlayStatusChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_STATUS_CHANGED,
AVRCP_NTF_CHANGED,
param, nullptr);
}
if (mPosition != aPosition &&
mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
BluetoothAvrcpNotificationParam param;
param.mSongPos = aPosition;
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
AVRCP_NTF_CHANGED,
param, nullptr);
}
mDuration = aDuration;
mPosition = aPosition;
mPlayStatus = aPlayStatus;
}
/*
* This function handles RegisterNotification request from
* AvrcpRegisterNotificationCallback, which updates current
* track/status/position status in the INTERRIM response.
*
* aParam is only valid when position changed
*/
void
BluetoothA2dpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
uint32_t aParam)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
BluetoothAvrcpNotificationParam param;
switch (aEvent) {
case AVRCP_EVENT_PLAY_STATUS_CHANGED:
mPlayStatusChangedNotifyType = AVRCP_NTF_INTERIM;
param.mPlayStatus = mPlayStatus;
break;
case AVRCP_EVENT_TRACK_CHANGE:
// In AVRCP 1.3 and 1.4, the identifier parameter of EVENT_TRACK_CHANGED
// is different.
// AVRCP 1.4: If no track is selected, we shall return 0xFFFFFFFFFFFFFFFF,
// otherwise return 0x0 in the INTERRIM response. The expanded text in
// version 1.4 is to allow for new UID feature. As for AVRCP 1.3, we shall
// return 0xFFFFFFFF. Since PTS enforces to check this part to comply with
// the most updated spec.
mTrackChangedNotifyType = AVRCP_NTF_INTERIM;
// needs to convert to network big endian format since track stores
// as uint8[8]. 56 = 8 * (BTRC_UID_SIZE -1).
for (int index = 0; index < AVRCP_UID_SIZE; ++index) {
// We cannot easily check if a track is selected, so whenever A2DP is
// streaming, we assume a track is selected.
if (mSinkState == BluetoothA2dpManager::SinkState::SINK_PLAYING) {
param.mTrack[index] = 0x0;
} else {
param.mTrack[index] = 0xFF;
}
}
break;
case AVRCP_EVENT_PLAY_POS_CHANGED:
// If no track is selected, return 0xFFFFFFFF in the INTERIM response
mPlayPosChangedNotifyType = AVRCP_NTF_INTERIM;
if (mSinkState == BluetoothA2dpManager::SinkState::SINK_PLAYING) {
param.mSongPos = mPosition;
} else {
param.mSongPos = 0xFFFFFFFF;
}
mPlaybackInterval = aParam;
break;
case AVRCP_EVENT_APP_SETTINGS_CHANGED:
mAppSettingsChangedNotifyType = AVRCP_NTF_INTERIM;
param.mNumAttr = 2;
param.mIds[0] = AVRCP_PLAYER_ATTRIBUTE_REPEAT;
param.mValues[0] = AVRCP_PLAYER_VAL_OFF_REPEAT;
param.mIds[1] = AVRCP_PLAYER_ATTRIBUTE_SHUFFLE;
param.mValues[1] = AVRCP_PLAYER_VAL_OFF_SHUFFLE;
break;
default:
break;
}
sBtAvrcpInterface->RegisterNotificationRsp(aEvent, AVRCP_NTF_INTERIM,
param, nullptr);
}
void
BluetoothA2dpManager::GetAlbum(nsAString& aAlbum)
{
aAlbum.Assign(mAlbum);
}
uint32_t
BluetoothA2dpManager::GetDuration()
{
return mDuration;
}
ControlPlayStatus
BluetoothA2dpManager::GetPlayStatus()
{
return mPlayStatus;
}
uint32_t
BluetoothA2dpManager::GetPosition()
{
return mPosition;
}
uint64_t
BluetoothA2dpManager::GetMediaNumber()
{
return mMediaNumber;
}
uint64_t
BluetoothA2dpManager::GetTotalMediaNumber()
{
return mTotalMediaCount;
}
void
BluetoothA2dpManager::GetTitle(nsAString& aTitle)
{
aTitle.Assign(mTitle);
}
void
BluetoothA2dpManager::GetArtist(nsAString& aArtist)
{
aArtist.Assign(mArtist);
}
/*
* A2DP Notifications
* Notifications
*/
void
@ -1054,179 +662,4 @@ BluetoothA2dpManager::AudioStateNotification(BluetoothA2dpAudioState aState,
nsString(aBdAddr), props));
}
/*
* AVRCP Notifications
*/
void
BluetoothA2dpManager::GetPlayStatusNotification()
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
return;
}
bs->DistributeSignal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
NS_LITERAL_STRING(KEY_ADAPTER));
}
/* Player application settings is optional for AVRCP 1.3. B2G
* currently does not support player-application-setting related
* functionality.
*/
void
BluetoothA2dpManager::ListPlayerAppAttrNotification()
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothA2dpManager::ListPlayerAppValuesNotification(
BluetoothAvrcpPlayerAttribute aAttrId)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothA2dpManager::GetPlayerAppValueNotification(
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothA2dpManager::GetPlayerAppAttrsTextNotification(
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothA2dpManager::GetPlayerAppValuesTextNotification(
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothA2dpManager::SetPlayerAppValueNotification(
const BluetoothAvrcpPlayerSettings& aSettings)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
/* This method returns element attributes, which are requested from
* CT. Unlike BlueZ it calls only UpdateMetaData. Bluedroid does not cache
* meta-data information, but instead uses |GetElementAttrNotifications|
* and |GetElementAttrRsp| request them.
*/
void
BluetoothA2dpManager::GetElementAttrNotification(
uint8_t aNumAttrs, const BluetoothAvrcpMediaAttribute* aAttrs)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoArrayPtr<BluetoothAvrcpElementAttribute> attrs(
new BluetoothAvrcpElementAttribute[aNumAttrs]);
for (uint8_t i = 0; i < aNumAttrs; ++i) {
attrs[i].mId = aAttrs[i];
ConvertAttributeString(
static_cast<BluetoothAvrcpMediaAttribute>(attrs[i].mId),
attrs[i].mValue);
}
MOZ_ASSERT(sBtAvrcpInterface);
sBtAvrcpInterface->GetElementAttrRsp(aNumAttrs, attrs, nullptr);
}
void
BluetoothA2dpManager::RegisterNotificationNotification(
BluetoothAvrcpEvent aEvent, uint32_t aParam)
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
if (!a2dp) {
return;
}
a2dp->UpdateRegisterNotification(aEvent, aParam);
}
/* This method is used to get CT features from the Feature Bit Mask. If
* Advanced Control Player bit is set, the CT supports volume sync (absolute
* volume feature). If Browsing bit is set, AVRCP 1.4 Browse feature will be
* supported.
*/
void
BluetoothA2dpManager::RemoteFeatureNotification(
const nsAString& aBdAddr, unsigned long aFeatures)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP 1.4 absolute volume/browse
}
/* This method is used to get notifications about volume changes on the
* remote car kit (if it supports AVRCP 1.4), not notification from phone.
*/
void
BluetoothA2dpManager::VolumeChangeNotification(uint8_t aVolume,
uint8_t aCType)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP 1.4 absolute volume/browse
}
void
BluetoothA2dpManager::PassthroughCmdNotification(int aId, int aKeyState)
{
MOZ_ASSERT(NS_IsMainThread());
// Fast-forward and rewind key events won't be generated from bluedroid
// stack after ANDROID_VERSION > 18, but via passthrough callback.
nsAutoString name;
NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
aKeyState == AVRC_KEY_RELEASE_STATE);
switch (aId) {
case AVRC_ID_FAST_FOR:
if (aKeyState == AVRC_KEY_PRESS_STATE) {
name.AssignLiteral("media-fast-forward-button-press");
} else {
name.AssignLiteral("media-fast-forward-button-release");
}
break;
case AVRC_ID_REWIND:
if (aKeyState == AVRC_KEY_PRESS_STATE) {
name.AssignLiteral("media-rewind-button-press");
} else {
name.AssignLiteral("media-rewind-button-release");
}
break;
default:
BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
return;
}
NS_NAMED_LITERAL_STRING(type, "media-button");
BroadcastSystemMessage(type, BluetoothValue(name));
}
NS_IMPL_ISUPPORTS(BluetoothA2dpManager, nsIObserver)

Просмотреть файл

@ -15,7 +15,6 @@
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothA2dpManager : public BluetoothProfileManagerBase
, public BluetoothA2dpNotificationHandler
, public BluetoothAvrcpNotificationHandler
{
public:
BT_DECL_PROFILE_MGR_BASE
@ -42,27 +41,6 @@ public:
// A2DP-specific functions
void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);
// AVRCP-specific functions
void SetAvrcpConnected(bool aConnected);
bool IsAvrcpConnected();
void UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration);
void UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus);
void UpdateRegisterNotification(BluetoothAvrcpEvent aEvent, uint32_t aParam);
void GetAlbum(nsAString& aAlbum);
uint32_t GetDuration();
ControlPlayStatus GetPlayStatus();
uint32_t GetPosition();
uint64_t GetMediaNumber();
uint64_t GetTotalMediaNumber();
void GetTitle(nsAString& aTitle);
void GetArtist(nsAString& aArtist);
void HandleBackendError();
protected:
@ -71,16 +49,12 @@ protected:
private:
class CleanupA2dpResultHandler;
class CleanupA2dpResultHandlerRunnable;
class CleanupAvrcpResultHandler;
class ConnectResultHandler;
class DisconnectResultHandler;
class InitA2dpResultHandler;
class InitAvrcpResultHandler;
class OnErrorProfileResultHandlerRunnable;
BluetoothA2dpManager();
void ResetA2dp();
void ResetAvrcp();
void HandleShutdown();
void NotifyConnectionStatusChanged();
@ -90,79 +64,12 @@ private:
void AudioStateNotification(BluetoothA2dpAudioState aState,
const nsAString& aBdAddr) override;
void GetPlayStatusNotification() override;
void ListPlayerAppAttrNotification() override;
void ListPlayerAppValuesNotification(
BluetoothAvrcpPlayerAttribute aAttrId) override;
void GetPlayerAppValueNotification(
uint8_t aNumAttrs,
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
void GetPlayerAppAttrsTextNotification(
uint8_t aNumAttrs,
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
void GetPlayerAppValuesTextNotification(
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues) override;
void SetPlayerAppValueNotification(
const BluetoothAvrcpPlayerSettings& aSettings) override;
void GetElementAttrNotification(
uint8_t aNumAttrs,
const BluetoothAvrcpMediaAttribute* aAttrs) override;
void RegisterNotificationNotification(
BluetoothAvrcpEvent aEvent, uint32_t aParam) override;
void RemoteFeatureNotification(
const nsAString& aBdAddr, unsigned long aFeatures) override;
void VolumeChangeNotification(uint8_t aVolume, uint8_t aCType) override;
void PassthroughCmdNotification(int aId, int aKeyState) override;
nsString mDeviceAddress;
nsRefPtr<BluetoothProfileController> mController;
// A2DP data member
bool mA2dpConnected;
SinkState mSinkState;
// AVRCP data member
bool mAvrcpConnected;
nsString mAlbum;
nsString mArtist;
nsString mTitle;
uint32_t mDuration;
uint64_t mMediaNumber;
uint64_t mTotalMediaCount;
uint32_t mPosition;
/*
* mPlaybackInterval specifies the time interval (in seconds) at which
* the change in playback position will be notified. If the song is being
* forwarded / rewound, a notification will be received whenever the playback
* position will change by this value.
*/
uint32_t mPlaybackInterval;
ControlPlayStatus mPlayStatus;
/*
* Notification types: 1. INTERIM 2. CHANGED
* 1. The initial response to this Notify command shall be an INTERIM
* response with current status.
* 2. The following response shall be a CHANGED response with the updated
* status.
* mPlayStatusChangedNotifType, mTrackChangedNotifType,
* mPlayPosChangedNotifType represents current RegisterNotification
* notification type.
*/
BluetoothAvrcpNotification mPlayStatusChangedNotifyType;
BluetoothAvrcpNotification mTrackChangedNotifyType;
BluetoothAvrcpNotification mPlayPosChangedNotifyType;
BluetoothAvrcpNotification mAppSettingsChangedNotifyType;
};
END_BLUETOOTH_NAMESPACE

Просмотреть файл

@ -0,0 +1,816 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "BluetoothAvrcpManager.h"
#include "BluetoothCommon.h"
#include "BluetoothService.h"
#include "BluetoothSocket.h"
#include "BluetoothUtils.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "MainThreadUtils.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h"
using namespace mozilla;
USING_BLUETOOTH_NAMESPACE
// AVRC_ID op code follows bluedroid avrc_defs.h
#define AVRC_ID_REWIND 0x48
#define AVRC_ID_FAST_FOR 0x49
#define AVRC_KEY_PRESS_STATE 1
#define AVRC_KEY_RELEASE_STATE 0
// bluedroid bt_rc.h
#define AVRC_MAX_ATTR_STR_LEN 255
namespace {
StaticRefPtr<BluetoothAvrcpManager> sBluetoothAvrcpManager;
bool sInShutdown = false;
static BluetoothAvrcpInterface* sBtAvrcpInterface;
} // namespace
/*
* This function maps attribute id and returns corresponding values
*/
static void
ConvertAttributeString(BluetoothAvrcpMediaAttribute aAttrId,
nsAString& aAttrStr)
{
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
NS_ENSURE_TRUE_VOID(avrcp);
switch (aAttrId) {
case AVRCP_MEDIA_ATTRIBUTE_TITLE:
avrcp->GetTitle(aAttrStr);
/*
* bluedroid can only send string length AVRC_MAX_ATTR_STR_LEN - 1
*/
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
BT_WARNING("Truncate media item attribute title, length is over 255");
}
break;
case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
avrcp->GetArtist(aAttrStr);
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
BT_WARNING("Truncate media item attribute artist, length is over 255");
}
break;
case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
avrcp->GetAlbum(aAttrStr);
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
BT_WARNING("Truncate media item attribute album, length is over 255");
}
break;
case AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM:
aAttrStr.AppendInt(avrcp->GetMediaNumber());
break;
case AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS:
aAttrStr.AppendInt(avrcp->GetTotalMediaNumber());
break;
case AVRCP_MEDIA_ATTRIBUTE_GENRE:
// TODO: we currently don't support genre from music player
aAttrStr.Truncate();
break;
case AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME:
aAttrStr.AppendInt(avrcp->GetDuration());
break;
}
}
NS_IMETHODIMP
BluetoothAvrcpManager::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(sBluetoothAvrcpManager);
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
HandleShutdown();
return NS_OK;
}
MOZ_ASSERT(false, "BluetoothAvrcpManager got unexpected topic!");
return NS_ERROR_UNEXPECTED;
}
BluetoothAvrcpManager::BluetoothAvrcpManager()
{
Reset();
}
void
BluetoothAvrcpManager::Reset()
{
mAvrcpConnected = false;
mDuration = 0;
mMediaNumber = 0;
mTotalMediaCount = 0;
mPosition = 0;
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
}
class BluetoothAvrcpManager::InitAvrcpResultHandler final
: public BluetoothAvrcpResultHandler
{
public:
InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
(int)aStatus);
if (mRes) {
if (aStatus == STATUS_UNSUPPORTED) {
/* Not all versions of Bluedroid support AVRCP. So if the
* initialization fails with STATUS_UNSUPPORTED, we still
* signal success.
*/
mRes->Init();
} else {
mRes->OnError(NS_ERROR_FAILURE);
}
}
}
void Init() override
{
if (mRes) {
mRes->Init();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothAvrcpManager::OnErrorProfileResultHandlerRunnable final
: public nsRunnable
{
public:
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() override
{
mRes->OnError(mRv);
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
nsresult mRv;
};
/*
* This function will be only called when Bluetooth is turning on.
*/
// static
void
BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no HFP interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
}
return;
}
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
if (NS_WARN_IF(!sBtAvrcpInterface)) {
// If there's no AVRCP interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
}
return;
}
BluetoothAvrcpManager* avrcpManager = BluetoothAvrcpManager::Get();
sBtAvrcpInterface->Init(avrcpManager, new InitAvrcpResultHandler(aRes));
}
BluetoothAvrcpManager::~BluetoothAvrcpManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
}
/*
* Static functions
*/
//static
BluetoothAvrcpManager*
BluetoothAvrcpManager::Get()
{
MOZ_ASSERT(NS_IsMainThread());
// If sBluetoothAvrcpManager already exists, exit early
if (sBluetoothAvrcpManager) {
return sBluetoothAvrcpManager;
}
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothAvrcpManager* manager = new BluetoothAvrcpManager();
sBluetoothAvrcpManager = manager;
return sBluetoothAvrcpManager;
}
class BluetoothAvrcpManager::CleanupAvrcpResultHandler final
: public BluetoothAvrcpResultHandler
{
public:
CleanupAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
(int)aStatus);
sBtAvrcpInterface = nullptr;
if (mRes) {
if (aStatus == STATUS_UNSUPPORTED) {
/* Not all versions of Bluedroid support AVRCP. So if the
* cleanup fails with STATUS_UNSUPPORTED, we still signal
* success.
*/
mRes->Deinit();
} else {
mRes->OnError(NS_ERROR_FAILURE);
}
}
}
void Cleanup() override
{
sBtAvrcpInterface = nullptr;
if (mRes) {
mRes->Deinit();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothAvrcpManager::CleanupAvrcpResultHandlerRunnable final
: public nsRunnable
{
public:
CleanupAvrcpResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
NS_IMETHOD Run() override
{
sBtAvrcpInterface = nullptr;
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
} else if (mRes) {
/* Not all backends support AVRCP. If it's not available
* we signal success from here.
*/
mRes->Deinit();
}
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
// static
void
BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if A2DP was initialized.
nsRefPtr<nsRunnable> r = new CleanupAvrcpResultHandlerRunnable(aRes);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
}
}
}
void
BluetoothAvrcpManager::HandleShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
sInShutdown = true;
Disconnect(nullptr);
sBluetoothAvrcpManager = nullptr;
}
void
BluetoothAvrcpManager::Connect(const nsAString& aDeviceAddress,
BluetoothProfileController* aController)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
MOZ_ASSERT(aController);
// AVRCP doesn't require connecting. We just set the remote address here.
mDeviceAddress = aDeviceAddress;
SetConnected(true);
OnConnect(EmptyString());
}
void
BluetoothAvrcpManager::Disconnect(BluetoothProfileController* aController)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mController);
mDeviceAddress.Truncate();
SetConnected(false);
OnDisconnect(EmptyString());
}
void
BluetoothAvrcpManager::OnConnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
/**
* On the one hand, notify the controller that we've done for outbound
* connections. On the other hand, we do nothing for inbound connections.
*/
NS_ENSURE_TRUE_VOID(mController);
nsRefPtr<BluetoothProfileController> controller = mController.forget();
controller->NotifyCompletion(aErrorStr);
}
void
BluetoothAvrcpManager::OnDisconnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
/**
* On the one hand, notify the controller that we've done for outbound
* connections. On the other hand, we do nothing for inbound connections.
*/
NS_ENSURE_TRUE_VOID(mController);
nsRefPtr<BluetoothProfileController> controller = mController.forget();
controller->NotifyCompletion(aErrorStr);
Reset();
}
void
BluetoothAvrcpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,
int aChannel)
{ }
void
BluetoothAvrcpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
{ }
void
BluetoothAvrcpManager::GetAddress(nsAString& aDeviceAddress)
{
aDeviceAddress = mDeviceAddress;
}
bool
BluetoothAvrcpManager::IsConnected()
{
return mAvrcpConnected;
}
/*
* In bluedroid stack case, there is no interface to know exactly
* avrcp connection status. All connection are managed by bluedroid stack.
*/
void
BluetoothAvrcpManager::SetConnected(bool aConnected)
{
mAvrcpConnected = aConnected;
if (!aConnected) {
Reset();
}
}
/*
* This function only updates meta data in BluetoothAvrcpManager. Send
* "Get Element Attributes response" in AvrcpGetElementAttrCallback
*/
void
BluetoothAvrcpManager::UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
// Send track changed and position changed if track num is not the same.
// See also AVRCP 1.3 Spec 5.4.2
if (mMediaNumber != aMediaNumber &&
mTrackChangedNotifyType == AVRCP_NTF_INTERIM) {
BluetoothAvrcpNotificationParam param;
// convert to network big endian format
// since track stores as uint8[8]
// 56 = 8 * (AVRCP_UID_SIZE -1)
for (int i = 0; i < AVRCP_UID_SIZE; ++i) {
param.mTrack[i] = (aMediaNumber >> (56 - 8 * i));
}
mTrackChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_TRACK_CHANGE,
AVRCP_NTF_CHANGED,
param, nullptr);
if (mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
param.mSongPos = mPosition;
// EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
AVRCP_NTF_CHANGED,
param, nullptr);
}
}
mTitle.Assign(aTitle);
mArtist.Assign(aArtist);
mAlbum.Assign(aAlbum);
mMediaNumber = aMediaNumber;
mTotalMediaCount = aTotalMediaCount;
mDuration = aDuration;
}
/*
* This function is to reply AvrcpGetPlayStatusCallback (play-status-request)
* from media player application (Gaia side)
*/
void
BluetoothAvrcpManager::UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
// always update playstatus first
sBtAvrcpInterface->GetPlayStatusRsp(aPlayStatus, aDuration,
aPosition, nullptr);
// when play status changed, send both play status and position
if (mPlayStatus != aPlayStatus &&
mPlayStatusChangedNotifyType == AVRCP_NTF_INTERIM) {
BluetoothAvrcpNotificationParam param;
param.mPlayStatus = aPlayStatus;
mPlayStatusChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_STATUS_CHANGED,
AVRCP_NTF_CHANGED,
param, nullptr);
}
if (mPosition != aPosition &&
mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
BluetoothAvrcpNotificationParam param;
param.mSongPos = aPosition;
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
AVRCP_NTF_CHANGED,
param, nullptr);
}
mDuration = aDuration;
mPosition = aPosition;
mPlayStatus = aPlayStatus;
}
/*
* This function handles RegisterNotification request from
* AvrcpRegisterNotificationCallback, which updates current
* track/status/position status in the INTERRIM response.
*
* aParam is only valid when position changed
*/
void
BluetoothAvrcpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
uint32_t aParam)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
BluetoothAvrcpNotificationParam param;
switch (aEvent) {
case AVRCP_EVENT_PLAY_STATUS_CHANGED:
mPlayStatusChangedNotifyType = AVRCP_NTF_INTERIM;
param.mPlayStatus = mPlayStatus;
break;
case AVRCP_EVENT_TRACK_CHANGE:
// In AVRCP 1.3 and 1.4, the identifier parameter of EVENT_TRACK_CHANGED
// is different.
// AVRCP 1.4: If no track is selected, we shall return 0xFFFFFFFFFFFFFFFF,
// otherwise return 0x0 in the INTERRIM response. The expanded text in
// version 1.4 is to allow for new UID feature. As for AVRCP 1.3, we shall
// return 0xFFFFFFFF. Since PTS enforces to check this part to comply with
// the most updated spec.
mTrackChangedNotifyType = AVRCP_NTF_INTERIM;
// needs to convert to network big endian format since track stores
// as uint8[8]. 56 = 8 * (BTRC_UID_SIZE -1).
for (int index = 0; index < AVRCP_UID_SIZE; ++index) {
// We cannot easily check if a track is selected, so whenever A2DP is
// streaming, we assume a track is selected.
if (mPlayStatus == ControlPlayStatus::PLAYSTATUS_PLAYING) {
param.mTrack[index] = 0x0;
} else {
param.mTrack[index] = 0xFF;
}
}
break;
case AVRCP_EVENT_PLAY_POS_CHANGED:
// If no track is selected, return 0xFFFFFFFF in the INTERIM response
mPlayPosChangedNotifyType = AVRCP_NTF_INTERIM;
if (mPlayStatus == ControlPlayStatus::PLAYSTATUS_PLAYING) {
param.mSongPos = mPosition;
} else {
param.mSongPos = 0xFFFFFFFF;
}
mPlaybackInterval = aParam;
break;
case AVRCP_EVENT_APP_SETTINGS_CHANGED:
mAppSettingsChangedNotifyType = AVRCP_NTF_INTERIM;
param.mNumAttr = 2;
param.mIds[0] = AVRCP_PLAYER_ATTRIBUTE_REPEAT;
param.mValues[0] = AVRCP_PLAYER_VAL_OFF_REPEAT;
param.mIds[1] = AVRCP_PLAYER_ATTRIBUTE_SHUFFLE;
param.mValues[1] = AVRCP_PLAYER_VAL_OFF_SHUFFLE;
break;
default:
break;
}
sBtAvrcpInterface->RegisterNotificationRsp(aEvent, AVRCP_NTF_INTERIM,
param, nullptr);
}
void
BluetoothAvrcpManager::GetAlbum(nsAString& aAlbum)
{
aAlbum.Assign(mAlbum);
}
uint32_t
BluetoothAvrcpManager::GetDuration()
{
return mDuration;
}
ControlPlayStatus
BluetoothAvrcpManager::GetPlayStatus()
{
return mPlayStatus;
}
uint32_t
BluetoothAvrcpManager::GetPosition()
{
return mPosition;
}
uint64_t
BluetoothAvrcpManager::GetMediaNumber()
{
return mMediaNumber;
}
uint64_t
BluetoothAvrcpManager::GetTotalMediaNumber()
{
return mTotalMediaCount;
}
void
BluetoothAvrcpManager::GetTitle(nsAString& aTitle)
{
aTitle.Assign(mTitle);
}
void
BluetoothAvrcpManager::GetArtist(nsAString& aArtist)
{
aArtist.Assign(mArtist);
}
/*
* Notifications
*/
void
BluetoothAvrcpManager::GetPlayStatusNotification()
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
return;
}
bs->DistributeSignal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
NS_LITERAL_STRING(KEY_ADAPTER));
}
/* Player application settings is optional for AVRCP 1.3. B2G
* currently does not support player-application-setting related
* functionality.
*/
void
BluetoothAvrcpManager::ListPlayerAppAttrNotification()
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothAvrcpManager::ListPlayerAppValuesNotification(
BluetoothAvrcpPlayerAttribute aAttrId)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothAvrcpManager::GetPlayerAppValueNotification(
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothAvrcpManager::GetPlayerAppAttrsTextNotification(
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothAvrcpManager::GetPlayerAppValuesTextNotification(
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
void
BluetoothAvrcpManager::SetPlayerAppValueNotification(
const BluetoothAvrcpPlayerSettings& aSettings)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP application-setting-related functions
}
/* This method returns element attributes, which are requested from
* CT. Unlike BlueZ it calls only UpdateMetaData. Bluedroid does not cache
* meta-data information, but instead uses |GetElementAttrNotifications|
* and |GetElementAttrRsp| request them.
*/
void
BluetoothAvrcpManager::GetElementAttrNotification(
uint8_t aNumAttrs, const BluetoothAvrcpMediaAttribute* aAttrs)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoArrayPtr<BluetoothAvrcpElementAttribute> attrs(
new BluetoothAvrcpElementAttribute[aNumAttrs]);
for (uint8_t i = 0; i < aNumAttrs; ++i) {
attrs[i].mId = aAttrs[i];
ConvertAttributeString(
static_cast<BluetoothAvrcpMediaAttribute>(attrs[i].mId),
attrs[i].mValue);
}
MOZ_ASSERT(sBtAvrcpInterface);
sBtAvrcpInterface->GetElementAttrRsp(aNumAttrs, attrs, nullptr);
}
void
BluetoothAvrcpManager::RegisterNotificationNotification(
BluetoothAvrcpEvent aEvent, uint32_t aParam)
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
if (!avrcp) {
return;
}
avrcp->UpdateRegisterNotification(aEvent, aParam);
}
/* This method is used to get CT features from the Feature Bit Mask. If
* Advanced Control Player bit is set, the CT supports volume sync (absolute
* volume feature). If Browsing bit is set, AVRCP 1.4 Browse feature will be
* supported.
*/
void
BluetoothAvrcpManager::RemoteFeatureNotification(
const nsAString& aBdAddr, unsigned long aFeatures)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP 1.4 absolute volume/browse
}
/* This method is used to get notifications about volume changes on the
* remote car kit (if it supports AVRCP 1.4), not notification from phone.
*/
void
BluetoothAvrcpManager::VolumeChangeNotification(uint8_t aVolume,
uint8_t aCType)
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: Support AVRCP 1.4 absolute volume/browse
}
void
BluetoothAvrcpManager::PassthroughCmdNotification(int aId, int aKeyState)
{
MOZ_ASSERT(NS_IsMainThread());
// Fast-forward and rewind key events won't be generated from bluedroid
// stack after ANDROID_VERSION > 18, but via passthrough callback.
nsAutoString name;
NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
aKeyState == AVRC_KEY_RELEASE_STATE);
switch (aId) {
case AVRC_ID_FAST_FOR:
if (aKeyState == AVRC_KEY_PRESS_STATE) {
name.AssignLiteral("media-fast-forward-button-press");
} else {
name.AssignLiteral("media-fast-forward-button-release");
}
break;
case AVRC_ID_REWIND:
if (aKeyState == AVRC_KEY_PRESS_STATE) {
name.AssignLiteral("media-rewind-button-press");
} else {
name.AssignLiteral("media-rewind-button-release");
}
break;
default:
BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
return;
}
NS_NAMED_LITERAL_STRING(type, "media-button");
BroadcastSystemMessage(type, BluetoothValue(name));
}
NS_IMPL_ISUPPORTS(BluetoothAvrcpManager, nsIObserver)

Просмотреть файл

@ -0,0 +1,147 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
#define mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
#include "BluetoothCommon.h"
#include "BluetoothInterface.h"
#include "BluetoothProfileController.h"
#include "BluetoothProfileManagerBase.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothAvrcpManager : public BluetoothProfileManagerBase
, public BluetoothAvrcpNotificationHandler
{
public:
BT_DECL_PROFILE_MGR_BASE
virtual void GetName(nsACString& aName)
{
aName.AssignLiteral("AVRCP");
}
enum SinkState {
SINK_UNKNOWN,
SINK_DISCONNECTED,
SINK_CONNECTING,
SINK_CONNECTED,
SINK_PLAYING,
};
static BluetoothAvrcpManager* Get();
static void InitAvrcpInterface(BluetoothProfileResultHandler* aRes);
static void DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes);
void SetConnected(bool aConnected);
void UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration);
void UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus);
void UpdateRegisterNotification(BluetoothAvrcpEvent aEvent, uint32_t aParam);
void GetAlbum(nsAString& aAlbum);
uint32_t GetDuration();
ControlPlayStatus GetPlayStatus();
uint32_t GetPosition();
uint64_t GetMediaNumber();
uint64_t GetTotalMediaNumber();
void GetTitle(nsAString& aTitle);
void GetArtist(nsAString& aArtist);
void HandleBackendError();
protected:
virtual ~BluetoothAvrcpManager();
private:
class CleanupAvrcpResultHandler;
class CleanupAvrcpResultHandlerRunnable;
class ConnectResultHandler;
class DisconnectResultHandler;
class InitAvrcpResultHandler;
class OnErrorProfileResultHandlerRunnable;
BluetoothAvrcpManager();
void HandleShutdown();
void NotifyConnectionStatusChanged();
void GetPlayStatusNotification() override;
void ListPlayerAppAttrNotification() override;
void ListPlayerAppValuesNotification(
BluetoothAvrcpPlayerAttribute aAttrId) override;
void GetPlayerAppValueNotification(
uint8_t aNumAttrs,
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
void GetPlayerAppAttrsTextNotification(
uint8_t aNumAttrs,
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
void GetPlayerAppValuesTextNotification(
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues) override;
void SetPlayerAppValueNotification(
const BluetoothAvrcpPlayerSettings& aSettings) override;
void GetElementAttrNotification(
uint8_t aNumAttrs,
const BluetoothAvrcpMediaAttribute* aAttrs) override;
void RegisterNotificationNotification(
BluetoothAvrcpEvent aEvent, uint32_t aParam) override;
void RemoteFeatureNotification(
const nsAString& aBdAddr, unsigned long aFeatures) override;
void VolumeChangeNotification(uint8_t aVolume, uint8_t aCType) override;
void PassthroughCmdNotification(int aId, int aKeyState) override;
nsString mDeviceAddress;
nsRefPtr<BluetoothProfileController> mController;
bool mAvrcpConnected;
nsString mAlbum;
nsString mArtist;
nsString mTitle;
uint32_t mDuration;
uint64_t mMediaNumber;
uint64_t mTotalMediaCount;
uint32_t mPosition;
/*
* mPlaybackInterval specifies the time interval (in seconds) at which
* the change in playback position will be notified. If the song is being
* forwarded / rewound, a notification will be received whenever the playback
* position will change by this value.
*/
uint32_t mPlaybackInterval;
ControlPlayStatus mPlayStatus;
/*
* Notification types: 1. INTERIM 2. CHANGED
* 1. The initial response to this Notify command shall be an INTERIM
* response with current status.
* 2. The following response shall be a CHANGED response with the updated
* status.
* mPlayStatusChangedNotifType, mTrackChangedNotifType,
* mPlayPosChangedNotifType represents current RegisterNotification
* notification type.
*/
BluetoothAvrcpNotification mPlayStatusChangedNotifyType;
BluetoothAvrcpNotification mTrackChangedNotifyType;
BluetoothAvrcpNotification mPlayPosChangedNotifyType;
BluetoothAvrcpNotification mAppSettingsChangedNotifyType;
};
END_BLUETOOTH_NAMESPACE
#endif // mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h

Просмотреть файл

@ -19,6 +19,7 @@
#include "BluetoothServiceBluedroid.h"
#include "BluetoothA2dpManager.h"
#include "BluetoothAvrcpManager.h"
#include "BluetoothGattManager.h"
#include "BluetoothHfpManager.h"
#include "BluetoothHidManager.h"
@ -154,6 +155,7 @@ public:
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
BluetoothHfpManager::InitHfpInterface,
BluetoothA2dpManager::InitA2dpInterface,
BluetoothAvrcpManager::InitAvrcpInterface,
BluetoothGattManager::InitGattInterface
};
@ -295,6 +297,7 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
static BluetoothProfileManagerBase* sProfiles[] = {
BluetoothHfpManager::Get(),
BluetoothAvrcpManager::Get(),
BluetoothA2dpManager::Get(),
BluetoothOppManager::Get(),
BluetoothPbapManager::Get(),
@ -1282,10 +1285,10 @@ BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle,
int64_t aDuration,
BluetoothReplyRunnable* aRunnable)
{
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
if (a2dp) {
a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber,
aTotalMediaCount, aDuration);
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
if (avrcp) {
avrcp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber,
aTotalMediaCount, aDuration);
}
DispatchReplySuccess(aRunnable);
}
@ -1296,11 +1299,11 @@ BluetoothServiceBluedroid::SendPlayStatus(
const nsAString& aPlayStatus,
BluetoothReplyRunnable* aRunnable)
{
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
if (a2dp) {
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
if (avrcp) {
ControlPlayStatus playStatus =
PlayStatusStringToControlPlayStatus(aPlayStatus);
a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus);
avrcp->UpdatePlayStatus(aDuration, aPosition, playStatus);
}
DispatchReplySuccess(aRunnable);
}

Просмотреть файл

@ -52,8 +52,9 @@ BluetoothA2dpManager::BluetoothA2dpManager()
void
BluetoothA2dpManager::Reset()
{
ResetA2dp();
ResetAvrcp();
mA2dpConnected = false;
mSinkState = SinkState::SINK_DISCONNECTED;
mController = nullptr;
}
bool
@ -80,25 +81,6 @@ BluetoothA2dpManager::~BluetoothA2dpManager()
}
}
void
BluetoothA2dpManager::ResetA2dp()
{
mA2dpConnected = false;
mSinkState = SinkState::SINK_DISCONNECTED;
mController = nullptr;
}
void
BluetoothA2dpManager::ResetAvrcp()
{
mAvrcpConnected = false;
mDuration = 0;
mMediaNumber = 0;
mTotalMediaCount = 0;
mPosition = 0;
mPlayStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
}
static BluetoothA2dpManager::SinkState
StatusStringToSinkState(const nsAString& aStatus)
{
@ -399,82 +381,4 @@ BluetoothA2dpManager::IsConnected()
return mA2dpConnected;
}
void
BluetoothA2dpManager::SetAvrcpConnected(bool aConnected)
{
mAvrcpConnected = aConnected;
if (!aConnected) {
ResetAvrcp();
}
}
bool
BluetoothA2dpManager::IsAvrcpConnected()
{
return mAvrcpConnected;
}
void
BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration)
{
mTitle.Assign(aTitle);
mArtist.Assign(aArtist);
mAlbum.Assign(aAlbum);
mMediaNumber = aMediaNumber;
mTotalMediaCount = aTotalMediaCount;
mDuration = aDuration;
}
void
BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus)
{
mDuration = aDuration;
mPosition = aPosition;
mPlayStatus = aPlayStatus;
}
void
BluetoothA2dpManager::GetAlbum(nsAString& aAlbum)
{
aAlbum.Assign(mAlbum);
}
uint32_t
BluetoothA2dpManager::GetDuration()
{
return mDuration;
}
ControlPlayStatus
BluetoothA2dpManager::GetPlayStatus()
{
return mPlayStatus;
}
uint32_t
BluetoothA2dpManager::GetPosition()
{
return mPosition;
}
uint64_t
BluetoothA2dpManager::GetMediaNumber()
{
return mMediaNumber;
}
void
BluetoothA2dpManager::GetTitle(nsAString& aTitle)
{
aTitle.Assign(mTitle);
}
NS_IMPL_ISUPPORTS(BluetoothA2dpManager, nsIObserver)

Просмотреть файл

@ -35,25 +35,6 @@ public:
// A2DP-specific functions
void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);
// AVRCP-specific functions
void SetAvrcpConnected(bool aConnected);
bool IsAvrcpConnected();
void UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration);
void UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus);
void GetAlbum(nsAString& aAlbum);
uint32_t GetDuration();
ControlPlayStatus GetPlayStatus();
uint32_t GetPosition();
uint64_t GetMediaNumber();
void GetTitle(nsAString& aTitle);
protected:
virtual ~BluetoothA2dpManager();
@ -61,7 +42,6 @@ private:
BluetoothA2dpManager();
bool Init();
void ResetA2dp();
void ResetAvrcp();
void HandleShutdown();
void NotifyConnectionStatusChanged();
@ -73,16 +53,6 @@ private:
bool mA2dpConnected;
SinkState mSinkState;
// AVRCP data member
bool mAvrcpConnected;
nsString mAlbum;
nsString mArtist;
nsString mTitle;
uint32_t mDuration;
uint64_t mMediaNumber;
uint64_t mTotalMediaCount;
uint32_t mPosition;
ControlPlayStatus mPlayStatus;
};
END_BLUETOOTH_NAMESPACE

Просмотреть файл

@ -0,0 +1,262 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "BluetoothAvrcpManager.h"
#include "BluetoothCommon.h"
#include "BluetoothService.h"
#include "BluetoothSocket.h"
#include "BluetoothUtils.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "nsIObserverService.h"
#include "MainThreadUtils.h"
using namespace mozilla;
USING_BLUETOOTH_NAMESPACE
namespace {
StaticRefPtr<BluetoothAvrcpManager> sBluetoothAvrcpManager;
bool sInShutdown = false;
} // namespace
NS_IMETHODIMP
BluetoothAvrcpManager::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(sBluetoothAvrcpManager);
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
HandleShutdown();
return NS_OK;
}
MOZ_ASSERT(false, "BluetoothAvrcpManager got unexpected topic!");
return NS_ERROR_UNEXPECTED;
}
BluetoothAvrcpManager::BluetoothAvrcpManager()
{
Reset();
}
void
BluetoothAvrcpManager::Reset()
{
mAvrcpConnected = false;
mDuration = 0;
mMediaNumber = 0;
mTotalMediaCount = 0;
mPosition = 0;
mPlayStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
}
bool
BluetoothAvrcpManager::Init()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, false);
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
BT_WARNING("Failed to add shutdown observer!");
return false;
}
return true;
}
BluetoothAvrcpManager::~BluetoothAvrcpManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
}
//static
BluetoothAvrcpManager*
BluetoothAvrcpManager::Get()
{
MOZ_ASSERT(NS_IsMainThread());
// If sBluetoothA2dpManager already exists, exit early
if (sBluetoothAvrcpManager) {
return sBluetoothAvrcpManager;
}
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothAvrcpManager* manager = new BluetoothAvrcpManager();
NS_ENSURE_TRUE(manager->Init(), nullptr);
sBluetoothAvrcpManager = manager;
return sBluetoothAvrcpManager;
}
void
BluetoothAvrcpManager::HandleShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
sInShutdown = true;
Disconnect(nullptr);
sBluetoothAvrcpManager = nullptr;
}
void
BluetoothAvrcpManager::Connect(const nsAString& aDeviceAddress,
BluetoothProfileController* aController)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
MOZ_ASSERT(aController && !mController);
mDeviceAddress = aDeviceAddress;
OnConnect(EmptyString());
}
void
BluetoothAvrcpManager::Disconnect(BluetoothProfileController* aController)
{
mDeviceAddress.Truncate();
OnDisconnect(EmptyString());
}
void
BluetoothAvrcpManager::OnConnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
/**
* On the one hand, notify the controller that we've done for outbound
* connections. On the other hand, we do nothing for inbound connections.
*/
NS_ENSURE_TRUE_VOID(mController);
nsRefPtr<BluetoothProfileController> controller = mController.forget();
controller->NotifyCompletion(aErrorStr);
}
void
BluetoothAvrcpManager::OnDisconnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
/**
* On the one hand, notify the controller that we've done for outbound
* connections. On the other hand, we do nothing for inbound connections.
*/
NS_ENSURE_TRUE_VOID(mController);
nsRefPtr<BluetoothProfileController> controller = mController.forget();
controller->NotifyCompletion(aErrorStr);
Reset();
}
void
BluetoothAvrcpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,
int aChannel)
{ }
void
BluetoothAvrcpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
{ }
void
BluetoothAvrcpManager::GetAddress(nsAString& aDeviceAddress)
{
aDeviceAddress = mDeviceAddress;
}
bool
BluetoothAvrcpManager::IsConnected()
{
return mAvrcpConnected;
}
void
BluetoothAvrcpManager::SetConnected(bool aConnected)
{
mAvrcpConnected = aConnected;
if (!aConnected) {
Reset();
}
}
void
BluetoothAvrcpManager::UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration)
{
mTitle.Assign(aTitle);
mArtist.Assign(aArtist);
mAlbum.Assign(aAlbum);
mMediaNumber = aMediaNumber;
mTotalMediaCount = aTotalMediaCount;
mDuration = aDuration;
}
void
BluetoothAvrcpManager::UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus)
{
mDuration = aDuration;
mPosition = aPosition;
mPlayStatus = aPlayStatus;
}
void
BluetoothAvrcpManager::GetAlbum(nsAString& aAlbum)
{
aAlbum.Assign(mAlbum);
}
uint32_t
BluetoothAvrcpManager::GetDuration()
{
return mDuration;
}
ControlPlayStatus
BluetoothAvrcpManager::GetPlayStatus()
{
return mPlayStatus;
}
uint32_t
BluetoothAvrcpManager::GetPosition()
{
return mPosition;
}
uint64_t
BluetoothAvrcpManager::GetMediaNumber()
{
return mMediaNumber;
}
void
BluetoothAvrcpManager::GetTitle(nsAString& aTitle)
{
aTitle.Assign(mTitle);
}
NS_IMPL_ISUPPORTS(BluetoothAvrcpManager, nsIObserver)

Просмотреть файл

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_bluetooth_bluez_BluetoothAvrcpManager_h
#define mozilla_dom_bluetooth_bluez_BluetoothAvrcpManager_h
#include "BluetoothCommon.h"
#include "BluetoothProfileController.h"
#include "BluetoothProfileManagerBase.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothAvrcpManager : public BluetoothProfileManagerBase
{
public:
BT_DECL_PROFILE_MGR_BASE
virtual void GetName(nsACString& aName)
{
aName.AssignLiteral("AVRCP");
}
static BluetoothAvrcpManager* Get();
// AVRCP-specific functions
void SetConnected(bool aConnected);
void UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
const nsAString& aAlbum,
uint64_t aMediaNumber,
uint64_t aTotalMediaCount,
uint32_t aDuration);
void UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus);
void GetAlbum(nsAString& aAlbum);
uint32_t GetDuration();
ControlPlayStatus GetPlayStatus();
uint32_t GetPosition();
uint64_t GetMediaNumber();
void GetTitle(nsAString& aTitle);
protected:
virtual ~BluetoothAvrcpManager();
private:
BluetoothAvrcpManager();
bool Init();
void HandleShutdown();
void NotifyConnectionStatusChanged();
nsString mDeviceAddress;
nsRefPtr<BluetoothProfileController> mController;
// AVRCP data member
bool mAvrcpConnected;
nsString mAlbum;
nsString mArtist;
nsString mTitle;
uint32_t mDuration;
uint64_t mMediaNumber;
uint64_t mTotalMediaCount;
uint32_t mPosition;
ControlPlayStatus mPlayStatus;
};
END_BLUETOOTH_NAMESPACE
#endif // mozilla_dom_bluetooth_bluez_BluetoothAvrcpManager_h

Просмотреть файл

@ -19,6 +19,7 @@
#include "base/basictypes.h"
#include "BluetoothDBusService.h"
#include "BluetoothA2dpManager.h"
#include "BluetoothAvrcpManager.h"
#include "BluetoothHfpManager.h"
#include "BluetoothHidManager.h"
#include "BluetoothOppManager.h"
@ -538,9 +539,9 @@ public:
MOZ_ASSERT(arr[0].value().type() == BluetoothValue::Tbool);
bool connected = arr[0].value().get_bool();
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
a2dp->SetAvrcpConnected(connected);
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
NS_ENSURE_TRUE(avrcp, NS_ERROR_FAILURE);
avrcp->SetConnected(connected);
return NS_OK;
}
@ -3957,32 +3958,28 @@ BluetoothDBusService::SendMetaData(const nsAString& aTitle,
return;
}
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE_VOID(a2dp);
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
NS_ENSURE_TRUE_VOID(avrcp);
if (!a2dp->IsConnected()) {
DispatchBluetoothReply(aRunnable, BluetoothValue(),
NS_LITERAL_STRING(ERR_A2DP_IS_DISCONNECTED));
return;
} else if (!a2dp->IsAvrcpConnected()) {
if (!avrcp->IsConnected()) {
DispatchBluetoothReply(aRunnable, BluetoothValue(),
NS_LITERAL_STRING(ERR_AVRCP_IS_DISCONNECTED));
return;
}
nsAutoString prevTitle, prevAlbum;
a2dp->GetTitle(prevTitle);
a2dp->GetAlbum(prevAlbum);
avrcp->GetTitle(prevTitle);
avrcp->GetAlbum(prevAlbum);
uint64_t mediaNumber = static_cast<uint64_t>(aMediaNumber);
if (mediaNumber != a2dp->GetMediaNumber() ||
if (mediaNumber != avrcp->GetMediaNumber() ||
!aTitle.Equals(prevTitle) ||
!aAlbum.Equals(prevAlbum)) {
UpdateNotification(ControlEventId::EVENT_TRACK_CHANGED, aMediaNumber);
}
nsAutoString deviceAddress;
a2dp->GetAddress(deviceAddress);
avrcp->GetAddress(deviceAddress);
Task* task = new SendMetadataTask(
deviceAddress,
@ -3995,8 +3992,8 @@ BluetoothDBusService::SendMetaData(const nsAString& aTitle,
aRunnable);
DispatchToDBusThread(task);
a2dp->UpdateMetaData(aTitle, aArtist, aAlbum,
aMediaNumber, aTotalMediaCount, aDuration);
avrcp->UpdateMetaData(aTitle, aArtist, aAlbum,
aMediaNumber, aTotalMediaCount, aDuration);
}
static ControlPlayStatus
@ -4101,28 +4098,24 @@ BluetoothDBusService::SendPlayStatus(int64_t aDuration,
return;
}
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE_VOID(a2dp);
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
NS_ENSURE_TRUE_VOID(avrcp);
if (!a2dp->IsConnected()) {
DispatchBluetoothReply(aRunnable, BluetoothValue(),
NS_LITERAL_STRING(ERR_A2DP_IS_DISCONNECTED));
return;
} else if (!a2dp->IsAvrcpConnected()) {
if (!avrcp->IsConnected()) {
DispatchBluetoothReply(aRunnable, BluetoothValue(),
NS_LITERAL_STRING(ERR_AVRCP_IS_DISCONNECTED));
return;
}
if (playStatus != a2dp->GetPlayStatus()) {
if (playStatus != avrcp->GetPlayStatus()) {
UpdateNotification(ControlEventId::EVENT_PLAYBACK_STATUS_CHANGED,
playStatus);
} else if (aPosition != a2dp->GetPosition()) {
} else if (aPosition != avrcp->GetPosition()) {
UpdateNotification(ControlEventId::EVENT_PLAYBACK_POS_CHANGED, aPosition);
}
nsAutoString deviceAddress;
a2dp->GetAddress(deviceAddress);
avrcp->GetAddress(deviceAddress);
Task* task = new SendPlayStatusTask(deviceAddress,
aDuration,
@ -4131,7 +4124,7 @@ BluetoothDBusService::SendPlayStatus(int64_t aDuration,
aRunnable);
DispatchToDBusThread(task);
a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus);
avrcp->UpdatePlayStatus(aDuration, aPosition, playStatus);
}
static void
@ -4200,14 +4193,13 @@ BluetoothDBusService::UpdatePlayStatus(uint32_t aDuration,
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(this->IsReady());
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE_VOID(a2dp);
MOZ_ASSERT(a2dp->IsConnected());
MOZ_ASSERT(a2dp->IsAvrcpConnected());
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
NS_ENSURE_TRUE_VOID(avrcp);
MOZ_ASSERT(avrcp->IsConnected());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsAutoString deviceAddress;
a2dp->GetAddress(deviceAddress);
avrcp->GetAddress(deviceAddress);
Task* task = new UpdatePlayStatusTask(deviceAddress,
aDuration,
@ -4264,14 +4256,13 @@ BluetoothDBusService::UpdateNotification(ControlEventId aEventId,
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(this->IsReady());
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE_VOID(a2dp);
MOZ_ASSERT(a2dp->IsConnected());
MOZ_ASSERT(a2dp->IsAvrcpConnected());
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
NS_ENSURE_TRUE_VOID(avrcp);
MOZ_ASSERT(avrcp->IsConnected());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsAutoString deviceAddress;
a2dp->GetAddress(deviceAddress);
avrcp->GetAddress(deviceAddress);
Task* task = new UpdateNotificationTask(deviceAddress, aEventId, aData);
DispatchToDBusThread(task);

Просмотреть файл

@ -7,6 +7,7 @@
#include "BluetoothProfileController.h"
#include "BluetoothA2dpManager.h"
#include "BluetoothAvrcpManager.h"
#include "BluetoothHfpManager.h"
#include "BluetoothHidManager.h"
#include "BluetoothReplyRunnable.h"
@ -111,6 +112,9 @@ BluetoothProfileController::AddProfileWithServiceClass(
case BluetoothServiceClass::A2DP:
profile = BluetoothA2dpManager::Get();
break;
case BluetoothServiceClass::AVRCP:
profile = BluetoothAvrcpManager::Get();
break;
case BluetoothServiceClass::HID:
profile = BluetoothHidManager::Get();
break;
@ -158,6 +162,7 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
// For a disconnect request, all connected profiles are put into array.
if (!mConnect) {
AddProfile(BluetoothHidManager::Get(), true);
AddProfile(BluetoothAvrcpManager::Get(), true);
AddProfile(BluetoothA2dpManager::Get(), true);
AddProfile(BluetoothHfpManager::Get(), true);
return;
@ -180,6 +185,7 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
if (isInvalid) {
AddProfile(BluetoothHfpManager::Get());
AddProfile(BluetoothA2dpManager::Get());
AddProfile(BluetoothAvrcpManager::Get()); // register after A2DP
AddProfile(BluetoothHidManager::Get());
return;
}
@ -196,6 +202,7 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
// a remote control.
if (hasRendering || (isPeripheral && isRemoteControl)) {
AddProfile(BluetoothA2dpManager::Get());
AddProfile(BluetoothAvrcpManager::Get()); // register after A2DP
}
// A device which supports HID should claim that it's a peripheral and it's

Просмотреть файл

@ -7,6 +7,7 @@
#include "BluetoothUuid.h"
#include "BluetoothA2dpManager.h"
#include "BluetoothAvrcpManager.h"
#include "BluetoothHfpManager.h"
#include "BluetoothHidManager.h"
#include "BluetoothOppManager.h"
@ -52,6 +53,9 @@ BluetoothUuidHelper::GetBluetoothServiceClass(uint16_t aServiceUuid)
switch (aServiceUuid) {
case BluetoothServiceClass::A2DP:
case BluetoothServiceClass::A2DP_SINK:
case BluetoothServiceClass::AVRCP:
case BluetoothServiceClass::AVRCP_TARGET:
case BluetoothServiceClass::AVRCP_CONTROLLER:
case BluetoothServiceClass::HANDSFREE:
case BluetoothServiceClass::HANDSFREE_AG:
case BluetoothServiceClass::HEADSET:
@ -79,6 +83,9 @@ BluetoothUuidHelper::GetBluetoothProfileManager(uint16_t aServiceUuid)
case BluetoothServiceClass::A2DP:
profile = BluetoothA2dpManager::Get();
break;
case BluetoothServiceClass::AVRCP:
profile = BluetoothAvrcpManager::Get();
break;
case BluetoothServiceClass::OBJECT_PUSH:
profile = BluetoothOppManager::Get();
break;

Просмотреть файл

@ -24,15 +24,18 @@ class BluetoothProfileManagerBase;
*/
enum BluetoothServiceClass
{
A2DP = 0x110D,
A2DP_SINK = 0x110B,
HANDSFREE = 0x111E,
HANDSFREE_AG = 0x111F,
HEADSET = 0x1108,
HEADSET_AG = 0x1112,
HID = 0x1124,
OBJECT_PUSH = 0x1105,
UNKNOWN = 0x0000
A2DP = 0x110D,
A2DP_SINK = 0x110B,
AVRCP = 0x110E,
AVRCP_TARGET = 0x110C,
AVRCP_CONTROLLER = 0x110F,
HANDSFREE = 0x111E,
HANDSFREE_AG = 0x111F,
HEADSET = 0x1108,
HEADSET_AG = 0x1112,
HID = 0x1124,
OBJECT_PUSH = 0x1105,
UNKNOWN = 0x0000
};
class BluetoothUuidHelper

Просмотреть файл

@ -57,6 +57,7 @@ if CONFIG['MOZ_B2G_BT']:
CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
SOURCES += [
'bluez/BluetoothA2dpManager.cpp',
'bluez/BluetoothAvrcpManager.cpp',
'bluez/BluetoothDBusService.cpp',
'bluez/BluetoothHfpManager.cpp',
'bluez/BluetoothOppManager.cpp',
@ -70,6 +71,7 @@ if CONFIG['MOZ_B2G_BT']:
elif CONFIG['MOZ_B2G_BT_DAEMON']:
SOURCES += [
'bluedroid/BluetoothA2dpManager.cpp',
'bluedroid/BluetoothAvrcpManager.cpp',
'bluedroid/BluetoothDaemonA2dpInterface.cpp',
'bluedroid/BluetoothDaemonAvrcpInterface.cpp',
'bluedroid/BluetoothDaemonGattInterface.cpp',

Просмотреть файл

@ -41,9 +41,15 @@ class DeviceStorageFileSystem;
} // namespace dom
namespace ipc {
class FileDescriptor;
class PrincipalInfo;
} // namespace ipc
} // namespace mozilla
class DeviceStorageRequest;
class DeviceStorageCursorRequest;
class DeviceStorageRequestManager;
class nsDOMDeviceStorageCursor;
class DeviceStorageFile final
: public nsISupports {
public:
@ -197,10 +203,6 @@ public:
AppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
ErrorResult& aRv);
already_AddRefed<DOMRequest>
AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
const int32_t aRequestType, ErrorResult& aRv);
already_AddRefed<DOMRequest>
Get(const nsAString& aPath, ErrorResult& aRv)
{
@ -290,16 +292,32 @@ public:
void OnVolumeStateChanged(nsIVolume* aVolume);
#endif
uint32_t CreateDOMRequest(DOMRequest** aRequest, ErrorResult& aRv);
uint32_t CreateDOMCursor(DeviceStorageCursorRequest* aRequest,
nsDOMDeviceStorageCursor** aCursor,
ErrorResult& aRv);
already_AddRefed<DOMRequest> CreateAndRejectDOMRequest(const char *aReason,
ErrorResult& aRv);
nsresult CheckPermission(DeviceStorageRequest* aRequest);
void StorePermission(DeviceStorageRequest* aRequest, bool aAllow);
bool IsOwningThread();
nsresult DispatchToOwningThread(nsIRunnable* aRunnable);
private:
~nsDOMDeviceStorage();
static nsresult CheckPrincipal(nsPIDOMWindow* aWindow, bool aIsAppsStorage,
nsIPrincipal** aPrincipal);
already_AddRefed<DOMRequest>
AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
bool aCreate, ErrorResult& aRv);
already_AddRefed<DOMRequest>
GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv);
void
GetInternal(nsPIDOMWindow* aWin, const nsAString& aPath, DOMRequest* aRequest,
bool aEditable);
void
DeleteInternal(nsPIDOMWindow* aWin, const nsAString& aPath,
DOMRequest* aRequest);
@ -327,10 +345,6 @@ private:
const nsAString& aStorageName,
const nsAString& aType);
nsCOMPtr<nsIPrincipal> mPrincipal;
bool mIsWatchingFile;
bool mAllowedToWatchFile;
bool mIsDefaultLocation;
nsresult Notify(const char* aReason, class DeviceStorageFile* aFile);
@ -347,7 +361,11 @@ private:
void DispatchStorageStatusChangeEvent(nsAString& aStorageStatus);
#endif
uint64_t mInnerWindowID;
nsRefPtr<DeviceStorageFileSystem> mFileSystem;
nsRefPtr<DeviceStorageRequestManager> mManager;
nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
nsCOMPtr<nsIThread> mOwningThread;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMDeviceStorage, NS_DOM_DEVICE_STORAGE_CID)

Просмотреть файл

@ -16,33 +16,14 @@ namespace dom {
namespace devicestorage {
DeviceStorageRequestChild::DeviceStorageRequestChild()
: mCallback(nullptr)
{
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest,
DeviceStorageFile* aDSFile)
DeviceStorageRequestChild::DeviceStorageRequestChild(DeviceStorageRequest* aRequest)
: mRequest(aRequest)
, mDSFile(aDSFile)
, mCallback(nullptr)
{
MOZ_ASSERT(aRequest);
MOZ_ASSERT(aDSFile);
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest,
DeviceStorageFile* aDSFile,
DeviceStorageFileDescriptor* aDSFileDescriptor)
: mRequest(aRequest)
, mDSFile(aDSFile)
, mDSFileDescriptor(aDSFileDescriptor)
, mCallback(nullptr)
{
MOZ_ASSERT(aRequest);
MOZ_ASSERT(aDSFile);
MOZ_ASSERT(aDSFileDescriptor);
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
@ -54,160 +35,126 @@ bool
DeviceStorageRequestChild::
Recv__delete__(const DeviceStorageResponseValue& aValue)
{
if (mCallback) {
mCallback->RequestComplete();
mCallback = nullptr;
}
nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner();
if (!window) {
return true;
}
switch (aValue.type()) {
case DeviceStorageResponseValue::TErrorResponse:
{
DS_LOG_INFO("error %u", mRequest->GetId());
ErrorResponse r = aValue;
mRequest->FireError(r.error());
mRequest->Reject(r.error());
break;
}
case DeviceStorageResponseValue::TSuccessResponse:
{
DS_LOG_INFO("success %u", mRequest->GetId());
nsString fullPath;
mDSFile->GetFullPath(fullPath);
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, fullPath, &result);
mRequest->FireSuccess(result);
mRequest->GetFile()->GetFullPath(fullPath);
mRequest->Resolve(fullPath);
break;
}
case DeviceStorageResponseValue::TFileDescriptorResponse:
{
DS_LOG_INFO("fd %u", mRequest->GetId());
FileDescriptorResponse r = aValue;
DeviceStorageFile* file = mRequest->GetFile();
DeviceStorageFileDescriptor* descriptor = mRequest->GetFileDescriptor();
nsString fullPath;
mDSFile->GetFullPath(fullPath);
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, fullPath, &result);
mDSFileDescriptor->mDSFile = mDSFile;
mDSFileDescriptor->mFileDescriptor = r.fileDescriptor();
mRequest->FireSuccess(result);
file->GetFullPath(fullPath);
descriptor->mDSFile = file;
descriptor->mFileDescriptor = r.fileDescriptor();
mRequest->Resolve(fullPath);
break;
}
case DeviceStorageResponseValue::TBlobResponse:
{
DS_LOG_INFO("blob %u", mRequest->GetId());
BlobResponse r = aValue;
BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
nsRefPtr<BlobImpl> bloblImpl = actor->GetBlobImpl();
nsRefPtr<Blob> blob = Blob::Create(mRequest->GetParentObject(),
bloblImpl);
AutoJSContext cx;
JS::Rooted<JSObject*> obj(cx, blob->WrapObject(cx, nullptr));
MOZ_ASSERT(obj);
JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*obj));
mRequest->FireSuccess(result);
nsRefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
mRequest->Resolve(blobImpl.get());
break;
}
case DeviceStorageResponseValue::TFreeSpaceStorageResponse:
{
DS_LOG_INFO("free %u", mRequest->GetId());
FreeSpaceStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx, JS_NumberValue(double(r.freeBytes())));
mRequest->FireSuccess(result);
mRequest->Resolve(r.freeBytes());
break;
}
case DeviceStorageResponseValue::TUsedSpaceStorageResponse:
{
DS_LOG_INFO("used %u", mRequest->GetId());
UsedSpaceStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx, JS_NumberValue(double(r.usedBytes())));
mRequest->FireSuccess(result);
mRequest->Resolve(r.usedBytes());
break;
}
case DeviceStorageResponseValue::TAvailableStorageResponse:
{
DS_LOG_INFO("available %u", mRequest->GetId());
AvailableStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.mountState(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.mountState());
break;
}
case DeviceStorageResponseValue::TStorageStatusResponse:
{
DS_LOG_INFO("status %u", mRequest->GetId());
StorageStatusResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.storageStatus(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TFormatStorageResponse:
{
DS_LOG_INFO("format %u", mRequest->GetId());
FormatStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.mountState(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.mountState());
break;
}
case DeviceStorageResponseValue::TMountStorageResponse:
{
DS_LOG_INFO("mount %u", mRequest->GetId());
MountStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.storageStatus(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TUnmountStorageResponse:
{
DS_LOG_INFO("unmount %u", mRequest->GetId());
UnmountStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.storageStatus(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TEnumerationResponse:
{
DS_LOG_INFO("enumerate %u", mRequest->GetId());
EnumerationResponse r = aValue;
nsDOMDeviceStorageCursor* cursor
= static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
auto request = static_cast<DeviceStorageCursorRequest*>(mRequest.get());
uint32_t count = r.paths().Length();
cursor->mFiles.SetCapacity(count);
request->AddFiles(count);
for (uint32_t i = 0; i < count; i++) {
nsRefPtr<DeviceStorageFile> dsf
= new DeviceStorageFile(r.type(), r.paths()[i].storageName(),
r.rootdir(), r.paths()[i].name());
cursor->mFiles.AppendElement(dsf.forget());
request->AddFile(dsf.forget());
}
nsRefPtr<ContinueCursorEvent> event = new ContinueCursorEvent(cursor);
event->Continue();
request->Continue();
break;
}
default:
{
DS_LOG_ERROR("unknown %u", mRequest->GetId());
NS_RUNTIMEABORT("not reached");
break;
}
@ -215,13 +162,6 @@ DeviceStorageRequestChild::
return true;
}
void
DeviceStorageRequestChild::
SetCallback(DeviceStorageRequestChildCallback *aCallback)
{
mCallback = aCallback;
}
} // namespace devicestorage
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -10,13 +10,12 @@
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
class DeviceStorageFile;
class DeviceStorageRequest;
struct DeviceStorageFileDescriptor;
namespace mozilla {
namespace dom {
class DOMRequest;
namespace devicestorage {
class DeviceStorageRequestChildCallback
@ -29,21 +28,13 @@ class DeviceStorageRequestChild : public PDeviceStorageRequestChild
{
public:
DeviceStorageRequestChild();
DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile);
DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile,
DeviceStorageFileDescriptor* aFileDescrptor);
explicit DeviceStorageRequestChild(DeviceStorageRequest* aRequest);
~DeviceStorageRequestChild();
void SetCallback(class DeviceStorageRequestChildCallback *aCallback);
virtual bool Recv__delete__(const DeviceStorageResponseValue& value);
private:
nsRefPtr<DOMRequest> mRequest;
nsRefPtr<DeviceStorageFile> mDSFile;
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
DeviceStorageRequestChildCallback* mCallback;
nsRefPtr<DeviceStorageRequest> mRequest;
};
} // namespace devicestorage

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -8,6 +8,7 @@
#define nsDeviceStorage_h
class nsPIDOMWindow;
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
@ -18,7 +19,6 @@ class nsPIDOMWindow;
#include "nsCycleCollectionParticipant.h"
#include "nsDOMClassInfoID.h"
#include "nsIClassInfo.h"
#include "nsIContentPermissionPrompt.h"
#include "nsIDOMWindow.h"
#include "nsIURI.h"
#include "nsIPrincipal.h"
@ -36,13 +36,18 @@ namespace mozilla {
class ErrorResult;
namespace dom {
class Blob;
class BlobImpl;
class DeviceStorageParams;
} // namespace dom
} // namespace mozilla
class nsDOMDeviceStorage;
class DeviceStorageCursorRequest;
//#define DS_LOGGING 1
#ifdef DS_LOGGING
// FIXME -- use MOZ_LOG and set to warn by default
#define DS_LOG_DEBUG(msg, ...) printf_stderr("[%s:%d] " msg "\n", __func__, __LINE__, ##__VA_ARGS__)
#define DS_LOG_INFO DS_LOG_DEBUG
#define DS_LOG_WARN DS_LOG_DEBUG
@ -62,20 +67,29 @@ class Blob;
#define POST_ERROR_EVENT_UNKNOWN "Unknown"
enum DeviceStorageRequestType {
DEVICE_STORAGE_REQUEST_READ,
DEVICE_STORAGE_REQUEST_WRITE,
DEVICE_STORAGE_REQUEST_APPEND,
DEVICE_STORAGE_REQUEST_CREATE,
DEVICE_STORAGE_REQUEST_DELETE,
DEVICE_STORAGE_REQUEST_WATCH,
DEVICE_STORAGE_REQUEST_FREE_SPACE,
DEVICE_STORAGE_REQUEST_USED_SPACE,
DEVICE_STORAGE_REQUEST_AVAILABLE,
DEVICE_STORAGE_REQUEST_STATUS,
DEVICE_STORAGE_REQUEST_FORMAT,
DEVICE_STORAGE_REQUEST_MOUNT,
DEVICE_STORAGE_REQUEST_UNMOUNT,
DEVICE_STORAGE_REQUEST_CREATEFD
DEVICE_STORAGE_REQUEST_READ,
DEVICE_STORAGE_REQUEST_WRITE,
DEVICE_STORAGE_REQUEST_APPEND,
DEVICE_STORAGE_REQUEST_CREATE,
DEVICE_STORAGE_REQUEST_DELETE,
DEVICE_STORAGE_REQUEST_WATCH,
DEVICE_STORAGE_REQUEST_FREE_SPACE,
DEVICE_STORAGE_REQUEST_USED_SPACE,
DEVICE_STORAGE_REQUEST_AVAILABLE,
DEVICE_STORAGE_REQUEST_STATUS,
DEVICE_STORAGE_REQUEST_FORMAT,
DEVICE_STORAGE_REQUEST_MOUNT,
DEVICE_STORAGE_REQUEST_UNMOUNT,
DEVICE_STORAGE_REQUEST_CREATEFD,
DEVICE_STORAGE_REQUEST_CURSOR
};
enum DeviceStorageAccessType {
DEVICE_STORAGE_ACCESS_READ,
DEVICE_STORAGE_ACCESS_WRITE,
DEVICE_STORAGE_ACCESS_CREATE,
DEVICE_STORAGE_ACCESS_UNDEFINED,
DEVICE_STORAGE_ACCESS_COUNT
};
class DeviceStorageUsedSpaceCache final
@ -176,14 +190,17 @@ public:
void InitFromBundle(nsIStringBundle* aBundle);
bool Check(const nsAString& aType, mozilla::dom::Blob* aBlob);
bool Check(const nsAString& aType, mozilla::dom::BlobImpl* aBlob);
bool Check(const nsAString& aType, nsIFile* aFile);
bool Check(const nsAString& aType, const nsString& aPath);
void GetTypeFromFile(nsIFile* aFile, nsAString& aType);
void GetTypeFromFileName(const nsAString& aFileName, nsAString& aType);
static nsresult GetPermissionForType(const nsAString& aType, nsACString& aPermissionResult);
static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType, nsACString& aAccessResult);
static nsresult GetPermissionForType(const nsAString& aType,
nsACString& aPermissionResult);
static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType,
nsACString& aAccessResult);
static nsresult GetAccessForIndex(size_t aAccessIndex, nsACString& aAccessResult);
static size_t GetAccessIndexForRequest(const DeviceStorageRequestType aRequestType);
static bool IsVolumeBased(const nsAString& aType);
static bool IsSharedMediaRoot(const nsAString& aType);
@ -195,65 +212,224 @@ private:
static mozilla::StaticAutoPtr<DeviceStorageTypeChecker> sDeviceStorageTypeChecker;
};
class ContinueCursorEvent final : public nsRunnable
{
public:
explicit ContinueCursorEvent(already_AddRefed<mozilla::dom::DOMRequest> aRequest);
explicit ContinueCursorEvent(mozilla::dom::DOMRequest* aRequest);
~ContinueCursorEvent();
void Continue();
NS_IMETHOD Run() override;
private:
already_AddRefed<DeviceStorageFile> GetNextFile();
nsRefPtr<mozilla::dom::DOMRequest> mRequest;
};
class nsDOMDeviceStorageCursor final
: public mozilla::dom::DOMCursor
, public nsIContentPermissionRequest
, public mozilla::dom::devicestorage::DeviceStorageRequestChildCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSICONTENTPERMISSIONREQUEST
NS_FORWARD_NSIDOMDOMCURSOR(mozilla::dom::DOMCursor::)
// DOMCursor
virtual void Continue(mozilla::ErrorResult& aRv) override;
nsDOMDeviceStorageCursor(nsPIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
DeviceStorageFile* aFile,
PRTime aSince);
nsDOMDeviceStorageCursor(nsIGlobalObject* aGlobal,
DeviceStorageCursorRequest* aRequest);
nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
bool mOkToCallContinue;
PRTime mSince;
size_t mIndex;
void GetStorageType(nsAString & aType);
void RequestComplete() override;
void FireSuccess(JS::Handle<JS::Value> aResult);
void FireError(const nsString& aReason);
void FireDone();
private:
~nsDOMDeviceStorageCursor();
virtual ~nsDOMDeviceStorageCursor();
nsRefPtr<DeviceStorageFile> mFile;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
bool mOkToCallContinue;
nsRefPtr<DeviceStorageCursorRequest> mRequest;
};
//helpers
bool
StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
JS::MutableHandle<JS::Value> result);
class DeviceStorageRequestManager final
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceStorageRequestManager)
JS::Value
nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile);
static const uint32_t INVALID_ID = 0;
JS::Value
InterfaceToJsval(nsPIDOMWindow* aWindow, nsISupports* aObject, const nsIID* aIID);
DeviceStorageRequestManager();
bool IsOwningThread();
nsresult DispatchToOwningThread(nsIRunnable* aRunnable);
void StorePermission(size_t aAccess, bool aAllow);
uint32_t CheckPermission(size_t aAccess);
/* These must be called on the owning thread context of the device
storage object. It will hold onto a device storage reference until
all of the pending requests are completed or shutdown is called. */
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
mozilla::dom::DOMRequest** aRequest);
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
DeviceStorageCursorRequest* aRequest,
nsDOMDeviceStorageCursor** aCursor);
/* These may be called from any thread context and post a request
to the owning thread to resolve the underlying DOMRequest or
DOMCursor. In order to trigger FireDone for a DOMCursor, one
should call Resolve with only the request ID. */
nsresult Resolve(uint32_t aId, bool aForceDispatch);
nsresult Resolve(uint32_t aId, const nsString& aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, uint64_t aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, DeviceStorageFile* aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, mozilla::dom::BlobImpl* aValue, bool aForceDispatch);
nsresult Reject(uint32_t aId, const nsString& aReason);
nsresult Reject(uint32_t aId, const char* aReason);
void Shutdown();
private:
DeviceStorageRequestManager(const DeviceStorageRequestManager&) = delete;
DeviceStorageRequestManager& operator=(const DeviceStorageRequestManager&) = delete;
struct ListEntry {
nsRefPtr<mozilla::dom::DOMRequest> mRequest;
uint32_t mId;
bool mCursor;
};
typedef nsTArray<ListEntry> ListType;
typedef ListType::index_type ListIndex;
virtual ~DeviceStorageRequestManager();
uint32_t CreateInternal(mozilla::dom::DOMRequest* aRequest, bool aCursor);
nsresult ResolveInternal(ListIndex aIndex, JS::HandleValue aResult);
nsresult RejectInternal(ListIndex aIndex, const nsString& aReason);
nsresult DispatchOrAbandon(uint32_t aId, nsIRunnable* aRunnable);
ListType::index_type Find(uint32_t aId);
nsCOMPtr<nsIThread> mOwningThread;
ListType mPending; // owning thread or destructor only
mozilla::Mutex mMutex;
uint32_t mPermissionCache[DEVICE_STORAGE_ACCESS_COUNT];
bool mShutdown;
static mozilla::Atomic<uint32_t> sLastRequestId;
};
class DeviceStorageRequest
: public nsRunnable
{
protected:
DeviceStorageRequest();
public:
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest);
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest,
mozilla::dom::BlobImpl* aBlob);
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest,
DeviceStorageFileDescriptor* aDSFileDescriptor);
DeviceStorageAccessType GetAccess() const;
void GetStorageType(nsAString& aType) const;
DeviceStorageFile* GetFile() const;
DeviceStorageFileDescriptor* GetFileDescriptor() const;
DeviceStorageRequestManager* GetManager() const;
uint32_t GetId() const
{
return mId;
}
void PermissionCacheMissed()
{
mPermissionCached = false;
}
nsresult Cancel();
nsresult Allow();
nsresult Resolve()
{
/* Always dispatch an empty resolve because that signals a cursor end
and should not be executed directly from the caller's context due
to the object potentially getting freed before we return. */
uint32_t id = mId;
mId = DeviceStorageRequestManager::INVALID_ID;
return mManager->Resolve(id, true);
}
template<class T>
nsresult Resolve(T aValue)
{
uint32_t id = mId;
if (!mMultipleResolve) {
mId = DeviceStorageRequestManager::INVALID_ID;
}
return mManager->Resolve(id, aValue, ForceDispatch());
}
template<class T>
nsresult Reject(T aReason)
{
uint32_t id = mId;
mId = DeviceStorageRequestManager::INVALID_ID;
return mManager->Reject(id, aReason);
}
protected:
bool ForceDispatch() const
{
return !mSendToParent && mPermissionCached;
}
virtual ~DeviceStorageRequest();
virtual void Prepare();
virtual nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams);
nsresult AllowInternal();
nsresult SendToParentProcess();
nsRefPtr<DeviceStorageRequestManager> mManager;
nsRefPtr<DeviceStorageFile> mFile;
uint32_t mId;
nsRefPtr<mozilla::dom::BlobImpl> mBlob;
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
DeviceStorageAccessType mAccess;
bool mSendToParent;
bool mUseStreamTransport;
bool mCheckFile;
bool mCheckBlob;
bool mMultipleResolve;
bool mPermissionCached;
private:
DeviceStorageRequest(const DeviceStorageRequest&) = delete;
DeviceStorageRequest& operator=(const DeviceStorageRequest&) = delete;
};
class DeviceStorageCursorRequest final
: public DeviceStorageRequest
{
public:
DeviceStorageCursorRequest();
using DeviceStorageRequest::Initialize;
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest,
PRTime aSince);
void AddFiles(size_t aSize);
void AddFile(already_AddRefed<DeviceStorageFile> aFile);
nsresult Continue();
NS_IMETHOD Run() override;
protected:
virtual ~DeviceStorageCursorRequest()
{ };
nsresult SendContinueToParentProcess();
nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams) override;
size_t mIndex;
PRTime mSince;
nsString mStorageType;
nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
};
#endif

Просмотреть файл

@ -24,6 +24,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/TimelineConsumers.h"
#include "mozilla/EventTimelineMarker.h"
#include "EventListenerService.h"
#include "nsCOMArray.h"
@ -1056,29 +1057,6 @@ EventListenerManager::GetDocShellForTarget()
return docShell;
}
class EventTimelineMarker : public TimelineMarker
{
public:
EventTimelineMarker(nsDocShell* aDocShell, TracingMetadata aMetaData,
uint16_t aPhase, const nsAString& aCause)
: TimelineMarker(aDocShell, "DOMEvent", aMetaData, aCause)
, mPhase(aPhase)
{
}
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mType.Construct(GetCause());
aMarker.mEventPhase.Construct(mPhase);
}
}
private:
uint16_t mPhase;
};
/**
* Causes a check for event listeners and processing by them if they exist.
* @param an event listener
@ -1149,9 +1127,8 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
(*aDOMEvent)->GetType(typeStr);
uint16_t phase;
(*aDOMEvent)->GetEventPhase(&phase);
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<EventTimelineMarker>(ds, TRACING_INTERVAL_START,
phase, typeStr);
UniquePtr<TimelineMarker> marker = MakeUnique<EventTimelineMarker>(
typeStr, phase, MarkerTracingType::START);
TimelineConsumers::AddMarkerForDocShell(ds, Move(marker));
}
}
@ -1163,7 +1140,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
if (isTimelineRecording) {
nsDocShell* ds = static_cast<nsDocShell*>(docShell.get());
TimelineConsumers::AddMarkerForDocShell(ds, "DOMEvent", TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForDocShell(ds, "DOMEvent", MarkerTracingType::END);
}
}
}

Просмотреть файл

@ -1409,6 +1409,18 @@ ContentChild::RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
return true;
}
bool
ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId)
{
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
NS_WARN_IF(!service);
NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId)));
return true;
}
PCrashReporterChild*
ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
const uint32_t& processType)

Просмотреть файл

@ -276,6 +276,7 @@ public:
virtual bool DeallocPPresentationChild(PPresentationChild* aActor) override;
virtual bool RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
const nsString& aSessionId) override;
virtual bool RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId) override;
virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild() override;
virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override;

Просмотреть файл

@ -659,6 +659,12 @@ child:
*/
async NotifyPresentationReceiverLaunched(PBrowser aIframe, nsString aSessionId);
/**
* Notify the child that the info about a presentation receiver needs to be
* cleaned up.
*/
async NotifyPresentationReceiverCleanUp(nsString aSessionId);
parent:
/**
* Tell the content process some attributes of itself. This is

Просмотреть файл

@ -81,7 +81,7 @@ Presentation::Init()
// session instance is ready at beginning because the web content may access
// it right away; whereas the sender doesn't until |startSession| succeeds.
nsAutoString sessionId;
rv = service->GetExistentSessionIdAtLaunch(sessionId);
rv = service->GetExistentSessionIdAtLaunch(GetOwner()->WindowID(), sessionId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}

Просмотреть файл

@ -116,13 +116,19 @@ PresentationResponderLoadingCallback::Init(nsIDocShell* aDocShell)
nsresult
PresentationResponderLoadingCallback::NotifyReceiverReady()
{
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mProgress);
if (NS_WARN_IF(!window || !window->GetCurrentInnerWindow())) {
return NS_ERROR_NOT_AVAILABLE;
}
uint64_t windowId = window->GetCurrentInnerWindow()->WindowID();
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
return NS_ERROR_NOT_AVAILABLE;
}
return service->NotifyReceiverReady(mSessionId);
return service->NotifyReceiverReady(mSessionId, windowId);
}
// nsIWebProgressListener

Просмотреть файл

@ -221,6 +221,7 @@ PresentationService::HandleShutdown()
mListeners.Clear();
mSessionInfo.Clear();
mRespondingSessionIds.Clear();
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
@ -305,24 +306,11 @@ PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aReques
}
#endif
// Make sure the service is not handling another session request.
if (NS_WARN_IF(!mRespondingSessionId.IsEmpty())) {
ctrlChannel->Close(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR);
return rv;
}
// Set |mRespondingSessionId| to indicate the service is handling a session
// request. Then a session instance will be prepared while instantiating
// |navigator.presentation| at receiver side. This variable will be reset when
// registering the session listener.
mRespondingSessionId = sessionId;
// Create or reuse session info.
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(sessionId);
if (NS_WARN_IF(info)) {
// TODO Update here after session resumption becomes supported.
ctrlChannel->Close(NS_ERROR_DOM_ABORT_ERR);
mRespondingSessionId.Truncate();
return NS_ERROR_DOM_ABORT_ERR;
}
@ -330,7 +318,6 @@ PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aReques
rv = info->Init(ctrlChannel);
if (NS_WARN_IF(NS_FAILED(rv))) {
ctrlChannel->Close(NS_ERROR_DOM_ABORT_ERR);
mRespondingSessionId.Truncate();
return rv;
}
@ -483,10 +470,6 @@ PresentationService::RegisterSessionListener(const nsAString& aSessionId,
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aListener);
if (mRespondingSessionId.Equals(aSessionId)) {
mRespondingSessionId.Truncate();
}
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
if (NS_WARN_IF(!info)) {
// Notify the listener of TERMINATED since no correspondent session info is
@ -512,30 +495,73 @@ PresentationService::UnregisterSessionListener(const nsAString& aSessionId)
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
if (info) {
NS_WARN_IF(NS_FAILED(info->Close(NS_OK)));
RemoveSessionInfo(aSessionId);
UntrackSessionInfo(aSessionId);
return info->SetListener(nullptr);
}
return NS_OK;
}
NS_IMETHODIMP
PresentationService::GetExistentSessionIdAtLaunch(nsAString& aSessionId)
PresentationService::GetExistentSessionIdAtLaunch(uint64_t aWindowId,
nsAString& aSessionId)
{
aSessionId = mRespondingSessionId;
MOZ_ASSERT(NS_IsMainThread());
nsString* sessionId = mRespondingSessionIds.Get(aWindowId);
if (sessionId) {
aSessionId.Assign(*sessionId);
} else {
aSessionId.Truncate();
}
return NS_OK;
}
NS_IMETHODIMP
PresentationService::NotifyReceiverReady(const nsAString& aSessionId)
PresentationService::NotifyReceiverReady(const nsAString& aSessionId,
uint64_t aWindowId)
{
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
if (NS_WARN_IF(!info)) {
return NS_ERROR_NOT_AVAILABLE;
}
// Only track the responding info when an actual window ID, which would never
// be 0, is provided (for an in-process receiver page).
if (aWindowId != 0) {
mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
mRespondingWindowIds.Put(aSessionId, aWindowId);
}
return static_cast<PresentationResponderInfo*>(info.get())->NotifyResponderReady();
}
NS_IMETHODIMP
PresentationService::UntrackSessionInfo(const nsAString& aSessionId)
{
// Remove the session info.
mSessionInfo.Remove(aSessionId);
// Remove the in-process responding info if there's still any.
uint64_t windowId = 0;
if(mRespondingWindowIds.Get(aSessionId, &windowId)) {
mRespondingWindowIds.Remove(aSessionId);
mRespondingSessionIds.Remove(windowId);
}
return NS_OK;
}
bool
PresentationService::IsSessionAccessible(const nsAString& aSessionId,
base::ProcessId aProcessId)
{
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
if (NS_WARN_IF(!info)) {
return false;
}
return info->IsAccessible(aProcessId);
}
already_AddRefed<nsIPresentationService>
NS_CreatePresentationService()
{

Просмотреть файл

@ -38,15 +38,8 @@ public:
info.forget() : nullptr;
}
void
RemoveSessionInfo(const nsAString& aSessionId)
{
if (mRespondingSessionId.Equals(aSessionId)) {
mRespondingSessionId.Truncate();
}
mSessionInfo.Remove(aSessionId);
}
bool IsSessionAccessible(const nsAString& aSessionId,
base::ProcessId aProcessId);
private:
~PresentationService();
@ -57,9 +50,16 @@ private:
bool IsAppInstalled(nsIURI* aUri);
bool mIsAvailable;
nsString mRespondingSessionId;
nsRefPtrHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfo;
nsTObserverArray<nsCOMPtr<nsIPresentationListener>> mListeners;
// Store the mapping between the window ID of the in-process page and the ID
// of the responding session. It's used for an in-process receiver page to
// retrieve the correspondent session ID. Besides, also keep the mapping
// between the responding session ID and the window ID to help look up the
// window ID.
nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
};
} // namespace dom

Просмотреть файл

@ -192,10 +192,17 @@ PresentationSessionInfo::Close(nsresult aReason)
{
// The session is disconnected and it's a normal close. Simply change the
// state to TERMINATED.
if (!IsSessionReady() && NS_SUCCEEDED(aReason) && mListener) {
nsresult rv = mListener->NotifyStateChange(mSessionId,
nsIPresentationSessionListener::STATE_TERMINATED);
NS_WARN_IF(NS_FAILED(rv));
if (!IsSessionReady() && NS_SUCCEEDED(aReason)) {
if (mListener) {
// Notify the listener and the service will untrack the session info after
// the listener calls |UnregisterSessionListener|.
nsresult rv = mListener->NotifyStateChange(mSessionId,
nsIPresentationSessionListener::STATE_TERMINATED);
NS_WARN_IF(NS_FAILED(rv));
} else {
// Directly untrack the session info from the service.
NS_WARN_IF(NS_FAILED(UntrackFromService()));
}
}
Shutdown(aReason);
@ -231,16 +238,29 @@ PresentationSessionInfo::ReplyError(nsresult aError)
}
// Remove itself since it never succeeds.
return UntrackFromService();
}
/* virtual */ nsresult
PresentationSessionInfo::UntrackFromService()
{
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
return NS_ERROR_NOT_AVAILABLE;
}
static_cast<PresentationService*>(service.get())->RemoveSessionInfo(mSessionId);
static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId);
return NS_OK;
}
/* virtual */ bool
PresentationSessionInfo::IsAccessible(base::ProcessId aProcessId)
{
// No restriction by default.
return true;
}
// nsIPresentationSessionTransportCallback
NS_IMETHODIMP
PresentationSessionInfo::NotifyTransportReady()
@ -280,12 +300,17 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
Shutdown(aReason);
uint16_t state = (NS_WARN_IF(NS_FAILED(aReason))) ?
nsIPresentationSessionListener::STATE_DISCONNECTED :
nsIPresentationSessionListener::STATE_TERMINATED;
if (mListener) {
// It happens after the session is ready. Notify session state change.
uint16_t state = (NS_WARN_IF(NS_FAILED(aReason))) ?
nsIPresentationSessionListener::STATE_DISCONNECTED :
nsIPresentationSessionListener::STATE_TERMINATED;
// If the new state is TERMINATED. the service will untrack the session info
// after the listener calls |UnregisterSessionListener|.
return mListener->NotifyStateChange(mSessionId, state);
} else if (state == nsIPresentationSessionListener::STATE_TERMINATED) {
// Directly untrack the session info from the service.
return UntrackFromService();
}
return NS_OK;
@ -639,6 +664,34 @@ PresentationResponderInfo::InitTransportAndSendAnswer()
return NS_OK;
}
nsresult
PresentationResponderInfo::UntrackFromService()
{
// Remove the OOP responding info (if it has never been used).
if (mContentParent) {
NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId));
}
// Remove the session info (and the in-process responding info if there's any).
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
return NS_ERROR_NOT_AVAILABLE;
}
static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId);
return NS_OK;
}
bool
PresentationResponderInfo::IsAccessible(base::ProcessId aProcessId)
{
// Only the specific content process should access the responder info.
return (mContentParent) ?
aProcessId == static_cast<ContentParent*>(mContentParent.get())->OtherPid() :
false;
}
nsresult
PresentationResponderInfo::NotifyResponderReady()
{
@ -774,8 +827,10 @@ PresentationResponderInfo::ResolvedCallback(JSContext* aCx,
nsRefPtr<TabParent> tabParent = TabParent::GetFrom(frameLoader);
if (tabParent) {
// OOP frame
nsCOMPtr<nsIContentParent> cp = tabParent->Manager();
NS_WARN_IF(!static_cast<ContentParent*>(cp.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
// Notify the content process that a receiver page has launched, so it can
// start monitoring the loading progress.
mContentParent = tabParent->Manager();
NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
} else {
// In-process frame
nsCOMPtr<nsIDocShell> docShell;
@ -785,6 +840,7 @@ PresentationResponderInfo::ResolvedCallback(JSContext* aCx,
return;
}
// Keep an eye on the loading progress of the receiver page.
mLoadingCallback = new PresentationResponderLoadingCallback(mSessionId);
rv = mLoadingCallback->Init(docShell);
if (NS_WARN_IF(NS_FAILED(rv))) {

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef mozilla_dom_PresentationSessionInfo_h
#define mozilla_dom_PresentationSessionInfo_h
#include "base/process.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/nsRefPtr.h"
@ -92,6 +93,8 @@ public:
nsresult ReplyError(nsresult aReason);
virtual bool IsAccessible(base::ProcessId aProcessId);
protected:
virtual ~PresentationSessionInfo()
{
@ -107,6 +110,8 @@ protected:
return mIsResponderReady && mIsTransportReady;
}
virtual nsresult UntrackFromService();
nsString mUrl;
nsString mSessionId;
bool mIsResponderReady;
@ -184,6 +189,8 @@ public:
mPromise->AppendNativeHandler(this);
}
bool IsAccessible(base::ProcessId aProcessId) override;
private:
~PresentationResponderInfo()
{
@ -194,10 +201,16 @@ private:
nsresult InitTransportAndSendAnswer();
nsresult UntrackFromService() override;
nsRefPtr<PresentationResponderLoadingCallback> mLoadingCallback;
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsIPresentationChannelDescription> mRequesterDescription;
nsRefPtr<Promise> mPromise;
// The content parent communicating with the content process which the OOP
// receiver page belongs to.
nsCOMPtr<nsIContentParent> mContentParent;
};
} // namespace dom

Просмотреть файл

@ -32,7 +32,7 @@ interface nsIPresentationServiceCallback : nsISupports
void notifyError(in nsresult error);
};
[scriptable, uuid(5801efd9-9dba-4af7-8be9-8fc97c2d54a6)]
[scriptable, uuid(731af98a-2760-4e7f-bb59-c7cf6665f26f)]
interface nsIPresentationService : nsISupports
{
/*
@ -99,14 +99,29 @@ interface nsIPresentationService : nsISupports
/*
* Check if the presentation instance has an existent session ID at launch.
* An empty string is returned at sender side; non-empty at receiver side.
* An empty string is always returned at sender side. Whereas at receiver side
* the associated session ID is returned if the window ID and URI are matched;
* otherwise an empty string is returned.
*
* @param windowId: The inner window ID used to look up the session ID.
*/
DOMString getExistentSessionIdAtLaunch();
DOMString getExistentSessionIdAtLaunch(in uint64_t windowId);
/*
* Notify the receiver page is ready for presentation use.
*
* @param sessionId: An ID to identify presentation session.
* @param windowId: The inner window ID associated with the presentation
* session. (0 implies no window ID since no actual window
* uses 0 as its ID.)
*/
void notifyReceiverReady(in DOMString sessionId);
void notifyReceiverReady(in DOMString sessionId,
[optional] in uint64_t windowId);
/*
* Untrack the relevant info about the presentation session if there's any.
*
* @param sessionId: An ID to identify presentation session.
*/
void untrackSessionInfo(in DOMString sessionId);
};

Просмотреть файл

@ -58,9 +58,6 @@ parent:
PPresentationRequest(PresentationRequest aRequest);
sync GetExistentSessionIdAtLaunch()
returns (nsString aSessionId);
NotifyReceiverReady(nsString aSessionId);
};

Просмотреть файл

@ -38,6 +38,8 @@ PresentationIPCService::~PresentationIPCService()
{
mListeners.Clear();
mSessionListeners.Clear();
mRespondingSessionIds.Clear();
mRespondingWindowIds.Clear();
sPresentationChild = nullptr;
}
@ -130,6 +132,8 @@ PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
UntrackSessionInfo(aSessionId);
mSessionListeners.Remove(aSessionId);
if (sPresentationChild) {
NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsAutoString(aSessionId)));
@ -174,26 +178,53 @@ PresentationIPCService::NotifyAvailableChange(bool aAvailable)
}
NS_IMETHODIMP
PresentationIPCService::GetExistentSessionIdAtLaunch(nsAString& aSessionId)
PresentationIPCService::GetExistentSessionIdAtLaunch(uint64_t aWindowId,
nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoString sessionId(aSessionId);
NS_WARN_IF(!sPresentationChild->SendGetExistentSessionIdAtLaunch(&sessionId));
aSessionId = sessionId;
nsString* sessionId = mRespondingSessionIds.Get(aWindowId);
if (sessionId) {
aSessionId.Assign(*sessionId);
} else {
aSessionId.Truncate();
}
return NS_OK;
}
nsresult
PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId)
NS_IMETHODIMP
PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId,
uint64_t aWindowId)
{
MOZ_ASSERT(NS_IsMainThread());
// No actual window uses 0 as its ID.
if (NS_WARN_IF(aWindowId == 0)) {
return NS_ERROR_NOT_AVAILABLE;
}
// Track the responding info for an OOP receiver page.
mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
mRespondingWindowIds.Put(aSessionId, aWindowId);
mCallback = nullptr;
NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsAutoString(aSessionId)));
return NS_OK;
}
NS_IMETHODIMP
PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId)
{
// Remove the OOP responding info (if it has never been used).
uint64_t windowId = 0;
if(mRespondingWindowIds.Get(aSessionId, &windowId)) {
mRespondingWindowIds.Remove(aSessionId);
mRespondingSessionIds.Remove(windowId);
}
return NS_OK;
}
void
PresentationIPCService::NotifyPresentationChildDestroyed()
{
@ -204,6 +235,8 @@ nsresult
PresentationIPCService::MonitorResponderLoading(const nsAString& aSessionId,
nsIDocShell* aDocShell)
{
MOZ_ASSERT(NS_IsMainThread());
mCallback = new PresentationResponderLoadingCallback(aSessionId);
return mCallback->Init(aDocShell);
}

Просмотреть файл

@ -48,6 +48,14 @@ private:
nsTObserverArray<nsCOMPtr<nsIPresentationListener> > mListeners;
nsRefPtrHashtable<nsStringHashKey, nsIPresentationSessionListener> mSessionListeners;
nsRefPtr<PresentationResponderLoadingCallback> mCallback;
// Store the mapping between the window ID of the OOP page (in this process)
// and the ID of the responding session. It's used for an OOP receiver page
// to retrieve the correspondent session ID. Besides, also keep the mapping
// between the responding session ID and the window ID to help look up the
// window ID.
nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
};
} // namespace dom

Просмотреть файл

@ -120,6 +120,14 @@ PresentationParent::RecvUnregisterHandler()
PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId)
{
MOZ_ASSERT(mService);
// Validate the accessibility (primarily for receiver side) so that a
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aSessionId, OtherPid()))) {
return true;
}
mSessionIds.AppendElement(aSessionId);
NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, this)));
return true;
@ -148,7 +156,7 @@ PresentationParent::NotifyStateChange(const nsAString& aSessionId,
uint16_t aState)
{
if (NS_WARN_IF(mActorDestroyed ||
!SendNotifySessionStateChange(nsString(aSessionId), aState))) {
!SendNotifySessionStateChange(nsAutoString(aSessionId), aState))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -159,25 +167,17 @@ PresentationParent::NotifyMessage(const nsAString& aSessionId,
const nsACString& aData)
{
if (NS_WARN_IF(mActorDestroyed ||
!SendNotifyMessage(nsString(aSessionId), nsCString(aData)))) {
!SendNotifyMessage(nsAutoString(aSessionId), nsAutoCString(aData)))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
bool
PresentationParent::RecvGetExistentSessionIdAtLaunch(nsString* aSessionId)
{
MOZ_ASSERT(mService);
NS_WARN_IF(NS_FAILED(mService->GetExistentSessionIdAtLaunch(*aSessionId)));
return true;
}
bool
PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId)
{
MOZ_ASSERT(mService);
NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId)));
NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, 0)));
return true;
}
@ -218,6 +218,14 @@ nsresult
PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
{
MOZ_ASSERT(mService);
// Validate the accessibility (primarily for receiver side) so that a
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
}
nsTArray<mozilla::ipc::FileDescriptor> fds;
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aRequest.data(), fds);
if(NS_WARN_IF(!stream)) {
@ -235,6 +243,14 @@ nsresult
PresentationRequestParent::DoRequest(const TerminateRequest& aRequest)
{
MOZ_ASSERT(mService);
// Validate the accessibility (primarily for receiver side) so that a
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
}
nsresult rv = mService->Terminate(aRequest.sessionId());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NotifyError(rv);

Просмотреть файл

@ -50,8 +50,6 @@ public:
virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId) override;
virtual bool RecvGetExistentSessionIdAtLaunch(nsString* aSessionId) override;
virtual bool RecvNotifyReceiverReady(const nsString& aSessionId) override;
private:

Просмотреть файл

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Session API on a non-receiver page at receiver side (OOP)</title>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function is(a, b, msg) {
alert((a === b ? 'OK ' : 'KO ') + msg);
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function finish() {
alert('DONE');
}
function testSessionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available in OOP pages.");
ok(!navigator.presentation.session, "Non-receiving OOP pages shouldn't get a predefined presentation session instance.");
aResolve();
});
}
testSessionAvailable().
then(finish);
</script>
</body>
</html>

Просмотреть файл

@ -4,6 +4,7 @@ support-files =
PresentationSessionChromeScript.js
file_presentation_receiver.html
file_presentation_receiver_oop.html
file_presentation_non_receiver_oop.html
file_presentation_receiver_start_session_error.html
[test_presentation_device_info.html]

Просмотреть файл

@ -82,6 +82,9 @@ function testIncomingSessionRequest() {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
ok(!navigator.presentation.session, "Non-receiving in-process pages shouldn't get a predefined presentation session instance.");
aResolve();
});

Просмотреть файл

@ -19,6 +19,10 @@
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver_oop.html');
var nonReceiverUrl = SimpleTest.getTestFileURL('file_presentation_non_receiver_oop.html');
var isReceiverFinished = false;
var isNonReceiverFinished = false;
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
@ -27,17 +31,17 @@ function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
// Create a receiver OOP iframe.
SpecialPowers.addPermission('presentation', true, { url: receiverUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true });
var iframe = document.createElement('iframe');
iframe.setAttribute('remote', 'true');
iframe.setAttribute('mozbrowser', 'true');
iframe.setAttribute('src', receiverUrl);
var receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute('remote', 'true');
receiverIframe.setAttribute('mozbrowser', 'true');
receiverIframe.setAttribute('src', receiverUrl);
// This event is triggered when the iframe calls "alert".
iframe.addEventListener('mozbrowsershowmodalprompt', function listener(aEvent) {
receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
@ -50,19 +54,58 @@ function setup() {
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
receiverIframe.removeEventListener('mozbrowsershowmodalprompt', receiverListener);
teardown();
isReceiverFinished = true;
if (isNonReceiverFinished) {
teardown();
}
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(iframe);
document.body.appendChild(receiverIframe);
aResolve(iframe);
aResolve(receiverIframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
// Create a non-receiver OOP iframe.
SpecialPowers.addPermission('presentation', true, { url: nonReceiverUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true });
var nonReceiverIframe = document.createElement('iframe');
nonReceiverIframe.setAttribute('remote', 'true');
nonReceiverIframe.setAttribute('mozbrowser', 'true');
nonReceiverIframe.setAttribute('src', nonReceiverUrl);
// This event is triggered when the iframe calls "alert".
nonReceiverIframe.addEventListener('mozbrowsershowmodalprompt', function nonReceiverListener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
nonReceiverIframe.removeEventListener('mozbrowsershowmodalprompt', nonReceiverListener);
isNonReceiverFinished = true;
if (isReceiverFinished) {
teardown();
}
}
}, false);
document.body.appendChild(nonReceiverIframe);
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
gScript.removeMessageListener('offer-received', offerReceivedHandler);
info("An offer is received.");

Просмотреть файл

@ -30,6 +30,7 @@
#include "nsPrintfCString.h"
#include "nsRenderingContext.h"
#include "nsSVGIntegrationUtils.h"
#include "mozilla/LayerTimelineMarker.h"
#include "mozilla/Move.h"
#include "mozilla/ReverseIterator.h"
@ -5497,36 +5498,6 @@ static void DrawForcedBackgroundColor(DrawTarget& aDrawTarget,
}
}
class LayerTimelineMarker : public TimelineMarker
{
public:
LayerTimelineMarker(nsDocShell* aDocShell, const nsIntRegion& aRegion)
: TimelineMarker(aDocShell, "Layer", TRACING_EVENT)
, mRegion(aRegion)
{
}
~LayerTimelineMarker()
{
}
virtual void AddLayerRectangles(mozilla::dom::Sequence<mozilla::dom::ProfileTimelineLayerRect>& aRectangles) override
{
nsIntRegionRectIterator it(mRegion);
while (const nsIntRect* iterRect = it.Next()) {
mozilla::dom::ProfileTimelineLayerRect rect;
rect.mX = iterRect->X();
rect.mY = iterRect->Y();
rect.mWidth = iterRect->Width();
rect.mHeight = iterRect->Height();
aRectangles.AppendElement(rect, fallible);
}
}
private:
nsIntRegion mRegion;
};
/*
* A note on residual transforms:
*
@ -5687,8 +5658,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
bool isRecording;
docShell->GetRecordProfileTimelineMarkers(&isRecording);
if (isRecording) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<LayerTimelineMarker>(docShell, aRegionToDraw);
UniquePtr<TimelineMarker> marker = MakeUnique<LayerTimelineMarker>(aRegionToDraw);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
}

Просмотреть файл

@ -78,6 +78,7 @@ struct EventRadiusPrefs
bool mRepositionEventCoords;
bool mTouchClusterDetectionEnabled;
uint32_t mLimitReadableSize;
uint32_t mKeepLimitSizeForCluster;
};
static EventRadiusPrefs sMouseEventRadiusPrefs;
@ -130,6 +131,9 @@ GetPrefsFor(EventClassID aEventClassID)
nsPrintfCString limitReadableSizePref("ui.zoomedview.limitReadableSize", prefBranch);
Preferences::AddUintVarCache(&prefs->mLimitReadableSize, limitReadableSizePref.get(), 8);
nsPrintfCString keepLimitSize("ui.zoomedview.keepLimitSize", prefBranch);
Preferences::AddUintVarCache(&prefs->mKeepLimitSizeForCluster, keepLimitSize.get(), 16);
}
return prefs;
@ -356,6 +360,21 @@ static bool IsElementPresent(nsTArray<nsIFrame*>& aCandidates, const nsAutoStrin
return false;
}
static bool
IsLargeElement(nsIFrame* aFrame, const EventRadiusPrefs* aPrefs)
{
uint32_t keepLimitSizeForCluster = aPrefs->mKeepLimitSizeForCluster;
nsSize frameSize = aFrame->GetSize();
nsPresContext* pc = aFrame->PresContext();
nsIPresShell* presShell = pc->PresShell();
float cumulativeResolution = presShell->GetCumulativeResolution();
if ((pc->AppUnitsToGfxUnits(frameSize.height) * cumulativeResolution) > keepLimitSizeForCluster &&
(pc->AppUnitsToGfxUnits(frameSize.width) * cumulativeResolution) > keepLimitSizeForCluster) {
return true;
}
return false;
}
static nsIFrame*
GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame,
const nsRect& aTargetRect, const EventRadiusPrefs* aPrefs,
@ -413,7 +432,8 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame,
// and "for" attribute is present in label element, search the frame list for the "for" element
// If this element is present in the current list, do not count the frame in
// the cluster elements counter
if (labelTargetId.IsEmpty() || !IsElementPresent(aCandidates, labelTargetId)) {
if ((labelTargetId.IsEmpty() || !IsElementPresent(aCandidates, labelTargetId)) &&
!IsLargeElement(f, aPrefs)) {
if (std::find(mContentsInCluster.begin(), mContentsInCluster.end(), clickableContent) == mContentsInCluster.end()) {
mContentsInCluster.push_back(clickableContent);
}

Просмотреть файл

@ -18,6 +18,7 @@
#include "RestyleManager.h"
#include "RestyleTrackerInlines.h"
#include "nsTransitionManager.h"
#include "mozilla/RestyleTimelineMarker.h"
namespace mozilla {
@ -97,31 +98,6 @@ struct RestyleCollector {
#endif
};
class RestyleTimelineMarker : public TimelineMarker
{
public:
RestyleTimelineMarker(nsDocShell* aDocShell,
TracingMetadata aMetaData,
nsRestyleHint aRestyleHint)
: TimelineMarker(aDocShell, "Styles", aMetaData)
{
if (aRestyleHint) {
mRestyleHint.AssignWithConversion(RestyleManager::RestyleHintToString(aRestyleHint));
}
}
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mRestyleHint.Construct(mRestyleHint);
}
}
private:
nsAutoString mRestyleHint;
};
static PLDHashOperator
CollectRestyles(nsISupports* aElement,
nsAutoPtr<RestyleTracker::RestyleData>& aData,
@ -358,10 +334,8 @@ RestyleTracker::DoProcessRestyles()
}
if (isTimelineRecording) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<RestyleTimelineMarker>(docShell,
TRACING_INTERVAL_START,
data->mRestyleHint);
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
data->mRestyleHint, MarkerTracingType::START);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
@ -376,10 +350,8 @@ RestyleTracker::DoProcessRestyles()
AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
if (isTimelineRecording) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<RestyleTimelineMarker>(docShell,
TRACING_INTERVAL_END,
data->mRestyleHint);
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
data->mRestyleHint, MarkerTracingType::END);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
}
@ -423,10 +395,8 @@ RestyleTracker::DoProcessRestyles()
}
#endif
if (isTimelineRecording) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<RestyleTimelineMarker>(docShell,
TRACING_INTERVAL_START,
currentRestyle->mRestyleHint);
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
currentRestyle->mRestyleHint, MarkerTracingType::START);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
@ -436,10 +406,8 @@ RestyleTracker::DoProcessRestyles()
currentRestyle->mRestyleHintData);
if (isTimelineRecording) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<RestyleTimelineMarker>(docShell,
TRACING_INTERVAL_END,
currentRestyle->mRestyleHint);
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
currentRestyle->mRestyleHint, MarkerTracingType::END);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
}

Просмотреть файл

@ -8983,7 +8983,7 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
if (docShell) {
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", TRACING_INTERVAL_START);
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
}
if (mReflowContinueTimer) {
@ -9160,7 +9160,7 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
}
if (docShell) {
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
}
return !interrupted;
}

Просмотреть файл

@ -1708,7 +1708,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
for (nsDocShell* docShell : profilingDocShells) {
// For the sake of the profile timeline's simplicity, this is flagged as
// paint even if it includes creating display lists
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", TRACING_INTERVAL_START);
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::START);
}
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
@ -1725,7 +1725,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
}
#endif
for (nsDocShell* docShell : profilingDocShells) {
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::END);
}
if (nsContentUtils::XPConnect()) {

Просмотреть файл

@ -415,6 +415,7 @@ pref("font.size.inflation.minTwips", 0);
pref("browser.ui.zoom.force-user-scalable", false);
pref("ui.zoomedview.enabled", true);
pref("ui.zoomedview.keepLimitSize", 16); // value in layer pixels, used to not keep the large elements in the cluster list (Bug 1191041)
pref("ui.zoomedview.limitReadableSize", 8); // value in layer pixels
pref("ui.zoomedview.defaultZoomFactor", 2);
pref("ui.zoomedview.simplified", true); // Do not display all the zoomed view controls

Просмотреть файл

@ -241,7 +241,7 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
touchListener = new ZoomedViewTouchListener();
EventDispatcher.getInstance().registerGeckoThreadListener(this,
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange",
"Gesture:CloseZoomedView");
"Gesture:CloseZoomedView", "Browser:ZoomToPageWidth", "Browser:ZoomToRect");
}
void destroy() {
@ -250,7 +250,7 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange",
"Gesture:CloseZoomedView");
"Gesture:CloseZoomedView", "Browser:ZoomToPageWidth", "Browser:ZoomToRect");
}
// This method (onFinishInflate) is called only when the zoomed view class is used inside
@ -562,8 +562,13 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
}
public void stopZoomDisplay(boolean withAnimation) {
// If "startZoomDisplay" is running and not totally completed (Gecko thread is still
// running and "showZoomedView" has not yet been called), the zoomed view will be
// displayed after this call and it should not.
// Force the stop of the zoomed view, changing the shouldSetVisibleOnUpdate flag
// before the test of the visibility.
shouldSetVisibleOnUpdate = false;
if (getVisibility() == View.VISIBLE) {
shouldSetVisibleOnUpdate = false;
hideZoomedView(withAnimation);
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
if (layerView != null) {
@ -616,7 +621,9 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
refreshZoomedViewSize(metrics);
} else if (event.equals("Content:LocationChange")) {
stopZoomDisplay(false);
} else if (event.equals("Gesture:CloseZoomedView")) {
} else if (event.equals("Gesture:CloseZoomedView") ||
event.equals("Browser:ZoomToPageWidth") ||
event.equals("Browser:ZoomToRect")) {
stopZoomDisplay(true);
}
} catch (JSONException e) {

Просмотреть файл

@ -123,13 +123,24 @@ this.Async = {
Services.obs.addObserver(function onQuitApplication() {
Services.obs.removeObserver(onQuitApplication, "quit-application");
Async.checkAppReady = function() {
throw Components.Exception("App. Quitting", Cr.NS_ERROR_ABORT);
let exception = Components.Exception("App. Quitting", Cr.NS_ERROR_ABORT);
exception.appIsShuttingDown = true;
throw exception;
};
}, "quit-application", false);
// In the common case, checkAppReady just returns true
return (Async.checkAppReady = function() { return true; })();
},
/**
* Check if the passed exception is one raised by checkAppReady. Typically
* this will be used in exception handlers to allow such exceptions to
* make their way to the top frame and allow the app to actually terminate.
*/
isShutdownException(exception) {
return exception && exception.appIsShuttingDown === true;
},
/**
* Return the two things you need to make an asynchronous call synchronous
* by spinning the event loop.

Просмотреть файл

@ -667,7 +667,7 @@ this.BrowserIDManager.prototype = {
this._ensureValidToken().then(cb, cb);
try {
cb.wait();
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.error("Failed to fetch a token for authentication", ex);
return null;
}

Просмотреть файл

@ -307,7 +307,7 @@ Store.prototype = {
// originating exception.
// ex.cause will carry its stack with it when rethrown.
throw ex.cause;
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.warn("Failed to apply incoming record " + record.id);
this._log.warn("Encountered exception: " + Utils.exceptionStr(ex));
failed.push(record.id);
@ -992,7 +992,7 @@ SyncEngine.prototype = {
this._tracker.ignoreAll = true;
try {
failed = failed.concat(this._store.applyIncomingBatch(applyBatch));
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
// Catch any error that escapes from applyIncomingBatch. At present
// those will all be abort events.
this._log.warn("Got exception " + Utils.exceptionStr(ex) +
@ -1086,7 +1086,7 @@ SyncEngine.prototype = {
self._log.warn("Reconciliation failed: aborting incoming processing.");
failed.push(item.id);
aborting = ex.cause;
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
self._log.warn("Failed to reconcile incoming record " + item.id);
self._log.warn("Encountered exception: " + Utils.exceptionStr(ex));
failed.push(item.id);
@ -1458,8 +1458,7 @@ SyncEngine.prototype = {
out.encrypt(this.service.collectionKeys.keyForCollection(this.name));
up.pushData(out);
}
catch(ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.warn("Error creating record: " + Utils.exceptionStr(ex));
}
@ -1550,8 +1549,7 @@ SyncEngine.prototype = {
try {
this._log.trace("Trying to decrypt a record from the server..");
test.get();
}
catch(ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.debug("Failed test decrypt: " + Utils.exceptionStr(ex));
}

Просмотреть файл

@ -256,7 +256,7 @@ BookmarksEngine.prototype = {
stmt.params.id = id;
let rows = Async.querySpinningly(stmt, ["url"]);
url = rows.length == 0 ? "<not found>" : rows[0].url;
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
if (ex instanceof Ci.mozIStorageError) {
url = `<failed: Storage error: ${ex.message} (${ex.result})>`;
} else {
@ -441,7 +441,7 @@ BookmarksEngine.prototype = {
let guidMap;
try {
guidMap = this._buildGUIDMap();
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.warn("Got exception \"" + Utils.exceptionStr(ex) +
"\" building GUID map." +
" Skipping all other incoming items.");

Просмотреть файл

@ -222,7 +222,7 @@ HistoryStore.prototype = {
} else {
shouldApply = this._recordToPlaceInfo(record);
}
} catch(ex) {
} catch (ex if !Async.isShutdownException(ex)) {
failed.push(record.id);
shouldApply = false;
}

Просмотреть файл

@ -10,6 +10,7 @@ Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-common/async.js");
this.LoginRec = function LoginRec(collection, id) {
CryptoWrapper.call(this, collection, id);
@ -67,7 +68,7 @@ PasswordEngine.prototype = {
// record success.
Svc.Prefs.set("deletePwdFxA", true);
Svc.Prefs.reset("deletePwd"); // The old prefname we previously used.
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.debug("Password deletes failed: " + Utils.exceptionStr(ex));
}
}

Просмотреть файл

@ -13,6 +13,7 @@ Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-common/async.js");
// Lazy import to prevent unnecessary load on startup.
for (let symbol of ["BulkKeyBundle", "SyncKeyBundle"]) {
@ -457,7 +458,7 @@ IdentityManager.prototype = {
// cache.
try {
service.recordManager.get(service.storageURL + "meta/fxa_credentials");
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.warn("Failed to pre-fetch the migration sentinel", ex);
}
},

Просмотреть файл

@ -23,6 +23,7 @@ Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/keys.js");
Cu.import("resource://services-sync/resource.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-common/async.js");
this.WBORecord = function WBORecord(collection, id) {
this.data = {};
@ -235,7 +236,7 @@ RecordManager.prototype = {
record.deserialize(this.response);
return this.set(url, record);
} catch(ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.debug("Failed to import record: " + Utils.exceptionStr(ex));
return null;
}

Просмотреть файл

@ -403,7 +403,7 @@ Resource.prototype = {
try {
this._doRequest(action, data, callback);
return Async.waitForSyncCallback(cb);
} catch(ex) {
} catch (ex if !Async.isShutdownException(ex)) {
// Combine the channel stack with this request stack. Need to create
// a new error object for that.
let error = Error(ex.message);
@ -556,7 +556,7 @@ ChannelListener.prototype = {
try {
this._onProgress();
} catch (ex) {
} catch (ex if !Async.isShutdownException(ex)) {
this._log.warn("Got exception calling onProgress handler during fetch of "
+ req.URI.spec);
this._log.debug(CommonUtils.exceptionStr(ex));

Просмотреть файл

@ -3,8 +3,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# XXX Bug 1181261 - Please update config in testing/mozharness/config
# instead. This file is still needed for mulet mochitests, but should
# be removed once bug 1188330 is finished.
# instead. This file is still needed for taskcluster emulator tests,
# but should be removed once bug 1188330 is finished.
config = {
"suite_definitions": {

Просмотреть файл

@ -0,0 +1,95 @@
# 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/.
# XXX Bug 1181261 - Please update config in testing/mozharness/config
# instead. This file is still needed for taskcluster emulator tests,
# but should be removed once bug 1188330 is finished.
config = {
"suite_definitions": {
"gaiatest_desktop": {
"options": [
"--restart",
"--timeout=%(timeout)s",
"--type=%(type)s",
"--testvars=%(testvars)s",
"--profile=%(profile)s",
"--symbols-path=%(symbols_path)s",
"--gecko-log=%(gecko_log)s",
"--xml-output=%(xml_output)s",
"--html-output=%(html_output)s",
"--log-raw=%(raw_log_file)s",
"--log-errorsummary=%(error_summary_file)s",
"--binary=%(binary)s",
"--address=%(address)s",
"--total-chunks=%(total_chunks)s",
"--this-chunk=%(this_chunk)s"
],
"run_filename": "",
"testsdir": ""
},
"gaiatest_emulator": {
"options": [
"--restart",
"--timeout=%(timeout)s",
"--type=%(type)s",
"--testvars=%(testvars)s",
"--profile=%(profile)s",
"--symbols-path=%(symbols_path)s",
"--xml-output=%(xml_output)s",
"--html-output=%(html_output)s",
"--log-raw=%(raw_log_file)s",
"--log-errorsummary=%(error_summary_file)s",
"--logcat-dir=%(logcat_dir)s",
"--emulator=%(emulator)s",
"--homedir=%(homedir)s"
],
"run_filename": "",
"testsdir": ""
},
"marionette_desktop": {
"options": [
"--type=%(type)s",
"--log-raw=%(raw_log_file)s",
"--log-errorsummary=%(error_summary_file)s",
"--binary=%(binary)s",
"--address=%(address)s",
"--symbols-path=%(symbols_path)s"
],
"run_filename": "",
"testsdir": ""
},
"marionette_emulator": {
"options": [
"--type=%(type)s",
"--log-raw=%(raw_log_file)s",
"--log-errorsummary=%(error_summary_file)s",
"--logcat-dir=%(logcat_dir)s",
"--emulator=%(emulator)s",
"--homedir=%(homedir)s",
"--symbols-path=%(symbols_path)s"
],
"run_filename": "",
"testsdir": ""
},
"webapi_desktop": {
"options": [],
"run_filename": "",
"testsdir": ""
},
"webapi_emulator": {
"options": [
"--type=%(type)s",
"--log-raw=%(raw_log_file)s",
"--log-errorsummary=%(error_summary_file)s",
"--symbols-path=%(symbols_path)s",
"--logcat-dir=%(logcat_dir)s",
"--emulator=%(emulator)s",
"--homedir=%(homedir)s"
],
"run_filename": "",
"testsdir": ""
}
}
}

Просмотреть файл

@ -21,7 +21,7 @@ RUN git config --global user.email "mozilla@example.com" && \
git config --global user.name "mozilla"
# VCS Tools
RUN npm install -g taskcluster-vcs@2.3.8
RUN npm install -g taskcluster-vcs@2.3.9
# TODO enable worker
# TODO volume mount permissions will be an issue

Просмотреть файл

@ -1 +1 @@
0.5.7
0.5.8

Просмотреть файл

@ -31,7 +31,7 @@ RUN git config --global user.email "mozilla@example.com" && \
# Get node packages
RUN npm install -g taskcluster-vcs@2.3.8
RUN npm install -g taskcluster-vcs@2.3.9
WORKDIR /home/worker

Просмотреть файл

@ -1 +1 @@
0.0.5
0.0.6

Просмотреть файл

@ -18,7 +18,7 @@ RUN chmod u+x /usr/local/bin/linux64-minidump_stackwalk
RUN apt-get install -y python-pip && pip install virtualenv;
RUN mkdir Documents; mkdir Pictures; mkdir Music; mkdir Videos; mkdir artifacts
RUN npm install -g npm@^2.0.0
RUN npm install -g taskcluster-vcs@2.3.8
RUN npm install -g taskcluster-vcs@2.3.9
RUN npm install -g taskcluster-npm-cache@1.1.14
RUN rm -Rf .cache && mkdir -p .cache
ENV PATH $PATH:/home/worker/bin

Просмотреть файл

@ -1 +1 @@
0.3.6
0.3.7

Просмотреть файл

@ -11,7 +11,7 @@ RUN bash /tmp/system-setup.sh
# configure git and install tc-vcs
RUN git config --global user.email "nobody@mozilla.com" && \
git config --global user.name "mozilla"
RUN npm install -g taskcluster-vcs@2.3.8
RUN npm install -g taskcluster-vcs@2.3.9
# Ensure that build specific dependencies live in a single layer
ADD build-setup.sh /tmp/build-setup.sh

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше