Compare commits

..

18 Commits

Author SHA1 Message Date
openvela-robot 33b57ae7b6 update .github 2025-07-23 10:50:56 +08:00
openvela-robot 5ab09981ce update .github 2025-07-23 00:25:25 +08:00
openvela-robot db3047f550 workflows add stale.yml 2025-05-06 16:45:21 +08:00
cuiziwei 319fa078ad ALOG: Fixed the issue that disable ALOG will print ANDROID_LOG_VERBOSE level logs by default.
Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-03-05 21:00:06 +08:00
cuiziwei e5494311ba apps/frameworks: Add ALOG to select LIBC_PRINT_EXTENSION to print log.
cause ALOG will print log with syslog(g_logprimap[prio], "[%s] %pV\n", tag, &vaf);

Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-03-05 21:00:06 +08:00
buxiasen 2ccf67284d kvdb: use filekv over tmpfs as no-persist kv backend
Persist NVS KVDB and rammtd temporary is not a good case,
Unqlite over tmpfs is much slower than tmpfs.

Signed-off-by: buxiasen <buxiasen@xiaomi.com>
2025-03-05 10:20:52 +08:00
chenrun1 67656912d8 kvdb:add API exitprop for exit kvdbd server
Summary:
  Added support for the Server exit capability
  1. Add new api property_exit()
  2. Add new command exitprop

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
2025-02-28 21:46:09 +08:00
openvela-robot b0ddf494af Update the ci trigger from pull_request to pull_request_target 2025-01-10 00:10:09 +08:00
openvela-robot a44fb5a327 update workflows ci.yml, delete pull_request_review trigger 2024-12-28 00:15:56 +08:00
openvela-robot 168b12ef14 add .github/CODEOWNERS PULL_REQUEST_TEMPLATE.md 2024-12-27 20:08:54 +08:00
openvela-robot 6a96d1f18e update ci pull_request types to [opened, reopened, synchronize] 2024-12-24 01:29:59 +08:00
liujinye 934dd070fa workflows add ci.yaml 2024-12-17 10:30:30 +08:00
openvela-robot 171cb5f416 workflows add checkpatch.yaml 2024-12-12 16:14:46 +08:00
openvela-robot eac77e5491 update issue template 2024-12-10 22:13:52 +08:00
openvela-robot ae9f5b50cf update workflows ci 2024-12-10 15:55:25 +08:00
openvela-robot 79f5248b8c add issue template 2024-12-09 21:39:47 +08:00
openvela-robot 362d791987 add ci.yml
Change-Id: I5945b1ba18fe918238310174f17adf5e91097d92
2024-11-25 19:50:12 +08:00
openvela-robot 4b6dd71a31 Merge commit
Change-Id: If3a7c4f1d2e235c79069c60841e9d83c9b14b5b7
2024-11-25 17:34:53 +08:00
29 changed files with 462 additions and 8116 deletions

View File

@ -6,8 +6,6 @@ name: CI
on:
pull_request_target:
types: [opened, reopened, synchronize]
issue_comment:
types: [created]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:

View File

@ -1,119 +1,41 @@
cc_defaults {
name: "framework_utils_defaults",
name: "kvdb_defaults",
static_libs: [
"libframework_utils",
"libkvdb",
],
header_libs: [
"kernel_modules_headers",
],
}
soong_config_module_type {
name: "framework_utils_cc_defaults",
module_type: "cc_defaults",
config_namespace: "vela",
variables: [
"kvdb_server",
],
properties: [
"cflags",
],
}
soong_config_string_variable {
name: "kvdb_server",
values: [
"cp",
"sensor",
"audio",
],
}
framework_utils_cc_defaults {
name: "frameworks_utils_cflags_defaults",
cflags: [
"-fvisibility=hidden",
"-DCONFIG_NET_RPMSG",
],
soong_config_variables: {
kvdb_server: {
cp: {
cflags: ["-DCONFIG_KVDB_SERVER_CPUNAME=\"cp\""],
},
sensor: {
cflags: ["-DCONFIG_KVDB_SERVER_CPUNAME=\"sensor\""],
},
audio: {
cflags: ["-DCONFIG_KVDB_SERVER_CPUNAME=\"audio\""],
},
conditions_default: {
cflags: ["-DCONFIG_KVDB_SERVER_CPUNAME=\"ap\""],
},
},
},
}
cc_library_static {
name: "libframework_utils",
name: "libkvdb",
export_include_dirs: ["include"],
defaults: ["frameworks_utils_cflags_defaults"],
srcs: [
"kvdb/common.c",
"kvdb/system_properties.c",
"kvdb/client.c",
],
header_libs: [
"kernel_modules_headers",
cflags: [
"-DCONFIG_KVDB_SERVER_CPUNAME=\"ap\"",
"-fvisibility=hidden",
],
}
cc_library_headers {
name: "libprop_headers",
export_include_dirs: ["include/cutils"],
vendor_available: true,
}
cc_library_headers {
name: "libframework_utils_headers",
name: "likvdb_headers",
export_include_dirs: ["include"],
vendor_available: true,
proprietary: true
}
cc_binary {
name: "kvset",
srcs: ["kvdb/setprop.c"],
defaults: ["framework_utils_defaults"],
defaults: ["kvdb_defaults"],
}
cc_binary {
name: "kvget",
srcs: ["kvdb/getprop.c"],
defaults: ["framework_utils_defaults"],
}
cc_library_static {
name: "libkvdb_vendor",
export_include_dirs: ["include"],
defaults: ["frameworks_utils_cflags_defaults"],
srcs: [
"kvdb/common.c",
"kvdb/system_properties.c",
"kvdb/client.c",
],
header_libs: [
"kernel_modules_headers",
],
proprietary: true
defaults: ["kvdb_defaults"],
}

View File

@ -16,7 +16,6 @@
if(CONFIG_SCHED_INSTRUMENTATION_DUMP
OR CONFIG_ANDROID_LIBBASE
OR CONFIG_ATRACE
OR CONFIG_LIB_DBUS
OR CONFIG_KVDB)
set_property(
@ -31,7 +30,9 @@ if(CONFIG_SCHED_INSTRUMENTATION_DUMP
nuttx_add_library(framework_utils STATIC)
list(APPEND CSRCS trace/trace.c)
if(CONFIG_SCHED_INSTRUMENTATION_DUMP)
list(APPEND CSRCS trace/trace.c)
endif()
if(CONFIG_ANDROID_LIBBASE)
list(APPEND CSRCS log/log_write.c log/set_abort_message.c)
endif()
@ -41,33 +42,11 @@ if(CONFIG_SCHED_INSTRUMENTATION_DUMP
framework_utils)
endif()
if(CONFIG_GDBUS)
file(GLOB GDBUS_CSRCS gdbus/*.c)
list(APPEND CSRCS ${GDBUS_CSRCS})
list(APPEND CFLAGS -DDBUS_COMPILATION -DVERSION="1.15.1")
list(APPEND INCDIR ${NUTTX_APPS_DIR}/external/dbus/dbus)
endif()
if(CONFIG_KVDB)
if(CONFIG_KVDB_DIRECT)
list(APPEND CSRCS kvdb/direct.c)
else()
list(APPEND CSRCS kvdb/client.c)
nuttx_add_application(
MODULE
${CONFIG_KVDB}
NAME
exitprop
STACKSIZE
${CONFIG_KVDB_STACKSIZE}
PRIORITY
${CONFIG_KVDB_PRIORITY}
SRCS
kvdb/exitprop.c
INCLUDE_DIRECTORIES
${INCDIR}
DEPENDS
framework_utils)
endif()
list(APPEND CSRCS kvdb/common.c kvdb/system_properties.c kvdb/backend.c)
@ -131,25 +110,6 @@ if(CONFIG_SCHED_INSTRUMENTATION_DUMP
${INCDIR}
DEPENDS
framework_utils)
if(CONFIG_KVDB_QEMU_PROPERTIES)
nuttx_add_application(
MODULE
${CONFIG_KVDB}
NAME
qemuprop
STACKSIZE
${CONFIG_KVDB_STACKSIZE}
PRIORITY
${CONFIG_KVDB_PRIORITY}
SRCS
kvdb/qemu_properties.c
INCLUDE_DIRECTORIES
${INCDIR}
DEPENDS
framework_utils)
endif()
endif()
target_sources(framework_utils PRIVATE ${CSRCS})

22
Kconfig
View File

@ -41,13 +41,6 @@ config ATRACE
---help---
Enable Android Trace.
config GDBUS
bool "Enable Vela GDBus"
depends on LIB_DBUS && LIBUV_EXTENSION
default y
---help---
Enable Vela GDBus
config KVDB
tristate "key-value database"
default n
@ -102,13 +95,12 @@ if !KVDB_DIRECT
config KVDB_SERVER_CPUNAME
string "which cpu kvdb server runs on"
depends on NET_RPMSG
depends on !KVDB_SERVER
default "ap"
config KVDB_TIMEOUT_INTERVAL
int "transaction timeout interval(usec)"
default 5000000
depends on NET_SOCKOPTS
int "transaction timeout interval(sec)"
default 0
endif
@ -117,11 +109,6 @@ config KVDB_COMMIT_INTERVAL
depends on KVDB_SERVER
default 5
config KVDB_BACKLOG_CONNS
int "backlog connections"
depends on KVDB_SERVER
default 256
if KVDB_DIRECT || KVDB_SERVER
config KVDB_SOURCE_PATH
@ -145,7 +132,8 @@ config KVDB_UNQLITE
config KVDB_NVS
bool "NVS"
depends on MTD_CONFIG_NAMED
select MTD_CONFIG_NAMED
depends on MTD_CONFIG_FAIL_SAFE
---help---
Configure using Non-Volatile Storage to store Key-value

View File

@ -16,7 +16,9 @@
include $(APPDIR)/Make.defs
ifneq ($(CONFIG_SCHED_INSTRUMENTATION_DUMP),)
CSRCS += trace/trace.c
endif
ifneq ($(CONFIG_ANDROID_LIBBASE),)
CSRCS += log/log_write.c log/set_abort_message.c
@ -27,12 +29,6 @@ MAINSRC += trace/atrace.c
PROGNAME += atrace
endif
ifneq ($(CONFIG_GDBUS),)
CSRCS += $(wildcard gdbus/*.c)
CFLAGS += -DDBUS_COMPILATION -DVERSION="1.15.1"
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/external/dbus/dbus
endif # CONFIG_LIB_DBUS
ifneq ($(CONFIG_KVDB),)
ifneq ($(CONFIG_KVDB_DIRECT),)
CSRCS += kvdb/direct.c
@ -72,6 +68,15 @@ STACKSIZE = $(CONFIG_KVDB_STACKSIZE)
MODULE = $(CONFIG_KVDB)
endif # CONFIG_KVDB
EXPORT_FILES := gdbus/gdbus.h include
ASRCS := $(wildcard $(ASRCS))
CSRCS := $(wildcard $(CSRCS))
CXXSRCS := $(wildcard $(CXXSRCS))
MAINSRC := $(wildcard $(MAINSRC))
NOEXPORTSRCS = $(ASRCS)$(CSRCS)$(CXXSRCS)$(MAINSRC)
ifneq ($(NOEXPORTSRCS),)
BIN := $(APPDIR)/staging/libutils.a
endif
include $(APPDIR)/Application.mk

326
README.md
View File

@ -7,49 +7,50 @@
The current directory mainly contains some common tool implementations provided by the framework.
| Tool | Brief description of tool |
| -- | -- |
| `gdbus` | Encapsulation of the `D-Bus` interface for convenient operation of `D-Bus`. |
| `kvdb` | `Key-value pair` data access interface based on local database. |
| `log` | Provides an `Log API` interface compatible with the `Android` platform.<br>Used to directly use the `Android` LOG API in `Vela`. |
| `log` | Provides an `Log API` interface compatible with the `Android` platform.<br>Used to directly use the Android LOG API in `openvela`. |
| `trace` | Provides a dotting tool for user-space programs. |
## Project Description
### 1. gdbus
### 1 kvdb
The `gdbus` module is an API module that further encapsulates the `D-Bus` interface. Since the `D-Bus` interface is relatively complex to use, when actually using modules, by encapsulating the `D-Bus` interface again, it will be more convenient to use. `gdbus` provides an API interface with easier operation to facilitate our operation of `D-Bus`.
#### Brief introduction
### 2. kvdb
`kvdb` provides a set of local database read and write interfaces. The `API` design refers to the `properties` access specification of `Android`, and also provides command line tools to facilitate local quick debugging.
#### 2.1 Introduction
`kvdb` in `openvela` supports local persistent storage and cross-core calls (requires Unix domain socket and rpmsg socket support respectively). The key value that needs to be permanently stored in the file needs to start with `"persist."`.
`kvdb` underlying implementation includes three mechanisms:
1. Based on the open source `UnQLite` database, dependent on the database.
2. Based on `MTD CONFIG` (currently only used for nor flash).
`kvdb` provides a set of read and write interfaces for local databases. The `API` design refers to the `Android` `properties` access specification. At the same time, a command-line tool is provided to facilitate local rapid debugging.
The `kvdb` in `Vela` supports local permanent storage and cross-core calls (requiring Unix domain socket and rpmsg socket support respectively). The key-value that needs to be permanently stored in a file needs to start with `"persist."`.
The underlying implementation of `kvdb` contains three mechanisms:
1. Based on the open source `UnQLite` database, it depends on the database;
2. Another one is based on `MTD CONFIG` (currently only used for nor flash);
3. The last one is based on `file` files.
> General interface description of `kvdb`: [frameworks/utils/include/kvdb.h](include/kvdb.h)
> `kvdb` interface description: [frameworks/utils/include/kvdb.h](include/kvdb.h)
#### 2.2 Typical configuration of `kvdb`
#### kvdb common configuration description
| kvdb Configuration | Description |
| kvdb configuration | Description |
| -- | -- |
| CONFIG_KVDB_PRIORITY | KVDB task priority, default is the system default value. |
| CONFIG_KVDB_STACKSIZE | KVDB stack space allocation, default is the system default value. |
| CONFIG_KVDB_SERVER | KVDB SERVER mode. Indicates whether the current CPU is the main CPU for reading and writing files. If it is 'n', only the KVDB on other CPUs will be called. |
| CONFIG_KVDB_DIRECT | KVDB DIRECT mode: In scenarios without rpmsg socket (no need for cross-core), this mode can be used.<br>Only one of CONFIG_KVDB_DIRECT and CONFIG_KVDB_SERVER modes can be selected. |
| CONFIG_KVDB_COMMIT_INTERVAL | KVDB commit interval (in seconds), default is 5.<br>KVDB has an internal cache and only after committing is the data truly written to the file. If power is off before the `CONFIG_KVDB_COMMIT_INTERVAL` time after submitting a persist type kv, the data will not be truly written to the `persist.db` file. The shorter the `CONFIG_KVDB_COMMIT_INTERVAL` time is set, the more frequently kvdb writes the internal cache to the file, which will affect system performance to a certain extent. |
| CONFIG_KVDB_SOURCE_PATH | KVDB default value loading path, default is `"/etc/build.prop"`, supports multiple paths, just separate them with `;`. At each startup, KV values will be automatically loaded from this file. |
| CONFIG_KVDB_UNQLITE | Configure to use unqlite database to store kv. |
| CONFIG_KVDB_NVS | Configure to use nvs to store kv. |
| CONFIG_KVDB_FILE | Configure to use file to store kv. |
| CONFIG_KVDB_PRIORITY | KVDB task priority, defaults to system default |
| CONFIG_KVDB_STACKSIZE | KVDB stack space allocation, defaults to system default |
| CONFIG_KVDB_SERVER | KVDB SERVER mode: indicates whether the current CPU is the main CPU for reading and writing files, if it is n, only KVDB on other CPUs is called |
| CONFIG_KVDB_DIRECT | KVDB DIRECT mode: This mode can be used in scenarios where rpmsg socket is not required (no need for cross-core)<br>CONFIG_KVDB_DIRECT and CONFIG_KVDB_SERVER can only be selected from the two modes |
| CONFIG_KVDB_COMMIT_INTERVAL | KVDB commit interval (seconds), default is 5 <br> KVDB has internal cache, and the data is actually written to the file only after committing. If the power is turned off before `CONFIG_KVDB_COMMIT_INTERVAL` time after committing the persist type kv, the data will not be actually written to the `persist.db` file. The shorter the `CONFIG_KVDB_COMMIT_INTERVAL` time is set, the more frequently `kvdb` writes the internal cache to the file, which will affect the system performance to a certain extent. |
| CONFIG_KVDB_SOURCE_PATH | KVDB default value loading path, the default is `"/etc/build.prop"`, supports multiple paths, separated by `;`, and the KV value will be automatically loaded from this file every time the computer starts. |
| CONFIG_KVDB_UNQLITE | Configure to use unqlite database to store kv |
| CONFIG_KVDB_NVS | Configure to use nvs to store kv |
| CONFIG_KVDB_FILE | Configure to use file to store kv |
> Only one of the three backends for data storage, `CONFIG_KVDB_UNQLITE`, `CONFIG_KVDB_NVS`, and `CONFIG_KVDB_FILE`, can be selected.
> Only one of the three data storage `backend`s `CONFIG_KVDB_UNQLITE`, `CONFIG_KVDB_NVS`, and `CONFIG_KVDB_FILE` can be selected.
### 3. log
### 2 log
The log module itself is a wrapper layer that encapsulates the Vela log system, making the API consistent with the log API in Android. When we port Android applications or frameworks to Vela, we don't need to provide our own log integration anymore, we can use this module directly. Here is the structure of the log module:
The log module itself is a wrapper layer, which encapsulates the `openvela log` system at the bottom layer. The encapsulated API is consistent with the `log API` in Android. When we port the `Android` application or framework to `openvela`, we do not need to provide our own `log` connection, and can directly use the current module.
The following is the structure of the log module:
```log
android log api
@ -61,194 +62,159 @@ android log api
vela log impl
```
### 4. trace
### 3 trace
This module mainly contains instrumentation tools for user-space programs. We can achieve instrumentation analysis by manually instrumenting in user programs. The atrace tool provided in trace is mainly used in conjunction with the instrumentation tools provided by the Vela system.
This module mainly contains the dot analysis tool for user space programs. We can implement dot analysis by manually inserting stubs in user programs.
The atrace tool provided in trace is mainly used in conjunction with the dot analysis tool provided by the openvela system.
## Usage Guide
### 1. gdbus
1. To enable the `CONFIG_LIB_DBUS` build option
### 1 kvdb
2. Instantiation
`kvdb` itself has multiple usage forms. We can integrate it directly in the code, or use it directly in `nsh` as a command line program.
GDBus is an interface module and requires the caller to instantiate it and pass the instantiated object when calling the GDBus interface.
The caller needs to create a structure. The members should at least include `gdbus Connection` and `client` instance objects, similar to the following:
#### 1.1 Example of direct integration in the code
```cpp
typedef struct {
DBusConnection* connection;
GDBusClient* client;
GDBusProxy* dbus_proxy[USER_SUPPORT_PROXY_MAX];
bool client_ready;
} dbus_context;
dbus_context* ctx = malloc(sizeof(dbus_context));
// Create a DbusConnection instance
ctx->connection = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
// Set the disconnection function for the Connection. Otherwise, when the dbus Connection exits, the current process will exit synchronously. After adding this function, the current process will not exit.
g_dbus_set_disconnect_function(ctx->connection, system_dbus_disconnected, callback, NULL);
// Set the client name for the current dbus Connection
dbus_request_name(ctx->connection, client_name, &err);
ctx->client = g_dbus_client_new(ctx->connection, OFONO_SERVICE, OFONO_MANAGER_PATH);
// Set the property filter function for the proxy.
// ofono_interface_proxy_added listens for proxy addition and caches the required proxy instances on demand for subsequent operations on the properties and methods of this proxy.
// ofono_interface_proxy_removed listens for proxy removal and synchronously clears the cached proxy instances.
// In the object_filter function, set which proxies do not need to read property attributes.
// ofono_property_changed listens for changes in properties and caches the property values of the corresponding proxies on demand.
g_dbus_client_set_proxy_handlers(dbus_client, ofono_interface_proxy_added,
ofono_interface_proxy_removed,
object_filter,
ofono_property_changed, tele);
// Set the callback function for successful dbus client connection on_dbus_client_ready
g_dbus_client_set_ready_watch(ctx->client, on_dbus_client_ready, cbd)
```
3. Exit and release
When the caller process exits, it needs to release the `dbus Connection` instance. Execute the following code:
```cpp
g_dbus_client_unref(ctx->client);
dbus_connection_close(ctx->connection);
dbus_connection_unref(ctx->connection);
```
4. Call the interface
Call the interface, pass in the instance of `voice manager proxy`, and initiate a dial request.
```cpp
g_dbus_proxy_method_call(ctx->dbus_proxy[VOICE_MANAGER], "Dial", dial_setup,
dial_reply, param, dial_destory)
```
### 2. kvdb
`kvdb` itself has multiple usage forms. We can integrate it directly in the code or use it as a command-line program in `nsh`.
#### 2.1 Example of direct integration in code
The following is a demo of the interface provided in `kvdb` for monitoring key/value changes. For simple and complex scenarios, two sets of APIs are provided.
The following is a demo of the interface provided by `kvdb` to monitor `key/value` changes. Two sets of APIs are provided for simple and complex scenarios:
1. Simple scenario: Only one `key` can be monitored.
```cpp
int main(void)
{
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int ret = property_wait("tsetkey", newkey, newvalue, -1);
if (ret < 0)
```cpp
int main(void)
{
printf("property_wait failed, ret=%d\n", ret);
goto out;
}
printf("the new key: %s\n", newkey);
printf("the new value: %s\n", newvalue);
out:
return ret;
}
```
2. Complex scenario: Supports polling. Users can freely monitor multiple `keys`.
```cpp
int main(void)
{
struct pollfd fds[2];
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int fd1 = property_monitor_open("monitorkey*");
int fd2 = property_monitor_open("testkey");
fds[0].fd = fd1;
fds[0].events = POLLIN;
fds[1].fd = fd2;
fds[1].events = POLLIN;
int ret= poll(fds, 2, -1);
if (ret <= 0)
goto out;
for (int i = 0; i < 2; i++)
{
if ((fds[i].revents & POLLIN) == 0)
continue;
ret = property_monitor_read(fds[i].fd, newkey, newvalue);
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int ret = property_wait("tsetkey", newkey, newvalue, -1);
if (ret < 0)
{
printf("property_wait failed, ret=%d\n", ret);
goto out;
}
printf("the new key: %s\n", newkey);
printf("the new value: %s\n", newvalue);
out:
return ret;
}
```
out:
property_monitor_close(fd1);
property_monitor_close(fd2);
return ret;
}
2. Complex scenarios: Supports `poll`, allowing users to freely monitor multiple `keys`.
```cpp
int main(void)
{
struct pollfd fds[2];
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int fd1 = property_monitor_open("monitorkey*");
int fd2 = property_monitor_open("testkey");
fds[0].fd = fd1;
fds[0].events = POLLIN;
fds[1].fd = fd2;
fds[1].events = POLLIN;
int ret= poll(fds, 2, -1);
if (ret <= 0)
goto out;
for (int i = 0; i < 2; i++)
{
if ((fds[i].revents & POLLIN) == 0)
continue;
ret = property_monitor_read(fds[i].fd, newkey, newvalue);
if (ret < 0)
goto out;
printf("the new key: %s\n", newkey);
printf("the new value: %s\n", newvalue);
}
out:
property_monitor_close(fd1);
property_monitor_close(fd2);
return ret;
}
```
#### 1.2 Use in nsh as command line
KVDB provides two command line programs, `getprop` and `setprop`, for users to use. Users can use `getprop` and `setprop` to easily view existing KVs or set new KVs.
These two command lines are enabled by default after KVDB is enabled.
- getprop: print out the set property
- nsh> getprop: list all current `props`
- nsh> getprop `key`: print out the `prop` corresponding to `key`
- setprop: set or delete property
- nsh> setprop `key`: delete the `prop` corresponding to `key`
- nsh> setprop `key` `value`: save `key`:`value` to the database
Here are specific usage examples:
```log
nsh> setprop name peter # add a key-value pair named name with a value of peter, which disappears when the power is off
nsh> setprop persist.name1 peter1 # add a key-value pair named name1 with a value of peter1, which does not disappear when the power is off
nsh> getprop # view all key-value pairs
name: peter
nsh> setprop name # delete a key-value pair named name
nsh> getprop name
```
### 3. log
1. To enable the `CONFIG_ANDROID_LIBBASE` build option
2. Then we can directly use the standard Android log API in the program to collect and print logs.
### 2 log
```c
#include <log/log.h>
1. Enable `CONFIG_ANDROID_LIBBASE`.
2. Use the standard Android log API to collect and print logs directly in the program.
// the tag for the ALOGI
#define LOG_TAG "MyAppTag"
```c
#include <log/log.h>
int main() {
// print log with custom priority level
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Formatted number: %d", 42);
// the tag for the ALOGI
#define LOG_TAG "MyAppTag"
// Using ALOGI macro to print info level log
ALOGI("ALOGI: A log message from my app.");
return 0;
}
```
int main() {
// print log with custom priority level
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Formatted number: %d", 42);
### 4. trace
// Using ALOGI macro to print info level log
ALOGI("ALOGI: A log message from my app.");
return 0;
}
```
### 3 trace
1. To enable the `CONFIG_SCHED_INSTRUMENTATION_DUMP` and `CONFIG_ATRACE` build options
2. Add the instrumentation point in the program:
```cpp
// define the tag for tracing
#define ATRACE_TAG ATRACE_TAG_ALWAYS
#include <cutils/trace.h>
```cpp
// define the tag for tracing
#define ATRACE_TAG ATRACE_TAG_ALWAYS
#include <cutils/trace.h>
int main(int argc, char *argv[])
{
// instrument the current function
ATRACE_BEGIN("hello_main");
sleep(1);
ATRACE_INSTANT("printf");
printf("hello world!");
// end instrumentation
ATRACE_END();
return 0;
}
```
int main(int argc, char *argv[])
{
// instrument the current function
ATRACE_BEGIN("hello_main");
sleep(1);
ATRACE_INSTANT("printf");
printf("hello world!");
// end instrumentation
ATRACE_END();
return 0;
}
```
3. Show the instrumentation result with `trace dump` tool:
```log
hello-7 [0] 3.187400000: sched_wakeup_new: comm=hello pid=7 target_cpu=0
hello-7 [0] 3.187400000: tracing_mark_write: B|7|hello_main
hello-7 [0] 4.197700000: tracing_mark_write: I|7|printf
hello-7 [0] 4.187700000: tracing_mark_write: E|7|hello_main
```
```log
hello-7 [0] 3.187400000: sched_wakeup_new: comm=hello pid=7 target_cpu=0
hello-7 [0] 3.187400000: tracing_mark_write: B|7|hello_main
hello-7 [0] 4.197700000: tracing_mark_write: I|7|printf
hello-7 [0] 4.187700000: tracing_mark_write: E|7|hello_main
```
In addition, the output result of atrace can also directly use the [perfetto](https://ui.perfetto.dev/) tool to view the timing diagram of the trace in a visual form.
In addition, the output result of atrace can also directly use the [perfetto](https://ui.perfetto.dev/) tool to view the timing diagram of the trace in a visual form.

View File

@ -4,52 +4,48 @@
## 项目概览
当前目录下包含的主要是framework当中提供的一些常用工具实现.
当前目录下包含的主要是 framework 当中提供的一些常用工具实现。
| 工具 | 工具简要描述 |
| -- | -- |
| `gdbus` | 对`D-Bus`接口封装, 方便操作`D-Bus` |
| `kvdb` | 基于本地数据库的`键值对`数据存取接口 |
| `log` | 提供和`Android`平台兼容的`Log API`接口<br>用于在`Vela`当中直接使用`Android` LOG API |
| `log` | 提供和 `Android` 平台兼容的 `Log API` 接口<br>用于在 `openvela` 当中直接使用 Android LOG API |
| `trace` | 提供用于用户空间程序的打点工具 |
## 项目描述
### 1. gdbus
### 1 kvdb
`gdbus`模块是对`D-Bus`接口的进一步封装的API模块. 由于`D-Bus`接口使用比较复杂, 在实际模块使用时, 通过将`D-Bus`接口再次封装, 会方便使用. `gdbus`通过提供更简易操作的API接口方便我们去操作`D-Bus`.
#### 简要介绍
### 2. kvdb
`kvdb` 提供了一套本地数据库的读写接口, `API` 设计参考 `Android``properties` 存取规范, 同时提供了命令行工具以方便本地快速调试。
`openvela` 中的 `kvdb` 支持本地永久化存储以及跨核调用(分别需要 Unix domain socket 和 rpmsg socket 支持), 需要永久存储到文件的键值需要以 `"persist."` 开头。
`kvdb` 底层实现包含了三种机制:
1. 基于开源的 `UnQLite` 数据库, 依赖于数据库。
2. 基于 `MTD CONFIG` (目前仅用于 nor flash)。
3. 最后一种基于 `file` 文件。
#### 2.1 简要介绍
> `kvdb` 接口说明:[frameworks/utils/include/kvdb.h](include/kvdb.h)
`kvdb`提供了一套本地数据库的读写接口, `API`设计参考`Android`的`properties`存取规范, 同时提供了命令行工具以方便本地快速调试.
`Vela`中的`kvdb`支持本地永久化存储以及跨核调用(分别需要Unix domain socket和rpmsg socket支持), 需要永久存储到文件的键值需要以`"persist."`开头.
`kvdb`底层实现包含了三种机制:
1. 基于开源的`UnQLite`数据库, 依赖于数据库;
2. 另外一种是基于`MTD CONFIG` (目前仅用于nor flash);
3. 最后一种基于`file`文件;
#### kvdb 常见配置说明
> `kvdb`一般接口说明: [frameworks/utils/include/kvdb.h](include/kvdb.h)
#### 2.2 `kvdb`的常见配置说明
| kvdb配置 | 说明 |
| kvdb 配置 | 说明 |
| -- | -- |
| CONFIG_KVDB_PRIORITY | KVDB任务优先级, 默认为系统默认值 |
| CONFIG_KVDB_STACKSIZE | KVDB栈空间分配默认为系统默认值 |
| CONFIG_KVDB_SERVER | KVDB SERVER模式. 表示当前CPU是否为读写文件的主CPU, 为n则只调用其他CPU上的KVDB |
| CONFIG_KVDB_DIRECT | KVDB DIRECT模式: 在无需rpmsg socket的场景(无需跨核),可使用此模式<br>CONFIG_KVDB_DIRECT 与 CONFIG_KVDB_SERVER 两种模式只能二选一 |
| CONFIG_KVDB_COMMIT_INTERVAL | KVDB提交间隔 (秒), 默认为5<br>KVDB有内部缓存, 提交后才真正写入文件, 如果提交persist类型的kv后, `CONFIG_KVDB_COMMIT_INTERVAL`时间前就下电, 数据不会真正写入到`persist.db`文件中. `CONFIG_KVDB_COMMIT_INTERVAL`时间设置的越短, `kvdb`将内部缓存写入文件越频繁, 会一定程度上影响系统性能 |
| CONFIG_KVDB_SOURCE_PATH | KVDB默认值加载路径,默认为`"/etc/build.prop"`, 支持多个路径, 用`;`分隔即可. 每次开机启动会自动从该文件加载KV值 |
| CONFIG_KVDB_PRIORITY | KVDB 任务优先级, 默认为系统默认值 |
| CONFIG_KVDB_STACKSIZE | KVDB 栈空间分配,默认为系统默认值 |
| CONFIG_KVDB_SERVER | KVDB SERVER 模式:表示当前 CPU 是否为读写文件的主 CPU, 为 n 则只调用其他 CPU 上的 KVDB |
| CONFIG_KVDB_DIRECT | KVDB DIRECT模式:在无需 rpmsg socket 的场景(无需跨核),可使用此模式<br>CONFIG_KVDB_DIRECT 与 CONFIG_KVDB_SERVER 两种模式只能二选一 |
| CONFIG_KVDB_COMMIT_INTERVAL | KVDB 提交间隔 (秒),默认为 5 <br> KVDB 有内部缓存,提交后才真正写入文件, 如果提交 persist 类型的 kv 后, `CONFIG_KVDB_COMMIT_INTERVAL` 时间前就下电, 数据不会真正写入到 `persist.db` 文件中。 `CONFIG_KVDB_COMMIT_INTERVAL` 时间设置的越短, `kvdb` 将内部缓存写入文件越频繁, 会一定程度上影响系统性能 |
| CONFIG_KVDB_SOURCE_PATH | KVDB 默认值加载路径,默认为 `"/etc/build.prop"`, 支持多个路径, 用 `;` 分隔即可,每次开机启动会自动从该文件加载KV值 |
| CONFIG_KVDB_UNQLITE | 配置使用 unqlite database 存储 kv |
| CONFIG_KVDB_NVS | 配置使用 nvs 存储 kv |
| CONFIG_KVDB_FILE | 配置使用 file 存储 kv |
> `CONFIG_KVDB_UNQLITE`,`CONFIG_KVDB_NVS`, `CONFIG_KVDB_FILE` 三种数据存储的backend只能三选一
### 3. log
> `CONFIG_KVDB_UNQLITE``CONFIG_KVDB_NVS``CONFIG_KVDB_FILE` 三种数据存储的 `backend` 只能三选一。
log模块本身是一个wrapper层,底层将Vela log系统进行了封装,封装成的API是和Android当中的log API一致, 当我们将Android应用或者框架移植到Vela当中, 不需要再提供自己的log对接,直接使用当前模块就可以了.
### 2 log
log 模块本身是一个 wrapper 层,底层将 `openvela log` 系统进行了封装,封装成的 API 是和 Android 当中的 `log API` 一致, 当我们将 `Android` 应用或者框架移植到 `openvela` 当中时, 不需要再提供自己的 `log` 对接,直接使用当前模块就可以了。
以下是log模块的结构:
```log
@ -62,155 +58,94 @@ android log api
vela log impl
```
### 4. trace
### 3 trace
这个模块当中包含的主要是用于用户空间程序的打点工具. 我们可以通过在用户程序当中手动插桩来实现打点分析.
trace当中提供的atrace工具主要是配合Vela系统提供的打点工具来使用的.
这个模块当中包含的主要是用于用户空间程序的打点工具,我们可以通过在用户程序当中手动插桩来实现打点分析,
trace 当中提供的 atrace 工具主要是配合 openvela 系统提供的打点工具来使用的。
## 使用指南
### 1. gdbus
### 1 kvdb
1. 打开`CONFIG_LIB_DBUS`选项
`kvdb` 本身有多种使用形式,我们可以直接在代码当中集成,也可以直接在 `nsh` 当中以命令行程序的方式来使用。
2. 实例化
#### 1.1 直接在代码当中集成的示例
gdbus为接口模块, 需要调用者实例化, 并在调用gdbus接口时, 传入实例化对象.
调用者需要创建一个结构体, 成员至少有`gdbus Connection`和`client`实例对象, 类似如下:
以下是针对 `kvdb` 当中提供的监控 `key/value`变化的接口的 demo针对简单和复杂场景提供了两套 API
```cpp
typedef struct {
DBusConnection* connection;
GDBusClient* client;
GDBusProxy* dbus_proxy[USER_SUPPORT_PROXY_MAX];
bool client_ready;
} dbus_context;
1. 简单场景: 只能监控一个 `key`
dbus_context* ctx = malloc(sizeof(dbus_context));
//创建DbusConnection实例
ctx->connection = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
//设置Connection退出函数否则dbus Connection退出时会同步退出当前进程添加后则不会退出当前进程
g_dbus_set_disconnect_function(ctx->connection, system_dbus_disconnected, callback, NULL);
//设置当前dbus Connection的client名字
dbus_request_name(ctx->connection, client_name, &err);
ctx->client = g_dbus_client_new(ctx->connection, OFONO_SERVICE, OFONO_MANAGER_PATH);
//设置proxy的property的filter函数
//ofono_interface_proxy_added 监听proxy添加按需缓存需要使用的proxy实例供后续操作这个proxy的属性和method
//ofono_interface_proxy_removed 监听proxy删除同步清除缓存的proxy实例
//在object_filter函数中设置哪些proxy不需要读取property属性
//ofono_property_changed 监听proper属性的变化按需缓存对应proxy的proper值。
g_dbus_client_set_proxy_handlers(dbus_client, ofono_interface_proxy_added,
ofono_interface_proxy_removed,
object_filter,
ofono_property_changed, tele);
//设置dbus client连接成功的回调函数on_dbus_client_ready
g_dbus_client_set_ready_watch(ctx->client, on_dbus_client_ready, cbd)
```
3. 退出释放
调用者进程退出时, 需要释放`dbus Connection`实例, 执行如下代码:
```cpp
g_dbus_client_unref(ctx->client);
dbus_connection_close(ctx->connection);
dbus_connection_unref(ctx->connection);
```
4. 调用接口
调用接口, 传入`voice manager proxy`实例, 发起dial请求:
```cpp
g_dbus_proxy_method_call(ctx->dbus_proxy[VOICE_MANAGER], "Dial", dial_setup,
dial_reply, param, dial_destory)
```
### 2. kvdb
`kvdb`本身有多种使用形式,我们可以直接在代码当中集成,也可以直接在`nsh`当中以命令行程序的方式来使用.
#### 2.1 直接在代码当中集成的示例
以下是针对`kvdb`当中提供的监控key/value变化的接口的demo, 针对简单和复杂场景,提供了2套API:
1. 简单场景: 只能监控一个`key`
```cpp
int main(void)
{
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int ret = property_wait("tsetkey", newkey, newvalue, -1);
if (ret < 0)
```cpp
int main(void)
{
printf("property_wait failed, ret=%d\n", ret);
goto out;
}
printf("the new key: %s\n", newkey);
printf("the new value: %s\n", newvalue);
out:
return ret;
}
```
2. 复杂场景: 支持poll用户自由监控多个key
```cpp
int main(void)
{
struct pollfd fds[2];
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int fd1 = property_monitor_open("monitorkey*");
int fd2 = property_monitor_open("testkey");
fds[0].fd = fd1;
fds[0].events = POLLIN;
fds[1].fd = fd2;
fds[1].events = POLLIN;
int ret= poll(fds, 2, -1);
if (ret <= 0)
goto out;
for (int i = 0; i < 2; i++)
{
if ((fds[i].revents & POLLIN) == 0)
continue;
ret = property_monitor_read(fds[i].fd, newkey, newvalue);
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int ret = property_wait("tsetkey", newkey, newvalue, -1);
if (ret < 0)
{
printf("property_wait failed, ret=%d\n", ret);
goto out;
}
printf("the new key: %s\n", newkey);
printf("the new value: %s\n", newvalue);
out:
return ret;
}
```
out:
property_monitor_close(fd1);
property_monitor_close(fd2);
return ret;
}
```
2. 复杂场景: 支持 `poll`,用户自由监控多个 `key`
#### 2.2 在nsh当中以命令行的形式来使用
```cpp
int main(void)
{
struct pollfd fds[2];
char newkey[PROPERTY_KEY_MAX];
char newvalue[PROPERTY_VALUE_MAX];
int fd1 = property_monitor_open("monitorkey*");
int fd2 = property_monitor_open("testkey");
KVDB提供了getprop和setprop两个命令行程序供用户使用用户可以使用getprop和setprop方便地查看已存在的KV或是设置新的KV。
这两个命令行在使能KVDB后默认开启
getprop打印出设置的property
- nsh> getprop列出当前所有props
- nsh> getprop <key>: 打印出<key>对应的prop
fds[0].fd = fd1;
fds[0].events = POLLIN;
fds[1].fd = fd2;
fds[1].events = POLLIN;
int ret= poll(fds, 2, -1);
if (ret <= 0)
goto out;
setprop设置或者删除property
- nsh> setprop <key> : 删除<key>对应的prop
- nsh> setprop <key> <value> : 保存<key>:<value>到数据库
for (int i = 0; i < 2; i++)
{
if ((fds[i].revents & POLLIN) == 0)
continue;
ret = property_monitor_read(fds[i].fd, newkey, newvalue);
if (ret < 0)
goto out;
printf("the new key: %s\n", newkey);
printf("the new value: %s\n", newvalue);
}
out:
property_monitor_close(fd1);
property_monitor_close(fd2);
return ret;
}
```
#### 1.2 在 nsh 当中以命令行的形式来使用
KVDB 提供了 `getprop``setprop` 两个命令行程序供用户使用,用户可以使用 `getprop``setprop` 方便地查看已存在的 KV 或是设置新的 KV。
这两个命令行在使能 KVDB 后默认开启。
- getprop打印出设置的 property
- nsh> getprop列出当前所有`props`
- nsh> getprop `key`:打印出 `key` 对应的`prop`
- setprop设置或者删除 property
- nsh> setprop `key` : 删除 `key` 对应的`prop`
- nsh> setprop `key` `value` :保存 `key`:`value`到数据库
下面是具体的使用示例:
@ -218,64 +153,64 @@ setprop设置或者删除property
nsh> setprop name peter #添加名为name值为peter的键值对 掉电消失
nsh> setprop persist.name1 peter1 #添加名为name1值为peter1的键值对 掉电不消失
nsh> getprop #查看所有键值对
nsh> getprop # 查看所有键值对
name: peter
nsh> setprop name #删除名为name的键值对
nsh> setprop name # 删除名为name的键值对
nsh> getprop name
```
### 3. log
### 2 log
1. 打开`CONFIG_ANDROID_LIBBASE`
2. 然后我们可以在程序当中直接使用标准的android log api来收集打印日志.
1. 打开 `CONFIG_ANDROID_LIBBASE`
2. 在程序当中直接使用标准的android log api来收集打印日志
```cpp
#include <log/log.h>
```cpp
#include <log/log.h>
#define LOG_TAG "MyAppTag"
#define LOG_TAG "MyAppTag"
int main() {
// 自定义优先级打印 log
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Formatted number: %d", 42);
int main() {
// 自定义优先级打印 log
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Formatted number: %d", 42);
// 使用宏打印 INFO 级别 log
ALOGI("ALOGI: A log message from my app.");
return 0;
}
```
// 使用宏打印 INFO 级别 log
ALOGI("ALOGI: A log message from my app.");
return 0;
}
```
### 4. trace
### 3 trace
1. 打开`CONFIG_SCHED_INSTRUMENTATION_DUMP`和`CONFIG_ATRACE`选项
1. 打开 `CONFIG_SCHED_INSTRUMENTATION_DUMP` `CONFIG_ATRACE` 选项
2. 在程序当中需要跟踪的地方添加上打点信息:
```cpp
// 使用是添加头文件必须添加TAG
#define ATRACE_TAG ATRACE_TAG_ALWAYS
#include <cutils/trace.h>
```cpp
// 使用是添加头文件必须添加TAG
#define ATRACE_TAG ATRACE_TAG_ALWAYS
#include <cutils/trace.h>
int main(int argc, char *argv[])
{
// 对当前函数进行插桩
ATRACE_BEGIN("hello_main");
sleep(1);
ATRACE_INSTANT("printf");
printf("hello world!");
// 结束插桩
ATRACE_END();
return 0;
}
```
int main(int argc, char *argv[])
{
// 对当前函数进行插桩
ATRACE_BEGIN("hello_main");
sleep(1);
ATRACE_INSTANT("printf");
printf("hello world!");
// 结束插桩
ATRACE_END();
return 0;
}
```
3. 使用trace dump工具查看打点输出的结果:
3. 使用 `trace dump` 工具查看打点输出的结果:
```log
hello-7 [0] 3.187400000: sched_wakeup_new: comm=hello pid=7 target_cpu=0
hello-7 [0] 3.187400000: tracing_mark_write: B|7|hello_main
hello-7 [0] 4.197700000: tracing_mark_write: I|7|printf
hello-7 [0] 4.187700000: tracing_mark_write: E|7|hello_main
```
```log
hello-7 [0] 3.187400000: sched_wakeup_new: comm=hello pid=7 target_cpu=0
hello-7 [0] 3.187400000: tracing_mark_write: B|7|hello_main
hello-7 [0] 4.197700000: tracing_mark_write: I|7|printf
hello-7 [0] 4.187700000: tracing_mark_write: E|7|hello_main
```
另外就是 atrace 的输出结果也是可以直接使用 [perfetto](https://ui.perfetto.dev/) 工具以可视化的形式来查看 trace 的时序图的.
atrace 的输出结果可以直接使用 [perfetto](https://ui.perfetto.dev/) 工具以可视化的形式来查看 trace 的时序图

File diff suppressed because it is too large Load Diff

View File

@ -1,107 +0,0 @@
/*
* Copyright (c) 2024 Xiaomi Technologies Co., Ltd.
* All rights reserved.
*
* This file is part of the Xiaomi project.
*
* This source code is 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 <uv_ext.h>
#include <dbus/dbus.h>
#include <dbus/dbus-hash.h>
#include "syslog.h"
#include "gdbus.h"
#define error(fmt, ...) \
do { \
syslog(LOG_ERR, fmt, ##__VA_ARGS__); \
} while (0)
#define warning(fmt, ...) \
do { \
syslog(LOG_WARNING, fmt, ##__VA_ARGS__); \
} while (0)
#define info(fmt, ...) \
do { \
syslog(LOG_INFO, fmt, ##__VA_ARGS__); \
} while (0)
#define debug(fmt, ...) \
do { \
syslog(LOG_DEBUG, fmt, ##__VA_ARGS__); \
} while (0)
struct GDBusClient {
int ref_count;
DBusConnection* dbus_conn;
char* service_name;
char* base_path;
char* root_path;
guint watch;
guint added_watch;
guint removed_watch;
struct ptr_array* match_rules;
DBusPendingCall* pending_call;
DBusPendingCall* get_objects_call;
GDBusWatchFunction connect_func;
void* connect_data;
GDBusWatchFunction disconn_func;
gboolean connected;
void* disconn_data;
GDBusMessageFunction signal_func;
void* signal_data;
GDBusProxyFunction proxy_added;
GDBusProxyFunction proxy_removed;
GDBusProxyPropertyFilterFunction proxy_property_filter;
GDBusProxyFilterFunction proxy_filter;
GDBusClientFunction ready;
void* ready_data;
gboolean ready_called;
GDBusPropertyFunction property_changed;
void* user_data;
DBusList* proxy_list;
gboolean standard;
gboolean getting_object_call;
uv_async_queue_t async_queue;
uv_thread_t main_thread;
GDBusWatch *watcher;
};
struct GDBusProxy {
int ref_count;
GDBusClient* client;
char* obj_path;
char* interface;
DBusHashTable* prop_list;
guint watch;
guint watch_non_standard;
GDBusPropertyFunction prop_func;
void* prop_data;
GDBusProxyFunction removed_func;
void* removed_data;
DBusPendingCall* get_all_call;
gboolean pending;
gboolean filter_first;
gboolean getting_all_prop;
};
GDBusWatch* new_dbus_watch(DBusConnection* connection);
void free_dbus_watch(GDBusWatch* watcher);
void dbus_watch_set_connection_state(GDBusWatch* watcher, gboolean closed);
int dbus_polkit_check_authorization(DBusConnection* conn,
const char* action, gboolean allow_interaction,
void (*callback)(dbus_bool_t, void*),
void* user_data, int timeout_ms);

View File

@ -1,964 +0,0 @@
/*
* Copyright (c) 2024 Xiaomi Technologies Co., Ltd.
* All rights reserved.
*
* This file is part of the Xiaomi project.
*
* This source code is 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 __GDBUS_H
#define __GDBUS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <dbus/dbus.h>
typedef void* gpointer;
typedef int gboolean;
typedef unsigned int guint;
typedef uint32_t guint32;
#define g_dbus_setup_bus dbus_setup_bus
#define g_dbus_setup_private dbus_setup_private
#define g_dbus_request_name dbus_request_name
#define g_dbus_set_flags dbus_set_flags
#define g_dbus_get_flags dbus_get_flags
#define g_dbus_register_interface dbus_register_interface
#define g_dbus_unregister_interface dbus_unregister_interface
#define g_dbus_register_security dbus_register_security
#define g_dbus_unregister_security dbus_unregister_security
#define g_dbus_pending_success dbus_pending_success
#define g_dbus_pending_error dbus_pending_error
#define g_dbus_pending_error_valist dbus_pending_error_valist
#define g_dbus_create_error dbus_create_error
#define g_dbus_create_error_valist dbus_create_error_valist
#define g_dbus_create_reply dbus_create_reply
#define g_dbus_create_reply_valist dbus_create_reply_valist
#define g_dbus_send_message dbus_send_message
#define g_dbus_send_message_with_reply dbus_send_message_with_reply
#define g_dbus_send_error dbus_send_error
#define g_dbus_send_error_valist dbus_send_error_valist
#define g_dbus_send_reply dbus_send_reply
#define g_dbus_send_reply_valist dbus_send_reply_valist
#define g_dbus_emit_signal dbus_emit_signal
#define g_dbus_emit_signal_valist dbus_emit_signal_valist
#define g_dbus_pending_property_success dbus_pending_property_success
#define g_dbus_pending_property_error_valist dbus_pending_property_error_valist
#define g_dbus_pending_property_error dbus_pending_property_error
#define g_dbus_emit_property_changed dbus_emit_property_changed
#define g_dbus_emit_property_changed_full dbus_emit_property_changed_full
#define g_dbus_get_properties dbus_get_properties
#define g_dbus_attach_object_manager dbus_attach_object_manager
#define g_dbus_detach_object_manager dbus_detach_object_manager
#define g_dbus_proxy_new dbus_proxy_new
#define g_dbus_proxy_ref dbus_proxy_ref
#define g_dbus_proxy_unref dbus_proxy_unref
#define g_dbus_proxy_get_path dbus_proxy_get_path
#define g_dbus_proxy_get_interface dbus_proxy_get_interface
#define g_dbus_proxy_get_property dbus_proxy_get_property
#define g_dbus_proxy_get_property_basic dbus_proxy_get_property_basic
#define g_dbus_proxy_get_property_iter_cb dbus_proxy_get_property_iter_cb
#define g_dbus_proxy_lookup dbus_proxy_lookup
#define g_dbus_proxy_path_lookup dbus_proxy_path_lookup
#define g_dbus_proxy_refresh_property dbus_proxy_refresh_property
#define g_dbus_proxy_set_property_basic dbus_proxy_set_property_basic
#define g_dbus_proxy_set_property_array dbus_proxy_set_property_array
#define g_dbus_dict_append_entry dbus_dict_append_entry
#define g_dbus_dict_append_basic_array dbus_dict_append_basic_array
#define g_dbus_dict_append_array dbus_dict_append_array
#define g_dbus_proxy_method_call dbus_proxy_method_call
#define g_dbus_proxy_set_property_watch dbus_proxy_set_property_watch
#define g_dbus_proxy_remove_property_watch dbus_proxy_remove_property_watch
#define g_dbus_proxy_set_removed_watch dbus_proxy_set_removed_watch
#define g_dbus_client_new dbus_client_new
#define g_dbus_client_new_full dbus_client_new_full
#define g_dbus_client_ref dbus_client_ref
#define g_dbus_client_unref dbus_client_unref
#define g_dbus_client_set_connect_watch dbus_client_set_connect_watch
#define g_dbus_client_set_disconnect_watch dbus_client_set_disconnect_watch
#define g_dbus_client_set_signal_watch dbus_client_set_signal_watch
#define g_dbus_client_set_ready_watch dbus_client_set_ready_watch
#define g_dbus_client_set_proxy_handlers dbus_client_set_proxy_handlers
#define g_dbus_client_set_proxy_filter dbus_client_set_proxy_filter
typedef struct GDBusArgInfo GDBusArgInfo;
typedef struct GDBusMethodTable GDBusMethodTable;
typedef struct GDBusSignalTable GDBusSignalTable;
typedef struct GDBusPropertyTable GDBusPropertyTable;
typedef struct GDBusSecurityTable GDBusSecurityTable;
typedef void (*GDBusWatchFunction)(DBusConnection* connection,
void* user_data);
typedef void (*GDBusMessageFunction)(DBusConnection* connection,
DBusMessage* message, void* user_data);
typedef gboolean (*GDBusSignalFunction)(DBusConnection* connection,
DBusMessage* message, void* user_data);
typedef void (*GDBusPropIterFunction)(DBusMessageIter* iter, void* value);
/**
* @brief Set and connect to the specified DBus bus type
*
* @param type the type of DBus bus, which can be DBUS_BUS_SESSION or DBUS_BUS_SYSTEM
* @param name The name of the DBus bus to connect to
* @param error A DBusError structure used to store error information
*
* @return If successful, returns a pointer to DBusConnection; if failed, returns NULL
*/
DBusConnection* dbus_setup_bus(DBusBusType type, const char* name, DBusError* error);
/**
* @brief Set up a private DBus connection
*
* This function is used to set up a private DBus connection. It accepts a DBusBusType
* parameter that specifies the type of connection (session or system), a string parameter
* that is the name of the DBus you want to connect to, and a DBusError pointer to store
* any error information that may occur.
* If the function succeeds, it returns a pointer to a DBusConnection, otherwise it returns NULL.
*
* @param type The type of DBus connection, which can be DBUS_BUS_SESSION or DBUS_BUS_SYSTEM
* @param name The name of the DBus you want to connect to
* @param error A DBusError structure used to store error information
* @return Returns a DBusConnection pointer on success, or NULL on failure
*/
DBusConnection* dbus_setup_private(DBusBusType type, const char* name, DBusError* error);
/**
* @brief Requests a specific D-Bus name on the specified DBus connection.
*
* @param connection Pointer to a DBusConnection object representing the connection for
* which the name is to be requested.
* @param name String of the D-Bus name to be requested.
* @param error Pointer to a DBusError object for storing possible errors that may occur
* during the name request.
*
* @return Returns a gboolean value of TRUE if the request succeeds or a gboolean value
* of FALSE if the request fails.
*/
gboolean dbus_request_name(DBusConnection* connection, const char* name, DBusError* error);
typedef void (*GDBusDestroyFunction)(void* user_data);
typedef DBusMessage* (*GDBusMethodFunction)(DBusConnection* connection,
DBusMessage* message, void* user_data);
typedef gboolean (*GDBusPropertyGetter)(const GDBusPropertyTable* property,
DBusMessageIter* iter, void* data);
typedef guint32 GDBusPendingPropertySet;
typedef void (*GDBusPropertySetter)(const GDBusPropertyTable* property,
DBusMessageIter* value, GDBusPendingPropertySet id,
void* data);
typedef gboolean (*GDBusPropertyExists)(const GDBusPropertyTable* property,
void* data);
typedef guint32 GDBusPendingReply;
typedef void (*GDBusSecurityFunction)(DBusConnection* connection,
const char* action,
gboolean interaction,
GDBusPendingReply pending);
enum GDBusFlags {
G_DBUS_FLAG_ENABLE_EXPERIMENTAL = (1 << 0),
};
enum GDBusMethodFlags {
G_DBUS_METHOD_FLAG_DEPRECATED = (1 << 0),
G_DBUS_METHOD_FLAG_NOREPLY = (1 << 1),
G_DBUS_METHOD_FLAG_ASYNC = (1 << 2),
G_DBUS_METHOD_FLAG_EXPERIMENTAL = (1 << 3),
};
enum GDBusSignalFlags {
G_DBUS_SIGNAL_FLAG_DEPRECATED = (1 << 0),
G_DBUS_SIGNAL_FLAG_EXPERIMENTAL = (1 << 1),
};
enum GDBusPropertyFlags {
G_DBUS_PROPERTY_FLAG_DEPRECATED = (1 << 0),
G_DBUS_PROPERTY_FLAG_EXPERIMENTAL = (1 << 1),
};
enum GDBusSecurityFlags {
G_DBUS_SECURITY_FLAG_DEPRECATED = (1 << 0),
G_DBUS_SECURITY_FLAG_BUILTIN = (1 << 1),
G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION = (1 << 2),
};
enum GDbusPropertyChangedFlags {
G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH = (1 << 0),
};
typedef enum GDBusMethodFlags GDBusMethodFlags;
typedef enum GDBusSignalFlags GDBusSignalFlags;
typedef enum GDBusPropertyFlags GDBusPropertyFlags;
typedef enum GDBusSecurityFlags GDBusSecurityFlags;
typedef enum GDbusPropertyChangedFlags GDbusPropertyChangedFlags;
struct GDBusArgInfo {
const char* name;
const char* signature;
};
struct GDBusMethodTable {
const char* name;
GDBusMethodFunction function;
GDBusMethodFlags flags;
unsigned int privilege;
const GDBusArgInfo* in_args;
const GDBusArgInfo* out_args;
};
struct GDBusSignalTable {
const char* name;
GDBusSignalFlags flags;
const GDBusArgInfo* args;
};
struct GDBusPropertyTable {
const char* name;
const char* type;
GDBusPropertyGetter get;
GDBusPropertySetter set;
GDBusPropertyExists exists;
GDBusPropertyFlags flags;
};
struct GDBusSecurityTable {
unsigned int privilege;
const char* action;
GDBusSecurityFlags flags;
GDBusSecurityFunction function;
};
#define GDBUS_ARGS(args...) \
(const GDBusArgInfo[]) \
{ \
args, { } \
}
#define GDBUS_METHOD(_name, _in_args, _out_args, _function) \
.name = _name, \
.in_args = _in_args, \
.out_args = _out_args, \
.function = _function
#define GDBUS_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
.name = _name, \
.in_args = _in_args, \
.out_args = _out_args, \
.function = _function, \
.flags = G_DBUS_METHOD_FLAG_ASYNC
#define GDBUS_DEPRECATED_METHOD(_name, _in_args, _out_args, _function) \
.name = _name, \
.in_args = _in_args, \
.out_args = _out_args, \
.function = _function, \
.flags = G_DBUS_METHOD_FLAG_DEPRECATED
#define GDBUS_DEPRECATED_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
.name = _name, \
.in_args = _in_args, \
.out_args = _out_args, \
.function = _function, \
.flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_DEPRECATED
#define GDBUS_EXPERIMENTAL_METHOD(_name, _in_args, _out_args, _function) \
.name = _name, \
.in_args = _in_args, \
.out_args = _out_args, \
.function = _function, \
.flags = G_DBUS_METHOD_FLAG_EXPERIMENTAL
#define GDBUS_EXPERIMENTAL_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
.name = _name, \
.in_args = _in_args, \
.out_args = _out_args, \
.function = _function, \
.flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_EXPERIMENTAL
#define GDBUS_NOREPLY_METHOD(_name, _in_args, _out_args, _function) \
.name = _name, \
.in_args = _in_args, \
.out_args = _out_args, \
.function = _function, \
.flags = G_DBUS_METHOD_FLAG_NOREPLY
#define GDBUS_SIGNAL(_name, _args) \
.name = _name, \
.args = _args
#define GDBUS_DEPRECATED_SIGNAL(_name, _args) \
.name = _name, \
.args = _args, \
.flags = G_DBUS_SIGNAL_FLAG_DEPRECATED
#define GDBUS_EXPERIMENTAL_SIGNAL(_name, _args) \
.name = _name, \
.args = _args, \
.flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL
void dbus_set_flags(int flags);
int dbus_get_flags(void);
/**
* @brief Register an interface on the specified DBus connection
*
* This function is used to register an interface on the specified DBus connection.
* It requires the following parameters:
* - connection: DBus connection object
* - path: path of DBus interface
* - name: name of DBus interface
* - methods: a GDBusMethodTable object containing methods of interface
* - signals: a GDBusSignalTable object containing signals of interface
* - properties: a GDBusPropertyTable object containing properties of interface
* - user_data: user data, which can be passed to callback function
* - destroy: a GDBusDestroyFunction, which is called when the interface is deregistered
* to clean up user data
*
* @param connection DBus connection object
* @param path path of DBus interface
* @param name name of DBus interface
* @param methods GDBusMethodTable object containing interface methods
* @param signals GDBusSignalTable object containing interface signals
* @param properties GDBusPropertyTable object containing interface properties
* @param user_data user data
* @param destroy GDBusDestroyFunction for cleaning up user data
* @return gboolean Returns TRUE if registration is successful, and FALSE if fails
*/
gboolean dbus_register_interface(DBusConnection* connection,
const char* path, const char* name,
const GDBusMethodTable* methods,
const GDBusSignalTable* signals,
const GDBusPropertyTable* properties,
void* user_data,
GDBusDestroyFunction destroy);
/**
* @brief Unregister the specified interface from the specified DBus connection
*
* @param connection Pointer to DBusConnection, indicating the DBus connection of the
* interface to be unregistered
* @param path Path of the interface
* @param name Name of the interface
* @return If the interface is successfully unregistered, return gboolean TRUE, otherwise
* return FALSE
*/
gboolean dbus_unregister_interface(DBusConnection* connection,
const char* path, const char* name);
gboolean dbus_register_security(const GDBusSecurityTable* security);
gboolean dbus_unregister_security(const GDBusSecurityTable* security);
void dbus_pending_success(DBusConnection* connection,
GDBusPendingReply pending);
void dbus_pending_error(DBusConnection* connection,
GDBusPendingReply pending,
const char* name, const char* format, ...)
__attribute__((format(printf, 4, 5)));
void dbus_pending_error_valist(DBusConnection* connection,
GDBusPendingReply pending, const char* name,
const char* format, va_list args);
DBusMessage* dbus_create_error(DBusMessage* message, const char* name,
const char* format, ...)
__attribute__((format(printf, 3, 4)));
DBusMessage* dbus_create_error_valist(DBusMessage* message, const char* name,
const char* format, va_list args);
DBusMessage* dbus_create_reply(DBusMessage* message, int type, ...);
DBusMessage* dbus_create_reply_valist(DBusMessage* message,
int type, va_list args);
/**
* @brief Send a message to the specified DBus connection
*
* @param connection Pointer to the DBusConnection object, indicating the DBus connection
* to send the message
* @param message Pointer to the DBusMessage object, indicating the message to send
*
* @return If the sending is successful, return the gboolean type with a value of TRUE;
* if the sending fails, return the gboolean type with a value of FALSE
*/
gboolean dbus_send_message(DBusConnection* connection, DBusMessage* message);
/**
* @brief Send a message to the specified DBus connection and wait for a reply,
* non-blocking call
*
* @param connection Pointer to the DBusConnection object, indicating the DBus connection
* @param message Pointer to the DBusMessage object, indicating the message to be sent
* @param call Pointer to the pointer to the DBusPendingCall object, used to store the
* handle of the asynchronous call
* @param timeout Timeout for waiting for a reply after sending a message, in milliseconds
*
* @return If the message is successfully sent and the DBusPendingCall object instance is
* replied, the return value of the gboolean type is TRUE; otherwise, it returns FALSE
*/
gboolean dbus_send_message_with_reply(DBusConnection* connection, DBusMessage* message,
DBusPendingCall** call, int timeout);
gboolean dbus_send_error(DBusConnection* connection, DBusMessage* message,
const char* name, const char* format, ...)
__attribute__((format(printf, 4, 5)));
gboolean dbus_send_error_valist(DBusConnection* connection,
DBusMessage* message, const char* name,
const char* format, va_list args);
gboolean dbus_send_reply(DBusConnection* connection,
DBusMessage* message, int type, ...);
gboolean dbus_send_reply_valist(DBusConnection* connection,
DBusMessage* message, int type, va_list args);
gboolean dbus_emit_signal(DBusConnection* connection,
const char* path, const char* interface,
const char* name, int type, ...);
gboolean dbus_emit_signal_valist(DBusConnection* connection,
const char* path, const char* interface,
const char* name, int type, va_list args);
typedef struct GDBusWatch GDBusWatch;
/**
* Adds a service watch to monitor the specified D-Bus service name
*
* @param watcher The GDBusWatch instance to add the watch to
* @param name The D-Bus service name to watch (e.g. "org.freedesktop.DBus")
* @param connect Callback function when service connects
* @param disconnect Callback function when service disconnects
* @param user_data User data passed to callbacks
* @param destroy Destroy notification callback for user_data
* @return Watch ID that can be used to remove the watch
*/
guint dbus_add_service_watch(GDBusWatch* watcher, const char* name,
GDBusWatchFunction connect, GDBusWatchFunction disconnect,
void* user_data, GDBusDestroyFunction destroy);
/**
* Adds a disconnect watch for the specified D-Bus name
*
* @param watcher The GDBusWatch instance to add the watch to
* @param name The D-Bus name to monitor for disconnection
* @param function Callback function when name disconnects
* @param user_data User data passed to callback
* @param destroy Destroy notification callback for user_data
* @return Watch ID that can be used to remove the watch
*/
guint dbus_add_service_disconnect_watch(GDBusWatch* watcher, const char* name,
GDBusWatchFunction function, void* user_data, GDBusDestroyFunction destroy);
/**
* @brief Add a signal monitor to the DBus connection
*
* @param connection: Pointer to DBusConnection, indicating the DBus connection to which
* the signal monitor is to be added
* @param sender: The name of the DBus client that sends the signal. If it is NULL, the
* signals of all clients are monitored
* @param path: The path of the signal. If it is NULL, the signals of all paths are
* monitored
* @param interface: The interface of the signal. If it is NULL, the signals of all
* interfaces are monitored
* @param member: The member of the signal, that is, the specific name of the signal.
* If it is NULL, the signals of all members are monitored
* @param function: The function called when the signal is received receives the
* following parameters:
* - DBusConnection*: DBus connection
* - const char*: The sender of the signal
* - const char*: The path of the signal
* - const char*: The interface of the signal
* - const char*: The member of the signal
* - void*: User data
* @param user_data: User data, which will be passed to the function when calling the
* function
* @param destroy: The function called when the signal monitor is removed to destroy
* user_data. If it is NULL, no action is performed.
* @return: Returns an unsigned integer representing the ID of the newly created signal
* monitor.
*/
guint dbus_add_signal_watch(GDBusWatch* watcher,
const char* sender, const char* path,
const char* interface, const char* member,
GDBusSignalFunction function, void* user_data,
GDBusDestroyFunction destroy);
guint dbus_add_properties_watch(GDBusWatch* watcher,
const char* sender, const char* path,
const char* interface,
GDBusSignalFunction function, void* user_data,
GDBusDestroyFunction destroy);
/**
* @brief Remove a specific watch from the specified DBus connection
*
* @param connection Pointer to DBusConnection, indicating the connection from which the
* watch is to be removed
* @param tag Indicates the unique identifier of the watch to be removed
*
* @return gboolean The function returns TRUE if executed successfully, otherwise returns
* FALSE
*/
gboolean dbus_remove_watch(GDBusWatch* watcher, guint tag);
void dbus_remove_all_watches(GDBusWatch* watcher);
void dbus_pending_property_success(GDBusPendingPropertySet id);
void dbus_pending_property_error_valist(GDBusPendingReply id,
const char* name, const char* format, va_list args);
void dbus_pending_property_error(GDBusPendingReply id, const char* name,
const char* format, ...);
/*
* Note that when multiple properties for a given object path are changed
* in the same mainloop iteration, they will be grouped with the last
* property changed. If this behaviour is undesired, use
* dbus_emit_property_changed_full() with the
* G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH flag, causing the signal to ignore
* any grouping.
*/
void dbus_emit_property_changed(DBusConnection* connection,
const char* path, const char* interface,
const char* name);
void dbus_emit_property_changed_full(DBusConnection* connection,
const char* path, const char* interface,
const char* name,
GDbusPropertyChangedFlags flags);
gboolean dbus_get_properties(DBusConnection* connection, const char* path,
const char* interface, DBusMessageIter* iter);
gboolean dbus_attach_object_manager(DBusConnection* connection);
gboolean dbus_detach_object_manager(DBusConnection* connection);
typedef struct GDBusClient GDBusClient;
typedef struct GDBusProxy GDBusProxy;
/**
* @brief Create a new D-Bus proxy object
*
* This function is used to create a new D-Bus proxy object.
*
* @param client Pointer to the GDBusClient object, which is an instance of the
* D-Bus client.
* @param path The path of the D-Bus proxy.
* @param interface The name of the interface to be implemented by the D-Bus proxy.
*
* @return Returns a pointer to the GDBusProxy object if it was created successfully,
* otherwise returns NULL.
*/
GDBusProxy* dbus_proxy_new(GDBusClient* client, const char* path,
const char* interface);
/**
* @brief Increase the reference count of a D-Bus proxy
*
* This function increases the reference count of a given D-Bus proxy.
*
* @param proxy Pointer to the D-Bus proxy whose reference count is to be increased.
* @return Returns the pointer to the D-Bus proxy after the reference count is increased.
*/
GDBusProxy* dbus_proxy_ref(GDBusProxy* proxy);
/**
* @brief Decrement the reference count of a D-Bus proxy
*
* This function decrements the reference count of a given D-Bus proxy. If the reference
* count reaches 0, the proxy will be released.
*
* @param proxy Pointer to the D-Bus proxy whose reference count is to be decremented.
*/
void dbus_proxy_unref(GDBusProxy* proxy);
/**
* @brief Get the path of the D-Bus proxy
*
* @param proxy Pointer to GDBusProxy
* @return Return the path of the proxy
*/
const char* dbus_proxy_get_path(const GDBusProxy* proxy);
/**
* @brief Get the interface of the D-Bus proxy
*
* @param proxy Pointer to GDBusProxy
* @return Return the interface of the proxy
*/
const char* dbus_proxy_get_interface(GDBusProxy* proxy);
/**
* @brief Gets a property value from a D-Bus proxy object, should run
* in uv default loop.
*
* @param proxy The D-Bus proxy object to query
* @param name The name of the property to get
* @param iter Pointer to a DBusMessageIter to store the property value
* @return gboolean TRUE if successful, FALSE otherwise
*
* This function synchronously gets a property value from a D-Bus proxy object
* and stores it in the provided DBusMessageIter. The caller is responsible
* for properly handling the DBusMessageIter contents.
*/
gboolean dbus_proxy_get_property(GDBusProxy* proxy, const char* name,
DBusMessageIter* iter);
/**
* @brief Gets a basic property value from a D-Bus proxy object (thread-safe)
*
* @param proxy The D-Bus proxy object to query
* @param name The name of the property to get
* @param value Pointer to store the property value (must match property type)
* @return gboolean TRUE if successful, FALSE otherwise
*
* This function synchronously gets a basic type property value from a D-Bus
* proxy object in a thread-safe manner. For complex struct properties,
* please use dbus_proxy_get_property_iter_cb instead. The value parameter
* must point to storage of the correct type for the property being retrieved.
*/
gboolean dbus_proxy_get_property_basic(GDBusProxy* proxy, const char* name,
void* value);
/**
* Asynchronously gets a D-Bus proxy property with thread safety
*
* @param proxy The D-Bus proxy object to query
* @param name Name of the property to retrieve
* @param value Pointer to store the property value
* @param iter_cb Callback function to handle property iteration
* @return TRUE if property was successfully retrieved, FALSE on error
*
* @note This function handles thread synchronization automatically.
* It can be called from any thread but will block if not in default loop.
*/
gboolean dbus_proxy_get_property_iter_cb(GDBusProxy* proxy, const char* name,
void* value, GDBusPropIterFunction iter_cb);
GDBusProxy* dbus_proxy_lookup(void* list, int* index, const char* path,
const char* interface);
char* dbus_proxy_path_lookup(void* list, int* index, const char* path);
gboolean dbus_proxy_refresh_property(GDBusProxy* proxy, const char* name);
typedef void (*GDBusResultFunction)(const DBusError* error, void* user_data);
/**
* @brief This function is used to set the properties of a D-Bus proxy.
*
* @param proxy Pointer to GDBusProxy, indicating the proxy to set the properties.
* @param name The name of the property, which should be a string type.
* @param type The type of the property, which should be an integer, indicating the data
* type of the property.
* @param value Pointer to the value of the property, which should be a void type,
* indicating the value of the property.
* @param function Pointer to GDBusResultFunction, indicating the function to be executed
* after setting the property.
* @param user_data Pointer to user data, which will be passed when executing
* the @param function function.
* @param destroy Pointer to GDBusDestroyFunction, indicating how to destroy the data
* pointed to by value when the set property is no longer needed.
*
* @return Returns a true value of type gboolean if the property is successfully set;
* otherwise, returns a false value.
*/
gboolean dbus_proxy_set_property_basic(GDBusProxy* proxy,
const char* name, int type, const void* value,
GDBusResultFunction function, void* user_data,
GDBusDestroyFunction destroy);
gboolean dbus_proxy_set_property_array(GDBusProxy* proxy,
const char* name, int type, const void* value,
size_t size, GDBusResultFunction function,
void* user_data, GDBusDestroyFunction destroy);
void dbus_dict_append_entry(DBusMessageIter* dict,
const char* key, int type, void* val);
void dbus_dict_append_basic_array(DBusMessageIter* dict, int key_type,
const void* key, int type, void* val,
int n_elements);
void dbus_dict_append_array(DBusMessageIter* dict,
const char* key, int type, void* val,
int n_elements);
typedef void (*GDBusSetupFunction)(DBusMessageIter* iter, void* user_data);
typedef void (*GDBusReturnFunction)(DBusMessage* message, void* user_data);
/**
* @brief Calls the specified @method method on the given D-Bus proxy
*
* @param proxy Pointer to GDBusProxy, indicating the D-Bus proxy to be called
* @param method The name of the method to be called
* @param setup A GDBusSetupFunction, used to set the parameters of the method call
* @param function A GDBusReturnFunction, called after the method call succeeds,
* returns the return value of the method
* @param user_data User data, passed to GDBusReturnFunction
* @param destroy A GDBusDestroyFunction, called after the method call is completed,
* used to clean up resources
*
* @return Returns gboolean if the method call succeeds, otherwise returns gboolean
*/
gboolean dbus_proxy_method_call(GDBusProxy* proxy, const char* method,
GDBusSetupFunction setup,
GDBusReturnFunction function, void* user_data,
GDBusDestroyFunction destroy);
typedef void (*GDBusClientFunction)(GDBusClient* client, void* user_data);
typedef void (*GDBusProxyFunction)(GDBusProxy* proxy, void* user_data);
typedef gboolean (*GDBusProxyPropertyFilterFunction)(GDBusProxy* proxy, void* user_data);
typedef void (*GDBusPropertyFunction)(GDBusProxy* proxy, const char* name,
DBusMessageIter* iter, void* user_data);
typedef gboolean (*GDBusProxyFilterFunction)(const char* path,
const char* interface, void* user_data);
/**
* @brief Sets a property monitor for the D-Bus proxy.
*
* @param proxy the GDBusProxy object which the property monitor is to be set.
* @param function Pointer to the callback function that handles property changes.
* @param user_data User data, which will be passed to the callback function.
* @return Returns TRUE if the monitor was successfully set, otherwise returns FALSE.
*/
gboolean dbus_proxy_set_property_watch(GDBusProxy* proxy,
GDBusPropertyFunction function, void* user_data);
/**
* @brief Removes a property monitor from a D-Bus proxy.
*
* @param proxy the GDBusProxy object whose property monitor is to be removed.
* @param destroy Pointer to a destruction function that handles user data.
* @return Returns TRUE if the monitor was successfully removed, otherwise returns FALSE.
*/
gboolean dbus_proxy_remove_property_watch(GDBusProxy* proxy,
GDBusDestroyFunction destroy);
gboolean dbus_proxy_set_removed_watch(GDBusProxy* proxy,
GDBusProxyFunction destroy, void* user_data);
/**
* @brief Create a new DBus client instance
*
* This function is used to create a new DBus client instance.
*
* @param connection Pointer to DBus connection.
* @param service Service name, used to identify DBus service.
* @param path Path, used to identify the path of DBus object.
*
* @return Returns a pointer to the newly created GDBusClient instance.
*/
GDBusClient* dbus_client_new(DBusConnection* connection,
const char* service, const char* path);
GDBusClient* dbus_client_new_full(DBusConnection* connection,
const char* service,
const char* path,
const char* root_path);
/**
* @brief Increase the reference count of the GDBusClient object.
*
* @param client The GDBusClient object whose reference count is to be increased.
* @return The GDBusClient object after the reference count is increased.
*/
GDBusClient* dbus_client_ref(GDBusClient* client);
/**
* @brief Decrement the reference count of a GDBusClient object.
*
* @param client The GDBusClient object whose reference count is to be decremented.
*/
void dbus_client_unref(GDBusClient* client);
/**
* @brief Set the connection monitoring function of the D-Bus client.
*
* @param client Pointer to the GDBusClient instance.
* @param function Pointer to the function of type GDBusWatchFunction, which will be
* called when there is a new D-Bus connection.
* @param user_data caller data, which will be passed to the caller when callback
* @return If the setting is successful, return a true value of type gboolean; otherwise,
* return a false value.
*/
gboolean dbus_client_set_connect_watch(GDBusClient* client, GDBusWatchFunction function,
void* user_data);
/**
* @brief Set the disconnection monitoring function of the D-Bus client.
*
* @param client Pointer to the GDBusClient instance.
* @param function Pointer to the function of type GDBusWatchFunction, which will be
* called when the D-Bus connection is disconnected.
* @param user_data caller data will be passed to the caller when calling the function.
* @return If the setting is successful, return a true value of type gboolean; otherwise,
* return a false value.
*/
gboolean dbus_client_set_disconnect_watch(GDBusClient* client,
GDBusWatchFunction function, void* user_data);
/**
* @brief Set the signal monitoring function of the D-Bus client
*
* This function is used to set the signal monitoring function of the D-Bus client.
* When the client receives a D-Bus signal, the function will be called.
*
* @param client Pointer to the D-Bus client
* @param function Points to the function that processes the D-Bus signal
* @param user_data caller data will be passed to the caller when calling the function
*
* @return If the setting is successful, return gboolean as TRUE, otherwise return FALSE
*/
gboolean dbus_client_set_signal_watch(GDBusClient* client,
GDBusMessageFunction function, void* user_data);
/**
* @brief Set the preparation function and user data of the DBus client
*
* This function is used to set the preparation function and user data of the DBus client.
* The preparation function will be called when the DBus client is ready, and the user
* data can be passed to this function.
*
* @param client Pointer to the DBus client
* @param ready Preparation function, which will be called when the DBus client is ready
* @param user_data User data, which can be passed to the preparation function
*
* @return gboolean If the setting is successful, it returns TRUE, otherwise it returns FALSE
*/
gboolean dbus_client_set_ready_watch(GDBusClient* client,
GDBusClientFunction ready, void* user_data);
/**
* @brief Set the proxy handler function
*
* This function is used to set the proxy handler function of the D-Bus client.
*
* @param client Pointer to the GDBusClient instance.
* @param proxy_added Callback function when the proxy is added.
* @param proxy_removed Callback function when the proxy is removed.
* @param proxy_property_filter Callback function for proxy property filtering.
* @param property_changed Callback function when the property is changed.
* @param user_data caller data, which will be used in the callback function.
* @return If the setting is successful, the return gboolean is TRUE, otherwise
* it returns FALSE.
*/
gboolean dbus_client_set_proxy_handlers(GDBusClient* client,
GDBusProxyFunction proxy_added,
GDBusProxyFunction proxy_removed,
GDBusProxyPropertyFilterFunction proxy_property_filter,
GDBusPropertyFunction property_changed,
void* user_data);
/**
* @brief Set the proxy filter function
*
* This function is used to set the proxy filter function of the D-Bus client.
*
* @param client Pointer to the GDBusClient instance.
* @param proxy_filter Callback function of the proxy filter.
* @param user_data caller data, which will be used in the callback function.
* @return If the setting is successful, the return gboolean is TRUE, otherwise
* it returns FALSE.
*/
gboolean dbus_client_set_proxy_filter(GDBusClient* client,
GDBusProxyFilterFunction proxy_filter,
void* user_data);
/**
* Adds a service watch for the specified name.
* @param client The DBus client instance
* @param name The service name to watch
* @param connect Callback when service connects
* @param disconnect Callback when service disconnects
* @param user_data User data passed to callbacks
* @param destroy Destroy notification callback
* @return Watch ID
*/
guint dbus_client_add_service_watch(GDBusClient* client, const char* name,
GDBusWatchFunction connect, GDBusWatchFunction disconnect,
void* user_data, GDBusDestroyFunction destroy);
/**
* Adds a watch for service disconnection only.
* @param client The DBus client instance
* @param name The service name to watch
* @param function Callback when service disconnects
* @param user_data User data passed to callback
* @param destroy Destroy notification callback
* @return Watch ID
*/
guint dbus_client_add_service_disconnect_watch(GDBusClient* client, const char* name,
GDBusWatchFunction function, void* user_data, GDBusDestroyFunction destroy);
/**
* Adds a signal watch with detailed matching criteria.
* @param client The DBus client instance
* @param sender The sender name to match
* @param path The object path to match
* @param interface The interface name to match
* @param member The member name to match
* @param function Callback when signal is received
* @param user_data User data passed to callback
* @param destroy Destroy notification callback
* @return Watch ID
*/
guint dbus_client_add_signal_watch(GDBusClient* client,const char* sender,
const char* path, const char* interface, const char* member,
GDBusSignalFunction function, void* user_data, GDBusDestroyFunction destroy);
/**
* Adds a properties change watch.
* @param client The DBus client instance
* @param sender The sender name to match
* @param path The object path to match
* @param interface The interface name to match
* @param function Callback when properties change
* @param user_data User data passed to callback
* @param destroy Destroy notification callback
* @return Watch ID
*/
guint dbus_client_add_properties_watch(GDBusClient* client,
const char* sender, const char* path, const char* interface,
GDBusSignalFunction function, void* user_data, GDBusDestroyFunction destroy);
/**
* Removes a previously added watch.
* @param client The DBus client instance
* @param tag The watch ID to remove
* @return TRUE if watch was found and removed
*/
gboolean dbus_client_remove_watch(GDBusClient* client, guint tag);
/**
* Removes all watches from the client.
* @param client The DBus client instance
*/
void dbus_client_remove_all_watches(GDBusClient* client);
/**
* Adds a watch for client disconnection.
* @param client The DBus client instance
* @param function Callback when client disconnects
* @param user_data User data passed to callback
* @param destroy Destroy notification callback
* @return Watch ID
*/
gboolean dbus_client_add_disconnect_watch(GDBusClient* client,
GDBusWatchFunction function, void* user_data, DBusFreeFunction destroy);
#ifdef __cplusplus
}
#endif
#endif /* __GDBUS_H */

View File

@ -1,512 +0,0 @@
/*
* Copyright (c) 2024 Xiaomi Technologies Co., Ltd.
* All rights reserved.
*
* This file is part of the Xiaomi project.
*
* This source code is 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 <dbus/dbus.h>
#include <poll.h>
#include <stdlib.h>
#include <uv.h>
#include "gdbus-internal.h"
struct idle_handler {
uv_idle_t handle;
DBusConnection* conn;
};
struct timeout_handler {
uv_timer_t handle;
DBusTimeout* timeout;
};
struct dbus_watch_info {
uv_poll_t* handle;
DBusWatch* read_watch;
DBusWatch* write_watch;
DBusConnection* conn;
};
static void close_cb(uv_handle_t* handle)
{
free(handle->data);
}
static void message_dispatch(uv_idle_t* handle)
{
struct idle_handler* handler = handle->data;
DBusConnection* conn = handler->conn;
/* Dispatch messages */
while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS)
;
dbus_connection_unref(conn);
uv_close((uv_handle_t*)handle, close_cb);
}
static inline void queue_dispatch(DBusConnection* conn,
DBusDispatchStatus status)
{
if (status == DBUS_DISPATCH_DATA_REMAINS) {
struct idle_handler* handler;
handler = calloc(1, sizeof(struct idle_handler));
if (handler == NULL) {
return;
}
if (uv_idle_init(uv_default_loop(), &handler->handle) != 0) {
free(handler);
return;
}
handler->conn = dbus_connection_ref(conn);
handler->handle.data = handler;
if (uv_idle_start(&handler->handle, message_dispatch) != 0) {
dbus_connection_unref(conn);
uv_close((uv_handle_t*)&handler->handle, close_cb);
free(handler);
}
}
}
static void watch_func(uv_poll_t* handle, int state, int events)
{
struct dbus_watch_info* info = handle->data;
unsigned int flags = 0;
DBusDispatchStatus status;
DBusConnection* conn;
if (events & UV_READABLE)
flags |= DBUS_WATCH_READABLE;
if (events & UV_WRITABLE)
flags |= DBUS_WATCH_WRITABLE;
if (events & UV_DISCONNECT)
flags |= DBUS_WATCH_HANGUP;
if (events & POLLERR)
flags |= DBUS_WATCH_ERROR;
/* Protect connection from being destroyed by dbus_watch_handle */
conn = dbus_connection_ref(info->conn);
if (flags & DBUS_WATCH_READABLE && info->read_watch != NULL)
dbus_watch_handle(info->read_watch, flags);
if (flags & DBUS_WATCH_WRITABLE && info->write_watch != NULL)
dbus_watch_handle(info->write_watch, flags);
status = dbus_connection_get_dispatch_status(conn);
queue_dispatch(conn, status);
dbus_connection_unref(conn);
}
static void close_watch_info_handler_cb(uv_handle_t* handle)
{
struct dbus_watch_info* info = handle->data;
if (info == NULL)
return;
if (info->read_watch) {
dbus_watch_set_data(info->read_watch, NULL, NULL);
info->read_watch = NULL;
}
if (info->write_watch) {
dbus_watch_set_data(info->write_watch, NULL, NULL);
info->write_watch = NULL;
}
free(info->handle);
info->handle = NULL;
}
static void watch_info_free_read(void* data)
{
struct dbus_watch_info* info = data;
if (info != NULL && info->read_watch != NULL) {
info->read_watch = NULL;
/**
* libdbus maybe call read watch free cb, not from remove watch.
* need close uv hander when read and watch both null.
*/
if (info->write_watch == NULL && info->handle != NULL)
uv_close((uv_handle_t*)info->handle, close_watch_info_handler_cb);
}
}
static void watch_info_free_write(void* data)
{
struct dbus_watch_info* info = data;
if (info != NULL && info->write_watch != NULL) {
info->write_watch = NULL;
/**
* libdbus maybe call write watch free cb, not from remove watch.
* need close uv hander when read and watch both null.
*/
if (info->read_watch == NULL && info->handle != NULL)
uv_close((uv_handle_t*)info->handle, close_watch_info_handler_cb);
}
}
static dbus_bool_t add_watch(DBusWatch* watch, void* data)
{
struct dbus_watch_info* watch_info = data;
int cond = UV_DISCONNECT;
int flags = 0;
if (!dbus_watch_get_enabled(watch))
return TRUE;
flags = dbus_watch_get_flags(watch);
if (flags & DBUS_WATCH_READABLE) {
dbus_watch_set_data(watch, watch_info, watch_info_free_read);
watch_info->read_watch = watch;
}
if (flags & DBUS_WATCH_WRITABLE) {
dbus_watch_set_data(watch, watch_info, watch_info_free_write);
watch_info->write_watch = watch;
}
if (watch_info->read_watch != NULL && watch != watch_info->read_watch)
flags |= dbus_watch_get_flags(watch_info->read_watch);
if (watch_info->write_watch != NULL && watch != watch_info->write_watch)
flags |= dbus_watch_get_flags(watch_info->write_watch);
if (flags & DBUS_WATCH_READABLE)
cond |= UV_READABLE;
if (flags & DBUS_WATCH_WRITABLE)
cond |= UV_WRITABLE;
if (!watch_info->handle) {
watch_info->handle = calloc(1, sizeof(uv_poll_t));
if (!watch_info->handle)
return FALSE;
int fd = dbus_watch_get_unix_fd(watch);
if (uv_poll_init(uv_default_loop(), watch_info->handle, fd) != 0) {
free(watch_info->handle);
watch_info->handle = NULL;
dbus_watch_set_data(watch, NULL, NULL);
return FALSE;
}
watch_info->handle->data = watch_info;
}
if (uv_poll_start(watch_info->handle, cond, watch_func) != 0) {
uv_close((uv_handle_t*)watch_info->handle, close_watch_info_handler_cb);
return FALSE;
}
return TRUE;
}
static void remove_watch(DBusWatch* watch, void* data)
{
int flags = 0;
int cond = 0;
struct dbus_watch_info* info = data;
/* If the watch is still enabled, we treat this as a toggle */
if (dbus_watch_get_enabled(watch))
return;
if (info->read_watch == watch && info->write_watch != NULL) {
/* remove watch is read, keep write flag if write watch is valid */
flags = dbus_watch_get_flags(info->write_watch);
} else if (info->write_watch == watch && info->read_watch != NULL) {
/* remove watch is write, keep read flag if read watch is valid */
flags = dbus_watch_get_flags(info->read_watch);
}
if (flags & DBUS_WATCH_READABLE)
cond |= UV_READABLE;
if (flags & DBUS_WATCH_WRITABLE)
cond |= UV_WRITABLE;
if (cond != 0) {
cond |= UV_DISCONNECT;
if (uv_poll_start(info->handle, cond, watch_func) != 0) {
uv_close((uv_handle_t*)info->handle, close_watch_info_handler_cb);
return;
}
}
/* will trigger watch_info_free_read/write() */
dbus_watch_set_data(watch, NULL, NULL);
}
static void watch_toggled(DBusWatch* watch, void* data)
{
/* Because we just exit on OOM, enable/disable is
* no different from add/remove */
if (dbus_watch_get_enabled(watch))
add_watch(watch, data);
else
remove_watch(watch, data);
}
static void timeout_handler_dispatch(uv_timer_t* handle)
{
struct timeout_handler* handler = handle->data;
/* if not enabled should not be polled by the main loop */
if (dbus_timeout_get_enabled(handler->timeout))
dbus_timeout_handle(handler->timeout);
}
static void timeout_handler_free(void* data)
{
struct timeout_handler* handler = data;
uv_close((uv_handle_t*)&handler->handle, close_cb);
}
static dbus_bool_t add_timeout(DBusTimeout* timeout, void* data)
{
int interval = dbus_timeout_get_interval(timeout);
struct timeout_handler* handler;
if (!dbus_timeout_get_enabled(timeout))
return TRUE;
handler = calloc(1, sizeof(struct timeout_handler));
if (handler == NULL)
return FALSE;
handler->timeout = timeout;
dbus_timeout_set_data(timeout, handler, timeout_handler_free);
if (uv_timer_init(uv_default_loop(), &handler->handle) != 0) {
goto errout;
}
handler->handle.data = handler;
if (uv_timer_start(&handler->handle, timeout_handler_dispatch, interval, 0) != 0) {
uv_close((uv_handle_t*)&handler->handle, close_cb);
goto errout;
}
return TRUE;
errout:
free(handler);
dbus_timeout_set_data(timeout, NULL, NULL);
return FALSE;
}
static void remove_timeout(DBusTimeout* timeout, void* data)
{
/* will trigger timeout_handler_free() */
dbus_timeout_set_data(timeout, NULL, NULL);
}
static void timeout_toggled(DBusTimeout* timeout, void* data)
{
if (dbus_timeout_get_enabled(timeout))
add_timeout(timeout, data);
else
remove_timeout(timeout, data);
}
static void dispatch_status(DBusConnection* conn,
DBusDispatchStatus status, void* data)
{
if (!dbus_connection_get_is_connected(conn))
return;
queue_dispatch(conn, status);
}
static void dbus_watch_info_free(void* data)
{
struct dbus_watch_info* info = data;
if (info != NULL) {
dbus_connection_unref(info->conn);
free(info);
}
}
static inline void setup_dbus_with_main_loop(DBusConnection* conn)
{
struct dbus_watch_info* info = calloc(1, sizeof(struct dbus_watch_info));
if (info == NULL)
return;
info->conn = dbus_connection_ref(conn);
dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
watch_toggled, info, dbus_watch_info_free);
dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
timeout_toggled, NULL, NULL);
dbus_connection_set_dispatch_status_function(conn, dispatch_status,
NULL, NULL);
}
static gboolean setup_bus(DBusConnection* conn, const char* name,
DBusError* error)
{
gboolean result;
DBusDispatchStatus status;
if (name != NULL) {
result = dbus_request_name(conn, name, error);
if (error != NULL) {
if (dbus_error_is_set(error) == TRUE)
return FALSE;
}
if (result == FALSE)
return FALSE;
}
setup_dbus_with_main_loop(conn);
status = dbus_connection_get_dispatch_status(conn);
queue_dispatch(conn, status);
return TRUE;
}
DBusConnection* dbus_setup_bus(DBusBusType type, const char* name,
DBusError* error)
{
DBusConnection* conn;
conn = dbus_bus_get(type, error);
if (error != NULL) {
if (dbus_error_is_set(error) == TRUE)
return NULL;
}
if (conn == NULL)
return NULL;
if (setup_bus(conn, name, error) == FALSE) {
dbus_connection_unref(conn);
return NULL;
}
return conn;
}
DBusConnection* dbus_setup_private(DBusBusType type, const char* name,
DBusError* error)
{
DBusConnection* conn;
conn = dbus_bus_get_private(type, error);
if (error != NULL) {
if (dbus_error_is_set(error) == TRUE)
return NULL;
}
if (conn == NULL)
return NULL;
if (setup_bus(conn, name, error) == FALSE) {
dbus_connection_close(conn);
dbus_connection_unref(conn);
return NULL;
}
return conn;
}
gboolean dbus_request_name(DBusConnection* connection, const char* name,
DBusError* error)
{
int result;
result = dbus_bus_request_name(connection, name,
DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
if (error != NULL) {
if (dbus_error_is_set(error) == TRUE)
return FALSE;
}
if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
if (error != NULL)
dbus_set_error(error, name, "Name already in use");
return FALSE;
}
return TRUE;
}
struct disconnect_data {
GDBusWatchFunction function;
void* user_data;
GDBusWatch* watcher;
};
static gboolean disconnected_signal(DBusConnection* conn,
DBusMessage* msg, void* data)
{
struct disconnect_data* dc_data = data;
info("Got disconnected from the system message bus");
dc_data->function(conn, dc_data->user_data);
dbus_connection_unref(conn);
dbus_watch_set_connection_state(dc_data->watcher, TRUE);
return FALSE;
}
gboolean dbus_client_add_disconnect_watch(GDBusClient* client,
GDBusWatchFunction function, void* user_data, DBusFreeFunction destroy)
{
struct disconnect_data* dc_data;
dbus_connection_set_exit_on_disconnect(client->dbus_conn, FALSE);
dc_data = calloc(1, sizeof(struct disconnect_data));
if (dc_data == NULL)
return FALSE;
dc_data->function = function;
dc_data->user_data = user_data;
dc_data->watcher = client->watcher;
if (dbus_add_signal_watch(client->watcher, NULL, NULL,
DBUS_INTERFACE_LOCAL, "Disconnected",
disconnected_signal, dc_data, free)
== 0) {
error("Failed to add watch for D-Bus Disconnected signal");
free(dc_data);
return FALSE;
}
dbus_connection_ref(client->dbus_conn);
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,226 +0,0 @@
/*
* Copyright (C) 2025 Xiaomi Corporation
*
* 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 <errno.h>
#include <stdlib.h>
#include <dbus/dbus.h>
#include "gdbus-internal.h"
#define POLICY_KIT_DBUS_NAME "org.freedesktop.PolicyKit1"
#define POLICY_KIT_INTERFACE "org.freedesktop.PolicyKit1.Authority"
#define POLICY_KIT_PATH "/org/freedesktop/PolicyKit1/Authority"
#define POLICY_KIT_ACTION "org.freedesktop.policykit.exec"
typedef enum polkit_interaction_flag {
POLKIT_FLAG_NONE = 0x00000000,
POLKIT_FLAG_ALLOW = 0x00000001
} polkit_interaction_flag;
typedef struct authorization_context {
void (*callback)(dbus_bool_t authorized, void* user_data);
void* user_data;
} authorization_context;
typedef struct dict_entry_builder {
DBusMessageIter iter;
const char* key;
const char* value;
} dict_entry_builder;
typedef enum contained_sig_type {
SIG_TYPE_EMPTY,
SIG_TYPE_VARIANT,
} contained_sig_type;
static const char* init_contained_signature_type(contained_sig_type type)
{
switch (type) {
case SIG_TYPE_EMPTY:
return DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
case SIG_TYPE_VARIANT:
return DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
default:
return NULL;
}
}
static void build_dict_entry(dict_entry_builder* builder)
{
DBusMessageIter dict, entry, variant;
dbus_message_iter_open_container(&builder->iter, DBUS_TYPE_ARRAY,
init_contained_signature_type(SIG_TYPE_VARIANT), &dict);
dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &builder->key);
dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
DBUS_TYPE_STRING_AS_STRING, &variant);
dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &builder->value);
dbus_message_iter_close_container(&entry, &variant);
dbus_message_iter_close_container(&dict, &entry);
dbus_message_iter_close_container(&builder->iter, &dict);
}
static void build_empty_dict(DBusMessageIter* iter)
{
DBusMessageIter dict;
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
init_contained_signature_type(SIG_TYPE_EMPTY), &dict);
dbus_message_iter_close_container(iter, &dict);
}
static void build_authorization_arguments(DBusConnection* conn, DBusMessageIter* iter,
const char* action, polkit_interaction_flag flags)
{
const char* bus_name = dbus_bus_get_unique_name(conn);
const char* subject_kind = "system-bus-name";
const char* cancellation_id = "";
DBusMessageIter subject;
// build main subject
dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &subject);
dbus_message_iter_append_basic(&subject, DBUS_TYPE_STRING, &subject_kind);
dict_entry_builder builder = {
.iter = subject,
.key = "name",
.value = bus_name
};
build_dict_entry(&builder);
dbus_message_iter_close_container(iter, &subject);
// add less parameters
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
action ? action : POLICY_KIT_ACTION);
build_empty_dict(iter);
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &flags);
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cancellation_id);
}
static dbus_bool_t parse_authorization_result(DBusMessageIter* iter)
{
DBusMessageIter recurse_iter;
dbus_bool_t auth = FALSE;
if (!iter)
return FALSE;
dbus_message_iter_recurse(iter, &recurse_iter);
dbus_message_iter_get_basic(&recurse_iter, &auth);
return auth;
}
static void handle_authorization_reply(DBusPendingCall* call, void* user_data)
{
authorization_context* context = user_data;
DBusMessage* reply = NULL;
DBusMessageIter iter;
dbus_bool_t authorized = FALSE;
if (!call || !context)
goto cleanup;
reply = dbus_pending_call_steal_reply(call);
if (!reply)
goto cleanup;
if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
error("Authorization error: %s\n", dbus_message_get_error_name(reply));
goto cleanup;
}
if (!dbus_message_has_signature(reply, "(bba{ss})")) {
error("Invalid reply signature\n");
goto cleanup;
}
if (!dbus_message_iter_init(reply, &iter))
goto cleanup;
authorized = parse_authorization_result(&iter);
cleanup:
if (context != NULL && context->callback) {
context->callback(authorized, context->user_data);
}
if (reply)
dbus_message_unref(reply);
dbus_pending_call_unref(call);
}
int dbus_polkit_check_authorization(DBusConnection* conn,
const char* action, gboolean allow_interaction,
void (*callback)(dbus_bool_t, void*),
void* user_data, int timeout_ms)
{
DBusMessage* msg;
DBusMessageIter iter;
DBusPendingCall* pending_call = NULL;
polkit_interaction_flag flags;
if (!conn)
return -EINVAL;
authorization_context* context = calloc(1, sizeof(authorization_context));
if (!context)
return -ENOMEM;
msg = dbus_message_new_method_call(POLICY_KIT_DBUS_NAME, POLICY_KIT_PATH,
POLICY_KIT_INTERFACE, "CheckAuthorization");
if (!msg) {
free(context);
return -ENOMEM;
}
flags = allow_interaction ? POLKIT_FLAG_ALLOW : POLKIT_FLAG_NONE;
dbus_message_iter_init_append(msg, &iter);
build_authorization_arguments(conn, &iter, action, flags);
if (!dbus_connection_send_with_reply(conn, msg, &pending_call, timeout_ms)) {
dbus_message_unref(msg);
free(context);
return -EIO;
}
if (!pending_call) {
dbus_message_unref(msg);
free(context);
return -EIO;
}
context->callback = callback;
context->user_data = user_data;
dbus_pending_call_set_notify(pending_call, handle_authorization_reply,
context, free);
dbus_message_unref(msg);
return 0;
}

View File

@ -1,995 +0,0 @@
/*
* Copyright (C) 2025 Xiaomi Corporation
*
* 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 <execinfo.h>
#include <stdio.h>
#include <string.h>
#include <dbus/dbus-list.h>
#include <dbus/dbus.h>
#include <uv.h>
#include "gdbus-internal.h"
static DBusHandlerResult message_filter(DBusConnection* connection,
DBusMessage* message, void* user_data);
struct GDBusWatch {
DBusConnection* conn;
guint serial;
DBusList* list;
gboolean conn_closed;
};
struct service_data {
DBusConnection* conn;
DBusPendingCall* call;
char* name;
const char* owner;
struct filter_callback* callback;
uv_idle_t handle;
};
struct filter_callback {
GDBusWatchFunction conn_func;
GDBusWatchFunction disc_func;
GDBusSignalFunction signal_func;
GDBusDestroyFunction destroy_func;
struct service_data* data;
void* user_data;
guint id;
};
struct filter_data {
DBusConnection* connection;
DBusHandleMessageFunction handle_func;
char* name;
char* owner;
char* path;
char* interface;
char* member;
char* argument;
DBusList* callbacks;
DBusList* processed;
guint name_watch;
gboolean lock;
gboolean registered;
GDBusWatch* watcher;
};
static int strcmp0(const char* str1, const char* str2)
{
if (str1 == NULL)
return -(str1 != str2);
if (str2 == NULL)
return -(str1 != str2);
return strcmp(str1, str2);
}
static char* strdup0(const char* str)
{
if (str)
return strdup(str);
return NULL;
}
static int get_watch_serial(GDBusWatch* watcher)
{
return ++watcher->serial;
}
static struct filter_data* filter_data_find_match(DBusConnection* connection,
DBusList* listener_list, const char* name, const char* owner,
const char* path, const char* interface, const char* member, const char* argument)
{
DBusList* current;
for (current = _dbus_list_get_first_link(&listener_list); current != NULL;
current = _dbus_list_get_next_link(&listener_list, current)) {
struct filter_data* data = current->data;
if (connection != data->connection)
continue;
if (strcmp0(name, data->name) != 0)
continue;
if (strcmp0(owner, data->owner) != 0)
continue;
if (strcmp0(path, data->path) != 0)
continue;
if (strcmp0(interface, data->interface) != 0)
continue;
if (strcmp0(member, data->member) != 0)
continue;
if (strcmp0(argument, data->argument) != 0)
continue;
return data;
}
return NULL;
}
static struct filter_data* filter_data_find(DBusConnection* connection, DBusList* listener_list)
{
DBusList* current;
for (current = _dbus_list_get_first_link(&listener_list); current != NULL;
current = _dbus_list_get_next_link(&listener_list, current)) {
struct filter_data* data = current->data;
if (connection != data->connection)
continue;
return data;
}
return NULL;
}
static void format_rule(struct filter_data* data, char* rule, size_t size)
{
const char* sender;
int offset;
offset = snprintf(rule, size, "type='signal'");
sender = data->name ?: data->owner;
if (sender)
offset += snprintf(rule + offset, size - offset,
",sender='%s'", sender);
if (data->path)
offset += snprintf(rule + offset, size - offset,
",path='%s'", data->path);
if (data->interface)
offset += snprintf(rule + offset, size - offset,
",interface='%s'", data->interface);
if (data->member)
offset += snprintf(rule + offset, size - offset,
",member='%s'", data->member);
if (data->argument)
snprintf(rule + offset, size - offset,
",arg0='%s'", data->argument);
}
static gboolean add_match(struct filter_data* data,
DBusHandleMessageFunction filter)
{
DBusError err;
char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
format_rule(data, rule, sizeof(rule));
dbus_error_init(&err);
dbus_bus_add_match(data->connection, rule, &err);
if (dbus_error_is_set(&err)) {
error("Adding match rule \"%s\" failed: %s", rule,
err.message);
dbus_error_free(&err);
return FALSE;
}
data->handle_func = filter;
data->registered = TRUE;
return TRUE;
}
static gboolean remove_match(struct filter_data* data)
{
DBusError err;
char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
if (data->watcher->conn_closed) {
/* If the connection is disconnected, we don't need to remove the match */
return TRUE;
}
format_rule(data, rule, sizeof(rule));
dbus_error_init(&err);
dbus_bus_remove_match(data->connection, rule, &err);
if (dbus_error_is_set(&err)) {
error("GDBUS Removing owner match rule for %s failed: %s",
rule, err.message);
dump_stack();
dbus_error_free(&err);
return FALSE;
}
return TRUE;
}
static void filter_data_free(struct filter_data* data, DBusList* listener_list)
{
DBusList* l;
/* Remove filter if there are no listeners left for the connection */
if (filter_data_find(data->connection, listener_list) == NULL) {
dbus_connection_remove_filter(data->connection, message_filter,
data->watcher);
}
for (l = _dbus_list_get_first_link(&data->callbacks); l != NULL;
l = _dbus_list_get_next_link(&data->callbacks, l))
free(l->data);
_dbus_list_clear(&data->callbacks);
dbus_remove_watch(data->watcher, data->name_watch);
free(data->name);
free(data->owner);
free(data->path);
free(data->interface);
free(data->member);
free(data->argument);
/* no listeners left for the connection */
if (_dbus_list_get_last(&listener_list) == NULL) {
free_dbus_watch(data->watcher);
}
dbus_connection_unref(data->connection);
free(data);
}
static struct filter_data* filter_data_get(GDBusWatch* watcher,
DBusHandleMessageFunction filter,
const char* sender, const char* path, const char* interface,
const char* member, const char* argument)
{
struct filter_data* data;
const char *name = NULL, *owner = NULL;
if (filter_data_find(watcher->conn, watcher->list) == NULL) {
if (!dbus_connection_add_filter(watcher->conn,
message_filter, watcher, NULL)) {
error("dbus_connection_add_filter() failed");
return NULL;
}
}
if (sender != NULL) {
if (sender[0] == ':')
owner = sender;
else
name = sender;
}
data = filter_data_find_match(watcher->conn, watcher->list, name, owner, path,
interface, member, argument);
if (data)
return data;
data = calloc(1, sizeof(struct filter_data));
data->connection = dbus_connection_ref(watcher->conn);
data->name = strdup0(name);
data->owner = strdup0(owner);
data->path = strdup0(path);
data->interface = strdup0(interface);
data->member = strdup0(member);
data->argument = strdup0(argument);
data->watcher = watcher;
if (!add_match(data, filter)) {
dbus_connection_unref(data->connection);
free(data->name);
free(data->owner);
free(data->path);
free(data->interface);
free(data->member);
free(data->argument);
free(data);
return NULL;
}
_dbus_list_append(&watcher->list, data);
return data;
}
static struct filter_callback* filter_data_find_callback(
struct filter_data* data,
guint id)
{
DBusList* l;
for (l = _dbus_list_get_first_link(&data->callbacks); l != NULL;
l = _dbus_list_get_next_link(&data->callbacks, l)) {
struct filter_callback* cb = l->data;
if (cb->id == id)
return cb;
}
for (l = _dbus_list_get_first_link(&data->processed); l != NULL;
l = _dbus_list_get_next_link(&data->processed, l)) {
struct filter_callback* cb = l->data;
if (cb->id == id)
return cb;
}
return NULL;
}
static void filter_data_call_and_free(struct filter_data* data, DBusList* listener_list)
{
DBusList* l;
for (l = _dbus_list_get_first_link(&data->callbacks); l != NULL;
l = _dbus_list_get_next_link(&data->callbacks, l)) {
struct filter_callback* cb = l->data;
if (cb->disc_func)
cb->disc_func(data->connection, cb->user_data);
if (cb->destroy_func)
cb->destroy_func(cb->user_data);
}
filter_data_free(data, listener_list);
}
static struct filter_callback* filter_data_add_callback(
struct filter_data* data,
GDBusWatchFunction connect,
GDBusWatchFunction disconnect,
GDBusSignalFunction signal,
GDBusDestroyFunction destroy,
guint watch_id,
void* user_data)
{
struct filter_callback* cb = NULL;
cb = calloc(1, sizeof(struct filter_callback));
cb->conn_func = connect;
cb->disc_func = disconnect;
cb->signal_func = signal;
cb->destroy_func = destroy;
cb->user_data = user_data;
cb->id = watch_id;
if (data->lock)
_dbus_list_append(&data->processed, cb);
else
_dbus_list_append(&data->callbacks, cb);
return cb;
}
static void close_cb(uv_handle_t* handle)
{
free(handle->data);
}
static void service_data_free(struct service_data* data)
{
struct filter_callback* callback = data->callback;
dbus_connection_unref(data->conn);
if (data->call)
dbus_pending_call_unref(data->call);
free(data->name);
callback->data = NULL;
uv_close((uv_handle_t*)&data->handle, close_cb);
}
/* Returns TRUE if data is freed */
static gboolean filter_data_remove_callback(struct filter_data* data,
struct filter_callback* cb)
{
_dbus_list_remove(&data->callbacks, cb);
_dbus_list_remove(&data->processed, cb);
/* Cancel pending operations */
if (cb->data) {
if (cb->data->call)
dbus_pending_call_cancel(cb->data->call);
service_data_free(cb->data);
}
if (cb->destroy_func)
cb->destroy_func(cb->user_data);
free(cb);
/* Don't remove the filter if other callbacks exist or data is lock
* processing callbacks */
if (data->callbacks || data->lock)
return FALSE;
if (data->registered && !remove_match(data))
return FALSE;
_dbus_list_remove(&data->watcher->list, data);
filter_data_free(data, data->watcher->list);
return TRUE;
}
static DBusHandlerResult signal_filter(DBusConnection* connection,
DBusMessage* message, void* user_data)
{
struct filter_data* data = user_data;
struct filter_callback* cb;
while (data->callbacks) {
cb = data->callbacks->data;
if (cb->signal_func && !cb->signal_func(connection, message, cb->user_data)) {
if (filter_data_remove_callback(data, cb))
break;
continue;
}
/* Check if the watch was removed/freed by the callback
* function */
if (_dbus_list_find_last(&data->callbacks, cb) == NULL)
continue;
_dbus_list_remove(&data->callbacks, cb);
_dbus_list_append(&data->processed, cb);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void update_name_cache(DBusList* listener_list, const char* name, const char* owner)
{
DBusList* l;
for (l = _dbus_list_get_first_link(&listener_list); l != NULL;
l = _dbus_list_get_next_link(&listener_list, l)) {
struct filter_data* data = l->data;
if (strcmp0(data->name, name) != 0)
continue;
free(data->owner);
data->owner = strdup0(owner);
}
}
static const char* check_name_cache(DBusList* listener_list, const char* name)
{
DBusList* l;
for (l = _dbus_list_get_first_link(&listener_list); l != NULL;
l = _dbus_list_get_next_link(&listener_list, l)) {
struct filter_data* data = l->data;
if (strcmp0(data->name, name) != 0)
continue;
return data->owner;
}
return NULL;
}
static DBusHandlerResult service_filter(DBusConnection* connection,
DBusMessage* message, void* user_data)
{
struct filter_data* data = user_data;
struct filter_callback* cb;
char *name, *old, *new;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID)) {
error("Invalid arguments for NameOwnerChanged signal");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
update_name_cache(data->watcher->list, name, new);
while (data->callbacks) {
cb = data->callbacks->data;
if (*new == '\0') {
if (cb->disc_func)
cb->disc_func(connection, cb->user_data);
} else {
if (cb->conn_func)
cb->conn_func(connection, cb->user_data);
}
/* Check if the watch was removed/freed by the callback
* function */
if (_dbus_list_find_last(&data->callbacks, cb) == NULL)
continue;
/* Only auto remove if it is a bus name watch */
if (data->argument[0] == ':' && (cb->conn_func == NULL || cb->disc_func == NULL)) {
if (filter_data_remove_callback(data, cb))
break;
continue;
}
_dbus_list_remove(&data->callbacks, cb);
_dbus_list_append(&data->processed, cb);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static bool process_signal_message(DBusMessage* message,
const char** sender, const char** path,
const char** iface, const char** member,
const char** arg)
{
if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
return false;
*sender = dbus_message_get_sender(message);
*path = dbus_message_get_path(message);
*iface = dbus_message_get_interface(message);
*member = dbus_message_get_member(message);
if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, arg, DBUS_TYPE_INVALID))
*arg = NULL;
return true;
}
static int filter_data_match(const char* str1, const char* data_param)
{
if (data_param == NULL)
return 0;
if (str1 == NULL)
return -1;
return strcmp(str1, data_param);
}
static gboolean match_listener_data(struct filter_data* data, DBusConnection* connection,
const char* sender, const char* path,
const char* iface, const char* member, const char* arg)
{
if (connection != data->connection)
return FALSE;
if (filter_data_match(sender, data->owner) != 0)
return FALSE;
if (filter_data_match(path, data->path) != 0)
return FALSE;
if (filter_data_match(iface, data->interface) != 0)
return FALSE;
if (filter_data_match(member, data->member) != 0)
return FALSE;
if (filter_data_match(arg, data->argument) != 0)
return FALSE;
return TRUE;
}
static void process_listener_callbacks(struct filter_data* data, DBusConnection* connection,
DBusMessage* message)
{
if (!data->handle_func)
return;
data->lock = TRUE;
data->handle_func(connection, message, data);
data->callbacks = data->processed;
data->processed = NULL;
data->lock = FALSE;
}
static void process_listeners(DBusList* listener_list, DBusConnection* connection,
DBusMessage* message, DBusList** delete_listener, const char* sender,
const char* path, const char* iface, const char* member, const char* arg)
{
DBusList* current;
struct filter_data* data;
for (current = _dbus_list_get_first_link(&listener_list); current;
current = _dbus_list_get_next_link(&listener_list, current)) {
data = current->data;
if (!match_listener_data(data, connection, sender,
path, iface, member, arg))
continue;
process_listener_callbacks(data, connection, message);
if (!data->callbacks)
_dbus_list_prepend(delete_listener, current);
}
}
static void cleanup_listeners(DBusList* delete_listener, GDBusWatch* watcher)
{
DBusList* current;
struct filter_data* data;
for (current = _dbus_list_get_first_link(&delete_listener); current;
current = _dbus_list_get_next_link(&delete_listener, current)) {
DBusList* l = current->data;
data = l->data;
/* Has any other callback added callbacks back to this data? */
if (data->callbacks)
continue;
remove_match(data);
_dbus_list_remove_link(&watcher->list, l);
filter_data_free(data, watcher->list);
}
_dbus_list_clear(&delete_listener);
}
static DBusHandlerResult message_filter(DBusConnection* connection,
DBusMessage* message, void* user_data)
{
const char *sender, *path, *iface, *member, *arg = NULL;
DBusList* delete_listener = NULL;
GDBusWatch* watcher = user_data;
if (!process_signal_message(message, &sender, &path,
&iface, &member, &arg))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
process_listeners(watcher->list, connection, message, &delete_listener,
sender, path, iface, member, arg);
if (delete_listener)
cleanup_listeners(delete_listener, watcher);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void update_service(uv_idle_t* handle)
{
struct service_data* data = handle->data;
struct filter_callback* cb = data->callback;
DBusConnection* conn;
conn = dbus_connection_ref(data->conn);
service_data_free(data);
if (cb->conn_func)
cb->conn_func(conn, cb->user_data);
dbus_connection_unref(conn);
}
static void service_reply(DBusPendingCall* call, void* user_data)
{
struct service_data* data = user_data;
DBusMessage* reply;
DBusError err;
reply = dbus_pending_call_steal_reply(call);
if (reply == NULL)
return;
dbus_error_init(&err);
if (dbus_set_error_from_message(&err, reply))
goto fail;
if (dbus_message_get_args(reply, &err, DBUS_TYPE_STRING,
&data->owner, DBUS_TYPE_INVALID)
== FALSE)
goto fail;
update_service(&data->handle);
goto done;
fail:
error("service_reply fail: %s", err.message);
dbus_error_free(&err);
service_data_free(data);
done:
dbus_message_unref(reply);
}
static struct service_data* create_service_data(DBusConnection* conn,
const char* name,
struct filter_callback* cb)
{
struct service_data* data = calloc(1, sizeof(*data));
if (!data) {
error("%s: malloc failed", __func__);
return NULL;
}
data->conn = dbus_connection_ref(conn);
data->name = strdup0(name);
data->callback = cb;
cb->data = data;
return data;
}
static bool init_uv_handle(struct service_data* data)
{
if (uv_idle_init(uv_default_loop(), &data->handle) != 0) {
error("%s: uv_idle_init failed", __func__);
return false;
}
data->handle.data = data;
return true;
}
static gboolean send_name_owner_request(struct service_data* data, const char* name)
{
DBusMessage* msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
if (!msg) {
error("%s: dbus_message_new_method_call failed", __func__);
return FALSE;
}
dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
if (!dbus_connection_send_with_reply(data->conn, msg, &data->call, -1)) {
error("%s: dbus_connection_send_with_reply failed", __func__);
dbus_message_unref(msg);
return FALSE;
}
if (!data->call) {
error("%s: dbus reply failed with empty pendingcall", __func__);
dbus_message_unref(msg);
return FALSE;
}
if (dbus_pending_call_get_completed(data->call)) {
service_reply(data->call, data);
} else {
dbus_pending_call_set_notify(data->call, service_reply, data, NULL);
}
dbus_message_unref(msg);
return TRUE;
}
static void check_service(DBusConnection* conn, const char* name,
struct filter_callback* cb, DBusList* listener_list)
{
struct service_data* data = create_service_data(conn, name, cb);
if (!data)
return;
if (!init_uv_handle(data)) {
dbus_connection_unref(data->conn);
free(data->name);
free(data);
return;
}
data->owner = check_name_cache(listener_list, name);
if (data->owner) {
if (uv_idle_start(&data->handle, update_service) != 0) {
error("%s: uv_idle_start failed:", __func__);
uv_close((uv_handle_t*)&data->handle, NULL);
dbus_connection_unref(data->conn);
free(data->name);
free(data);
}
return;
}
if (send_name_owner_request(data, name) == FALSE) {
uv_close((uv_handle_t*)&data->handle, NULL);
dbus_connection_unref(data->conn);
free(data->name);
free(data);
return;
}
}
guint dbus_add_service_watch(GDBusWatch* watcher, const char* name,
GDBusWatchFunction connect,
GDBusWatchFunction disconnect,
void* user_data, GDBusDestroyFunction destroy)
{
struct filter_data* data;
struct filter_callback* cb;
if (name == NULL)
return 0;
data = filter_data_get(watcher, service_filter, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS, "NameOwnerChanged", name);
if (data == NULL)
return 0;
cb = filter_data_add_callback(data, connect, disconnect, NULL, destroy,
get_watch_serial(watcher), user_data);
if (cb == NULL)
return 0;
if (connect)
check_service(watcher->conn, name, cb, watcher->list);
return cb->id;
}
guint dbus_add_service_disconnect_watch(GDBusWatch* watcher, const char* name,
GDBusWatchFunction func, void* user_data, GDBusDestroyFunction destroy)
{
return dbus_add_service_watch(watcher, name, NULL, func, user_data, destroy);
}
guint dbus_add_signal_watch(GDBusWatch* watcher,
const char* sender, const char* path,
const char* interface, const char* member,
GDBusSignalFunction function, void* user_data,
GDBusDestroyFunction destroy)
{
struct filter_data* data;
struct filter_callback* cb;
data = filter_data_get(watcher, signal_filter, sender, path,
interface, member, NULL);
if (data == NULL)
return 0;
cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
get_watch_serial(watcher), user_data);
if (cb == NULL)
return 0;
if (data->name != NULL && data->name_watch == 0)
data->name_watch = dbus_add_service_watch(watcher,
data->name, NULL,
NULL, NULL, NULL);
return cb->id;
}
guint dbus_add_properties_watch(GDBusWatch* watcher,
const char* sender, const char* path,
const char* interface,
GDBusSignalFunction function, void* user_data,
GDBusDestroyFunction destroy)
{
struct filter_data* data;
struct filter_callback* cb;
data = filter_data_get(watcher, signal_filter, sender, path,
DBUS_INTERFACE_PROPERTIES, "PropertiesChanged", interface);
if (data == NULL)
return 0;
cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
get_watch_serial(watcher), user_data);
if (cb == NULL)
return 0;
if (data->name != NULL && data->name_watch == 0)
data->name_watch = dbus_add_service_watch(watcher,
data->name, NULL,
NULL, NULL, NULL);
return cb->id;
}
gboolean dbus_remove_watch(GDBusWatch* watcher, guint id)
{
struct filter_data* data;
struct filter_callback* cb;
DBusList* ldata;
if (id == 0)
return FALSE;
for (ldata = _dbus_list_get_first_link(&watcher->list); ldata != NULL;
ldata = _dbus_list_get_next_link(&watcher->list, ldata)) {
data = ldata->data;
cb = filter_data_find_callback(data, id);
if (cb) {
filter_data_remove_callback(data, cb);
return TRUE;
}
}
return FALSE;
}
void dbus_remove_all_watches(GDBusWatch* watcher)
{
struct filter_data* data;
while ((data = filter_data_find(watcher->conn, watcher->list))) {
_dbus_list_remove(&watcher->list, data);
filter_data_call_and_free(data, watcher->list);
}
}
GDBusWatch* new_dbus_watch(DBusConnection* connection)
{
GDBusWatch* watcher;
watcher = calloc(1, sizeof(GDBusWatch));
if (watcher == NULL)
return NULL;
watcher->conn = dbus_connection_ref(connection);
watcher->list = NULL;
watcher->serial = 0;
watcher->conn_closed = FALSE;
return watcher;
}
void free_dbus_watch(GDBusWatch* watcher)
{
dbus_connection_unref(watcher->conn);
free(watcher);
}
guint dbus_client_add_service_watch(GDBusClient* client, const char* name,
GDBusWatchFunction connect, GDBusWatchFunction disconnect,
void* user_data, GDBusDestroyFunction destroy)
{
return dbus_add_service_watch(client->watcher, name, connect, disconnect,
user_data, destroy);
}
guint dbus_client_add_service_disconnect_watch(GDBusClient* client, const char* name,
GDBusWatchFunction function, void* user_data, GDBusDestroyFunction destroy)
{
return dbus_add_service_disconnect_watch(client->watcher, name, function, user_data, destroy);
}
guint dbus_client_add_signal_watch(GDBusClient* client, const char* sender,
const char* path, const char* interface, const char* member,
GDBusSignalFunction function, void* user_data, GDBusDestroyFunction destroy)
{
return dbus_add_signal_watch(client->watcher, sender, path, interface,
member, function, user_data, destroy);
}
guint dbus_client_add_properties_watch(GDBusClient* client,
const char* sender, const char* path, const char* interface,
GDBusSignalFunction function, void* user_data, GDBusDestroyFunction destroy)
{
return dbus_add_properties_watch(client->watcher, sender, path, interface,
function, user_data, destroy);
}
gboolean dbus_client_remove_watch(GDBusClient* client, guint tag)
{
return dbus_remove_watch(client->watcher, tag);
}
void dbus_client_remove_all_watches(GDBusClient* client)
{
dbus_remove_all_watches(client->watcher);
}
void dbus_watch_set_connection_state(GDBusWatch* watcher, gboolean closed)
{
watcher->conn_closed = closed;
}

View File

@ -57,7 +57,7 @@ int property_get(const char* key, char* value, const char* default_value);
** If no property with this key is set (or the key is NULL) or the boolean
** conversion fails, the default value is returned.
**/
int8_t property_get_bool(const char* key, int8_t default_value);
int8_t property_get_bool(const char *key, int8_t default_value);
/* property_get_int64: returns the value of key truncated and coerced into a
** int64_t. If the property is not set, then the default value is used.
@ -78,7 +78,7 @@ int8_t property_get_bool(const char* key, int8_t default_value);
** If no property with this key is set (or the key is NULL) or the numeric
** conversion fails, the default value is returned.
**/
int64_t property_get_int64(const char* key, int64_t default_value);
int64_t property_get_int64(const char *key, int64_t default_value);
/* property_get_int32: returns the value of key truncated and coerced into an
** int32_t. If the property is not set, then the default value is used.
@ -99,13 +99,13 @@ int64_t property_get_int64(const char* key, int64_t default_value);
** If no property with this key is set (or the key is NULL) or the numeric
** conversion fails, the default value is returned.
**/
int32_t property_get_int32(const char* key, int32_t default_value);
int32_t property_get_int32(const char *key, int32_t default_value);
/* property_set: returns 0 on success, < 0 on failure
*/
int property_set(const char* key, const char* value);
*/
int property_set(const char *key, const char *value);
int property_list(void (*propfn)(const char* key, const char* value, void* cookie), void* cookie);
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
#if defined(__BIONIC_FORTIFY)
#define __property_get_err_str "property_get() called with too small of a buffer"
@ -116,18 +116,19 @@ int property_list(void (*propfn)(const char* key, const char* value, void* cooki
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
int property_get(const char* key, char* value, const char* default_value)
__clang_error_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos(value) < PROPERTY_VALUE_MAX,
__property_get_err_str);
__clang_error_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
__bos(value) < PROPERTY_VALUE_MAX,
__property_get_err_str);
#pragma clang diagnostic pop
#else /* defined(__clang__) */
extern int __property_get_real(const char*, char*, const char*) __asm__(__USER_LABEL_PREFIX__ "property_get");
extern int __property_get_real(const char *, char *, const char *)
__asm__(__USER_LABEL_PREFIX__ "property_get");
__errordecl(__property_get_too_small_error, __property_get_err_str);
__BIONIC_FORTIFY_INLINE
int property_get(const char* key, char* value, const char* default_value)
{
int property_get(const char *key, char *value, const char *default_value) {
size_t bos = __bos(value);
if (bos < PROPERTY_VALUE_MAX) {
__property_get_too_small_error();

View File

@ -134,7 +134,6 @@ static inline uint64_t atrace_is_tag_enabled(uint64_t tag)
* @param name: Context name.
*/
#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name)
void atrace_begin_body(const char*);
static inline void atrace_begin(uint64_t tag, const char* name)
{
if (atrace_is_tag_enabled(tag)) {
@ -146,7 +145,6 @@ static inline void atrace_begin(uint64_t tag, const char* name)
* Ends a tracing context that was started by ATRACE_BEGIN.
*/
#define ATRACE_END() atrace_end(ATRACE_TAG)
void atrace_end_body(void);
static inline void atrace_end(uint64_t tag)
{
if (atrace_is_tag_enabled(tag)) {
@ -159,11 +157,8 @@ static inline void atrace_end(uint64_t tag)
* @param name: Event name
* @param cookie: Unique identifier for the event.
*/
#define ATRACE_ASYNC_BEGIN(name, cookie) \
atrace_async_begin(ATRACE_TAG, name, cookie)
void atrace_async_begin_body(const char*, int32_t);
static inline void atrace_async_begin(uint64_t tag, const char* name,
int32_t cookie)
#define ATRACE_ASYNC_BEGIN(name, cookie) atrace_async_begin(ATRACE_TAG, name, cookie)
static inline void atrace_async_begin(uint64_t tag, const char* name, int32_t cookie)
{
if (atrace_is_tag_enabled(tag)) {
atrace_async_begin_body(name, cookie);
@ -176,7 +171,6 @@ static inline void atrace_async_begin(uint64_t tag, const char* name,
* @param cookie: Unique identifier for the event.
*/
#define ATRACE_ASYNC_END(name, cookie) atrace_async_end(ATRACE_TAG, name, cookie)
void atrace_async_end_body(const char*, int32_t);
static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cookie)
{
if (atrace_is_tag_enabled(tag)) {
@ -192,11 +186,12 @@ static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cook
*/
#define ATRACE_ASYNC_FOR_TRACK_BEGIN(track_name, name, cookie) \
atrace_async_for_track_begin(ATRACE_TAG, track_name, name, cookie)
void atrace_async_for_track_begin_body(const char*, const char*, int32_t);
atrace_async_for_track_begin(ATRACE_TAG, track_name, name, cookie)
static inline void atrace_async_for_track_begin(uint64_t tag, const char* track_name,
const char* name, int32_t cookie) {
if (atrace_is_tag_enabled(tag)) {
void atrace_async_for_track_begin_body(const char*, const char*, int32_t);
atrace_async_for_track_begin_body(track_name, name, cookie);
}
}
@ -217,10 +212,10 @@ static inline void atrace_async_for_track_begin(uint64_t tag, const char* track_
*/
#define ATRACE_ASYNC_FOR_TRACK_END(track_name, name, cookie) \
atrace_async_for_track_end(ATRACE_TAG, track_name, name, cookie)
void atrace_async_for_track_end_body(const char*, const char*, int32_t);
static inline void atrace_async_for_track_end(uint64_t tag, const char* track_name,
const char* name, int32_t cookie) {
if (atrace_is_tag_enabled(tag)) {
void atrace_async_for_track_end_body(const char*, const char*, int32_t);
atrace_async_for_track_end_body(track_name, name, cookie);
}
}
@ -236,9 +231,9 @@ static inline void atrace_async_for_track_end(uint64_t tag, const char* track_na
* @param[in] name the value that using to identify the context
*/
#define ATRACE_INSTANT(name) atrace_instant(ATRACE_TAG, name)
void atrace_instant_body(const char*);
static inline void atrace_instant(uint64_t tag, const char* name) {
if (atrace_is_tag_enabled(tag)) {
void atrace_instant_body(const char*);
atrace_instant_body(name);
}
}
@ -254,10 +249,10 @@ static inline void atrace_instant(uint64_t tag, const char* name) {
*/
#define ATRACE_INSTANT_FOR_TRACK(trackName, name) \
atrace_instant_for_track(ATRACE_TAG, trackName, name)
void atrace_instant_for_track_body(const char*, const char*);
static inline void atrace_instant_for_track(uint64_t tag, const char* track_name,
const char* name) {
if (atrace_is_tag_enabled(tag)) {
void atrace_instant_for_track_body(const char*, const char*);
atrace_instant_for_track_body(track_name, name);
}
}
@ -269,10 +264,10 @@ static inline void atrace_instant_for_track(uint64_t tag, const char* track_name
* @param[in] velue this can be used to track how a value changes over time.
*/
#define ATRACE_INT(name, value) atrace_int(ATRACE_TAG, name, value)
void atrace_int_body(const char*, int32_t);
static inline void atrace_int(uint64_t tag, const char* name, int32_t value)
{
if (atrace_is_tag_enabled(tag)) {
void atrace_int_body(const char*, int32_t);
atrace_int_body(name, value);
}
}
@ -284,10 +279,10 @@ static inline void atrace_int(uint64_t tag, const char* name, int32_t value)
* @param[in] value This can be used to track how a value changes over time.
*/
#define ATRACE_INT64(name, value) atrace_int64(ATRACE_TAG, name, value)
void atrace_int64_body(const char*, int64_t);
static inline void atrace_int64(uint64_t tag, const char* name, int64_t value)
{
if (atrace_is_tag_enabled(tag)) {
void atrace_int64_body(const char*, int64_t);
atrace_int64_body(name, value);
}
}

View File

@ -50,10 +50,10 @@ int property_delete(const char* key);
int property_commit(void);
/**
* @brief load default property value.
* @brief Reload default property value.
* @return On success returns 0, -errno otherwise.
*/
int property_load(const char* path);
int property_reload(void);
/**
* @brief Exit the kvdb service.
@ -163,39 +163,6 @@ ssize_t property_get_binary(const char* key, void* value, size_t val_len);
* @Returns 0 on success, <0 if all databases failed to open.
*/
int property_list_binary(void (*propfn)(const char* key, const void* value, size_t val_len, void* cookie), void* cookie);
/**
* @Get property with an error param
* @param[in] key entry key string
* @param[out] value entry
* @Retruns >0 length of the value, <0 if failed.
*/
int property_get_with_err(const char* key, char* value);
/**
* @Get bool property with an error param
* @param[in] key entry key string
* @param[out] value entry
* @Retruns =0 if success !=0 if failed.
*/
int property_get_bool_with_err(const char* key, int8_t* value);
/**
* @Get int32 property with an error param
* @param[in] key entry key string
* @param[out] value entry
* @Retruns =0 if success !=0 if failed.
*/
int property_get_int32_with_err(const char* key, int32_t* value);
/**
* @Get int64 property with an error param
* @param[in] key entry key string
* @param[out] value entry
* @Retruns =0 if success !=0 if failed.
*/
int property_get_int64_with_err(const char* key, int64_t* value);
#if defined(__cplusplus)
}
#endif

View File

@ -1,81 +0,0 @@
#ifndef __MURMURHASH_H
#define __MURMURHASH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
static inline uint32_t murmurhash(const char *name)
{
uint32_t c1 = 0xcc9e2d51;
uint32_t c2 = 0x1b873593;
uint32_t n = 0xe6546b64;
uint32_t m = 5;
uint32_t h = 0;
uint32_t k = 0;
uint32_t r1 = 15;
uint32_t r2 = 13;
int i = 0, seed = 0;
uint8_t *d = (uint8_t *) name; // 32 bit extract from `key'
const uint32_t *chunks = NULL;
const uint8_t *tail = NULL; // tail - last 8 bytes
int len = strlen(name);
int l = len / 4; // chunk length
h = seed;
chunks = (const uint32_t *) (d + l * 4); // body
tail = (const uint8_t *) (d + l * 4); // last 8 byte chunk of `key'
// for each 4 byte chunk of `key'
for (i = -l; i != 0; ++i) {
// next 4 byte chunk of `key'
k = chunks[i];
// encode next 4 byte chunk of `key'
k *= c1;
k = (k << r1) | (k >> (32 - r1));
k *= c2;
// append to hash
h ^= k;
h = (h << r2) | (h >> (32 - r2));
h = h * m + n;
}
k = 0;
// remainder
switch (len & 3) { // `len % 4'
case 3: k ^= (tail[2] << 16);
[[fallthrough]];
case 2: k ^= (tail[1] << 8);
[[fallthrough]];
case 1:
k ^= tail[0];
k *= c1;
k = (k << r1) | (k >> (32 - r1));
k *= c2;
h ^= k;
}
h ^= len;
h ^= (h >> 16);
h *= 0x85ebca6b;
h ^= (h >> 13);
h *= 0xc2b2ae35;
h ^= (h >> 16);
return h;
}
/* clang-format on */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -43,21 +43,8 @@ static ssize_t recv_safe(int sockfd, char* buf, size_t offset, size_t len)
{
while (offset < len) {
ssize_t ret = recv(sockfd, buf + offset, len - offset, 0);
if (ret < 0) {
if (errno == EAGAIN) {
struct pollfd pfd;
pfd.fd = sockfd;
pfd.events = POLLIN;
ret = poll(&pfd, 1, -1);
if (ret > 0 && (pfd.revents & POLLIN)) {
continue;
} else {
KVERR("poll ret %d error %d\n", ret, errno);
break;
}
}
if (ret < 0)
return -errno;
}
if (ret == 0)
return -ENODATA;
offset += ret;
@ -67,77 +54,13 @@ static ssize_t recv_safe(int sockfd, char* buf, size_t offset, size_t len)
}
/****************************************************************************
* Name: property_connect_one
* Name: property_connect
*
* Description:
* Initialize client socket and connect to server
*
* Input Parameters:
* addr - server address
* addrlen - server address length
*
* Returned Value:
* On success return client socket fd.
* On error return error value (<0).
*
****************************************************************************/
#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_RPMSG)
static int property_connect_one(const struct sockaddr* addr,
socklen_t addrlen)
{
int fd = socket(addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
int ret = connect(fd, addr, addrlen);
if (ret < 0) {
ret = -errno;
close(fd);
return ret;
}
return fd;
}
#endif
#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_RPMSG)
/****************************************************************************
* Name: use_local_socket
*
* Description:
* Determine whether to use local socket or rpmsg socket to
* connect to server
*
* Returned Value:
* true: use local socket
* false: use rpmsg socket
*
****************************************************************************/
static inline bool use_local_socket(void)
{
#ifdef CONFIG_KVDB_SERVER_CPUNAME
struct sockaddr_rpmsg addr;
socklen_t addrlen = sizeof(addr);
int fd = socket(AF_RPMSG, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd >= 0) {
int ret = getsockname(fd, (struct sockaddr*)&addr, &addrlen);
close(fd);
if (ret == 0) {
return strcmp(addr.rp_cpu, CONFIG_KVDB_SERVER_CPUNAME) == 0;
}
}
#endif
return true;
}
#endif
/****************************************************************************
* Name: property_connect
*
* Description:
* Initialize client socket and connect to server
* None
*
* Returned Value:
* On success return client socket fd.
@ -147,45 +70,48 @@ static inline bool use_local_socket(void)
static int property_connect(void)
{
#ifdef CONFIG_NET_LOCAL
const struct sockaddr_un laddr = {
#ifdef CONFIG_KVDB_SERVER
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
#else
int fd = socket(AF_RPMSG, SOCK_STREAM | SOCK_CLOEXEC, 0);
#endif
if (fd < 0)
return -errno;
#if CONFIG_KVDB_TIMEOUT_INTERVAL
struct timeval timeout = {
.tv_sec = CONFIG_KVDB_TIMEOUT_INTERVAL,
.tv_usec = 0,
};
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
#endif
#ifdef CONFIG_KVDB_SERVER
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
.sun_path = PROP_SERVER_PATH,
};
#endif
#ifdef CONFIG_NET_RPMSG
const struct sockaddr_rpmsg raddr = {
#else
struct sockaddr_rpmsg addr = {
.rp_family = AF_RPMSG,
.rp_name = PROP_SERVER_PATH,
.rp_cpu = CONFIG_KVDB_SERVER_CPUNAME,
};
#endif
int ret = -ENOTSUP;
#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_RPMSG)
bool use_local = use_local_socket();
#endif
while (1) {
#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_RPMSG)
if (use_local)
ret = property_connect_one((const struct sockaddr*)&laddr, sizeof(laddr));
else
ret = property_connect_one((const struct sockaddr*)&raddr, sizeof(raddr));
#elif defined(CONFIG_NET_LOCAL)
ret = property_connect_one((const struct sockaddr*)&laddr, sizeof(laddr));
#elif defined(CONFIG_NET_RPMSG)
ret = property_connect_one((const struct sockaddr*)&raddr, sizeof(raddr));
#else
break;
#endif
if (ret >= 0)
break;
int ret = connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
if (ret < 0 && errno != ENOENT) {
ret = -errno;
close(fd);
return ret;
} else if (ret == 0) {
return fd;
}
usleep(1000);
}
return ret;
}
/****************************************************************************
@ -835,13 +761,13 @@ out:
}
/****************************************************************************
* Name: property_load
* Name: property_reload
*
* Description:
* load default property value
* Reload default property value
*
* Input Parameters:
* const char* path: file path
* None
*
* Returned Value:
* On success returns 0.
@ -849,34 +775,14 @@ out:
*
****************************************************************************/
int property_load(const char* path)
int property_reload(void)
{
size_t file_len;
int fd = property_connect();
int ret;
int fd;
if (path == NULL)
path = "";
file_len = strlen(path) + 1;
fd = property_connect();
if (fd < 0)
return fd;
char cmd[2] = {
'R', file_len
};
struct iovec iov[2] = {
{ .iov_base = cmd, .iov_len = 2 },
{ .iov_base = (char*)path, .iov_len = file_len },
};
struct msghdr msg = { 0 };
msg.msg_iov = iov;
msg.msg_iovlen = 2;
ret = sendmsg(fd, &msg, 0) > 0 ? 0 : -errno;
ret = send(fd, "R", 1, 0) > 0 ? 0 : -errno;
close(fd);
return ret;

View File

@ -126,51 +126,6 @@ int property_set(const char* key, const char* value)
return property_set_(key, value, false);
}
/****************************************************************************
* Name: property_get_with_err
*
* Description:
* Retrieve Key-Values from database.
*
* Input Parameters:
* const char* key: entry key string
* char* value: not NULL : pointer to string buffer
* NULL : check whether this [key, value] exists
*
* Returned Value:
* On success returns the length of the value which will never be greater
* than PROP_NAME_MAX - 1 and will always be zero terminated.
* (the length does not include the terminating zero).
* On failure returns negative value.
*
****************************************************************************/
int property_get_with_err(const char* key, char* value)
{
/* in environment variable? */
const char* env = getenv(key);
if (env) {
size_t len = strlen(env);
if (len >= PROP_VALUE_MAX)
return -E2BIG;
if (value)
memcpy(value, env, len + 1);
return len;
}
ssize_t ret = property_get_binary(key, value, PROP_VALUE_MAX);
if (ret == 0) {
return -ENODATA;
} else if (ret > 0) {
*(value + ret) = '\0';
return strlen(value);
}
return ret;
}
/****************************************************************************
* Name: property_get
*
@ -193,7 +148,20 @@ int property_get_with_err(const char* key, char* value)
int property_get(const char* key, char* value, const char* default_value)
{
int ret = property_get_with_err(key, value);
/* in environment variable? */
const char* env = getenv(key);
if (env) {
size_t len = strlen(env);
if (len >= PROP_VALUE_MAX)
return -E2BIG;
if (value)
memcpy(value, env, len + 1);
return len;
}
ssize_t ret = property_get_binary(key, value, PROP_VALUE_MAX);
if (ret <= 0) {
if (!default_value)
return -EINVAL;
@ -202,8 +170,8 @@ int property_get(const char* key, char* value, const char* default_value)
memcpy(value, default_value, len + 1);
return len;
}
return ret;
*(value + ret) = '\0';
return strlen(value);
}
/****************************************************************************
@ -265,57 +233,6 @@ int property_set_bool_oneway(const char* key, int8_t value)
return property_set_bool_(key, value, true);
}
/****************************************************************************
* Name: property_get_bool_with_err
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as boolean.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int8_t* value: the entry value
*
* Returned Value:
* On success returns zero.
* On failure returns non-zero.
*
****************************************************************************/
int property_get_bool_with_err(const char* key, int8_t* value)
{
char buf[PROP_VALUE_MAX];
if (value == NULL)
return -EINVAL;
int len = property_get_with_err(key, buf);
if (len < 0)
return len;
if (len == 1) {
char ch = buf[0];
if (ch == '0' || ch == 'n') {
*value = 0;
return 0;
} else if (ch == '1' || ch == 'y') {
*value = 1;
return 0;
}
} else if (len > 1) {
if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
*value = 0;
return 0;
} else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
*value = 1;
return 0;
}
}
return -ENODATA;
}
/****************************************************************************
* Name: property_get_bool
*
@ -337,10 +254,22 @@ int property_get_bool_with_err(const char* key, int8_t* value)
int8_t property_get_bool(const char* key, int8_t default_value)
{
int8_t value;
int ret = property_get_bool_with_err(key, &value);
char buf[PROP_VALUE_MAX];
int len = property_get(key, buf, NULL);
if (len == 1) {
char ch = buf[0];
if (ch == '0' || ch == 'n')
return 0;
else if (ch == '1' || ch == 'y')
return 1;
} else if (len > 1) {
if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off"))
return 0;
else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on"))
return 1;
}
return ret ? default_value : value;
return default_value;
}
/****************************************************************************
@ -376,46 +305,6 @@ int property_set_int32_oneway(const char* key, int32_t value)
return property_set_int32_(key, value, true);
}
/****************************************************************************
* Name: property_get_int32_with_err
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as int32_t.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int32_t* value: the entry value
*
* Returned Value:
* On success returns zero.
* On failure returns non-zero.
*
****************************************************************************/
int property_get_int32_with_err(const char* key, int32_t* value)
{
char buf[PROP_VALUE_MAX];
if (value == NULL)
return -EINVAL;
int32_t ret = property_get_with_err(key, buf);
if (ret < 0)
return ret;
errno = 0;
char* end;
ret = strtol(buf, &end, 0);
if (errno || *end || buf == end)
return -ENODATA;
*value = ret;
return 0;
}
/****************************************************************************
* Name: property_get_int32
*
@ -437,10 +326,17 @@ int property_get_int32_with_err(const char* key, int32_t* value)
int32_t property_get_int32(const char* key, int32_t default_value)
{
int32_t value;
int ret = property_get_int32_with_err(key, &value);
char value[PROP_VALUE_MAX];
if (property_get(key, value, NULL) < 0)
return default_value;
return ret ? default_value : value;
errno = 0;
char* end;
int32_t ret = strtol(value, &end, 0);
if (errno || *end || value == end)
return default_value;
return ret;
}
/****************************************************************************
@ -476,46 +372,6 @@ int property_set_int64_oneway(const char* key, int64_t value)
return property_set_int64_(key, value, true);
}
/****************************************************************************
* Name: property_get_int64_with_err
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as int64_t.
* This is modified from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int64_t* value: the entry value
*
* Returned Value:
* On success returns zero.
* On failure returns non-zero.
*
****************************************************************************/
int property_get_int64_with_err(const char* key, int64_t* value)
{
char buf[PROP_VALUE_MAX];
if (value == NULL)
return -EINVAL;
int64_t ret = property_get_with_err(key, buf);
if (ret < 0)
return ret;
errno = 0;
char* end;
ret = strtoll(buf, &end, 0);
if (errno || *end || buf == end)
return -ENODATA;
*value = ret;
return 0;
}
/****************************************************************************
* Name: property_get_int64
*
@ -537,10 +393,17 @@ int property_get_int64_with_err(const char* key, int64_t* value)
int64_t property_get_int64(const char* key, int64_t default_value)
{
int64_t value;
int ret = property_get_int64_with_err(key, &value);
char value[PROP_VALUE_MAX];
if (property_get(key, value, NULL) < 0)
return default_value;
return ret ? default_value : value;
errno = 0;
char* end;
int64_t ret = strtoll(value, &end, 0);
if (errno || *end || value == end)
return default_value;
return ret;
}
/****************************************************************************

View File

@ -192,17 +192,17 @@ int property_commit(void)
}
/****************************************************************************
* Name: property_load
* Name: property_reload
*
* Description:
* load default property value
* Reload default property value
*
* Input Parameters:
* const char* path: file path
* None
*
****************************************************************************/
int property_load(const char* path)
int property_reload(void)
{
return 0;
}

View File

@ -21,7 +21,6 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include "internal.h"
#include "kvdb.h"

View File

@ -21,6 +21,7 @@
#include <kvdb.h>
#ifdef CONFIG_KVDB_DUMPLIST
static void callback(const char* name, const void* value, size_t val_len, void* cookie)
{
const char* temp = value;
@ -43,6 +44,7 @@ static void callback(const char* name, const void* value, size_t val_len, void*
printf("\n");
}
}
#endif
int main(int argc, char* argv[])
{

View File

@ -25,7 +25,6 @@
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include "internal.h"
#include "kvdb.h"

View File

@ -121,48 +121,6 @@ qemud_channel_recv(int pipe, void* msg, int maxsize)
return size;
}
static void
misc_pipe_close(int* fd)
{
if (*fd >= 0) {
close(*fd);
*fd = -1;
}
}
static void
misc_pipe_send(int* fd, const char* msg)
{
if (*fd < 0) {
*fd = qemu_pipe_open_ns(NULL, "QemuMiscPipe", O_RDWR);
if (*fd < 0) {
return;
}
}
int32_t cmd_len = strlen(msg) + 1;
write(*fd, &cmd_len, sizeof(cmd_len));
write(*fd, msg, cmd_len);
int r = read(*fd, &cmd_len, sizeof(cmd_len));
if (r < 0 || cmd_len < 0) {
misc_pipe_close(fd);
return;
}
while (cmd_len > 0) {
char buf[64];
const size_t chunk = cmd_len < sizeof(buf) ? cmd_len : sizeof(buf);
r = read(*fd, buf, chunk);
if (r < 0) {
misc_pipe_close(fd);
return;
} else {
cmd_len -= chunk;
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -230,12 +188,6 @@ int main(void)
++prop_value;
fprintf(stderr, "key = %s | value = %s\n", prop_key, prop_value);
if (strcmp(prop_key, "qemu.sf.lcd_density") == 0) {
property_set("ro.sf.lcd_density", prop_value);
continue;
}
if (property_set(prop_key, prop_value) < 0) {
continue;
}
@ -243,22 +195,5 @@ int main(void)
close(qemud_fd);
qemud_fd = -1;
do {
misc_pipe_send(&qemud_fd, "heartbeat");
sleep(5);
if (property_get_bool("vendor.qemu.dev.bootcomplete", 0)) {
fprintf(stderr, "tell the host boot completed\n");
misc_pipe_send(&qemud_fd, "bootcomplete");
break;
}
} while (qemud_fd >= 0);
while (qemud_fd >= 0) {
sleep(30);
misc_pipe_send(&qemud_fd, "heartbeat");
}
return EXIT_SUCCESS;
}

View File

@ -17,11 +17,9 @@
#include <fnmatch.h>
#include <stdio.h>
#include <sys/param.h>
#include <unistd.h>
#include <netpacket/rpmsg.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/time.h>
@ -68,7 +66,6 @@ static int kvdb_monitor_open(kvdb_server* server, int fd, const char* key,
/* Malloc monitor element to store [key, fd] pair */
kvdb_monitor* mon = zalloc(sizeof(kvdb_monitor) + key_len);
if (mon == NULL) {
KVERR("kvdb_monitor_open: zalloc failed\n");
return -ENOMEM;
}
@ -79,7 +76,6 @@ static int kvdb_monitor_open(kvdb_server* server, int fd, const char* key,
};
int ret = epoll_ctl(server->efd, EPOLL_CTL_ADD, fd, &ev);
if (ret < 0) {
KVERR("kvdb_monitor_open: epoll_ctl failed, ret=%d, errno=%d\n", ret, errno);
free(mon);
return ret;
}
@ -144,17 +140,6 @@ static void kvdb_monitor_notify(kvdb_server* server, const char* key, const void
if (fnmatch(mon->key, key, FNM_NOESCAPE) != 0)
continue;
int space;
ioctl(mon->fd, FIONSPACE, &space);
if (space < (key_len + val_len + 2)) {
/* Check space before monitor notify to avoid deadlock.
Cause the send may write buffer full and wait,
then the client just get a new key and also wait,
deadlock! */
KVWARN("monitor space is not enough for key %s\n", key);
continue;
}
if (sendmsg(mon->fd, &msg, 0) < 0) {
/* Client close or some error happends, stop monitor */
LIST_REMOVE(mon, entry);
@ -291,22 +276,16 @@ static int kvdb_bind(int fd[])
for (int i = 0; i < KVFD_COUNT; i++) {
fd[i] = socket(family[i], SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd[i] < 0) {
KVERR("kvdb_bind: socket failed, i=%d, errno=%d\n", i, errno);
if (fd[i] < 0)
continue;
}
int ret = bind(fd[i], addr[i], addrlen[i]);
if (ret < 0) {
KVERR("kvdb_bind: bind failed, i=%d, ret=%d, errno=%d\n", i, ret, errno);
if (ret < 0)
return ret;
}
ret = listen(fd[i], CONFIG_KVDB_BACKLOG_CONNS);
if (ret < 0) {
KVERR("kvdb_bind: listen failed, i=%d, ret=%d, errno=%d\n", i, ret, errno);
ret = listen(fd[i], SOMAXCONN);
if (ret < 0)
return ret;
}
}
return 0;
@ -346,14 +325,10 @@ static ssize_t kvdb_recv(int sockfd, char* buf, size_t offset, size_t len)
{
while (offset < len) {
ssize_t ret = recv(sockfd, buf + offset, len - offset, 0);
if (ret < 0) {
KVERR("kvdb_recv: recv failed, ret=%zd, errno=%d\n", ret, errno);
if (ret < 0)
return ret;
}
if (ret == 0) {
KVERR("kvdb_recv: recv returned 0, connection closed\n");
if (ret == 0)
return -ENODATA;
}
offset += ret;
}
@ -366,38 +341,29 @@ static bool kvdb_client(kvdb_server* server, int fd)
ssize_t len;
char* msg;
#if defined(CONFIG_KVDB_TIMEOUT_INTERVAL) && CONFIG_KVDB_TIMEOUT_INTERVAL > 0
#if CONFIG_KVDB_TIMEOUT_INTERVAL
struct timeval timeout = {
.tv_sec = 0,
.tv_usec = CONFIG_KVDB_TIMEOUT_INTERVAL,
.tv_sec = CONFIG_KVDB_TIMEOUT_INTERVAL,
.tv_usec = 0,
};
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0
|| setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
KVWARN("Failed to set socket timeout\n");
}
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
#endif
msg = malloc(PROP_MSG_MAX);
if (msg == NULL) {
KVERR("kvdb_client: malloc failed\n");
KVERR("malloc failed\n");
goto out;
}
msg[0] = msg[1] = msg[2] = 0; /* zero the first key bytes */
len = recv(fd, msg, PROP_MSG_MAX, 0);
if (len <= 0) {
KVERR("kvdb_client: recv failed, len=%zd, errno=%d\n", len, errno);
if (len <= 0)
goto out;
}
switch (msg[0]) {
case 'D': {
if (len < 2)
len = kvdb_recv(fd, msg, len, 2);
if (len < 0)
goto out;
size_t key_len = (unsigned char)msg[1];
size_t end_pos = key_len + 2;
if (end_pos >= PROP_MSG_MAX)
@ -416,11 +382,6 @@ static bool kvdb_client(kvdb_server* server, int fd)
break;
}
case 'G': {
if (len < 3)
len = kvdb_recv(fd, msg, len, 3);
if (len < 0)
goto out;
size_t key_len = (unsigned char)msg[1];
size_t val_len = (unsigned char)msg[2];
size_t end_pos = key_len + 3;
@ -438,11 +399,6 @@ static bool kvdb_client(kvdb_server* server, int fd)
break;
}
case 'S': {
if (len < 3)
len = kvdb_recv(fd, msg, len, 3);
if (len < 0)
goto out;
size_t key_len = (unsigned char)msg[1];
size_t val_len = (unsigned char)msg[2];
size_t end_pos = key_len + val_len + 3;
@ -475,32 +431,10 @@ static bool kvdb_client(kvdb_server* server, int fd)
break;
}
case 'R': {
if (len < 2)
len = kvdb_recv(fd, msg, len, 2);
if (len < 0)
goto out;
size_t path_len = (unsigned char)msg[1];
size_t end_pos = path_len + 2;
if (end_pos >= PROP_MSG_MAX)
break;
const char* path = msg + 2;
len = kvdb_recv(fd, msg, len, end_pos);
if (len > 0) {
if (path[0])
kvdb_load(server->kvdb, path, true);
else
kvdb_load(server->kvdb, CONFIG_KVDB_SOURCE_PATH, true);
}
kvdb_load(server->kvdb, CONFIG_KVDB_SOURCE_PATH, true);
break;
}
case 'M': {
if (len < 2)
len = kvdb_recv(fd, msg, len, 2);
if (len < 0)
goto out;
/* Property monitor open operation */
size_t key_len = (unsigned char)msg[1];
size_t end_pos = key_len + 2;
@ -522,7 +456,6 @@ static bool kvdb_client(kvdb_server* server, int fd)
}
case 'E': {
int ret = 0;
KVERR("kvdb_client: received exit command, stopping server\n");
server->running = false;
kvdb_uninit(server->kvdb);
send(fd, &ret, sizeof(ret), 0);
@ -542,17 +475,14 @@ static void kvdb_loop(kvdb_server* server)
struct timespec ts;
server->efd = epoll_create(KVFD_MAX);
if (server->efd < 0) {
KVERR("kvdb_loop: epoll_create failed, errno=%d\n", errno);
if (server->efd < 0)
return;
}
for (int i = 0; i < KVFD_COUNT; i++) {
if (server->fd[i] >= 0) {
evs[0].data.ptr = &server->fd[i];
evs[0].events = EPOLLIN;
if (epoll_ctl(server->efd, EPOLL_CTL_ADD, server->fd[i], &evs[0]) < 0) {
KVERR("kvdb_loop: epoll_ctl ADD failed, fd=%d, errno=%d\n", server->fd[i], errno);
close(server->efd);
return;
}
@ -579,7 +509,7 @@ static void kvdb_loop(kvdb_server* server)
int nfds = epoll_wait(server->efd, evs, KVFD_MAX, timeout);
for (int i = 0; i < nfds; i++) {
int fd = *(int*)evs[i].data.ptr;
#if (KVFD_COUNT > 1)
#ifdef CONFIG_NET_RPMSG
if (fd != server->fd[0] && fd != server->fd[1]) {
#else
if (fd != server->fd[0]) {
@ -606,7 +536,6 @@ static void kvdb_loop(kvdb_server* server)
}
}
}
KVERR("kvdb_loop: server loop exited, running=%d\n", server->running);
}
/****************************************************************************
@ -630,21 +559,16 @@ int main(int argc, char* argv[])
.head = LIST_HEAD_INITIALIZER(),
};
int ret = kvdb_bind(server.fd);
if (ret < 0) {
KVERR("main: kvdb_bind failed, ret=%d, errno=%d\n", ret, errno);
if (ret < 0)
goto out;
}
ret = kvdb_init(&server.kvdb);
if (ret < 0) {
KVERR("main: kvdb_init failed, ret=%d\n", ret);
if (ret < 0)
goto out;
}
kvdb_load(server.kvdb, CONFIG_KVDB_SOURCE_PATH, false);
kvdb_loop(&server);
out:
KVERR("main: exiting, ret=%d\n", ret);
kvdb_unbind(server.fd);
return -ret;
}

View File

@ -40,24 +40,15 @@ struct kvdb {
int kvdb_persist_set(struct kvdb* kvdb, const char* key, size_t key_len, const void* value, size_t val_len, bool force)
{
int ret = unqlite_kv_store(kvdb->db, key, key_len, value, val_len);
if (ret < 0) {
KVERR("kv_store key:%s key_len:%d error %d!\n", key, (int)key_len, ret);
return ret;
}
return ret;
return unqlite_kv_store(kvdb->db, key, key_len, value, val_len);
}
ssize_t kvdb_persist_get(struct kvdb* kvdb, const char* key, size_t key_len, void* value, size_t val_len)
{
unqlite_int64 val_size = val_len;
ssize_t ret = unqlite_kv_fetch(kvdb->db, key, key_len, value, &val_size);
if (ret < 0) {
if (ret != UNQLITE_NOTFOUND)
KVERR("kv_fetch key:%s key_len:%d error %d!\n", key, (int)key_len, ret);
if (ret < 0)
return ret;
}
if (val_size <= 0)
return -EINVAL;
@ -67,13 +58,7 @@ ssize_t kvdb_persist_get(struct kvdb* kvdb, const char* key, size_t key_len, voi
int kvdb_persist_delete(struct kvdb* kvdb, const char* key, size_t key_len)
{
int ret = unqlite_kv_delete(kvdb->db, key, key_len);
if (ret < 0) {
KVERR("kv_delete key:%s key_len:%d error %d!\n", key, (int)key_len, ret);
return ret;
}
return ret;
return unqlite_kv_delete(kvdb->db, key, key_len);
}
static int kvdb_list_value(const void* value, unsigned int len, void* arg)
@ -85,17 +70,10 @@ static int kvdb_list_value(const void* value, unsigned int len, void* arg)
static int kvdb_list_key(const void* value, unsigned int len, void* arg)
{
int ret;
kvdb_consume_data* data = arg;
data->key = value;
data->key_len = len;
ret = unqlite_kv_cursor_data_callback(data->cur, kvdb_list_value, data);
if (ret < 0) {
KVERR("kv_cursor_data_callback failed error %d!\n", ret);
return ret;
}
return ret;
return unqlite_kv_cursor_data_callback(data->cur, kvdb_list_value, data);
}
int kvdb_persist_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie)
@ -113,7 +91,6 @@ int kvdb_persist_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie)
while (unqlite_kv_cursor_valid_entry(cur)) {
int ret = unqlite_kv_cursor_key_callback(cur, kvdb_list_key, &data);
if (ret < 0) { /* exit loop demanded by consume */
KVERR("kv_cursor_key_callback failed error %d!\n", ret);
unqlite_kv_cursor_release(kvdb->db, cur);
return ret;
}
@ -154,10 +131,8 @@ int kvdb_persist_init(struct kvdb** kvdb)
ret = unqlite_open(&(*kvdb)->db, CONFIG_KVDB_PERSIST_PATH, UNQLITE_OPEN_CREATE | UNQLITE_OPEN_OMIT_JOURNALING);
if (ret < 0) {
KVERR("unqlite_open failed error %d!\n", ret);
if (ret < 0)
free(*kvdb);
}
return ret;
}

View File

@ -21,7 +21,6 @@
#include <nuttx/streams.h>
#include <debug.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

View File

@ -55,58 +55,58 @@ void atrace_set_tracing_enabled(bool enabled)
void atrace_begin_body(const char* name)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "B|%d|%s", gettid(), name);
sched_note_printf(NOTE_TAG_ALWAYS, "B|%d|%s", gettid(), name);
}
void atrace_end_body(void)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "E|%d", gettid());
sched_note_printf(NOTE_TAG_ALWAYS, "E|%d", gettid());
}
void atrace_async_begin_body(const char* name, int32_t cookie)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "S|%d|%s|%" PRId32, gettid(),
sched_note_printf(NOTE_TAG_ALWAYS, "S|%d|%s|%" PRId32, gettid(),
name, cookie);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "F|%d|%s|%" PRId32, gettid(),
sched_note_printf(NOTE_TAG_ALWAYS, "F|%d|%s|%" PRId32, gettid(),
name, cookie);
}
void atrace_async_for_track_begin_body(const char* track_name,
const char* name, int32_t cookie)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "G|%d|%s|%s|%" PRId32, gettid(),
sched_note_printf(NOTE_TAG_ALWAYS, "G|%d|%s|%s|%" PRId32, gettid(),
track_name, name, cookie);
}
void atrace_async_for_track_end_body(const char* track_name, const char* name, int32_t cookie)
void atrace_async_for_track_end_body(const char* track_name, const char *name, int32_t cookie)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "H|%d|%s|%s|%" PRId32, gettid(),
sched_note_printf(NOTE_TAG_ALWAYS, "H|%d|%s|%s|%" PRId32, gettid(),
track_name, name, cookie);
}
void atrace_instant_body(const char* name)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "I|%d|%s", gettid(), name);
sched_note_printf(NOTE_TAG_ALWAYS, "I|%d|%s", gettid(), name);
}
void atrace_instant_for_track_body(const char* track_name, const char* name)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "N|%d|%s|%s", gettid(),
sched_note_printf(NOTE_TAG_ALWAYS, "N|%d|%s|%s", gettid(),
track_name, name);
}
void atrace_int_body(const char* name, int32_t value)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "C|%d|%s|%" PRId32,
sched_note_printf(NOTE_TAG_ALWAYS, "C|%d|%s|%" PRId32,
gettid(), name, value);
}
void atrace_int64_body(const char* name, int64_t value)
{
sched_note_printf(NOTE_TAG_ALWAYS, LOG_INFO, "C|%d|%s|%" PRId64, gettid(),
sched_note_printf(NOTE_TAG_ALWAYS, "C|%d|%s|%" PRId64, gettid(),
name, value);
}