# Sub modules
ADD_SUBDIRECTORY(src/client-api)
ADD_SUBDIRECTORY(src/dumpsys)
-ADD_SUBDIRECTORY(src/agent)
ADD_SUBDIRECTORY(src/service)
IF("${TESTS}" STREQUAL "ON")
ADD_SUBDIRECTORY(tests)
%{_unitdir}/dumpsys-service.service
%{_libdir}/tmpfiles.d/dumpsys-run.conf
%{_sysconfdir}/dbus-1/system.d/dumpsys-service.conf
-%{_sysconfdir}/dbus-1/system.d/dumpsys-agent.conf
%files -n dumpsys-devel
%manifest %{name}.manifest
+++ /dev/null
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-PROJECT(DUMPSYS_AGENT C)
-
-INCLUDE(GNUInstallDirs)
-INCLUDE(FindPkgConfig)
-
-SET(AGENT_LIB "libdumpsys-agent")
-
-find_package(PkgConfig REQUIRED)
-pkg_check_modules(libagent_pkgs REQUIRED
- dlog
- gio-2.0
- glib-2.0
- gio-unix-2.0)
-
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/shared)
-FOREACH(flag ${libagent_pkgs_CFLAGS})
- SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-
-FOREACH(flag ${libagent_pkgs_LDFLAGS})
- SET(EXTRA_LDFLAGS "${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Wextra -Werror -fPIE -Wno-unused-function -Wno-unused-const-variable")
-
-ADD_LIBRARY(${AGENT_LIB} STATIC libdumpsys-agent.c)
-TARGET_LINK_LIBRARIES(${AGENT_LIB} PUBLIC ${libagent_pkgs_LIBRARIES})
-SET_TARGET_PROPERTIES(${AGENT_LIB} PROPERTIES
- SOVERSION 1
- OUTPUT_NAME dumpsys-agent)
-
-INSTALL (FILES dumpsys-agent.conf DESTINATION /etc/dbus-1/system.d/
- PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
+++ /dev/null
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
- <policy user="log">
- <allow own="org.tizen.dumpsys.agent"/>
- <allow send_destination="org.tizen.dumpsys.agent"/>
- </policy>
- <policy context="default">
- <deny own="org.tizen.dumpsys.agent"/>
- <deny send_destination="org.tizen.dumpsys.agent"/>
- </policy>
-</busconfig>
+++ /dev/null
-/*
- * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 <assert.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <gio/gio.h>
-#include <gio/gunixfdlist.h>
-#include <linux/limits.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#ifndef LOG_TAG
-#define LOG_TAG "LIBDUMPSYS_AGENT"
-#endif
-
-#include <dlog.h>
-
-#include "common.h"
-
-static GDBusConnection *conn_system, *conn_session;
-static GMainLoop *main_loop;
-static guint name_ident;
-static GDBusNodeInfo *introspection_data;
-static const gchar introspection_xml[] =
-
-"<node>"
- "<interface name='org.tizen.dumpsys.agent'>"
- "<method name='Dump'>"
- "<arg type='as' name='args' direction='in'/>"
- "<arg type='s' name='name' direction='in'/>"
- "<arg type='i' name='result' direction='out'/>"
- "</method>"
- "</interface>"
-"</node>";
-
-static const char *uniq_name;
-
-static void free_objects()
-{
- if (introspection_data) {
- g_dbus_node_info_unref(introspection_data);
- introspection_data = NULL;
- }
-
- if (name_ident != 0) {
- g_bus_unown_name(name_ident);
- name_ident = 0;
- }
-
- if (conn_system) {
- g_object_unref(conn_system);
- conn_system = NULL;
- }
-
- if (conn_session) {
- g_object_unref(conn_session);
- conn_session = NULL;
- }
-}
-
-static GDBusMessage* prepare_message(GVariant *parameters, GUnixFDList *fd_list)
-{
- assert(parameters);
- assert(fd_list);
-
- GVariant *args = g_variant_get_child_value(parameters, 0);
- GVariant *name = g_variant_get_child_value(parameters, 1);
-
- const char *name_str = g_variant_get_string(name, NULL);
- char *new_name = NULL;
- if (asprintf(&new_name, "%s.%s", DUMPSYS_SERVICE_NAME_PREFIX, name_str) == -1) {
- LOGE("[%s] asprintf() error: %m\n", uniq_name);
- return NULL;
- }
-
- GDBusMessage *message = g_dbus_message_new_method_call(new_name,
- DUMPSYS_PATH,
- DUMPSYS_NAME,
- METHOD_DUMP);
-
- g_variant_unref(name);
-
- GVariant *args_tuple = g_variant_new_tuple(&args, 1);
- g_variant_unref(args);
-
- g_dbus_message_set_body(message, args_tuple);
- g_dbus_message_set_unix_fd_list(message, fd_list);
-
- free(new_name);
- return message;
-}
-
-static void dump_call_handler(GVariant *parameters,
- GDBusMethodInvocation *invocation)
-{
- bool result = true;
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(ass)"))) {
- LOGE("[%s] Parameters are not of the correct type (ass)\n", uniq_name);
- g_dbus_method_invocation_return_error(
- invocation,
- CS_ERROR,
- CS_ERR_PARAM,
- "%s",
- "Parameters are not of the correct type (ass)");
- return;
- }
-
- GDBusMessage *incoming_message = g_dbus_method_invocation_get_message(invocation);
- GUnixFDList *fd_list = g_dbus_message_get_unix_fd_list(incoming_message);
- GDBusMessage *message = prepare_message(parameters, fd_list);
- if (message == NULL) {
- LOGE("[%s] Message preparing error", uniq_name);
- goto out;
- }
-
- GError *error = NULL;
- GDBusMessage *reply = g_dbus_connection_send_message_with_reply_sync(
- conn_session,
- message,
- G_DBUS_SEND_MESSAGE_FLAGS_NONE,
- -1,
- NULL,
- NULL,
- &error);
- g_object_unref(message);
-
- if (reply != NULL && g_dbus_message_get_message_type(reply) == G_DBUS_MESSAGE_TYPE_ERROR)
- g_dbus_message_to_gerror(reply, &error);
-
- g_object_unref(reply);
-
- if (error != NULL) {
- if (error->domain == g_dbus_error_quark() &&
- error->code == G_DBUS_ERROR_SERVICE_UNKNOWN) {
- LOGD("[%s] Service not found on my bus\n", uniq_name);
- result = false;
- } else {
- LOGE("[%s] Dump method call error: %s\n", uniq_name, ERR_TEXT(error));
- g_dbus_method_invocation_return_gerror(invocation, error);
- goto out;
- }
- }
-
- g_dbus_method_invocation_return_value(invocation,
- g_variant_new("(i)",
- result ? DUMP_SUCCESS : DUMP_FAIL));
-out:
- if (error)
- g_error_free(error);
-}
-
-static void method_call_handler(GDBusConnection *conn,
- const gchar *sender,
- const gchar *object_path,
- const gchar *iface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
-{
- (void) conn;
- (void) sender;
- (void) object_path;
- (void) iface_name;
- (void) user_data;
- if (g_strcmp0(method_name, METHOD_DUMP) == 0)
- dump_call_handler(parameters, invocation);
-}
-
-static const GDBusInterfaceVTable interface_vtable = {
- method_call_handler, NULL, NULL, {}
-};
-
-static void on_bus_acquired(GDBusConnection *conn,
- const gchar *name,
- gpointer user_data)
-{
- (void) name;
- (void) user_data;
- guint registration_id;
- GError *error = NULL;
-
- registration_id = g_dbus_connection_register_object(conn,
- AGENT_OBJECT_PATH,
- introspection_data->interfaces[0],
- &interface_vtable, NULL, NULL, &error);
-
- if (registration_id == 0 || error) {
- LOGE("[%s] Failed to g_dbus_connection_register_object: %s\n",
- uniq_name,
- ERR_TEXT(error));
- if (error)
- g_error_free(error);
- }
-}
-
-static void name_lost_handler(GDBusConnection *conn,
- const gchar *name,
- gpointer user_data)
-{
- (void) conn;
- (void) name;
- (void) user_data;
- LOGE("[%s] DBus name lost. Exiting.", uniq_name);
- free_objects();
- g_main_loop_quit(main_loop);
-}
-
-static bool register_agent(GDBusConnection *conn)
-{
- GError *error = NULL;
-
- GVariant *v_result = g_dbus_connection_call_sync(conn,
- SERVICE_BUS_NAME,
- SERVICE_OBJECT_PATH,
- SERVICE_INTERFACE,
- METHOD_REGISTER,
- NULL,
- G_VARIANT_TYPE("(b)"),
- G_DBUS_CALL_FLAGS_NONE,
- SERVICE_TIMEOUT_MS,
- NULL,
- &error);
-
- if (v_result == NULL || error != NULL) {
- LOGE("[%s] Registration error: %s\n", uniq_name, ERR_TEXT(error));
- if (error)
- g_error_free(error);
- return false;
- }
- bool result;
- g_variant_get(v_result, "(b)", &result);
-
- if (result) {
- LOGD("[%s] Registration success\n", uniq_name);
- return true;
- } else {
- LOGD("[%s] Registration failed\n", uniq_name);
- return true;
- }
-}
-
-static GDBusConnection* dbus_connect(GBusType bus_type) {
- GError *error = NULL;
- GDBusConnection *conn = g_bus_get_sync(bus_type, NULL, &error);
- if (!conn || error) {
- LOGE("Failed to get the %s bus: %s\n", bus_type == G_BUS_TYPE_SESSION ? "session" : "system",
- ERR_TEXT(error));
- if (error)
- g_error_free(error);
- return NULL;
- }
- return conn;
-}
-
-static bool dbus_init(GBusType bus_type)
-{
- introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
- if (introspection_data == NULL) {
- LOGE("Failed to init g_dbus_node_info_new_for_xml\n");
- return false;
- }
-
- conn_system = dbus_connect(G_BUS_TYPE_SYSTEM);
- if (!conn_system)
- return false;
-
- uniq_name = g_dbus_connection_get_unique_name(conn_system);
- if (!uniq_name) {
- LOGE("Failed to get unique name\n");
- return false;
- }
-
- conn_session = dbus_connect(bus_type);
- if (!conn_session)
- return false;
-
- name_ident = g_bus_own_name(G_BUS_TYPE_SYSTEM, AGENT_BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE,
- on_bus_acquired, NULL, name_lost_handler, NULL, NULL);
-
- return register_agent(conn_system);
-}
-
-API_FUNCTION bool dumpsys_agent_run(GMainLoop *loop, GBusType bus_type)
-{
- main_loop = loop;
- bool result = dbus_init(bus_type);
- return result;
-}
-
-API_FUNCTION void dumpsys_agent_stop()
-{
- free_objects();
-}
+++ /dev/null
-/*
- * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- */
-
-#ifndef __LIBDUMPSYS_AGENT_H__
-#define __LIBDUMPSYS_AGENT_H__
-
-#include <stdbool.h>
-#include <gio/gio.h>
-
-bool dumpsys_agent_run(GMainLoop *loop, GBusType bus_type);
-void dumpsys_agent_stop();
-
-#endif // __LIBDUMPSYS_AGENT_H__
gio-unix-2.0)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/shared)
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/agent)
FOREACH(flag ${dumpsys_service_pkgs_CFLAGS})
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
ENDFOREACH(flag)
SET(DUMPSYS_SERVICE dumpsys-service.c)
LINK_DIRECTORIES(${CMAKE_BINARY_DIR})
-LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/agent)
ADD_EXECUTABLE(dumpsys-service ${DUMPSYS_SERVICE})
-ADD_DEPENDENCIES(dumpsys-service libdumpsys-agent)
-TARGET_LINK_LIBRARIES(dumpsys-service PUBLIC ${dumpsys_service_pkgs_LIBRARIES} libdumpsys-agent)
+TARGET_LINK_LIBRARIES(dumpsys-service PUBLIC ${dumpsys_service_pkgs_LIBRARIES})
INSTALL (TARGETS dumpsys-service DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
#include <sys/types.h>
#include <unistd.h>
-#include "libdumpsys-agent.h"
-
#ifndef LOG_TAG
#define LOG_TAG "DUMPSYS_SERVICE"
#endif
"</node>";
static GMainLoop* loop;
-static GList *agents_list;
-static GTask *agent_task;
-static bool agent_success;
static bool reset_fd_flag(int fd, int flag)
{
return fd_list;
}
+static GDBusMessage* prepare_message(GVariant *parameters, GUnixFDList *fd_list)
+{
+ assert(parameters);
+ assert(fd_list);
+
+ GVariant *args = g_variant_get_child_value(parameters, 0);
+ GVariant *name = g_variant_get_child_value(parameters, 1);
+
+ const char *name_str = g_variant_get_string(name, NULL);
+ char *new_name = NULL;
+ if (asprintf(&new_name, "%s.%s", DUMPSYS_SERVICE_NAME_PREFIX, name_str) == -1) {
+ LOGE("asprintf() error: %m\n");
+ return NULL;
+ }
+
+ GDBusMessage *message = g_dbus_message_new_method_call(new_name,
+ DUMPSYS_PATH,
+ DUMPSYS_NAME,
+ METHOD_DUMP);
+
+ g_variant_unref(name);
+
+ GVariant *args_tuple = g_variant_new_tuple(&args, 1);
+ g_variant_unref(args);
+
+ g_dbus_message_set_body(message, args_tuple);
+ g_dbus_message_set_unix_fd_list(message, fd_list);
+
+ free(new_name);
+ return message;
+}
+
static bool forward_dump(GDBusConnection *conn, GVariant *body, int write_fd)
{
assert(conn);
assert(body);
assert(write_fd >= 0);
- GList *element = agents_list;
- bool sent = false;
-
- while (element != NULL && !sent) {
- bool invalid_agent = false;
-
- LOGD("Forwarding the dump call to agent %s\n", (char *)element->data);
-
- GUnixFDList *fd_list_write = prepare_unix_fd_list(write_fd);
- if (fd_list_write == NULL)
- goto end;
-
- GError *error = NULL;
- GVariant *reply_value = g_dbus_connection_call_with_unix_fd_list_sync(
- conn,
- (char *)element->data,
- AGENT_OBJECT_PATH,
- AGENT_INTERFACE,
- METHOD_DUMP,
- body,
- G_VARIANT_TYPE("(i)"),
- G_DBUS_SEND_MESSAGE_FLAGS_NONE,
- SERVICE_TIMEOUT_MS,
- fd_list_write,
- NULL,
- NULL,
- &error);
- g_object_unref(fd_list_write);
-
- if (error == NULL) {
- int result = DUMP_FAIL;
-
- if (reply_value != NULL)
- g_variant_get(reply_value, "(i)", &result);
-
- sent = result == DUMP_SUCCESS;
- } else {
- if (error->domain == g_dbus_error_quark() &&
- error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
- invalid_agent = true;
- else
- LOGE("Dump method call error: %s\n", ERR_TEXT(error));
+ bool result = true;
- g_error_free(error);
- }
+ GUnixFDList *fd_list_write = prepare_unix_fd_list(write_fd);
+ if (fd_list_write == NULL)
+ goto out;
- if (sent) {
- char *service_name;
- g_variant_get(body, "(ass)", NULL, &service_name);
- LOGD("Service %s was found by %s agent.\n",
- service_name,
- (char *)element->data);
- free(service_name);
- } else {
- GList *prev_element = element;
- element = g_list_next(element);
+ GDBusMessage *message = prepare_message(body, fd_list_write);
- if (invalid_agent) {
- LOGD("Removing agent %s\n", (char *)prev_element->data);
- agents_list = g_list_remove_link(agents_list, prev_element);
+ g_object_unref(fd_list_write);
- g_list_free_full(prev_element, free);
- }
- }
+ if (message == NULL) {
+ LOGE("Message preparing error");
+ goto out;
}
-end:
- return sent;
-}
-static void register_call_handler(GDBusMethodInvocation *invocation, const gchar *agent)
-{
- assert(invocation);
- assert(agent);
+ GError *error = NULL;
+ GDBusMessage *reply = g_dbus_connection_send_message_with_reply_sync(
+ conn,
+ message,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ &error);
+ g_object_unref(message);
+
+ if (reply != NULL && g_dbus_message_get_message_type(reply) == G_DBUS_MESSAGE_TYPE_ERROR)
+ g_dbus_message_to_gerror(reply, &error);
- LOGD("The new agent has been registered: %s\n", agent);
- char *name = strdup(agent);
+ g_object_unref(reply);
- if (name == NULL)
- LOGE("strdup error: %m\n");
- else
- agents_list = g_list_append(agents_list, name);
+ if (error != NULL) {
+ if (error->domain == g_dbus_error_quark() &&
+ error->code == G_DBUS_ERROR_SERVICE_UNKNOWN) {
+ LOGE("Service not found\n");
+ } else {
+ LOGE("Dump method call error: %s\n", ERR_TEXT(error));
+ }
+ result = false;
+ }
+out:
+ if (error)
+ g_error_free(error);
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", name != NULL));
+ return result;
}
static bool attach_unix_fd(GDBusMessage *message, int fd)
CS_ERROR,
CS_ERR_INTERNAL,
"Prepare fd list error");
+ LOGE("Prepare fd list error\n");
goto end;
}
GDBusMethodInvocation *invocation,
gpointer user_data)
{
- if (g_strcmp0(method_name, METHOD_REGISTER) == 0)
- register_call_handler(invocation, sender);
- else if (g_strcmp0(method_name, METHOD_DUMP) == 0)
+ if (g_strcmp0(method_name, METHOD_DUMP) == 0)
dump_call_handler(conn, parameters, invocation);
}
-static void run_agent_thread(GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- bool result = true;
- GMainContext *context = g_main_context_new();
- GMainLoop *agent_loop = g_main_loop_new(context, false);
-
- g_main_context_push_thread_default(context);
-
- if (dumpsys_agent_run(loop, G_BUS_TYPE_SYSTEM)) {
- g_main_loop_run(agent_loop);
- } else {
- LOGE("Failed to run agent\n");
- result = false;
- }
-
- g_main_context_pop_thread_default(context);
- g_main_loop_unref(agent_loop);
- g_main_context_unref(context);
- g_task_return_boolean(task, result);
-}
-
-static bool run_agent_finish(GAsyncResult *res,
- GError **error)
-{
- g_return_val_if_fail(g_task_is_valid(res, NULL), false);
- return g_task_propagate_boolean(G_TASK(res), error);
-}
-
-static void run_agent_callback(GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- GError *error = NULL;
- bool result = run_agent_finish(res, &error);
- if (!result) {
- LOGE("Agent thread failed - exiting: %s\n", ERR_TEXT(error));
- if (error)
- g_error_free(error);
- g_main_loop_quit(loop);
- } else {
- LOGD("Agent thread success\n");
- agent_success = true;
- }
-}
-
-static void on_name_acquired(GDBusConnection *conn,
- const gchar *name,
- gpointer user_data)
-{
- agent_task = g_task_new(NULL, NULL, run_agent_callback, NULL);
- g_task_run_in_thread(agent_task, run_agent_thread);
-}
-
static const GDBusInterfaceVTable interface_vtable = {
method_call_handler, NULL, NULL
};
}
}
+static void on_name_lost(GDBusConnection *conn,
+ const gchar *name,
+ gpointer user_data)
+{
+ LOGE("Lost the name %s on the system bus", name);
+ g_main_loop_quit(loop);
+}
+
static bool dbus_init(void)
{
GError *error = NULL;
SERVICE_BUS_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
- on_name_acquired,
- NULL, NULL, NULL);
+ NULL,
+ on_name_lost,
+ NULL,
+ NULL);
return true;
}
-static void free_agents()
-{
- GList *element = agents_list;
- while (element != NULL) {
- element = g_list_next(element);
- g_list_free_full(g_list_previous(element), free);
- }
- g_list_free_full(agents_list, free);
-}
-
int main(int argc, char *argv[])
{
- agent_success = false;
loop = g_main_loop_new(NULL, false);
if (!dbus_init())
if (introspection_data != NULL)
g_dbus_node_info_unref(introspection_data);
- free_agents();
-
- return agent_success ? EXIT_SUCCESS : EXIT_FAILURE;
+ return EXIT_SUCCESS;
}
#define DUMPSYS_INTERFACE DUMPSYS_NAME
#define DUMPSYS_SERVICE_NAME_PREFIX DUMPSYS_NAME
-#define AGENT_BUS_NAME "org.tizen.dumpsys.agent"
-#define AGENT_INTERFACE "org.tizen.dumpsys.agent"
-#define AGENT_OBJECT_PATH "/Org/Tizen/Dumpsys/Agent"
#define SERVICE_BUS_NAME "org.tizen.dumpsys.service"
#define SERVICE_INTERFACE "org.tizen.dumpsys.service"
#define SERVICE_OBJECT_PATH "/Org/Tizen/Dumpsys/Service"
#define SERVICE_TIMEOUT_MS 5000
#define METHOD_DUMP "Dump"
-#define METHOD_REGISTER "Register"
#define CS_ERROR 1
#define CS_ERR_PARAM 1