blob: 3395cef9632bcde46285669a222ae7eff1504ad8 [file] [log] [blame]
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "analyzer.hpp"
#include "histogram.hpp"
#include "main.hpp"
#include "sensorhelper.hpp"
#include <ncurses.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <unordered_map>
bool IS_USER_BUS = false; // User bus or System bus?
extern sd_bus* g_bus;
extern DBusConnectionSnapshot* g_connection_snapshot;
static std::unordered_map<uint64_t, uint64_t> in_flight_methodcalls;
extern bool g_sensor_update_thread_active;
extern std::string g_snapshot_update_bus_cxn;
extern int g_snapshot_update_bus_cxn_id;
extern int GetConnectionNumericID(const std::string& unique_name);
namespace dbus_top_analyzer
{
extern DBusTopStatistics g_dbus_statistics;
extern Histogram<float> g_mc_time_histogram;
} // namespace dbus_top_analyzer
static void TrackMessage([[maybe_unused]] sd_bus_message* m) {}
// Obtain a Monitoring DBus connection
int AcquireBus(sd_bus** ret)
{
int r;
r = sd_bus_new(ret);
if (r < 0)
{
printf("Could not allocate bus: %s\n", strerror(-r));
return 0;
}
r = sd_bus_set_monitor(*ret, true);
if (r < 0)
{
printf("Could not set monitor mode: %s\n", strerror(-r));
return 0;
}
r = sd_bus_negotiate_creds(*ret, true, _SD_BUS_CREDS_ALL);
if (r < 0)
{
printf("Could not enable credentials: %s\n", strerror(-r));
return 0;
}
r = sd_bus_negotiate_timestamp(*ret, true);
if (r < 0)
{
printf("Could not enable timestamps: %s\n", strerror(-r));
return 0;
}
r = sd_bus_negotiate_fds(*ret, true);
if (r < 0)
{
printf("Could not enable fds: %s\n", strerror(-r));
return 0;
}
r = sd_bus_set_bus_client(*ret, true);
if (r < 0)
{
printf("Could not enable bus client: %s\n", strerror(-r));
return 0;
}
if (IS_USER_BUS)
{
r = sd_bus_set_address(*ret, "haha");
if (r < 0)
{
printf("Could not set user bus: %s\n", strerror(-r));
return 0;
}
}
else
{
r = sd_bus_set_address(*ret, "unix:path=/run/dbus/system_bus_socket");
if (r < 0)
{
printf("Could not set system bus: %s\n", strerror(-r));
return 0;
}
}
r = sd_bus_start(*ret);
if (r < 0)
{
printf("Could not connect to bus: %s\n", strerror(-r));
return 0;
}
return r;
}
void DbusCaptureThread()
{
int r;
// Become Monitor
uint32_t flags = 0;
sd_bus_message* message;
sd_bus_error error = SD_BUS_ERROR_NULL;
r = sd_bus_message_new_method_call(
g_bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus",
"org.freedesktop.DBus.Monitoring", "BecomeMonitor");
if (r < 0)
{
printf("Could not create the BecomeMonitor function call\n");
exit(0);
}
// Match conditions
r = sd_bus_message_open_container(message, 'a', "s");
if (r < 0)
{
printf("Could not open container\n");
exit(0);
}
r = sd_bus_message_close_container(message);
if (r < 0)
{
printf("Could not close container\n");
exit(0);
}
r = sd_bus_message_append_basic(message, 'u', &flags);
if (r < 0)
{
printf("Could not append flags\n");
exit(0);
}
r = sd_bus_call(g_bus, message, 0, &error, nullptr);
if (r < 0)
{
printf("Could not call org.freedesktop.DBus.Monitoring.BecomeMonitor "
"%d, %s\n",
r, strerror(-r));
exit(0);
}
const char* unique_name;
r = sd_bus_get_unique_name(g_bus, &unique_name);
if (r < 0)
{
printf("Could not get unique name: %s\n", strerror(-r));
exit(0);
}
// Enter packet processing loop
while (true)
{
struct sd_bus_message* m = nullptr;
r = sd_bus_process(g_bus, &m);
if (m != nullptr)
{
if (r < 0)
{
printf("Failed to call sd_bus_process: %s\n", strerror(-r));
}
uint8_t type;
r = sd_bus_message_get_type(m, &type);
const char* path = sd_bus_message_get_path(m);
// const char* iface = sd_bus_message_get_interface(m);
const char* sender = sd_bus_message_get_sender(m);
const char* destination = sd_bus_message_get_destination(m);
const char* interface = sd_bus_message_get_interface(m);
const char* member = sd_bus_message_get_member(m);
// For looking up the unique connection name for sender and
// destination
std::string sender_uniq, dest_uniq;
bool should_ignore = false;
if (g_sensor_update_thread_active &&
g_snapshot_update_bus_cxn != "")
{
int cxn_id = -999;
if (sender != nullptr)
{
cxn_id = GetConnectionNumericID(std::string(sender));
}
if (destination != nullptr)
{
cxn_id = GetConnectionNumericID(std::string(destination));
}
// Reason for this: The connection may be the connection from
// the update thread plus 1, example: :1.10000 vs :1.10001 Not
// sure where the new connection comes from. FIXME
if (cxn_id <= 4 + g_snapshot_update_bus_cxn_id &&
cxn_id >= g_snapshot_update_bus_cxn_id)
{
should_ignore = true;
}
}
if (!should_ignore)
{
// TODO: This is for the bottom-left window
TrackMessage(m);
if (sender != nullptr)
{
sender_uniq =
g_connection_snapshot->GetUniqueNameIfExists(sender);
}
if (destination != nullptr)
{
dest_uniq = g_connection_snapshot->GetUniqueNameIfExists(
destination);
}
// This is for the bottom-right window
dbus_top_analyzer::g_dbus_statistics.OnNewDBusMessage(
sender_uniq.c_str(), dest_uniq.c_str(), interface, path,
member, type, m);
}
sd_bus_message_unref(m);
}
r = sd_bus_wait(g_bus,
(uint64_t)(GetSummaryIntervalInMillises() * 1000));
if (r < 0)
{
printf("Failed to wait on bus: %s\n", strerror(-r));
abort();
}
// Perform one analysis step
dbus_top_analyzer::Process();
}
}