Bug 1658097 - [fission] Send resource timing data for cross-origin frames to the correct process r=nika,necko-reviewers,dragana

Differential Revision: https://phabricator.services.mozilla.com/D96754
This commit is contained in:
Valentin Gosu 2020-11-13 13:48:00 +00:00
parent 4916cac75d
commit bd132e112d
12 changed files with 292 additions and 13 deletions

View File

@ -196,6 +196,7 @@
#include "base/task.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/dom/PCycleCollectWithLogsChild.h"
#include "mozilla/dom/PerformanceStorage.h"
#include "nsChromeRegistryContent.h"
#include "nsFrameMessageManager.h"
#include "nsIScriptSecurityManager.h"
@ -4078,6 +4079,24 @@ mozilla::ipc::IPCResult ContentChild::RecvScriptError(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvReportFrameTimingData(
uint64_t innerWindowId, const nsString& entryName,
const nsString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
auto* innerWindow = nsGlobalWindowInner::GetInnerWindowWithId(innerWindowId);
if (!innerWindow) {
return IPC_OK();
}
mozilla::dom::Performance* performance = innerWindow->GetPerformance();
if (!performance) {
return IPC_OK();
}
performance->AsPerformanceStorage()->AddEntry(entryName, initiatorType,
std::move(aData));
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvLoadURI(
const MaybeDiscarded<BrowsingContext>& aContext,
nsDocShellLoadState* aLoadState, bool aSetNavigating,

View File

@ -763,6 +763,10 @@ class ContentChild final : public PContentChild,
const nsCString& aCategory, const bool& aFromPrivateWindow,
const uint64_t& aInnerWindowId, const bool& aFromChromeContext);
mozilla::ipc::IPCResult RecvReportFrameTimingData(
uint64_t innerWindowId, const nsString& entryName,
const nsString& initiatorType, UniquePtr<PerformanceTimingData>&& aData);
mozilla::ipc::IPCResult RecvLoadURI(
const MaybeDiscarded<BrowsingContext>& aContext,
nsDocShellLoadState* aLoadState, bool aSetNavigating,

View File

@ -4504,6 +4504,23 @@ mozilla::ipc::IPCResult ContentParent::RecvConsoleMessage(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvReportFrameTimingData(
uint64_t aInnerWindowId, const nsString& entryName,
const nsString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
RefPtr<WindowGlobalParent> parent =
WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
if (!parent || !parent->GetContentParent()) {
return IPC_OK();
}
MOZ_ASSERT(parent->GetContentParent() != this,
"No need to bounce around if in the same process");
Unused << parent->GetContentParent()->SendReportFrameTimingData(
aInnerWindowId, entryName, initiatorType, std::move(aData));
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvScriptError(
const nsString& aMessage, const nsString& aSourceName,
const nsString& aSourceLine, const uint32_t& aLineNumber,

View File

@ -1097,6 +1097,10 @@ class ContentParent final
const nsCString& aCategory, const bool& aIsFromPrivateWindow,
const uint64_t& aInnerWindowId, const bool& aIsFromChromeContext);
mozilla::ipc::IPCResult RecvReportFrameTimingData(
uint64_t innerWindowId, const nsString& entryName,
const nsString& initiatorType, UniquePtr<PerformanceTimingData>&& aData);
mozilla::ipc::IPCResult RecvScriptErrorWithStack(
const nsString& aMessage, const nsString& aSourceName,
const nsString& aSourceLine, const uint32_t& aLineNumber,

View File

@ -133,6 +133,7 @@ using class mozilla::dom::SessionHistoryInfo from "mozilla/dom/SessionHistoryEnt
using nsPoint from "mozilla/GfxMessageUtils.h";
using struct mozilla::dom::LoadingSessionHistoryInfo from "mozilla/dom/SessionHistoryEntry.h";
using mozilla::PDMFactory::MediaCodecsSupported from "PDMFactory.h";
using mozilla::dom::PerformanceTimingData from "mozilla/dom/PerformanceTiming.h";
union ChromeRegistryItem
{
@ -1708,6 +1709,16 @@ both:
nsCString category, bool privateWindow, uint64_t innerWindowId,
bool fromChromeContext);
/**
* Used in fission to report timing data when the parent window is in
* another process. Child frame will send data to its ContentParent which
* will then identify the ContentParent for the innerWindowId and pass
* the data to the correct process.
*/
async ReportFrameTimingData(uint64_t innerWindowId, nsString entryName,
nsString initiatorType,
UniquePtr<PerformanceTimingData> aData);
async CommitBrowsingContextTransaction(MaybeDiscardedBrowsingContext aContext,
BrowsingContextTransaction aTransaction,
uint64_t aEpoch);

View File

@ -154,6 +154,12 @@ void PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
AddRawEntry(std::move(performanceTimingData), initiatorType, entryName);
}
void PerformanceMainThread::AddEntry(const nsString& entryName,
const nsString& initiatorType,
UniquePtr<PerformanceTimingData>&& aData) {
AddRawEntry(std::move(aData), initiatorType, entryName);
}
void PerformanceMainThread::AddRawEntry(UniquePtr<PerformanceTimingData> aData,
const nsAString& aInitiatorType,
const nsAString& aEntryName) {

View File

@ -34,6 +34,9 @@ class PerformanceMainThread final : public Performance,
virtual void AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel) override;
virtual void AddEntry(const nsString& entryName,
const nsString& initiatorType,
UniquePtr<PerformanceTimingData>&& aData) override;
void AddRawEntry(UniquePtr<PerformanceTimingData>,
const nsAString& aInitiatorType,

View File

@ -23,6 +23,9 @@ class PerformanceStorage {
virtual void AddEntry(nsIHttpChannel* aChannel,
nsITimedChannel* aTimedChannel) = 0;
virtual void AddEntry(const nsString& entryName,
const nsString& initiatorType,
UniquePtr<PerformanceTimingData>&& aData) = 0;
protected:
virtual ~PerformanceStorage() = default;

View File

@ -29,7 +29,9 @@ class PerformanceStorageWorker final : public PerformanceStorage {
void AddEntry(nsIHttpChannel* aChannel,
nsITimedChannel* aTimedChannel) override;
virtual void AddEntry(const nsString& entryName,
const nsString& initiatorType,
UniquePtr<PerformanceTimingData>&& aData) override {}
void AddEntryOnWorker(UniquePtr<PerformanceProxyData>&& aData);
private:

View File

@ -16,6 +16,9 @@
#include "nsWrapperCache.h"
#include "Performance.h"
#include "nsITimedChannel.h"
#include "mozilla/ipc/IPDLParamTraits.h"
#include "ipc/IPCMessageUtils.h"
#include "mozilla/net/nsServerTiming.h"
class nsIHttpChannel;
@ -26,8 +29,11 @@ class PerformanceTiming;
class PerformanceTimingData final {
friend class PerformanceTiming;
friend struct mozilla::ipc::IPDLParamTraits<
mozilla::dom::PerformanceTimingData>;
public:
PerformanceTimingData() = default; // For deserialization
// This can return null.
static PerformanceTimingData* Create(nsITimedChannel* aChannel,
nsIHttpChannel* aHttpChannel,
@ -181,28 +187,28 @@ class PerformanceTimingData final {
// There are only 2 possible values: (1) logicaly equal to navigationStart
// TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results
// are relative to the navigation start).
DOMHighResTimeStamp mZeroTime;
DOMHighResTimeStamp mZeroTime = 0;
DOMHighResTimeStamp mFetchStart;
DOMHighResTimeStamp mFetchStart = 0;
uint64_t mEncodedBodySize;
uint64_t mTransferSize;
uint64_t mDecodedBodySize;
uint64_t mEncodedBodySize = 0;
uint64_t mTransferSize = 0;
uint64_t mDecodedBodySize = 0;
uint8_t mRedirectCount;
uint8_t mRedirectCount = 0;
bool mAllRedirectsSameOrigin;
bool mAllRedirectsSameOrigin = false;
// If the resourceTiming object should have non-zero redirectStart and
// redirectEnd attributes. It is false if there were no redirects, or if any
// of the responses didn't pass the timing-allow-check
bool mReportCrossOriginRedirect;
bool mReportCrossOriginRedirect = false;
bool mSecureConnection;
bool mSecureConnection = false;
bool mTimingAllowed;
bool mTimingAllowed = false;
bool mInitialized;
bool mInitialized = false;
};
// Script "performance.timing" object
@ -408,4 +414,181 @@ class PerformanceTiming final : public nsWrapperCache {
} // namespace dom
} // namespace mozilla
namespace mozilla {
namespace ipc {
template <>
struct IPDLParamTraits<mozilla::dom::PerformanceTimingData> {
typedef mozilla::dom::PerformanceTimingData paramType;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
WriteIPDLParam(aMsg, aActor, aParam.mServerTiming);
WriteIPDLParam(aMsg, aActor, aParam.mNextHopProtocol);
WriteIPDLParam(aMsg, aActor, aParam.mAsyncOpen);
WriteIPDLParam(aMsg, aActor, aParam.mRedirectStart);
WriteIPDLParam(aMsg, aActor, aParam.mRedirectEnd);
WriteIPDLParam(aMsg, aActor, aParam.mDomainLookupStart);
WriteIPDLParam(aMsg, aActor, aParam.mDomainLookupEnd);
WriteIPDLParam(aMsg, aActor, aParam.mConnectStart);
WriteIPDLParam(aMsg, aActor, aParam.mSecureConnectionStart);
WriteIPDLParam(aMsg, aActor, aParam.mConnectEnd);
WriteIPDLParam(aMsg, aActor, aParam.mRequestStart);
WriteIPDLParam(aMsg, aActor, aParam.mResponseStart);
WriteIPDLParam(aMsg, aActor, aParam.mCacheReadStart);
WriteIPDLParam(aMsg, aActor, aParam.mResponseEnd);
WriteIPDLParam(aMsg, aActor, aParam.mCacheReadEnd);
WriteIPDLParam(aMsg, aActor, aParam.mWorkerStart);
WriteIPDLParam(aMsg, aActor, aParam.mWorkerRequestStart);
WriteIPDLParam(aMsg, aActor, aParam.mWorkerResponseEnd);
WriteIPDLParam(aMsg, aActor, aParam.mZeroTime);
WriteIPDLParam(aMsg, aActor, aParam.mFetchStart);
WriteIPDLParam(aMsg, aActor, aParam.mEncodedBodySize);
WriteIPDLParam(aMsg, aActor, aParam.mTransferSize);
WriteIPDLParam(aMsg, aActor, aParam.mDecodedBodySize);
WriteIPDLParam(aMsg, aActor, aParam.mRedirectCount);
WriteIPDLParam(aMsg, aActor, aParam.mAllRedirectsSameOrigin);
WriteIPDLParam(aMsg, aActor, aParam.mReportCrossOriginRedirect);
WriteIPDLParam(aMsg, aActor, aParam.mSecureConnection);
WriteIPDLParam(aMsg, aActor, aParam.mTimingAllowed);
WriteIPDLParam(aMsg, aActor, aParam.mInitialized);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mServerTiming)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mNextHopProtocol)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mAsyncOpen)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRedirectStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRedirectEnd)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDomainLookupStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDomainLookupEnd)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mConnectStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSecureConnectionStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mConnectEnd)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRequestStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mResponseStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mCacheReadStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mResponseEnd)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mCacheReadEnd)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mWorkerStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mWorkerRequestStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mWorkerResponseEnd)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mZeroTime)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mFetchStart)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mEncodedBodySize)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mTransferSize)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDecodedBodySize)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRedirectCount)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mAllRedirectsSameOrigin)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mReportCrossOriginRedirect)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSecureConnection)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mTimingAllowed)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mInitialized)) {
return false;
}
return true;
}
};
template <>
struct IPDLParamTraits<nsCOMPtr<nsIServerTiming>> {
typedef nsCOMPtr<nsIServerTiming> paramType;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
nsAutoCString name;
Unused << aParam->GetName(name);
double duration = 0;
Unused << aParam->GetDuration(&duration);
nsAutoCString description;
Unused << aParam->GetDescription(description);
WriteIPDLParam(aMsg, aActor, name);
WriteIPDLParam(aMsg, aActor, duration);
WriteIPDLParam(aMsg, aActor, description);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
nsAutoCString name;
double duration;
nsAutoCString description;
if (!ReadIPDLParam(aMsg, aIter, aActor, &name)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &duration)) {
return false;
}
if (!ReadIPDLParam(aMsg, aIter, aActor, &description)) {
return false;
}
RefPtr<nsServerTiming> timing = new nsServerTiming();
timing->SetName(name);
timing->SetDuration(duration);
timing->SetDescription(description);
*aResult = timing;
return true;
}
};
} // namespace ipc
} // namespace mozilla
#endif // mozilla_dom_PerformanceTiming_h

View File

@ -119,7 +119,6 @@ skip-if = verify
[test_resource_timing.html]
skip-if = verify
[test_resource_timing_cross_origin.html]
skip-if = fission # bug 1658097
[test_resource_timing_frameset.html]
[test_selectevents.html]
skip-if = toolkit == 'android' # bug 1627523

View File

@ -88,6 +88,7 @@
#include "mozilla/RemoteLazyInputStreamChild.h"
#include "mozilla/RemoteLazyInputStreamUtils.h"
#include "mozilla/net/SFVService.h"
#include "mozilla/dom/ContentChild.h"
namespace mozilla {
namespace net {
@ -4831,10 +4832,37 @@ mozilla::dom::PerformanceStorage* HttpBaseChannel::GetPerformanceStorage() {
}
void HttpBaseChannel::MaybeReportTimingData() {
if (XRE_IsE10sParentProcess()) {
return;
}
mozilla::dom::PerformanceStorage* documentPerformance =
GetPerformanceStorage();
if (documentPerformance) {
documentPerformance->AddEntry(this, this);
return;
}
if (!nsGlobalWindowInner::GetInnerWindowWithId(
mLoadInfo->GetInnerWindowID())) {
// The inner window is in a different process.
dom::ContentChild* child = dom::ContentChild::GetSingleton();
if (!child) {
return;
}
nsAutoString initiatorType;
nsAutoString entryName;
UniquePtr<dom::PerformanceTimingData> performanceTimingData(
dom::PerformanceTimingData::Create(this, this, 0, initiatorType,
entryName));
if (!performanceTimingData) {
return;
}
child->SendReportFrameTimingData(mLoadInfo->GetInnerWindowID(), entryName,
initiatorType,
std::move(performanceTimingData));
}
}