mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1607047 - Include build ID in recordings and introduction message, r=jlast.
Differential Revision: https://phabricator.services.mozilla.com/D58697 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
0e24025af0
commit
30f811339f
@ -11,6 +11,7 @@
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "ProcessRewind.h"
|
||||
#include "SpinLock.h"
|
||||
#include "nsAppRunner.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -331,15 +332,43 @@ void Stream::DumpEvents() {
|
||||
// Recording
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We expect to find this at the start of every recording.
|
||||
static const uint64_t MagicValue = 0xd3e7f5fae445b3ac;
|
||||
|
||||
void GetCurrentBuildId(BuildId* aBuildId) {
|
||||
int n = snprintf(aBuildId->mContents, sizeof(aBuildId->mContents), "macOS-%s",
|
||||
PlatformBuildID());
|
||||
MOZ_RELEASE_ASSERT((size_t)n + 1 <= sizeof(aBuildId->mContents));
|
||||
}
|
||||
|
||||
struct Header {
|
||||
uint64_t mMagic;
|
||||
BuildId mBuildId;
|
||||
};
|
||||
|
||||
Recording::Recording() : mMode(IsRecording() ? WRITE : READ) {
|
||||
PodZero(&mLock);
|
||||
PodZero(&mStreamLock);
|
||||
|
||||
if (IsReplaying()) {
|
||||
if (IsRecording()) {
|
||||
Header header;
|
||||
header.mMagic = MagicValue;
|
||||
GetCurrentBuildId(&header.mBuildId);
|
||||
mContents.append((const uint8_t*)&header, sizeof(Header));
|
||||
} else {
|
||||
gDumpEvents = TestEnv("MOZ_REPLAYING_DUMP_EVENTS");
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void Recording::ExtractBuildId(const char* aContents, size_t aLength,
|
||||
BuildId* aBuildId) {
|
||||
MOZ_RELEASE_ASSERT(aLength >= sizeof(Header));
|
||||
const Header* header = (const Header*)aContents;
|
||||
MOZ_RELEASE_ASSERT(header->mMagic == MagicValue);
|
||||
*aBuildId = header->mBuildId;
|
||||
}
|
||||
|
||||
// The recording format is a series of chunks. Each chunk is a ChunkDescriptor
|
||||
// followed by the compressed contents of the chunk itself.
|
||||
struct ChunkDescriptor {
|
||||
@ -361,9 +390,22 @@ void Recording::NewContents(const uint8_t* aContents, size_t aSize,
|
||||
MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
|
||||
MOZ_RELEASE_ASSERT(IsReading());
|
||||
|
||||
// Make sure the header matches when reading the first data in the recording.
|
||||
size_t offset = 0;
|
||||
if (mContents.empty()) {
|
||||
MOZ_RELEASE_ASSERT(aSize >= sizeof(Header));
|
||||
offset += sizeof(Header);
|
||||
|
||||
Header* header = (Header*) aContents;
|
||||
MOZ_RELEASE_ASSERT(header->mMagic == MagicValue);
|
||||
|
||||
BuildId currentBuildId;
|
||||
GetCurrentBuildId(¤tBuildId);
|
||||
MOZ_RELEASE_ASSERT(currentBuildId.Matches(header->mBuildId));
|
||||
}
|
||||
|
||||
mContents.append(aContents, aSize);
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset < aSize) {
|
||||
MOZ_RELEASE_ASSERT(offset + sizeof(ChunkDescriptor) <= aSize);
|
||||
ChunkDescriptor* desc = (ChunkDescriptor*)(aContents + offset);
|
||||
|
@ -207,6 +207,19 @@ class Stream {
|
||||
bool ReadMismatchedEventData(ThreadEvent aEvent);
|
||||
};
|
||||
|
||||
// All information about the platform and build where a recording was made.
|
||||
struct BuildId {
|
||||
char mContents[128];
|
||||
|
||||
BuildId() { PodZero(this); }
|
||||
bool Matches(const BuildId& aOther) {
|
||||
return !memcmp(this, &aOther, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
// Get the build ID for the currently running process.
|
||||
void GetCurrentBuildId(BuildId* aBuildId);
|
||||
|
||||
class Recording {
|
||||
public:
|
||||
enum Mode { WRITE, READ };
|
||||
@ -259,6 +272,10 @@ class Recording {
|
||||
// Flush all streams to the recording.
|
||||
void Flush();
|
||||
|
||||
// Get the build ID embedded in a recording.
|
||||
static void ExtractBuildId(const char* aContents, size_t aLength,
|
||||
BuildId* aBuildId);
|
||||
|
||||
private:
|
||||
StreamChunkLocation WriteChunk(StreamName aName, size_t aNameIndex,
|
||||
const char* aStart, size_t aCompressedSize,
|
||||
|
@ -42,11 +42,17 @@ namespace recordreplay {
|
||||
// below.
|
||||
|
||||
#define ForEachMessageType(_Macro) \
|
||||
/* Messages sent from the middleman to the child process. */ \
|
||||
/* Messages which can be interpreted or constructed by the cloud server. */ \
|
||||
/* Avoid changing the message IDs for these. */ \
|
||||
\
|
||||
/* Sent at startup. */ \
|
||||
/* Sent by the middleman at startup. */ \
|
||||
_Macro(Introduction) \
|
||||
\
|
||||
/* An error occurred in the cloud server. */ \
|
||||
_Macro(CloudError) \
|
||||
\
|
||||
/* Messages sent from the middleman to the child process. */ \
|
||||
\
|
||||
/* Sent to recording processes to indicate that the middleman will be running */ \
|
||||
/* developer tools server-side code instead of the recording process itself. */ \
|
||||
_Macro(SetDebuggerRunsInMiddleman) \
|
||||
@ -82,6 +88,7 @@ namespace recordreplay {
|
||||
/* Respond to a ping message */ \
|
||||
_Macro(PingResponse) \
|
||||
\
|
||||
/* An unhandled recording divergence occurred and execution cannot continue. */ \
|
||||
_Macro(UnhandledDivergence) \
|
||||
\
|
||||
/* A critical error occurred and execution cannot continue. The child will */ \
|
||||
@ -187,7 +194,12 @@ struct Message {
|
||||
};
|
||||
|
||||
struct IntroductionMessage : public Message {
|
||||
// Used when replaying to describe the build that must be used for the replay.
|
||||
BuildId mBuildId;
|
||||
|
||||
// Used when recording to specify the parent process pid.
|
||||
base::ProcessId mParentPid;
|
||||
|
||||
uint32_t mArgc;
|
||||
|
||||
IntroductionMessage(uint32_t aSize, base::ProcessId aParentPid,
|
||||
@ -263,13 +275,17 @@ struct JSONMessage : public Message {
|
||||
typedef JSONMessage<MessageType::ManifestStart> ManifestStartMessage;
|
||||
typedef JSONMessage<MessageType::ManifestFinished> ManifestFinishedMessage;
|
||||
|
||||
struct FatalErrorMessage : public Message {
|
||||
explicit FatalErrorMessage(uint32_t aSize, uint32_t aForkId)
|
||||
: Message(MessageType::FatalError, aSize, aForkId) {}
|
||||
template <MessageType Type>
|
||||
struct ErrorMessage : public Message {
|
||||
explicit ErrorMessage(uint32_t aSize, uint32_t aForkId)
|
||||
: Message(Type, aSize, aForkId) {}
|
||||
|
||||
const char* Error() const { return Data<FatalErrorMessage, const char>(); }
|
||||
const char* Error() const { return Data<ErrorMessage<Type>, const char>(); }
|
||||
};
|
||||
|
||||
typedef ErrorMessage<MessageType::FatalError> FatalErrorMessage;
|
||||
typedef ErrorMessage<MessageType::CloudError> CloudErrorMessage;
|
||||
|
||||
typedef EmptyMessage<MessageType::UnhandledDivergence> UnhandledDivergenceMessage;
|
||||
|
||||
// The format for graphics data which will be sent to the middleman process.
|
||||
|
@ -51,6 +51,12 @@ void ChildProcessInfo::OnIncomingMessage(const Message& aMsg) {
|
||||
OnCrash(nmsg.mForkId, nmsg.Error());
|
||||
return;
|
||||
}
|
||||
case MessageType::CloudError: {
|
||||
const auto& nmsg = static_cast<const CloudErrorMessage&>(aMsg);
|
||||
Print("Fatal Cloud Error: %s\n", nmsg.Error());
|
||||
MOZ_CRASH("Cloud Error");
|
||||
return;
|
||||
}
|
||||
case MessageType::Paint:
|
||||
UpdateGraphicsAfterPaint(static_cast<const PaintMessage&>(aMsg));
|
||||
break;
|
||||
|
@ -343,6 +343,8 @@ void InitializeMiddleman(int aArgc, char* aArgv[], base::ProcessId aParentPid,
|
||||
|
||||
// Construct the message that will be sent to each child when starting up.
|
||||
IntroductionMessage* msg = IntroductionMessage::New(aParentPid, aArgc, aArgv);
|
||||
GetCurrentBuildId(&msg->mBuildId);
|
||||
|
||||
ChildProcessInfo::SetIntroductionMessage(msg);
|
||||
|
||||
MOZ_RELEASE_ASSERT(gProcessKind == ProcessKind::MiddlemanRecording ||
|
||||
@ -379,6 +381,13 @@ void InitializeMiddleman(int aArgc, char* aArgv[], base::ProcessId aParentPid,
|
||||
}
|
||||
|
||||
DirectCloseFile(fd);
|
||||
|
||||
// Update the build ID in the introduction message according to what we
|
||||
// find in the recording. The introduction message is sent first to each
|
||||
// replaying process, and when replaying in the cloud its contents will be
|
||||
// analyzed to determine what binaries to use for the replay.
|
||||
Recording::ExtractBuildId(gRecordingContents.begin(),
|
||||
gRecordingContents.length(), &msg->mBuildId);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user