Bug 1581963 - [devtools] Handle errors properly when capturing a profile r=profiler-reviewers,mstange
Differential Revision: https://phabricator.services.mozilla.com/D245886
This commit is contained in:
committed by
jwajsberg@mozilla.com
parent
2417113533
commit
29c9a8dba5
@@ -215,7 +215,8 @@ export interface SymbolicationService {
|
|||||||
* profile has been obtained.
|
* profile has been obtained.
|
||||||
*/
|
*/
|
||||||
export type OnProfileReceived = (
|
export type OnProfileReceived = (
|
||||||
profileAndAdditionalInformation: ProfileAndAdditionalInformation
|
profileAndAdditionalInformation: ProfileAndAdditionalInformation | null,
|
||||||
|
error?: Error | string
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -643,7 +644,7 @@ export class ProfilerWebChannel {
|
|||||||
*/
|
*/
|
||||||
export type ProfilerBrowserInfo = {
|
export type ProfilerBrowserInfo = {
|
||||||
profileCaptureResult: ProfileCaptureResult;
|
profileCaptureResult: ProfileCaptureResult;
|
||||||
symbolicationService: SymbolicationService;
|
symbolicationService: SymbolicationService | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProfileCaptureResult =
|
export type ProfileCaptureResult =
|
||||||
|
|||||||
@@ -75,9 +75,14 @@ class RecordingButton extends PureComponent {
|
|||||||
_onCaptureButtonClick = async () => {
|
_onCaptureButtonClick = async () => {
|
||||||
const { getProfileAndStopProfiler, onProfileReceived, perfFront } =
|
const { getProfileAndStopProfiler, onProfileReceived, perfFront } =
|
||||||
this.props;
|
this.props;
|
||||||
|
try {
|
||||||
const profileAndAdditionalInformation =
|
const profileAndAdditionalInformation =
|
||||||
await getProfileAndStopProfiler(perfFront);
|
await getProfileAndStopProfiler(perfFront);
|
||||||
onProfileReceived(profileAndAdditionalInformation);
|
onProfileReceived(profileAndAdditionalInformation);
|
||||||
|
} catch (e) {
|
||||||
|
const assertedError = /** @type {Error | string} */ (e);
|
||||||
|
onProfileReceived(null, assertedError);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_onStopButtonClick = () => {
|
_onStopButtonClick = () => {
|
||||||
|
|||||||
@@ -131,11 +131,31 @@ async function gInit(perfFront, traits, pageContext, openAboutProfiling) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MockedExports.ProfileAndAdditionalInformation} profileAndAdditionalInformation
|
* @param {MockedExports.ProfileAndAdditionalInformation | null} profileAndAdditionalInformation
|
||||||
|
* @param {Error | string} [error]
|
||||||
*/
|
*/
|
||||||
const onProfileReceived = async ({ profile, additionalInformation }) => {
|
const onProfileReceived = async (profileAndAdditionalInformation, error) => {
|
||||||
const objdirs = selectors.getObjdirs(store.getState());
|
const objdirs = selectors.getObjdirs(store.getState());
|
||||||
const profilerViewMode = getProfilerViewModeForCurrentPreset(pageContext);
|
const profilerViewMode = getProfilerViewModeForCurrentPreset(pageContext);
|
||||||
|
const browser = await openProfilerTab({ profilerViewMode });
|
||||||
|
|
||||||
|
if (error || !profileAndAdditionalInformation) {
|
||||||
|
if (!error) {
|
||||||
|
error =
|
||||||
|
"No profile data has been passed to onProfileReceived, and no specific error has been specified. This is unexpected.";
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @type {ProfileCaptureResult}
|
||||||
|
*/
|
||||||
|
const profileCaptureResult = {
|
||||||
|
type: "ERROR",
|
||||||
|
error: typeof error === "string" ? new Error(error) : error,
|
||||||
|
};
|
||||||
|
registerProfileCaptureForBrowser(browser, profileCaptureResult, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { profile, additionalInformation } = profileAndAdditionalInformation;
|
||||||
const sharedLibraries = additionalInformation?.sharedLibraries ?? [];
|
const sharedLibraries = additionalInformation?.sharedLibraries ?? [];
|
||||||
if (!sharedLibraries.length) {
|
if (!sharedLibraries.length) {
|
||||||
console.error(
|
console.error(
|
||||||
@@ -147,7 +167,6 @@ async function gInit(perfFront, traits, pageContext, openAboutProfiling) {
|
|||||||
objdirs,
|
objdirs,
|
||||||
perfFront
|
perfFront
|
||||||
);
|
);
|
||||||
const browser = await openProfilerTab({ profilerViewMode });
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {ProfileCaptureResult}
|
* @type {ProfileCaptureResult}
|
||||||
|
|||||||
@@ -289,11 +289,17 @@ async function getResponseForMessage(request, browser) {
|
|||||||
case "GET_SYMBOL_TABLE": {
|
case "GET_SYMBOL_TABLE": {
|
||||||
const { debugName, breakpadId } = request;
|
const { debugName, breakpadId } = request;
|
||||||
const symbolicationService = getSymbolicationServiceForBrowser(browser);
|
const symbolicationService = getSymbolicationServiceForBrowser(browser);
|
||||||
|
if (!symbolicationService) {
|
||||||
|
throw new Error("No symbolication service has been found for this tab");
|
||||||
|
}
|
||||||
return symbolicationService.getSymbolTable(debugName, breakpadId);
|
return symbolicationService.getSymbolTable(debugName, breakpadId);
|
||||||
}
|
}
|
||||||
case "QUERY_SYMBOLICATION_API": {
|
case "QUERY_SYMBOLICATION_API": {
|
||||||
const { path, requestJson } = request;
|
const { path, requestJson } = request;
|
||||||
const symbolicationService = getSymbolicationServiceForBrowser(browser);
|
const symbolicationService = getSymbolicationServiceForBrowser(browser);
|
||||||
|
if (!symbolicationService) {
|
||||||
|
throw new Error("No symbolication service has been found for this tab");
|
||||||
|
}
|
||||||
return symbolicationService.querySymbolicationApi(path, requestJson);
|
return symbolicationService.querySymbolicationApi(path, requestJson);
|
||||||
}
|
}
|
||||||
case "GET_EXTERNAL_POWER_TRACKS": {
|
case "GET_EXTERNAL_POWER_TRACKS": {
|
||||||
@@ -351,7 +357,7 @@ async function getResponseForMessage(request, browser) {
|
|||||||
* tab, or a fallback service for browsers from tabs opened by the user.
|
* tab, or a fallback service for browsers from tabs opened by the user.
|
||||||
*
|
*
|
||||||
* @param {MockedExports.Browser} browser
|
* @param {MockedExports.Browser} browser
|
||||||
* @return {SymbolicationService}
|
* @return {SymbolicationService | null}
|
||||||
*/
|
*/
|
||||||
function getSymbolicationServiceForBrowser(browser) {
|
function getSymbolicationServiceForBrowser(browser) {
|
||||||
// We try to serve symbolication requests that come from tabs that we
|
// We try to serve symbolication requests that come from tabs that we
|
||||||
@@ -429,7 +435,7 @@ export async function handleWebChannelMessage(channel, id, message, target) {
|
|||||||
/**
|
/**
|
||||||
* @param {MockedExports.Browser} browser - The tab's browser.
|
* @param {MockedExports.Browser} browser - The tab's browser.
|
||||||
* @param {ProfileCaptureResult} profileCaptureResult - The Gecko profile.
|
* @param {ProfileCaptureResult} profileCaptureResult - The Gecko profile.
|
||||||
* @param {SymbolicationService} symbolicationService - An object which implements the
|
* @param {SymbolicationService | null} symbolicationService - An object which implements the
|
||||||
* SymbolicationService interface, whose getSymbolTable method will be invoked
|
* SymbolicationService interface, whose getSymbolTable method will be invoked
|
||||||
* when profiler.firefox.com sends GET_SYMBOL_TABLE WebChannel messages to us. This
|
* when profiler.firefox.com sends GET_SYMBOL_TABLE WebChannel messages to us. This
|
||||||
* method should obtain a symbol table for the requested binary and resolve the
|
* method should obtain a symbol table for the requested binary and resolve the
|
||||||
|
|||||||
@@ -78,7 +78,26 @@ add_task(async function () {
|
|||||||
"The profiler was stopped and the profile discarded."
|
"The profiler was stopped and the profile discarded."
|
||||||
);
|
);
|
||||||
|
|
||||||
// Clean up.
|
await front.destroy();
|
||||||
|
await client.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_error_case() {
|
||||||
|
const { front, client } = await initPerfFront();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// We try to get the profile without starting the profiler first. This should
|
||||||
|
// trigger an error in the our C++ code.
|
||||||
|
await front.getProfileAndStopProfiler();
|
||||||
|
ok(false, "Getting the profile should fail");
|
||||||
|
} catch (e) {
|
||||||
|
Assert.stringContains(
|
||||||
|
e.message,
|
||||||
|
"The profiler is not active.",
|
||||||
|
"The error contains the expected error message."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await front.destroy();
|
await front.destroy();
|
||||||
await client.close();
|
await client.close();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user