Implement Runtime.getHeapUsage for hermes chrome inspector (#33173)

Summary:
Reland of https://github.com/facebook/react-native/issues/32895 with fix for optional params object.

Original description:

I was looking at the hermes chrome devtools integration and noticed requests to `Runtime.getHeapUsage` which was not implemented. When implemented it will show a summary of memory usage of the javascript instance in devtools.

<img width="325" alt="image" src="https://user-images.githubusercontent.com/2677334/149637113-e1d95d26-9e26-46c2-9be6-47d22284f15f.png">

## Changelog

[General] [Added] - Implement Runtime.getHeapUsage for hermes chrome inspector

Pull Request resolved: https://github.com/facebook/react-native/pull/33173

Test Plan:
I was able to reproduce the issue that caused the initial PR to be reverted using the resume request in Flipper. Pausing JS execution then resuming it will cause it to crash before this change, and works fine after.

Before

<img width="912" alt="image" src="https://user-images.githubusercontent.com/2677334/149637073-15f4e1fa-8183-42dc-8673-d4371731415c.png">

After

<img width="1076" alt="image" src="https://user-images.githubusercontent.com/2677334/149637085-579dee8f-5efb-4658-b0a8-2400bd119924.png">

Reviewed By: jpporto

Differential Revision: D34446672

Pulled By: ShikaSD

fbshipit-source-id: 6e26b8d53cd88cddded36437c72a01822551b9d0
This commit is contained in:
Janic Duplessis 2022-03-01 10:09:05 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 46bc521513
Коммит cff9590864
10 изменённых файлов: 166 добавлений и 24 удалений

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

@ -103,6 +103,7 @@ class Connection::Impl : public inspector::InspectorObserver,
void handle(const m::heapProfiler::GetHeapObjectIdRequest &req) override; void handle(const m::heapProfiler::GetHeapObjectIdRequest &req) override;
void handle(const m::runtime::CallFunctionOnRequest &req) override; void handle(const m::runtime::CallFunctionOnRequest &req) override;
void handle(const m::runtime::EvaluateRequest &req) override; void handle(const m::runtime::EvaluateRequest &req) override;
void handle(const m::runtime::GetHeapUsageRequest &req) override;
void handle(const m::runtime::GetPropertiesRequest &req) override; void handle(const m::runtime::GetPropertiesRequest &req) override;
void handle(const m::runtime::RunIfWaitingForDebuggerRequest &req) override; void handle(const m::runtime::RunIfWaitingForDebuggerRequest &req) override;
@ -1348,6 +1349,23 @@ Connection::Impl::makePropsFromValue(
return result; return result;
} }
void Connection::Impl::handle(const m::runtime::GetHeapUsageRequest &req) {
auto resp = std::make_shared<m::runtime::GetHeapUsageResponse>();
resp->id = req.id;
inspector_
->executeIfEnabled(
"Runtime.getHeapUsage",
[this, req, resp](const debugger::ProgramState &state) {
auto heapInfo = getRuntime().instrumentation().getHeapInfo(false);
resp->usedSize = heapInfo["hermes_allocatedBytes"];
resp->totalSize = heapInfo["hermes_heapSize"];
})
.via(executor_.get())
.thenValue([this, resp](auto &&) { sendResponseToClient(*resp); })
.thenError<std::exception>(sendErrorToClient(req.id));
}
void Connection::Impl::handle(const m::runtime::GetPropertiesRequest &req) { void Connection::Impl::handle(const m::runtime::GetPropertiesRequest &req) {
auto resp = std::make_shared<m::runtime::GetPropertiesResponse>(); auto resp = std::make_shared<m::runtime::GetPropertiesResponse>();
resp->id = req.id; resp->id = req.id;

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

@ -62,6 +62,7 @@ std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
makeUnique<heapProfiler::TakeHeapSnapshotRequest>}, makeUnique<heapProfiler::TakeHeapSnapshotRequest>},
{"Runtime.callFunctionOn", makeUnique<runtime::CallFunctionOnRequest>}, {"Runtime.callFunctionOn", makeUnique<runtime::CallFunctionOnRequest>},
{"Runtime.evaluate", makeUnique<runtime::EvaluateRequest>}, {"Runtime.evaluate", makeUnique<runtime::EvaluateRequest>},
{"Runtime.getHeapUsage", makeUnique<runtime::GetHeapUsageRequest>},
{"Runtime.getProperties", makeUnique<runtime::GetPropertiesRequest>}, {"Runtime.getProperties", makeUnique<runtime::GetPropertiesRequest>},
{"Runtime.runIfWaitingForDebugger", {"Runtime.runIfWaitingForDebugger",
makeUnique<runtime::RunIfWaitingForDebuggerRequest>}, makeUnique<runtime::RunIfWaitingForDebuggerRequest>},
@ -503,12 +504,22 @@ debugger::ResumeRequest::ResumeRequest(const dynamic &obj)
: Request("Debugger.resume") { : Request("Debugger.resume") {
assign(id, obj, "id"); assign(id, obj, "id");
assign(method, obj, "method"); assign(method, obj, "method");
auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
assign(terminateOnResume, params, "terminateOnResume");
}
} }
dynamic debugger::ResumeRequest::toDynamic() const { dynamic debugger::ResumeRequest::toDynamic() const {
dynamic params = dynamic::object;
put(params, "terminateOnResume", terminateOnResume);
dynamic obj = dynamic::object; dynamic obj = dynamic::object;
put(obj, "id", id); put(obj, "id", id);
put(obj, "method", method); put(obj, "method", method);
put(obj, "params", std::move(params));
return obj; return obj;
} }
@ -817,8 +828,11 @@ heapProfiler::StartSamplingRequest::StartSamplingRequest(const dynamic &obj)
assign(id, obj, "id"); assign(id, obj, "id");
assign(method, obj, "method"); assign(method, obj, "method");
dynamic params = obj.at("params"); auto it = obj.find("params");
assign(samplingInterval, params, "samplingInterval"); if (it != obj.items().end()) {
dynamic params = it->second;
assign(samplingInterval, params, "samplingInterval");
}
} }
dynamic heapProfiler::StartSamplingRequest::toDynamic() const { dynamic heapProfiler::StartSamplingRequest::toDynamic() const {
@ -845,8 +859,11 @@ heapProfiler::StartTrackingHeapObjectsRequest::StartTrackingHeapObjectsRequest(
assign(id, obj, "id"); assign(id, obj, "id");
assign(method, obj, "method"); assign(method, obj, "method");
dynamic params = obj.at("params"); auto it = obj.find("params");
assign(trackAllocations, params, "trackAllocations"); if (it != obj.items().end()) {
dynamic params = it->second;
assign(trackAllocations, params, "trackAllocations");
}
} }
dynamic heapProfiler::StartTrackingHeapObjectsRequest::toDynamic() const { dynamic heapProfiler::StartTrackingHeapObjectsRequest::toDynamic() const {
@ -894,15 +911,20 @@ heapProfiler::StopTrackingHeapObjectsRequest::StopTrackingHeapObjectsRequest(
assign(id, obj, "id"); assign(id, obj, "id");
assign(method, obj, "method"); assign(method, obj, "method");
dynamic params = obj.at("params"); auto it = obj.find("params");
assign(reportProgress, params, "reportProgress"); if (it != obj.items().end()) {
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots"); dynamic params = it->second;
assign(reportProgress, params, "reportProgress");
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
assign(captureNumericValue, params, "captureNumericValue");
}
} }
dynamic heapProfiler::StopTrackingHeapObjectsRequest::toDynamic() const { dynamic heapProfiler::StopTrackingHeapObjectsRequest::toDynamic() const {
dynamic params = dynamic::object; dynamic params = dynamic::object;
put(params, "reportProgress", reportProgress); put(params, "reportProgress", reportProgress);
put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots); put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots);
put(params, "captureNumericValue", captureNumericValue);
dynamic obj = dynamic::object; dynamic obj = dynamic::object;
put(obj, "id", id); put(obj, "id", id);
@ -925,15 +947,20 @@ heapProfiler::TakeHeapSnapshotRequest::TakeHeapSnapshotRequest(
assign(id, obj, "id"); assign(id, obj, "id");
assign(method, obj, "method"); assign(method, obj, "method");
dynamic params = obj.at("params"); auto it = obj.find("params");
assign(reportProgress, params, "reportProgress"); if (it != obj.items().end()) {
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots"); dynamic params = it->second;
assign(reportProgress, params, "reportProgress");
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
assign(captureNumericValue, params, "captureNumericValue");
}
} }
dynamic heapProfiler::TakeHeapSnapshotRequest::toDynamic() const { dynamic heapProfiler::TakeHeapSnapshotRequest::toDynamic() const {
dynamic params = dynamic::object; dynamic params = dynamic::object;
put(params, "reportProgress", reportProgress); put(params, "reportProgress", reportProgress);
put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots); put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots);
put(params, "captureNumericValue", captureNumericValue);
dynamic obj = dynamic::object; dynamic obj = dynamic::object;
put(obj, "id", id); put(obj, "id", id);
@ -1030,6 +1057,26 @@ void runtime::EvaluateRequest::accept(RequestHandler &handler) const {
handler.handle(*this); handler.handle(*this);
} }
runtime::GetHeapUsageRequest::GetHeapUsageRequest()
: Request("Runtime.getHeapUsage") {}
runtime::GetHeapUsageRequest::GetHeapUsageRequest(const dynamic &obj)
: Request("Runtime.getHeapUsage") {
assign(id, obj, "id");
assign(method, obj, "method");
}
dynamic runtime::GetHeapUsageRequest::toDynamic() const {
dynamic obj = dynamic::object;
put(obj, "id", id);
put(obj, "method", method);
return obj;
}
void runtime::GetHeapUsageRequest::accept(RequestHandler &handler) const {
handler.handle(*this);
}
runtime::GetPropertiesRequest::GetPropertiesRequest() runtime::GetPropertiesRequest::GetPropertiesRequest()
: Request("Runtime.getProperties") {} : Request("Runtime.getProperties") {}
@ -1284,6 +1331,25 @@ dynamic runtime::EvaluateResponse::toDynamic() const {
return obj; return obj;
} }
runtime::GetHeapUsageResponse::GetHeapUsageResponse(const dynamic &obj) {
assign(id, obj, "id");
dynamic res = obj.at("result");
assign(usedSize, res, "usedSize");
assign(totalSize, res, "totalSize");
}
dynamic runtime::GetHeapUsageResponse::toDynamic() const {
dynamic res = dynamic::object;
put(res, "usedSize", usedSize);
put(res, "totalSize", totalSize);
dynamic obj = dynamic::object;
put(obj, "id", id);
put(obj, "result", std::move(res));
return obj;
}
runtime::GetPropertiesResponse::GetPropertiesResponse(const dynamic &obj) { runtime::GetPropertiesResponse::GetPropertiesResponse(const dynamic &obj) {
assign(id, obj, "id"); assign(id, obj, "id");

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

@ -59,6 +59,8 @@ struct ExceptionDetails;
struct ExecutionContextCreatedNotification; struct ExecutionContextCreatedNotification;
struct ExecutionContextDescription; struct ExecutionContextDescription;
using ExecutionContextId = int; using ExecutionContextId = int;
struct GetHeapUsageRequest;
struct GetHeapUsageResponse;
struct GetPropertiesRequest; struct GetPropertiesRequest;
struct GetPropertiesResponse; struct GetPropertiesResponse;
struct InternalPropertyDescriptor; struct InternalPropertyDescriptor;
@ -127,6 +129,7 @@ struct RequestHandler {
virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0; virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0;
virtual void handle(const runtime::CallFunctionOnRequest &req) = 0; virtual void handle(const runtime::CallFunctionOnRequest &req) = 0;
virtual void handle(const runtime::EvaluateRequest &req) = 0; virtual void handle(const runtime::EvaluateRequest &req) = 0;
virtual void handle(const runtime::GetHeapUsageRequest &req) = 0;
virtual void handle(const runtime::GetPropertiesRequest &req) = 0; virtual void handle(const runtime::GetPropertiesRequest &req) = 0;
virtual void handle(const runtime::RunIfWaitingForDebuggerRequest &req) = 0; virtual void handle(const runtime::RunIfWaitingForDebuggerRequest &req) = 0;
}; };
@ -162,6 +165,7 @@ struct NoopRequestHandler : public RequestHandler {
void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {} void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {}
void handle(const runtime::CallFunctionOnRequest &req) override {} void handle(const runtime::CallFunctionOnRequest &req) override {}
void handle(const runtime::EvaluateRequest &req) override {} void handle(const runtime::EvaluateRequest &req) override {}
void handle(const runtime::GetHeapUsageRequest &req) override {}
void handle(const runtime::GetPropertiesRequest &req) override {} void handle(const runtime::GetPropertiesRequest &req) override {}
void handle(const runtime::RunIfWaitingForDebuggerRequest &req) override {} void handle(const runtime::RunIfWaitingForDebuggerRequest &req) override {}
}; };
@ -400,6 +404,8 @@ struct debugger::ResumeRequest : public Request {
folly::dynamic toDynamic() const override; folly::dynamic toDynamic() const override;
void accept(RequestHandler &handler) const override; void accept(RequestHandler &handler) const override;
folly::Optional<bool> terminateOnResume;
}; };
struct debugger::SetBreakpointRequest : public Request { struct debugger::SetBreakpointRequest : public Request {
@ -548,6 +554,7 @@ struct heapProfiler::StopTrackingHeapObjectsRequest : public Request {
folly::Optional<bool> reportProgress; folly::Optional<bool> reportProgress;
folly::Optional<bool> treatGlobalObjectsAsRoots; folly::Optional<bool> treatGlobalObjectsAsRoots;
folly::Optional<bool> captureNumericValue;
}; };
struct heapProfiler::TakeHeapSnapshotRequest : public Request { struct heapProfiler::TakeHeapSnapshotRequest : public Request {
@ -559,6 +566,7 @@ struct heapProfiler::TakeHeapSnapshotRequest : public Request {
folly::Optional<bool> reportProgress; folly::Optional<bool> reportProgress;
folly::Optional<bool> treatGlobalObjectsAsRoots; folly::Optional<bool> treatGlobalObjectsAsRoots;
folly::Optional<bool> captureNumericValue;
}; };
struct runtime::CallFunctionOnRequest : public Request { struct runtime::CallFunctionOnRequest : public Request {
@ -596,6 +604,14 @@ struct runtime::EvaluateRequest : public Request {
folly::Optional<bool> awaitPromise; folly::Optional<bool> awaitPromise;
}; };
struct runtime::GetHeapUsageRequest : public Request {
GetHeapUsageRequest();
explicit GetHeapUsageRequest(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
void accept(RequestHandler &handler) const override;
};
struct runtime::GetPropertiesRequest : public Request { struct runtime::GetPropertiesRequest : public Request {
GetPropertiesRequest(); GetPropertiesRequest();
explicit GetPropertiesRequest(const folly::dynamic &obj); explicit GetPropertiesRequest(const folly::dynamic &obj);
@ -709,6 +725,15 @@ struct runtime::EvaluateResponse : public Response {
folly::Optional<runtime::ExceptionDetails> exceptionDetails; folly::Optional<runtime::ExceptionDetails> exceptionDetails;
}; };
struct runtime::GetHeapUsageResponse : public Response {
GetHeapUsageResponse() = default;
explicit GetHeapUsageResponse(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
double usedSize{};
double totalSize{};
};
struct runtime::GetPropertiesResponse : public Response { struct runtime::GetPropertiesResponse : public Response {
GetPropertiesResponse() = default; GetPropertiesResponse() = default;
explicit GetPropertiesResponse(const folly::dynamic &obj); explicit GetPropertiesResponse(const folly::dynamic &obj);

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

@ -692,7 +692,10 @@ TEST(MessageTests, testResumeRequest) {
std::string message = R"( std::string message = R"(
{ {
"id": 10, "id": 10,
"method": "Debugger.resume" "method": "Debugger.resume",
"params": {
"terminateOnResume": false
}
} }
)"; )";

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

@ -32,5 +32,6 @@ Runtime.callFunctionOn
Runtime.consoleAPICalled Runtime.consoleAPICalled
Runtime.evaluate Runtime.evaluate
Runtime.executionContextCreated Runtime.executionContextCreated
Runtime.getHeapUsage
Runtime.getProperties Runtime.getProperties
Runtime.runIfWaitingForDebugger Runtime.runIfWaitingForDebugger

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

@ -12,7 +12,7 @@
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
"devtools-protocol": "0.0.730699", "devtools-protocol": "0.0.959523",
"yargs": "^14.2.0" "yargs": "^14.2.0"
}, },
"devDependencies": { "devDependencies": {

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

@ -266,13 +266,26 @@ export function emitRequestDef(stream: Writable, command: Command) {
assign(method, obj, "method");\n\n`); assign(method, obj, "method");\n\n`);
if (props.length > 0) { if (props.length > 0) {
stream.write('dynamic params = obj.at("params");\n'); const optionalParams = props.every(p => p.optional);
if (optionalParams) {
stream.write(`
auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
`);
} else {
stream.write('dynamic params = obj.at("params");\n');
}
for (const prop of props) { for (const prop of props) {
const id = prop.getCppIdentifier(); const id = prop.getCppIdentifier();
const name = prop.name; const name = prop.name;
stream.write(`assign(${id}, params, "${name}");\n`); stream.write(`assign(${id}, params, "${name}");\n`);
} }
if (optionalParams) {
stream.write('}');
}
} }
stream.write('}\n\n'); stream.write('}\n\n');

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

@ -41,6 +41,7 @@ const proto = mergeDomains(standard, custom);
function parseDomains( function parseDomains(
domainObjs: Array<any>, domainObjs: Array<any>,
ignoreExperimental: boolean, ignoreExperimental: boolean,
includeExperimental: Set<string>,
): Descriptor { ): Descriptor {
const desc = { const desc = {
types: [], types: [],
@ -59,7 +60,12 @@ function parseDomains(
} }
for (const commandObj of obj.commands || []) { for (const commandObj of obj.commands || []) {
const command = Command.create(domain, commandObj, ignoreExperimental); const command = Command.create(
domain,
commandObj,
!includeExperimental.has(`${domain}.${commandObj.name}`) &&
ignoreExperimental,
);
if (command) { if (command) {
desc.commands.push(command); desc.commands.push(command);
} }
@ -199,18 +205,27 @@ function main() {
.boolean('e') .boolean('e')
.alias('e', 'ignore-experimental') .alias('e', 'ignore-experimental')
.describe('e', 'ignore experimental commands, props, and types') .describe('e', 'ignore experimental commands, props, and types')
.alias('i', 'include-experimental')
.describe('i', 'experimental commands to include')
.alias('r', 'roots') .alias('r', 'roots')
.describe('r', 'path to a file listing root types, events, and commands') .describe('r', 'path to a file listing root types, events, and commands')
.nargs('r', 1) .nargs('r', 1)
.demandCommand(2, 2).argv; .demandCommand(2, 2).argv;
const ignoreExperimental = !!args.e; const ignoreExperimental = !!args.e;
const includeExperimental = new Set(
typeof args.i === 'string' ? args.i.split(',') : [],
);
const [headerPath, implPath] = args._; const [headerPath, implPath] = args._;
const headerStream = fs.createWriteStream(headerPath); const headerStream = fs.createWriteStream(headerPath);
const implStream = fs.createWriteStream(implPath); const implStream = fs.createWriteStream(implPath);
const desc = parseDomains(proto.domains, ignoreExperimental); const desc = parseDomains(
proto.domains,
ignoreExperimental,
includeExperimental,
);
const graph = buildGraph(desc); const graph = buildGraph(desc);
const roots = parseRoots(desc, String(args.roots)); const roots = parseRoots(desc, String(args.roots));

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

@ -2434,10 +2434,10 @@ detect-newline@^3.0.0:
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
devtools-protocol@0.0.730699: devtools-protocol@0.0.959523:
version "0.0.730699" version "0.0.959523"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.730699.tgz#4d18f6a9b7fb7cf3f1ffe73bfe14aad66cf3b2ef" resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.959523.tgz#a7ce62c6b88876081fe5bec866f70e467bc021ba"
integrity sha512-dprBpuPzVIIXXL6GevzhvWe2wg836h3d5hY+n6IzzHbKLsUh6QlVmcIy15za0J3MhDFbmEH60s6uYsrw/tgBbw== integrity sha512-taOcAND/oJA5FhJD2I3RA+I8RPdrpPJWwvMBPzTq7Sugev1xTOG3lgtlSfkh5xkjTYw0Ti2CRQq016goFHMoPQ==
diff-sequences@^26.6.2: diff-sequences@^26.6.2:
version "26.6.2" version "26.6.2"

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

@ -2,24 +2,25 @@
set -e set -e
DIR=$(dirname "${BASH_SOURCE[0]}") DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
cd "${DIR}/msggen" cd "${DIR}/msggen"
yarn install yarn install
yarn build yarn build
FBSOURCE=$(hg root) MSGTYPES_PATH="${DIR}/message_types.txt"
MSGTYPES_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/tools/message_types.txt" HEADER_PATH="${DIR}/../chrome/MessageTypes.h"
HEADER_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/chrome/MessageTypes.h" CPP_PATH="${DIR}/../chrome/MessageTypes.cpp"
CPP_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp"
node bin/index.js \ node bin/index.js \
--ignore-experimental \ --ignore-experimental \
--include-experimental=Runtime.getHeapUsage \
--roots "$MSGTYPES_PATH" \ --roots "$MSGTYPES_PATH" \
"$HEADER_PATH" "$CPP_PATH" "$HEADER_PATH" "$CPP_PATH"
clang-format -i --style=file "$HEADER_PATH" clang-format -i --style=file "$HEADER_PATH"
clang-format -i --style=file "$CPP_PATH" clang-format -i --style=file "$CPP_PATH"
FBSOURCE=$(hg root)
"${FBSOURCE}/tools/signedsource" sign "$HEADER_PATH" "${FBSOURCE}/tools/signedsource" sign "$HEADER_PATH"
"${FBSOURCE}/tools/signedsource" sign "$CPP_PATH" "${FBSOURCE}/tools/signedsource" sign "$CPP_PATH"