in xplat/Flipper/FlipperClient.cpp [162:281]
void FlipperClient::onMessageReceived(
const dynamic& message,
std::unique_ptr<FlipperResponder> uniqueResponder) {
// Convert to shared pointer so we can hold on to it while passing it to the
// plugin, and still use it to respond with an error if we catch an exception.
std::shared_ptr<FlipperResponder> responder = std::move(uniqueResponder);
try {
std::unique_lock<std::mutex> lock(mutex_);
const auto& method = message["method"];
const auto& params = message.getDefault("params");
if (method == "getPlugins") {
dynamic identifiers = dynamic::array();
for (const auto& elem : plugins_) {
identifiers.push_back(elem.first);
}
dynamic response = dynamic::object("plugins", identifiers);
responder->success(response);
return;
}
if (method == "getBackgroundPlugins") {
dynamic identifiers = dynamic::array();
for (const auto& elem : plugins_) {
if (elem.second->runInBackground()) {
identifiers.push_back(elem.first);
}
}
dynamic response = dynamic::object("plugins", identifiers);
responder->success(response);
return;
}
if (method == "init") {
const auto identifier = params["plugin"].getString();
if (plugins_.find(identifier) == plugins_.end()) {
std::string errorMessage = "Plugin " + identifier +
" not found for method " + method.getString();
log(errorMessage);
responder->error(folly::dynamic::object("message", errorMessage)(
"name", "PluginNotFound"));
return;
}
const auto plugin = plugins_.at(identifier);
connect(plugin);
return;
}
if (method == "deinit") {
const auto identifier = params["plugin"].getString();
if (plugins_.find(identifier) == plugins_.end()) {
std::string errorMessage = "Plugin " + identifier +
" not found for method " + method.getString();
log(errorMessage);
responder->error(folly::dynamic::object("message", errorMessage)(
"name", "PluginNotFound"));
return;
}
const auto plugin = plugins_.at(identifier);
disconnect(plugin);
return;
}
if (method == "execute") {
const auto identifier = params["api"].getString();
if (connections_.find(identifier) == connections_.end()) {
std::string errorMessage = "Connection " + identifier +
" not found for method " + method.getString();
log(errorMessage);
responder->error(folly::dynamic::object("message", errorMessage)(
"name", "ConnectionNotFound"));
return;
}
const auto conn = connections_.at(params["api"].getString());
// conn->call(...) may call back to FlipperClient causing a deadlock (see
// T92341964). Making sure the mutex is not locked.
lock.unlock();
conn->call(
params["method"].getString(), params.getDefault("params"), responder);
return;
}
if (method == "isMethodSupported") {
const auto identifier = params["api"].getString();
if (connections_.find(identifier) == connections_.end()) {
std::string errorMessage = "Connection " + identifier +
" not found for method " + method.getString();
log(errorMessage);
responder->error(folly::dynamic::object("message", errorMessage)(
"name", "ConnectionNotFound"));
return;
}
const auto& conn = connections_.at(params["api"].getString());
bool isSupported = conn->hasReceiver(params["method"].getString());
responder->success(dynamic::object("isSupported", isSupported));
return;
}
dynamic response =
dynamic::object("message", "Received unknown method: " + method);
responder->error(response);
} catch (std::exception& e) {
log(std::string("Error: ") + e.what());
if (responder) {
responder->error(dynamic::object("message", e.what())(
"stacktrace", callstack())("name", e.what()));
}
} catch (...) {
log("Unknown error suppressed in FlipperClient");
if (responder) {
responder->error(dynamic::object(
"message",
"Unknown error during " + message["method"] + ". " +
folly::toJson(message))("stacktrace", callstack())(
"name", "Unknown"));
}
}
}